1 //=== IteratorsChecker.cpp - Check for Invalidated Iterators ------*- C++ -*----
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
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'
14 //===----------------------------------------------------------------------===//
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"
32 using namespace clang;
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.
40 enum Kind { BeginValid, EndValid, Invalid, Undefined, Unknown } K;
44 RefState(Kind k, const void *vr) : K(k), VR(vr) {}
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;
55 const MemberExpr *getMemberExpr() const {
57 return(const MemberExpr *)VR;
61 bool operator==(const RefState &X) const {
62 return K == X.K && VR == X.VR;
65 static RefState getBeginValid(const MemRegion *vr) {
67 return RefState(BeginValid, vr);
69 static RefState getEndValid(const MemRegion *vr) {
71 return RefState(EndValid, vr);
73 static RefState getInvalid( const MemberExpr *ME ) {
74 return RefState(Invalid, ME);
76 static RefState getUndefined( void ) {
77 return RefState(Undefined, 0);
79 static RefState getUnknown( void ) {
80 return RefState(Unknown, 0);
83 void Profile(llvm::FoldingSetNodeID &ID) const {
89 enum RefKind { NoKind, VectorKind, VectorIteratorKind };
91 class IteratorsChecker :
92 public Checker<check::PreStmt<CXXOperatorCallExpr>,
93 check::PreStmt<DeclStmt>,
94 check::PreStmt<CXXMemberCallExpr>,
95 check::PreStmt<CallExpr> >
97 // Used when parsing iterators and vectors and deques.
98 BuiltinBug *BT_Invalid, *BT_Undefined, *BT_Incompatible;
102 BT_Invalid(0), BT_Undefined(0), BT_Incompatible(0)
104 static void *getTag() { static int tag; return &tag; }
106 // Checker entry points.
107 void checkPreStmt(const CXXOperatorCallExpr *OCE,
108 CheckerContext &C) const;
110 void checkPreStmt(const DeclStmt *DS,
111 CheckerContext &C) const;
113 void checkPreStmt(const CXXMemberCallExpr *MCE,
114 CheckerContext &C) const;
116 void checkPreStmt(const CallExpr *CE,
117 CheckerContext &C) const;
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;
133 class IteratorState {
135 typedef llvm::ImmutableMap<const MemRegion *, RefState> EntryMap;
137 } //end anonymous namespace
142 struct GRStateTrait<IteratorState>
143 : public GRStatePartialTrait<IteratorState::EntryMap> {
144 static void *GDMIndex() { return IteratorsChecker::getTag(); }
149 void ento::registerIteratorsChecker(CheckerManager &mgr) {
150 mgr.registerChecker<IteratorsChecker>();
153 // ===============================================
154 // Utility functions used by visitor functions
155 // ===============================================
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")
165 llvm::StringRef name = td->getName();
166 return llvm::StringSwitch<RefKind>(name)
167 .Cases("vector", "deque", VectorKind)
171 static RefKind getTemplateKind(const DeclContext *dc) {
172 if (const ClassTemplateSpecializationDecl *td =
173 dyn_cast<ClassTemplateSpecializationDecl>(dc))
174 return getTemplateKind(cast<NamedDecl>(td));
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())
185 "reverse_iterator", VectorIteratorKind)
191 static RefKind getTemplateKind(const TemplateSpecializationType *tsp) {
192 const TemplateName &tname = tsp->getTemplateName();
193 TemplateDecl *td = tname.getAsTemplateDecl();
196 return getTemplateKind(td);
199 static RefKind getTemplateKind(QualType T) {
200 if (const TemplateSpecializationType *tsp =
201 T->getAs<TemplateSpecializationType>()) {
202 return getTemplateKind(tsp);
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);
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>();
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();
228 RefState RS = I.getData();
229 if (RS.getMemRegion() == MR)
230 state = state->set<IteratorState>(I.getKey(), RefState::getInvalid(ME));
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();
249 RefKind kind = getTemplateKind(lexp->getType());
251 // If assigning to a vector, invalidate any iterators currently associated.
252 if (kind == VectorKind)
253 return invalidateIterators(state, MR, 0);
255 // Make sure that we are assigning to an iterator.
256 if (getTemplateKind(lexp->getType()) != VectorIteratorKind)
258 return handleAssign(state, MR, rexp, LC);
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());
278 // Verify that the type is std::vector<T>.
279 if (getTemplateKind(DRE->getType()) != VectorKind)
281 // Now get the MemRegion associated with the instance.
282 const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl());
285 const MemRegion *IMR = state->getRegion(VD, LC);
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();
292 if (llvm::StringSwitch<bool>(mName)
293 .Cases("begin", "insert", "erase", true).Default(false)) {
294 return state->set<IteratorState>(MR, RefState::getBeginValid(IMR));
297 return state->set<IteratorState>(MR, RefState::getEndValid(IMR));
299 return state->set<IteratorState>(MR, RefState::getUnknown());
302 // Handle straight copy from another iterator.
303 if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(rexp)) {
304 if (getTemplateKind(DRE->getType()) != VectorIteratorKind)
306 // Now get the MemRegion associated with the instance.
307 const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl());
310 const MemRegion *IMR = state->getRegion(VD, LC);
313 // Get the RefState of the iterator being copied.
314 const RefState *RS = state->get<IteratorState>(IMR);
317 // Use it to set the state of the LValue.
318 return state->set<IteratorState>(MR, *RS);
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())
330 // Otherwise return what we find in the right side.
331 return handleAssign(state, MR, OCE->getArg(1), LC);
334 // Fall through if nothing matched.
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();
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();
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)
363 return dyn_cast<DeclRefExpr>(E);
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);
372 const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl());
375 // return the MemRegion associated with the iterator
376 return state->getRegion(VD, LC);
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());
391 // Get the state associated with the iterator.
392 const RefState *RS = state->get<IteratorState>(MR);
395 if (RS->isInvalid()) {
396 if (ExplodedNode *N = C.generateNode()) {
398 // FIXME: We are eluding constness here.
399 const_cast<IteratorsChecker*>(this)->BT_Invalid = new BuiltinBug("");
402 const MemberExpr *ME = RS->getMemberExpr();
404 std::string name = ME->getMemberNameInfo().getAsString();
405 msg = "Attempt to use an iterator made invalid by call to '" +
409 msg = "Attempt to use an iterator made invalid by copying another "
410 "container to its container";
413 EnhancedBugReport *R = new EnhancedBugReport(*BT_Invalid, msg, N);
414 R->addRange(getDeclRefExpr(E)->getSourceRange());
418 else if (RS->isUndefined()) {
419 if (ExplodedNode *N = C.generateNode()) {
421 // FIXME: We are eluding constness here.
422 const_cast<IteratorsChecker*>(this)->BT_Undefined =
423 new BuiltinBug("Use of iterator that is not defined");
425 EnhancedBugReport *R = new EnhancedBugReport(*BT_Undefined,
426 BT_Undefined->getDescription(), N);
427 R->addRange(getDeclRefExpr(E)->getSourceRange());
433 // ===============================================
434 // Path analysis visitor functions
435 // ===============================================
437 // For a generic Call, just check the args for bad iterators.
438 void IteratorsChecker::checkPreStmt(const CallExpr *CE,
439 CheckerContext &C) const{
441 // FIXME: These checks are to currently work around a bug
442 // in CheckerManager.
443 if (isa<CXXOperatorCallExpr>(CE))
445 if (isa<CXXMemberCallExpr>(CE))
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
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);
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);
477 MR1 = getRegion(state, OCE->getArg(1), LC);
480 const RefState *RS0, *RS1;
481 RS0 = state->get<IteratorState>(MR0);
484 RS1 = state->get<IteratorState>(MR1);
487 if (RS0->getMemRegion() != RS1->getMemRegion()) {
488 if (ExplodedNode *N = C.generateNode()) {
489 if (!BT_Incompatible)
490 const_cast<IteratorsChecker*>(this)->BT_Incompatible =
492 "Cannot compare iterators from different containers");
494 EnhancedBugReport *R = new EnhancedBugReport(*BT_Incompatible,
495 BT_Incompatible->getDescription(), N);
496 R->addRange(OCE->getSourceRange());
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)
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();
520 state = state->set<IteratorState>(MR, RefState::getUndefined());
522 // if there is an initializer, handle marking Valid if a proper initializer
523 const Expr* InitEx = VD->getInit();
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());
541 C.addTransition(state);
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; }
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
556 void IteratorsChecker::checkPreStmt(const CXXMemberCallExpr *MCE,
557 CheckerContext &C) const {
558 // Check the arguments.
560 const MemberExpr *ME = dyn_cast<MemberExpr>(MCE->getCallee());
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)
567 SVal tsv = C.getState()->getSVal(DRE);
568 // Get the MemRegion associated with the container instance.
569 const MemRegion *MR = tsv.getAsRegion();
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)
580 // If there was a 'reserve' call, assume iterators are good.
581 if (!state->contains<CalledReserved>(MR))
582 state = invalidateIterators(state, MR, ME);
584 // Keep track of instances that have called 'reserve'
585 // note: do this after we invalidate any iterators by calling
587 if (mName == "reserve")
588 state = state->add<CalledReserved>(MR);
590 if (state != C.getState())
591 C.addTransition(state);