ExprEngineCXX.cpp revision 537716ad8dd10f984b6cfe6985afade1185c5e3c
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, 233 E, blockCount, 0, 234 /* invalidateGlobals = */ true); 235 236 Builder->MakeNode(destCall, E, Pred, state); 237 } 238 239 // Do the post visit. 240 getCheckerManager().runCheckersForPostStmt(destNodes, destCall, E, *this); 241} 242 243void ExprEngine::VisitCXXDestructor(const CXXDestructorDecl *DD, 244 const MemRegion *Dest, 245 const Stmt *S, 246 ExplodedNode *Pred, 247 ExplodedNodeSet &Dst) { 248 if (!(DD->doesThisDeclarationHaveABody() && AMgr.shouldInlineCall())) 249 return; 250 // Create the context for 'this' region. 251 const StackFrameContext *SFC = AMgr.getStackFrame(DD, 252 Pred->getLocationContext(), 253 S, Builder->getBlock(), 254 Builder->getIndex()); 255 256 const CXXThisRegion *ThisR = getCXXThisRegion(DD->getParent(), SFC); 257 258 CallEnter PP(S, SFC, Pred->getLocationContext()); 259 260 const ProgramState *state = Pred->getState(); 261 state = state->bindLoc(loc::MemRegionVal(ThisR), loc::MemRegionVal(Dest)); 262 ExplodedNode *N = Builder->generateNode(PP, state, Pred); 263 if (N) 264 Dst.Add(N); 265} 266 267void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, 268 ExplodedNodeSet &Dst) { 269 270 unsigned blockCount = Builder->getCurrentBlockCount(); 271 DefinedOrUnknownSVal symVal = 272 svalBuilder.getConjuredSymbolVal(NULL, CNE, CNE->getType(), blockCount); 273 const MemRegion *NewReg = cast<loc::MemRegionVal>(symVal).getRegion(); 274 QualType ObjTy = CNE->getType()->getAs<PointerType>()->getPointeeType(); 275 const ElementRegion *EleReg = 276 getStoreManager().GetElementZeroRegion(NewReg, ObjTy); 277 278 if (CNE->isArray()) { 279 // FIXME: allocating an array requires simulating the constructors. 280 // For now, just return a symbolicated region. 281 const ProgramState *state = Pred->getState(); 282 state = state->BindExpr(CNE, loc::MemRegionVal(EleReg)); 283 MakeNode(Dst, CNE, Pred, state); 284 return; 285 } 286 287 // Evaluate constructor arguments. 288 const FunctionProtoType *FnType = NULL; 289 const CXXConstructorDecl *CD = CNE->getConstructor(); 290 if (CD) 291 FnType = CD->getType()->getAs<FunctionProtoType>(); 292 ExplodedNodeSet argsEvaluated; 293 evalArguments(CNE->constructor_arg_begin(), CNE->constructor_arg_end(), 294 FnType, Pred, argsEvaluated); 295 296 // Initialize the object region and bind the 'new' expression. 297 for (ExplodedNodeSet::iterator I = argsEvaluated.begin(), 298 E = argsEvaluated.end(); I != E; ++I) { 299 300 const ProgramState *state = (*I)->getState(); 301 302 // Accumulate list of regions that are invalidated. 303 // FIXME: Eventually we should unify the logic for constructor 304 // processing in one place. 305 SmallVector<const MemRegion*, 10> regionsToInvalidate; 306 for (CXXNewExpr::const_arg_iterator 307 ai = CNE->constructor_arg_begin(), ae = CNE->constructor_arg_end(); 308 ai != ae; ++ai) 309 { 310 SVal val = state->getSVal(*ai); 311 if (const MemRegion *region = val.getAsRegion()) 312 regionsToInvalidate.push_back(region); 313 } 314 315 if (ObjTy->isRecordType()) { 316 regionsToInvalidate.push_back(EleReg); 317 // Invalidate the regions. 318 state = state->invalidateRegions(regionsToInvalidate, 319 CNE, blockCount, 0, 320 /* invalidateGlobals = */ true); 321 322 } else { 323 // Invalidate the regions. 324 state = state->invalidateRegions(regionsToInvalidate, 325 CNE, blockCount, 0, 326 /* invalidateGlobals = */ true); 327 328 if (CNE->hasInitializer()) { 329 SVal V = state->getSVal(*CNE->constructor_arg_begin()); 330 state = state->bindLoc(loc::MemRegionVal(EleReg), V); 331 } else { 332 // Explicitly set to undefined, because currently we retrieve symbolic 333 // value from symbolic region. 334 state = state->bindLoc(loc::MemRegionVal(EleReg), UndefinedVal()); 335 } 336 } 337 state = state->BindExpr(CNE, loc::MemRegionVal(EleReg)); 338 MakeNode(Dst, CNE, *I, state); 339 } 340} 341 342void ExprEngine::VisitCXXDeleteExpr(const CXXDeleteExpr *CDE, 343 ExplodedNode *Pred,ExplodedNodeSet &Dst) { 344 // Should do more checking. 345 ExplodedNodeSet Argevaluated; 346 Visit(CDE->getArgument(), Pred, Argevaluated); 347 for (ExplodedNodeSet::iterator I = Argevaluated.begin(), 348 E = Argevaluated.end(); I != E; ++I) { 349 const ProgramState *state = (*I)->getState(); 350 MakeNode(Dst, CDE, *I, state); 351 } 352} 353 354void ExprEngine::VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred, 355 ExplodedNodeSet &Dst) { 356 // Get the this object region from StoreManager. 357 const MemRegion *R = 358 svalBuilder.getRegionManager().getCXXThisRegion( 359 getContext().getCanonicalType(TE->getType()), 360 Pred->getLocationContext()); 361 362 const ProgramState *state = Pred->getState(); 363 SVal V = state->getSVal(loc::MemRegionVal(R)); 364 MakeNode(Dst, TE, Pred, state->BindExpr(TE, V)); 365} 366