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