ExprEngineCallAndReturn.cpp revision 5eca482fe895ea57bc82410222e6426c09e63284
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/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h" 17#include "clang/AST/DeclCXX.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 const LocationContext *LCtx = Pred->getLocationContext(); 48 SVal RetVal = state->getSVal(ReturnedExpr, LCtx); 49 state = state->BindExpr(CE, LCtx, RetVal); 50 // Clear the return expr GDM. 51 state = state->remove<ReturnExpr>(); 52 } 53 54 // Bind the constructed object value to CXXConstructExpr. 55 if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(CE)) { 56 const CXXThisRegion *ThisR = 57 getCXXThisRegion(CCE->getConstructor()->getParent(), calleeCtx); 58 59 SVal ThisV = state->getSVal(ThisR); 60 // Always bind the region to the CXXConstructExpr. 61 state = state->BindExpr(CCE, Pred->getLocationContext(), ThisV); 62 } 63 64 B.generateNode(state); 65} 66 67static bool isPointerToConst(const ParmVarDecl *ParamDecl) { 68 QualType PointeeTy = ParamDecl->getOriginalType()->getPointeeType(); 69 if (PointeeTy != QualType() && PointeeTy.isConstQualified() && 70 !PointeeTy->isAnyPointerType() && !PointeeTy->isReferenceType()) { 71 return true; 72 } 73 return false; 74} 75 76// Try to retrieve the function declaration and find the function parameter 77// types which are pointers/references to a non-pointer const. 78// We do not invalidate the corresponding argument regions. 79static void findPtrToConstParams(llvm::SmallSet<unsigned, 1> &PreserveArgs, 80 const CallOrObjCMessage &Call) { 81 const Decl *CallDecl = Call.getDecl(); 82 if (!CallDecl) 83 return; 84 85 if (const FunctionDecl *FDecl = dyn_cast<FunctionDecl>(CallDecl)) { 86 for (unsigned Idx = 0, E = Call.getNumArgs(); Idx != E; ++Idx) { 87 if (FDecl && Idx < FDecl->getNumParams()) { 88 if (isPointerToConst(FDecl->getParamDecl(Idx))) 89 PreserveArgs.insert(Idx); 90 } 91 } 92 return; 93 } 94 95 if (const ObjCMethodDecl *MDecl = dyn_cast<ObjCMethodDecl>(CallDecl)) { 96 assert(MDecl->param_size() <= Call.getNumArgs()); 97 unsigned Idx = 0; 98 for (clang::ObjCMethodDecl::param_const_iterator 99 I = MDecl->param_begin(), E = MDecl->param_end(); I != E; ++I, ++Idx) { 100 if (isPointerToConst(*I)) 101 PreserveArgs.insert(Idx); 102 } 103 return; 104 } 105} 106 107const ProgramState * 108ExprEngine::invalidateArguments(const ProgramState *State, 109 const CallOrObjCMessage &Call, 110 const LocationContext *LC) { 111 SmallVector<const MemRegion *, 8> RegionsToInvalidate; 112 113 if (Call.isObjCMessage()) { 114 // Invalidate all instance variables of the receiver of an ObjC message. 115 // FIXME: We should be able to do better with inter-procedural analysis. 116 if (const MemRegion *MR = Call.getInstanceMessageReceiver(LC).getAsRegion()) 117 RegionsToInvalidate.push_back(MR); 118 119 } else if (Call.isCXXCall()) { 120 // Invalidate all instance variables for the callee of a C++ method call. 121 // FIXME: We should be able to do better with inter-procedural analysis. 122 // FIXME: We can probably do better for const versus non-const methods. 123 if (const MemRegion *Callee = Call.getCXXCallee().getAsRegion()) 124 RegionsToInvalidate.push_back(Callee); 125 126 } else if (Call.isFunctionCall()) { 127 // Block calls invalidate all captured-by-reference values. 128 SVal CalleeVal = Call.getFunctionCallee(); 129 if (const MemRegion *Callee = CalleeVal.getAsRegion()) { 130 if (isa<BlockDataRegion>(Callee)) 131 RegionsToInvalidate.push_back(Callee); 132 } 133 } 134 135 // Indexes of arguments whose values will be preserved by the call. 136 llvm::SmallSet<unsigned, 1> PreserveArgs; 137 findPtrToConstParams(PreserveArgs, Call); 138 139 for (unsigned idx = 0, e = Call.getNumArgs(); idx != e; ++idx) { 140 if (PreserveArgs.count(idx)) 141 continue; 142 143 SVal V = Call.getArgSVal(idx); 144 145 // If we are passing a location wrapped as an integer, unwrap it and 146 // invalidate the values referred by the location. 147 if (nonloc::LocAsInteger *Wrapped = dyn_cast<nonloc::LocAsInteger>(&V)) 148 V = Wrapped->getLoc(); 149 else if (!isa<Loc>(V)) 150 continue; 151 152 if (const MemRegion *R = V.getAsRegion()) { 153 // Invalidate the value of the variable passed by reference. 154 155 // Are we dealing with an ElementRegion? If the element type is 156 // a basic integer type (e.g., char, int) and the underlying region 157 // is a variable region then strip off the ElementRegion. 158 // FIXME: We really need to think about this for the general case 159 // as sometimes we are reasoning about arrays and other times 160 // about (char*), etc., is just a form of passing raw bytes. 161 // e.g., void *p = alloca(); foo((char*)p); 162 if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) { 163 // Checking for 'integral type' is probably too promiscuous, but 164 // we'll leave it in for now until we have a systematic way of 165 // handling all of these cases. Eventually we need to come up 166 // with an interface to StoreManager so that this logic can be 167 // appropriately delegated to the respective StoreManagers while 168 // still allowing us to do checker-specific logic (e.g., 169 // invalidating reference counts), probably via callbacks. 170 if (ER->getElementType()->isIntegralOrEnumerationType()) { 171 const MemRegion *superReg = ER->getSuperRegion(); 172 if (isa<VarRegion>(superReg) || isa<FieldRegion>(superReg) || 173 isa<ObjCIvarRegion>(superReg)) 174 R = cast<TypedRegion>(superReg); 175 } 176 // FIXME: What about layers of ElementRegions? 177 } 178 179 // Mark this region for invalidation. We batch invalidate regions 180 // below for efficiency. 181 RegionsToInvalidate.push_back(R); 182 } else { 183 // Nuke all other arguments passed by reference. 184 // FIXME: is this necessary or correct? This handles the non-Region 185 // cases. Is it ever valid to store to these? 186 State = State->unbindLoc(cast<Loc>(V)); 187 } 188 } 189 190 // Invalidate designated regions using the batch invalidation API. 191 192 // FIXME: We can have collisions on the conjured symbol if the 193 // expression *I also creates conjured symbols. We probably want 194 // to identify conjured symbols by an expression pair: the enclosing 195 // expression (the context) and the expression itself. This should 196 // disambiguate conjured symbols. 197 unsigned Count = currentBuilderContext->getCurrentBlockCount(); 198 StoreManager::InvalidatedSymbols IS; 199 200 // NOTE: Even if RegionsToInvalidate is empty, we may still invalidate 201 // global variables. 202 return State->invalidateRegions(RegionsToInvalidate, 203 Call.getOriginExpr(), Count, 204 &IS, &Call); 205 206} 207 208void ExprEngine::VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred, 209 ExplodedNodeSet &dst) { 210 // Perform the previsit of the CallExpr. 211 ExplodedNodeSet dstPreVisit; 212 getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, CE, *this); 213 214 // Now evaluate the call itself. 215 class DefaultEval : public GraphExpander { 216 ExprEngine &Eng; 217 const CallExpr *CE; 218 public: 219 220 DefaultEval(ExprEngine &eng, const CallExpr *ce) 221 : Eng(eng), CE(ce) {} 222 virtual void expandGraph(ExplodedNodeSet &Dst, ExplodedNode *Pred) { 223 // Should we inline the call? 224 if (Eng.getAnalysisManager().shouldInlineCall() && 225 Eng.InlineCall(Dst, CE, Pred)) { 226 return; 227 } 228 229 // First handle the return value. 230 StmtNodeBuilder Bldr(Pred, Dst, *Eng.currentBuilderContext); 231 232 // Get the callee. 233 const Expr *Callee = CE->getCallee()->IgnoreParens(); 234 const ProgramState *state = Pred->getState(); 235 SVal L = state->getSVal(Callee, Pred->getLocationContext()); 236 237 // Figure out the result type. We do this dance to handle references. 238 QualType ResultTy; 239 if (const FunctionDecl *FD = L.getAsFunctionDecl()) 240 ResultTy = FD->getResultType(); 241 else 242 ResultTy = CE->getType(); 243 244 if (CE->isLValue()) 245 ResultTy = Eng.getContext().getPointerType(ResultTy); 246 247 // Conjure a symbol value to use as the result. 248 SValBuilder &SVB = Eng.getSValBuilder(); 249 unsigned Count = Eng.currentBuilderContext->getCurrentBlockCount(); 250 SVal RetVal = SVB.getConjuredSymbolVal(0, CE, ResultTy, Count); 251 252 // Generate a new state with the return value set. 253 const LocationContext *LCtx = Pred->getLocationContext(); 254 state = state->BindExpr(CE, LCtx, RetVal); 255 256 // Invalidate the arguments. 257 state = Eng.invalidateArguments(state, CallOrObjCMessage(CE, state, LCtx), 258 LCtx); 259 260 // And make the result node. 261 Bldr.generateNode(CE, Pred, state); 262 } 263 }; 264 265 // Finally, evaluate the function call. We try each of the checkers 266 // to see if the can evaluate the function call. 267 ExplodedNodeSet dstCallEvaluated; 268 DefaultEval defEval(*this, CE); 269 getCheckerManager().runCheckersForEvalCall(dstCallEvaluated, 270 dstPreVisit, 271 CE, *this, &defEval); 272 273 // Finally, perform the post-condition check of the CallExpr and store 274 // the created nodes in 'Dst'. 275 getCheckerManager().runCheckersForPostStmt(dst, dstCallEvaluated, CE, 276 *this); 277} 278 279void ExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred, 280 ExplodedNodeSet &Dst) { 281 ExplodedNodeSet Src; 282 { 283 StmtNodeBuilder Bldr(Pred, Src, *currentBuilderContext); 284 if (const Expr *RetE = RS->getRetValue()) { 285 // Record the returned expression in the state. It will be used in 286 // processCallExit to bind the return value to the call expr. 287 { 288 static SimpleProgramPointTag tag("ExprEngine: ReturnStmt"); 289 const ProgramState *state = Pred->getState(); 290 state = state->set<ReturnExpr>(RetE); 291 Pred = Bldr.generateNode(RetE, Pred, state, false, &tag); 292 } 293 // We may get a NULL Pred because we generated a cached node. 294 if (Pred) { 295 Bldr.takeNodes(Pred); 296 ExplodedNodeSet Tmp; 297 Visit(RetE, Pred, Tmp); 298 Bldr.addNodes(Tmp); 299 } 300 } 301 } 302 303 getCheckerManager().runCheckersForPreStmt(Dst, Src, RS, *this); 304} 305