1*480093f4SDimitry Andric //===-- IteratorModeling.cpp --------------------------------------*- C++ -*--// 2*480093f4SDimitry Andric // 3*480093f4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*480093f4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*480093f4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*480093f4SDimitry Andric // 7*480093f4SDimitry Andric //===----------------------------------------------------------------------===// 8*480093f4SDimitry Andric // 9*480093f4SDimitry Andric // Defines a checker for using iterators outside their range (past end). Usage 10*480093f4SDimitry Andric // means here dereferencing, incrementing etc. 11*480093f4SDimitry Andric // 12*480093f4SDimitry Andric //===----------------------------------------------------------------------===// 13*480093f4SDimitry Andric // 14*480093f4SDimitry Andric // In the code, iterator can be represented as a: 15*480093f4SDimitry Andric // * type-I: typedef-ed pointer. Operations over such iterator, such as 16*480093f4SDimitry Andric // comparisons or increments, are modeled straightforwardly by the 17*480093f4SDimitry Andric // analyzer. 18*480093f4SDimitry Andric // * type-II: structure with its method bodies available. Operations over such 19*480093f4SDimitry Andric // iterator are inlined by the analyzer, and results of modeling 20*480093f4SDimitry Andric // these operations are exposing implementation details of the 21*480093f4SDimitry Andric // iterators, which is not necessarily helping. 22*480093f4SDimitry Andric // * type-III: completely opaque structure. Operations over such iterator are 23*480093f4SDimitry Andric // modeled conservatively, producing conjured symbols everywhere. 24*480093f4SDimitry Andric // 25*480093f4SDimitry Andric // To handle all these types in a common way we introduce a structure called 26*480093f4SDimitry Andric // IteratorPosition which is an abstraction of the position the iterator 27*480093f4SDimitry Andric // represents using symbolic expressions. The checker handles all the 28*480093f4SDimitry Andric // operations on this structure. 29*480093f4SDimitry Andric // 30*480093f4SDimitry Andric // Additionally, depending on the circumstances, operators of types II and III 31*480093f4SDimitry Andric // can be represented as: 32*480093f4SDimitry Andric // * type-IIa, type-IIIa: conjured structure symbols - when returned by value 33*480093f4SDimitry Andric // from conservatively evaluated methods such as 34*480093f4SDimitry Andric // `.begin()`. 35*480093f4SDimitry Andric // * type-IIb, type-IIIb: memory regions of iterator-typed objects, such as 36*480093f4SDimitry Andric // variables or temporaries, when the iterator object is 37*480093f4SDimitry Andric // currently treated as an lvalue. 38*480093f4SDimitry Andric // * type-IIc, type-IIIc: compound values of iterator-typed objects, when the 39*480093f4SDimitry Andric // iterator object is treated as an rvalue taken of a 40*480093f4SDimitry Andric // particular lvalue, eg. a copy of "type-a" iterator 41*480093f4SDimitry Andric // object, or an iterator that existed before the 42*480093f4SDimitry Andric // analysis has started. 43*480093f4SDimitry Andric // 44*480093f4SDimitry Andric // To handle any of these three different representations stored in an SVal we 45*480093f4SDimitry Andric // use setter and getters functions which separate the three cases. To store 46*480093f4SDimitry Andric // them we use a pointer union of symbol and memory region. 47*480093f4SDimitry Andric // 48*480093f4SDimitry Andric // The checker works the following way: We record the begin and the 49*480093f4SDimitry Andric // past-end iterator for all containers whenever their `.begin()` and `.end()` 50*480093f4SDimitry Andric // are called. Since the Constraint Manager cannot handle such SVals we need 51*480093f4SDimitry Andric // to take over its role. We post-check equality and non-equality comparisons 52*480093f4SDimitry Andric // and record that the two sides are equal if we are in the 'equal' branch 53*480093f4SDimitry Andric // (true-branch for `==` and false-branch for `!=`). 54*480093f4SDimitry Andric // 55*480093f4SDimitry Andric // In case of type-I or type-II iterators we get a concrete integer as a result 56*480093f4SDimitry Andric // of the comparison (1 or 0) but in case of type-III we only get a Symbol. In 57*480093f4SDimitry Andric // this latter case we record the symbol and reload it in evalAssume() and do 58*480093f4SDimitry Andric // the propagation there. We also handle (maybe double) negated comparisons 59*480093f4SDimitry Andric // which are represented in the form of (x == 0 or x != 0) where x is the 60*480093f4SDimitry Andric // comparison itself. 61*480093f4SDimitry Andric // 62*480093f4SDimitry Andric // Since `SimpleConstraintManager` cannot handle complex symbolic expressions 63*480093f4SDimitry Andric // we only use expressions of the format S, S+n or S-n for iterator positions 64*480093f4SDimitry Andric // where S is a conjured symbol and n is an unsigned concrete integer. When 65*480093f4SDimitry Andric // making an assumption e.g. `S1 + n == S2 + m` we store `S1 - S2 == m - n` as 66*480093f4SDimitry Andric // a constraint which we later retrieve when doing an actual comparison. 67*480093f4SDimitry Andric 68*480093f4SDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 69*480093f4SDimitry Andric #include "clang/AST/DeclTemplate.h" 70*480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 71*480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h" 72*480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 73*480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 74*480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h" 75*480093f4SDimitry Andric 76*480093f4SDimitry Andric #include "Iterator.h" 77*480093f4SDimitry Andric 78*480093f4SDimitry Andric #include <utility> 79*480093f4SDimitry Andric 80*480093f4SDimitry Andric using namespace clang; 81*480093f4SDimitry Andric using namespace ento; 82*480093f4SDimitry Andric using namespace iterator; 83*480093f4SDimitry Andric 84*480093f4SDimitry Andric namespace { 85*480093f4SDimitry Andric 86*480093f4SDimitry Andric class IteratorModeling 87*480093f4SDimitry Andric : public Checker<check::PostCall, check::PostStmt<MaterializeTemporaryExpr>, 88*480093f4SDimitry Andric check::Bind, check::LiveSymbols, check::DeadSymbols> { 89*480093f4SDimitry Andric 90*480093f4SDimitry Andric void handleComparison(CheckerContext &C, const Expr *CE, SVal RetVal, 91*480093f4SDimitry Andric const SVal &LVal, const SVal &RVal, 92*480093f4SDimitry Andric OverloadedOperatorKind Op) const; 93*480093f4SDimitry Andric void processComparison(CheckerContext &C, ProgramStateRef State, 94*480093f4SDimitry Andric SymbolRef Sym1, SymbolRef Sym2, const SVal &RetVal, 95*480093f4SDimitry Andric OverloadedOperatorKind Op) const; 96*480093f4SDimitry Andric void handleIncrement(CheckerContext &C, const SVal &RetVal, const SVal &Iter, 97*480093f4SDimitry Andric bool Postfix) const; 98*480093f4SDimitry Andric void handleDecrement(CheckerContext &C, const SVal &RetVal, const SVal &Iter, 99*480093f4SDimitry Andric bool Postfix) const; 100*480093f4SDimitry Andric void handleRandomIncrOrDecr(CheckerContext &C, const Expr *CE, 101*480093f4SDimitry Andric OverloadedOperatorKind Op, const SVal &RetVal, 102*480093f4SDimitry Andric const SVal &LHS, const SVal &RHS) const; 103*480093f4SDimitry Andric void handleBegin(CheckerContext &C, const Expr *CE, const SVal &RetVal, 104*480093f4SDimitry Andric const SVal &Cont) const; 105*480093f4SDimitry Andric void handleEnd(CheckerContext &C, const Expr *CE, const SVal &RetVal, 106*480093f4SDimitry Andric const SVal &Cont) const; 107*480093f4SDimitry Andric void assignToContainer(CheckerContext &C, const Expr *CE, const SVal &RetVal, 108*480093f4SDimitry Andric const MemRegion *Cont) const; 109*480093f4SDimitry Andric void handleAssign(CheckerContext &C, const SVal &Cont, 110*480093f4SDimitry Andric const Expr *CE = nullptr, 111*480093f4SDimitry Andric const SVal &OldCont = UndefinedVal()) const; 112*480093f4SDimitry Andric void handleClear(CheckerContext &C, const SVal &Cont) const; 113*480093f4SDimitry Andric void handlePushBack(CheckerContext &C, const SVal &Cont) const; 114*480093f4SDimitry Andric void handlePopBack(CheckerContext &C, const SVal &Cont) const; 115*480093f4SDimitry Andric void handlePushFront(CheckerContext &C, const SVal &Cont) const; 116*480093f4SDimitry Andric void handlePopFront(CheckerContext &C, const SVal &Cont) const; 117*480093f4SDimitry Andric void handleInsert(CheckerContext &C, const SVal &Iter) const; 118*480093f4SDimitry Andric void handleErase(CheckerContext &C, const SVal &Iter) const; 119*480093f4SDimitry Andric void handleErase(CheckerContext &C, const SVal &Iter1, 120*480093f4SDimitry Andric const SVal &Iter2) const; 121*480093f4SDimitry Andric void handleEraseAfter(CheckerContext &C, const SVal &Iter) const; 122*480093f4SDimitry Andric void handleEraseAfter(CheckerContext &C, const SVal &Iter1, 123*480093f4SDimitry Andric const SVal &Iter2) const; 124*480093f4SDimitry Andric void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, 125*480093f4SDimitry Andric const char *Sep) const override; 126*480093f4SDimitry Andric 127*480093f4SDimitry Andric public: 128*480093f4SDimitry Andric IteratorModeling() {} 129*480093f4SDimitry Andric 130*480093f4SDimitry Andric void checkPostCall(const CallEvent &Call, CheckerContext &C) const; 131*480093f4SDimitry Andric void checkBind(SVal Loc, SVal Val, const Stmt *S, CheckerContext &C) const; 132*480093f4SDimitry Andric void checkPostStmt(const CXXConstructExpr *CCE, CheckerContext &C) const; 133*480093f4SDimitry Andric void checkPostStmt(const DeclStmt *DS, CheckerContext &C) const; 134*480093f4SDimitry Andric void checkPostStmt(const MaterializeTemporaryExpr *MTE, 135*480093f4SDimitry Andric CheckerContext &C) const; 136*480093f4SDimitry Andric void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const; 137*480093f4SDimitry Andric void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const; 138*480093f4SDimitry Andric }; 139*480093f4SDimitry Andric 140*480093f4SDimitry Andric bool isBeginCall(const FunctionDecl *Func); 141*480093f4SDimitry Andric bool isEndCall(const FunctionDecl *Func); 142*480093f4SDimitry Andric bool isAssignCall(const FunctionDecl *Func); 143*480093f4SDimitry Andric bool isClearCall(const FunctionDecl *Func); 144*480093f4SDimitry Andric bool isPushBackCall(const FunctionDecl *Func); 145*480093f4SDimitry Andric bool isEmplaceBackCall(const FunctionDecl *Func); 146*480093f4SDimitry Andric bool isPopBackCall(const FunctionDecl *Func); 147*480093f4SDimitry Andric bool isPushFrontCall(const FunctionDecl *Func); 148*480093f4SDimitry Andric bool isEmplaceFrontCall(const FunctionDecl *Func); 149*480093f4SDimitry Andric bool isPopFrontCall(const FunctionDecl *Func); 150*480093f4SDimitry Andric bool isAssignmentOperator(OverloadedOperatorKind OK); 151*480093f4SDimitry Andric bool isSimpleComparisonOperator(OverloadedOperatorKind OK); 152*480093f4SDimitry Andric bool hasSubscriptOperator(ProgramStateRef State, const MemRegion *Reg); 153*480093f4SDimitry Andric bool frontModifiable(ProgramStateRef State, const MemRegion *Reg); 154*480093f4SDimitry Andric bool backModifiable(ProgramStateRef State, const MemRegion *Reg); 155*480093f4SDimitry Andric SymbolRef getContainerBegin(ProgramStateRef State, const MemRegion *Cont); 156*480093f4SDimitry Andric SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont); 157*480093f4SDimitry Andric ProgramStateRef createContainerBegin(ProgramStateRef State, 158*480093f4SDimitry Andric const MemRegion *Cont, const Expr *E, 159*480093f4SDimitry Andric QualType T, const LocationContext *LCtx, 160*480093f4SDimitry Andric unsigned BlockCount); 161*480093f4SDimitry Andric ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont, 162*480093f4SDimitry Andric const Expr *E, QualType T, 163*480093f4SDimitry Andric const LocationContext *LCtx, 164*480093f4SDimitry Andric unsigned BlockCount); 165*480093f4SDimitry Andric ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont, 166*480093f4SDimitry Andric const ContainerData &CData); 167*480093f4SDimitry Andric ProgramStateRef removeIteratorPosition(ProgramStateRef State, const SVal &Val); 168*480093f4SDimitry Andric ProgramStateRef assumeNoOverflow(ProgramStateRef State, SymbolRef Sym, 169*480093f4SDimitry Andric long Scale); 170*480093f4SDimitry Andric ProgramStateRef invalidateAllIteratorPositions(ProgramStateRef State, 171*480093f4SDimitry Andric const MemRegion *Cont); 172*480093f4SDimitry Andric ProgramStateRef 173*480093f4SDimitry Andric invalidateAllIteratorPositionsExcept(ProgramStateRef State, 174*480093f4SDimitry Andric const MemRegion *Cont, SymbolRef Offset, 175*480093f4SDimitry Andric BinaryOperator::Opcode Opc); 176*480093f4SDimitry Andric ProgramStateRef invalidateIteratorPositions(ProgramStateRef State, 177*480093f4SDimitry Andric SymbolRef Offset, 178*480093f4SDimitry Andric BinaryOperator::Opcode Opc); 179*480093f4SDimitry Andric ProgramStateRef invalidateIteratorPositions(ProgramStateRef State, 180*480093f4SDimitry Andric SymbolRef Offset1, 181*480093f4SDimitry Andric BinaryOperator::Opcode Opc1, 182*480093f4SDimitry Andric SymbolRef Offset2, 183*480093f4SDimitry Andric BinaryOperator::Opcode Opc2); 184*480093f4SDimitry Andric ProgramStateRef reassignAllIteratorPositions(ProgramStateRef State, 185*480093f4SDimitry Andric const MemRegion *Cont, 186*480093f4SDimitry Andric const MemRegion *NewCont); 187*480093f4SDimitry Andric ProgramStateRef reassignAllIteratorPositionsUnless(ProgramStateRef State, 188*480093f4SDimitry Andric const MemRegion *Cont, 189*480093f4SDimitry Andric const MemRegion *NewCont, 190*480093f4SDimitry Andric SymbolRef Offset, 191*480093f4SDimitry Andric BinaryOperator::Opcode Opc); 192*480093f4SDimitry Andric ProgramStateRef rebaseSymbolInIteratorPositionsIf( 193*480093f4SDimitry Andric ProgramStateRef State, SValBuilder &SVB, SymbolRef OldSym, 194*480093f4SDimitry Andric SymbolRef NewSym, SymbolRef CondSym, BinaryOperator::Opcode Opc); 195*480093f4SDimitry Andric ProgramStateRef relateSymbols(ProgramStateRef State, SymbolRef Sym1, 196*480093f4SDimitry Andric SymbolRef Sym2, bool Equal); 197*480093f4SDimitry Andric SymbolRef rebaseSymbol(ProgramStateRef State, SValBuilder &SVB, SymbolRef Expr, 198*480093f4SDimitry Andric SymbolRef OldSym, SymbolRef NewSym); 199*480093f4SDimitry Andric bool hasLiveIterators(ProgramStateRef State, const MemRegion *Cont); 200*480093f4SDimitry Andric bool isBoundThroughLazyCompoundVal(const Environment &Env, 201*480093f4SDimitry Andric const MemRegion *Reg); 202*480093f4SDimitry Andric 203*480093f4SDimitry Andric } // namespace 204*480093f4SDimitry Andric 205*480093f4SDimitry Andric void IteratorModeling::checkPostCall(const CallEvent &Call, 206*480093f4SDimitry Andric CheckerContext &C) const { 207*480093f4SDimitry Andric // Record new iterator positions and iterator position changes 208*480093f4SDimitry Andric const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); 209*480093f4SDimitry Andric if (!Func) 210*480093f4SDimitry Andric return; 211*480093f4SDimitry Andric 212*480093f4SDimitry Andric if (Func->isOverloadedOperator()) { 213*480093f4SDimitry Andric const auto Op = Func->getOverloadedOperator(); 214*480093f4SDimitry Andric if (isAssignmentOperator(Op)) { 215*480093f4SDimitry Andric // Overloaded 'operator=' must be a non-static member function. 216*480093f4SDimitry Andric const auto *InstCall = cast<CXXInstanceCall>(&Call); 217*480093f4SDimitry Andric if (cast<CXXMethodDecl>(Func)->isMoveAssignmentOperator()) { 218*480093f4SDimitry Andric handleAssign(C, InstCall->getCXXThisVal(), Call.getOriginExpr(), 219*480093f4SDimitry Andric Call.getArgSVal(0)); 220*480093f4SDimitry Andric return; 221*480093f4SDimitry Andric } 222*480093f4SDimitry Andric 223*480093f4SDimitry Andric handleAssign(C, InstCall->getCXXThisVal()); 224*480093f4SDimitry Andric return; 225*480093f4SDimitry Andric } else if (isSimpleComparisonOperator(Op)) { 226*480093f4SDimitry Andric const auto *OrigExpr = Call.getOriginExpr(); 227*480093f4SDimitry Andric if (!OrigExpr) 228*480093f4SDimitry Andric return; 229*480093f4SDimitry Andric 230*480093f4SDimitry Andric if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { 231*480093f4SDimitry Andric handleComparison(C, OrigExpr, Call.getReturnValue(), 232*480093f4SDimitry Andric InstCall->getCXXThisVal(), Call.getArgSVal(0), Op); 233*480093f4SDimitry Andric return; 234*480093f4SDimitry Andric } 235*480093f4SDimitry Andric 236*480093f4SDimitry Andric handleComparison(C, OrigExpr, Call.getReturnValue(), Call.getArgSVal(0), 237*480093f4SDimitry Andric Call.getArgSVal(1), Op); 238*480093f4SDimitry Andric return; 239*480093f4SDimitry Andric } else if (isRandomIncrOrDecrOperator(Func->getOverloadedOperator())) { 240*480093f4SDimitry Andric const auto *OrigExpr = Call.getOriginExpr(); 241*480093f4SDimitry Andric if (!OrigExpr) 242*480093f4SDimitry Andric return; 243*480093f4SDimitry Andric 244*480093f4SDimitry Andric if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { 245*480093f4SDimitry Andric if (Call.getNumArgs() >= 1 && 246*480093f4SDimitry Andric Call.getArgExpr(0)->getType()->isIntegralOrEnumerationType()) { 247*480093f4SDimitry Andric handleRandomIncrOrDecr(C, OrigExpr, Func->getOverloadedOperator(), 248*480093f4SDimitry Andric Call.getReturnValue(), 249*480093f4SDimitry Andric InstCall->getCXXThisVal(), Call.getArgSVal(0)); 250*480093f4SDimitry Andric return; 251*480093f4SDimitry Andric } 252*480093f4SDimitry Andric } else { 253*480093f4SDimitry Andric if (Call.getNumArgs() >= 2 && 254*480093f4SDimitry Andric Call.getArgExpr(1)->getType()->isIntegralOrEnumerationType()) { 255*480093f4SDimitry Andric handleRandomIncrOrDecr(C, OrigExpr, Func->getOverloadedOperator(), 256*480093f4SDimitry Andric Call.getReturnValue(), Call.getArgSVal(0), 257*480093f4SDimitry Andric Call.getArgSVal(1)); 258*480093f4SDimitry Andric return; 259*480093f4SDimitry Andric } 260*480093f4SDimitry Andric } 261*480093f4SDimitry Andric } else if (isIncrementOperator(Func->getOverloadedOperator())) { 262*480093f4SDimitry Andric if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { 263*480093f4SDimitry Andric handleIncrement(C, Call.getReturnValue(), InstCall->getCXXThisVal(), 264*480093f4SDimitry Andric Call.getNumArgs()); 265*480093f4SDimitry Andric return; 266*480093f4SDimitry Andric } 267*480093f4SDimitry Andric 268*480093f4SDimitry Andric handleIncrement(C, Call.getReturnValue(), Call.getArgSVal(0), 269*480093f4SDimitry Andric Call.getNumArgs()); 270*480093f4SDimitry Andric return; 271*480093f4SDimitry Andric } else if (isDecrementOperator(Func->getOverloadedOperator())) { 272*480093f4SDimitry Andric if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { 273*480093f4SDimitry Andric handleDecrement(C, Call.getReturnValue(), InstCall->getCXXThisVal(), 274*480093f4SDimitry Andric Call.getNumArgs()); 275*480093f4SDimitry Andric return; 276*480093f4SDimitry Andric } 277*480093f4SDimitry Andric 278*480093f4SDimitry Andric handleDecrement(C, Call.getReturnValue(), Call.getArgSVal(0), 279*480093f4SDimitry Andric Call.getNumArgs()); 280*480093f4SDimitry Andric return; 281*480093f4SDimitry Andric } 282*480093f4SDimitry Andric } else { 283*480093f4SDimitry Andric if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { 284*480093f4SDimitry Andric if (isAssignCall(Func)) { 285*480093f4SDimitry Andric handleAssign(C, InstCall->getCXXThisVal()); 286*480093f4SDimitry Andric return; 287*480093f4SDimitry Andric } 288*480093f4SDimitry Andric 289*480093f4SDimitry Andric if (isClearCall(Func)) { 290*480093f4SDimitry Andric handleClear(C, InstCall->getCXXThisVal()); 291*480093f4SDimitry Andric return; 292*480093f4SDimitry Andric } 293*480093f4SDimitry Andric 294*480093f4SDimitry Andric if (isPushBackCall(Func) || isEmplaceBackCall(Func)) { 295*480093f4SDimitry Andric handlePushBack(C, InstCall->getCXXThisVal()); 296*480093f4SDimitry Andric return; 297*480093f4SDimitry Andric } 298*480093f4SDimitry Andric 299*480093f4SDimitry Andric if (isPopBackCall(Func)) { 300*480093f4SDimitry Andric handlePopBack(C, InstCall->getCXXThisVal()); 301*480093f4SDimitry Andric return; 302*480093f4SDimitry Andric } 303*480093f4SDimitry Andric 304*480093f4SDimitry Andric if (isPushFrontCall(Func) || isEmplaceFrontCall(Func)) { 305*480093f4SDimitry Andric handlePushFront(C, InstCall->getCXXThisVal()); 306*480093f4SDimitry Andric return; 307*480093f4SDimitry Andric } 308*480093f4SDimitry Andric 309*480093f4SDimitry Andric if (isPopFrontCall(Func)) { 310*480093f4SDimitry Andric handlePopFront(C, InstCall->getCXXThisVal()); 311*480093f4SDimitry Andric return; 312*480093f4SDimitry Andric } 313*480093f4SDimitry Andric 314*480093f4SDimitry Andric if (isInsertCall(Func) || isEmplaceCall(Func)) { 315*480093f4SDimitry Andric handleInsert(C, Call.getArgSVal(0)); 316*480093f4SDimitry Andric return; 317*480093f4SDimitry Andric } 318*480093f4SDimitry Andric 319*480093f4SDimitry Andric if (isEraseCall(Func)) { 320*480093f4SDimitry Andric if (Call.getNumArgs() == 1) { 321*480093f4SDimitry Andric handleErase(C, Call.getArgSVal(0)); 322*480093f4SDimitry Andric return; 323*480093f4SDimitry Andric } 324*480093f4SDimitry Andric 325*480093f4SDimitry Andric if (Call.getNumArgs() == 2) { 326*480093f4SDimitry Andric handleErase(C, Call.getArgSVal(0), Call.getArgSVal(1)); 327*480093f4SDimitry Andric return; 328*480093f4SDimitry Andric } 329*480093f4SDimitry Andric } 330*480093f4SDimitry Andric 331*480093f4SDimitry Andric if (isEraseAfterCall(Func)) { 332*480093f4SDimitry Andric if (Call.getNumArgs() == 1) { 333*480093f4SDimitry Andric handleEraseAfter(C, Call.getArgSVal(0)); 334*480093f4SDimitry Andric return; 335*480093f4SDimitry Andric } 336*480093f4SDimitry Andric 337*480093f4SDimitry Andric if (Call.getNumArgs() == 2) { 338*480093f4SDimitry Andric handleEraseAfter(C, Call.getArgSVal(0), Call.getArgSVal(1)); 339*480093f4SDimitry Andric return; 340*480093f4SDimitry Andric } 341*480093f4SDimitry Andric } 342*480093f4SDimitry Andric } 343*480093f4SDimitry Andric 344*480093f4SDimitry Andric const auto *OrigExpr = Call.getOriginExpr(); 345*480093f4SDimitry Andric if (!OrigExpr) 346*480093f4SDimitry Andric return; 347*480093f4SDimitry Andric 348*480093f4SDimitry Andric if (!isIteratorType(Call.getResultType())) 349*480093f4SDimitry Andric return; 350*480093f4SDimitry Andric 351*480093f4SDimitry Andric auto State = C.getState(); 352*480093f4SDimitry Andric 353*480093f4SDimitry Andric if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { 354*480093f4SDimitry Andric if (isBeginCall(Func)) { 355*480093f4SDimitry Andric handleBegin(C, OrigExpr, Call.getReturnValue(), 356*480093f4SDimitry Andric InstCall->getCXXThisVal()); 357*480093f4SDimitry Andric return; 358*480093f4SDimitry Andric } 359*480093f4SDimitry Andric 360*480093f4SDimitry Andric if (isEndCall(Func)) { 361*480093f4SDimitry Andric handleEnd(C, OrigExpr, Call.getReturnValue(), 362*480093f4SDimitry Andric InstCall->getCXXThisVal()); 363*480093f4SDimitry Andric return; 364*480093f4SDimitry Andric } 365*480093f4SDimitry Andric } 366*480093f4SDimitry Andric 367*480093f4SDimitry Andric // Already bound to container? 368*480093f4SDimitry Andric if (getIteratorPosition(State, Call.getReturnValue())) 369*480093f4SDimitry Andric return; 370*480093f4SDimitry Andric 371*480093f4SDimitry Andric // Copy-like and move constructors 372*480093f4SDimitry Andric if (isa<CXXConstructorCall>(&Call) && Call.getNumArgs() == 1) { 373*480093f4SDimitry Andric if (const auto *Pos = getIteratorPosition(State, Call.getArgSVal(0))) { 374*480093f4SDimitry Andric State = setIteratorPosition(State, Call.getReturnValue(), *Pos); 375*480093f4SDimitry Andric if (cast<CXXConstructorDecl>(Func)->isMoveConstructor()) { 376*480093f4SDimitry Andric State = removeIteratorPosition(State, Call.getArgSVal(0)); 377*480093f4SDimitry Andric } 378*480093f4SDimitry Andric C.addTransition(State); 379*480093f4SDimitry Andric return; 380*480093f4SDimitry Andric } 381*480093f4SDimitry Andric } 382*480093f4SDimitry Andric 383*480093f4SDimitry Andric // Assumption: if return value is an iterator which is not yet bound to a 384*480093f4SDimitry Andric // container, then look for the first iterator argument, and 385*480093f4SDimitry Andric // bind the return value to the same container. This approach 386*480093f4SDimitry Andric // works for STL algorithms. 387*480093f4SDimitry Andric // FIXME: Add a more conservative mode 388*480093f4SDimitry Andric for (unsigned i = 0; i < Call.getNumArgs(); ++i) { 389*480093f4SDimitry Andric if (isIteratorType(Call.getArgExpr(i)->getType())) { 390*480093f4SDimitry Andric if (const auto *Pos = getIteratorPosition(State, Call.getArgSVal(i))) { 391*480093f4SDimitry Andric assignToContainer(C, OrigExpr, Call.getReturnValue(), 392*480093f4SDimitry Andric Pos->getContainer()); 393*480093f4SDimitry Andric return; 394*480093f4SDimitry Andric } 395*480093f4SDimitry Andric } 396*480093f4SDimitry Andric } 397*480093f4SDimitry Andric } 398*480093f4SDimitry Andric } 399*480093f4SDimitry Andric 400*480093f4SDimitry Andric void IteratorModeling::checkBind(SVal Loc, SVal Val, const Stmt *S, 401*480093f4SDimitry Andric CheckerContext &C) const { 402*480093f4SDimitry Andric auto State = C.getState(); 403*480093f4SDimitry Andric const auto *Pos = getIteratorPosition(State, Val); 404*480093f4SDimitry Andric if (Pos) { 405*480093f4SDimitry Andric State = setIteratorPosition(State, Loc, *Pos); 406*480093f4SDimitry Andric C.addTransition(State); 407*480093f4SDimitry Andric } else { 408*480093f4SDimitry Andric const auto *OldPos = getIteratorPosition(State, Loc); 409*480093f4SDimitry Andric if (OldPos) { 410*480093f4SDimitry Andric State = removeIteratorPosition(State, Loc); 411*480093f4SDimitry Andric C.addTransition(State); 412*480093f4SDimitry Andric } 413*480093f4SDimitry Andric } 414*480093f4SDimitry Andric } 415*480093f4SDimitry Andric 416*480093f4SDimitry Andric void IteratorModeling::checkPostStmt(const MaterializeTemporaryExpr *MTE, 417*480093f4SDimitry Andric CheckerContext &C) const { 418*480093f4SDimitry Andric /* Transfer iterator state to temporary objects */ 419*480093f4SDimitry Andric auto State = C.getState(); 420*480093f4SDimitry Andric const auto *Pos = getIteratorPosition(State, C.getSVal(MTE->getSubExpr())); 421*480093f4SDimitry Andric if (!Pos) 422*480093f4SDimitry Andric return; 423*480093f4SDimitry Andric State = setIteratorPosition(State, C.getSVal(MTE), *Pos); 424*480093f4SDimitry Andric C.addTransition(State); 425*480093f4SDimitry Andric } 426*480093f4SDimitry Andric 427*480093f4SDimitry Andric void IteratorModeling::checkLiveSymbols(ProgramStateRef State, 428*480093f4SDimitry Andric SymbolReaper &SR) const { 429*480093f4SDimitry Andric // Keep symbolic expressions of iterator positions, container begins and ends 430*480093f4SDimitry Andric // alive 431*480093f4SDimitry Andric auto RegionMap = State->get<IteratorRegionMap>(); 432*480093f4SDimitry Andric for (const auto &Reg : RegionMap) { 433*480093f4SDimitry Andric const auto Offset = Reg.second.getOffset(); 434*480093f4SDimitry Andric for (auto i = Offset->symbol_begin(); i != Offset->symbol_end(); ++i) 435*480093f4SDimitry Andric if (isa<SymbolData>(*i)) 436*480093f4SDimitry Andric SR.markLive(*i); 437*480093f4SDimitry Andric } 438*480093f4SDimitry Andric 439*480093f4SDimitry Andric auto SymbolMap = State->get<IteratorSymbolMap>(); 440*480093f4SDimitry Andric for (const auto &Sym : SymbolMap) { 441*480093f4SDimitry Andric const auto Offset = Sym.second.getOffset(); 442*480093f4SDimitry Andric for (auto i = Offset->symbol_begin(); i != Offset->symbol_end(); ++i) 443*480093f4SDimitry Andric if (isa<SymbolData>(*i)) 444*480093f4SDimitry Andric SR.markLive(*i); 445*480093f4SDimitry Andric } 446*480093f4SDimitry Andric 447*480093f4SDimitry Andric auto ContMap = State->get<ContainerMap>(); 448*480093f4SDimitry Andric for (const auto &Cont : ContMap) { 449*480093f4SDimitry Andric const auto CData = Cont.second; 450*480093f4SDimitry Andric if (CData.getBegin()) { 451*480093f4SDimitry Andric SR.markLive(CData.getBegin()); 452*480093f4SDimitry Andric if(const auto *SIE = dyn_cast<SymIntExpr>(CData.getBegin())) 453*480093f4SDimitry Andric SR.markLive(SIE->getLHS()); 454*480093f4SDimitry Andric } 455*480093f4SDimitry Andric if (CData.getEnd()) { 456*480093f4SDimitry Andric SR.markLive(CData.getEnd()); 457*480093f4SDimitry Andric if(const auto *SIE = dyn_cast<SymIntExpr>(CData.getEnd())) 458*480093f4SDimitry Andric SR.markLive(SIE->getLHS()); 459*480093f4SDimitry Andric } 460*480093f4SDimitry Andric } 461*480093f4SDimitry Andric } 462*480093f4SDimitry Andric 463*480093f4SDimitry Andric void IteratorModeling::checkDeadSymbols(SymbolReaper &SR, 464*480093f4SDimitry Andric CheckerContext &C) const { 465*480093f4SDimitry Andric // Cleanup 466*480093f4SDimitry Andric auto State = C.getState(); 467*480093f4SDimitry Andric 468*480093f4SDimitry Andric auto RegionMap = State->get<IteratorRegionMap>(); 469*480093f4SDimitry Andric for (const auto &Reg : RegionMap) { 470*480093f4SDimitry Andric if (!SR.isLiveRegion(Reg.first)) { 471*480093f4SDimitry Andric // The region behind the `LazyCompoundVal` is often cleaned up before 472*480093f4SDimitry Andric // the `LazyCompoundVal` itself. If there are iterator positions keyed 473*480093f4SDimitry Andric // by these regions their cleanup must be deferred. 474*480093f4SDimitry Andric if (!isBoundThroughLazyCompoundVal(State->getEnvironment(), Reg.first)) { 475*480093f4SDimitry Andric State = State->remove<IteratorRegionMap>(Reg.first); 476*480093f4SDimitry Andric } 477*480093f4SDimitry Andric } 478*480093f4SDimitry Andric } 479*480093f4SDimitry Andric 480*480093f4SDimitry Andric auto SymbolMap = State->get<IteratorSymbolMap>(); 481*480093f4SDimitry Andric for (const auto &Sym : SymbolMap) { 482*480093f4SDimitry Andric if (!SR.isLive(Sym.first)) { 483*480093f4SDimitry Andric State = State->remove<IteratorSymbolMap>(Sym.first); 484*480093f4SDimitry Andric } 485*480093f4SDimitry Andric } 486*480093f4SDimitry Andric 487*480093f4SDimitry Andric auto ContMap = State->get<ContainerMap>(); 488*480093f4SDimitry Andric for (const auto &Cont : ContMap) { 489*480093f4SDimitry Andric if (!SR.isLiveRegion(Cont.first)) { 490*480093f4SDimitry Andric // We must keep the container data while it has live iterators to be able 491*480093f4SDimitry Andric // to compare them to the begin and the end of the container. 492*480093f4SDimitry Andric if (!hasLiveIterators(State, Cont.first)) { 493*480093f4SDimitry Andric State = State->remove<ContainerMap>(Cont.first); 494*480093f4SDimitry Andric } 495*480093f4SDimitry Andric } 496*480093f4SDimitry Andric } 497*480093f4SDimitry Andric 498*480093f4SDimitry Andric C.addTransition(State); 499*480093f4SDimitry Andric } 500*480093f4SDimitry Andric 501*480093f4SDimitry Andric void IteratorModeling::handleComparison(CheckerContext &C, const Expr *CE, 502*480093f4SDimitry Andric SVal RetVal, const SVal &LVal, 503*480093f4SDimitry Andric const SVal &RVal, 504*480093f4SDimitry Andric OverloadedOperatorKind Op) const { 505*480093f4SDimitry Andric // Record the operands and the operator of the comparison for the next 506*480093f4SDimitry Andric // evalAssume, if the result is a symbolic expression. If it is a concrete 507*480093f4SDimitry Andric // value (only one branch is possible), then transfer the state between 508*480093f4SDimitry Andric // the operands according to the operator and the result 509*480093f4SDimitry Andric auto State = C.getState(); 510*480093f4SDimitry Andric const auto *LPos = getIteratorPosition(State, LVal); 511*480093f4SDimitry Andric const auto *RPos = getIteratorPosition(State, RVal); 512*480093f4SDimitry Andric const MemRegion *Cont = nullptr; 513*480093f4SDimitry Andric if (LPos) { 514*480093f4SDimitry Andric Cont = LPos->getContainer(); 515*480093f4SDimitry Andric } else if (RPos) { 516*480093f4SDimitry Andric Cont = RPos->getContainer(); 517*480093f4SDimitry Andric } 518*480093f4SDimitry Andric if (!Cont) 519*480093f4SDimitry Andric return; 520*480093f4SDimitry Andric 521*480093f4SDimitry Andric // At least one of the iterators have recorded positions. If one of them has 522*480093f4SDimitry Andric // not then create a new symbol for the offset. 523*480093f4SDimitry Andric SymbolRef Sym; 524*480093f4SDimitry Andric if (!LPos || !RPos) { 525*480093f4SDimitry Andric auto &SymMgr = C.getSymbolManager(); 526*480093f4SDimitry Andric Sym = SymMgr.conjureSymbol(CE, C.getLocationContext(), 527*480093f4SDimitry Andric C.getASTContext().LongTy, C.blockCount()); 528*480093f4SDimitry Andric State = assumeNoOverflow(State, Sym, 4); 529*480093f4SDimitry Andric } 530*480093f4SDimitry Andric 531*480093f4SDimitry Andric if (!LPos) { 532*480093f4SDimitry Andric State = setIteratorPosition(State, LVal, 533*480093f4SDimitry Andric IteratorPosition::getPosition(Cont, Sym)); 534*480093f4SDimitry Andric LPos = getIteratorPosition(State, LVal); 535*480093f4SDimitry Andric } else if (!RPos) { 536*480093f4SDimitry Andric State = setIteratorPosition(State, RVal, 537*480093f4SDimitry Andric IteratorPosition::getPosition(Cont, Sym)); 538*480093f4SDimitry Andric RPos = getIteratorPosition(State, RVal); 539*480093f4SDimitry Andric } 540*480093f4SDimitry Andric 541*480093f4SDimitry Andric // We cannot make assumpotions on `UnknownVal`. Let us conjure a symbol 542*480093f4SDimitry Andric // instead. 543*480093f4SDimitry Andric if (RetVal.isUnknown()) { 544*480093f4SDimitry Andric auto &SymMgr = C.getSymbolManager(); 545*480093f4SDimitry Andric auto *LCtx = C.getLocationContext(); 546*480093f4SDimitry Andric RetVal = nonloc::SymbolVal(SymMgr.conjureSymbol( 547*480093f4SDimitry Andric CE, LCtx, C.getASTContext().BoolTy, C.blockCount())); 548*480093f4SDimitry Andric State = State->BindExpr(CE, LCtx, RetVal); 549*480093f4SDimitry Andric } 550*480093f4SDimitry Andric 551*480093f4SDimitry Andric processComparison(C, State, LPos->getOffset(), RPos->getOffset(), RetVal, Op); 552*480093f4SDimitry Andric } 553*480093f4SDimitry Andric 554*480093f4SDimitry Andric void IteratorModeling::processComparison(CheckerContext &C, 555*480093f4SDimitry Andric ProgramStateRef State, SymbolRef Sym1, 556*480093f4SDimitry Andric SymbolRef Sym2, const SVal &RetVal, 557*480093f4SDimitry Andric OverloadedOperatorKind Op) const { 558*480093f4SDimitry Andric if (const auto TruthVal = RetVal.getAs<nonloc::ConcreteInt>()) { 559*480093f4SDimitry Andric if ((State = relateSymbols(State, Sym1, Sym2, 560*480093f4SDimitry Andric (Op == OO_EqualEqual) == 561*480093f4SDimitry Andric (TruthVal->getValue() != 0)))) { 562*480093f4SDimitry Andric C.addTransition(State); 563*480093f4SDimitry Andric } else { 564*480093f4SDimitry Andric C.generateSink(State, C.getPredecessor()); 565*480093f4SDimitry Andric } 566*480093f4SDimitry Andric return; 567*480093f4SDimitry Andric } 568*480093f4SDimitry Andric 569*480093f4SDimitry Andric const auto ConditionVal = RetVal.getAs<DefinedSVal>(); 570*480093f4SDimitry Andric if (!ConditionVal) 571*480093f4SDimitry Andric return; 572*480093f4SDimitry Andric 573*480093f4SDimitry Andric if (auto StateTrue = relateSymbols(State, Sym1, Sym2, Op == OO_EqualEqual)) { 574*480093f4SDimitry Andric StateTrue = StateTrue->assume(*ConditionVal, true); 575*480093f4SDimitry Andric C.addTransition(StateTrue); 576*480093f4SDimitry Andric } 577*480093f4SDimitry Andric 578*480093f4SDimitry Andric if (auto StateFalse = relateSymbols(State, Sym1, Sym2, Op != OO_EqualEqual)) { 579*480093f4SDimitry Andric StateFalse = StateFalse->assume(*ConditionVal, false); 580*480093f4SDimitry Andric C.addTransition(StateFalse); 581*480093f4SDimitry Andric } 582*480093f4SDimitry Andric } 583*480093f4SDimitry Andric 584*480093f4SDimitry Andric void IteratorModeling::handleIncrement(CheckerContext &C, const SVal &RetVal, 585*480093f4SDimitry Andric const SVal &Iter, bool Postfix) const { 586*480093f4SDimitry Andric // Increment the symbolic expressions which represents the position of the 587*480093f4SDimitry Andric // iterator 588*480093f4SDimitry Andric auto State = C.getState(); 589*480093f4SDimitry Andric auto &BVF = C.getSymbolManager().getBasicVals(); 590*480093f4SDimitry Andric 591*480093f4SDimitry Andric const auto *Pos = getIteratorPosition(State, Iter); 592*480093f4SDimitry Andric if (!Pos) 593*480093f4SDimitry Andric return; 594*480093f4SDimitry Andric 595*480093f4SDimitry Andric auto NewState = 596*480093f4SDimitry Andric advancePosition(State, Iter, OO_Plus, 597*480093f4SDimitry Andric nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1)))); 598*480093f4SDimitry Andric assert(NewState && 599*480093f4SDimitry Andric "Advancing position by concrete int should always be successful"); 600*480093f4SDimitry Andric 601*480093f4SDimitry Andric const auto *NewPos = getIteratorPosition(NewState, Iter); 602*480093f4SDimitry Andric assert(NewPos && 603*480093f4SDimitry Andric "Iterator should have position after successful advancement"); 604*480093f4SDimitry Andric 605*480093f4SDimitry Andric State = setIteratorPosition(State, Iter, *NewPos); 606*480093f4SDimitry Andric State = setIteratorPosition(State, RetVal, Postfix ? *Pos : *NewPos); 607*480093f4SDimitry Andric C.addTransition(State); 608*480093f4SDimitry Andric } 609*480093f4SDimitry Andric 610*480093f4SDimitry Andric void IteratorModeling::handleDecrement(CheckerContext &C, const SVal &RetVal, 611*480093f4SDimitry Andric const SVal &Iter, bool Postfix) const { 612*480093f4SDimitry Andric // Decrement the symbolic expressions which represents the position of the 613*480093f4SDimitry Andric // iterator 614*480093f4SDimitry Andric auto State = C.getState(); 615*480093f4SDimitry Andric auto &BVF = C.getSymbolManager().getBasicVals(); 616*480093f4SDimitry Andric 617*480093f4SDimitry Andric const auto *Pos = getIteratorPosition(State, Iter); 618*480093f4SDimitry Andric if (!Pos) 619*480093f4SDimitry Andric return; 620*480093f4SDimitry Andric 621*480093f4SDimitry Andric auto NewState = 622*480093f4SDimitry Andric advancePosition(State, Iter, OO_Minus, 623*480093f4SDimitry Andric nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1)))); 624*480093f4SDimitry Andric assert(NewState && 625*480093f4SDimitry Andric "Advancing position by concrete int should always be successful"); 626*480093f4SDimitry Andric 627*480093f4SDimitry Andric const auto *NewPos = getIteratorPosition(NewState, Iter); 628*480093f4SDimitry Andric assert(NewPos && 629*480093f4SDimitry Andric "Iterator should have position after successful advancement"); 630*480093f4SDimitry Andric 631*480093f4SDimitry Andric State = setIteratorPosition(State, Iter, *NewPos); 632*480093f4SDimitry Andric State = setIteratorPosition(State, RetVal, Postfix ? *Pos : *NewPos); 633*480093f4SDimitry Andric C.addTransition(State); 634*480093f4SDimitry Andric } 635*480093f4SDimitry Andric 636*480093f4SDimitry Andric void IteratorModeling::handleRandomIncrOrDecr(CheckerContext &C, 637*480093f4SDimitry Andric const Expr *CE, 638*480093f4SDimitry Andric OverloadedOperatorKind Op, 639*480093f4SDimitry Andric const SVal &RetVal, 640*480093f4SDimitry Andric const SVal &LHS, 641*480093f4SDimitry Andric const SVal &RHS) const { 642*480093f4SDimitry Andric // Increment or decrement the symbolic expressions which represents the 643*480093f4SDimitry Andric // position of the iterator 644*480093f4SDimitry Andric auto State = C.getState(); 645*480093f4SDimitry Andric 646*480093f4SDimitry Andric const auto *Pos = getIteratorPosition(State, LHS); 647*480093f4SDimitry Andric if (!Pos) 648*480093f4SDimitry Andric return; 649*480093f4SDimitry Andric 650*480093f4SDimitry Andric const auto *value = &RHS; 651*480093f4SDimitry Andric if (auto loc = RHS.getAs<Loc>()) { 652*480093f4SDimitry Andric const auto val = State->getRawSVal(*loc); 653*480093f4SDimitry Andric value = &val; 654*480093f4SDimitry Andric } 655*480093f4SDimitry Andric 656*480093f4SDimitry Andric auto &TgtVal = (Op == OO_PlusEqual || Op == OO_MinusEqual) ? LHS : RetVal; 657*480093f4SDimitry Andric 658*480093f4SDimitry Andric auto NewState = 659*480093f4SDimitry Andric advancePosition(State, LHS, Op, *value); 660*480093f4SDimitry Andric if (NewState) { 661*480093f4SDimitry Andric const auto *NewPos = getIteratorPosition(NewState, LHS); 662*480093f4SDimitry Andric assert(NewPos && 663*480093f4SDimitry Andric "Iterator should have position after successful advancement"); 664*480093f4SDimitry Andric 665*480093f4SDimitry Andric State = setIteratorPosition(NewState, TgtVal, *NewPos); 666*480093f4SDimitry Andric C.addTransition(State); 667*480093f4SDimitry Andric } else { 668*480093f4SDimitry Andric assignToContainer(C, CE, TgtVal, Pos->getContainer()); 669*480093f4SDimitry Andric } 670*480093f4SDimitry Andric } 671*480093f4SDimitry Andric 672*480093f4SDimitry Andric void IteratorModeling::handleBegin(CheckerContext &C, const Expr *CE, 673*480093f4SDimitry Andric const SVal &RetVal, const SVal &Cont) const { 674*480093f4SDimitry Andric const auto *ContReg = Cont.getAsRegion(); 675*480093f4SDimitry Andric if (!ContReg) 676*480093f4SDimitry Andric return; 677*480093f4SDimitry Andric 678*480093f4SDimitry Andric ContReg = ContReg->getMostDerivedObjectRegion(); 679*480093f4SDimitry Andric 680*480093f4SDimitry Andric // If the container already has a begin symbol then use it. Otherwise first 681*480093f4SDimitry Andric // create a new one. 682*480093f4SDimitry Andric auto State = C.getState(); 683*480093f4SDimitry Andric auto BeginSym = getContainerBegin(State, ContReg); 684*480093f4SDimitry Andric if (!BeginSym) { 685*480093f4SDimitry Andric State = createContainerBegin(State, ContReg, CE, C.getASTContext().LongTy, 686*480093f4SDimitry Andric C.getLocationContext(), C.blockCount()); 687*480093f4SDimitry Andric BeginSym = getContainerBegin(State, ContReg); 688*480093f4SDimitry Andric } 689*480093f4SDimitry Andric State = setIteratorPosition(State, RetVal, 690*480093f4SDimitry Andric IteratorPosition::getPosition(ContReg, BeginSym)); 691*480093f4SDimitry Andric C.addTransition(State); 692*480093f4SDimitry Andric } 693*480093f4SDimitry Andric 694*480093f4SDimitry Andric void IteratorModeling::handleEnd(CheckerContext &C, const Expr *CE, 695*480093f4SDimitry Andric const SVal &RetVal, const SVal &Cont) const { 696*480093f4SDimitry Andric const auto *ContReg = Cont.getAsRegion(); 697*480093f4SDimitry Andric if (!ContReg) 698*480093f4SDimitry Andric return; 699*480093f4SDimitry Andric 700*480093f4SDimitry Andric ContReg = ContReg->getMostDerivedObjectRegion(); 701*480093f4SDimitry Andric 702*480093f4SDimitry Andric // If the container already has an end symbol then use it. Otherwise first 703*480093f4SDimitry Andric // create a new one. 704*480093f4SDimitry Andric auto State = C.getState(); 705*480093f4SDimitry Andric auto EndSym = getContainerEnd(State, ContReg); 706*480093f4SDimitry Andric if (!EndSym) { 707*480093f4SDimitry Andric State = createContainerEnd(State, ContReg, CE, C.getASTContext().LongTy, 708*480093f4SDimitry Andric C.getLocationContext(), C.blockCount()); 709*480093f4SDimitry Andric EndSym = getContainerEnd(State, ContReg); 710*480093f4SDimitry Andric } 711*480093f4SDimitry Andric State = setIteratorPosition(State, RetVal, 712*480093f4SDimitry Andric IteratorPosition::getPosition(ContReg, EndSym)); 713*480093f4SDimitry Andric C.addTransition(State); 714*480093f4SDimitry Andric } 715*480093f4SDimitry Andric 716*480093f4SDimitry Andric void IteratorModeling::assignToContainer(CheckerContext &C, const Expr *CE, 717*480093f4SDimitry Andric const SVal &RetVal, 718*480093f4SDimitry Andric const MemRegion *Cont) const { 719*480093f4SDimitry Andric Cont = Cont->getMostDerivedObjectRegion(); 720*480093f4SDimitry Andric 721*480093f4SDimitry Andric auto State = C.getState(); 722*480093f4SDimitry Andric auto &SymMgr = C.getSymbolManager(); 723*480093f4SDimitry Andric auto Sym = SymMgr.conjureSymbol(CE, C.getLocationContext(), 724*480093f4SDimitry Andric C.getASTContext().LongTy, C.blockCount()); 725*480093f4SDimitry Andric State = assumeNoOverflow(State, Sym, 4); 726*480093f4SDimitry Andric State = setIteratorPosition(State, RetVal, 727*480093f4SDimitry Andric IteratorPosition::getPosition(Cont, Sym)); 728*480093f4SDimitry Andric C.addTransition(State); 729*480093f4SDimitry Andric } 730*480093f4SDimitry Andric 731*480093f4SDimitry Andric void IteratorModeling::handleAssign(CheckerContext &C, const SVal &Cont, 732*480093f4SDimitry Andric const Expr *CE, const SVal &OldCont) const { 733*480093f4SDimitry Andric const auto *ContReg = Cont.getAsRegion(); 734*480093f4SDimitry Andric if (!ContReg) 735*480093f4SDimitry Andric return; 736*480093f4SDimitry Andric 737*480093f4SDimitry Andric ContReg = ContReg->getMostDerivedObjectRegion(); 738*480093f4SDimitry Andric 739*480093f4SDimitry Andric // Assignment of a new value to a container always invalidates all its 740*480093f4SDimitry Andric // iterators 741*480093f4SDimitry Andric auto State = C.getState(); 742*480093f4SDimitry Andric const auto CData = getContainerData(State, ContReg); 743*480093f4SDimitry Andric if (CData) { 744*480093f4SDimitry Andric State = invalidateAllIteratorPositions(State, ContReg); 745*480093f4SDimitry Andric } 746*480093f4SDimitry Andric 747*480093f4SDimitry Andric // In case of move, iterators of the old container (except the past-end 748*480093f4SDimitry Andric // iterators) remain valid but refer to the new container 749*480093f4SDimitry Andric if (!OldCont.isUndef()) { 750*480093f4SDimitry Andric const auto *OldContReg = OldCont.getAsRegion(); 751*480093f4SDimitry Andric if (OldContReg) { 752*480093f4SDimitry Andric OldContReg = OldContReg->getMostDerivedObjectRegion(); 753*480093f4SDimitry Andric const auto OldCData = getContainerData(State, OldContReg); 754*480093f4SDimitry Andric if (OldCData) { 755*480093f4SDimitry Andric if (const auto OldEndSym = OldCData->getEnd()) { 756*480093f4SDimitry Andric // If we already assigned an "end" symbol to the old container, then 757*480093f4SDimitry Andric // first reassign all iterator positions to the new container which 758*480093f4SDimitry Andric // are not past the container (thus not greater or equal to the 759*480093f4SDimitry Andric // current "end" symbol). 760*480093f4SDimitry Andric State = reassignAllIteratorPositionsUnless(State, OldContReg, ContReg, 761*480093f4SDimitry Andric OldEndSym, BO_GE); 762*480093f4SDimitry Andric auto &SymMgr = C.getSymbolManager(); 763*480093f4SDimitry Andric auto &SVB = C.getSValBuilder(); 764*480093f4SDimitry Andric // Then generate and assign a new "end" symbol for the new container. 765*480093f4SDimitry Andric auto NewEndSym = 766*480093f4SDimitry Andric SymMgr.conjureSymbol(CE, C.getLocationContext(), 767*480093f4SDimitry Andric C.getASTContext().LongTy, C.blockCount()); 768*480093f4SDimitry Andric State = assumeNoOverflow(State, NewEndSym, 4); 769*480093f4SDimitry Andric if (CData) { 770*480093f4SDimitry Andric State = setContainerData(State, ContReg, CData->newEnd(NewEndSym)); 771*480093f4SDimitry Andric } else { 772*480093f4SDimitry Andric State = setContainerData(State, ContReg, 773*480093f4SDimitry Andric ContainerData::fromEnd(NewEndSym)); 774*480093f4SDimitry Andric } 775*480093f4SDimitry Andric // Finally, replace the old "end" symbol in the already reassigned 776*480093f4SDimitry Andric // iterator positions with the new "end" symbol. 777*480093f4SDimitry Andric State = rebaseSymbolInIteratorPositionsIf( 778*480093f4SDimitry Andric State, SVB, OldEndSym, NewEndSym, OldEndSym, BO_LT); 779*480093f4SDimitry Andric } else { 780*480093f4SDimitry Andric // There was no "end" symbol assigned yet to the old container, 781*480093f4SDimitry Andric // so reassign all iterator positions to the new container. 782*480093f4SDimitry Andric State = reassignAllIteratorPositions(State, OldContReg, ContReg); 783*480093f4SDimitry Andric } 784*480093f4SDimitry Andric if (const auto OldBeginSym = OldCData->getBegin()) { 785*480093f4SDimitry Andric // If we already assigned a "begin" symbol to the old container, then 786*480093f4SDimitry Andric // assign it to the new container and remove it from the old one. 787*480093f4SDimitry Andric if (CData) { 788*480093f4SDimitry Andric State = 789*480093f4SDimitry Andric setContainerData(State, ContReg, CData->newBegin(OldBeginSym)); 790*480093f4SDimitry Andric } else { 791*480093f4SDimitry Andric State = setContainerData(State, ContReg, 792*480093f4SDimitry Andric ContainerData::fromBegin(OldBeginSym)); 793*480093f4SDimitry Andric } 794*480093f4SDimitry Andric State = 795*480093f4SDimitry Andric setContainerData(State, OldContReg, OldCData->newEnd(nullptr)); 796*480093f4SDimitry Andric } 797*480093f4SDimitry Andric } else { 798*480093f4SDimitry Andric // There was neither "begin" nor "end" symbol assigned yet to the old 799*480093f4SDimitry Andric // container, so reassign all iterator positions to the new container. 800*480093f4SDimitry Andric State = reassignAllIteratorPositions(State, OldContReg, ContReg); 801*480093f4SDimitry Andric } 802*480093f4SDimitry Andric } 803*480093f4SDimitry Andric } 804*480093f4SDimitry Andric C.addTransition(State); 805*480093f4SDimitry Andric } 806*480093f4SDimitry Andric 807*480093f4SDimitry Andric void IteratorModeling::handleClear(CheckerContext &C, const SVal &Cont) const { 808*480093f4SDimitry Andric const auto *ContReg = Cont.getAsRegion(); 809*480093f4SDimitry Andric if (!ContReg) 810*480093f4SDimitry Andric return; 811*480093f4SDimitry Andric 812*480093f4SDimitry Andric ContReg = ContReg->getMostDerivedObjectRegion(); 813*480093f4SDimitry Andric 814*480093f4SDimitry Andric // The clear() operation invalidates all the iterators, except the past-end 815*480093f4SDimitry Andric // iterators of list-like containers 816*480093f4SDimitry Andric auto State = C.getState(); 817*480093f4SDimitry Andric if (!hasSubscriptOperator(State, ContReg) || 818*480093f4SDimitry Andric !backModifiable(State, ContReg)) { 819*480093f4SDimitry Andric const auto CData = getContainerData(State, ContReg); 820*480093f4SDimitry Andric if (CData) { 821*480093f4SDimitry Andric if (const auto EndSym = CData->getEnd()) { 822*480093f4SDimitry Andric State = 823*480093f4SDimitry Andric invalidateAllIteratorPositionsExcept(State, ContReg, EndSym, BO_GE); 824*480093f4SDimitry Andric C.addTransition(State); 825*480093f4SDimitry Andric return; 826*480093f4SDimitry Andric } 827*480093f4SDimitry Andric } 828*480093f4SDimitry Andric } 829*480093f4SDimitry Andric State = invalidateAllIteratorPositions(State, ContReg); 830*480093f4SDimitry Andric C.addTransition(State); 831*480093f4SDimitry Andric } 832*480093f4SDimitry Andric 833*480093f4SDimitry Andric void IteratorModeling::handlePushBack(CheckerContext &C, 834*480093f4SDimitry Andric const SVal &Cont) const { 835*480093f4SDimitry Andric const auto *ContReg = Cont.getAsRegion(); 836*480093f4SDimitry Andric if (!ContReg) 837*480093f4SDimitry Andric return; 838*480093f4SDimitry Andric 839*480093f4SDimitry Andric ContReg = ContReg->getMostDerivedObjectRegion(); 840*480093f4SDimitry Andric 841*480093f4SDimitry Andric // For deque-like containers invalidate all iterator positions 842*480093f4SDimitry Andric auto State = C.getState(); 843*480093f4SDimitry Andric if (hasSubscriptOperator(State, ContReg) && frontModifiable(State, ContReg)) { 844*480093f4SDimitry Andric State = invalidateAllIteratorPositions(State, ContReg); 845*480093f4SDimitry Andric C.addTransition(State); 846*480093f4SDimitry Andric return; 847*480093f4SDimitry Andric } 848*480093f4SDimitry Andric 849*480093f4SDimitry Andric const auto CData = getContainerData(State, ContReg); 850*480093f4SDimitry Andric if (!CData) 851*480093f4SDimitry Andric return; 852*480093f4SDimitry Andric 853*480093f4SDimitry Andric // For vector-like containers invalidate the past-end iterator positions 854*480093f4SDimitry Andric if (const auto EndSym = CData->getEnd()) { 855*480093f4SDimitry Andric if (hasSubscriptOperator(State, ContReg)) { 856*480093f4SDimitry Andric State = invalidateIteratorPositions(State, EndSym, BO_GE); 857*480093f4SDimitry Andric } 858*480093f4SDimitry Andric auto &SymMgr = C.getSymbolManager(); 859*480093f4SDimitry Andric auto &BVF = SymMgr.getBasicVals(); 860*480093f4SDimitry Andric auto &SVB = C.getSValBuilder(); 861*480093f4SDimitry Andric const auto newEndSym = 862*480093f4SDimitry Andric SVB.evalBinOp(State, BO_Add, 863*480093f4SDimitry Andric nonloc::SymbolVal(EndSym), 864*480093f4SDimitry Andric nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))), 865*480093f4SDimitry Andric SymMgr.getType(EndSym)).getAsSymbol(); 866*480093f4SDimitry Andric State = setContainerData(State, ContReg, CData->newEnd(newEndSym)); 867*480093f4SDimitry Andric } 868*480093f4SDimitry Andric C.addTransition(State); 869*480093f4SDimitry Andric } 870*480093f4SDimitry Andric 871*480093f4SDimitry Andric void IteratorModeling::handlePopBack(CheckerContext &C, 872*480093f4SDimitry Andric const SVal &Cont) const { 873*480093f4SDimitry Andric const auto *ContReg = Cont.getAsRegion(); 874*480093f4SDimitry Andric if (!ContReg) 875*480093f4SDimitry Andric return; 876*480093f4SDimitry Andric 877*480093f4SDimitry Andric ContReg = ContReg->getMostDerivedObjectRegion(); 878*480093f4SDimitry Andric 879*480093f4SDimitry Andric auto State = C.getState(); 880*480093f4SDimitry Andric const auto CData = getContainerData(State, ContReg); 881*480093f4SDimitry Andric if (!CData) 882*480093f4SDimitry Andric return; 883*480093f4SDimitry Andric 884*480093f4SDimitry Andric if (const auto EndSym = CData->getEnd()) { 885*480093f4SDimitry Andric auto &SymMgr = C.getSymbolManager(); 886*480093f4SDimitry Andric auto &BVF = SymMgr.getBasicVals(); 887*480093f4SDimitry Andric auto &SVB = C.getSValBuilder(); 888*480093f4SDimitry Andric const auto BackSym = 889*480093f4SDimitry Andric SVB.evalBinOp(State, BO_Sub, 890*480093f4SDimitry Andric nonloc::SymbolVal(EndSym), 891*480093f4SDimitry Andric nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))), 892*480093f4SDimitry Andric SymMgr.getType(EndSym)).getAsSymbol(); 893*480093f4SDimitry Andric // For vector-like and deque-like containers invalidate the last and the 894*480093f4SDimitry Andric // past-end iterator positions. For list-like containers only invalidate 895*480093f4SDimitry Andric // the last position 896*480093f4SDimitry Andric if (hasSubscriptOperator(State, ContReg) && 897*480093f4SDimitry Andric backModifiable(State, ContReg)) { 898*480093f4SDimitry Andric State = invalidateIteratorPositions(State, BackSym, BO_GE); 899*480093f4SDimitry Andric State = setContainerData(State, ContReg, CData->newEnd(nullptr)); 900*480093f4SDimitry Andric } else { 901*480093f4SDimitry Andric State = invalidateIteratorPositions(State, BackSym, BO_EQ); 902*480093f4SDimitry Andric } 903*480093f4SDimitry Andric auto newEndSym = BackSym; 904*480093f4SDimitry Andric State = setContainerData(State, ContReg, CData->newEnd(newEndSym)); 905*480093f4SDimitry Andric C.addTransition(State); 906*480093f4SDimitry Andric } 907*480093f4SDimitry Andric } 908*480093f4SDimitry Andric 909*480093f4SDimitry Andric void IteratorModeling::handlePushFront(CheckerContext &C, 910*480093f4SDimitry Andric const SVal &Cont) const { 911*480093f4SDimitry Andric const auto *ContReg = Cont.getAsRegion(); 912*480093f4SDimitry Andric if (!ContReg) 913*480093f4SDimitry Andric return; 914*480093f4SDimitry Andric 915*480093f4SDimitry Andric ContReg = ContReg->getMostDerivedObjectRegion(); 916*480093f4SDimitry Andric 917*480093f4SDimitry Andric // For deque-like containers invalidate all iterator positions 918*480093f4SDimitry Andric auto State = C.getState(); 919*480093f4SDimitry Andric if (hasSubscriptOperator(State, ContReg)) { 920*480093f4SDimitry Andric State = invalidateAllIteratorPositions(State, ContReg); 921*480093f4SDimitry Andric C.addTransition(State); 922*480093f4SDimitry Andric } else { 923*480093f4SDimitry Andric const auto CData = getContainerData(State, ContReg); 924*480093f4SDimitry Andric if (!CData) 925*480093f4SDimitry Andric return; 926*480093f4SDimitry Andric 927*480093f4SDimitry Andric if (const auto BeginSym = CData->getBegin()) { 928*480093f4SDimitry Andric auto &SymMgr = C.getSymbolManager(); 929*480093f4SDimitry Andric auto &BVF = SymMgr.getBasicVals(); 930*480093f4SDimitry Andric auto &SVB = C.getSValBuilder(); 931*480093f4SDimitry Andric const auto newBeginSym = 932*480093f4SDimitry Andric SVB.evalBinOp(State, BO_Sub, 933*480093f4SDimitry Andric nonloc::SymbolVal(BeginSym), 934*480093f4SDimitry Andric nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))), 935*480093f4SDimitry Andric SymMgr.getType(BeginSym)).getAsSymbol(); 936*480093f4SDimitry Andric State = setContainerData(State, ContReg, CData->newBegin(newBeginSym)); 937*480093f4SDimitry Andric C.addTransition(State); 938*480093f4SDimitry Andric } 939*480093f4SDimitry Andric } 940*480093f4SDimitry Andric } 941*480093f4SDimitry Andric 942*480093f4SDimitry Andric void IteratorModeling::handlePopFront(CheckerContext &C, 943*480093f4SDimitry Andric const SVal &Cont) const { 944*480093f4SDimitry Andric const auto *ContReg = Cont.getAsRegion(); 945*480093f4SDimitry Andric if (!ContReg) 946*480093f4SDimitry Andric return; 947*480093f4SDimitry Andric 948*480093f4SDimitry Andric ContReg = ContReg->getMostDerivedObjectRegion(); 949*480093f4SDimitry Andric 950*480093f4SDimitry Andric auto State = C.getState(); 951*480093f4SDimitry Andric const auto CData = getContainerData(State, ContReg); 952*480093f4SDimitry Andric if (!CData) 953*480093f4SDimitry Andric return; 954*480093f4SDimitry Andric 955*480093f4SDimitry Andric // For deque-like containers invalidate all iterator positions. For list-like 956*480093f4SDimitry Andric // iterators only invalidate the first position 957*480093f4SDimitry Andric if (const auto BeginSym = CData->getBegin()) { 958*480093f4SDimitry Andric if (hasSubscriptOperator(State, ContReg)) { 959*480093f4SDimitry Andric State = invalidateIteratorPositions(State, BeginSym, BO_LE); 960*480093f4SDimitry Andric } else { 961*480093f4SDimitry Andric State = invalidateIteratorPositions(State, BeginSym, BO_EQ); 962*480093f4SDimitry Andric } 963*480093f4SDimitry Andric auto &SymMgr = C.getSymbolManager(); 964*480093f4SDimitry Andric auto &BVF = SymMgr.getBasicVals(); 965*480093f4SDimitry Andric auto &SVB = C.getSValBuilder(); 966*480093f4SDimitry Andric const auto newBeginSym = 967*480093f4SDimitry Andric SVB.evalBinOp(State, BO_Add, 968*480093f4SDimitry Andric nonloc::SymbolVal(BeginSym), 969*480093f4SDimitry Andric nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))), 970*480093f4SDimitry Andric SymMgr.getType(BeginSym)).getAsSymbol(); 971*480093f4SDimitry Andric State = setContainerData(State, ContReg, CData->newBegin(newBeginSym)); 972*480093f4SDimitry Andric C.addTransition(State); 973*480093f4SDimitry Andric } 974*480093f4SDimitry Andric } 975*480093f4SDimitry Andric 976*480093f4SDimitry Andric void IteratorModeling::handleInsert(CheckerContext &C, const SVal &Iter) const { 977*480093f4SDimitry Andric auto State = C.getState(); 978*480093f4SDimitry Andric const auto *Pos = getIteratorPosition(State, Iter); 979*480093f4SDimitry Andric if (!Pos) 980*480093f4SDimitry Andric return; 981*480093f4SDimitry Andric 982*480093f4SDimitry Andric // For deque-like containers invalidate all iterator positions. For 983*480093f4SDimitry Andric // vector-like containers invalidate iterator positions after the insertion. 984*480093f4SDimitry Andric const auto *Cont = Pos->getContainer(); 985*480093f4SDimitry Andric if (hasSubscriptOperator(State, Cont) && backModifiable(State, Cont)) { 986*480093f4SDimitry Andric if (frontModifiable(State, Cont)) { 987*480093f4SDimitry Andric State = invalidateAllIteratorPositions(State, Cont); 988*480093f4SDimitry Andric } else { 989*480093f4SDimitry Andric State = invalidateIteratorPositions(State, Pos->getOffset(), BO_GE); 990*480093f4SDimitry Andric } 991*480093f4SDimitry Andric if (const auto *CData = getContainerData(State, Cont)) { 992*480093f4SDimitry Andric if (const auto EndSym = CData->getEnd()) { 993*480093f4SDimitry Andric State = invalidateIteratorPositions(State, EndSym, BO_GE); 994*480093f4SDimitry Andric State = setContainerData(State, Cont, CData->newEnd(nullptr)); 995*480093f4SDimitry Andric } 996*480093f4SDimitry Andric } 997*480093f4SDimitry Andric C.addTransition(State); 998*480093f4SDimitry Andric } 999*480093f4SDimitry Andric } 1000*480093f4SDimitry Andric 1001*480093f4SDimitry Andric void IteratorModeling::handleErase(CheckerContext &C, const SVal &Iter) const { 1002*480093f4SDimitry Andric auto State = C.getState(); 1003*480093f4SDimitry Andric const auto *Pos = getIteratorPosition(State, Iter); 1004*480093f4SDimitry Andric if (!Pos) 1005*480093f4SDimitry Andric return; 1006*480093f4SDimitry Andric 1007*480093f4SDimitry Andric // For deque-like containers invalidate all iterator positions. For 1008*480093f4SDimitry Andric // vector-like containers invalidate iterator positions at and after the 1009*480093f4SDimitry Andric // deletion. For list-like containers only invalidate the deleted position. 1010*480093f4SDimitry Andric const auto *Cont = Pos->getContainer(); 1011*480093f4SDimitry Andric if (hasSubscriptOperator(State, Cont) && backModifiable(State, Cont)) { 1012*480093f4SDimitry Andric if (frontModifiable(State, Cont)) { 1013*480093f4SDimitry Andric State = invalidateAllIteratorPositions(State, Cont); 1014*480093f4SDimitry Andric } else { 1015*480093f4SDimitry Andric State = invalidateIteratorPositions(State, Pos->getOffset(), BO_GE); 1016*480093f4SDimitry Andric } 1017*480093f4SDimitry Andric if (const auto *CData = getContainerData(State, Cont)) { 1018*480093f4SDimitry Andric if (const auto EndSym = CData->getEnd()) { 1019*480093f4SDimitry Andric State = invalidateIteratorPositions(State, EndSym, BO_GE); 1020*480093f4SDimitry Andric State = setContainerData(State, Cont, CData->newEnd(nullptr)); 1021*480093f4SDimitry Andric } 1022*480093f4SDimitry Andric } 1023*480093f4SDimitry Andric } else { 1024*480093f4SDimitry Andric State = invalidateIteratorPositions(State, Pos->getOffset(), BO_EQ); 1025*480093f4SDimitry Andric } 1026*480093f4SDimitry Andric C.addTransition(State); 1027*480093f4SDimitry Andric } 1028*480093f4SDimitry Andric 1029*480093f4SDimitry Andric void IteratorModeling::handleErase(CheckerContext &C, const SVal &Iter1, 1030*480093f4SDimitry Andric const SVal &Iter2) const { 1031*480093f4SDimitry Andric auto State = C.getState(); 1032*480093f4SDimitry Andric const auto *Pos1 = getIteratorPosition(State, Iter1); 1033*480093f4SDimitry Andric const auto *Pos2 = getIteratorPosition(State, Iter2); 1034*480093f4SDimitry Andric if (!Pos1 || !Pos2) 1035*480093f4SDimitry Andric return; 1036*480093f4SDimitry Andric 1037*480093f4SDimitry Andric // For deque-like containers invalidate all iterator positions. For 1038*480093f4SDimitry Andric // vector-like containers invalidate iterator positions at and after the 1039*480093f4SDimitry Andric // deletion range. For list-like containers only invalidate the deleted 1040*480093f4SDimitry Andric // position range [first..last]. 1041*480093f4SDimitry Andric const auto *Cont = Pos1->getContainer(); 1042*480093f4SDimitry Andric if (hasSubscriptOperator(State, Cont) && backModifiable(State, Cont)) { 1043*480093f4SDimitry Andric if (frontModifiable(State, Cont)) { 1044*480093f4SDimitry Andric State = invalidateAllIteratorPositions(State, Cont); 1045*480093f4SDimitry Andric } else { 1046*480093f4SDimitry Andric State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GE); 1047*480093f4SDimitry Andric } 1048*480093f4SDimitry Andric if (const auto *CData = getContainerData(State, Cont)) { 1049*480093f4SDimitry Andric if (const auto EndSym = CData->getEnd()) { 1050*480093f4SDimitry Andric State = invalidateIteratorPositions(State, EndSym, BO_GE); 1051*480093f4SDimitry Andric State = setContainerData(State, Cont, CData->newEnd(nullptr)); 1052*480093f4SDimitry Andric } 1053*480093f4SDimitry Andric } 1054*480093f4SDimitry Andric } else { 1055*480093f4SDimitry Andric State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GE, 1056*480093f4SDimitry Andric Pos2->getOffset(), BO_LT); 1057*480093f4SDimitry Andric } 1058*480093f4SDimitry Andric C.addTransition(State); 1059*480093f4SDimitry Andric } 1060*480093f4SDimitry Andric 1061*480093f4SDimitry Andric void IteratorModeling::handleEraseAfter(CheckerContext &C, 1062*480093f4SDimitry Andric const SVal &Iter) const { 1063*480093f4SDimitry Andric auto State = C.getState(); 1064*480093f4SDimitry Andric const auto *Pos = getIteratorPosition(State, Iter); 1065*480093f4SDimitry Andric if (!Pos) 1066*480093f4SDimitry Andric return; 1067*480093f4SDimitry Andric 1068*480093f4SDimitry Andric // Invalidate the deleted iterator position, which is the position of the 1069*480093f4SDimitry Andric // parameter plus one. 1070*480093f4SDimitry Andric auto &SymMgr = C.getSymbolManager(); 1071*480093f4SDimitry Andric auto &BVF = SymMgr.getBasicVals(); 1072*480093f4SDimitry Andric auto &SVB = C.getSValBuilder(); 1073*480093f4SDimitry Andric const auto NextSym = 1074*480093f4SDimitry Andric SVB.evalBinOp(State, BO_Add, 1075*480093f4SDimitry Andric nonloc::SymbolVal(Pos->getOffset()), 1076*480093f4SDimitry Andric nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))), 1077*480093f4SDimitry Andric SymMgr.getType(Pos->getOffset())).getAsSymbol(); 1078*480093f4SDimitry Andric State = invalidateIteratorPositions(State, NextSym, BO_EQ); 1079*480093f4SDimitry Andric C.addTransition(State); 1080*480093f4SDimitry Andric } 1081*480093f4SDimitry Andric 1082*480093f4SDimitry Andric void IteratorModeling::handleEraseAfter(CheckerContext &C, const SVal &Iter1, 1083*480093f4SDimitry Andric const SVal &Iter2) const { 1084*480093f4SDimitry Andric auto State = C.getState(); 1085*480093f4SDimitry Andric const auto *Pos1 = getIteratorPosition(State, Iter1); 1086*480093f4SDimitry Andric const auto *Pos2 = getIteratorPosition(State, Iter2); 1087*480093f4SDimitry Andric if (!Pos1 || !Pos2) 1088*480093f4SDimitry Andric return; 1089*480093f4SDimitry Andric 1090*480093f4SDimitry Andric // Invalidate the deleted iterator position range (first..last) 1091*480093f4SDimitry Andric State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GT, 1092*480093f4SDimitry Andric Pos2->getOffset(), BO_LT); 1093*480093f4SDimitry Andric C.addTransition(State); 1094*480093f4SDimitry Andric } 1095*480093f4SDimitry Andric 1096*480093f4SDimitry Andric void IteratorModeling::printState(raw_ostream &Out, ProgramStateRef State, 1097*480093f4SDimitry Andric const char *NL, const char *Sep) const { 1098*480093f4SDimitry Andric 1099*480093f4SDimitry Andric auto ContMap = State->get<ContainerMap>(); 1100*480093f4SDimitry Andric 1101*480093f4SDimitry Andric if (!ContMap.isEmpty()) { 1102*480093f4SDimitry Andric Out << Sep << "Container Data :" << NL; 1103*480093f4SDimitry Andric for (const auto &Cont : ContMap) { 1104*480093f4SDimitry Andric Cont.first->dumpToStream(Out); 1105*480093f4SDimitry Andric Out << " : [ "; 1106*480093f4SDimitry Andric const auto CData = Cont.second; 1107*480093f4SDimitry Andric if (CData.getBegin()) 1108*480093f4SDimitry Andric CData.getBegin()->dumpToStream(Out); 1109*480093f4SDimitry Andric else 1110*480093f4SDimitry Andric Out << "<Unknown>"; 1111*480093f4SDimitry Andric Out << " .. "; 1112*480093f4SDimitry Andric if (CData.getEnd()) 1113*480093f4SDimitry Andric CData.getEnd()->dumpToStream(Out); 1114*480093f4SDimitry Andric else 1115*480093f4SDimitry Andric Out << "<Unknown>"; 1116*480093f4SDimitry Andric Out << " ]" << NL; 1117*480093f4SDimitry Andric } 1118*480093f4SDimitry Andric } 1119*480093f4SDimitry Andric 1120*480093f4SDimitry Andric auto SymbolMap = State->get<IteratorSymbolMap>(); 1121*480093f4SDimitry Andric auto RegionMap = State->get<IteratorRegionMap>(); 1122*480093f4SDimitry Andric 1123*480093f4SDimitry Andric if (!SymbolMap.isEmpty() || !RegionMap.isEmpty()) { 1124*480093f4SDimitry Andric Out << Sep << "Iterator Positions :" << NL; 1125*480093f4SDimitry Andric for (const auto &Sym : SymbolMap) { 1126*480093f4SDimitry Andric Sym.first->dumpToStream(Out); 1127*480093f4SDimitry Andric Out << " : "; 1128*480093f4SDimitry Andric const auto Pos = Sym.second; 1129*480093f4SDimitry Andric Out << (Pos.isValid() ? "Valid" : "Invalid") << " ; Container == "; 1130*480093f4SDimitry Andric Pos.getContainer()->dumpToStream(Out); 1131*480093f4SDimitry Andric Out<<" ; Offset == "; 1132*480093f4SDimitry Andric Pos.getOffset()->dumpToStream(Out); 1133*480093f4SDimitry Andric } 1134*480093f4SDimitry Andric 1135*480093f4SDimitry Andric for (const auto &Reg : RegionMap) { 1136*480093f4SDimitry Andric Reg.first->dumpToStream(Out); 1137*480093f4SDimitry Andric Out << " : "; 1138*480093f4SDimitry Andric const auto Pos = Reg.second; 1139*480093f4SDimitry Andric Out << (Pos.isValid() ? "Valid" : "Invalid") << " ; Container == "; 1140*480093f4SDimitry Andric Pos.getContainer()->dumpToStream(Out); 1141*480093f4SDimitry Andric Out<<" ; Offset == "; 1142*480093f4SDimitry Andric Pos.getOffset()->dumpToStream(Out); 1143*480093f4SDimitry Andric } 1144*480093f4SDimitry Andric } 1145*480093f4SDimitry Andric } 1146*480093f4SDimitry Andric 1147*480093f4SDimitry Andric 1148*480093f4SDimitry Andric namespace { 1149*480093f4SDimitry Andric 1150*480093f4SDimitry Andric const CXXRecordDecl *getCXXRecordDecl(ProgramStateRef State, 1151*480093f4SDimitry Andric const MemRegion *Reg); 1152*480093f4SDimitry Andric 1153*480093f4SDimitry Andric bool isBeginCall(const FunctionDecl *Func) { 1154*480093f4SDimitry Andric const auto *IdInfo = Func->getIdentifier(); 1155*480093f4SDimitry Andric if (!IdInfo) 1156*480093f4SDimitry Andric return false; 1157*480093f4SDimitry Andric return IdInfo->getName().endswith_lower("begin"); 1158*480093f4SDimitry Andric } 1159*480093f4SDimitry Andric 1160*480093f4SDimitry Andric bool isEndCall(const FunctionDecl *Func) { 1161*480093f4SDimitry Andric const auto *IdInfo = Func->getIdentifier(); 1162*480093f4SDimitry Andric if (!IdInfo) 1163*480093f4SDimitry Andric return false; 1164*480093f4SDimitry Andric return IdInfo->getName().endswith_lower("end"); 1165*480093f4SDimitry Andric } 1166*480093f4SDimitry Andric 1167*480093f4SDimitry Andric bool isAssignCall(const FunctionDecl *Func) { 1168*480093f4SDimitry Andric const auto *IdInfo = Func->getIdentifier(); 1169*480093f4SDimitry Andric if (!IdInfo) 1170*480093f4SDimitry Andric return false; 1171*480093f4SDimitry Andric if (Func->getNumParams() > 2) 1172*480093f4SDimitry Andric return false; 1173*480093f4SDimitry Andric return IdInfo->getName() == "assign"; 1174*480093f4SDimitry Andric } 1175*480093f4SDimitry Andric 1176*480093f4SDimitry Andric bool isClearCall(const FunctionDecl *Func) { 1177*480093f4SDimitry Andric const auto *IdInfo = Func->getIdentifier(); 1178*480093f4SDimitry Andric if (!IdInfo) 1179*480093f4SDimitry Andric return false; 1180*480093f4SDimitry Andric if (Func->getNumParams() > 0) 1181*480093f4SDimitry Andric return false; 1182*480093f4SDimitry Andric return IdInfo->getName() == "clear"; 1183*480093f4SDimitry Andric } 1184*480093f4SDimitry Andric 1185*480093f4SDimitry Andric bool isPushBackCall(const FunctionDecl *Func) { 1186*480093f4SDimitry Andric const auto *IdInfo = Func->getIdentifier(); 1187*480093f4SDimitry Andric if (!IdInfo) 1188*480093f4SDimitry Andric return false; 1189*480093f4SDimitry Andric if (Func->getNumParams() != 1) 1190*480093f4SDimitry Andric return false; 1191*480093f4SDimitry Andric return IdInfo->getName() == "push_back"; 1192*480093f4SDimitry Andric } 1193*480093f4SDimitry Andric 1194*480093f4SDimitry Andric bool isEmplaceBackCall(const FunctionDecl *Func) { 1195*480093f4SDimitry Andric const auto *IdInfo = Func->getIdentifier(); 1196*480093f4SDimitry Andric if (!IdInfo) 1197*480093f4SDimitry Andric return false; 1198*480093f4SDimitry Andric if (Func->getNumParams() < 1) 1199*480093f4SDimitry Andric return false; 1200*480093f4SDimitry Andric return IdInfo->getName() == "emplace_back"; 1201*480093f4SDimitry Andric } 1202*480093f4SDimitry Andric 1203*480093f4SDimitry Andric bool isPopBackCall(const FunctionDecl *Func) { 1204*480093f4SDimitry Andric const auto *IdInfo = Func->getIdentifier(); 1205*480093f4SDimitry Andric if (!IdInfo) 1206*480093f4SDimitry Andric return false; 1207*480093f4SDimitry Andric if (Func->getNumParams() > 0) 1208*480093f4SDimitry Andric return false; 1209*480093f4SDimitry Andric return IdInfo->getName() == "pop_back"; 1210*480093f4SDimitry Andric } 1211*480093f4SDimitry Andric 1212*480093f4SDimitry Andric bool isPushFrontCall(const FunctionDecl *Func) { 1213*480093f4SDimitry Andric const auto *IdInfo = Func->getIdentifier(); 1214*480093f4SDimitry Andric if (!IdInfo) 1215*480093f4SDimitry Andric return false; 1216*480093f4SDimitry Andric if (Func->getNumParams() != 1) 1217*480093f4SDimitry Andric return false; 1218*480093f4SDimitry Andric return IdInfo->getName() == "push_front"; 1219*480093f4SDimitry Andric } 1220*480093f4SDimitry Andric 1221*480093f4SDimitry Andric bool isEmplaceFrontCall(const FunctionDecl *Func) { 1222*480093f4SDimitry Andric const auto *IdInfo = Func->getIdentifier(); 1223*480093f4SDimitry Andric if (!IdInfo) 1224*480093f4SDimitry Andric return false; 1225*480093f4SDimitry Andric if (Func->getNumParams() < 1) 1226*480093f4SDimitry Andric return false; 1227*480093f4SDimitry Andric return IdInfo->getName() == "emplace_front"; 1228*480093f4SDimitry Andric } 1229*480093f4SDimitry Andric 1230*480093f4SDimitry Andric bool isPopFrontCall(const FunctionDecl *Func) { 1231*480093f4SDimitry Andric const auto *IdInfo = Func->getIdentifier(); 1232*480093f4SDimitry Andric if (!IdInfo) 1233*480093f4SDimitry Andric return false; 1234*480093f4SDimitry Andric if (Func->getNumParams() > 0) 1235*480093f4SDimitry Andric return false; 1236*480093f4SDimitry Andric return IdInfo->getName() == "pop_front"; 1237*480093f4SDimitry Andric } 1238*480093f4SDimitry Andric 1239*480093f4SDimitry Andric bool isAssignmentOperator(OverloadedOperatorKind OK) { return OK == OO_Equal; } 1240*480093f4SDimitry Andric 1241*480093f4SDimitry Andric bool isSimpleComparisonOperator(OverloadedOperatorKind OK) { 1242*480093f4SDimitry Andric return OK == OO_EqualEqual || OK == OO_ExclaimEqual; 1243*480093f4SDimitry Andric } 1244*480093f4SDimitry Andric 1245*480093f4SDimitry Andric bool hasSubscriptOperator(ProgramStateRef State, const MemRegion *Reg) { 1246*480093f4SDimitry Andric const auto *CRD = getCXXRecordDecl(State, Reg); 1247*480093f4SDimitry Andric if (!CRD) 1248*480093f4SDimitry Andric return false; 1249*480093f4SDimitry Andric 1250*480093f4SDimitry Andric for (const auto *Method : CRD->methods()) { 1251*480093f4SDimitry Andric if (!Method->isOverloadedOperator()) 1252*480093f4SDimitry Andric continue; 1253*480093f4SDimitry Andric const auto OPK = Method->getOverloadedOperator(); 1254*480093f4SDimitry Andric if (OPK == OO_Subscript) { 1255*480093f4SDimitry Andric return true; 1256*480093f4SDimitry Andric } 1257*480093f4SDimitry Andric } 1258*480093f4SDimitry Andric return false; 1259*480093f4SDimitry Andric } 1260*480093f4SDimitry Andric 1261*480093f4SDimitry Andric bool frontModifiable(ProgramStateRef State, const MemRegion *Reg) { 1262*480093f4SDimitry Andric const auto *CRD = getCXXRecordDecl(State, Reg); 1263*480093f4SDimitry Andric if (!CRD) 1264*480093f4SDimitry Andric return false; 1265*480093f4SDimitry Andric 1266*480093f4SDimitry Andric for (const auto *Method : CRD->methods()) { 1267*480093f4SDimitry Andric if (!Method->getDeclName().isIdentifier()) 1268*480093f4SDimitry Andric continue; 1269*480093f4SDimitry Andric if (Method->getName() == "push_front" || Method->getName() == "pop_front") { 1270*480093f4SDimitry Andric return true; 1271*480093f4SDimitry Andric } 1272*480093f4SDimitry Andric } 1273*480093f4SDimitry Andric return false; 1274*480093f4SDimitry Andric } 1275*480093f4SDimitry Andric 1276*480093f4SDimitry Andric bool backModifiable(ProgramStateRef State, const MemRegion *Reg) { 1277*480093f4SDimitry Andric const auto *CRD = getCXXRecordDecl(State, Reg); 1278*480093f4SDimitry Andric if (!CRD) 1279*480093f4SDimitry Andric return false; 1280*480093f4SDimitry Andric 1281*480093f4SDimitry Andric for (const auto *Method : CRD->methods()) { 1282*480093f4SDimitry Andric if (!Method->getDeclName().isIdentifier()) 1283*480093f4SDimitry Andric continue; 1284*480093f4SDimitry Andric if (Method->getName() == "push_back" || Method->getName() == "pop_back") { 1285*480093f4SDimitry Andric return true; 1286*480093f4SDimitry Andric } 1287*480093f4SDimitry Andric } 1288*480093f4SDimitry Andric return false; 1289*480093f4SDimitry Andric } 1290*480093f4SDimitry Andric 1291*480093f4SDimitry Andric const CXXRecordDecl *getCXXRecordDecl(ProgramStateRef State, 1292*480093f4SDimitry Andric const MemRegion *Reg) { 1293*480093f4SDimitry Andric auto TI = getDynamicTypeInfo(State, Reg); 1294*480093f4SDimitry Andric if (!TI.isValid()) 1295*480093f4SDimitry Andric return nullptr; 1296*480093f4SDimitry Andric 1297*480093f4SDimitry Andric auto Type = TI.getType(); 1298*480093f4SDimitry Andric if (const auto *RefT = Type->getAs<ReferenceType>()) { 1299*480093f4SDimitry Andric Type = RefT->getPointeeType(); 1300*480093f4SDimitry Andric } 1301*480093f4SDimitry Andric 1302*480093f4SDimitry Andric return Type->getUnqualifiedDesugaredType()->getAsCXXRecordDecl(); 1303*480093f4SDimitry Andric } 1304*480093f4SDimitry Andric 1305*480093f4SDimitry Andric SymbolRef getContainerBegin(ProgramStateRef State, const MemRegion *Cont) { 1306*480093f4SDimitry Andric const auto *CDataPtr = getContainerData(State, Cont); 1307*480093f4SDimitry Andric if (!CDataPtr) 1308*480093f4SDimitry Andric return nullptr; 1309*480093f4SDimitry Andric 1310*480093f4SDimitry Andric return CDataPtr->getBegin(); 1311*480093f4SDimitry Andric } 1312*480093f4SDimitry Andric 1313*480093f4SDimitry Andric SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont) { 1314*480093f4SDimitry Andric const auto *CDataPtr = getContainerData(State, Cont); 1315*480093f4SDimitry Andric if (!CDataPtr) 1316*480093f4SDimitry Andric return nullptr; 1317*480093f4SDimitry Andric 1318*480093f4SDimitry Andric return CDataPtr->getEnd(); 1319*480093f4SDimitry Andric } 1320*480093f4SDimitry Andric 1321*480093f4SDimitry Andric ProgramStateRef createContainerBegin(ProgramStateRef State, 1322*480093f4SDimitry Andric const MemRegion *Cont, const Expr *E, 1323*480093f4SDimitry Andric QualType T, const LocationContext *LCtx, 1324*480093f4SDimitry Andric unsigned BlockCount) { 1325*480093f4SDimitry Andric // Only create if it does not exist 1326*480093f4SDimitry Andric const auto *CDataPtr = getContainerData(State, Cont); 1327*480093f4SDimitry Andric if (CDataPtr && CDataPtr->getBegin()) 1328*480093f4SDimitry Andric return State; 1329*480093f4SDimitry Andric 1330*480093f4SDimitry Andric auto &SymMgr = State->getSymbolManager(); 1331*480093f4SDimitry Andric const SymbolConjured *Sym = SymMgr.conjureSymbol(E, LCtx, T, BlockCount, 1332*480093f4SDimitry Andric "begin"); 1333*480093f4SDimitry Andric State = assumeNoOverflow(State, Sym, 4); 1334*480093f4SDimitry Andric 1335*480093f4SDimitry Andric if (CDataPtr) { 1336*480093f4SDimitry Andric const auto CData = CDataPtr->newBegin(Sym); 1337*480093f4SDimitry Andric return setContainerData(State, Cont, CData); 1338*480093f4SDimitry Andric } 1339*480093f4SDimitry Andric 1340*480093f4SDimitry Andric const auto CData = ContainerData::fromBegin(Sym); 1341*480093f4SDimitry Andric return setContainerData(State, Cont, CData); 1342*480093f4SDimitry Andric } 1343*480093f4SDimitry Andric 1344*480093f4SDimitry Andric ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont, 1345*480093f4SDimitry Andric const Expr *E, QualType T, 1346*480093f4SDimitry Andric const LocationContext *LCtx, 1347*480093f4SDimitry Andric unsigned BlockCount) { 1348*480093f4SDimitry Andric // Only create if it does not exist 1349*480093f4SDimitry Andric const auto *CDataPtr = getContainerData(State, Cont); 1350*480093f4SDimitry Andric if (CDataPtr && CDataPtr->getEnd()) 1351*480093f4SDimitry Andric return State; 1352*480093f4SDimitry Andric 1353*480093f4SDimitry Andric auto &SymMgr = State->getSymbolManager(); 1354*480093f4SDimitry Andric const SymbolConjured *Sym = SymMgr.conjureSymbol(E, LCtx, T, BlockCount, 1355*480093f4SDimitry Andric "end"); 1356*480093f4SDimitry Andric State = assumeNoOverflow(State, Sym, 4); 1357*480093f4SDimitry Andric 1358*480093f4SDimitry Andric if (CDataPtr) { 1359*480093f4SDimitry Andric const auto CData = CDataPtr->newEnd(Sym); 1360*480093f4SDimitry Andric return setContainerData(State, Cont, CData); 1361*480093f4SDimitry Andric } 1362*480093f4SDimitry Andric 1363*480093f4SDimitry Andric const auto CData = ContainerData::fromEnd(Sym); 1364*480093f4SDimitry Andric return setContainerData(State, Cont, CData); 1365*480093f4SDimitry Andric } 1366*480093f4SDimitry Andric 1367*480093f4SDimitry Andric ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont, 1368*480093f4SDimitry Andric const ContainerData &CData) { 1369*480093f4SDimitry Andric return State->set<ContainerMap>(Cont, CData); 1370*480093f4SDimitry Andric } 1371*480093f4SDimitry Andric 1372*480093f4SDimitry Andric ProgramStateRef removeIteratorPosition(ProgramStateRef State, const SVal &Val) { 1373*480093f4SDimitry Andric if (auto Reg = Val.getAsRegion()) { 1374*480093f4SDimitry Andric Reg = Reg->getMostDerivedObjectRegion(); 1375*480093f4SDimitry Andric return State->remove<IteratorRegionMap>(Reg); 1376*480093f4SDimitry Andric } else if (const auto Sym = Val.getAsSymbol()) { 1377*480093f4SDimitry Andric return State->remove<IteratorSymbolMap>(Sym); 1378*480093f4SDimitry Andric } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) { 1379*480093f4SDimitry Andric return State->remove<IteratorRegionMap>(LCVal->getRegion()); 1380*480093f4SDimitry Andric } 1381*480093f4SDimitry Andric return nullptr; 1382*480093f4SDimitry Andric } 1383*480093f4SDimitry Andric 1384*480093f4SDimitry Andric // This function tells the analyzer's engine that symbols produced by our 1385*480093f4SDimitry Andric // checker, most notably iterator positions, are relatively small. 1386*480093f4SDimitry Andric // A distance between items in the container should not be very large. 1387*480093f4SDimitry Andric // By assuming that it is within around 1/8 of the address space, 1388*480093f4SDimitry Andric // we can help the analyzer perform operations on these symbols 1389*480093f4SDimitry Andric // without being afraid of integer overflows. 1390*480093f4SDimitry Andric // FIXME: Should we provide it as an API, so that all checkers could use it? 1391*480093f4SDimitry Andric ProgramStateRef assumeNoOverflow(ProgramStateRef State, SymbolRef Sym, 1392*480093f4SDimitry Andric long Scale) { 1393*480093f4SDimitry Andric SValBuilder &SVB = State->getStateManager().getSValBuilder(); 1394*480093f4SDimitry Andric BasicValueFactory &BV = SVB.getBasicValueFactory(); 1395*480093f4SDimitry Andric 1396*480093f4SDimitry Andric QualType T = Sym->getType(); 1397*480093f4SDimitry Andric assert(T->isSignedIntegerOrEnumerationType()); 1398*480093f4SDimitry Andric APSIntType AT = BV.getAPSIntType(T); 1399*480093f4SDimitry Andric 1400*480093f4SDimitry Andric ProgramStateRef NewState = State; 1401*480093f4SDimitry Andric 1402*480093f4SDimitry Andric llvm::APSInt Max = AT.getMaxValue() / AT.getValue(Scale); 1403*480093f4SDimitry Andric SVal IsCappedFromAbove = 1404*480093f4SDimitry Andric SVB.evalBinOpNN(State, BO_LE, nonloc::SymbolVal(Sym), 1405*480093f4SDimitry Andric nonloc::ConcreteInt(Max), SVB.getConditionType()); 1406*480093f4SDimitry Andric if (auto DV = IsCappedFromAbove.getAs<DefinedSVal>()) { 1407*480093f4SDimitry Andric NewState = NewState->assume(*DV, true); 1408*480093f4SDimitry Andric if (!NewState) 1409*480093f4SDimitry Andric return State; 1410*480093f4SDimitry Andric } 1411*480093f4SDimitry Andric 1412*480093f4SDimitry Andric llvm::APSInt Min = -Max; 1413*480093f4SDimitry Andric SVal IsCappedFromBelow = 1414*480093f4SDimitry Andric SVB.evalBinOpNN(State, BO_GE, nonloc::SymbolVal(Sym), 1415*480093f4SDimitry Andric nonloc::ConcreteInt(Min), SVB.getConditionType()); 1416*480093f4SDimitry Andric if (auto DV = IsCappedFromBelow.getAs<DefinedSVal>()) { 1417*480093f4SDimitry Andric NewState = NewState->assume(*DV, true); 1418*480093f4SDimitry Andric if (!NewState) 1419*480093f4SDimitry Andric return State; 1420*480093f4SDimitry Andric } 1421*480093f4SDimitry Andric 1422*480093f4SDimitry Andric return NewState; 1423*480093f4SDimitry Andric } 1424*480093f4SDimitry Andric 1425*480093f4SDimitry Andric ProgramStateRef relateSymbols(ProgramStateRef State, SymbolRef Sym1, 1426*480093f4SDimitry Andric SymbolRef Sym2, bool Equal) { 1427*480093f4SDimitry Andric auto &SVB = State->getStateManager().getSValBuilder(); 1428*480093f4SDimitry Andric 1429*480093f4SDimitry Andric // FIXME: This code should be reworked as follows: 1430*480093f4SDimitry Andric // 1. Subtract the operands using evalBinOp(). 1431*480093f4SDimitry Andric // 2. Assume that the result doesn't overflow. 1432*480093f4SDimitry Andric // 3. Compare the result to 0. 1433*480093f4SDimitry Andric // 4. Assume the result of the comparison. 1434*480093f4SDimitry Andric const auto comparison = 1435*480093f4SDimitry Andric SVB.evalBinOp(State, BO_EQ, nonloc::SymbolVal(Sym1), 1436*480093f4SDimitry Andric nonloc::SymbolVal(Sym2), SVB.getConditionType()); 1437*480093f4SDimitry Andric 1438*480093f4SDimitry Andric assert(comparison.getAs<DefinedSVal>() && 1439*480093f4SDimitry Andric "Symbol comparison must be a `DefinedSVal`"); 1440*480093f4SDimitry Andric 1441*480093f4SDimitry Andric auto NewState = State->assume(comparison.castAs<DefinedSVal>(), Equal); 1442*480093f4SDimitry Andric if (!NewState) 1443*480093f4SDimitry Andric return nullptr; 1444*480093f4SDimitry Andric 1445*480093f4SDimitry Andric if (const auto CompSym = comparison.getAsSymbol()) { 1446*480093f4SDimitry Andric assert(isa<SymIntExpr>(CompSym) && 1447*480093f4SDimitry Andric "Symbol comparison must be a `SymIntExpr`"); 1448*480093f4SDimitry Andric assert(BinaryOperator::isComparisonOp( 1449*480093f4SDimitry Andric cast<SymIntExpr>(CompSym)->getOpcode()) && 1450*480093f4SDimitry Andric "Symbol comparison must be a comparison"); 1451*480093f4SDimitry Andric return assumeNoOverflow(NewState, cast<SymIntExpr>(CompSym)->getLHS(), 2); 1452*480093f4SDimitry Andric } 1453*480093f4SDimitry Andric 1454*480093f4SDimitry Andric return NewState; 1455*480093f4SDimitry Andric } 1456*480093f4SDimitry Andric 1457*480093f4SDimitry Andric bool hasLiveIterators(ProgramStateRef State, const MemRegion *Cont) { 1458*480093f4SDimitry Andric auto RegionMap = State->get<IteratorRegionMap>(); 1459*480093f4SDimitry Andric for (const auto &Reg : RegionMap) { 1460*480093f4SDimitry Andric if (Reg.second.getContainer() == Cont) 1461*480093f4SDimitry Andric return true; 1462*480093f4SDimitry Andric } 1463*480093f4SDimitry Andric 1464*480093f4SDimitry Andric auto SymbolMap = State->get<IteratorSymbolMap>(); 1465*480093f4SDimitry Andric for (const auto &Sym : SymbolMap) { 1466*480093f4SDimitry Andric if (Sym.second.getContainer() == Cont) 1467*480093f4SDimitry Andric return true; 1468*480093f4SDimitry Andric } 1469*480093f4SDimitry Andric 1470*480093f4SDimitry Andric return false; 1471*480093f4SDimitry Andric } 1472*480093f4SDimitry Andric 1473*480093f4SDimitry Andric bool isBoundThroughLazyCompoundVal(const Environment &Env, 1474*480093f4SDimitry Andric const MemRegion *Reg) { 1475*480093f4SDimitry Andric for (const auto &Binding : Env) { 1476*480093f4SDimitry Andric if (const auto LCVal = Binding.second.getAs<nonloc::LazyCompoundVal>()) { 1477*480093f4SDimitry Andric if (LCVal->getRegion() == Reg) 1478*480093f4SDimitry Andric return true; 1479*480093f4SDimitry Andric } 1480*480093f4SDimitry Andric } 1481*480093f4SDimitry Andric 1482*480093f4SDimitry Andric return false; 1483*480093f4SDimitry Andric } 1484*480093f4SDimitry Andric 1485*480093f4SDimitry Andric template <typename Condition, typename Process> 1486*480093f4SDimitry Andric ProgramStateRef processIteratorPositions(ProgramStateRef State, Condition Cond, 1487*480093f4SDimitry Andric Process Proc) { 1488*480093f4SDimitry Andric auto &RegionMapFactory = State->get_context<IteratorRegionMap>(); 1489*480093f4SDimitry Andric auto RegionMap = State->get<IteratorRegionMap>(); 1490*480093f4SDimitry Andric bool Changed = false; 1491*480093f4SDimitry Andric for (const auto &Reg : RegionMap) { 1492*480093f4SDimitry Andric if (Cond(Reg.second)) { 1493*480093f4SDimitry Andric RegionMap = RegionMapFactory.add(RegionMap, Reg.first, Proc(Reg.second)); 1494*480093f4SDimitry Andric Changed = true; 1495*480093f4SDimitry Andric } 1496*480093f4SDimitry Andric } 1497*480093f4SDimitry Andric 1498*480093f4SDimitry Andric if (Changed) 1499*480093f4SDimitry Andric State = State->set<IteratorRegionMap>(RegionMap); 1500*480093f4SDimitry Andric 1501*480093f4SDimitry Andric auto &SymbolMapFactory = State->get_context<IteratorSymbolMap>(); 1502*480093f4SDimitry Andric auto SymbolMap = State->get<IteratorSymbolMap>(); 1503*480093f4SDimitry Andric Changed = false; 1504*480093f4SDimitry Andric for (const auto &Sym : SymbolMap) { 1505*480093f4SDimitry Andric if (Cond(Sym.second)) { 1506*480093f4SDimitry Andric SymbolMap = SymbolMapFactory.add(SymbolMap, Sym.first, Proc(Sym.second)); 1507*480093f4SDimitry Andric Changed = true; 1508*480093f4SDimitry Andric } 1509*480093f4SDimitry Andric } 1510*480093f4SDimitry Andric 1511*480093f4SDimitry Andric if (Changed) 1512*480093f4SDimitry Andric State = State->set<IteratorSymbolMap>(SymbolMap); 1513*480093f4SDimitry Andric 1514*480093f4SDimitry Andric return State; 1515*480093f4SDimitry Andric } 1516*480093f4SDimitry Andric 1517*480093f4SDimitry Andric ProgramStateRef invalidateAllIteratorPositions(ProgramStateRef State, 1518*480093f4SDimitry Andric const MemRegion *Cont) { 1519*480093f4SDimitry Andric auto MatchCont = [&](const IteratorPosition &Pos) { 1520*480093f4SDimitry Andric return Pos.getContainer() == Cont; 1521*480093f4SDimitry Andric }; 1522*480093f4SDimitry Andric auto Invalidate = [&](const IteratorPosition &Pos) { 1523*480093f4SDimitry Andric return Pos.invalidate(); 1524*480093f4SDimitry Andric }; 1525*480093f4SDimitry Andric return processIteratorPositions(State, MatchCont, Invalidate); 1526*480093f4SDimitry Andric } 1527*480093f4SDimitry Andric 1528*480093f4SDimitry Andric ProgramStateRef 1529*480093f4SDimitry Andric invalidateAllIteratorPositionsExcept(ProgramStateRef State, 1530*480093f4SDimitry Andric const MemRegion *Cont, SymbolRef Offset, 1531*480093f4SDimitry Andric BinaryOperator::Opcode Opc) { 1532*480093f4SDimitry Andric auto MatchContAndCompare = [&](const IteratorPosition &Pos) { 1533*480093f4SDimitry Andric return Pos.getContainer() == Cont && 1534*480093f4SDimitry Andric !compare(State, Pos.getOffset(), Offset, Opc); 1535*480093f4SDimitry Andric }; 1536*480093f4SDimitry Andric auto Invalidate = [&](const IteratorPosition &Pos) { 1537*480093f4SDimitry Andric return Pos.invalidate(); 1538*480093f4SDimitry Andric }; 1539*480093f4SDimitry Andric return processIteratorPositions(State, MatchContAndCompare, Invalidate); 1540*480093f4SDimitry Andric } 1541*480093f4SDimitry Andric 1542*480093f4SDimitry Andric ProgramStateRef invalidateIteratorPositions(ProgramStateRef State, 1543*480093f4SDimitry Andric SymbolRef Offset, 1544*480093f4SDimitry Andric BinaryOperator::Opcode Opc) { 1545*480093f4SDimitry Andric auto Compare = [&](const IteratorPosition &Pos) { 1546*480093f4SDimitry Andric return compare(State, Pos.getOffset(), Offset, Opc); 1547*480093f4SDimitry Andric }; 1548*480093f4SDimitry Andric auto Invalidate = [&](const IteratorPosition &Pos) { 1549*480093f4SDimitry Andric return Pos.invalidate(); 1550*480093f4SDimitry Andric }; 1551*480093f4SDimitry Andric return processIteratorPositions(State, Compare, Invalidate); 1552*480093f4SDimitry Andric } 1553*480093f4SDimitry Andric 1554*480093f4SDimitry Andric ProgramStateRef invalidateIteratorPositions(ProgramStateRef State, 1555*480093f4SDimitry Andric SymbolRef Offset1, 1556*480093f4SDimitry Andric BinaryOperator::Opcode Opc1, 1557*480093f4SDimitry Andric SymbolRef Offset2, 1558*480093f4SDimitry Andric BinaryOperator::Opcode Opc2) { 1559*480093f4SDimitry Andric auto Compare = [&](const IteratorPosition &Pos) { 1560*480093f4SDimitry Andric return compare(State, Pos.getOffset(), Offset1, Opc1) && 1561*480093f4SDimitry Andric compare(State, Pos.getOffset(), Offset2, Opc2); 1562*480093f4SDimitry Andric }; 1563*480093f4SDimitry Andric auto Invalidate = [&](const IteratorPosition &Pos) { 1564*480093f4SDimitry Andric return Pos.invalidate(); 1565*480093f4SDimitry Andric }; 1566*480093f4SDimitry Andric return processIteratorPositions(State, Compare, Invalidate); 1567*480093f4SDimitry Andric } 1568*480093f4SDimitry Andric 1569*480093f4SDimitry Andric ProgramStateRef reassignAllIteratorPositions(ProgramStateRef State, 1570*480093f4SDimitry Andric const MemRegion *Cont, 1571*480093f4SDimitry Andric const MemRegion *NewCont) { 1572*480093f4SDimitry Andric auto MatchCont = [&](const IteratorPosition &Pos) { 1573*480093f4SDimitry Andric return Pos.getContainer() == Cont; 1574*480093f4SDimitry Andric }; 1575*480093f4SDimitry Andric auto ReAssign = [&](const IteratorPosition &Pos) { 1576*480093f4SDimitry Andric return Pos.reAssign(NewCont); 1577*480093f4SDimitry Andric }; 1578*480093f4SDimitry Andric return processIteratorPositions(State, MatchCont, ReAssign); 1579*480093f4SDimitry Andric } 1580*480093f4SDimitry Andric 1581*480093f4SDimitry Andric ProgramStateRef reassignAllIteratorPositionsUnless(ProgramStateRef State, 1582*480093f4SDimitry Andric const MemRegion *Cont, 1583*480093f4SDimitry Andric const MemRegion *NewCont, 1584*480093f4SDimitry Andric SymbolRef Offset, 1585*480093f4SDimitry Andric BinaryOperator::Opcode Opc) { 1586*480093f4SDimitry Andric auto MatchContAndCompare = [&](const IteratorPosition &Pos) { 1587*480093f4SDimitry Andric return Pos.getContainer() == Cont && 1588*480093f4SDimitry Andric !compare(State, Pos.getOffset(), Offset, Opc); 1589*480093f4SDimitry Andric }; 1590*480093f4SDimitry Andric auto ReAssign = [&](const IteratorPosition &Pos) { 1591*480093f4SDimitry Andric return Pos.reAssign(NewCont); 1592*480093f4SDimitry Andric }; 1593*480093f4SDimitry Andric return processIteratorPositions(State, MatchContAndCompare, ReAssign); 1594*480093f4SDimitry Andric } 1595*480093f4SDimitry Andric 1596*480093f4SDimitry Andric // This function rebases symbolic expression `OldSym + Int` to `NewSym + Int`, 1597*480093f4SDimitry Andric // `OldSym - Int` to `NewSym - Int` and `OldSym` to `NewSym` in any iterator 1598*480093f4SDimitry Andric // position offsets where `CondSym` is true. 1599*480093f4SDimitry Andric ProgramStateRef rebaseSymbolInIteratorPositionsIf( 1600*480093f4SDimitry Andric ProgramStateRef State, SValBuilder &SVB, SymbolRef OldSym, 1601*480093f4SDimitry Andric SymbolRef NewSym, SymbolRef CondSym, BinaryOperator::Opcode Opc) { 1602*480093f4SDimitry Andric auto LessThanEnd = [&](const IteratorPosition &Pos) { 1603*480093f4SDimitry Andric return compare(State, Pos.getOffset(), CondSym, Opc); 1604*480093f4SDimitry Andric }; 1605*480093f4SDimitry Andric auto RebaseSymbol = [&](const IteratorPosition &Pos) { 1606*480093f4SDimitry Andric return Pos.setTo(rebaseSymbol(State, SVB, Pos.getOffset(), OldSym, 1607*480093f4SDimitry Andric NewSym)); 1608*480093f4SDimitry Andric }; 1609*480093f4SDimitry Andric return processIteratorPositions(State, LessThanEnd, RebaseSymbol); 1610*480093f4SDimitry Andric } 1611*480093f4SDimitry Andric 1612*480093f4SDimitry Andric // This function rebases symbolic expression `OldExpr + Int` to `NewExpr + Int`, 1613*480093f4SDimitry Andric // `OldExpr - Int` to `NewExpr - Int` and `OldExpr` to `NewExpr` in expression 1614*480093f4SDimitry Andric // `OrigExpr`. 1615*480093f4SDimitry Andric SymbolRef rebaseSymbol(ProgramStateRef State, SValBuilder &SVB, 1616*480093f4SDimitry Andric SymbolRef OrigExpr, SymbolRef OldExpr, 1617*480093f4SDimitry Andric SymbolRef NewSym) { 1618*480093f4SDimitry Andric auto &SymMgr = SVB.getSymbolManager(); 1619*480093f4SDimitry Andric auto Diff = SVB.evalBinOpNN(State, BO_Sub, nonloc::SymbolVal(OrigExpr), 1620*480093f4SDimitry Andric nonloc::SymbolVal(OldExpr), 1621*480093f4SDimitry Andric SymMgr.getType(OrigExpr)); 1622*480093f4SDimitry Andric 1623*480093f4SDimitry Andric const auto DiffInt = Diff.getAs<nonloc::ConcreteInt>(); 1624*480093f4SDimitry Andric if (!DiffInt) 1625*480093f4SDimitry Andric return OrigExpr; 1626*480093f4SDimitry Andric 1627*480093f4SDimitry Andric return SVB.evalBinOpNN(State, BO_Add, *DiffInt, nonloc::SymbolVal(NewSym), 1628*480093f4SDimitry Andric SymMgr.getType(OrigExpr)).getAsSymbol(); 1629*480093f4SDimitry Andric } 1630*480093f4SDimitry Andric 1631*480093f4SDimitry Andric } // namespace 1632*480093f4SDimitry Andric 1633*480093f4SDimitry Andric void ento::registerIteratorModeling(CheckerManager &mgr) { 1634*480093f4SDimitry Andric mgr.registerChecker<IteratorModeling>(); 1635*480093f4SDimitry Andric } 1636*480093f4SDimitry Andric 1637*480093f4SDimitry Andric bool ento::shouldRegisterIteratorModeling(const LangOptions &LO) { 1638*480093f4SDimitry Andric return true; 1639*480093f4SDimitry Andric } 1640