diff options
| -rw-r--r-- | clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 33 | ||||
| -rw-r--r-- | clang/test/Analysis/ctor.mm (renamed from clang/test/Analysis/ctor-inlining.mm) | 91 |
2 files changed, 123 insertions, 1 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index 84f96349f74..3f16c624922 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -176,6 +176,7 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, } // 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 @@ -233,8 +234,38 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, 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; diff --git a/clang/test/Analysis/ctor-inlining.mm b/clang/test/Analysis/ctor.mm index 9eb9888e935..16ad9d10030 100644 --- a/clang/test/Analysis/ctor-inlining.mm +++ b/clang/test/Analysis/ctor.mm @@ -534,3 +534,94 @@ namespace VirtualInheritance { 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. + } + }; +} |

