ExprEngineCallAndReturn.cpp revision 500abad7edfcc2409b18dd616cdbc28a094926f5
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 // First handle the return value. 88 StmtNodeBuilder &Builder = Eng.getBuilder(); 89 assert(&Builder && "StmtNodeBuilder must be defined."); 90 91 // Get the callee. 92 const Expr *Callee = CE->getCallee()->IgnoreParens(); 93 const ProgramState *state = Pred->getState(); 94 SVal L = state->getSVal(Callee); 95 96 // Figure out the result type. We do this dance to handle references. 97 QualType ResultTy; 98 if (const FunctionDecl *FD = L.getAsFunctionDecl()) 99 ResultTy = FD->getResultType(); 100 else 101 ResultTy = CE->getType(); 102 103 if (CE->isLValue()) 104 ResultTy = Eng.getContext().getPointerType(ResultTy); 105 106 // Conjure a symbol value to use as the result. 107 SValBuilder &SVB = Eng.getSValBuilder(); 108 unsigned Count = Builder.getCurrentBlockCount(); 109 SVal RetVal = SVB.getConjuredSymbolVal(0, CE, ResultTy, Count); 110 111 // Generate a new ExplodedNode with the return value set. 112 state = state->BindExpr(CE, RetVal); 113 Pred = Builder.generateNode(CE, state, Pred); 114 115 // Then handle everything else. 116 unsigned oldSize = Dst.size(); 117 SaveOr OldHasGen(Builder.hasGeneratedNode); 118 119 // Dispatch to transfer function logic to handle the rest of the call. 120 Eng.getTF().evalCall(Dst, Eng, Builder, CE, L, Pred); 121 122 // Handle the case where no nodes where generated. Auto-generate that 123 // contains the updated state if we aren't generating sinks. 124 if (!Builder.BuildSinks && Dst.size() == oldSize && 125 !Builder.hasGeneratedNode) 126 Eng.MakeNode(Dst, CE, Pred, state); 127 } 128 }; 129 130 // Finally, evaluate the function call. We try each of the checkers 131 // to see if the can evaluate the function call. 132 ExplodedNodeSet dstCallEvaluated; 133 DefaultEval defEval(*this, CE); 134 getCheckerManager().runCheckersForEvalCall(dstCallEvaluated, 135 dstPreVisit, 136 CE, *this, &defEval); 137 138 // Finally, perform the post-condition check of the CallExpr and store 139 // the created nodes in 'Dst'. 140 getCheckerManager().runCheckersForPostStmt(dst, dstCallEvaluated, CE, 141 *this); 142} 143 144void ExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred, 145 ExplodedNodeSet &Dst) { 146 ExplodedNodeSet Src; 147 if (const Expr *RetE = RS->getRetValue()) { 148 // Record the returned expression in the state. It will be used in 149 // processCallExit to bind the return value to the call expr. 150 { 151 static SimpleProgramPointTag tag("ExprEngine: ReturnStmt"); 152 const ProgramState *state = Pred->getState(); 153 state = state->set<ReturnExpr>(RetE); 154 Pred = Builder->generateNode(RetE, state, Pred, &tag); 155 } 156 // We may get a NULL Pred because we generated a cached node. 157 if (Pred) 158 Visit(RetE, Pred, Src); 159 } 160 else { 161 Src.Add(Pred); 162 } 163 164 ExplodedNodeSet CheckedSet; 165 getCheckerManager().runCheckersForPreStmt(CheckedSet, Src, RS, *this); 166 167 for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); 168 I != E; ++I) { 169 170 assert(Builder && "StmtNodeBuilder must be defined."); 171 172 Pred = *I; 173 unsigned size = Dst.size(); 174 175 SaveAndRestore<bool> OldSink(Builder->BuildSinks); 176 SaveOr OldHasGen(Builder->hasGeneratedNode); 177 178 getTF().evalReturn(Dst, *this, *Builder, RS, Pred); 179 180 // Handle the case where no nodes where generated. 181 if (!Builder->BuildSinks && Dst.size() == size && 182 !Builder->hasGeneratedNode) 183 MakeNode(Dst, RS, Pred, Pred->getState()); 184 } 185} 186