[cfe-commits] r159560 - in /cfe/trunk: include/clang/StaticAnalyzer/Core/CheckerManager.h include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h lib/StaticAnalyzer/Core/Calls.cpp lib/StaticAnalyzer/Core/CheckerManager.cpp lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
Jordan Rose
jordan_rose at apple.com
Mon Jul 2 12:28:10 PDT 2012
Author: jrose
Date: Mon Jul 2 14:28:09 2012
New Revision: 159560
URL: http://llvm.org/viewvc/llvm-project?rev=159560&view=rev
Log:
[analyzer] Use CallEvent for inlining and call default-evaluation.
Modified:
cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h
cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h
cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
cfe/trunk/lib/StaticAnalyzer/Core/Calls.cpp
cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp
cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h?rev=159560&r1=159559&r2=159560&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h Mon Jul 2 14:28:09 2012
@@ -33,6 +33,7 @@
class AnalysisManager;
class BugReporter;
class CheckerContext;
+ class SimpleCall;
class ObjCMethodCall;
class SVal;
class ExplodedNode;
@@ -44,12 +45,6 @@
class MemRegion;
class SymbolReaper;
-class GraphExpander {
-public:
- virtual ~GraphExpander();
- virtual void expandGraph(ExplodedNodeSet &Dst, ExplodedNode *Pred) = 0;
-};
-
template <typename T> class CheckerFn;
template <typename RET, typename P1, typename P2, typename P3, typename P4,
@@ -303,8 +298,7 @@
/// \brief Run checkers for evaluating a call.
void runCheckersForEvalCall(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
- const CallExpr *CE, ExprEngine &Eng,
- GraphExpander *defaultEval = 0);
+ const SimpleCall &CE, ExprEngine &Eng);
/// \brief Run checkers for the entire Translation Unit.
void runCheckersOnEndOfTranslationUnit(const TranslationUnitDecl *TU,
Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h?rev=159560&r1=159559&r2=159560&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h Mon Jul 2 14:28:09 2012
@@ -278,16 +278,27 @@
public:
BlockCall(const CallExpr *CE, ProgramStateRef St,
const LocationContext *LCtx)
- : SimpleCall(CE, St, LCtx, CE_Block) {
- assert(isa<BlockDataRegion>(getSVal(CE->getCallee()).getAsRegion()));
+ : SimpleCall(CE, St, LCtx, CE_Block) {}
+
+ /// \brief Returns the region associated with this instance of the block.
+ ///
+ /// This may be NULL if the block's origin is unknown.
+ const BlockDataRegion *getBlockRegion() const;
+
+ /// \brief Gets the declaration of the block.
+ ///
+ /// This is not an override of getDecl() because AnyFunctionCall has already
+ /// assumed that it's a FunctionDecl.
+ const BlockDecl *getBlockDecl() const {
+ const BlockDataRegion *BR = getBlockRegion();
+ if (!BR)
+ return 0;
+ return BR->getDecl();
}
static bool classof(const CallEvent *CA) {
return CA->getKind() == CE_Block;
}
-
-private:
- const BlockDataRegion *getBlockRegion() const;
};
/// \brief Represents a call to a C++ constructor.
Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h?rev=159560&r1=159559&r2=159560&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h Mon Jul 2 14:28:09 2012
@@ -42,6 +42,7 @@
class AnalysisManager;
class CallEvent;
+class SimpleCall;
class ObjCMethodCall;
class ExprEngine : public SubEngine {
@@ -468,6 +469,11 @@
void evalStore(ExplodedNodeSet &Dst, const Expr *AssignE, const Expr *StoreE,
ExplodedNode *Pred, ProgramStateRef St, SVal TargetLV, SVal Val,
const ProgramPointTag *tag = 0);
+
+ void evalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred,
+ const SimpleCall &Call);
+ void defaultEvalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred,
+ const CallEvent &Call);
private:
void evalLoadCommon(ExplodedNodeSet &Dst,
const Expr *NodeEx, /* Eventually will be a CFGStmt */
@@ -488,7 +494,8 @@
const ProgramPointTag *tag, bool isLoad);
bool shouldInlineDecl(const Decl *D, ExplodedNode *Pred);
- bool InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE, ExplodedNode *Pred);
+ bool inlineCall(ExplodedNodeSet &Dst, const CallEvent &Call,
+ ExplodedNode *Pred);
bool replayWithoutInlining(ExplodedNode *P, const LocationContext *CalleeLC);
};
Modified: cfe/trunk/lib/StaticAnalyzer/Core/Calls.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/Calls.cpp?rev=159560&r1=159559&r2=159560&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/Calls.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/Calls.cpp Mon Jul 2 14:28:09 2012
@@ -307,23 +307,34 @@
const Expr *Callee = getOriginExpr()->getCallee();
const MemRegion *DataReg = getSVal(Callee).getAsRegion();
- return cast<BlockDataRegion>(DataReg);
+ return dyn_cast_or_null<BlockDataRegion>(DataReg);
}
CallEvent::param_iterator BlockCall::param_begin() const {
- return getBlockRegion()->getDecl()->param_begin();
+ const BlockDecl *D = getBlockDecl();
+ if (!D)
+ return 0;
+ return D->param_begin();
}
CallEvent::param_iterator BlockCall::param_end() const {
- return getBlockRegion()->getDecl()->param_end();
+ const BlockDecl *D = getBlockDecl();
+ if (!D)
+ return 0;
+ return D->param_end();
}
void BlockCall::addExtraInvalidatedRegions(RegionList &Regions) const {
- Regions.push_back(getBlockRegion());
+ // FIXME: This also needs to invalidate captured globals.
+ if (const MemRegion *R = getBlockRegion())
+ Regions.push_back(R);
}
QualType BlockCall::getDeclaredResultType() const {
- QualType BlockTy = getBlockRegion()->getCodeRegion()->getLocationType();
+ const BlockDataRegion *BR = getBlockRegion();
+ if (!BR)
+ return QualType();
+ QualType BlockTy = BR->getCodeRegion()->getLocationType();
return cast<FunctionType>(BlockTy->getPointeeType())->getResultType();
}
Modified: cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp?rev=159560&r1=159559&r2=159560&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp Mon Jul 2 14:28:09 2012
@@ -461,16 +461,9 @@
/// Only one checker will evaluate the call.
void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
- const CallExpr *CE,
- ExprEngine &Eng,
- GraphExpander *defaultEval) {
- if (EvalCallCheckers.empty() &&
- InlineCallCheckers.empty() &&
- defaultEval == 0) {
- Dst.insert(Src);
- return;
- }
-
+ const SimpleCall &Call,
+ ExprEngine &Eng) {
+ const CallExpr *CE = Call.getOriginExpr();
for (ExplodedNodeSet::iterator
NI = Src.begin(), NE = Src.end(); NI != NE; ++NI) {
@@ -533,12 +526,8 @@
}
// If none of the checkers evaluated the call, ask ExprEngine to handle it.
- if (!anyEvaluated) {
- if (defaultEval)
- defaultEval->expandGraph(Dst, Pred);
- else
- Dst.insert(Pred);
- }
+ if (!anyEvaluated)
+ Eng.defaultEvalCall(Dst, Pred, Call);
}
}
@@ -678,6 +667,3 @@
for (unsigned i = 0, e = CheckerDtors.size(); i != e; ++i)
CheckerDtors[i]();
}
-
-// Anchor for the vtable.
-GraphExpander::~GraphExpander() { }
Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp?rev=159560&r1=159559&r2=159560&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp Mon Jul 2 14:28:09 2012
@@ -207,6 +207,10 @@
// Determine if we should inline the call.
bool ExprEngine::shouldInlineDecl(const Decl *D, ExplodedNode *Pred) {
+ // FIXME: default constructors don't have bodies.
+ if (!D->hasBody())
+ return false;
+
AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(D);
const CFG *CalleeCFG = CalleeADC->getCFG();
@@ -235,52 +239,47 @@
return false;
}
+ // Do not inline constructors until we can model destructors.
+ // This is unfortunate, but basically necessary for smart pointers and such.
+ if (isa<CXXConstructorDecl>(D))
+ return false;
+
return true;
}
-bool ExprEngine::InlineCall(ExplodedNodeSet &Dst,
- const CallExpr *CE,
+bool ExprEngine::inlineCall(ExplodedNodeSet &Dst,
+ const CallEvent &Call,
ExplodedNode *Pred) {
if (!getAnalysisManager().shouldInlineCall())
return false;
- // if (!shouldInlineCallExpr(CE, this))
- // return false;
-
const StackFrameContext *CallerSFC =
Pred->getLocationContext()->getCurrentStackFrame();
- ProgramStateRef state = Pred->getState();
- const Expr *Callee = CE->getCallee();
- SVal CalleeVal = state->getSVal(Callee, Pred->getLocationContext());
- const Decl *D = 0;
+ const Decl *D = Call.getDecl();
const LocationContext *ParentOfCallee = 0;
-
- if (const FunctionDecl *FD = CalleeVal.getAsFunctionDecl()) {
- if (!FD->hasBody(FD))
+
+ switch (Call.getKind()) {
+ case CE_Function:
+ case CE_CXXConstructor:
+ case CE_CXXMember:
+ // These are always at least possible to inline.
+ break;
+ case CE_Block: {
+ const BlockDataRegion *BR = cast<BlockCall>(Call).getBlockRegion();
+ if (!BR)
return false;
-
- switch (CE->getStmtClass()) {
- default:
- break;
- case Stmt::CXXMemberCallExprClass:
- case Stmt::CallExprClass: {
- D = FD;
- break;
-
- }
- }
- } else if (const BlockDataRegion *BR =
- dyn_cast_or_null<BlockDataRegion>(CalleeVal.getAsRegion())) {
- assert(CE->getStmtClass() == Stmt::CallExprClass);
- const BlockDecl *BD = BR->getDecl();
- D = BD;
- AnalysisDeclContext *BlockCtx = AMgr.getAnalysisDeclContext(BD);
+ D = BR->getDecl();
+ AnalysisDeclContext *BlockCtx = AMgr.getAnalysisDeclContext(D);
ParentOfCallee = BlockCtx->getBlockInvocationContext(CallerSFC,
- BD,
+ cast<BlockDecl>(D),
BR);
- } else {
- // This is case we don't handle yet.
+ break;
+ }
+ case CE_ObjCMessage:
+ case CE_ObjCPropertyAccess:
+ // These always use dynamic dispatch; enabling inlining means assuming
+ // that a particular method will be called at runtime.
return false;
}
@@ -290,16 +289,19 @@
if (!ParentOfCallee)
ParentOfCallee = CallerSFC;
+ const Expr *CallE = Call.getOriginExpr();
+ assert(CallE && "It is not yet possible to have calls without statements");
+
// Construct a new stack frame for the callee.
AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(D);
const StackFrameContext *CalleeSFC =
- CalleeADC->getStackFrame(ParentOfCallee, CE,
+ CalleeADC->getStackFrame(ParentOfCallee, CallE,
currentBuilderContext->getBlock(),
currentStmtIdx);
- CallEnter Loc(CE, CalleeSFC, Pred->getLocationContext());
+ CallEnter Loc(CallE, CalleeSFC, Pred->getLocationContext());
bool isNew;
- if (ExplodedNode *N = G.getNode(Loc, state, false, &isNew)) {
+ if (ExplodedNode *N = G.getNode(Loc, Pred->getState(), false, &isNew)) {
N->addPredecessor(Pred, G);
if (isNew)
Engine.getWorkList()->enqueue(N);
@@ -307,13 +309,13 @@
return true;
}
-static ProgramStateRef getReplayWithoutInliningState(ExplodedNode *&N,
- const CallExpr *CE) {
+static ProgramStateRef getInlineFailedState(ExplodedNode *&N,
+ const Stmt *CallE) {
void *ReplayState = N->getState()->get<ReplayWithoutInlining>();
if (!ReplayState)
return 0;
- const CallExpr *ReplayCE = reinterpret_cast<const CallExpr*>(ReplayState);
- if (CE == ReplayCE) {
+ const Stmt *ReplayCallE = reinterpret_cast<const Stmt *>(ReplayState);
+ if (CallE == ReplayCallE) {
return N->getState()->remove<ReplayWithoutInlining>();
}
return 0;
@@ -324,83 +326,75 @@
// Perform the previsit of the CallExpr.
ExplodedNodeSet dstPreVisit;
getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, CE, *this);
-
- // Now evaluate the call itself.
- class DefaultEval : public GraphExpander {
- ExprEngine &Eng;
- const CallExpr *CE;
- public:
-
- DefaultEval(ExprEngine &eng, const CallExpr *ce)
- : Eng(eng), CE(ce) {}
- virtual void expandGraph(ExplodedNodeSet &Dst, ExplodedNode *Pred) {
-
- ProgramStateRef state = getReplayWithoutInliningState(Pred, CE);
-
- // First, try to inline the call.
- if (state == 0 && Eng.InlineCall(Dst, CE, Pred))
- return;
-
- // First handle the return value.
- StmtNodeBuilder Bldr(Pred, Dst, *Eng.currentBuilderContext);
-
- // Get the callee.
- const Expr *Callee = CE->getCallee()->IgnoreParens();
- if (state == 0)
- state = Pred->getState();
- SVal L = state->getSVal(Callee, Pred->getLocationContext());
-
- // Figure out the result type. We do this dance to handle references.
- // FIXME: This doesn't handle C++ methods, blocks, etc.
- QualType ResultTy;
- if (const FunctionDecl *FD = L.getAsFunctionDecl())
- ResultTy = FD->getResultType();
- else
- ResultTy = CE->getType();
-
- if (CE->isGLValue())
- ResultTy = Eng.getContext().getPointerType(ResultTy);
-
- // Conjure a symbol value to use as the result.
- SValBuilder &SVB = Eng.getSValBuilder();
- unsigned Count = Eng.currentBuilderContext->getCurrentBlockCount();
- const LocationContext *LCtx = Pred->getLocationContext();
- SVal RetVal = SVB.getConjuredSymbolVal(0, CE, LCtx, ResultTy, Count);
-
- // Generate a new state with the return value set.
- state = state->BindExpr(CE, LCtx, RetVal);
-
- // Invalidate the arguments.
- if (const CXXMemberCallExpr *MemberCE = dyn_cast<CXXMemberCallExpr>(CE)) {
- CXXMemberCall Call(MemberCE, state, LCtx);
- state = Call.invalidateRegions(Count);
- } else if (isa<BlockDataRegion>(L.getAsRegion())) {
- BlockCall Call(CE, state, LCtx);
- state = Call.invalidateRegions(Count);
- } else {
- FunctionCall Call(CE, state, LCtx);
- state = Call.invalidateRegions(Count);
- }
- // And make the result node.
- Bldr.generateNode(CE, Pred, state);
- }
- };
-
- // Finally, evaluate the function call. We try each of the checkers
+ // Get the callee kind.
+ const CXXMemberCallExpr *MemberCE = dyn_cast<CXXMemberCallExpr>(CE);
+ bool IsBlock = (MemberCE ? false
+ : CE->getCallee()->getType()->isBlockPointerType());
+
+ // Evaluate the function call. We try each of the checkers
// to see if the can evaluate the function call.
ExplodedNodeSet dstCallEvaluated;
- DefaultEval defEval(*this, CE);
- getCheckerManager().runCheckersForEvalCall(dstCallEvaluated,
- dstPreVisit,
- CE, *this, &defEval);
-
+ for (ExplodedNodeSet::iterator I = dstPreVisit.begin(), E = dstPreVisit.end();
+ I != E; ++I) {
+ ProgramStateRef State = (*I)->getState();
+ const LocationContext *LCtx = (*I)->getLocationContext();
+
+ // Evaluate the call.
+ if (MemberCE)
+ evalCall(dstCallEvaluated, *I, CXXMemberCall(MemberCE, State, LCtx));
+ else if (IsBlock)
+ evalCall(dstCallEvaluated, *I, BlockCall(CE, State, LCtx));
+ else
+ evalCall(dstCallEvaluated, *I, FunctionCall(CE, State, LCtx));
+ }
+
// Finally, perform the post-condition check of the CallExpr and store
// the created nodes in 'Dst'.
+ // Note that if the call was inlined, dstCallEvaluated will be empty.
+ // The post-CallExpr check will occur in processCallExit.
getCheckerManager().runCheckersForPostStmt(dst, dstCallEvaluated, CE,
*this);
}
+void ExprEngine::evalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred,
+ const SimpleCall &Call) {
+ getCheckerManager().runCheckersForEvalCall(Dst, Pred, Call, *this);
+}
+
+void ExprEngine::defaultEvalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred,
+ const CallEvent &Call) {
+ // Try to inline the call.
+ ProgramStateRef state = 0;
+ const Expr *E = Call.getOriginExpr();
+ if (E) {
+ state = getInlineFailedState(Pred, E);
+ if (state == 0 && inlineCall(Dst, Call, Pred))
+ return;
+ }
+
+ // If we can't inline it, handle the return value and invalidate the regions.
+ StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
+
+ // Invalidate any regions touched by the call.
+ unsigned Count = currentBuilderContext->getCurrentBlockCount();
+ if (state == 0)
+ state = Pred->getState();
+ 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);
+
+ // And make the result node.
+ state = state->BindExpr(Call.getOriginExpr(), LCtx, RetVal);
+ Bldr.generateNode(Call.getOriginExpr(), Pred, state);
+}
+
void ExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
More information about the cfe-commits
mailing list