clang API Documentation

IteratorsChecker.cpp
Go to the documentation of this file.
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