ExprEngineCXX.cpp revision ebae6d0209e1ec3d5ea14f9e63bd0d740218ed14
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 20using namespace clang; 21using namespace ento; 22 23namespace { 24class CallExprWLItem { 25public: 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 34void 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 66void 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 94const 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 101const CXXThisRegion *ExprEngine::getCXXThisRegion(const CXXMethodDecl *decl, 102 const StackFrameContext *frameCtx) { 103 return svalBuilder.getRegionManager(). 104 getCXXThisRegion(decl->getThisType(getContext()), frameCtx); 105} 106 107void ExprEngine::CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME, 108 ExplodedNode *Pred, 109 ExplodedNodeSet &Dst) { 110 PureStmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext, Builder); 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 126void 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 PureStmtNodeBuilder 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 PureStmtNodeBuilder Bldr(destPreVisit, destCall, 203 *currentBuilderContext, Builder); 204 for (ExplodedNodeSet::iterator 205 i = destPreVisit.begin(), e = destPreVisit.end(); 206 i != e; ++i) 207 { 208 ExplodedNode *Pred = *i; 209 const LocationContext *LC = Pred->getLocationContext(); 210 const ProgramState *state = Pred->getState(); 211 212 state = invalidateArguments(state, CallOrObjCMessage(E, state), LC); 213 Bldr.generateNode(E, Pred, state); 214 } 215 } 216 // Do the post visit. 217 getCheckerManager().runCheckersForPostStmt(destNodes, destCall, E, *this); 218} 219 220void ExprEngine::VisitCXXDestructor(const CXXDestructorDecl *DD, 221 const MemRegion *Dest, 222 const Stmt *S, 223 ExplodedNode *Pred, 224 ExplodedNodeSet &Dst) { 225 PureStmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext, Builder); 226 if (!(DD->doesThisDeclarationHaveABody() && AMgr.shouldInlineCall())) 227 return; 228 229 // Create the context for 'this' region. 230 const StackFrameContext *SFC = 231 AnalysisDeclContexts.getContext(DD)-> 232 getStackFrame(Pred->getLocationContext(), S, 233 currentBuilderContext->getBlock(), currentStmtIdx); 234 235 const CXXThisRegion *ThisR = getCXXThisRegion(DD->getParent(), SFC); 236 237 CallEnter PP(S, SFC, Pred->getLocationContext()); 238 239 const ProgramState *state = Pred->getState(); 240 state = state->bindLoc(loc::MemRegionVal(ThisR), loc::MemRegionVal(Dest)); 241 Bldr.generateNode(PP, Pred, state); 242} 243 244void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, 245 ExplodedNodeSet &Dst) { 246 PureStmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext, Builder); 247 248 unsigned blockCount = currentBuilderContext->getCurrentBlockCount(); 249 DefinedOrUnknownSVal symVal = 250 svalBuilder.getConjuredSymbolVal(NULL, CNE, CNE->getType(), blockCount); 251 const MemRegion *NewReg = cast<loc::MemRegionVal>(symVal).getRegion(); 252 QualType ObjTy = CNE->getType()->getAs<PointerType>()->getPointeeType(); 253 const ElementRegion *EleReg = 254 getStoreManager().GetElementZeroRegion(NewReg, ObjTy); 255 256 if (CNE->isArray()) { 257 // FIXME: allocating an array requires simulating the constructors. 258 // For now, just return a symbolicated region. 259 const ProgramState *state = Pred->getState(); 260 state = state->BindExpr(CNE, loc::MemRegionVal(EleReg)); 261 Bldr.generateNode(CNE, Pred, state); 262 return; 263 } 264 265 // Evaluate constructor arguments. 266 const FunctionProtoType *FnType = NULL; 267 const CXXConstructorDecl *CD = CNE->getConstructor(); 268 if (CD) 269 FnType = CD->getType()->getAs<FunctionProtoType>(); 270 ExplodedNodeSet argsEvaluated; 271 Bldr.takeNodes(Pred); 272 evalArguments(CNE->constructor_arg_begin(), CNE->constructor_arg_end(), 273 FnType, Pred, argsEvaluated); 274 Bldr.addNodes(argsEvaluated); 275 276 // Initialize the object region and bind the 'new' expression. 277 for (ExplodedNodeSet::iterator I = argsEvaluated.begin(), 278 E = argsEvaluated.end(); I != E; ++I) { 279 280 const ProgramState *state = (*I)->getState(); 281 282 // Accumulate list of regions that are invalidated. 283 // FIXME: Eventually we should unify the logic for constructor 284 // processing in one place. 285 SmallVector<const MemRegion*, 10> regionsToInvalidate; 286 for (CXXNewExpr::const_arg_iterator 287 ai = CNE->constructor_arg_begin(), ae = CNE->constructor_arg_end(); 288 ai != ae; ++ai) 289 { 290 SVal val = state->getSVal(*ai); 291 if (const MemRegion *region = val.getAsRegion()) 292 regionsToInvalidate.push_back(region); 293 } 294 295 if (ObjTy->isRecordType()) { 296 regionsToInvalidate.push_back(EleReg); 297 // Invalidate the regions. 298 state = state->invalidateRegions(regionsToInvalidate, 299 CNE, blockCount, 0, 300 /* invalidateGlobals = */ true); 301 302 } else { 303 // Invalidate the regions. 304 state = state->invalidateRegions(regionsToInvalidate, 305 CNE, blockCount, 0, 306 /* invalidateGlobals = */ true); 307 308 if (CNE->hasInitializer()) { 309 SVal V = state->getSVal(*CNE->constructor_arg_begin()); 310 state = state->bindLoc(loc::MemRegionVal(EleReg), V); 311 } else { 312 // Explicitly set to undefined, because currently we retrieve symbolic 313 // value from symbolic region. 314 state = state->bindLoc(loc::MemRegionVal(EleReg), UndefinedVal()); 315 } 316 } 317 state = state->BindExpr(CNE, loc::MemRegionVal(EleReg)); 318 Bldr.generateNode(CNE, *I, state); 319 } 320} 321 322void ExprEngine::VisitCXXDeleteExpr(const CXXDeleteExpr *CDE, 323 ExplodedNode *Pred, ExplodedNodeSet &Dst) { 324 // Should do more checking. 325 ExplodedNodeSet Argevaluated; 326 Visit(CDE->getArgument(), Pred, Argevaluated); 327 PureStmtNodeBuilder Bldr(Argevaluated, Dst, *currentBuilderContext, Builder); 328 for (ExplodedNodeSet::iterator I = Argevaluated.begin(), 329 E = Argevaluated.end(); I != E; ++I) { 330 const ProgramState *state = (*I)->getState(); 331 Bldr.generateNode(CDE, *I, state); 332 } 333} 334 335void ExprEngine::VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred, 336 ExplodedNodeSet &Dst) { 337 PureStmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext, Builder); 338 339 // Get the this object region from StoreManager. 340 const MemRegion *R = 341 svalBuilder.getRegionManager().getCXXThisRegion( 342 getContext().getCanonicalType(TE->getType()), 343 Pred->getLocationContext()); 344 345 const ProgramState *state = Pred->getState(); 346 SVal V = state->getSVal(loc::MemRegionVal(R)); 347 Bldr.generateNode(TE, Pred, state->BindExpr(TE, V)); 348} 349