blob: ab3242bdf5b26d008b1e2420d6ad83b5b64f4b15 [file] [log] [blame]
Ted Kremenekdd54de82011-03-12 02:49:15 +00001//=== 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"
Ted Kremenek18c66fd2011-08-15 22:09:50 +000023#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
Ted Kremenekdd54de82011-03-12 02:49:15 +000024#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
32using namespace clang;
33using 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.
38namespace {
39class RefState {
40 enum Kind { BeginValid, EndValid, Invalid, Undefined, Unknown } K;
41 const void *VR;
42
43public:
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
89enum RefKind { NoKind, VectorKind, VectorIteratorKind };
90
91class 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
100public:
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
119private:
Ted Kremenek18c66fd2011-08-15 22:09:50 +0000120 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
Ted Kremenekdd54de82011-03-12 02:49:15 +0000134 void checkExpr(CheckerContext &C, const Expr *E) const;
Ted Kremenek18c66fd2011-08-15 22:09:50 +0000135
Ted Kremenekdd54de82011-03-12 02:49:15 +0000136 void checkArgs(CheckerContext &C, const CallExpr *CE) const;
Ted Kremenek18c66fd2011-08-15 22:09:50 +0000137
138 const MemRegion *getRegion(const ProgramState *state,
139 const Expr *E,
140 const LocationContext *LC) const;
141
Ted Kremenekdd54de82011-03-12 02:49:15 +0000142 const DeclRefExpr *getDeclRefExpr(const Expr *E) const;
143};
144
145class IteratorState {
146public:
147 typedef llvm::ImmutableMap<const MemRegion *, RefState> EntryMap;
148};
149} //end anonymous namespace
150
151namespace clang {
152 namespace ento {
153 template <>
Ted Kremenek18c66fd2011-08-15 22:09:50 +0000154 struct ProgramStateTrait<IteratorState>
155 : public ProgramStatePartialTrait<IteratorState::EntryMap> {
Ted Kremenekdd54de82011-03-12 02:49:15 +0000156 static void *GDMIndex() { return IteratorsChecker::getTag(); }
157 };
158 }
159}
160
161void 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
170static 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
Chris Lattner5f9e2722011-07-23 10:55:15 +0000177 StringRef name = td->getName();
Ted Kremenekdd54de82011-03-12 02:49:15 +0000178 return llvm::StringSwitch<RefKind>(name)
179 .Cases("vector", "deque", VectorKind)
180 .Default(NoKind);
181}
182
183static 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
190static RefKind getTemplateKind(const TypedefType *tdt) {
Richard Smith162e1c12011-04-15 14:24:37 +0000191 const TypedefNameDecl *td = tdt->getDecl();
Ted Kremenekdd54de82011-03-12 02:49:15 +0000192 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
203static 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
211static 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.
Ted Kremenek18c66fd2011-08-15 22:09:50 +0000230const ProgramState *IteratorsChecker::invalidateIterators(const ProgramState *state,
Ted Kremenekdd54de82011-03-12 02:49:15 +0000231 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.
Ted Kremenek18c66fd2011-08-15 22:09:50 +0000249const ProgramState *IteratorsChecker::handleAssign(const ProgramState *state,
Ted Kremenekdd54de82011-03-12 02:49:15 +0000250 const Expr *lexp, const Expr *rexp, const LocationContext *LC) const {
251 // Skip the cast if present.
Douglas Gregor03e80032011-06-21 17:03:29 +0000252 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();
Ted Kremenekdd54de82011-03-12 02:49:15 +0000257 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
Ted Kremenek18c66fd2011-08-15 22:09:50 +0000274const ProgramState *IteratorsChecker::handleAssign(const ProgramState *state,
Ted Kremenekdd54de82011-03-12 02:49:15 +0000275 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());
Douglas Gregor03e80032011-06-21 17:03:29 +0000278 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();
Ted Kremenekdd54de82011-03-12 02:49:15 +0000283 // 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.
Chris Lattner5f9e2722011-07-23 10:55:15 +0000302 StringRef mName = ME->getMemberDecl()->getName();
Ted Kremenek7084da32011-03-12 04:08:07 +0000303
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());
Ted Kremenekdd54de82011-03-12 02:49:15 +0000312 }
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.
351void 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.
359const 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 }
Douglas Gregor03e80032011-06-21 17:03:29 +0000368 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();
Ted Kremenekdd54de82011-03-12 02:49:15 +0000372 // 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.
Ted Kremenek18c66fd2011-08-15 22:09:50 +0000379const MemRegion *IteratorsChecker::getRegion(const ProgramState *state,
Ted Kremenekdd54de82011-03-12 02:49:15 +0000380 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.
396void IteratorsChecker::checkExpr(CheckerContext &C, const Expr *E) const {
Ted Kremenek18c66fd2011-08-15 22:09:50 +0000397 const ProgramState *state = C.getState();
Anna Zaks39ac1872011-10-26 21:06:44 +0000398 const MemRegion *MR = getRegion(state, E, C.getLocationContext());
Ted Kremenekdd54de82011-03-12 02:49:15 +0000399 if (!MR)
400 return;
401
402 // Get the state associated with the iterator.
403 const RefState *RS = state->get<IteratorState>(MR);
404 if (!RS)
405 return;
406 if (RS->isInvalid()) {
Anna Zaks0bd6b112011-10-26 21:06:34 +0000407 if (ExplodedNode *N = C.addTransition()) {
Ted Kremenekdd54de82011-03-12 02:49:15 +0000408 if (!BT_Invalid)
409 // FIXME: We are eluding constness here.
410 const_cast<IteratorsChecker*>(this)->BT_Invalid = new BuiltinBug("");
411
412 std::string msg;
413 const MemberExpr *ME = RS->getMemberExpr();
414 if (ME) {
415 std::string name = ME->getMemberNameInfo().getAsString();
416 msg = "Attempt to use an iterator made invalid by call to '" +
417 name + "'";
418 }
419 else {
420 msg = "Attempt to use an iterator made invalid by copying another "
421 "container to its container";
422 }
423
Anna Zakse172e8b2011-08-17 23:00:25 +0000424 BugReport *R = new BugReport(*BT_Invalid, msg, N);
Ted Kremenekdd54de82011-03-12 02:49:15 +0000425 R->addRange(getDeclRefExpr(E)->getSourceRange());
426 C.EmitReport(R);
427 }
428 }
429 else if (RS->isUndefined()) {
Anna Zaks0bd6b112011-10-26 21:06:34 +0000430 if (ExplodedNode *N = C.addTransition()) {
Ted Kremenekdd54de82011-03-12 02:49:15 +0000431 if (!BT_Undefined)
432 // FIXME: We are eluding constness here.
433 const_cast<IteratorsChecker*>(this)->BT_Undefined =
434 new BuiltinBug("Use of iterator that is not defined");
435
Anna Zakse172e8b2011-08-17 23:00:25 +0000436 BugReport *R = new BugReport(*BT_Undefined,
Ted Kremenekdd54de82011-03-12 02:49:15 +0000437 BT_Undefined->getDescription(), N);
438 R->addRange(getDeclRefExpr(E)->getSourceRange());
439 C.EmitReport(R);
440 }
441 }
442}
443
444// ===============================================
445// Path analysis visitor functions
446// ===============================================
447
448// For a generic Call, just check the args for bad iterators.
449void IteratorsChecker::checkPreStmt(const CallExpr *CE,
450 CheckerContext &C) const{
451
452 // FIXME: These checks are to currently work around a bug
453 // in CheckerManager.
454 if (isa<CXXOperatorCallExpr>(CE))
455 return;
456 if (isa<CXXMemberCallExpr>(CE))
457 return;
458
459 checkArgs(C, CE);
460}
461
462// Handle operator calls. First, if it is operator=, check the argument,
463// and handle assigning and set target state appropriately. Otherwise, for
464// other operators, check the args for bad iterators and handle comparisons.
465void IteratorsChecker::checkPreStmt(const CXXOperatorCallExpr *OCE,
466 CheckerContext &C) const
467{
Anna Zaks39ac1872011-10-26 21:06:44 +0000468 const LocationContext *LC = C.getLocationContext();
Ted Kremenek18c66fd2011-08-15 22:09:50 +0000469 const ProgramState *state = C.getState();
Ted Kremenekdd54de82011-03-12 02:49:15 +0000470 OverloadedOperatorKind Kind = OCE->getOperator();
471 if (Kind == OO_Equal) {
472 checkExpr(C, OCE->getArg(1));
473 state = handleAssign(state, OCE->getArg(0), OCE->getArg(1), LC);
Anna Zaks0bd6b112011-10-26 21:06:34 +0000474 C.addTransition(state);
Ted Kremenekdd54de82011-03-12 02:49:15 +0000475 return;
476 }
477 else {
478 checkArgs(C, OCE);
479 // If it is a compare and both are iterators, ensure that they are for
480 // the same container.
481 if (Kind == OO_EqualEqual || Kind == OO_ExclaimEqual ||
482 Kind == OO_Less || Kind == OO_LessEqual ||
483 Kind == OO_Greater || Kind == OO_GreaterEqual) {
484 const MemRegion *MR0, *MR1;
485 MR0 = getRegion(state, OCE->getArg(0), LC);
486 if (!MR0)
487 return;
488 MR1 = getRegion(state, OCE->getArg(1), LC);
489 if (!MR1)
490 return;
491 const RefState *RS0, *RS1;
492 RS0 = state->get<IteratorState>(MR0);
493 if (!RS0)
494 return;
495 RS1 = state->get<IteratorState>(MR1);
496 if (!RS1)
497 return;
498 if (RS0->getMemRegion() != RS1->getMemRegion()) {
Anna Zaks0bd6b112011-10-26 21:06:34 +0000499 if (ExplodedNode *N = C.addTransition()) {
Ted Kremenekdd54de82011-03-12 02:49:15 +0000500 if (!BT_Incompatible)
501 const_cast<IteratorsChecker*>(this)->BT_Incompatible =
502 new BuiltinBug(
503 "Cannot compare iterators from different containers");
504
Anna Zakse172e8b2011-08-17 23:00:25 +0000505 BugReport *R = new BugReport(*BT_Incompatible,
506 BT_Incompatible->getDescription(), N);
Ted Kremenekdd54de82011-03-12 02:49:15 +0000507 R->addRange(OCE->getSourceRange());
508 C.EmitReport(R);
509 }
510 }
511 }
512 }
513}
514
515// Need to handle DeclStmts to pick up initializing of iterators and to mark
516// uninitialized ones as Undefined.
517void IteratorsChecker::checkPreStmt(const DeclStmt *DS,
518 CheckerContext &C) const {
Ted Kremenek9c378f72011-08-12 23:37:29 +0000519 const Decl *D = *DS->decl_begin();
520 const VarDecl *VD = dyn_cast<VarDecl>(D);
Ted Kremenekdd54de82011-03-12 02:49:15 +0000521 // Only care about iterators.
522 if (getTemplateKind(VD->getType()) != VectorIteratorKind)
523 return;
524
525 // Get the MemRegion associated with the iterator and mark it as Undefined.
Ted Kremenek18c66fd2011-08-15 22:09:50 +0000526 const ProgramState *state = C.getState();
Anna Zaks39ac1872011-10-26 21:06:44 +0000527 Loc VarLoc = state->getLValue(VD, C.getLocationContext());
Ted Kremenekdd54de82011-03-12 02:49:15 +0000528 const MemRegion *MR = VarLoc.getAsRegion();
529 if (!MR)
530 return;
531 state = state->set<IteratorState>(MR, RefState::getUndefined());
532
533 // if there is an initializer, handle marking Valid if a proper initializer
Ted Kremenek9c378f72011-08-12 23:37:29 +0000534 const Expr *InitEx = VD->getInit();
Ted Kremenekdd54de82011-03-12 02:49:15 +0000535 if (InitEx) {
536 // FIXME: This is too syntactic. Since 'InitEx' will be analyzed first
537 // it should resolve to an SVal that we can check for validity
538 // *semantically* instead of walking through the AST.
539 if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(InitEx)) {
540 if (CE->getNumArgs() == 1) {
541 const Expr *E = CE->getArg(0);
Douglas Gregor03e80032011-06-21 17:03:29 +0000542 if (const MaterializeTemporaryExpr *M
543 = dyn_cast<MaterializeTemporaryExpr>(E))
544 E = M->GetTemporaryExpr();
545 if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E))
546 InitEx = ICE->getSubExpr();
Anna Zaks39ac1872011-10-26 21:06:44 +0000547 state = handleAssign(state, MR, InitEx, C.getLocationContext());
Ted Kremenekdd54de82011-03-12 02:49:15 +0000548 }
549 }
550 }
Anna Zaks0bd6b112011-10-26 21:06:34 +0000551 C.addTransition(state);
Ted Kremenekdd54de82011-03-12 02:49:15 +0000552}
553
554
555namespace { struct CalledReserved {}; }
556namespace clang { namespace ento {
Ted Kremenek18c66fd2011-08-15 22:09:50 +0000557template<> struct ProgramStateTrait<CalledReserved>
558 : public ProgramStatePartialTrait<llvm::ImmutableSet<const MemRegion*> > {
Ted Kremenekdd54de82011-03-12 02:49:15 +0000559 static void *GDMIndex() { static int index = 0; return &index; }
560};
561}}
562
563// on a member call, first check the args for any bad iterators
564// then, check to see if it is a call to a function that will invalidate
565// the iterators
566void IteratorsChecker::checkPreStmt(const CXXMemberCallExpr *MCE,
567 CheckerContext &C) const {
568 // Check the arguments.
569 checkArgs(C, MCE);
570 const MemberExpr *ME = dyn_cast<MemberExpr>(MCE->getCallee());
571 if (!ME)
572 return;
573 // Make sure we have the right kind of container.
574 const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ME->getBase());
575 if (!DRE || getTemplateKind(DRE->getType()) != VectorKind)
576 return;
577 SVal tsv = C.getState()->getSVal(DRE);
578 // Get the MemRegion associated with the container instance.
579 const MemRegion *MR = tsv.getAsRegion();
580 if (!MR)
581 return;
582 // If we are calling a function that invalidates iterators, mark them
583 // appropriately by finding matching instances.
Ted Kremenek18c66fd2011-08-15 22:09:50 +0000584 const ProgramState *state = C.getState();
Chris Lattner5f9e2722011-07-23 10:55:15 +0000585 StringRef mName = ME->getMemberDecl()->getName();
Ted Kremenekdd54de82011-03-12 02:49:15 +0000586 if (llvm::StringSwitch<bool>(mName)
587 .Cases("insert", "reserve", "push_back", true)
588 .Cases("erase", "pop_back", "clear", "resize", true)
589 .Default(false)) {
590 // If there was a 'reserve' call, assume iterators are good.
591 if (!state->contains<CalledReserved>(MR))
592 state = invalidateIterators(state, MR, ME);
593 }
594 // Keep track of instances that have called 'reserve'
595 // note: do this after we invalidate any iterators by calling
596 // 'reserve' itself.
597 if (mName == "reserve")
598 state = state->add<CalledReserved>(MR);
599
600 if (state != C.getState())
Anna Zaks0bd6b112011-10-26 21:06:34 +0000601 C.addTransition(state);
Ted Kremenekdd54de82011-03-12 02:49:15 +0000602}
603