ExprEngineCallAndReturn.cpp revision 294fd0a62b95f512637910bf85c7efa6c2354b50
1//=-- ExprEngineCallAndReturn.cpp - Support for call/return -----*- C++ -*-===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file defines ExprEngine's support for calls and returns. 11// 12//===----------------------------------------------------------------------===// 13 14#include "clang/StaticAnalyzer/Core/CheckerManager.h" 15#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" 16#include "clang/AST/DeclCXX.h" 17#include "clang/Analysis/Support/SaveAndRestore.h" 18 19using namespace clang; 20using namespace ento; 21 22namespace { 23 // Trait class for recording returned expression in the state. 24 struct ReturnExpr { 25 static int TagInt; 26 typedef const Stmt *data_type; 27 }; 28 int ReturnExpr::TagInt; 29} 30 31void ExprEngine::processCallEnter(CallEnterNodeBuilder &B) { 32 const ProgramState *state = 33 B.getState()->enterStackFrame(B.getCalleeContext()); 34 B.generateNode(state); 35} 36 37void ExprEngine::processCallExit(CallExitNodeBuilder &B) { 38 const ProgramState *state = B.getState(); 39 const ExplodedNode *Pred = B.getPredecessor(); 40 const StackFrameContext *calleeCtx = 41 cast<StackFrameContext>(Pred->getLocationContext()); 42 const Stmt *CE = calleeCtx->getCallSite(); 43 44 // If the callee returns an expression, bind its value to CallExpr. 45 const Stmt *ReturnedExpr = state->get<ReturnExpr>(); 46 if (ReturnedExpr) { 47 SVal RetVal = state->getSVal(ReturnedExpr); 48 state = state->BindExpr(CE, RetVal); 49 // Clear the return expr GDM. 50 state = state->remove<ReturnExpr>(); 51 } 52 53 // Bind the constructed object value to CXXConstructExpr. 54 if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(CE)) { 55 const CXXThisRegion *ThisR = 56 getCXXThisRegion(CCE->getConstructor()->getParent(), calleeCtx); 57 58 SVal ThisV = state->getSVal(ThisR); 59 // Always bind the region to the CXXConstructExpr. 60 state = state->BindExpr(CCE, ThisV); 61 } 62 63 B.generateNode(state); 64} 65 66void ExprEngine::VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred, 67 ExplodedNodeSet &dst) { 68 // Perform the previsit of the CallExpr. 69 ExplodedNodeSet dstPreVisit; 70 getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, CE, *this); 71 72 // Now evaluate the call itself. 73 class DefaultEval : public GraphExpander { 74 ExprEngine &Eng; 75 const CallExpr *CE; 76 public: 77 78 DefaultEval(ExprEngine &eng, const CallExpr *ce) 79 : Eng(eng), CE(ce) {} 80 virtual void expandGraph(ExplodedNodeSet &Dst, ExplodedNode *Pred) { 81 // Should we inline the call? 82 if (Eng.getAnalysisManager().shouldInlineCall() && 83 Eng.InlineCall(Dst, CE, Pred)) { 84 return; 85 } 86 87 StmtNodeBuilder &Builder = Eng.getBuilder(); 88 assert(&Builder && "StmtNodeBuilder must be defined."); 89 90 // Dispatch to the plug-in transfer function. 91 unsigned oldSize = Dst.size(); 92 SaveOr OldHasGen(Builder.hasGeneratedNode); 93 94 // Dispatch to transfer function logic to handle the call itself. 95 const Expr *Callee = CE->getCallee()->IgnoreParens(); 96 const ProgramState *state = Pred->getState(); 97 SVal L = state->getSVal(Callee); 98 Eng.getTF().evalCall(Dst, Eng, Builder, CE, L, Pred); 99 100 // Handle the case where no nodes where generated. Auto-generate that 101 // contains the updated state if we aren't generating sinks. 102 if (!Builder.BuildSinks && Dst.size() == oldSize && 103 !Builder.hasGeneratedNode) 104 Eng.MakeNode(Dst, CE, Pred, state); 105 } 106 }; 107 108 // Finally, evaluate the function call. We try each of the checkers 109 // to see if the can evaluate the function call. 110 ExplodedNodeSet dstCallEvaluated; 111 DefaultEval defEval(*this, CE); 112 getCheckerManager().runCheckersForEvalCall(dstCallEvaluated, 113 dstPreVisit, 114 CE, *this, &defEval); 115 116 // Finally, perform the post-condition check of the CallExpr and store 117 // the created nodes in 'Dst'. 118 getCheckerManager().runCheckersForPostStmt(dst, dstCallEvaluated, CE, 119 *this); 120} 121 122void ExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred, 123 ExplodedNodeSet &Dst) { 124 ExplodedNodeSet Src; 125 if (const Expr *RetE = RS->getRetValue()) { 126 // Record the returned expression in the state. It will be used in 127 // processCallExit to bind the return value to the call expr. 128 { 129 static SimpleProgramPointTag tag("ExprEngine: ReturnStmt"); 130 const ProgramState *state = Pred->getState(); 131 state = state->set<ReturnExpr>(RetE); 132 Pred = Builder->generateNode(RetE, state, Pred, &tag); 133 } 134 // We may get a NULL Pred because we generated a cached node. 135 if (Pred) 136 Visit(RetE, Pred, Src); 137 } 138 else { 139 Src.Add(Pred); 140 } 141 142 ExplodedNodeSet CheckedSet; 143 getCheckerManager().runCheckersForPreStmt(CheckedSet, Src, RS, *this); 144 145 for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); 146 I != E; ++I) { 147 148 assert(Builder && "StmtNodeBuilder must be defined."); 149 150 Pred = *I; 151 unsigned size = Dst.size(); 152 153 SaveAndRestore<bool> OldSink(Builder->BuildSinks); 154 SaveOr OldHasGen(Builder->hasGeneratedNode); 155 156 getTF().evalReturn(Dst, *this, *Builder, RS, Pred); 157 158 // Handle the case where no nodes where generated. 159 if (!Builder->BuildSinks && Dst.size() == size && 160 !Builder->hasGeneratedNode) 161 MakeNode(Dst, RS, Pred, Pred->getState()); 162 } 163} 164