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