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