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