}
// FIXME: This will eventually need to handle new-expressions as well.
- // Don't forget to update the pre-constructor initialization code below.
}
// If we couldn't find an existing region to construct into, assume we're
ExplodedNodeSet DstPreVisit;
getCheckerManager().runCheckersForPreStmt(DstPreVisit, Pred, CE, *this);
-
- bool IsArray = isa<ElementRegion>(Target);
- ExplodedNodeSet PreInitialized;
- {
- StmtNodeBuilder Bldr(DstPreVisit, PreInitialized, *currBldrCtx);
- if (CE->requiresZeroInitialization()) {
- // Type of the zero doesn't matter.
- SVal ZeroVal = svalBuilder.makeZeroVal(getContext().CharTy);
-
- for (ExplodedNodeSet::iterator I = DstPreVisit.begin(),
- E = DstPreVisit.end();
- I != E; ++I) {
- ProgramStateRef State = (*I)->getState();
- // FIXME: Once we properly handle constructors in new-expressions, we'll
- // need to invalidate the region before setting a default value, to make
- // sure there aren't any lingering bindings around. This probably needs
- // to happen regardless of whether or not the object is zero-initialized
- // to handle random fields of a placement-initialized object picking up
- // old bindings. We might only want to do it when we need to, though.
- // FIXME: This isn't actually correct for arrays -- we need to zero-
- // initialize the entire array, not just the first element -- but our
- // handling of arrays everywhere else is weak as well, so this shouldn't
- // actually make things worse.
- State = State->bindDefault(loc::MemRegionVal(Target), ZeroVal);
- Bldr.generateNode(CE, *I, State, /*tag=*/0, ProgramPoint::PreStmtKind);
- }
- }
- }
-
ExplodedNodeSet DstPreCall;
- getCheckerManager().runCheckersForPreCall(DstPreCall, PreInitialized,
+ getCheckerManager().runCheckersForPreCall(DstPreCall, DstPreVisit,
*Call, *this);
ExplodedNodeSet DstEvaluated;
StmtNodeBuilder Bldr(DstPreCall, DstEvaluated, *currBldrCtx);
- if (CE->getConstructor()->isTrivial() && !IsArray) {
- if (CE->getConstructor()->isCopyOrMoveConstructor()) {
- for (ExplodedNodeSet::iterator I = DstPreCall.begin(),
- E = DstPreCall.end();
- I != E; ++I)
- performTrivialCopy(Bldr, *I, *Call);
- } else {
- assert(CE->getConstructor()->isDefaultConstructor());
-
- // We still have to bind the return value.
- for (ExplodedNodeSet::iterator I = DstPreCall.begin(),
- E = DstPreCall.end();
- I != E; ++I) {
- ProgramStateRef State = (*I)->getState();
- State = bindReturnValue(*Call, LCtx, State);
- Bldr.generateNode(CE, *I, State);
- }
- }
+ bool IsArray = isa<ElementRegion>(Target);
+ if (CE->getConstructor()->isTrivial() &&
+ CE->getConstructor()->isCopyOrMoveConstructor() &&
+ !IsArray) {
+ // FIXME: Handle other kinds of trivial constructors as well.
+ for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
+ I != E; ++I)
+ performTrivialCopy(Bldr, *I, *Call);
+
} else {
for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
I != E; ++I)
clang_analyzer_eval(c.values[2].x == 3); // expected-warning{{UNKNOWN}}
}
};
-
-namespace ZeroInitialization {
- struct raw_pair {
- int p1;
- int p2;
- };
-
- void testVarDecl() {
- raw_pair p{};
- clang_analyzer_eval(p.p1 == 0); // expected-warning{{TRUE}}
- clang_analyzer_eval(p.p2 == 0); // expected-warning{{TRUE}}
- }
-
- void testTemporary() {
- clang_analyzer_eval(raw_pair().p1 == 0); // expected-warning{{TRUE}}
- clang_analyzer_eval(raw_pair().p2 == 0); // expected-warning{{TRUE}}
- }
-
- void testArray() {
- raw_pair p[2] = {};
- clang_analyzer_eval(p[0].p1 == 0); // expected-warning{{TRUE}}
- clang_analyzer_eval(p[0].p2 == 0); // expected-warning{{TRUE}}
- clang_analyzer_eval(p[1].p1 == 0); // expected-warning{{TRUE}}
- clang_analyzer_eval(p[1].p2 == 0); // expected-warning{{TRUE}}
- }
-
- void testNew() {
- // FIXME: Pending proper implementation of constructors for 'new'.
- raw_pair *pp = new raw_pair();
- clang_analyzer_eval(pp->p1 == 0); // expected-warning{{UNKNOWN}}
- clang_analyzer_eval(pp->p2 == 0); // expected-warning{{UNKNOWN}}
- }
-
- void testArrayNew() {
- // FIXME: Pending proper implementation of constructors for 'new[]'.
- raw_pair *p = new raw_pair[2]();
- clang_analyzer_eval(p[0].p1 == 0); // expected-warning{{UNKNOWN}}
- clang_analyzer_eval(p[0].p2 == 0); // expected-warning{{UNKNOWN}}
- clang_analyzer_eval(p[1].p1 == 0); // expected-warning{{UNKNOWN}}
- clang_analyzer_eval(p[1].p2 == 0); // expected-warning{{UNKNOWN}}
- }
-
- struct initializing_pair {
- public:
- int x;
- raw_pair y;
- initializing_pair() : x(), y() {}
- };
-
- void testFieldInitializers() {
- initializing_pair p;
- clang_analyzer_eval(p.x == 0); // expected-warning{{TRUE}}
- clang_analyzer_eval(p.y.p1 == 0); // expected-warning{{TRUE}}
- clang_analyzer_eval(p.y.p2 == 0); // expected-warning{{TRUE}}
- }
-
- struct subclass : public raw_pair {
- subclass() = default;
- };
-
- void testSubclass() {
- subclass p;
- clang_analyzer_eval(p.p1 == 0); // expected-warning{{garbage}}
- }
-
- struct initializing_subclass : public raw_pair {
- initializing_subclass() : raw_pair() {}
- };
-
- void testInitializingSubclass() {
- initializing_subclass p;
- clang_analyzer_eval(p.p1 == 0); // expected-warning{{TRUE}}
- clang_analyzer_eval(p.p2 == 0); // expected-warning{{TRUE}}
- }
-}
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>32</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>44</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>44</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>44</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>44</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>46</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>