15ffd83dbSDimitry Andric //===-- ContainerModeling.cpp -------------------------------------*- C++ -*--// 25ffd83dbSDimitry Andric // 35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65ffd83dbSDimitry Andric // 75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 85ffd83dbSDimitry Andric // 95ffd83dbSDimitry Andric // Defines a modeling-checker for modeling STL container-like containers. 105ffd83dbSDimitry Andric // 115ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 125ffd83dbSDimitry Andric 135ffd83dbSDimitry Andric #include "clang/AST/DeclTemplate.h" 145ffd83dbSDimitry Andric #include "clang/Driver/DriverDiagnostic.h" 15349cc55cSDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 165ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 175ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h" 18349cc55cSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" 195ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 205ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 215ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h" 225ffd83dbSDimitry Andric 235ffd83dbSDimitry Andric #include "Iterator.h" 245ffd83dbSDimitry Andric 255ffd83dbSDimitry Andric #include <utility> 265ffd83dbSDimitry Andric 275ffd83dbSDimitry Andric using namespace clang; 285ffd83dbSDimitry Andric using namespace ento; 295ffd83dbSDimitry Andric using namespace iterator; 305ffd83dbSDimitry Andric 315ffd83dbSDimitry Andric namespace { 325ffd83dbSDimitry Andric 335ffd83dbSDimitry Andric class ContainerModeling 345ffd83dbSDimitry Andric : public Checker<check::PostCall, check::LiveSymbols, check::DeadSymbols> { 355ffd83dbSDimitry Andric 365ffd83dbSDimitry Andric void handleBegin(CheckerContext &C, const Expr *CE, SVal RetVal, 375ffd83dbSDimitry Andric SVal Cont) const; 385ffd83dbSDimitry Andric void handleEnd(CheckerContext &C, const Expr *CE, SVal RetVal, 395ffd83dbSDimitry Andric SVal Cont) const; 405ffd83dbSDimitry Andric void handleAssignment(CheckerContext &C, SVal Cont, const Expr *CE = nullptr, 415ffd83dbSDimitry Andric SVal OldCont = UndefinedVal()) const; 425ffd83dbSDimitry Andric void handleAssign(CheckerContext &C, SVal Cont, const Expr *ContE) const; 435ffd83dbSDimitry Andric void handleClear(CheckerContext &C, SVal Cont, const Expr *ContE) const; 445ffd83dbSDimitry Andric void handlePushBack(CheckerContext &C, SVal Cont, const Expr *ContE) const; 455ffd83dbSDimitry Andric void handlePopBack(CheckerContext &C, SVal Cont, const Expr *ContE) const; 465ffd83dbSDimitry Andric void handlePushFront(CheckerContext &C, SVal Cont, const Expr *ContE) const; 475ffd83dbSDimitry Andric void handlePopFront(CheckerContext &C, SVal Cont, const Expr *ContE) const; 485ffd83dbSDimitry Andric void handleInsert(CheckerContext &C, SVal Cont, SVal Iter) const; 495ffd83dbSDimitry Andric void handleErase(CheckerContext &C, SVal Cont, SVal Iter) const; 505ffd83dbSDimitry Andric void handleErase(CheckerContext &C, SVal Cont, SVal Iter1, SVal Iter2) const; 515ffd83dbSDimitry Andric void handleEraseAfter(CheckerContext &C, SVal Cont, SVal Iter) const; 525ffd83dbSDimitry Andric void handleEraseAfter(CheckerContext &C, SVal Cont, SVal Iter1, 535ffd83dbSDimitry Andric SVal Iter2) const; 545ffd83dbSDimitry Andric const NoteTag *getChangeTag(CheckerContext &C, StringRef Text, 555ffd83dbSDimitry Andric const MemRegion *ContReg, 565ffd83dbSDimitry Andric const Expr *ContE) const; 575ffd83dbSDimitry Andric void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, 585ffd83dbSDimitry Andric const char *Sep) const override; 595ffd83dbSDimitry Andric 605ffd83dbSDimitry Andric public: 615ffd83dbSDimitry Andric ContainerModeling() = default; 625ffd83dbSDimitry Andric 635ffd83dbSDimitry Andric void checkPostCall(const CallEvent &Call, CheckerContext &C) const; 645ffd83dbSDimitry Andric void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const; 655ffd83dbSDimitry Andric void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const; 665ffd83dbSDimitry Andric 675ffd83dbSDimitry Andric using NoItParamFn = void (ContainerModeling::*)(CheckerContext &, SVal, 685ffd83dbSDimitry Andric const Expr *) const; 695ffd83dbSDimitry Andric using OneItParamFn = void (ContainerModeling::*)(CheckerContext &, SVal, 705ffd83dbSDimitry Andric SVal) const; 715ffd83dbSDimitry Andric using TwoItParamFn = void (ContainerModeling::*)(CheckerContext &, SVal, SVal, 725ffd83dbSDimitry Andric SVal) const; 735ffd83dbSDimitry Andric 745ffd83dbSDimitry Andric CallDescriptionMap<NoItParamFn> NoIterParamFunctions = { 75*bdd1243dSDimitry Andric {{{"clear"}, 0}, &ContainerModeling::handleClear}, 76*bdd1243dSDimitry Andric {{{"assign"}, 2}, &ContainerModeling::handleAssign}, 77*bdd1243dSDimitry Andric {{{"push_back"}, 1}, &ContainerModeling::handlePushBack}, 78*bdd1243dSDimitry Andric {{{"emplace_back"}, 1}, &ContainerModeling::handlePushBack}, 79*bdd1243dSDimitry Andric {{{"pop_back"}, 0}, &ContainerModeling::handlePopBack}, 80*bdd1243dSDimitry Andric {{{"push_front"}, 1}, &ContainerModeling::handlePushFront}, 81*bdd1243dSDimitry Andric {{{"emplace_front"}, 1}, &ContainerModeling::handlePushFront}, 82*bdd1243dSDimitry Andric {{{"pop_front"}, 0}, &ContainerModeling::handlePopFront}, 835ffd83dbSDimitry Andric }; 845ffd83dbSDimitry Andric 855ffd83dbSDimitry Andric CallDescriptionMap<OneItParamFn> OneIterParamFunctions = { 86*bdd1243dSDimitry Andric {{{"insert"}, 2}, &ContainerModeling::handleInsert}, 87*bdd1243dSDimitry Andric {{{"emplace"}, 2}, &ContainerModeling::handleInsert}, 88*bdd1243dSDimitry Andric {{{"erase"}, 1}, &ContainerModeling::handleErase}, 89*bdd1243dSDimitry Andric {{{"erase_after"}, 1}, &ContainerModeling::handleEraseAfter}, 905ffd83dbSDimitry Andric }; 915ffd83dbSDimitry Andric 925ffd83dbSDimitry Andric CallDescriptionMap<TwoItParamFn> TwoIterParamFunctions = { 93*bdd1243dSDimitry Andric {{{"erase"}, 2}, &ContainerModeling::handleErase}, 94*bdd1243dSDimitry Andric {{{"erase_after"}, 2}, &ContainerModeling::handleEraseAfter}, 955ffd83dbSDimitry Andric }; 965ffd83dbSDimitry Andric }; 975ffd83dbSDimitry Andric 985ffd83dbSDimitry Andric bool isBeginCall(const FunctionDecl *Func); 995ffd83dbSDimitry Andric bool isEndCall(const FunctionDecl *Func); 1005ffd83dbSDimitry Andric bool hasSubscriptOperator(ProgramStateRef State, const MemRegion *Reg); 1015ffd83dbSDimitry Andric bool frontModifiable(ProgramStateRef State, const MemRegion *Reg); 1025ffd83dbSDimitry Andric bool backModifiable(ProgramStateRef State, const MemRegion *Reg); 1035ffd83dbSDimitry Andric SymbolRef getContainerBegin(ProgramStateRef State, const MemRegion *Cont); 1045ffd83dbSDimitry Andric SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont); 1055ffd83dbSDimitry Andric ProgramStateRef createContainerBegin(ProgramStateRef State, 1065ffd83dbSDimitry Andric const MemRegion *Cont, const Expr *E, 1075ffd83dbSDimitry Andric QualType T, const LocationContext *LCtx, 1085ffd83dbSDimitry Andric unsigned BlockCount); 1095ffd83dbSDimitry Andric ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont, 1105ffd83dbSDimitry Andric const Expr *E, QualType T, 1115ffd83dbSDimitry Andric const LocationContext *LCtx, 1125ffd83dbSDimitry Andric unsigned BlockCount); 1135ffd83dbSDimitry Andric ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont, 1145ffd83dbSDimitry Andric const ContainerData &CData); 1155ffd83dbSDimitry Andric ProgramStateRef invalidateAllIteratorPositions(ProgramStateRef State, 1165ffd83dbSDimitry Andric const MemRegion *Cont); 1175ffd83dbSDimitry Andric ProgramStateRef 1185ffd83dbSDimitry Andric invalidateAllIteratorPositionsExcept(ProgramStateRef State, 1195ffd83dbSDimitry Andric const MemRegion *Cont, SymbolRef Offset, 1205ffd83dbSDimitry Andric BinaryOperator::Opcode Opc); 1215ffd83dbSDimitry Andric ProgramStateRef invalidateIteratorPositions(ProgramStateRef State, 1225ffd83dbSDimitry Andric SymbolRef Offset, 1235ffd83dbSDimitry Andric BinaryOperator::Opcode Opc); 1245ffd83dbSDimitry Andric ProgramStateRef invalidateIteratorPositions(ProgramStateRef State, 1255ffd83dbSDimitry Andric SymbolRef Offset1, 1265ffd83dbSDimitry Andric BinaryOperator::Opcode Opc1, 1275ffd83dbSDimitry Andric SymbolRef Offset2, 1285ffd83dbSDimitry Andric BinaryOperator::Opcode Opc2); 1295ffd83dbSDimitry Andric ProgramStateRef reassignAllIteratorPositions(ProgramStateRef State, 1305ffd83dbSDimitry Andric const MemRegion *Cont, 1315ffd83dbSDimitry Andric const MemRegion *NewCont); 1325ffd83dbSDimitry Andric ProgramStateRef reassignAllIteratorPositionsUnless(ProgramStateRef State, 1335ffd83dbSDimitry Andric const MemRegion *Cont, 1345ffd83dbSDimitry Andric const MemRegion *NewCont, 1355ffd83dbSDimitry Andric SymbolRef Offset, 1365ffd83dbSDimitry Andric BinaryOperator::Opcode Opc); 1375ffd83dbSDimitry Andric ProgramStateRef rebaseSymbolInIteratorPositionsIf( 1385ffd83dbSDimitry Andric ProgramStateRef State, SValBuilder &SVB, SymbolRef OldSym, 1395ffd83dbSDimitry Andric SymbolRef NewSym, SymbolRef CondSym, BinaryOperator::Opcode Opc); 1405ffd83dbSDimitry Andric SymbolRef rebaseSymbol(ProgramStateRef State, SValBuilder &SVB, SymbolRef Expr, 1415ffd83dbSDimitry Andric SymbolRef OldSym, SymbolRef NewSym); 1425ffd83dbSDimitry Andric bool hasLiveIterators(ProgramStateRef State, const MemRegion *Cont); 1435ffd83dbSDimitry Andric 1445ffd83dbSDimitry Andric } // namespace 1455ffd83dbSDimitry Andric 1465ffd83dbSDimitry Andric void ContainerModeling::checkPostCall(const CallEvent &Call, 1475ffd83dbSDimitry Andric CheckerContext &C) const { 1485ffd83dbSDimitry Andric const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); 1495ffd83dbSDimitry Andric if (!Func) 1505ffd83dbSDimitry Andric return; 1515ffd83dbSDimitry Andric 1525ffd83dbSDimitry Andric if (Func->isOverloadedOperator()) { 1535ffd83dbSDimitry Andric const auto Op = Func->getOverloadedOperator(); 1545ffd83dbSDimitry Andric if (Op == OO_Equal) { 1555ffd83dbSDimitry Andric // Overloaded 'operator=' must be a non-static member function. 1565ffd83dbSDimitry Andric const auto *InstCall = cast<CXXInstanceCall>(&Call); 1575ffd83dbSDimitry Andric if (cast<CXXMethodDecl>(Func)->isMoveAssignmentOperator()) { 1585ffd83dbSDimitry Andric handleAssignment(C, InstCall->getCXXThisVal(), Call.getOriginExpr(), 1595ffd83dbSDimitry Andric Call.getArgSVal(0)); 1605ffd83dbSDimitry Andric return; 1615ffd83dbSDimitry Andric } 1625ffd83dbSDimitry Andric 1635ffd83dbSDimitry Andric handleAssignment(C, InstCall->getCXXThisVal()); 1645ffd83dbSDimitry Andric return; 1655ffd83dbSDimitry Andric } 1665ffd83dbSDimitry Andric } else { 1675ffd83dbSDimitry Andric if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { 1685ffd83dbSDimitry Andric const NoItParamFn *Handler0 = NoIterParamFunctions.lookup(Call); 1695ffd83dbSDimitry Andric if (Handler0) { 1705ffd83dbSDimitry Andric (this->**Handler0)(C, InstCall->getCXXThisVal(), 1715ffd83dbSDimitry Andric InstCall->getCXXThisExpr()); 1725ffd83dbSDimitry Andric return; 1735ffd83dbSDimitry Andric } 1745ffd83dbSDimitry Andric 1755ffd83dbSDimitry Andric const OneItParamFn *Handler1 = OneIterParamFunctions.lookup(Call); 1765ffd83dbSDimitry Andric if (Handler1) { 1775ffd83dbSDimitry Andric (this->**Handler1)(C, InstCall->getCXXThisVal(), Call.getArgSVal(0)); 1785ffd83dbSDimitry Andric return; 1795ffd83dbSDimitry Andric } 1805ffd83dbSDimitry Andric 1815ffd83dbSDimitry Andric const TwoItParamFn *Handler2 = TwoIterParamFunctions.lookup(Call); 1825ffd83dbSDimitry Andric if (Handler2) { 1835ffd83dbSDimitry Andric (this->**Handler2)(C, InstCall->getCXXThisVal(), Call.getArgSVal(0), 1845ffd83dbSDimitry Andric Call.getArgSVal(1)); 1855ffd83dbSDimitry Andric return; 1865ffd83dbSDimitry Andric } 1875ffd83dbSDimitry Andric 1885ffd83dbSDimitry Andric const auto *OrigExpr = Call.getOriginExpr(); 1895ffd83dbSDimitry Andric if (!OrigExpr) 1905ffd83dbSDimitry Andric return; 1915ffd83dbSDimitry Andric 1925ffd83dbSDimitry Andric if (isBeginCall(Func)) { 1935ffd83dbSDimitry Andric handleBegin(C, OrigExpr, Call.getReturnValue(), 1945ffd83dbSDimitry Andric InstCall->getCXXThisVal()); 1955ffd83dbSDimitry Andric return; 1965ffd83dbSDimitry Andric } 1975ffd83dbSDimitry Andric 1985ffd83dbSDimitry Andric if (isEndCall(Func)) { 1995ffd83dbSDimitry Andric handleEnd(C, OrigExpr, Call.getReturnValue(), 2005ffd83dbSDimitry Andric InstCall->getCXXThisVal()); 2015ffd83dbSDimitry Andric return; 2025ffd83dbSDimitry Andric } 2035ffd83dbSDimitry Andric } 2045ffd83dbSDimitry Andric } 2055ffd83dbSDimitry Andric } 2065ffd83dbSDimitry Andric 2075ffd83dbSDimitry Andric void ContainerModeling::checkLiveSymbols(ProgramStateRef State, 2085ffd83dbSDimitry Andric SymbolReaper &SR) const { 2095ffd83dbSDimitry Andric // Keep symbolic expressions of container begins and ends alive 2105ffd83dbSDimitry Andric auto ContMap = State->get<ContainerMap>(); 2115ffd83dbSDimitry Andric for (const auto &Cont : ContMap) { 2125ffd83dbSDimitry Andric const auto CData = Cont.second; 2135ffd83dbSDimitry Andric if (CData.getBegin()) { 2145ffd83dbSDimitry Andric SR.markLive(CData.getBegin()); 2155ffd83dbSDimitry Andric if(const auto *SIE = dyn_cast<SymIntExpr>(CData.getBegin())) 2165ffd83dbSDimitry Andric SR.markLive(SIE->getLHS()); 2175ffd83dbSDimitry Andric } 2185ffd83dbSDimitry Andric if (CData.getEnd()) { 2195ffd83dbSDimitry Andric SR.markLive(CData.getEnd()); 2205ffd83dbSDimitry Andric if(const auto *SIE = dyn_cast<SymIntExpr>(CData.getEnd())) 2215ffd83dbSDimitry Andric SR.markLive(SIE->getLHS()); 2225ffd83dbSDimitry Andric } 2235ffd83dbSDimitry Andric } 2245ffd83dbSDimitry Andric } 2255ffd83dbSDimitry Andric 2265ffd83dbSDimitry Andric void ContainerModeling::checkDeadSymbols(SymbolReaper &SR, 2275ffd83dbSDimitry Andric CheckerContext &C) const { 2285ffd83dbSDimitry Andric // Cleanup 2295ffd83dbSDimitry Andric auto State = C.getState(); 2305ffd83dbSDimitry Andric 2315ffd83dbSDimitry Andric auto ContMap = State->get<ContainerMap>(); 2325ffd83dbSDimitry Andric for (const auto &Cont : ContMap) { 2335ffd83dbSDimitry Andric if (!SR.isLiveRegion(Cont.first)) { 2345ffd83dbSDimitry Andric // We must keep the container data while it has live iterators to be able 2355ffd83dbSDimitry Andric // to compare them to the begin and the end of the container. 2365ffd83dbSDimitry Andric if (!hasLiveIterators(State, Cont.first)) { 2375ffd83dbSDimitry Andric State = State->remove<ContainerMap>(Cont.first); 2385ffd83dbSDimitry Andric } 2395ffd83dbSDimitry Andric } 2405ffd83dbSDimitry Andric } 2415ffd83dbSDimitry Andric 2425ffd83dbSDimitry Andric C.addTransition(State); 2435ffd83dbSDimitry Andric } 2445ffd83dbSDimitry Andric 2455ffd83dbSDimitry Andric void ContainerModeling::handleBegin(CheckerContext &C, const Expr *CE, 2465ffd83dbSDimitry Andric SVal RetVal, SVal Cont) const { 2475ffd83dbSDimitry Andric const auto *ContReg = Cont.getAsRegion(); 2485ffd83dbSDimitry Andric if (!ContReg) 2495ffd83dbSDimitry Andric return; 2505ffd83dbSDimitry Andric 2515ffd83dbSDimitry Andric ContReg = ContReg->getMostDerivedObjectRegion(); 2525ffd83dbSDimitry Andric 2535ffd83dbSDimitry Andric // If the container already has a begin symbol then use it. Otherwise first 2545ffd83dbSDimitry Andric // create a new one. 2555ffd83dbSDimitry Andric auto State = C.getState(); 2565ffd83dbSDimitry Andric auto BeginSym = getContainerBegin(State, ContReg); 2575ffd83dbSDimitry Andric if (!BeginSym) { 2585ffd83dbSDimitry Andric State = createContainerBegin(State, ContReg, CE, C.getASTContext().LongTy, 2595ffd83dbSDimitry Andric C.getLocationContext(), C.blockCount()); 2605ffd83dbSDimitry Andric BeginSym = getContainerBegin(State, ContReg); 2615ffd83dbSDimitry Andric } 2625ffd83dbSDimitry Andric State = setIteratorPosition(State, RetVal, 2635ffd83dbSDimitry Andric IteratorPosition::getPosition(ContReg, BeginSym)); 2645ffd83dbSDimitry Andric C.addTransition(State); 2655ffd83dbSDimitry Andric } 2665ffd83dbSDimitry Andric 2675ffd83dbSDimitry Andric void ContainerModeling::handleEnd(CheckerContext &C, const Expr *CE, 2685ffd83dbSDimitry Andric SVal RetVal, SVal Cont) const { 2695ffd83dbSDimitry Andric const auto *ContReg = Cont.getAsRegion(); 2705ffd83dbSDimitry Andric if (!ContReg) 2715ffd83dbSDimitry Andric return; 2725ffd83dbSDimitry Andric 2735ffd83dbSDimitry Andric ContReg = ContReg->getMostDerivedObjectRegion(); 2745ffd83dbSDimitry Andric 2755ffd83dbSDimitry Andric // If the container already has an end symbol then use it. Otherwise first 2765ffd83dbSDimitry Andric // create a new one. 2775ffd83dbSDimitry Andric auto State = C.getState(); 2785ffd83dbSDimitry Andric auto EndSym = getContainerEnd(State, ContReg); 2795ffd83dbSDimitry Andric if (!EndSym) { 2805ffd83dbSDimitry Andric State = createContainerEnd(State, ContReg, CE, C.getASTContext().LongTy, 2815ffd83dbSDimitry Andric C.getLocationContext(), C.blockCount()); 2825ffd83dbSDimitry Andric EndSym = getContainerEnd(State, ContReg); 2835ffd83dbSDimitry Andric } 2845ffd83dbSDimitry Andric State = setIteratorPosition(State, RetVal, 2855ffd83dbSDimitry Andric IteratorPosition::getPosition(ContReg, EndSym)); 2865ffd83dbSDimitry Andric C.addTransition(State); 2875ffd83dbSDimitry Andric } 2885ffd83dbSDimitry Andric 2895ffd83dbSDimitry Andric void ContainerModeling::handleAssignment(CheckerContext &C, SVal Cont, 2905ffd83dbSDimitry Andric const Expr *CE, SVal OldCont) const { 2915ffd83dbSDimitry Andric const auto *ContReg = Cont.getAsRegion(); 2925ffd83dbSDimitry Andric if (!ContReg) 2935ffd83dbSDimitry Andric return; 2945ffd83dbSDimitry Andric 2955ffd83dbSDimitry Andric ContReg = ContReg->getMostDerivedObjectRegion(); 2965ffd83dbSDimitry Andric 2975ffd83dbSDimitry Andric // Assignment of a new value to a container always invalidates all its 2985ffd83dbSDimitry Andric // iterators 2995ffd83dbSDimitry Andric auto State = C.getState(); 3005ffd83dbSDimitry Andric const auto CData = getContainerData(State, ContReg); 3015ffd83dbSDimitry Andric if (CData) { 3025ffd83dbSDimitry Andric State = invalidateAllIteratorPositions(State, ContReg); 3035ffd83dbSDimitry Andric } 3045ffd83dbSDimitry Andric 3055ffd83dbSDimitry Andric // In case of move, iterators of the old container (except the past-end 3065ffd83dbSDimitry Andric // iterators) remain valid but refer to the new container 3075ffd83dbSDimitry Andric if (!OldCont.isUndef()) { 3085ffd83dbSDimitry Andric const auto *OldContReg = OldCont.getAsRegion(); 3095ffd83dbSDimitry Andric if (OldContReg) { 3105ffd83dbSDimitry Andric OldContReg = OldContReg->getMostDerivedObjectRegion(); 3115ffd83dbSDimitry Andric const auto OldCData = getContainerData(State, OldContReg); 3125ffd83dbSDimitry Andric if (OldCData) { 3135ffd83dbSDimitry Andric if (const auto OldEndSym = OldCData->getEnd()) { 3145ffd83dbSDimitry Andric // If we already assigned an "end" symbol to the old container, then 3155ffd83dbSDimitry Andric // first reassign all iterator positions to the new container which 3165ffd83dbSDimitry Andric // are not past the container (thus not greater or equal to the 3175ffd83dbSDimitry Andric // current "end" symbol). 3185ffd83dbSDimitry Andric State = reassignAllIteratorPositionsUnless(State, OldContReg, ContReg, 3195ffd83dbSDimitry Andric OldEndSym, BO_GE); 3205ffd83dbSDimitry Andric auto &SymMgr = C.getSymbolManager(); 3215ffd83dbSDimitry Andric auto &SVB = C.getSValBuilder(); 3225ffd83dbSDimitry Andric // Then generate and assign a new "end" symbol for the new container. 3235ffd83dbSDimitry Andric auto NewEndSym = 3245ffd83dbSDimitry Andric SymMgr.conjureSymbol(CE, C.getLocationContext(), 3255ffd83dbSDimitry Andric C.getASTContext().LongTy, C.blockCount()); 3265ffd83dbSDimitry Andric State = assumeNoOverflow(State, NewEndSym, 4); 3275ffd83dbSDimitry Andric if (CData) { 3285ffd83dbSDimitry Andric State = setContainerData(State, ContReg, CData->newEnd(NewEndSym)); 3295ffd83dbSDimitry Andric } else { 3305ffd83dbSDimitry Andric State = setContainerData(State, ContReg, 3315ffd83dbSDimitry Andric ContainerData::fromEnd(NewEndSym)); 3325ffd83dbSDimitry Andric } 3335ffd83dbSDimitry Andric // Finally, replace the old "end" symbol in the already reassigned 3345ffd83dbSDimitry Andric // iterator positions with the new "end" symbol. 3355ffd83dbSDimitry Andric State = rebaseSymbolInIteratorPositionsIf( 3365ffd83dbSDimitry Andric State, SVB, OldEndSym, NewEndSym, OldEndSym, BO_LT); 3375ffd83dbSDimitry Andric } else { 3385ffd83dbSDimitry Andric // There was no "end" symbol assigned yet to the old container, 3395ffd83dbSDimitry Andric // so reassign all iterator positions to the new container. 3405ffd83dbSDimitry Andric State = reassignAllIteratorPositions(State, OldContReg, ContReg); 3415ffd83dbSDimitry Andric } 3425ffd83dbSDimitry Andric if (const auto OldBeginSym = OldCData->getBegin()) { 3435ffd83dbSDimitry Andric // If we already assigned a "begin" symbol to the old container, then 3445ffd83dbSDimitry Andric // assign it to the new container and remove it from the old one. 3455ffd83dbSDimitry Andric if (CData) { 3465ffd83dbSDimitry Andric State = 3475ffd83dbSDimitry Andric setContainerData(State, ContReg, CData->newBegin(OldBeginSym)); 3485ffd83dbSDimitry Andric } else { 3495ffd83dbSDimitry Andric State = setContainerData(State, ContReg, 3505ffd83dbSDimitry Andric ContainerData::fromBegin(OldBeginSym)); 3515ffd83dbSDimitry Andric } 3525ffd83dbSDimitry Andric State = 3535ffd83dbSDimitry Andric setContainerData(State, OldContReg, OldCData->newBegin(nullptr)); 3545ffd83dbSDimitry Andric } 3555ffd83dbSDimitry Andric } else { 3565ffd83dbSDimitry Andric // There was neither "begin" nor "end" symbol assigned yet to the old 3575ffd83dbSDimitry Andric // container, so reassign all iterator positions to the new container. 3585ffd83dbSDimitry Andric State = reassignAllIteratorPositions(State, OldContReg, ContReg); 3595ffd83dbSDimitry Andric } 3605ffd83dbSDimitry Andric } 3615ffd83dbSDimitry Andric } 3625ffd83dbSDimitry Andric C.addTransition(State); 3635ffd83dbSDimitry Andric } 3645ffd83dbSDimitry Andric 3655ffd83dbSDimitry Andric void ContainerModeling::handleAssign(CheckerContext &C, SVal Cont, 3665ffd83dbSDimitry Andric const Expr *ContE) const { 3675ffd83dbSDimitry Andric const auto *ContReg = Cont.getAsRegion(); 3685ffd83dbSDimitry Andric if (!ContReg) 3695ffd83dbSDimitry Andric return; 3705ffd83dbSDimitry Andric 3715ffd83dbSDimitry Andric ContReg = ContReg->getMostDerivedObjectRegion(); 3725ffd83dbSDimitry Andric 3735ffd83dbSDimitry Andric // The assign() operation invalidates all the iterators 3745ffd83dbSDimitry Andric auto State = C.getState(); 3755ffd83dbSDimitry Andric State = invalidateAllIteratorPositions(State, ContReg); 3765ffd83dbSDimitry Andric C.addTransition(State); 3775ffd83dbSDimitry Andric } 3785ffd83dbSDimitry Andric 3795ffd83dbSDimitry Andric void ContainerModeling::handleClear(CheckerContext &C, SVal Cont, 3805ffd83dbSDimitry Andric const Expr *ContE) const { 3815ffd83dbSDimitry Andric const auto *ContReg = Cont.getAsRegion(); 3825ffd83dbSDimitry Andric if (!ContReg) 3835ffd83dbSDimitry Andric return; 3845ffd83dbSDimitry Andric 3855ffd83dbSDimitry Andric ContReg = ContReg->getMostDerivedObjectRegion(); 3865ffd83dbSDimitry Andric 3875ffd83dbSDimitry Andric // The clear() operation invalidates all the iterators, except the past-end 3885ffd83dbSDimitry Andric // iterators of list-like containers 3895ffd83dbSDimitry Andric auto State = C.getState(); 3905ffd83dbSDimitry Andric if (!hasSubscriptOperator(State, ContReg) || 3915ffd83dbSDimitry Andric !backModifiable(State, ContReg)) { 3925ffd83dbSDimitry Andric const auto CData = getContainerData(State, ContReg); 3935ffd83dbSDimitry Andric if (CData) { 3945ffd83dbSDimitry Andric if (const auto EndSym = CData->getEnd()) { 3955ffd83dbSDimitry Andric State = 3965ffd83dbSDimitry Andric invalidateAllIteratorPositionsExcept(State, ContReg, EndSym, BO_GE); 3975ffd83dbSDimitry Andric C.addTransition(State); 3985ffd83dbSDimitry Andric return; 3995ffd83dbSDimitry Andric } 4005ffd83dbSDimitry Andric } 4015ffd83dbSDimitry Andric } 4025ffd83dbSDimitry Andric const NoteTag *ChangeTag = 4035ffd83dbSDimitry Andric getChangeTag(C, "became empty", ContReg, ContE); 4045ffd83dbSDimitry Andric State = invalidateAllIteratorPositions(State, ContReg); 4055ffd83dbSDimitry Andric C.addTransition(State, ChangeTag); 4065ffd83dbSDimitry Andric } 4075ffd83dbSDimitry Andric 4085ffd83dbSDimitry Andric void ContainerModeling::handlePushBack(CheckerContext &C, SVal Cont, 4095ffd83dbSDimitry Andric const Expr *ContE) const { 4105ffd83dbSDimitry Andric const auto *ContReg = Cont.getAsRegion(); 4115ffd83dbSDimitry Andric if (!ContReg) 4125ffd83dbSDimitry Andric return; 4135ffd83dbSDimitry Andric 4145ffd83dbSDimitry Andric ContReg = ContReg->getMostDerivedObjectRegion(); 4155ffd83dbSDimitry Andric 4165ffd83dbSDimitry Andric // For deque-like containers invalidate all iterator positions 4175ffd83dbSDimitry Andric auto State = C.getState(); 4185ffd83dbSDimitry Andric if (hasSubscriptOperator(State, ContReg) && frontModifiable(State, ContReg)) { 4195ffd83dbSDimitry Andric State = invalidateAllIteratorPositions(State, ContReg); 4205ffd83dbSDimitry Andric C.addTransition(State); 4215ffd83dbSDimitry Andric return; 4225ffd83dbSDimitry Andric } 4235ffd83dbSDimitry Andric 4245ffd83dbSDimitry Andric const auto CData = getContainerData(State, ContReg); 4255ffd83dbSDimitry Andric if (!CData) 4265ffd83dbSDimitry Andric return; 4275ffd83dbSDimitry Andric 4285ffd83dbSDimitry Andric // For vector-like containers invalidate the past-end iterator positions 4295ffd83dbSDimitry Andric if (const auto EndSym = CData->getEnd()) { 4305ffd83dbSDimitry Andric if (hasSubscriptOperator(State, ContReg)) { 4315ffd83dbSDimitry Andric State = invalidateIteratorPositions(State, EndSym, BO_GE); 4325ffd83dbSDimitry Andric } 4335ffd83dbSDimitry Andric auto &SymMgr = C.getSymbolManager(); 4345ffd83dbSDimitry Andric auto &BVF = SymMgr.getBasicVals(); 4355ffd83dbSDimitry Andric auto &SVB = C.getSValBuilder(); 4365ffd83dbSDimitry Andric const auto newEndSym = 4375ffd83dbSDimitry Andric SVB.evalBinOp(State, BO_Add, 4385ffd83dbSDimitry Andric nonloc::SymbolVal(EndSym), 4395ffd83dbSDimitry Andric nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))), 4405ffd83dbSDimitry Andric SymMgr.getType(EndSym)).getAsSymbol(); 4415ffd83dbSDimitry Andric const NoteTag *ChangeTag = 4425ffd83dbSDimitry Andric getChangeTag(C, "extended to the back by 1 position", ContReg, ContE); 4435ffd83dbSDimitry Andric State = setContainerData(State, ContReg, CData->newEnd(newEndSym)); 4445ffd83dbSDimitry Andric C.addTransition(State, ChangeTag); 4455ffd83dbSDimitry Andric } 4465ffd83dbSDimitry Andric } 4475ffd83dbSDimitry Andric 4485ffd83dbSDimitry Andric void ContainerModeling::handlePopBack(CheckerContext &C, SVal Cont, 4495ffd83dbSDimitry Andric const Expr *ContE) const { 4505ffd83dbSDimitry Andric const auto *ContReg = Cont.getAsRegion(); 4515ffd83dbSDimitry Andric if (!ContReg) 4525ffd83dbSDimitry Andric return; 4535ffd83dbSDimitry Andric 4545ffd83dbSDimitry Andric ContReg = ContReg->getMostDerivedObjectRegion(); 4555ffd83dbSDimitry Andric 4565ffd83dbSDimitry Andric auto State = C.getState(); 4575ffd83dbSDimitry Andric const auto CData = getContainerData(State, ContReg); 4585ffd83dbSDimitry Andric if (!CData) 4595ffd83dbSDimitry Andric return; 4605ffd83dbSDimitry Andric 4615ffd83dbSDimitry Andric if (const auto EndSym = CData->getEnd()) { 4625ffd83dbSDimitry Andric auto &SymMgr = C.getSymbolManager(); 4635ffd83dbSDimitry Andric auto &BVF = SymMgr.getBasicVals(); 4645ffd83dbSDimitry Andric auto &SVB = C.getSValBuilder(); 4655ffd83dbSDimitry Andric const auto BackSym = 4665ffd83dbSDimitry Andric SVB.evalBinOp(State, BO_Sub, 4675ffd83dbSDimitry Andric nonloc::SymbolVal(EndSym), 4685ffd83dbSDimitry Andric nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))), 4695ffd83dbSDimitry Andric SymMgr.getType(EndSym)).getAsSymbol(); 4705ffd83dbSDimitry Andric const NoteTag *ChangeTag = 4715ffd83dbSDimitry Andric getChangeTag(C, "shrank from the back by 1 position", ContReg, ContE); 4725ffd83dbSDimitry Andric // For vector-like and deque-like containers invalidate the last and the 4735ffd83dbSDimitry Andric // past-end iterator positions. For list-like containers only invalidate 4745ffd83dbSDimitry Andric // the last position 4755ffd83dbSDimitry Andric if (hasSubscriptOperator(State, ContReg) && 4765ffd83dbSDimitry Andric backModifiable(State, ContReg)) { 4775ffd83dbSDimitry Andric State = invalidateIteratorPositions(State, BackSym, BO_GE); 4785ffd83dbSDimitry Andric State = setContainerData(State, ContReg, CData->newEnd(nullptr)); 4795ffd83dbSDimitry Andric } else { 4805ffd83dbSDimitry Andric State = invalidateIteratorPositions(State, BackSym, BO_EQ); 4815ffd83dbSDimitry Andric } 4825ffd83dbSDimitry Andric auto newEndSym = BackSym; 4835ffd83dbSDimitry Andric State = setContainerData(State, ContReg, CData->newEnd(newEndSym)); 4845ffd83dbSDimitry Andric C.addTransition(State, ChangeTag); 4855ffd83dbSDimitry Andric } 4865ffd83dbSDimitry Andric } 4875ffd83dbSDimitry Andric 4885ffd83dbSDimitry Andric void ContainerModeling::handlePushFront(CheckerContext &C, SVal Cont, 4895ffd83dbSDimitry Andric const Expr *ContE) const { 4905ffd83dbSDimitry Andric const auto *ContReg = Cont.getAsRegion(); 4915ffd83dbSDimitry Andric if (!ContReg) 4925ffd83dbSDimitry Andric return; 4935ffd83dbSDimitry Andric 4945ffd83dbSDimitry Andric ContReg = ContReg->getMostDerivedObjectRegion(); 4955ffd83dbSDimitry Andric 4965ffd83dbSDimitry Andric // For deque-like containers invalidate all iterator positions 4975ffd83dbSDimitry Andric auto State = C.getState(); 4985ffd83dbSDimitry Andric if (hasSubscriptOperator(State, ContReg)) { 4995ffd83dbSDimitry Andric State = invalidateAllIteratorPositions(State, ContReg); 5005ffd83dbSDimitry Andric C.addTransition(State); 5015ffd83dbSDimitry Andric } else { 5025ffd83dbSDimitry Andric const auto CData = getContainerData(State, ContReg); 5035ffd83dbSDimitry Andric if (!CData) 5045ffd83dbSDimitry Andric return; 5055ffd83dbSDimitry Andric 5065ffd83dbSDimitry Andric if (const auto BeginSym = CData->getBegin()) { 5075ffd83dbSDimitry Andric auto &SymMgr = C.getSymbolManager(); 5085ffd83dbSDimitry Andric auto &BVF = SymMgr.getBasicVals(); 5095ffd83dbSDimitry Andric auto &SVB = C.getSValBuilder(); 5105ffd83dbSDimitry Andric const auto newBeginSym = 5115ffd83dbSDimitry Andric SVB.evalBinOp(State, BO_Sub, 5125ffd83dbSDimitry Andric nonloc::SymbolVal(BeginSym), 5135ffd83dbSDimitry Andric nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))), 5145ffd83dbSDimitry Andric SymMgr.getType(BeginSym)).getAsSymbol(); 5155ffd83dbSDimitry Andric const NoteTag *ChangeTag = 5165ffd83dbSDimitry Andric getChangeTag(C, "extended to the front by 1 position", ContReg, ContE); 5175ffd83dbSDimitry Andric State = setContainerData(State, ContReg, CData->newBegin(newBeginSym)); 5185ffd83dbSDimitry Andric C.addTransition(State, ChangeTag); 5195ffd83dbSDimitry Andric } 5205ffd83dbSDimitry Andric } 5215ffd83dbSDimitry Andric } 5225ffd83dbSDimitry Andric 5235ffd83dbSDimitry Andric void ContainerModeling::handlePopFront(CheckerContext &C, SVal Cont, 5245ffd83dbSDimitry Andric const Expr *ContE) const { 5255ffd83dbSDimitry Andric const auto *ContReg = Cont.getAsRegion(); 5265ffd83dbSDimitry Andric if (!ContReg) 5275ffd83dbSDimitry Andric return; 5285ffd83dbSDimitry Andric 5295ffd83dbSDimitry Andric ContReg = ContReg->getMostDerivedObjectRegion(); 5305ffd83dbSDimitry Andric 5315ffd83dbSDimitry Andric auto State = C.getState(); 5325ffd83dbSDimitry Andric const auto CData = getContainerData(State, ContReg); 5335ffd83dbSDimitry Andric if (!CData) 5345ffd83dbSDimitry Andric return; 5355ffd83dbSDimitry Andric 5365ffd83dbSDimitry Andric // For deque-like containers invalidate all iterator positions. For list-like 5375ffd83dbSDimitry Andric // iterators only invalidate the first position 5385ffd83dbSDimitry Andric if (const auto BeginSym = CData->getBegin()) { 5395ffd83dbSDimitry Andric if (hasSubscriptOperator(State, ContReg)) { 5405ffd83dbSDimitry Andric State = invalidateIteratorPositions(State, BeginSym, BO_LE); 5415ffd83dbSDimitry Andric } else { 5425ffd83dbSDimitry Andric State = invalidateIteratorPositions(State, BeginSym, BO_EQ); 5435ffd83dbSDimitry Andric } 5445ffd83dbSDimitry Andric auto &SymMgr = C.getSymbolManager(); 5455ffd83dbSDimitry Andric auto &BVF = SymMgr.getBasicVals(); 5465ffd83dbSDimitry Andric auto &SVB = C.getSValBuilder(); 5475ffd83dbSDimitry Andric const auto newBeginSym = 5485ffd83dbSDimitry Andric SVB.evalBinOp(State, BO_Add, 5495ffd83dbSDimitry Andric nonloc::SymbolVal(BeginSym), 5505ffd83dbSDimitry Andric nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))), 5515ffd83dbSDimitry Andric SymMgr.getType(BeginSym)).getAsSymbol(); 5525ffd83dbSDimitry Andric const NoteTag *ChangeTag = 5535ffd83dbSDimitry Andric getChangeTag(C, "shrank from the front by 1 position", ContReg, ContE); 5545ffd83dbSDimitry Andric State = setContainerData(State, ContReg, CData->newBegin(newBeginSym)); 5555ffd83dbSDimitry Andric C.addTransition(State, ChangeTag); 5565ffd83dbSDimitry Andric } 5575ffd83dbSDimitry Andric } 5585ffd83dbSDimitry Andric 5595ffd83dbSDimitry Andric void ContainerModeling::handleInsert(CheckerContext &C, SVal Cont, 5605ffd83dbSDimitry Andric SVal Iter) const { 5615ffd83dbSDimitry Andric const auto *ContReg = Cont.getAsRegion(); 5625ffd83dbSDimitry Andric if (!ContReg) 5635ffd83dbSDimitry Andric return; 5645ffd83dbSDimitry Andric 5655ffd83dbSDimitry Andric ContReg = ContReg->getMostDerivedObjectRegion(); 5665ffd83dbSDimitry Andric 5675ffd83dbSDimitry Andric auto State = C.getState(); 5685ffd83dbSDimitry Andric const auto *Pos = getIteratorPosition(State, Iter); 5695ffd83dbSDimitry Andric if (!Pos) 5705ffd83dbSDimitry Andric return; 5715ffd83dbSDimitry Andric 5725ffd83dbSDimitry Andric // For deque-like containers invalidate all iterator positions. For 5735ffd83dbSDimitry Andric // vector-like containers invalidate iterator positions after the insertion. 5745ffd83dbSDimitry Andric if (hasSubscriptOperator(State, ContReg) && backModifiable(State, ContReg)) { 5755ffd83dbSDimitry Andric if (frontModifiable(State, ContReg)) { 5765ffd83dbSDimitry Andric State = invalidateAllIteratorPositions(State, ContReg); 5775ffd83dbSDimitry Andric } else { 5785ffd83dbSDimitry Andric State = invalidateIteratorPositions(State, Pos->getOffset(), BO_GE); 5795ffd83dbSDimitry Andric } 5805ffd83dbSDimitry Andric if (const auto *CData = getContainerData(State, ContReg)) { 5815ffd83dbSDimitry Andric if (const auto EndSym = CData->getEnd()) { 5825ffd83dbSDimitry Andric State = invalidateIteratorPositions(State, EndSym, BO_GE); 5835ffd83dbSDimitry Andric State = setContainerData(State, ContReg, CData->newEnd(nullptr)); 5845ffd83dbSDimitry Andric } 5855ffd83dbSDimitry Andric } 5865ffd83dbSDimitry Andric C.addTransition(State); 5875ffd83dbSDimitry Andric } 5885ffd83dbSDimitry Andric } 5895ffd83dbSDimitry Andric 5905ffd83dbSDimitry Andric void ContainerModeling::handleErase(CheckerContext &C, SVal Cont, 5915ffd83dbSDimitry Andric SVal Iter) const { 5925ffd83dbSDimitry Andric const auto *ContReg = Cont.getAsRegion(); 5935ffd83dbSDimitry Andric if (!ContReg) 5945ffd83dbSDimitry Andric return; 5955ffd83dbSDimitry Andric 5965ffd83dbSDimitry Andric ContReg = ContReg->getMostDerivedObjectRegion(); 5975ffd83dbSDimitry Andric 5985ffd83dbSDimitry Andric auto State = C.getState(); 5995ffd83dbSDimitry Andric const auto *Pos = getIteratorPosition(State, Iter); 6005ffd83dbSDimitry Andric if (!Pos) 6015ffd83dbSDimitry Andric return; 6025ffd83dbSDimitry Andric 6035ffd83dbSDimitry Andric // For deque-like containers invalidate all iterator positions. For 6045ffd83dbSDimitry Andric // vector-like containers invalidate iterator positions at and after the 6055ffd83dbSDimitry Andric // deletion. For list-like containers only invalidate the deleted position. 6065ffd83dbSDimitry Andric if (hasSubscriptOperator(State, ContReg) && backModifiable(State, ContReg)) { 6075ffd83dbSDimitry Andric if (frontModifiable(State, ContReg)) { 6085ffd83dbSDimitry Andric State = invalidateAllIteratorPositions(State, ContReg); 6095ffd83dbSDimitry Andric } else { 6105ffd83dbSDimitry Andric State = invalidateIteratorPositions(State, Pos->getOffset(), BO_GE); 6115ffd83dbSDimitry Andric } 6125ffd83dbSDimitry Andric if (const auto *CData = getContainerData(State, ContReg)) { 6135ffd83dbSDimitry Andric if (const auto EndSym = CData->getEnd()) { 6145ffd83dbSDimitry Andric State = invalidateIteratorPositions(State, EndSym, BO_GE); 6155ffd83dbSDimitry Andric State = setContainerData(State, ContReg, CData->newEnd(nullptr)); 6165ffd83dbSDimitry Andric } 6175ffd83dbSDimitry Andric } 6185ffd83dbSDimitry Andric } else { 6195ffd83dbSDimitry Andric State = invalidateIteratorPositions(State, Pos->getOffset(), BO_EQ); 6205ffd83dbSDimitry Andric } 6215ffd83dbSDimitry Andric C.addTransition(State); 6225ffd83dbSDimitry Andric } 6235ffd83dbSDimitry Andric 6245ffd83dbSDimitry Andric void ContainerModeling::handleErase(CheckerContext &C, SVal Cont, SVal Iter1, 6255ffd83dbSDimitry Andric SVal Iter2) const { 6265ffd83dbSDimitry Andric const auto *ContReg = Cont.getAsRegion(); 6275ffd83dbSDimitry Andric if (!ContReg) 6285ffd83dbSDimitry Andric return; 6295ffd83dbSDimitry Andric 6305ffd83dbSDimitry Andric ContReg = ContReg->getMostDerivedObjectRegion(); 6315ffd83dbSDimitry Andric auto State = C.getState(); 6325ffd83dbSDimitry Andric const auto *Pos1 = getIteratorPosition(State, Iter1); 6335ffd83dbSDimitry Andric const auto *Pos2 = getIteratorPosition(State, Iter2); 6345ffd83dbSDimitry Andric if (!Pos1 || !Pos2) 6355ffd83dbSDimitry Andric return; 6365ffd83dbSDimitry Andric 6375ffd83dbSDimitry Andric // For deque-like containers invalidate all iterator positions. For 6385ffd83dbSDimitry Andric // vector-like containers invalidate iterator positions at and after the 6395ffd83dbSDimitry Andric // deletion range. For list-like containers only invalidate the deleted 6405ffd83dbSDimitry Andric // position range [first..last]. 6415ffd83dbSDimitry Andric if (hasSubscriptOperator(State, ContReg) && backModifiable(State, ContReg)) { 6425ffd83dbSDimitry Andric if (frontModifiable(State, ContReg)) { 6435ffd83dbSDimitry Andric State = invalidateAllIteratorPositions(State, ContReg); 6445ffd83dbSDimitry Andric } else { 6455ffd83dbSDimitry Andric State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GE); 6465ffd83dbSDimitry Andric } 6475ffd83dbSDimitry Andric if (const auto *CData = getContainerData(State, ContReg)) { 6485ffd83dbSDimitry Andric if (const auto EndSym = CData->getEnd()) { 6495ffd83dbSDimitry Andric State = invalidateIteratorPositions(State, EndSym, BO_GE); 6505ffd83dbSDimitry Andric State = setContainerData(State, ContReg, CData->newEnd(nullptr)); 6515ffd83dbSDimitry Andric } 6525ffd83dbSDimitry Andric } 6535ffd83dbSDimitry Andric } else { 6545ffd83dbSDimitry Andric State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GE, 6555ffd83dbSDimitry Andric Pos2->getOffset(), BO_LT); 6565ffd83dbSDimitry Andric } 6575ffd83dbSDimitry Andric C.addTransition(State); 6585ffd83dbSDimitry Andric } 6595ffd83dbSDimitry Andric 6605ffd83dbSDimitry Andric void ContainerModeling::handleEraseAfter(CheckerContext &C, SVal Cont, 6615ffd83dbSDimitry Andric SVal Iter) const { 6625ffd83dbSDimitry Andric auto State = C.getState(); 6635ffd83dbSDimitry Andric const auto *Pos = getIteratorPosition(State, Iter); 6645ffd83dbSDimitry Andric if (!Pos) 6655ffd83dbSDimitry Andric return; 6665ffd83dbSDimitry Andric 6675ffd83dbSDimitry Andric // Invalidate the deleted iterator position, which is the position of the 6685ffd83dbSDimitry Andric // parameter plus one. 6695ffd83dbSDimitry Andric auto &SymMgr = C.getSymbolManager(); 6705ffd83dbSDimitry Andric auto &BVF = SymMgr.getBasicVals(); 6715ffd83dbSDimitry Andric auto &SVB = C.getSValBuilder(); 6725ffd83dbSDimitry Andric const auto NextSym = 6735ffd83dbSDimitry Andric SVB.evalBinOp(State, BO_Add, 6745ffd83dbSDimitry Andric nonloc::SymbolVal(Pos->getOffset()), 6755ffd83dbSDimitry Andric nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))), 6765ffd83dbSDimitry Andric SymMgr.getType(Pos->getOffset())).getAsSymbol(); 6775ffd83dbSDimitry Andric State = invalidateIteratorPositions(State, NextSym, BO_EQ); 6785ffd83dbSDimitry Andric C.addTransition(State); 6795ffd83dbSDimitry Andric } 6805ffd83dbSDimitry Andric 6815ffd83dbSDimitry Andric void ContainerModeling::handleEraseAfter(CheckerContext &C, SVal Cont, 6825ffd83dbSDimitry Andric SVal Iter1, SVal Iter2) const { 6835ffd83dbSDimitry Andric auto State = C.getState(); 6845ffd83dbSDimitry Andric const auto *Pos1 = getIteratorPosition(State, Iter1); 6855ffd83dbSDimitry Andric const auto *Pos2 = getIteratorPosition(State, Iter2); 6865ffd83dbSDimitry Andric if (!Pos1 || !Pos2) 6875ffd83dbSDimitry Andric return; 6885ffd83dbSDimitry Andric 6895ffd83dbSDimitry Andric // Invalidate the deleted iterator position range (first..last) 6905ffd83dbSDimitry Andric State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GT, 6915ffd83dbSDimitry Andric Pos2->getOffset(), BO_LT); 6925ffd83dbSDimitry Andric C.addTransition(State); 6935ffd83dbSDimitry Andric } 6945ffd83dbSDimitry Andric 6955ffd83dbSDimitry Andric const NoteTag *ContainerModeling::getChangeTag(CheckerContext &C, 6965ffd83dbSDimitry Andric StringRef Text, 6975ffd83dbSDimitry Andric const MemRegion *ContReg, 6985ffd83dbSDimitry Andric const Expr *ContE) const { 6995ffd83dbSDimitry Andric StringRef Name; 7005ffd83dbSDimitry Andric // First try to get the name of the variable from the region 7015ffd83dbSDimitry Andric if (const auto *DR = dyn_cast<DeclRegion>(ContReg)) { 7025ffd83dbSDimitry Andric Name = DR->getDecl()->getName(); 7035ffd83dbSDimitry Andric // If the region is not a `DeclRegion` then use the expression instead 7045ffd83dbSDimitry Andric } else if (const auto *DRE = 7055ffd83dbSDimitry Andric dyn_cast<DeclRefExpr>(ContE->IgnoreParenCasts())) { 7065ffd83dbSDimitry Andric Name = DRE->getDecl()->getName(); 7075ffd83dbSDimitry Andric } 7085ffd83dbSDimitry Andric 7095ffd83dbSDimitry Andric return C.getNoteTag( 7105ffd83dbSDimitry Andric [Text, Name, ContReg](PathSensitiveBugReport &BR) -> std::string { 7115ffd83dbSDimitry Andric if (!BR.isInteresting(ContReg)) 7125ffd83dbSDimitry Andric return ""; 7135ffd83dbSDimitry Andric 7145ffd83dbSDimitry Andric SmallString<256> Msg; 7155ffd83dbSDimitry Andric llvm::raw_svector_ostream Out(Msg); 7165ffd83dbSDimitry Andric Out << "Container " << (!Name.empty() ? ("'" + Name.str() + "' ") : "" ) 7175ffd83dbSDimitry Andric << Text; 7185ffd83dbSDimitry Andric return std::string(Out.str()); 7195ffd83dbSDimitry Andric }); 7205ffd83dbSDimitry Andric } 7215ffd83dbSDimitry Andric 7225ffd83dbSDimitry Andric void ContainerModeling::printState(raw_ostream &Out, ProgramStateRef State, 7235ffd83dbSDimitry Andric const char *NL, const char *Sep) const { 7245ffd83dbSDimitry Andric auto ContMap = State->get<ContainerMap>(); 7255ffd83dbSDimitry Andric 7265ffd83dbSDimitry Andric if (!ContMap.isEmpty()) { 7275ffd83dbSDimitry Andric Out << Sep << "Container Data :" << NL; 7285ffd83dbSDimitry Andric for (const auto &Cont : ContMap) { 7295ffd83dbSDimitry Andric Cont.first->dumpToStream(Out); 7305ffd83dbSDimitry Andric Out << " : [ "; 7315ffd83dbSDimitry Andric const auto CData = Cont.second; 7325ffd83dbSDimitry Andric if (CData.getBegin()) 7335ffd83dbSDimitry Andric CData.getBegin()->dumpToStream(Out); 7345ffd83dbSDimitry Andric else 7355ffd83dbSDimitry Andric Out << "<Unknown>"; 7365ffd83dbSDimitry Andric Out << " .. "; 7375ffd83dbSDimitry Andric if (CData.getEnd()) 7385ffd83dbSDimitry Andric CData.getEnd()->dumpToStream(Out); 7395ffd83dbSDimitry Andric else 7405ffd83dbSDimitry Andric Out << "<Unknown>"; 7415ffd83dbSDimitry Andric Out << " ]"; 7425ffd83dbSDimitry Andric } 7435ffd83dbSDimitry Andric } 7445ffd83dbSDimitry Andric } 7455ffd83dbSDimitry Andric 7465ffd83dbSDimitry Andric namespace { 7475ffd83dbSDimitry Andric 7485ffd83dbSDimitry Andric bool isBeginCall(const FunctionDecl *Func) { 7495ffd83dbSDimitry Andric const auto *IdInfo = Func->getIdentifier(); 7505ffd83dbSDimitry Andric if (!IdInfo) 7515ffd83dbSDimitry Andric return false; 752fe6060f1SDimitry Andric return IdInfo->getName().endswith_insensitive("begin"); 7535ffd83dbSDimitry Andric } 7545ffd83dbSDimitry Andric 7555ffd83dbSDimitry Andric bool isEndCall(const FunctionDecl *Func) { 7565ffd83dbSDimitry Andric const auto *IdInfo = Func->getIdentifier(); 7575ffd83dbSDimitry Andric if (!IdInfo) 7585ffd83dbSDimitry Andric return false; 759fe6060f1SDimitry Andric return IdInfo->getName().endswith_insensitive("end"); 7605ffd83dbSDimitry Andric } 7615ffd83dbSDimitry Andric 7625ffd83dbSDimitry Andric const CXXRecordDecl *getCXXRecordDecl(ProgramStateRef State, 7635ffd83dbSDimitry Andric const MemRegion *Reg) { 7645ffd83dbSDimitry Andric auto TI = getDynamicTypeInfo(State, Reg); 7655ffd83dbSDimitry Andric if (!TI.isValid()) 7665ffd83dbSDimitry Andric return nullptr; 7675ffd83dbSDimitry Andric 7685ffd83dbSDimitry Andric auto Type = TI.getType(); 7695ffd83dbSDimitry Andric if (const auto *RefT = Type->getAs<ReferenceType>()) { 7705ffd83dbSDimitry Andric Type = RefT->getPointeeType(); 7715ffd83dbSDimitry Andric } 7725ffd83dbSDimitry Andric 7735ffd83dbSDimitry Andric return Type->getUnqualifiedDesugaredType()->getAsCXXRecordDecl(); 7745ffd83dbSDimitry Andric } 7755ffd83dbSDimitry Andric 7765ffd83dbSDimitry Andric bool hasSubscriptOperator(ProgramStateRef State, const MemRegion *Reg) { 7775ffd83dbSDimitry Andric const auto *CRD = getCXXRecordDecl(State, Reg); 7785ffd83dbSDimitry Andric if (!CRD) 7795ffd83dbSDimitry Andric return false; 7805ffd83dbSDimitry Andric 7815ffd83dbSDimitry Andric for (const auto *Method : CRD->methods()) { 7825ffd83dbSDimitry Andric if (!Method->isOverloadedOperator()) 7835ffd83dbSDimitry Andric continue; 7845ffd83dbSDimitry Andric const auto OPK = Method->getOverloadedOperator(); 7855ffd83dbSDimitry Andric if (OPK == OO_Subscript) { 7865ffd83dbSDimitry Andric return true; 7875ffd83dbSDimitry Andric } 7885ffd83dbSDimitry Andric } 7895ffd83dbSDimitry Andric return false; 7905ffd83dbSDimitry Andric } 7915ffd83dbSDimitry Andric 7925ffd83dbSDimitry Andric bool frontModifiable(ProgramStateRef State, const MemRegion *Reg) { 7935ffd83dbSDimitry Andric const auto *CRD = getCXXRecordDecl(State, Reg); 7945ffd83dbSDimitry Andric if (!CRD) 7955ffd83dbSDimitry Andric return false; 7965ffd83dbSDimitry Andric 7975ffd83dbSDimitry Andric for (const auto *Method : CRD->methods()) { 7985ffd83dbSDimitry Andric if (!Method->getDeclName().isIdentifier()) 7995ffd83dbSDimitry Andric continue; 8005ffd83dbSDimitry Andric if (Method->getName() == "push_front" || Method->getName() == "pop_front") { 8015ffd83dbSDimitry Andric return true; 8025ffd83dbSDimitry Andric } 8035ffd83dbSDimitry Andric } 8045ffd83dbSDimitry Andric return false; 8055ffd83dbSDimitry Andric } 8065ffd83dbSDimitry Andric 8075ffd83dbSDimitry Andric bool backModifiable(ProgramStateRef State, const MemRegion *Reg) { 8085ffd83dbSDimitry Andric const auto *CRD = getCXXRecordDecl(State, Reg); 8095ffd83dbSDimitry Andric if (!CRD) 8105ffd83dbSDimitry Andric return false; 8115ffd83dbSDimitry Andric 8125ffd83dbSDimitry Andric for (const auto *Method : CRD->methods()) { 8135ffd83dbSDimitry Andric if (!Method->getDeclName().isIdentifier()) 8145ffd83dbSDimitry Andric continue; 8155ffd83dbSDimitry Andric if (Method->getName() == "push_back" || Method->getName() == "pop_back") { 8165ffd83dbSDimitry Andric return true; 8175ffd83dbSDimitry Andric } 8185ffd83dbSDimitry Andric } 8195ffd83dbSDimitry Andric return false; 8205ffd83dbSDimitry Andric } 8215ffd83dbSDimitry Andric 8225ffd83dbSDimitry Andric SymbolRef getContainerBegin(ProgramStateRef State, const MemRegion *Cont) { 8235ffd83dbSDimitry Andric const auto *CDataPtr = getContainerData(State, Cont); 8245ffd83dbSDimitry Andric if (!CDataPtr) 8255ffd83dbSDimitry Andric return nullptr; 8265ffd83dbSDimitry Andric 8275ffd83dbSDimitry Andric return CDataPtr->getBegin(); 8285ffd83dbSDimitry Andric } 8295ffd83dbSDimitry Andric 8305ffd83dbSDimitry Andric SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont) { 8315ffd83dbSDimitry Andric const auto *CDataPtr = getContainerData(State, Cont); 8325ffd83dbSDimitry Andric if (!CDataPtr) 8335ffd83dbSDimitry Andric return nullptr; 8345ffd83dbSDimitry Andric 8355ffd83dbSDimitry Andric return CDataPtr->getEnd(); 8365ffd83dbSDimitry Andric } 8375ffd83dbSDimitry Andric 8385ffd83dbSDimitry Andric ProgramStateRef createContainerBegin(ProgramStateRef State, 8395ffd83dbSDimitry Andric const MemRegion *Cont, const Expr *E, 8405ffd83dbSDimitry Andric QualType T, const LocationContext *LCtx, 8415ffd83dbSDimitry Andric unsigned BlockCount) { 8425ffd83dbSDimitry Andric // Only create if it does not exist 8435ffd83dbSDimitry Andric const auto *CDataPtr = getContainerData(State, Cont); 8445ffd83dbSDimitry Andric if (CDataPtr && CDataPtr->getBegin()) 8455ffd83dbSDimitry Andric return State; 8465ffd83dbSDimitry Andric 8475ffd83dbSDimitry Andric auto &SymMgr = State->getSymbolManager(); 8485ffd83dbSDimitry Andric const SymbolConjured *Sym = SymMgr.conjureSymbol(E, LCtx, T, BlockCount, 8495ffd83dbSDimitry Andric "begin"); 8505ffd83dbSDimitry Andric State = assumeNoOverflow(State, Sym, 4); 8515ffd83dbSDimitry Andric 8525ffd83dbSDimitry Andric if (CDataPtr) { 8535ffd83dbSDimitry Andric const auto CData = CDataPtr->newBegin(Sym); 8545ffd83dbSDimitry Andric return setContainerData(State, Cont, CData); 8555ffd83dbSDimitry Andric } 8565ffd83dbSDimitry Andric 8575ffd83dbSDimitry Andric const auto CData = ContainerData::fromBegin(Sym); 8585ffd83dbSDimitry Andric return setContainerData(State, Cont, CData); 8595ffd83dbSDimitry Andric } 8605ffd83dbSDimitry Andric 8615ffd83dbSDimitry Andric ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont, 8625ffd83dbSDimitry Andric const Expr *E, QualType T, 8635ffd83dbSDimitry Andric const LocationContext *LCtx, 8645ffd83dbSDimitry Andric unsigned BlockCount) { 8655ffd83dbSDimitry Andric // Only create if it does not exist 8665ffd83dbSDimitry Andric const auto *CDataPtr = getContainerData(State, Cont); 8675ffd83dbSDimitry Andric if (CDataPtr && CDataPtr->getEnd()) 8685ffd83dbSDimitry Andric return State; 8695ffd83dbSDimitry Andric 8705ffd83dbSDimitry Andric auto &SymMgr = State->getSymbolManager(); 8715ffd83dbSDimitry Andric const SymbolConjured *Sym = SymMgr.conjureSymbol(E, LCtx, T, BlockCount, 8725ffd83dbSDimitry Andric "end"); 8735ffd83dbSDimitry Andric State = assumeNoOverflow(State, Sym, 4); 8745ffd83dbSDimitry Andric 8755ffd83dbSDimitry Andric if (CDataPtr) { 8765ffd83dbSDimitry Andric const auto CData = CDataPtr->newEnd(Sym); 8775ffd83dbSDimitry Andric return setContainerData(State, Cont, CData); 8785ffd83dbSDimitry Andric } 8795ffd83dbSDimitry Andric 8805ffd83dbSDimitry Andric const auto CData = ContainerData::fromEnd(Sym); 8815ffd83dbSDimitry Andric return setContainerData(State, Cont, CData); 8825ffd83dbSDimitry Andric } 8835ffd83dbSDimitry Andric 8845ffd83dbSDimitry Andric ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont, 8855ffd83dbSDimitry Andric const ContainerData &CData) { 8865ffd83dbSDimitry Andric return State->set<ContainerMap>(Cont, CData); 8875ffd83dbSDimitry Andric } 8885ffd83dbSDimitry Andric 8895ffd83dbSDimitry Andric template <typename Condition, typename Process> 8905ffd83dbSDimitry Andric ProgramStateRef processIteratorPositions(ProgramStateRef State, Condition Cond, 8915ffd83dbSDimitry Andric Process Proc) { 8925ffd83dbSDimitry Andric auto &RegionMapFactory = State->get_context<IteratorRegionMap>(); 8935ffd83dbSDimitry Andric auto RegionMap = State->get<IteratorRegionMap>(); 8945ffd83dbSDimitry Andric bool Changed = false; 8955ffd83dbSDimitry Andric for (const auto &Reg : RegionMap) { 8965ffd83dbSDimitry Andric if (Cond(Reg.second)) { 8975ffd83dbSDimitry Andric RegionMap = RegionMapFactory.add(RegionMap, Reg.first, Proc(Reg.second)); 8985ffd83dbSDimitry Andric Changed = true; 8995ffd83dbSDimitry Andric } 9005ffd83dbSDimitry Andric } 9015ffd83dbSDimitry Andric 9025ffd83dbSDimitry Andric if (Changed) 9035ffd83dbSDimitry Andric State = State->set<IteratorRegionMap>(RegionMap); 9045ffd83dbSDimitry Andric 9055ffd83dbSDimitry Andric auto &SymbolMapFactory = State->get_context<IteratorSymbolMap>(); 9065ffd83dbSDimitry Andric auto SymbolMap = State->get<IteratorSymbolMap>(); 9075ffd83dbSDimitry Andric Changed = false; 9085ffd83dbSDimitry Andric for (const auto &Sym : SymbolMap) { 9095ffd83dbSDimitry Andric if (Cond(Sym.second)) { 9105ffd83dbSDimitry Andric SymbolMap = SymbolMapFactory.add(SymbolMap, Sym.first, Proc(Sym.second)); 9115ffd83dbSDimitry Andric Changed = true; 9125ffd83dbSDimitry Andric } 9135ffd83dbSDimitry Andric } 9145ffd83dbSDimitry Andric 9155ffd83dbSDimitry Andric if (Changed) 9165ffd83dbSDimitry Andric State = State->set<IteratorSymbolMap>(SymbolMap); 9175ffd83dbSDimitry Andric 9185ffd83dbSDimitry Andric return State; 9195ffd83dbSDimitry Andric } 9205ffd83dbSDimitry Andric 9215ffd83dbSDimitry Andric ProgramStateRef invalidateAllIteratorPositions(ProgramStateRef State, 9225ffd83dbSDimitry Andric const MemRegion *Cont) { 9235ffd83dbSDimitry Andric auto MatchCont = [&](const IteratorPosition &Pos) { 9245ffd83dbSDimitry Andric return Pos.getContainer() == Cont; 9255ffd83dbSDimitry Andric }; 9265ffd83dbSDimitry Andric auto Invalidate = [&](const IteratorPosition &Pos) { 9275ffd83dbSDimitry Andric return Pos.invalidate(); 9285ffd83dbSDimitry Andric }; 9295ffd83dbSDimitry Andric return processIteratorPositions(State, MatchCont, Invalidate); 9305ffd83dbSDimitry Andric } 9315ffd83dbSDimitry Andric 9325ffd83dbSDimitry Andric ProgramStateRef 9335ffd83dbSDimitry Andric invalidateAllIteratorPositionsExcept(ProgramStateRef State, 9345ffd83dbSDimitry Andric const MemRegion *Cont, SymbolRef Offset, 9355ffd83dbSDimitry Andric BinaryOperator::Opcode Opc) { 9365ffd83dbSDimitry Andric auto MatchContAndCompare = [&](const IteratorPosition &Pos) { 9375ffd83dbSDimitry Andric return Pos.getContainer() == Cont && 9385ffd83dbSDimitry Andric !compare(State, Pos.getOffset(), Offset, Opc); 9395ffd83dbSDimitry Andric }; 9405ffd83dbSDimitry Andric auto Invalidate = [&](const IteratorPosition &Pos) { 9415ffd83dbSDimitry Andric return Pos.invalidate(); 9425ffd83dbSDimitry Andric }; 9435ffd83dbSDimitry Andric return processIteratorPositions(State, MatchContAndCompare, Invalidate); 9445ffd83dbSDimitry Andric } 9455ffd83dbSDimitry Andric 9465ffd83dbSDimitry Andric ProgramStateRef invalidateIteratorPositions(ProgramStateRef State, 9475ffd83dbSDimitry Andric SymbolRef Offset, 9485ffd83dbSDimitry Andric BinaryOperator::Opcode Opc) { 9495ffd83dbSDimitry Andric auto Compare = [&](const IteratorPosition &Pos) { 9505ffd83dbSDimitry Andric return compare(State, Pos.getOffset(), Offset, Opc); 9515ffd83dbSDimitry Andric }; 9525ffd83dbSDimitry Andric auto Invalidate = [&](const IteratorPosition &Pos) { 9535ffd83dbSDimitry Andric return Pos.invalidate(); 9545ffd83dbSDimitry Andric }; 9555ffd83dbSDimitry Andric return processIteratorPositions(State, Compare, Invalidate); 9565ffd83dbSDimitry Andric } 9575ffd83dbSDimitry Andric 9585ffd83dbSDimitry Andric ProgramStateRef invalidateIteratorPositions(ProgramStateRef State, 9595ffd83dbSDimitry Andric SymbolRef Offset1, 9605ffd83dbSDimitry Andric BinaryOperator::Opcode Opc1, 9615ffd83dbSDimitry Andric SymbolRef Offset2, 9625ffd83dbSDimitry Andric BinaryOperator::Opcode Opc2) { 9635ffd83dbSDimitry Andric auto Compare = [&](const IteratorPosition &Pos) { 9645ffd83dbSDimitry Andric return compare(State, Pos.getOffset(), Offset1, Opc1) && 9655ffd83dbSDimitry Andric compare(State, Pos.getOffset(), Offset2, Opc2); 9665ffd83dbSDimitry Andric }; 9675ffd83dbSDimitry Andric auto Invalidate = [&](const IteratorPosition &Pos) { 9685ffd83dbSDimitry Andric return Pos.invalidate(); 9695ffd83dbSDimitry Andric }; 9705ffd83dbSDimitry Andric return processIteratorPositions(State, Compare, Invalidate); 9715ffd83dbSDimitry Andric } 9725ffd83dbSDimitry Andric 9735ffd83dbSDimitry Andric ProgramStateRef reassignAllIteratorPositions(ProgramStateRef State, 9745ffd83dbSDimitry Andric const MemRegion *Cont, 9755ffd83dbSDimitry Andric const MemRegion *NewCont) { 9765ffd83dbSDimitry Andric auto MatchCont = [&](const IteratorPosition &Pos) { 9775ffd83dbSDimitry Andric return Pos.getContainer() == Cont; 9785ffd83dbSDimitry Andric }; 9795ffd83dbSDimitry Andric auto ReAssign = [&](const IteratorPosition &Pos) { 9805ffd83dbSDimitry Andric return Pos.reAssign(NewCont); 9815ffd83dbSDimitry Andric }; 9825ffd83dbSDimitry Andric return processIteratorPositions(State, MatchCont, ReAssign); 9835ffd83dbSDimitry Andric } 9845ffd83dbSDimitry Andric 9855ffd83dbSDimitry Andric ProgramStateRef reassignAllIteratorPositionsUnless(ProgramStateRef State, 9865ffd83dbSDimitry Andric const MemRegion *Cont, 9875ffd83dbSDimitry Andric const MemRegion *NewCont, 9885ffd83dbSDimitry Andric SymbolRef Offset, 9895ffd83dbSDimitry Andric BinaryOperator::Opcode Opc) { 9905ffd83dbSDimitry Andric auto MatchContAndCompare = [&](const IteratorPosition &Pos) { 9915ffd83dbSDimitry Andric return Pos.getContainer() == Cont && 9925ffd83dbSDimitry Andric !compare(State, Pos.getOffset(), Offset, Opc); 9935ffd83dbSDimitry Andric }; 9945ffd83dbSDimitry Andric auto ReAssign = [&](const IteratorPosition &Pos) { 9955ffd83dbSDimitry Andric return Pos.reAssign(NewCont); 9965ffd83dbSDimitry Andric }; 9975ffd83dbSDimitry Andric return processIteratorPositions(State, MatchContAndCompare, ReAssign); 9985ffd83dbSDimitry Andric } 9995ffd83dbSDimitry Andric 10005ffd83dbSDimitry Andric // This function rebases symbolic expression `OldSym + Int` to `NewSym + Int`, 10015ffd83dbSDimitry Andric // `OldSym - Int` to `NewSym - Int` and `OldSym` to `NewSym` in any iterator 10025ffd83dbSDimitry Andric // position offsets where `CondSym` is true. 10035ffd83dbSDimitry Andric ProgramStateRef rebaseSymbolInIteratorPositionsIf( 10045ffd83dbSDimitry Andric ProgramStateRef State, SValBuilder &SVB, SymbolRef OldSym, 10055ffd83dbSDimitry Andric SymbolRef NewSym, SymbolRef CondSym, BinaryOperator::Opcode Opc) { 10065ffd83dbSDimitry Andric auto LessThanEnd = [&](const IteratorPosition &Pos) { 10075ffd83dbSDimitry Andric return compare(State, Pos.getOffset(), CondSym, Opc); 10085ffd83dbSDimitry Andric }; 10095ffd83dbSDimitry Andric auto RebaseSymbol = [&](const IteratorPosition &Pos) { 10105ffd83dbSDimitry Andric return Pos.setTo(rebaseSymbol(State, SVB, Pos.getOffset(), OldSym, 10115ffd83dbSDimitry Andric NewSym)); 10125ffd83dbSDimitry Andric }; 10135ffd83dbSDimitry Andric return processIteratorPositions(State, LessThanEnd, RebaseSymbol); 10145ffd83dbSDimitry Andric } 10155ffd83dbSDimitry Andric 10165ffd83dbSDimitry Andric // This function rebases symbolic expression `OldExpr + Int` to `NewExpr + Int`, 10175ffd83dbSDimitry Andric // `OldExpr - Int` to `NewExpr - Int` and `OldExpr` to `NewExpr` in expression 10185ffd83dbSDimitry Andric // `OrigExpr`. 10195ffd83dbSDimitry Andric SymbolRef rebaseSymbol(ProgramStateRef State, SValBuilder &SVB, 10205ffd83dbSDimitry Andric SymbolRef OrigExpr, SymbolRef OldExpr, 10215ffd83dbSDimitry Andric SymbolRef NewSym) { 10225ffd83dbSDimitry Andric auto &SymMgr = SVB.getSymbolManager(); 10235ffd83dbSDimitry Andric auto Diff = SVB.evalBinOpNN(State, BO_Sub, nonloc::SymbolVal(OrigExpr), 10245ffd83dbSDimitry Andric nonloc::SymbolVal(OldExpr), 10255ffd83dbSDimitry Andric SymMgr.getType(OrigExpr)); 10265ffd83dbSDimitry Andric 10275ffd83dbSDimitry Andric const auto DiffInt = Diff.getAs<nonloc::ConcreteInt>(); 10285ffd83dbSDimitry Andric if (!DiffInt) 10295ffd83dbSDimitry Andric return OrigExpr; 10305ffd83dbSDimitry Andric 10315ffd83dbSDimitry Andric return SVB.evalBinOpNN(State, BO_Add, *DiffInt, nonloc::SymbolVal(NewSym), 10325ffd83dbSDimitry Andric SymMgr.getType(OrigExpr)).getAsSymbol(); 10335ffd83dbSDimitry Andric } 10345ffd83dbSDimitry Andric 10355ffd83dbSDimitry Andric bool hasLiveIterators(ProgramStateRef State, const MemRegion *Cont) { 10365ffd83dbSDimitry Andric auto RegionMap = State->get<IteratorRegionMap>(); 10375ffd83dbSDimitry Andric for (const auto &Reg : RegionMap) { 10385ffd83dbSDimitry Andric if (Reg.second.getContainer() == Cont) 10395ffd83dbSDimitry Andric return true; 10405ffd83dbSDimitry Andric } 10415ffd83dbSDimitry Andric 10425ffd83dbSDimitry Andric auto SymbolMap = State->get<IteratorSymbolMap>(); 10435ffd83dbSDimitry Andric for (const auto &Sym : SymbolMap) { 10445ffd83dbSDimitry Andric if (Sym.second.getContainer() == Cont) 10455ffd83dbSDimitry Andric return true; 10465ffd83dbSDimitry Andric } 10475ffd83dbSDimitry Andric 10485ffd83dbSDimitry Andric return false; 10495ffd83dbSDimitry Andric } 10505ffd83dbSDimitry Andric 10515ffd83dbSDimitry Andric } // namespace 10525ffd83dbSDimitry Andric 10535ffd83dbSDimitry Andric void ento::registerContainerModeling(CheckerManager &mgr) { 10545ffd83dbSDimitry Andric mgr.registerChecker<ContainerModeling>(); 10555ffd83dbSDimitry Andric } 10565ffd83dbSDimitry Andric 10575ffd83dbSDimitry Andric bool ento::shouldRegisterContainerModeling(const CheckerManager &mgr) { 10585ffd83dbSDimitry Andric if (!mgr.getLangOpts().CPlusPlus) 10595ffd83dbSDimitry Andric return false; 10605ffd83dbSDimitry Andric 10615ffd83dbSDimitry Andric if (!mgr.getAnalyzerOptions().ShouldAggressivelySimplifyBinaryOperation) { 10625ffd83dbSDimitry Andric mgr.getASTContext().getDiagnostics().Report( 10635ffd83dbSDimitry Andric diag::err_analyzer_checker_incompatible_analyzer_option) 10645ffd83dbSDimitry Andric << "aggressive-binary-operation-simplification" << "false"; 10655ffd83dbSDimitry Andric return false; 10665ffd83dbSDimitry Andric } 10675ffd83dbSDimitry Andric 10685ffd83dbSDimitry Andric return true; 10695ffd83dbSDimitry Andric } 1070