}
// 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);
+
+ 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. Placement new makes this tricky as well,
+ // since it's then possible to be initializing one part of a multi-
+ // dimensional array.
+ State = State->bindDefault(loc::MemRegionVal(Target), ZeroVal);
+ Bldr.generateNode(CE, *I, State, /*tag=*/0, ProgramPoint::PreStmtKind);
+ }
+ }
+ }
+
ExplodedNodeSet DstPreCall;
- getCheckerManager().runCheckersForPreCall(DstPreCall, DstPreVisit,
+ getCheckerManager().runCheckersForPreCall(DstPreCall, PreInitialized,
*Call, *this);
ExplodedNodeSet DstEvaluated;
clang_analyzer_eval(counter == 1); // expected-warning{{TRUE}}
}
}
+
+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}}
+ }
+
+ struct pair_wrapper {
+ pair_wrapper() : p() {}
+ raw_pair p;
+ };
+
+ struct virtual_subclass : public virtual pair_wrapper {
+ virtual_subclass() {}
+ };
+
+ struct double_virtual_subclass : public virtual_subclass {
+ double_virtual_subclass() {
+ // This previously caused a crash because the pair_wrapper subobject was
+ // initialized twice.
+ }
+ };
+}