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