IteratorsChecker.cpp 21 KB

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