diff options
author | Jordan Rose <jordan_rose@apple.com> | 2012-08-25 01:06:23 +0000 |
---|---|---|
committer | Jordan Rose <jordan_rose@apple.com> | 2012-08-25 01:06:23 +0000 |
commit | 3682f1ea9c7fddc7dcbc590891158ba40f7fca16 (patch) | |
tree | bbf81b3e0a318f84b785dbb77ac63ea7bc382f40 /lib/StaticAnalyzer/Core/ExprEngine.cpp | |
parent | 3f9411a31a5d56757271e150400458491195da0b (diff) |
[analyzer] Use the common evalBind infrastructure for initializers.
This allows checkers (like the MallocChecker) to process the effects of the
bind. Previously, using a memory-allocating function (like strdup()) in an
initializer would result in a leak warning.
This does bend the expectations of checkBind a bit; since there is no
assignment expression, the statement being used is the initializer value.
In most cases this shouldn't matter because we'll use a PostInitializer
program point (rather than PostStmt) for any checker-generated nodes, though
we /will/ generate a PostStore node referencing the internal statement.
(In theory this could have funny effects if someone actually does an
assignment within an initializer; in practice, that seems like it would be
very rare.)
<rdar://problem/12171711>
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@162637 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/StaticAnalyzer/Core/ExprEngine.cpp')
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngine.cpp | 41 |
1 files changed, 25 insertions, 16 deletions
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index 6fb9116dbb..d6bcfe4eb2 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -354,11 +354,6 @@ void ExprEngine::ProcessStmt(const CFGStmt S, void ExprEngine::ProcessInitializer(const CFGInitializer Init, ExplodedNode *Pred) { - ExplodedNodeSet Dst; - NodeBuilder Bldr(Pred, Dst, *currBldrCtx); - - ProgramStateRef State = Pred->getState(); - const CXXCtorInitializer *BMI = Init.getInitializer(); PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), @@ -370,13 +365,19 @@ void ExprEngine::ProcessInitializer(const CFGInitializer Init, cast<StackFrameContext>(Pred->getLocationContext()); const CXXConstructorDecl *decl = cast<CXXConstructorDecl>(stackFrame->getDecl()); + + ProgramStateRef State = Pred->getState(); SVal thisVal = State->getSVal(svalBuilder.getCXXThis(decl, stackFrame)); + PostInitializer PP(BMI, stackFrame); + ExplodedNodeSet Tmp(Pred); + // Evaluate the initializer, if necessary if (BMI->isAnyMemberInitializer()) { // Constructors build the object directly in the field, // but non-objects must be copied in from the initializer. - if (!isa<CXXConstructExpr>(BMI->getInit())) { + const Expr *Init = BMI->getInit(); + if (!isa<CXXConstructExpr>(Init)) { SVal FieldLoc; if (BMI->isIndirectMemberInitializer()) FieldLoc = State->getLValue(BMI->getIndirectMember(), thisVal); @@ -384,19 +385,23 @@ void ExprEngine::ProcessInitializer(const CFGInitializer Init, FieldLoc = State->getLValue(BMI->getMember(), thisVal); SVal InitVal = State->getSVal(BMI->getInit(), stackFrame); - State = State->bindLoc(FieldLoc, InitVal); + + Tmp.clear(); + evalBind(Tmp, Init, Pred, FieldLoc, InitVal, /*isInit=*/true, &PP); } } else { assert(BMI->isBaseInitializer() || BMI->isDelegatingInitializer()); // We already did all the work when visiting the CXXConstructExpr. } - // Construct a PostInitializer node whether the state changed or not, + // Construct PostInitializer nodes whether the state changed or not, // so that the diagnostics don't get confused. - PostInitializer PP(BMI, stackFrame); - // Builder automatically add the generated node to the deferred set, - // which are processed in the builder's dtor. - Bldr.generateNode(PP, State, Pred); + ExplodedNodeSet Dst; + NodeBuilder Bldr(Tmp, Dst, *currBldrCtx); + for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) { + ExplodedNode *N = *I; + Bldr.generateNode(PP, N->getState(), N); + } // Enqueue the new nodes onto the work list. Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx); @@ -1541,13 +1546,17 @@ void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred, void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE, ExplodedNode *Pred, SVal location, SVal Val, - bool atDeclInit) { + bool atDeclInit, const ProgramPoint *PP) { + + const LocationContext *LC = Pred->getLocationContext(); + PostStmt PS(StoreE, LC); + if (!PP) + PP = &PS; // Do a previsit of the bind. ExplodedNodeSet CheckedSet; getCheckerManager().runCheckersForBind(CheckedSet, Pred, location, Val, - StoreE, *this, - ProgramPoint::PostStmtKind); + StoreE, *this, *PP); // If the location is not a 'Loc', it will already be handled by // the checkers. There is nothing left to do. @@ -1559,7 +1568,6 @@ void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE, ExplodedNodeSet TmpDst; StmtNodeBuilder Bldr(CheckedSet, TmpDst, *currBldrCtx); - const LocationContext *LC = Pred->getLocationContext(); for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); I!=E; ++I) { ExplodedNode *PredI = *I; @@ -1575,6 +1583,7 @@ void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE, if (loc::MemRegionVal *LocRegVal = dyn_cast<loc::MemRegionVal>(&location)) { LocReg = LocRegVal->getRegion(); } + const ProgramPoint L = PostStore(StoreE, LC, LocReg, 0); Bldr.generateNode(L, state, PredI); } |