1 //===- ExprEngineCXX.cpp - ExprEngine support for C++ -----------*- 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 the C++ expression evaluation engine. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 15 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" 16 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" 17 #include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h" 18 #include "clang/AST/DeclCXX.h" 19 20 using namespace clang; 21 using namespace ento; 22 23 namespace { 24 class CallExprWLItem { 25 public: 26 CallExpr::const_arg_iterator I; 27 ExplodedNode *N; 28 29 CallExprWLItem(const CallExpr::const_arg_iterator &i, ExplodedNode *n) 30 : I(i), N(n) {} 31 }; 32 } 33 34 void ExprEngine::evalArguments(ConstExprIterator AI, ConstExprIterator AE, 35 const FunctionProtoType *FnType, 36 ExplodedNode *Pred, ExplodedNodeSet &Dst, 37 bool FstArgAsLValue) { 38 39 40 SmallVector<CallExprWLItem, 20> WorkList; 41 WorkList.reserve(AE - AI); 42 WorkList.push_back(CallExprWLItem(AI, Pred)); 43 44 while (!WorkList.empty()) { 45 CallExprWLItem Item = WorkList.back(); 46 WorkList.pop_back(); 47 48 if (Item.I == AE) { 49 Dst.insert(Item.N); 50 continue; 51 } 52 53 // Evaluate the argument. 54 ExplodedNodeSet Tmp; 55 if (FstArgAsLValue) { 56 FstArgAsLValue = false; 57 } 58 59 Visit(*Item.I, Item.N, Tmp); 60 ++(Item.I); 61 for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI != NE; ++NI) 62 WorkList.push_back(CallExprWLItem(Item.I, *NI)); 63 } 64 } 65 66 void ExprEngine::evalCallee(const CallExpr *callExpr, 67 const ExplodedNodeSet &src, 68 ExplodedNodeSet &dest) { 69 70 const Expr *callee = 0; 71 72 switch (callExpr->getStmtClass()) { 73 case Stmt::CXXMemberCallExprClass: { 74 // Evaluate the implicit object argument that is the recipient of the 75 // call. 76 callee = cast<CXXMemberCallExpr>(callExpr)->getImplicitObjectArgument(); 77 78 // FIXME: handle member pointers. 79 if (!callee) 80 return; 81 82 break; 83 } 84 default: { 85 callee = callExpr->getCallee()->IgnoreParens(); 86 break; 87 } 88 } 89 90 for (ExplodedNodeSet::iterator i = src.begin(), e = src.end(); i != e; ++i) 91 Visit(callee, *i, dest); 92 } 93 94 const CXXThisRegion *ExprEngine::getCXXThisRegion(const CXXRecordDecl *D, 95 const StackFrameContext *SFC) { 96 const Type *T = D->getTypeForDecl(); 97 QualType PT = getContext().getPointerType(QualType(T, 0)); 98 return svalBuilder.getRegionManager().getCXXThisRegion(PT, SFC); 99 } 100 101 const CXXThisRegion *ExprEngine::getCXXThisRegion(const CXXMethodDecl *decl, 102 const StackFrameContext *frameCtx) { 103 return svalBuilder.getRegionManager(). 104 getCXXThisRegion(decl->getThisType(getContext()), frameCtx); 105 } 106 107 void ExprEngine::CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME, 108 ExplodedNode *Pred, 109 ExplodedNodeSet &Dst) { 110 StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext); 111 const Expr *tempExpr = ME->GetTemporaryExpr()->IgnoreParens(); 112 const ProgramState *state = Pred->getState(); 113 114 // Bind the temporary object to the value of the expression. Then bind 115 // the expression to the location of the object. 116 SVal V = state->getSVal(tempExpr); 117 118 const MemRegion *R = 119 svalBuilder.getRegionManager().getCXXTempObjectRegion(ME, 120 Pred->getLocationContext()); 121 122 state = state->bindLoc(loc::MemRegionVal(R), V); 123 Bldr.generateNode(ME, Pred, state->BindExpr(ME, loc::MemRegionVal(R))); 124 } 125 126 void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, 127 const MemRegion *Dest, 128 ExplodedNode *Pred, 129 ExplodedNodeSet &destNodes) { 130 131 const CXXConstructorDecl *CD = E->getConstructor(); 132 assert(CD); 133 134 #if 0 135 if (!(CD->doesThisDeclarationHaveABody() && AMgr.shouldInlineCall())) 136 // FIXME: invalidate the object. 137 return; 138 #endif 139 140 // Evaluate other arguments. 141 ExplodedNodeSet argsEvaluated; 142 const FunctionProtoType *FnType = CD->getType()->getAs<FunctionProtoType>(); 143 evalArguments(E->arg_begin(), E->arg_end(), FnType, Pred, argsEvaluated); 144 145 #if 0 146 // Is the constructor elidable? 147 if (E->isElidable()) { 148 VisitAggExpr(E->getArg(0), destNodes, Pred, Dst); 149 // FIXME: this is here to force propagation if VisitAggExpr doesn't 150 if (destNodes.empty()) 151 destNodes.Add(Pred); 152 return; 153 } 154 #endif 155 156 // Perform the previsit of the constructor. 157 ExplodedNodeSet destPreVisit; 158 getCheckerManager().runCheckersForPreStmt(destPreVisit, argsEvaluated, E, 159 *this); 160 161 // Evaluate the constructor. Currently we don't now allow checker-specific 162 // implementations of specific constructors (as we do with ordinary 163 // function calls. We can re-evaluate this in the future. 164 165 #if 0 166 // Inlining currently isn't fully implemented. 167 168 if (AMgr.shouldInlineCall()) { 169 if (!Dest) 170 Dest = 171 svalBuilder.getRegionManager().getCXXTempObjectRegion(E, 172 Pred->getLocationContext()); 173 174 // The callee stack frame context used to create the 'this' 175 // parameter region. 176 const StackFrameContext *SFC = 177 AMgr.getStackFrame(CD, Pred->getLocationContext(), 178 E, currentBuilderContext->getBlock(), 179 currentStmtIdx); 180 181 // Create the 'this' region. 182 const CXXThisRegion *ThisR = 183 getCXXThisRegion(E->getConstructor()->getParent(), SFC); 184 185 CallEnter Loc(E, SFC, Pred->getLocationContext()); 186 187 StmtNodeBuilder Bldr(argsEvaluated, destNodes, *currentBuilderContext); 188 for (ExplodedNodeSet::iterator NI = argsEvaluated.begin(), 189 NE = argsEvaluated.end(); NI != NE; ++NI) { 190 const ProgramState *state = (*NI)->getState(); 191 // Setup 'this' region, so that the ctor is evaluated on the object pointed 192 // by 'Dest'. 193 state = state->bindLoc(loc::MemRegionVal(ThisR), loc::MemRegionVal(Dest)); 194 Bldr.generateNode(Loc, *NI, state); 195 } 196 } 197 #endif 198 199 // Default semantics: invalidate all regions passed as arguments. 200 ExplodedNodeSet destCall; 201 { 202 StmtNodeBuilder Bldr(destPreVisit, destCall, *currentBuilderContext); 203 for (ExplodedNodeSet::iterator 204 i = destPreVisit.begin(), e = destPreVisit.end(); 205 i != e; ++i) 206 { 207 ExplodedNode *Pred = *i; 208 const LocationContext *LC = Pred->getLocationContext(); 209 const ProgramState *state = Pred->getState(); 210 211 state = invalidateArguments(state, CallOrObjCMessage(E, state), LC); 212 Bldr.generateNode(E, Pred, state); 213 } 214 } 215 // Do the post visit. 216 getCheckerManager().runCheckersForPostStmt(destNodes, destCall, E, *this); 217 } 218 219 void ExprEngine::VisitCXXDestructor(const CXXDestructorDecl *DD, 220 const MemRegion *Dest, 221 const Stmt *S, 222 ExplodedNode *Pred, 223 ExplodedNodeSet &Dst) { 224 StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext); 225 if (!(DD->doesThisDeclarationHaveABody() && AMgr.shouldInlineCall())) 226 return; 227 228 // Create the context for 'this' region. 229 const StackFrameContext *SFC = 230 AnalysisDeclContexts.getContext(DD)-> 231 getStackFrame(Pred->getLocationContext(), S, 232 currentBuilderContext->getBlock(), currentStmtIdx); 233 234 const CXXThisRegion *ThisR = getCXXThisRegion(DD->getParent(), SFC); 235 236 CallEnter PP(S, SFC, Pred->getLocationContext()); 237 238 const ProgramState *state = Pred->getState(); 239 state = state->bindLoc(loc::MemRegionVal(ThisR), loc::MemRegionVal(Dest)); 240 Bldr.generateNode(PP, Pred, state); 241 } 242 243 void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, 244 ExplodedNodeSet &Dst) { 245 StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext); 246 247 unsigned blockCount = currentBuilderContext->getCurrentBlockCount(); 248 DefinedOrUnknownSVal symVal = 249 svalBuilder.getConjuredSymbolVal(NULL, CNE, CNE->getType(), blockCount); 250 const MemRegion *NewReg = cast<loc::MemRegionVal>(symVal).getRegion(); 251 QualType ObjTy = CNE->getType()->getAs<PointerType>()->getPointeeType(); 252 const ElementRegion *EleReg = 253 getStoreManager().GetElementZeroRegion(NewReg, ObjTy); 254 255 if (CNE->isArray()) { 256 // FIXME: allocating an array requires simulating the constructors. 257 // For now, just return a symbolicated region. 258 const ProgramState *state = Pred->getState(); 259 state = state->BindExpr(CNE, loc::MemRegionVal(EleReg)); 260 Bldr.generateNode(CNE, Pred, state); 261 return; 262 } 263 264 // Evaluate constructor arguments. 265 const FunctionProtoType *FnType = NULL; 266 const CXXConstructorDecl *CD = CNE->getConstructor(); 267 if (CD) 268 FnType = CD->getType()->getAs<FunctionProtoType>(); 269 ExplodedNodeSet argsEvaluated; 270 Bldr.takeNodes(Pred); 271 evalArguments(CNE->constructor_arg_begin(), CNE->constructor_arg_end(), 272 FnType, Pred, argsEvaluated); 273 Bldr.addNodes(argsEvaluated); 274 275 // Initialize the object region and bind the 'new' expression. 276 for (ExplodedNodeSet::iterator I = argsEvaluated.begin(), 277 E = argsEvaluated.end(); I != E; ++I) { 278 279 const ProgramState *state = (*I)->getState(); 280 281 // Accumulate list of regions that are invalidated. 282 // FIXME: Eventually we should unify the logic for constructor 283 // processing in one place. 284 SmallVector<const MemRegion*, 10> regionsToInvalidate; 285 for (CXXNewExpr::const_arg_iterator 286 ai = CNE->constructor_arg_begin(), ae = CNE->constructor_arg_end(); 287 ai != ae; ++ai) 288 { 289 SVal val = state->getSVal(*ai); 290 if (const MemRegion *region = val.getAsRegion()) 291 regionsToInvalidate.push_back(region); 292 } 293 294 if (ObjTy->isRecordType()) { 295 regionsToInvalidate.push_back(EleReg); 296 // Invalidate the regions. 297 state = state->invalidateRegions(regionsToInvalidate, 298 CNE, blockCount, 0, 299 /* invalidateGlobals = */ true); 300 301 } else { 302 // Invalidate the regions. 303 state = state->invalidateRegions(regionsToInvalidate, 304 CNE, blockCount, 0, 305 /* invalidateGlobals = */ true); 306 307 if (CNE->hasInitializer()) { 308 SVal V = state->getSVal(*CNE->constructor_arg_begin()); 309 state = state->bindLoc(loc::MemRegionVal(EleReg), V); 310 } else { 311 // Explicitly set to undefined, because currently we retrieve symbolic 312 // value from symbolic region. 313 state = state->bindLoc(loc::MemRegionVal(EleReg), UndefinedVal()); 314 } 315 } 316 state = state->BindExpr(CNE, loc::MemRegionVal(EleReg)); 317 Bldr.generateNode(CNE, *I, state); 318 } 319 } 320 321 void ExprEngine::VisitCXXDeleteExpr(const CXXDeleteExpr *CDE, 322 ExplodedNode *Pred, ExplodedNodeSet &Dst) { 323 // Should do more checking. 324 ExplodedNodeSet Argevaluated; 325 Visit(CDE->getArgument(), Pred, Argevaluated); 326 StmtNodeBuilder Bldr(Argevaluated, Dst, *currentBuilderContext); 327 for (ExplodedNodeSet::iterator I = Argevaluated.begin(), 328 E = Argevaluated.end(); I != E; ++I) { 329 const ProgramState *state = (*I)->getState(); 330 Bldr.generateNode(CDE, *I, state); 331 } 332 } 333 334 void ExprEngine::VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred, 335 ExplodedNodeSet &Dst) { 336 StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext); 337 338 // Get the this object region from StoreManager. 339 const MemRegion *R = 340 svalBuilder.getRegionManager().getCXXThisRegion( 341 getContext().getCanonicalType(TE->getType()), 342 Pred->getLocationContext()); 343 344 const ProgramState *state = Pred->getState(); 345 SVal V = state->getSVal(loc::MemRegionVal(R)); 346 Bldr.generateNode(TE, Pred, state->BindExpr(TE, V)); 347 } 348