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 ExplodedNodeSet Tmp; 111 Visit(ME->GetTemporaryExpr(), Pred, Tmp); 112 for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) { 113 const ProgramState *state = (*I)->getState(); 114 115 // Bind the temporary object to the value of the expression. Then bind 116 // the expression to the location of the object. 117 SVal V = state->getSVal(ME->GetTemporaryExpr()); 118 119 const MemRegion *R = 120 svalBuilder.getRegionManager().getCXXTempObjectRegion(ME, 121 Pred->getLocationContext()); 122 123 state = state->bindLoc(loc::MemRegionVal(R), V); 124 MakeNode(Dst, ME, Pred, state->BindExpr(ME, loc::MemRegionVal(R))); 125 } 126 } 127 128 void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, 129 const MemRegion *Dest, 130 ExplodedNode *Pred, 131 ExplodedNodeSet &destNodes) { 132 133 const CXXConstructorDecl *CD = E->getConstructor(); 134 assert(CD); 135 136 #if 0 137 if (!(CD->doesThisDeclarationHaveABody() && AMgr.shouldInlineCall())) 138 // FIXME: invalidate the object. 139 return; 140 #endif 141 142 // Evaluate other arguments. 143 ExplodedNodeSet argsEvaluated; 144 const FunctionProtoType *FnType = CD->getType()->getAs<FunctionProtoType>(); 145 evalArguments(E->arg_begin(), E->arg_end(), FnType, Pred, argsEvaluated); 146 147 #if 0 148 // Is the constructor elidable? 149 if (E->isElidable()) { 150 VisitAggExpr(E->getArg(0), destNodes, Pred, Dst); 151 // FIXME: this is here to force propagation if VisitAggExpr doesn't 152 if (destNodes.empty()) 153 destNodes.Add(Pred); 154 return; 155 } 156 #endif 157 158 // Perform the previsit of the constructor. 159 ExplodedNodeSet destPreVisit; 160 getCheckerManager().runCheckersForPreStmt(destPreVisit, argsEvaluated, E, 161 *this); 162 163 // Evaluate the constructor. Currently we don't now allow checker-specific 164 // implementations of specific constructors (as we do with ordinary 165 // function calls. We can re-evaluate this in the future. 166 167 #if 0 168 // Inlining currently isn't fully implemented. 169 170 if (AMgr.shouldInlineCall()) { 171 if (!Dest) 172 Dest = 173 svalBuilder.getRegionManager().getCXXTempObjectRegion(E, 174 Pred->getLocationContext()); 175 176 // The callee stack frame context used to create the 'this' 177 // parameter region. 178 const StackFrameContext *SFC = 179 AMgr.getStackFrame(CD, Pred->getLocationContext(), 180 E, Builder->getBlock(), Builder->getIndex()); 181 182 // Create the 'this' region. 183 const CXXThisRegion *ThisR = 184 getCXXThisRegion(E->getConstructor()->getParent(), SFC); 185 186 CallEnter Loc(E, SFC, Pred->getLocationContext()); 187 188 189 for (ExplodedNodeSet::iterator NI = argsEvaluated.begin(), 190 NE = argsEvaluated.end(); NI != NE; ++NI) { 191 const ProgramState *state = (*NI)->getState(); 192 // Setup 'this' region, so that the ctor is evaluated on the object pointed 193 // by 'Dest'. 194 state = state->bindLoc(loc::MemRegionVal(ThisR), loc::MemRegionVal(Dest)); 195 if (ExplodedNode *N = Builder->generateNode(Loc, state, *NI)) 196 destNodes.Add(N); 197 } 198 } 199 #endif 200 201 // Default semantics: invalidate all regions passed as arguments. 202 ExplodedNodeSet destCall; 203 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 Builder->MakeNode(destCall, E, Pred, state); 214 } 215 216 // Do the post visit. 217 getCheckerManager().runCheckersForPostStmt(destNodes, destCall, E, *this); 218 } 219 220 void ExprEngine::VisitCXXDestructor(const CXXDestructorDecl *DD, 221 const MemRegion *Dest, 222 const Stmt *S, 223 ExplodedNode *Pred, 224 ExplodedNodeSet &Dst) { 225 if (!(DD->doesThisDeclarationHaveABody() && AMgr.shouldInlineCall())) 226 return; 227 // Create the context for 'this' region. 228 const StackFrameContext *SFC = AMgr.getStackFrame(DD, 229 Pred->getLocationContext(), 230 S, Builder->getBlock(), 231 Builder->getIndex()); 232 233 const CXXThisRegion *ThisR = getCXXThisRegion(DD->getParent(), SFC); 234 235 CallEnter PP(S, SFC, Pred->getLocationContext()); 236 237 const ProgramState *state = Pred->getState(); 238 state = state->bindLoc(loc::MemRegionVal(ThisR), loc::MemRegionVal(Dest)); 239 ExplodedNode *N = Builder->generateNode(PP, state, Pred); 240 if (N) 241 Dst.Add(N); 242 } 243 244 void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, 245 ExplodedNodeSet &Dst) { 246 247 unsigned blockCount = Builder->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 MakeNode(Dst, 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 evalArguments(CNE->constructor_arg_begin(), CNE->constructor_arg_end(), 271 FnType, Pred, argsEvaluated); 272 273 // Initialize the object region and bind the 'new' expression. 274 for (ExplodedNodeSet::iterator I = argsEvaluated.begin(), 275 E = argsEvaluated.end(); I != E; ++I) { 276 277 const ProgramState *state = (*I)->getState(); 278 279 // Accumulate list of regions that are invalidated. 280 // FIXME: Eventually we should unify the logic for constructor 281 // processing in one place. 282 SmallVector<const MemRegion*, 10> regionsToInvalidate; 283 for (CXXNewExpr::const_arg_iterator 284 ai = CNE->constructor_arg_begin(), ae = CNE->constructor_arg_end(); 285 ai != ae; ++ai) 286 { 287 SVal val = state->getSVal(*ai); 288 if (const MemRegion *region = val.getAsRegion()) 289 regionsToInvalidate.push_back(region); 290 } 291 292 if (ObjTy->isRecordType()) { 293 regionsToInvalidate.push_back(EleReg); 294 // Invalidate the regions. 295 state = state->invalidateRegions(regionsToInvalidate, 296 CNE, blockCount, 0, 297 /* invalidateGlobals = */ true); 298 299 } else { 300 // Invalidate the regions. 301 state = state->invalidateRegions(regionsToInvalidate, 302 CNE, blockCount, 0, 303 /* invalidateGlobals = */ true); 304 305 if (CNE->hasInitializer()) { 306 SVal V = state->getSVal(*CNE->constructor_arg_begin()); 307 state = state->bindLoc(loc::MemRegionVal(EleReg), V); 308 } else { 309 // Explicitly set to undefined, because currently we retrieve symbolic 310 // value from symbolic region. 311 state = state->bindLoc(loc::MemRegionVal(EleReg), UndefinedVal()); 312 } 313 } 314 state = state->BindExpr(CNE, loc::MemRegionVal(EleReg)); 315 MakeNode(Dst, CNE, *I, state); 316 } 317 } 318 319 void ExprEngine::VisitCXXDeleteExpr(const CXXDeleteExpr *CDE, 320 ExplodedNode *Pred,ExplodedNodeSet &Dst) { 321 // Should do more checking. 322 ExplodedNodeSet Argevaluated; 323 Visit(CDE->getArgument(), Pred, Argevaluated); 324 for (ExplodedNodeSet::iterator I = Argevaluated.begin(), 325 E = Argevaluated.end(); I != E; ++I) { 326 const ProgramState *state = (*I)->getState(); 327 MakeNode(Dst, CDE, *I, state); 328 } 329 } 330 331 void ExprEngine::VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred, 332 ExplodedNodeSet &Dst) { 333 // Get the this object region from StoreManager. 334 const MemRegion *R = 335 svalBuilder.getRegionManager().getCXXThisRegion( 336 getContext().getCanonicalType(TE->getType()), 337 Pred->getLocationContext()); 338 339 const ProgramState *state = Pred->getState(); 340 SVal V = state->getSVal(loc::MemRegionVal(R)); 341 MakeNode(Dst, TE, Pred, state->BindExpr(TE, V)); 342 } 343