diff options
-rw-r--r-- | include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h | 33 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp | 1 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/Calls.cpp | 6 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 26 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp | 22 |
5 files changed, 64 insertions, 24 deletions
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h index 0d830c3ce9..e1d30e42c2 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h @@ -37,6 +37,7 @@ enum CallEventKind { CE_BEG_SIMPLE_CALLS = CE_Function, CE_END_SIMPLE_CALLS = CE_Block, CE_CXXConstructor, + CE_CXXDestructor, CE_CXXAllocator, CE_BEG_FUNCTION_CALLS = CE_Function, CE_END_FUNCTION_CALLS = CE_CXXAllocator, @@ -159,7 +160,7 @@ public: } /// \brief Returns an appropriate ProgramPoint for this call. - ProgramPoint getProgramPoint(bool IsPreVisit, + ProgramPoint getProgramPoint(bool IsPreVisit = false, const ProgramPointTag *Tag = 0) const; /// \brief Returns a new state with all argument regions invalidated. @@ -391,6 +392,36 @@ public: } }; +/// \brief Represents an implicit call to a C++ destructor. +/// +/// This can occur at the end of a scope (for automatic objects), at the end +/// of a full-expression (for temporaries), or as part of a delete. +class CXXDestructorCall : public AnyFunctionCall { + const CXXDestructorDecl *DD; + const MemRegion *Target; + SourceLocation Loc; + +protected: + void addExtraInvalidatedRegions(RegionList &Regions) const; + +public: + CXXDestructorCall(const CXXDestructorDecl *dd, const Stmt *Trigger, + const MemRegion *target, ProgramStateRef St, + const LocationContext *LCtx) + : AnyFunctionCall(St, LCtx, CE_CXXDestructor), DD(dd), Target(target), + Loc(Trigger->getLocEnd()) {} + + const Expr *getOriginExpr() const { return 0; } + SourceRange getSourceRange() const { return Loc; } + + const CXXDestructorDecl *getDecl() const { return DD; } + unsigned getNumArgs() const { return 0; } + + static bool classof(const CallEvent *CA) { + return CA->getKind() == CE_CXXDestructor; + } +}; + /// \brief Represents the memory allocation call in a C++ new-expression. /// /// This is a call to "operator new". diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp index 32f7706bd9..541a8b7c15 100644 --- a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp @@ -948,6 +948,7 @@ RetainSummaryManager::getSummary(const CallEvent &Call, case CE_CXXMemberOperator: case CE_Block: case CE_CXXConstructor: + case CE_CXXDestructor: case CE_CXXAllocator: // FIXME: These calls are currently unsupported. return getPersistentStopSummary(); diff --git a/lib/StaticAnalyzer/Core/Calls.cpp b/lib/StaticAnalyzer/Core/Calls.cpp index 7b86d44276..8ea1336bb7 100644 --- a/lib/StaticAnalyzer/Core/Calls.cpp +++ b/lib/StaticAnalyzer/Core/Calls.cpp @@ -372,6 +372,12 @@ void CXXConstructorCall::addExtraInvalidatedRegions(RegionList &Regions) const { } +void CXXDestructorCall::addExtraInvalidatedRegions(RegionList &Regions) const { + if (Target) + Regions.push_back(Target); +} + + CallEvent::param_iterator ObjCMethodCall::param_begin() const { const ObjCMethodDecl *D = getDecl(); if (!D) diff --git a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index bac5b70f69..3fa052817c 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -75,21 +75,21 @@ void ExprEngine::VisitCXXDestructor(const CXXDestructorDecl *DD, const Stmt *S, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext); - if (!(DD->doesThisDeclarationHaveABody() && AMgr.shouldInlineCall())) - return; + CXXDestructorCall Call(DD, S, Dest, Pred->getState(), + Pred->getLocationContext()); - // Create the context for 'this' region. - const StackFrameContext *SFC = - AnalysisDeclContexts.getContext(DD)-> - getStackFrame(Pred->getLocationContext(), S, - currentBuilderContext->getBlock(), currentStmtIdx); + ExplodedNodeSet DstPreCall; + getCheckerManager().runCheckersForPreCall(DstPreCall, Pred, + Call, *this); - CallEnter PP(S, SFC, Pred->getLocationContext()); - ProgramStateRef state = Pred->getState(); - state = state->bindLoc(svalBuilder.getCXXThis(DD->getParent(), SFC), - loc::MemRegionVal(Dest)); - Bldr.generateNode(PP, Pred, state); + ExplodedNodeSet DstInvalidated; + for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end(); + I != E; ++I) + defaultEvalCall(DstInvalidated, *I, Call); + + ExplodedNodeSet DstPostCall; + getCheckerManager().runCheckersForPostCall(Dst, DstInvalidated, + Call, *this); } void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index bf55ceb5fd..cce55ea023 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -292,7 +292,8 @@ bool ExprEngine::inlineCall(ExplodedNodeSet &Dst, // enterStackFrame as well. return false; case CE_CXXConstructor: - // Do not inline constructors until we can model destructors. + case CE_CXXDestructor: + // Do not inline constructors until we can really model destructors. // This is unfortunate, but basically necessary for smart pointers and such. return false; case CE_CXXAllocator: @@ -430,7 +431,7 @@ void ExprEngine::defaultEvalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred, return; // If we can't inline it, handle the return value and invalidate the regions. - StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext); + NodeBuilder Bldr(Pred, Dst, *currentBuilderContext); // Invalidate any regions touched by the call. unsigned Count = currentBuilderContext->getCurrentBlockCount(); @@ -439,16 +440,17 @@ void ExprEngine::defaultEvalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred, state = Call.invalidateRegions(Count, state); // Conjure a symbol value to use as the result. - assert(Call.getOriginExpr() && "Must have an expression to bind the result"); - QualType ResultTy = Call.getResultType(); - SValBuilder &SVB = getSValBuilder(); - const LocationContext *LCtx = Pred->getLocationContext(); - SVal RetVal = SVB.getConjuredSymbolVal(0, Call.getOriginExpr(), LCtx, - ResultTy, Count); + if (E) { + QualType ResultTy = Call.getResultType(); + SValBuilder &SVB = getSValBuilder(); + const LocationContext *LCtx = Pred->getLocationContext(); + SVal RetVal = SVB.getConjuredSymbolVal(0, E, LCtx, ResultTy, Count); + + state = state->BindExpr(E, LCtx, RetVal); + } // And make the result node. - state = state->BindExpr(Call.getOriginExpr(), LCtx, RetVal); - Bldr.generateNode(Call.getOriginExpr(), Pred, state); + Bldr.generateNode(Call.getProgramPoint(), state, Pred); } void ExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred, |