From 256ef642f8feef22fd53be7efa868e8e34752eed Mon Sep 17 00:00:00 2001 From: Ted Kremenek Date: Wed, 11 Jan 2012 01:06:27 +0000 Subject: [PATCH] Remove '#if 0' from ExprEngine::InlineCall(), and start fresh by wiring up inlining for straight C calls. My hope is to reimplement this from first principles based on the simplifications of removing unneeded node builders and re-evaluating how C++ calls are handled in the CFG. The hope is to turn inlining "on-by-default" as soon as possible with a core set of things working well, and then expand over time. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147904 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/StaticAnalyzer/Core/Environment.cpp | 8 ++ lib/StaticAnalyzer/Core/ExplodedGraph.cpp | 3 +- lib/StaticAnalyzer/Core/ExprEngine.cpp | 77 ------------ .../Core/ExprEngineCallAndReturn.cpp | 116 ++++++++++++------ test/Analysis/inline.c | 1 - 5 files changed, 89 insertions(+), 116 deletions(-) diff --git a/lib/StaticAnalyzer/Core/Environment.cpp b/lib/StaticAnalyzer/Core/Environment.cpp index f43c2adc64..691530bdcb 100644 --- a/lib/StaticAnalyzer/Core/Environment.cpp +++ b/lib/StaticAnalyzer/Core/Environment.cpp @@ -90,6 +90,14 @@ SVal Environment::getSVal(const EnvironmentEntry &Entry, continue; case Stmt::ObjCPropertyRefExprClass: return loc::ObjCPropRef(cast(E)); + case Stmt::ReturnStmtClass: { + const ReturnStmt *RS = cast(E); + if (const Expr *RE = RS->getRetValue()) { + E = RE; + continue; + } + return UndefinedVal(); + } // Handle all other Stmt* using a lookup. default: diff --git a/lib/StaticAnalyzer/Core/ExplodedGraph.cpp b/lib/StaticAnalyzer/Core/ExplodedGraph.cpp index 691a82ed3c..160925b08f 100644 --- a/lib/StaticAnalyzer/Core/ExplodedGraph.cpp +++ b/lib/StaticAnalyzer/Core/ExplodedGraph.cpp @@ -91,7 +91,8 @@ void ExplodedGraph::reclaimRecentlyAllocatedNodes() { // Condition 3. ProgramPoint progPoint = node->getLocation(); - if (!isa(progPoint)) + if (!isa(progPoint) || + (isa(progPoint) || isa(progPoint))) continue; // Condition 4. PostStmt ps = cast(progPoint); diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index c520cc1afa..a48d69abc1 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1569,83 +1569,6 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst, const Stmt *S, BldrTop.addNodes(Tmp); } -bool ExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE, - ExplodedNode *Pred) { - return false; - - // Inlining isn't correct right now because we: - // (a) don't generate CallExit nodes. - // (b) we need a way to postpone doing post-visits of CallExprs until - // the CallExit. This means we need CallExits for the non-inline - // cases as well. - -#if 0 - const ProgramState *state = Pred->getState(); - const Expr *Callee = CE->getCallee(); - SVal L = state->getSVal(Callee); - - const FunctionDecl *FD = L.getAsFunctionDecl(); - if (!FD) - return false; - - // Specially handle CXXMethods. - const CXXMethodDecl *methodDecl = 0; - - switch (CE->getStmtClass()) { - default: break; - case Stmt::CXXOperatorCallExprClass: { - const CXXOperatorCallExpr *opCall = cast(CE); - methodDecl = - dyn_cast_or_null(opCall->getCalleeDecl()); - break; - } - case Stmt::CXXMemberCallExprClass: { - const CXXMemberCallExpr *memberCall = cast(CE); - const MemberExpr *memberExpr = - cast(memberCall->getCallee()->IgnoreParens()); - methodDecl = cast(memberExpr->getMemberDecl()); - break; - } - } - - - - - // Check if the function definition is in the same translation unit. - if (FD->hasBody(FD)) { - const StackFrameContext *stackFrame = - AMgr.getStackFrame(AMgr.getAnalysisDeclContext(FD), - Pred->getLocationContext(), - CE, currentBuilderContext->getBlock(), - currentStmtIdx); - // Now we have the definition of the callee, create a CallEnter node. - CallEnter Loc(CE, stackFrame, Pred->getLocationContext()); - - ExplodedNode *N = Builder->generateNode(Loc, state, Pred); - Dst.Add(N); - return true; - } - - // Check if we can find the function definition in other translation units. - if (AMgr.hasIndexer()) { - AnalysisDeclContext *C = AMgr.getAnalysisDeclContextInAnotherTU(FD); - if (C == 0) - return false; - const StackFrameContext *stackFrame = - AMgr.getStackFrame(C, Pred->getLocationContext(), - CE, currentBuilderContext->getBlock(), currentStmtIdx); - CallEnter Loc(CE, stackFrame, Pred->getLocationContext()); - ExplodedNode *N = Builder->generateNode(Loc, state, Pred); - Dst.Add(N); - return true; - } - - // Generate the CallExit node. - - return false; -#endif -} - std::pair ExprEngine::getEagerlyAssumeTags() { static SimpleProgramPointTag diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index c8975cba3b..81472fae6c 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -14,20 +14,12 @@ #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h" +#include "clang/Analysis/Support/SaveAndRestore.h" #include "clang/AST/DeclCXX.h" using namespace clang; using namespace ento; -namespace { - // Trait class for recording returned expression in the state. - struct ReturnExpr { - static int TagInt; - typedef const Stmt *data_type; - }; - int ReturnExpr::TagInt; -} - void ExprEngine::processCallEnter(CallEnter CE, ExplodedNode *Pred) { // Get the entry block in the CFG of the callee. const StackFrameContext *SFC = CE.getCalleeContext(); @@ -56,20 +48,36 @@ void ExprEngine::processCallEnter(CallEnter CE, ExplodedNode *Pred) { Engine.getWorkList()->enqueue(Node); } +static const ReturnStmt *getReturnStmt(const ExplodedNode *Node) { + while (Node) { + const ProgramPoint &PP = Node->getLocation(); + // Skip any BlockEdges. + if (isa(PP) || isa(PP)) { + assert(Node->pred_size() == 1); + Node = *Node->pred_begin(); + continue; + } + if (const StmtPoint *SP = dyn_cast(&PP)) { + const Stmt *S = SP->getStmt(); + return dyn_cast(S); + } + break; + } + return 0; +} + void ExprEngine::processCallExit(ExplodedNode *Pred) { const ProgramState *state = Pred->getState(); const StackFrameContext *calleeCtx = Pred->getLocationContext()->getCurrentStackFrame(); + const LocationContext *callerCtx = calleeCtx->getParent(); const Stmt *CE = calleeCtx->getCallSite(); // If the callee returns an expression, bind its value to CallExpr. - const Stmt *ReturnedExpr = state->get(); - if (ReturnedExpr) { + if (const ReturnStmt *RS = getReturnStmt(Pred)) { const LocationContext *LCtx = Pred->getLocationContext(); - SVal RetVal = state->getSVal(ReturnedExpr, LCtx); - state = state->BindExpr(CE, LCtx, RetVal); - // Clear the return expr GDM. - state = state->remove(); + SVal V = state->getSVal(RS, LCtx); + state = state->BindExpr(CE, callerCtx, V); } // Bind the constructed object value to CXXConstructExpr. @@ -82,7 +90,8 @@ void ExprEngine::processCallExit(ExplodedNode *Pred) { state = state->BindExpr(CCE, Pred->getLocationContext(), ThisV); } - PostStmt Loc(CE, calleeCtx->getParent()); + static SimpleProgramPointTag returnTag("ExprEngine : Call Return"); + PostStmt Loc(CE, callerCtx, &returnTag); bool isNew; ExplodedNode *N = G.getNode(Loc, state, false, &isNew); N->addPredecessor(Pred, G); @@ -91,6 +100,11 @@ void ExprEngine::processCallExit(ExplodedNode *Pred) { // Perform the post-condition check of the CallExpr. ExplodedNodeSet Dst; + NodeBuilderContext Ctx(Engine, calleeCtx->getCallSiteBlock(), N); + SaveAndRestore NBCSave(currentBuilderContext, + &Ctx); + SaveAndRestore CBISave(currentStmtIdx, calleeCtx->getIndex()); + getCheckerManager().runCheckersForPostStmt(Dst, N, CE, *this); // Enqueue the next element in the block. @@ -101,6 +115,42 @@ void ExprEngine::processCallExit(ExplodedNode *Pred) { } } +bool ExprEngine::InlineCall(ExplodedNodeSet &Dst, + const CallExpr *CE, + ExplodedNode *Pred) { + const ProgramState *state = Pred->getState(); + const Expr *Callee = CE->getCallee(); + const FunctionDecl *FD = + state->getSVal(Callee, Pred->getLocationContext()).getAsFunctionDecl(); + if (!FD || !FD->hasBody(FD)) + return false; + + switch (CE->getStmtClass()) { + default: + // FIXME: Handle C++. + break; + case Stmt::CallExprClass: { + // Construct a new stack frame for the callee. + AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(FD); + const StackFrameContext *CallerSFC = + Pred->getLocationContext()->getCurrentStackFrame(); + const StackFrameContext *CalleeSFC = + CalleeADC->getStackFrame(CallerSFC, CE, + currentBuilderContext->getBlock(), + currentStmtIdx); + + CallEnter Loc(CE, CalleeSFC, Pred->getLocationContext()); + bool isNew; + ExplodedNode *N = G.getNode(Loc, state, false, &isNew); + N->addPredecessor(Pred, G); + if (isNew) + Engine.getWorkList()->enqueue(N); + return true; + } + } + return false; +} + static bool isPointerToConst(const ParmVarDecl *ParamDecl) { QualType PointeeTy = ParamDecl->getOriginalType()->getPointeeType(); if (PointeeTy != QualType() && PointeeTy.isConstQualified() && @@ -315,27 +365,19 @@ void ExprEngine::VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred, void ExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - ExplodedNodeSet Src; - { - StmtNodeBuilder Bldr(Pred, Src, *currentBuilderContext); - if (const Expr *RetE = RS->getRetValue()) { - // Record the returned expression in the state. It will be used in - // processCallExit to bind the return value to the call expr. - { - static SimpleProgramPointTag tag("ExprEngine: ReturnStmt"); - const ProgramState *state = Pred->getState(); - state = state->set(RetE); - Pred = Bldr.generateNode(RetE, Pred, state, false, &tag); - } - // We may get a NULL Pred because we generated a cached node. - if (Pred) { - Bldr.takeNodes(Pred); - ExplodedNodeSet Tmp; - Visit(RetE, Pred, Tmp); - Bldr.addNodes(Tmp); - } + + ExplodedNodeSet dstPreVisit; + getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, RS, *this); + + StmtNodeBuilder B(dstPreVisit, Dst, *currentBuilderContext); + + if (RS->getRetValue()) { + for (ExplodedNodeSet::iterator it = dstPreVisit.begin(), + ei = dstPreVisit.end(); it != ei; ++it) { + B.generateNode(RS, *it, (*it)->getState()); } } - - getCheckerManager().runCheckersForPreStmt(Dst, Src, RS, *this); + else { + B.takeNodes(dstPreVisit); + } } diff --git a/test/Analysis/inline.c b/test/Analysis/inline.c index 2aac15661b..e3c7e83893 100644 --- a/test/Analysis/inline.c +++ b/test/Analysis/inline.c @@ -1,5 +1,4 @@ // RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-inline-call -analyzer-store region -verify %s -// XFAIL: * int test1_f1() { int y = 1; -- 2.40.0