aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h33
-rw-r--r--lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp1
-rw-r--r--lib/StaticAnalyzer/Core/Calls.cpp6
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCXX.cpp26
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp22
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,