clang API Documentation
00001 //=== IteratorsChecker.cpp - Check for Invalidated Iterators ------*- C++ -*---- 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This defines IteratorsChecker, a number of small checks for conditions 00011 // leading to invalid iterators being used. 00012 // FIXME: Currently only supports 'vector' and 'deque' 00013 // 00014 //===----------------------------------------------------------------------===// 00015 00016 #include "clang/AST/DeclTemplate.h" 00017 #include "clang/Basic/SourceManager.h" 00018 #include "ClangSACheckers.h" 00019 #include "clang/StaticAnalyzer/Core/Checker.h" 00020 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 00021 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 00022 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 00023 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" 00024 #include "clang/AST/DeclCXX.h" 00025 #include "clang/AST/ExprCXX.h" 00026 #include "clang/AST/Type.h" 00027 #include "clang/AST/PrettyPrinter.h" 00028 #include "llvm/ADT/SmallPtrSet.h" 00029 #include "llvm/ADT/StringSwitch.h" 00030 00031 00032 using namespace clang; 00033 using namespace ento; 00034 00035 // This is the state associated with each iterator which includes both the 00036 // kind of state and the instance used to initialize it. 00037 // FIXME: add location where invalidated for better error reporting. 00038 namespace { 00039 class RefState { 00040 enum Kind { BeginValid, EndValid, Invalid, Undefined, Unknown } K; 00041 const void *VR; 00042 00043 public: 00044 RefState(Kind k, const void *vr) : K(k), VR(vr) {} 00045 00046 bool isValid() const { return K == BeginValid || K == EndValid; } 00047 bool isInvalid() const { return K == Invalid; } 00048 bool isUndefined() const { return K == Undefined; } 00049 bool isUnknown() const { return K == Unknown; } 00050 const MemRegion *getMemRegion() const { 00051 if (K == BeginValid || K == EndValid) 00052 return(const MemRegion *)VR; 00053 return 0; 00054 } 00055 const MemberExpr *getMemberExpr() const { 00056 if (K == Invalid) 00057 return(const MemberExpr *)VR; 00058 return 0; 00059 } 00060 00061 bool operator==(const RefState &X) const { 00062 return K == X.K && VR == X.VR; 00063 } 00064 00065 static RefState getBeginValid(const MemRegion *vr) { 00066 assert(vr); 00067 return RefState(BeginValid, vr); 00068 } 00069 static RefState getEndValid(const MemRegion *vr) { 00070 assert(vr); 00071 return RefState(EndValid, vr); 00072 } 00073 static RefState getInvalid( const MemberExpr *ME ) { 00074 return RefState(Invalid, ME); 00075 } 00076 static RefState getUndefined( void ) { 00077 return RefState(Undefined, 0); 00078 } 00079 static RefState getUnknown( void ) { 00080 return RefState(Unknown, 0); 00081 } 00082 00083 void Profile(llvm::FoldingSetNodeID &ID) const { 00084 ID.AddInteger(K); 00085 ID.AddPointer(VR); 00086 } 00087 }; 00088 00089 enum RefKind { NoKind, VectorKind, VectorIteratorKind }; 00090 00091 class IteratorsChecker : 00092 public Checker<check::PreStmt<CXXOperatorCallExpr>, 00093 check::PreStmt<DeclStmt>, 00094 check::PreStmt<CXXMemberCallExpr>, 00095 check::PreStmt<CallExpr> > 00096 { 00097 // Used when parsing iterators and vectors and deques. 00098 BuiltinBug *BT_Invalid, *BT_Undefined, *BT_Incompatible; 00099 00100 public: 00101 IteratorsChecker() : 00102 BT_Invalid(0), BT_Undefined(0), BT_Incompatible(0) 00103 {} 00104 static void *getTag() { static int tag; return &tag; } 00105 00106 // Checker entry points. 00107 void checkPreStmt(const CXXOperatorCallExpr *OCE, 00108 CheckerContext &C) const; 00109 00110 void checkPreStmt(const DeclStmt *DS, 00111 CheckerContext &C) const; 00112 00113 void checkPreStmt(const CXXMemberCallExpr *MCE, 00114 CheckerContext &C) const; 00115 00116 void checkPreStmt(const CallExpr *CE, 00117 CheckerContext &C) const; 00118 00119 private: 00120 ProgramStateRef handleAssign(ProgramStateRef state, 00121 const Expr *lexp, 00122 const Expr *rexp, 00123 const LocationContext *LC) const; 00124 00125 ProgramStateRef handleAssign(ProgramStateRef state, 00126 const MemRegion *MR, 00127 const Expr *rexp, 00128 const LocationContext *LC) const; 00129 00130 ProgramStateRef invalidateIterators(ProgramStateRef state, 00131 const MemRegion *MR, 00132 const MemberExpr *ME) const; 00133 00134 void checkExpr(CheckerContext &C, const Expr *E) const; 00135 00136 void checkArgs(CheckerContext &C, const CallExpr *CE) const; 00137 00138 const MemRegion *getRegion(ProgramStateRef state, 00139 const Expr *E, 00140 const LocationContext *LC) const; 00141 00142 const DeclRefExpr *getDeclRefExpr(const Expr *E) const; 00143 }; 00144 00145 class IteratorState { 00146 public: 00147 typedef llvm::ImmutableMap<const MemRegion *, RefState> EntryMap; 00148 }; 00149 } //end anonymous namespace 00150 00151 namespace clang { 00152 namespace ento { 00153 template <> 00154 struct ProgramStateTrait<IteratorState> 00155 : public ProgramStatePartialTrait<IteratorState::EntryMap> { 00156 static void *GDMIndex() { return IteratorsChecker::getTag(); } 00157 }; 00158 } 00159 } 00160 00161 void ento::registerIteratorsChecker(CheckerManager &mgr) { 00162 mgr.registerChecker<IteratorsChecker>(); 00163 } 00164 00165 // =============================================== 00166 // Utility functions used by visitor functions 00167 // =============================================== 00168 00169 // check a templated type for std::vector or std::deque 00170 static RefKind getTemplateKind(const NamedDecl *td) { 00171 const DeclContext *dc = td->getDeclContext(); 00172 const NamespaceDecl *nameSpace = dyn_cast<NamespaceDecl>(dc); 00173 if (!nameSpace || !isa<TranslationUnitDecl>(nameSpace->getDeclContext()) 00174 || nameSpace->getName() != "std") 00175 return NoKind; 00176 00177 StringRef name = td->getName(); 00178 return llvm::StringSwitch<RefKind>(name) 00179 .Cases("vector", "deque", VectorKind) 00180 .Default(NoKind); 00181 } 00182 00183 static RefKind getTemplateKind(const DeclContext *dc) { 00184 if (const ClassTemplateSpecializationDecl *td = 00185 dyn_cast<ClassTemplateSpecializationDecl>(dc)) 00186 return getTemplateKind(cast<NamedDecl>(td)); 00187 return NoKind; 00188 } 00189 00190 static RefKind getTemplateKind(const TypedefType *tdt) { 00191 const TypedefNameDecl *td = tdt->getDecl(); 00192 RefKind parentKind = getTemplateKind(td->getDeclContext()); 00193 if (parentKind == VectorKind) { 00194 return llvm::StringSwitch<RefKind>(td->getName()) 00195 .Cases("iterator", 00196 "const_iterator", 00197 "reverse_iterator", VectorIteratorKind) 00198 .Default(NoKind); 00199 } 00200 return NoKind; 00201 } 00202 00203 static RefKind getTemplateKind(const TemplateSpecializationType *tsp) { 00204 const TemplateName &tname = tsp->getTemplateName(); 00205 TemplateDecl *td = tname.getAsTemplateDecl(); 00206 if (!td) 00207 return NoKind; 00208 return getTemplateKind(td); 00209 } 00210 00211 static RefKind getTemplateKind(QualType T) { 00212 if (const TemplateSpecializationType *tsp = 00213 T->getAs<TemplateSpecializationType>()) { 00214 return getTemplateKind(tsp); 00215 } 00216 if (const ElaboratedType *ET = dyn_cast<ElaboratedType>(T)) { 00217 QualType namedType = ET->getNamedType(); 00218 if (const TypedefType *tdt = namedType->getAs<TypedefType>()) 00219 return getTemplateKind(tdt); 00220 if (const TemplateSpecializationType *tsp = 00221 namedType->getAs<TemplateSpecializationType>()) { 00222 return getTemplateKind(tsp); 00223 } 00224 } 00225 return NoKind; 00226 } 00227 00228 // Iterate through our map and invalidate any iterators that were 00229 // initialized fromt the specified instance MemRegion. 00230 ProgramStateRef IteratorsChecker::invalidateIterators(ProgramStateRef state, 00231 const MemRegion *MR, const MemberExpr *ME) const { 00232 IteratorState::EntryMap Map = state->get<IteratorState>(); 00233 if (Map.isEmpty()) 00234 return state; 00235 00236 // Loop over the entries in the current state. 00237 // The key doesn't change, so the map iterators won't change. 00238 for (IteratorState::EntryMap::iterator I = Map.begin(), E = Map.end(); 00239 I != E; ++I) { 00240 RefState RS = I.getData(); 00241 if (RS.getMemRegion() == MR) 00242 state = state->set<IteratorState>(I.getKey(), RefState::getInvalid(ME)); 00243 } 00244 00245 return state; 00246 } 00247 00248 // Handle assigning to an iterator where we don't have the LValue MemRegion. 00249 ProgramStateRef IteratorsChecker::handleAssign(ProgramStateRef state, 00250 const Expr *lexp, const Expr *rexp, const LocationContext *LC) const { 00251 // Skip the cast if present. 00252 if (const MaterializeTemporaryExpr *M 00253 = dyn_cast<MaterializeTemporaryExpr>(lexp)) 00254 lexp = M->GetTemporaryExpr(); 00255 if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(lexp)) 00256 lexp = ICE->getSubExpr(); 00257 SVal sv = state->getSVal(lexp, LC); 00258 const MemRegion *MR = sv.getAsRegion(); 00259 if (!MR) 00260 return state; 00261 RefKind kind = getTemplateKind(lexp->getType()); 00262 00263 // If assigning to a vector, invalidate any iterators currently associated. 00264 if (kind == VectorKind) 00265 return invalidateIterators(state, MR, 0); 00266 00267 // Make sure that we are assigning to an iterator. 00268 if (getTemplateKind(lexp->getType()) != VectorIteratorKind) 00269 return state; 00270 return handleAssign(state, MR, rexp, LC); 00271 } 00272 00273 // handle assigning to an iterator 00274 ProgramStateRef IteratorsChecker::handleAssign(ProgramStateRef state, 00275 const MemRegion *MR, const Expr *rexp, const LocationContext *LC) const { 00276 // Assume unknown until we find something definite. 00277 state = state->set<IteratorState>(MR, RefState::getUnknown()); 00278 if (const MaterializeTemporaryExpr *M 00279 = dyn_cast<MaterializeTemporaryExpr>(rexp)) 00280 rexp = M->GetTemporaryExpr(); 00281 if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(rexp)) 00282 rexp = ICE->getSubExpr(); 00283 // Need to handle three cases: MemberCall, copy, copy with addition. 00284 if (const CallExpr *CE = dyn_cast<CallExpr>(rexp)) { 00285 // Handle MemberCall. 00286 if (const MemberExpr *ME = dyn_cast<MemberExpr>(CE->getCallee())) { 00287 const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ME->getBase()); 00288 if (!DRE) 00289 return state; 00290 // Verify that the type is std::vector<T>. 00291 if (getTemplateKind(DRE->getType()) != VectorKind) 00292 return state; 00293 // Now get the MemRegion associated with the instance. 00294 const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()); 00295 if (!VD) 00296 return state; 00297 const MemRegion *IMR = state->getRegion(VD, LC); 00298 if (!IMR) 00299 return state; 00300 // Finally, see if it is one of the calls that will create 00301 // a valid iterator and mark it if so, else mark as Unknown. 00302 StringRef mName = ME->getMemberDecl()->getName(); 00303 00304 if (llvm::StringSwitch<bool>(mName) 00305 .Cases("begin", "insert", "erase", true).Default(false)) { 00306 return state->set<IteratorState>(MR, RefState::getBeginValid(IMR)); 00307 } 00308 if (mName == "end") 00309 return state->set<IteratorState>(MR, RefState::getEndValid(IMR)); 00310 00311 return state->set<IteratorState>(MR, RefState::getUnknown()); 00312 } 00313 } 00314 // Handle straight copy from another iterator. 00315 if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(rexp)) { 00316 if (getTemplateKind(DRE->getType()) != VectorIteratorKind) 00317 return state; 00318 // Now get the MemRegion associated with the instance. 00319 const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()); 00320 if (!VD) 00321 return state; 00322 const MemRegion *IMR = state->getRegion(VD, LC); 00323 if (!IMR) 00324 return state; 00325 // Get the RefState of the iterator being copied. 00326 const RefState *RS = state->get<IteratorState>(IMR); 00327 if (!RS) 00328 return state; 00329 // Use it to set the state of the LValue. 00330 return state->set<IteratorState>(MR, *RS); 00331 } 00332 // If we have operator+ or operator- ... 00333 if (const CXXOperatorCallExpr *OCE = dyn_cast<CXXOperatorCallExpr>(rexp)) { 00334 OverloadedOperatorKind Kind = OCE->getOperator(); 00335 if (Kind == OO_Plus || Kind == OO_Minus) { 00336 // Check left side of tree for a valid value. 00337 state = handleAssign( state, MR, OCE->getArg(0), LC); 00338 const RefState *RS = state->get<IteratorState>(MR); 00339 // If found, return it. 00340 if (!RS->isUnknown()) 00341 return state; 00342 // Otherwise return what we find in the right side. 00343 return handleAssign(state, MR, OCE->getArg(1), LC); 00344 } 00345 } 00346 // Fall through if nothing matched. 00347 return state; 00348 } 00349 00350 // Iterate through the arguments looking for an Invalid or Undefined iterator. 00351 void IteratorsChecker::checkArgs(CheckerContext &C, const CallExpr *CE) const { 00352 for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end(); 00353 I != E; ++I) { 00354 checkExpr(C, *I); 00355 } 00356 } 00357 00358 // Get the DeclRefExpr associated with the expression. 00359 const DeclRefExpr *IteratorsChecker::getDeclRefExpr(const Expr *E) const { 00360 // If it is a CXXConstructExpr, need to get the subexpression. 00361 if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(E)) { 00362 if (CE->getNumArgs()== 1) { 00363 CXXConstructorDecl *CD = CE->getConstructor(); 00364 if (CD->isTrivial()) 00365 E = CE->getArg(0); 00366 } 00367 } 00368 if (const MaterializeTemporaryExpr *M = dyn_cast<MaterializeTemporaryExpr>(E)) 00369 E = M->GetTemporaryExpr(); 00370 if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) 00371 E = ICE->getSubExpr(); 00372 // If it isn't one of our types, don't do anything. 00373 if (getTemplateKind(E->getType()) != VectorIteratorKind) 00374 return NULL; 00375 return dyn_cast<DeclRefExpr>(E); 00376 } 00377 00378 // Get the MemRegion associated with the expresssion. 00379 const MemRegion *IteratorsChecker::getRegion(ProgramStateRef state, 00380 const Expr *E, const LocationContext *LC) const { 00381 const DeclRefExpr *DRE = getDeclRefExpr(E); 00382 if (!DRE) 00383 return NULL; 00384 const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()); 00385 if (!VD) 00386 return NULL; 00387 // return the MemRegion associated with the iterator 00388 return state->getRegion(VD, LC); 00389 } 00390 00391 // Check the expression and if it is an iterator, generate a diagnostic 00392 // if the iterator is not valid. 00393 // FIXME: this method can generate new nodes, and subsequent logic should 00394 // use those nodes. We also cannot create multiple nodes at one ProgramPoint 00395 // with the same tag. 00396 void IteratorsChecker::checkExpr(CheckerContext &C, const Expr *E) const { 00397 ProgramStateRef state = C.getState(); 00398 const MemRegion *MR = getRegion(state, E, C.getLocationContext()); 00399 if (!MR) 00400 return; 00401 00402 // Get the state associated with the iterator. 00403 const RefState *RS = state->get<IteratorState>(MR); 00404 if (!RS) 00405 return; 00406 if (RS->isInvalid()) { 00407 if (ExplodedNode *N = C.addTransition()) { 00408 if (!BT_Invalid) 00409 // FIXME: We are eluding constness here. 00410 const_cast<IteratorsChecker*>(this)->BT_Invalid = new BuiltinBug(""); 00411 00412 std::string msg; 00413 const MemberExpr *ME = RS->getMemberExpr(); 00414 if (ME) { 00415 std::string name = ME->getMemberNameInfo().getAsString(); 00416 msg = "Attempt to use an iterator made invalid by call to '" + 00417 name + "'"; 00418 } 00419 else { 00420 msg = "Attempt to use an iterator made invalid by copying another " 00421 "container to its container"; 00422 } 00423 00424 BugReport *R = new BugReport(*BT_Invalid, msg, N); 00425 R->addRange(getDeclRefExpr(E)->getSourceRange()); 00426 C.EmitReport(R); 00427 } 00428 } 00429 else if (RS->isUndefined()) { 00430 if (ExplodedNode *N = C.addTransition()) { 00431 if (!BT_Undefined) 00432 // FIXME: We are eluding constness here. 00433 const_cast<IteratorsChecker*>(this)->BT_Undefined = 00434 new BuiltinBug("Use of iterator that is not defined"); 00435 00436 BugReport *R = new BugReport(*BT_Undefined, 00437 BT_Undefined->getDescription(), N); 00438 R->addRange(getDeclRefExpr(E)->getSourceRange()); 00439 C.EmitReport(R); 00440 } 00441 } 00442 } 00443 00444 // =============================================== 00445 // Path analysis visitor functions 00446 // =============================================== 00447 00448 // For a generic Call, just check the args for bad iterators. 00449 void IteratorsChecker::checkPreStmt(const CallExpr *CE, 00450 CheckerContext &C) const{ 00451 00452 // FIXME: These checks are to currently work around a bug 00453 // in CheckerManager. 00454 if (isa<CXXOperatorCallExpr>(CE)) 00455 return; 00456 if (isa<CXXMemberCallExpr>(CE)) 00457 return; 00458 00459 checkArgs(C, CE); 00460 } 00461 00462 // Handle operator calls. First, if it is operator=, check the argument, 00463 // and handle assigning and set target state appropriately. Otherwise, for 00464 // other operators, check the args for bad iterators and handle comparisons. 00465 void IteratorsChecker::checkPreStmt(const CXXOperatorCallExpr *OCE, 00466 CheckerContext &C) const 00467 { 00468 const LocationContext *LC = C.getLocationContext(); 00469 ProgramStateRef state = C.getState(); 00470 OverloadedOperatorKind Kind = OCE->getOperator(); 00471 if (Kind == OO_Equal) { 00472 checkExpr(C, OCE->getArg(1)); 00473 state = handleAssign(state, OCE->getArg(0), OCE->getArg(1), LC); 00474 C.addTransition(state); 00475 return; 00476 } 00477 else { 00478 checkArgs(C, OCE); 00479 // If it is a compare and both are iterators, ensure that they are for 00480 // the same container. 00481 if (Kind == OO_EqualEqual || Kind == OO_ExclaimEqual || 00482 Kind == OO_Less || Kind == OO_LessEqual || 00483 Kind == OO_Greater || Kind == OO_GreaterEqual) { 00484 const MemRegion *MR0, *MR1; 00485 MR0 = getRegion(state, OCE->getArg(0), LC); 00486 if (!MR0) 00487 return; 00488 MR1 = getRegion(state, OCE->getArg(1), LC); 00489 if (!MR1) 00490 return; 00491 const RefState *RS0, *RS1; 00492 RS0 = state->get<IteratorState>(MR0); 00493 if (!RS0) 00494 return; 00495 RS1 = state->get<IteratorState>(MR1); 00496 if (!RS1) 00497 return; 00498 if (RS0->getMemRegion() != RS1->getMemRegion()) { 00499 if (ExplodedNode *N = C.addTransition()) { 00500 if (!BT_Incompatible) 00501 const_cast<IteratorsChecker*>(this)->BT_Incompatible = 00502 new BuiltinBug( 00503 "Cannot compare iterators from different containers"); 00504 00505 BugReport *R = new BugReport(*BT_Incompatible, 00506 BT_Incompatible->getDescription(), N); 00507 R->addRange(OCE->getSourceRange()); 00508 C.EmitReport(R); 00509 } 00510 } 00511 } 00512 } 00513 } 00514 00515 // Need to handle DeclStmts to pick up initializing of iterators and to mark 00516 // uninitialized ones as Undefined. 00517 void IteratorsChecker::checkPreStmt(const DeclStmt *DS, 00518 CheckerContext &C) const { 00519 const Decl *D = *DS->decl_begin(); 00520 const VarDecl *VD = dyn_cast<VarDecl>(D); 00521 // Only care about iterators. 00522 if (getTemplateKind(VD->getType()) != VectorIteratorKind) 00523 return; 00524 00525 // Get the MemRegion associated with the iterator and mark it as Undefined. 00526 ProgramStateRef state = C.getState(); 00527 Loc VarLoc = state->getLValue(VD, C.getLocationContext()); 00528 const MemRegion *MR = VarLoc.getAsRegion(); 00529 if (!MR) 00530 return; 00531 state = state->set<IteratorState>(MR, RefState::getUndefined()); 00532 00533 // if there is an initializer, handle marking Valid if a proper initializer 00534 const Expr *InitEx = VD->getInit(); 00535 if (InitEx) { 00536 // FIXME: This is too syntactic. Since 'InitEx' will be analyzed first 00537 // it should resolve to an SVal that we can check for validity 00538 // *semantically* instead of walking through the AST. 00539 if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(InitEx)) { 00540 if (CE->getNumArgs() == 1) { 00541 const Expr *E = CE->getArg(0); 00542 if (const MaterializeTemporaryExpr *M 00543 = dyn_cast<MaterializeTemporaryExpr>(E)) 00544 E = M->GetTemporaryExpr(); 00545 if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) 00546 InitEx = ICE->getSubExpr(); 00547 state = handleAssign(state, MR, InitEx, C.getLocationContext()); 00548 } 00549 } 00550 } 00551 C.addTransition(state); 00552 } 00553 00554 00555 namespace { struct CalledReserved {}; } 00556 namespace clang { namespace ento { 00557 template<> struct ProgramStateTrait<CalledReserved> 00558 : public ProgramStatePartialTrait<llvm::ImmutableSet<const MemRegion*> > { 00559 static void *GDMIndex() { static int index = 0; return &index; } 00560 }; 00561 }} 00562 00563 // on a member call, first check the args for any bad iterators 00564 // then, check to see if it is a call to a function that will invalidate 00565 // the iterators 00566 void IteratorsChecker::checkPreStmt(const CXXMemberCallExpr *MCE, 00567 CheckerContext &C) const { 00568 // Check the arguments. 00569 checkArgs(C, MCE); 00570 const MemberExpr *ME = dyn_cast<MemberExpr>(MCE->getCallee()); 00571 if (!ME) 00572 return; 00573 // Make sure we have the right kind of container. 00574 const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ME->getBase()); 00575 if (!DRE || getTemplateKind(DRE->getType()) != VectorKind) 00576 return; 00577 SVal tsv = C.getState()->getSVal(DRE, C.getLocationContext()); 00578 // Get the MemRegion associated with the container instance. 00579 const MemRegion *MR = tsv.getAsRegion(); 00580 if (!MR) 00581 return; 00582 // If we are calling a function that invalidates iterators, mark them 00583 // appropriately by finding matching instances. 00584 ProgramStateRef state = C.getState(); 00585 StringRef mName = ME->getMemberDecl()->getName(); 00586 if (llvm::StringSwitch<bool>(mName) 00587 .Cases("insert", "reserve", "push_back", true) 00588 .Cases("erase", "pop_back", "clear", "resize", true) 00589 .Default(false)) { 00590 // If there was a 'reserve' call, assume iterators are good. 00591 if (!state->contains<CalledReserved>(MR)) 00592 state = invalidateIterators(state, MR, ME); 00593 } 00594 // Keep track of instances that have called 'reserve' 00595 // note: do this after we invalidate any iterators by calling 00596 // 'reserve' itself. 00597 if (mName == "reserve") 00598 state = state->add<CalledReserved>(MR); 00599 00600 if (state != C.getState()) 00601 C.addTransition(state); 00602 } 00603