Home | History | Annotate | Download | only in Checkers
      1 //=== IteratorsChecker.cpp - Check for Invalidated Iterators ------*- 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 defines IteratorsChecker, a number of small checks for conditions
     11 // leading to invalid iterators being used.
     12 // FIXME: Currently only supports 'vector' and 'deque'
     13 //
     14 //===----------------------------------------------------------------------===//
     15 
     16 #include "clang/AST/DeclTemplate.h"
     17 #include "clang/Basic/SourceManager.h"
     18 #include "ClangSACheckers.h"
     19 #include "clang/StaticAnalyzer/Core/Checker.h"
     20 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
     21 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
     22 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
     23 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
     24 #include "clang/AST/DeclCXX.h"
     25 #include "clang/AST/Decl.h"
     26 #include "clang/AST/Type.h"
     27 #include "clang/AST/PrettyPrinter.h"
     28 #include "llvm/ADT/SmallPtrSet.h"
     29 #include "llvm/ADT/StringSwitch.h"
     30 
     31 
     32 using namespace clang;
     33 using namespace ento;
     34 
     35 // This is the state associated with each iterator which includes both the
     36 // kind of state and the instance used to initialize it.
     37 // FIXME: add location where invalidated for better error reporting.
     38 namespace {
     39 class RefState {
     40   enum Kind { BeginValid, EndValid, Invalid, Undefined, Unknown } K;
     41   const void *VR;
     42 
     43 public:
     44   RefState(Kind k, const void *vr) : K(k), VR(vr) {}
     45 
     46   bool isValid() const { return K == BeginValid || K == EndValid; }
     47   bool isInvalid() const { return K == Invalid; }
     48   bool isUndefined() const { return K == Undefined; }
     49   bool isUnknown() const { return K == Unknown; }
     50   const MemRegion *getMemRegion() const {
     51     if (K == BeginValid || K == EndValid)
     52       return(const MemRegion *)VR;
     53     return 0;
     54   }
     55   const MemberExpr *getMemberExpr() const {
     56     if (K == Invalid)
     57       return(const MemberExpr *)VR;
     58     return 0;
     59   }
     60 
     61   bool operator==(const RefState &X) const {
     62     return K == X.K && VR == X.VR;
     63   }
     64 
     65   static RefState getBeginValid(const MemRegion *vr) {
     66     assert(vr);
     67     return RefState(BeginValid, vr);
     68   }
     69   static RefState getEndValid(const MemRegion *vr) {
     70     assert(vr);
     71     return RefState(EndValid, vr);
     72   }
     73   static RefState getInvalid( const MemberExpr *ME ) {
     74     return RefState(Invalid, ME);
     75   }
     76   static RefState getUndefined( void ) {
     77     return RefState(Undefined, 0);
     78   }
     79   static RefState getUnknown( void ) {
     80     return RefState(Unknown, 0);
     81   }
     82 
     83   void Profile(llvm::FoldingSetNodeID &ID) const {
     84     ID.AddInteger(K);
     85     ID.AddPointer(VR);
     86   }
     87 };
     88 
     89 enum RefKind { NoKind, VectorKind, VectorIteratorKind };
     90 
     91 class IteratorsChecker :
     92     public Checker<check::PreStmt<CXXOperatorCallExpr>,
     93                    check::PreStmt<DeclStmt>,
     94                    check::PreStmt<CXXMemberCallExpr>,
     95                    check::PreStmt<CallExpr> >
     96   {
     97   // Used when parsing iterators and vectors and deques.
     98   BuiltinBug *BT_Invalid, *BT_Undefined, *BT_Incompatible;
     99 
    100 public:
    101   IteratorsChecker() :
    102     BT_Invalid(0), BT_Undefined(0), BT_Incompatible(0)
    103   {}
    104   static void *getTag() { static int tag; return &tag; }
    105 
    106   // Checker entry points.
    107   void checkPreStmt(const CXXOperatorCallExpr *OCE,
    108                     CheckerContext &C) const;
    109 
    110   void checkPreStmt(const DeclStmt *DS,
    111                     CheckerContext &C) const;
    112 
    113   void checkPreStmt(const CXXMemberCallExpr *MCE,
    114                     CheckerContext &C) const;
    115 
    116   void checkPreStmt(const CallExpr *CE,
    117                     CheckerContext &C) const;
    118 
    119 private:
    120   const ProgramState *handleAssign(const ProgramState *state,
    121                                    const Expr *lexp,
    122                                    const Expr *rexp,
    123                                    const LocationContext *LC) const;
    124 
    125   const ProgramState *handleAssign(const ProgramState *state,
    126                                    const MemRegion *MR,
    127                                    const Expr *rexp,
    128                                    const LocationContext *LC) const;
    129 
    130   const ProgramState *invalidateIterators(const ProgramState *state,
    131                                           const MemRegion *MR,
    132                                           const MemberExpr *ME) const;
    133 
    134   void checkExpr(CheckerContext &C, const Expr *E) const;
    135 
    136   void checkArgs(CheckerContext &C, const CallExpr *CE) const;
    137 
    138   const MemRegion *getRegion(const ProgramState *state,
    139                              const Expr *E,
    140                              const LocationContext *LC) const;
    141 
    142   const DeclRefExpr *getDeclRefExpr(const Expr *E) const;
    143 };
    144 
    145 class IteratorState {
    146 public:
    147   typedef llvm::ImmutableMap<const MemRegion *, RefState> EntryMap;
    148 };
    149 } //end anonymous namespace
    150 
    151 namespace clang {
    152   namespace ento {
    153     template <>
    154     struct ProgramStateTrait<IteratorState>
    155       : public ProgramStatePartialTrait<IteratorState::EntryMap> {
    156       static void *GDMIndex() { return IteratorsChecker::getTag(); }
    157     };
    158   }
    159 }
    160 
    161 void ento::registerIteratorsChecker(CheckerManager &mgr) {
    162   mgr.registerChecker<IteratorsChecker>();
    163 }
    164 
    165 // ===============================================
    166 // Utility functions used by visitor functions
    167 // ===============================================
    168 
    169 // check a templated type for std::vector or std::deque
    170 static RefKind getTemplateKind(const NamedDecl *td) {
    171   const DeclContext *dc = td->getDeclContext();
    172   const NamespaceDecl *nameSpace = dyn_cast<NamespaceDecl>(dc);
    173   if (!nameSpace || !isa<TranslationUnitDecl>(nameSpace->getDeclContext())
    174       || nameSpace->getName() != "std")
    175     return NoKind;
    176 
    177   StringRef name = td->getName();
    178   return llvm::StringSwitch<RefKind>(name)
    179     .Cases("vector", "deque", VectorKind)
    180     .Default(NoKind);
    181 }
    182 
    183 static RefKind getTemplateKind(const DeclContext *dc) {
    184   if (const ClassTemplateSpecializationDecl *td =
    185       dyn_cast<ClassTemplateSpecializationDecl>(dc))
    186     return getTemplateKind(cast<NamedDecl>(td));
    187   return NoKind;
    188 }
    189 
    190 static RefKind getTemplateKind(const TypedefType *tdt) {
    191   const TypedefNameDecl *td = tdt->getDecl();
    192   RefKind parentKind = getTemplateKind(td->getDeclContext());
    193   if (parentKind == VectorKind) {
    194     return llvm::StringSwitch<RefKind>(td->getName())
    195     .Cases("iterator",
    196            "const_iterator",
    197            "reverse_iterator", VectorIteratorKind)
    198     .Default(NoKind);
    199   }
    200   return NoKind;
    201 }
    202 
    203 static RefKind getTemplateKind(const TemplateSpecializationType *tsp) {
    204   const TemplateName &tname = tsp->getTemplateName();
    205   TemplateDecl *td = tname.getAsTemplateDecl();
    206   if (!td)
    207     return NoKind;
    208   return getTemplateKind(td);
    209 }
    210 
    211 static RefKind getTemplateKind(QualType T) {
    212   if (const TemplateSpecializationType *tsp =
    213       T->getAs<TemplateSpecializationType>()) {
    214     return getTemplateKind(tsp);
    215   }
    216   if (const ElaboratedType *ET = dyn_cast<ElaboratedType>(T)) {
    217     QualType namedType = ET->getNamedType();
    218     if (const TypedefType *tdt = namedType->getAs<TypedefType>())
    219       return getTemplateKind(tdt);
    220     if (const TemplateSpecializationType *tsp =
    221         namedType->getAs<TemplateSpecializationType>()) {
    222       return getTemplateKind(tsp);
    223     }
    224   }
    225   return NoKind;
    226 }
    227 
    228 // Iterate through our map and invalidate any iterators that were
    229 // initialized fromt the specified instance MemRegion.
    230 const ProgramState *IteratorsChecker::invalidateIterators(const ProgramState *state,
    231                           const MemRegion *MR, const MemberExpr *ME) const {
    232   IteratorState::EntryMap Map = state->get<IteratorState>();
    233   if (Map.isEmpty())
    234     return state;
    235 
    236   // Loop over the entries in the current state.
    237   // The key doesn't change, so the map iterators won't change.
    238   for (IteratorState::EntryMap::iterator I = Map.begin(), E = Map.end();
    239                                                             I != E; ++I) {
    240     RefState RS = I.getData();
    241     if (RS.getMemRegion() == MR)
    242       state = state->set<IteratorState>(I.getKey(), RefState::getInvalid(ME));
    243   }
    244 
    245   return state;
    246 }
    247 
    248 // Handle assigning to an iterator where we don't have the LValue MemRegion.
    249 const ProgramState *IteratorsChecker::handleAssign(const ProgramState *state,
    250     const Expr *lexp, const Expr *rexp, const LocationContext *LC) const {
    251   // Skip the cast if present.
    252   if (const MaterializeTemporaryExpr *M
    253                                     = dyn_cast<MaterializeTemporaryExpr>(lexp))
    254     lexp = M->GetTemporaryExpr();
    255   if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(lexp))
    256     lexp = ICE->getSubExpr();
    257   SVal sv = state->getSVal(lexp);
    258   const MemRegion *MR = sv.getAsRegion();
    259   if (!MR)
    260     return state;
    261   RefKind kind = getTemplateKind(lexp->getType());
    262 
    263   // If assigning to a vector, invalidate any iterators currently associated.
    264   if (kind == VectorKind)
    265     return invalidateIterators(state, MR, 0);
    266 
    267   // Make sure that we are assigning to an iterator.
    268   if (getTemplateKind(lexp->getType()) != VectorIteratorKind)
    269     return state;
    270   return handleAssign(state, MR, rexp, LC);
    271 }
    272 
    273 // handle assigning to an iterator
    274 const ProgramState *IteratorsChecker::handleAssign(const ProgramState *state,
    275     const MemRegion *MR, const Expr *rexp, const LocationContext *LC) const {
    276   // Assume unknown until we find something definite.
    277   state = state->set<IteratorState>(MR, RefState::getUnknown());
    278   if (const MaterializeTemporaryExpr *M
    279                                     = dyn_cast<MaterializeTemporaryExpr>(rexp))
    280     rexp = M->GetTemporaryExpr();
    281   if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(rexp))
    282     rexp = ICE->getSubExpr();
    283   // Need to handle three cases: MemberCall, copy, copy with addition.
    284   if (const CallExpr *CE = dyn_cast<CallExpr>(rexp)) {
    285     // Handle MemberCall.
    286     if (const MemberExpr *ME = dyn_cast<MemberExpr>(CE->getCallee())) {
    287       const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ME->getBase());
    288       if (!DRE)
    289         return state;
    290       // Verify that the type is std::vector<T>.
    291       if (getTemplateKind(DRE->getType()) != VectorKind)
    292           return state;
    293       // Now get the MemRegion associated with the instance.
    294       const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl());
    295       if (!VD)
    296         return state;
    297       const MemRegion *IMR = state->getRegion(VD, LC);
    298       if (!IMR)
    299         return state;
    300       // Finally, see if it is one of the calls that will create
    301       // a valid iterator and mark it if so, else mark as Unknown.
    302       StringRef mName = ME->getMemberDecl()->getName();
    303 
    304       if (llvm::StringSwitch<bool>(mName)
    305           .Cases("begin", "insert", "erase", true).Default(false)) {
    306         return state->set<IteratorState>(MR, RefState::getBeginValid(IMR));
    307       }
    308       if (mName == "end")
    309         return state->set<IteratorState>(MR, RefState::getEndValid(IMR));
    310 
    311       return state->set<IteratorState>(MR, RefState::getUnknown());
    312     }
    313   }
    314   // Handle straight copy from another iterator.
    315   if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(rexp)) {
    316     if (getTemplateKind(DRE->getType()) != VectorIteratorKind)
    317       return state;
    318     // Now get the MemRegion associated with the instance.
    319     const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl());
    320     if (!VD)
    321       return state;
    322     const MemRegion *IMR = state->getRegion(VD, LC);
    323     if (!IMR)
    324       return state;
    325     // Get the RefState of the iterator being copied.
    326     const RefState *RS = state->get<IteratorState>(IMR);
    327     if (!RS)
    328       return state;
    329     // Use it to set the state of the LValue.
    330     return state->set<IteratorState>(MR, *RS);
    331   }
    332   // If we have operator+ or operator- ...
    333   if (const CXXOperatorCallExpr *OCE = dyn_cast<CXXOperatorCallExpr>(rexp)) {
    334     OverloadedOperatorKind Kind = OCE->getOperator();
    335     if (Kind == OO_Plus || Kind == OO_Minus) {
    336       // Check left side of tree for a valid value.
    337       state = handleAssign( state, MR, OCE->getArg(0), LC);
    338       const RefState *RS = state->get<IteratorState>(MR);
    339       // If found, return it.
    340       if (!RS->isUnknown())
    341         return state;
    342       // Otherwise return what we find in the right side.
    343       return handleAssign(state, MR, OCE->getArg(1), LC);
    344     }
    345   }
    346   // Fall through if nothing matched.
    347   return state;
    348 }
    349 
    350 // Iterate through the arguments looking for an Invalid or Undefined iterator.
    351 void IteratorsChecker::checkArgs(CheckerContext &C, const CallExpr *CE) const {
    352   for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end();
    353        I != E; ++I) {
    354     checkExpr(C, *I);
    355   }
    356 }
    357 
    358 // Get the DeclRefExpr associated with the expression.
    359 const DeclRefExpr *IteratorsChecker::getDeclRefExpr(const Expr *E) const {
    360   // If it is a CXXConstructExpr, need to get the subexpression.
    361   if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(E)) {
    362     if (CE->getNumArgs()== 1) {
    363       CXXConstructorDecl *CD = CE->getConstructor();
    364       if (CD->isTrivial())
    365         E = CE->getArg(0);
    366     }
    367   }
    368   if (const MaterializeTemporaryExpr *M = dyn_cast<MaterializeTemporaryExpr>(E))
    369     E = M->GetTemporaryExpr();
    370   if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E))
    371     E = ICE->getSubExpr();
    372   // If it isn't one of our types, don't do anything.
    373   if (getTemplateKind(E->getType()) != VectorIteratorKind)
    374     return NULL;
    375   return dyn_cast<DeclRefExpr>(E);
    376 }
    377 
    378 // Get the MemRegion associated with the expresssion.
    379 const MemRegion *IteratorsChecker::getRegion(const ProgramState *state,
    380     const Expr *E, const LocationContext *LC) const {
    381   const DeclRefExpr *DRE = getDeclRefExpr(E);
    382   if (!DRE)
    383     return NULL;
    384   const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl());
    385   if (!VD)
    386     return NULL;
    387   // return the MemRegion associated with the iterator
    388   return state->getRegion(VD, LC);
    389 }
    390 
    391 // Check the expression and if it is an iterator, generate a diagnostic
    392 // if the iterator is not valid.
    393 // FIXME: this method can generate new nodes, and subsequent logic should
    394 // use those nodes.  We also cannot create multiple nodes at one ProgramPoint
    395 // with the same tag.
    396 void IteratorsChecker::checkExpr(CheckerContext &C, const Expr *E) const {
    397   const ProgramState *state = C.getState();
    398   const MemRegion *MR = getRegion(state, E,
    399                    C.getPredecessor()->getLocationContext());
    400   if (!MR)
    401     return;
    402 
    403   // Get the state associated with the iterator.
    404   const RefState *RS = state->get<IteratorState>(MR);
    405   if (!RS)
    406     return;
    407   if (RS->isInvalid()) {
    408     if (ExplodedNode *N = C.generateNode()) {
    409       if (!BT_Invalid)
    410         // FIXME: We are eluding constness here.
    411         const_cast<IteratorsChecker*>(this)->BT_Invalid = new BuiltinBug("");
    412 
    413       std::string msg;
    414       const MemberExpr *ME = RS->getMemberExpr();
    415       if (ME) {
    416         std::string name = ME->getMemberNameInfo().getAsString();
    417         msg = "Attempt to use an iterator made invalid by call to '" +
    418                                                                   name + "'";
    419       }
    420       else {
    421         msg = "Attempt to use an iterator made invalid by copying another "
    422                     "container to its container";
    423       }
    424 
    425       BugReport *R = new BugReport(*BT_Invalid, msg, N);
    426       R->addRange(getDeclRefExpr(E)->getSourceRange());
    427       C.EmitReport(R);
    428     }
    429   }
    430   else if (RS->isUndefined()) {
    431     if (ExplodedNode *N = C.generateNode()) {
    432       if (!BT_Undefined)
    433         // FIXME: We are eluding constness here.
    434         const_cast<IteratorsChecker*>(this)->BT_Undefined =
    435           new BuiltinBug("Use of iterator that is not defined");
    436 
    437       BugReport *R = new BugReport(*BT_Undefined,
    438                                            BT_Undefined->getDescription(), N);
    439       R->addRange(getDeclRefExpr(E)->getSourceRange());
    440       C.EmitReport(R);
    441     }
    442   }
    443 }
    444 
    445 // ===============================================
    446 // Path analysis visitor functions
    447 // ===============================================
    448 
    449 // For a generic Call, just check the args for bad iterators.
    450 void IteratorsChecker::checkPreStmt(const CallExpr *CE,
    451                                     CheckerContext &C) const{
    452 
    453   // FIXME: These checks are to currently work around a bug
    454   // in CheckerManager.
    455   if (isa<CXXOperatorCallExpr>(CE))
    456     return;
    457   if (isa<CXXMemberCallExpr>(CE))
    458     return;
    459 
    460   checkArgs(C, CE);
    461 }
    462 
    463 // Handle operator calls. First, if it is operator=, check the argument,
    464 // and handle assigning and set target state appropriately. Otherwise, for
    465 // other operators, check the args for bad iterators and handle comparisons.
    466 void IteratorsChecker::checkPreStmt(const CXXOperatorCallExpr *OCE,
    467                                     CheckerContext &C) const
    468 {
    469   const LocationContext *LC = C.getPredecessor()->getLocationContext();
    470   const ProgramState *state = C.getState();
    471   OverloadedOperatorKind Kind = OCE->getOperator();
    472   if (Kind == OO_Equal) {
    473     checkExpr(C, OCE->getArg(1));
    474     state = handleAssign(state, OCE->getArg(0), OCE->getArg(1), LC);
    475     C.addTransition(state);
    476     return;
    477   }
    478   else {
    479     checkArgs(C, OCE);
    480     // If it is a compare and both are iterators, ensure that they are for
    481     // the same container.
    482     if (Kind == OO_EqualEqual || Kind == OO_ExclaimEqual ||
    483         Kind == OO_Less || Kind == OO_LessEqual ||
    484         Kind == OO_Greater || Kind == OO_GreaterEqual) {
    485       const MemRegion *MR0, *MR1;
    486       MR0 = getRegion(state, OCE->getArg(0), LC);
    487       if (!MR0)
    488         return;
    489       MR1 = getRegion(state, OCE->getArg(1), LC);
    490       if (!MR1)
    491         return;
    492       const RefState *RS0, *RS1;
    493       RS0 = state->get<IteratorState>(MR0);
    494       if (!RS0)
    495         return;
    496       RS1 = state->get<IteratorState>(MR1);
    497       if (!RS1)
    498         return;
    499       if (RS0->getMemRegion() != RS1->getMemRegion()) {
    500       if (ExplodedNode *N = C.generateNode()) {
    501           if (!BT_Incompatible)
    502             const_cast<IteratorsChecker*>(this)->BT_Incompatible =
    503               new BuiltinBug(
    504                       "Cannot compare iterators from different containers");
    505 
    506           BugReport *R = new BugReport(*BT_Incompatible,
    507                                         BT_Incompatible->getDescription(), N);
    508           R->addRange(OCE->getSourceRange());
    509           C.EmitReport(R);
    510         }
    511       }
    512     }
    513   }
    514 }
    515 
    516 // Need to handle DeclStmts to pick up initializing of iterators and to mark
    517 // uninitialized ones as Undefined.
    518 void IteratorsChecker::checkPreStmt(const DeclStmt *DS,
    519                                     CheckerContext &C) const {
    520   const Decl *D = *DS->decl_begin();
    521   const VarDecl *VD = dyn_cast<VarDecl>(D);
    522   // Only care about iterators.
    523   if (getTemplateKind(VD->getType()) != VectorIteratorKind)
    524     return;
    525 
    526   // Get the MemRegion associated with the iterator and mark it as Undefined.
    527   const ProgramState *state = C.getState();
    528   Loc VarLoc = state->getLValue(VD, C.getPredecessor()->getLocationContext());
    529   const MemRegion *MR = VarLoc.getAsRegion();
    530   if (!MR)
    531     return;
    532   state = state->set<IteratorState>(MR, RefState::getUndefined());
    533 
    534   // if there is an initializer, handle marking Valid if a proper initializer
    535   const Expr *InitEx = VD->getInit();
    536   if (InitEx) {
    537     // FIXME: This is too syntactic.  Since 'InitEx' will be analyzed first
    538     // it should resolve to an SVal that we can check for validity
    539     // *semantically* instead of walking through the AST.
    540     if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(InitEx)) {
    541       if (CE->getNumArgs() == 1) {
    542         const Expr *E = CE->getArg(0);
    543         if (const MaterializeTemporaryExpr *M
    544                                         = dyn_cast<MaterializeTemporaryExpr>(E))
    545           E = M->GetTemporaryExpr();
    546         if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E))
    547           InitEx = ICE->getSubExpr();
    548         state = handleAssign(state, MR, InitEx,
    549                                   C.getPredecessor()->getLocationContext());
    550       }
    551     }
    552   }
    553   C.addTransition(state);
    554 }
    555 
    556 
    557 namespace { struct CalledReserved {}; }
    558 namespace clang { namespace ento {
    559 template<> struct ProgramStateTrait<CalledReserved>
    560     :  public ProgramStatePartialTrait<llvm::ImmutableSet<const MemRegion*> > {
    561   static void *GDMIndex() { static int index = 0; return &index; }
    562 };
    563 }}
    564 
    565 // on a member call, first check the args for any bad iterators
    566 // then, check to see if it is a call to a function that will invalidate
    567 // the iterators
    568 void IteratorsChecker::checkPreStmt(const CXXMemberCallExpr *MCE,
    569                                     CheckerContext &C) const {
    570   // Check the arguments.
    571   checkArgs(C, MCE);
    572   const MemberExpr *ME = dyn_cast<MemberExpr>(MCE->getCallee());
    573   if (!ME)
    574     return;
    575   // Make sure we have the right kind of container.
    576   const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ME->getBase());
    577   if (!DRE || getTemplateKind(DRE->getType()) != VectorKind)
    578     return;
    579   SVal tsv = C.getState()->getSVal(DRE);
    580   // Get the MemRegion associated with the container instance.
    581   const MemRegion *MR = tsv.getAsRegion();
    582   if (!MR)
    583     return;
    584   // If we are calling a function that invalidates iterators, mark them
    585   // appropriately by finding matching instances.
    586   const ProgramState *state = C.getState();
    587   StringRef mName = ME->getMemberDecl()->getName();
    588   if (llvm::StringSwitch<bool>(mName)
    589       .Cases("insert", "reserve", "push_back", true)
    590       .Cases("erase", "pop_back", "clear", "resize", true)
    591       .Default(false)) {
    592     // If there was a 'reserve' call, assume iterators are good.
    593     if (!state->contains<CalledReserved>(MR))
    594       state = invalidateIterators(state, MR, ME);
    595   }
    596   // Keep track of instances that have called 'reserve'
    597   // note: do this after we invalidate any iterators by calling
    598   // 'reserve' itself.
    599   if (mName == "reserve")
    600     state = state->add<CalledReserved>(MR);
    601 
    602   if (state != C.getState())
    603     C.addTransition(state);
    604 }
    605 
    606