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