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