1*5ffd83dbSDimitry Andric //===-- ContainerModeling.cpp -------------------------------------*- C++ -*--// 2*5ffd83dbSDimitry Andric // 3*5ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*5ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*5ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*5ffd83dbSDimitry Andric // 7*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 8*5ffd83dbSDimitry Andric // 9*5ffd83dbSDimitry Andric // Defines a modeling-checker for modeling STL container-like containers. 10*5ffd83dbSDimitry Andric // 11*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 12*5ffd83dbSDimitry Andric 13*5ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 14*5ffd83dbSDimitry Andric #include "clang/AST/DeclTemplate.h" 15*5ffd83dbSDimitry Andric #include "clang/Driver/DriverDiagnostic.h" 16*5ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 17*5ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h" 18*5ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 19*5ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 20*5ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h" 21*5ffd83dbSDimitry Andric 22*5ffd83dbSDimitry Andric #include "Iterator.h" 23*5ffd83dbSDimitry Andric 24*5ffd83dbSDimitry Andric #include <utility> 25*5ffd83dbSDimitry Andric 26*5ffd83dbSDimitry Andric using namespace clang; 27*5ffd83dbSDimitry Andric using namespace ento; 28*5ffd83dbSDimitry Andric using namespace iterator; 29*5ffd83dbSDimitry Andric 30*5ffd83dbSDimitry Andric namespace { 31*5ffd83dbSDimitry Andric 32*5ffd83dbSDimitry Andric class ContainerModeling 33*5ffd83dbSDimitry Andric : public Checker<check::PostCall, check::LiveSymbols, check::DeadSymbols> { 34*5ffd83dbSDimitry Andric 35*5ffd83dbSDimitry Andric void handleBegin(CheckerContext &C, const Expr *CE, SVal RetVal, 36*5ffd83dbSDimitry Andric SVal Cont) const; 37*5ffd83dbSDimitry Andric void handleEnd(CheckerContext &C, const Expr *CE, SVal RetVal, 38*5ffd83dbSDimitry Andric SVal Cont) const; 39*5ffd83dbSDimitry Andric void handleAssignment(CheckerContext &C, SVal Cont, const Expr *CE = nullptr, 40*5ffd83dbSDimitry Andric SVal OldCont = UndefinedVal()) const; 41*5ffd83dbSDimitry Andric void handleAssign(CheckerContext &C, SVal Cont, const Expr *ContE) const; 42*5ffd83dbSDimitry Andric void handleClear(CheckerContext &C, SVal Cont, const Expr *ContE) const; 43*5ffd83dbSDimitry Andric void handlePushBack(CheckerContext &C, SVal Cont, const Expr *ContE) const; 44*5ffd83dbSDimitry Andric void handlePopBack(CheckerContext &C, SVal Cont, const Expr *ContE) const; 45*5ffd83dbSDimitry Andric void handlePushFront(CheckerContext &C, SVal Cont, const Expr *ContE) const; 46*5ffd83dbSDimitry Andric void handlePopFront(CheckerContext &C, SVal Cont, const Expr *ContE) const; 47*5ffd83dbSDimitry Andric void handleInsert(CheckerContext &C, SVal Cont, SVal Iter) const; 48*5ffd83dbSDimitry Andric void handleErase(CheckerContext &C, SVal Cont, SVal Iter) const; 49*5ffd83dbSDimitry Andric void handleErase(CheckerContext &C, SVal Cont, SVal Iter1, SVal Iter2) const; 50*5ffd83dbSDimitry Andric void handleEraseAfter(CheckerContext &C, SVal Cont, SVal Iter) const; 51*5ffd83dbSDimitry Andric void handleEraseAfter(CheckerContext &C, SVal Cont, SVal Iter1, 52*5ffd83dbSDimitry Andric SVal Iter2) const; 53*5ffd83dbSDimitry Andric const NoteTag *getChangeTag(CheckerContext &C, StringRef Text, 54*5ffd83dbSDimitry Andric const MemRegion *ContReg, 55*5ffd83dbSDimitry Andric const Expr *ContE) const; 56*5ffd83dbSDimitry Andric void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, 57*5ffd83dbSDimitry Andric const char *Sep) const override; 58*5ffd83dbSDimitry Andric 59*5ffd83dbSDimitry Andric public: 60*5ffd83dbSDimitry Andric ContainerModeling() = default; 61*5ffd83dbSDimitry Andric 62*5ffd83dbSDimitry Andric void checkPostCall(const CallEvent &Call, CheckerContext &C) const; 63*5ffd83dbSDimitry Andric void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const; 64*5ffd83dbSDimitry Andric void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const; 65*5ffd83dbSDimitry Andric 66*5ffd83dbSDimitry Andric using NoItParamFn = void (ContainerModeling::*)(CheckerContext &, SVal, 67*5ffd83dbSDimitry Andric const Expr *) const; 68*5ffd83dbSDimitry Andric using OneItParamFn = void (ContainerModeling::*)(CheckerContext &, SVal, 69*5ffd83dbSDimitry Andric SVal) const; 70*5ffd83dbSDimitry Andric using TwoItParamFn = void (ContainerModeling::*)(CheckerContext &, SVal, SVal, 71*5ffd83dbSDimitry Andric SVal) const; 72*5ffd83dbSDimitry Andric 73*5ffd83dbSDimitry Andric CallDescriptionMap<NoItParamFn> NoIterParamFunctions = { 74*5ffd83dbSDimitry Andric {{0, "clear", 0}, 75*5ffd83dbSDimitry Andric &ContainerModeling::handleClear}, 76*5ffd83dbSDimitry Andric {{0, "assign", 2}, 77*5ffd83dbSDimitry Andric &ContainerModeling::handleAssign}, 78*5ffd83dbSDimitry Andric {{0, "push_back", 1}, 79*5ffd83dbSDimitry Andric &ContainerModeling::handlePushBack}, 80*5ffd83dbSDimitry Andric {{0, "emplace_back", 1}, 81*5ffd83dbSDimitry Andric &ContainerModeling::handlePushBack}, 82*5ffd83dbSDimitry Andric {{0, "pop_back", 0}, 83*5ffd83dbSDimitry Andric &ContainerModeling::handlePopBack}, 84*5ffd83dbSDimitry Andric {{0, "push_front", 1}, 85*5ffd83dbSDimitry Andric &ContainerModeling::handlePushFront}, 86*5ffd83dbSDimitry Andric {{0, "emplace_front", 1}, 87*5ffd83dbSDimitry Andric &ContainerModeling::handlePushFront}, 88*5ffd83dbSDimitry Andric {{0, "pop_front", 0}, 89*5ffd83dbSDimitry Andric &ContainerModeling::handlePopFront}, 90*5ffd83dbSDimitry Andric }; 91*5ffd83dbSDimitry Andric 92*5ffd83dbSDimitry Andric CallDescriptionMap<OneItParamFn> OneIterParamFunctions = { 93*5ffd83dbSDimitry Andric {{0, "insert", 2}, 94*5ffd83dbSDimitry Andric &ContainerModeling::handleInsert}, 95*5ffd83dbSDimitry Andric {{0, "emplace", 2}, 96*5ffd83dbSDimitry Andric &ContainerModeling::handleInsert}, 97*5ffd83dbSDimitry Andric {{0, "erase", 1}, 98*5ffd83dbSDimitry Andric &ContainerModeling::handleErase}, 99*5ffd83dbSDimitry Andric {{0, "erase_after", 1}, 100*5ffd83dbSDimitry Andric &ContainerModeling::handleEraseAfter}, 101*5ffd83dbSDimitry Andric }; 102*5ffd83dbSDimitry Andric 103*5ffd83dbSDimitry Andric CallDescriptionMap<TwoItParamFn> TwoIterParamFunctions = { 104*5ffd83dbSDimitry Andric {{0, "erase", 2}, 105*5ffd83dbSDimitry Andric &ContainerModeling::handleErase}, 106*5ffd83dbSDimitry Andric {{0, "erase_after", 2}, 107*5ffd83dbSDimitry Andric &ContainerModeling::handleEraseAfter}, 108*5ffd83dbSDimitry Andric }; 109*5ffd83dbSDimitry Andric 110*5ffd83dbSDimitry Andric }; 111*5ffd83dbSDimitry Andric 112*5ffd83dbSDimitry Andric bool isBeginCall(const FunctionDecl *Func); 113*5ffd83dbSDimitry Andric bool isEndCall(const FunctionDecl *Func); 114*5ffd83dbSDimitry Andric bool hasSubscriptOperator(ProgramStateRef State, const MemRegion *Reg); 115*5ffd83dbSDimitry Andric bool frontModifiable(ProgramStateRef State, const MemRegion *Reg); 116*5ffd83dbSDimitry Andric bool backModifiable(ProgramStateRef State, const MemRegion *Reg); 117*5ffd83dbSDimitry Andric SymbolRef getContainerBegin(ProgramStateRef State, const MemRegion *Cont); 118*5ffd83dbSDimitry Andric SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont); 119*5ffd83dbSDimitry Andric ProgramStateRef createContainerBegin(ProgramStateRef State, 120*5ffd83dbSDimitry Andric const MemRegion *Cont, const Expr *E, 121*5ffd83dbSDimitry Andric QualType T, const LocationContext *LCtx, 122*5ffd83dbSDimitry Andric unsigned BlockCount); 123*5ffd83dbSDimitry Andric ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont, 124*5ffd83dbSDimitry Andric const Expr *E, QualType T, 125*5ffd83dbSDimitry Andric const LocationContext *LCtx, 126*5ffd83dbSDimitry Andric unsigned BlockCount); 127*5ffd83dbSDimitry Andric ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont, 128*5ffd83dbSDimitry Andric const ContainerData &CData); 129*5ffd83dbSDimitry Andric ProgramStateRef invalidateAllIteratorPositions(ProgramStateRef State, 130*5ffd83dbSDimitry Andric const MemRegion *Cont); 131*5ffd83dbSDimitry Andric ProgramStateRef 132*5ffd83dbSDimitry Andric invalidateAllIteratorPositionsExcept(ProgramStateRef State, 133*5ffd83dbSDimitry Andric const MemRegion *Cont, SymbolRef Offset, 134*5ffd83dbSDimitry Andric BinaryOperator::Opcode Opc); 135*5ffd83dbSDimitry Andric ProgramStateRef invalidateIteratorPositions(ProgramStateRef State, 136*5ffd83dbSDimitry Andric SymbolRef Offset, 137*5ffd83dbSDimitry Andric BinaryOperator::Opcode Opc); 138*5ffd83dbSDimitry Andric ProgramStateRef invalidateIteratorPositions(ProgramStateRef State, 139*5ffd83dbSDimitry Andric SymbolRef Offset1, 140*5ffd83dbSDimitry Andric BinaryOperator::Opcode Opc1, 141*5ffd83dbSDimitry Andric SymbolRef Offset2, 142*5ffd83dbSDimitry Andric BinaryOperator::Opcode Opc2); 143*5ffd83dbSDimitry Andric ProgramStateRef reassignAllIteratorPositions(ProgramStateRef State, 144*5ffd83dbSDimitry Andric const MemRegion *Cont, 145*5ffd83dbSDimitry Andric const MemRegion *NewCont); 146*5ffd83dbSDimitry Andric ProgramStateRef reassignAllIteratorPositionsUnless(ProgramStateRef State, 147*5ffd83dbSDimitry Andric const MemRegion *Cont, 148*5ffd83dbSDimitry Andric const MemRegion *NewCont, 149*5ffd83dbSDimitry Andric SymbolRef Offset, 150*5ffd83dbSDimitry Andric BinaryOperator::Opcode Opc); 151*5ffd83dbSDimitry Andric ProgramStateRef rebaseSymbolInIteratorPositionsIf( 152*5ffd83dbSDimitry Andric ProgramStateRef State, SValBuilder &SVB, SymbolRef OldSym, 153*5ffd83dbSDimitry Andric SymbolRef NewSym, SymbolRef CondSym, BinaryOperator::Opcode Opc); 154*5ffd83dbSDimitry Andric SymbolRef rebaseSymbol(ProgramStateRef State, SValBuilder &SVB, SymbolRef Expr, 155*5ffd83dbSDimitry Andric SymbolRef OldSym, SymbolRef NewSym); 156*5ffd83dbSDimitry Andric bool hasLiveIterators(ProgramStateRef State, const MemRegion *Cont); 157*5ffd83dbSDimitry Andric 158*5ffd83dbSDimitry Andric } // namespace 159*5ffd83dbSDimitry Andric 160*5ffd83dbSDimitry Andric void ContainerModeling::checkPostCall(const CallEvent &Call, 161*5ffd83dbSDimitry Andric CheckerContext &C) const { 162*5ffd83dbSDimitry Andric const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); 163*5ffd83dbSDimitry Andric if (!Func) 164*5ffd83dbSDimitry Andric return; 165*5ffd83dbSDimitry Andric 166*5ffd83dbSDimitry Andric if (Func->isOverloadedOperator()) { 167*5ffd83dbSDimitry Andric const auto Op = Func->getOverloadedOperator(); 168*5ffd83dbSDimitry Andric if (Op == OO_Equal) { 169*5ffd83dbSDimitry Andric // Overloaded 'operator=' must be a non-static member function. 170*5ffd83dbSDimitry Andric const auto *InstCall = cast<CXXInstanceCall>(&Call); 171*5ffd83dbSDimitry Andric if (cast<CXXMethodDecl>(Func)->isMoveAssignmentOperator()) { 172*5ffd83dbSDimitry Andric handleAssignment(C, InstCall->getCXXThisVal(), Call.getOriginExpr(), 173*5ffd83dbSDimitry Andric Call.getArgSVal(0)); 174*5ffd83dbSDimitry Andric return; 175*5ffd83dbSDimitry Andric } 176*5ffd83dbSDimitry Andric 177*5ffd83dbSDimitry Andric handleAssignment(C, InstCall->getCXXThisVal()); 178*5ffd83dbSDimitry Andric return; 179*5ffd83dbSDimitry Andric } 180*5ffd83dbSDimitry Andric } else { 181*5ffd83dbSDimitry Andric if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { 182*5ffd83dbSDimitry Andric const NoItParamFn *Handler0 = NoIterParamFunctions.lookup(Call); 183*5ffd83dbSDimitry Andric if (Handler0) { 184*5ffd83dbSDimitry Andric (this->**Handler0)(C, InstCall->getCXXThisVal(), 185*5ffd83dbSDimitry Andric InstCall->getCXXThisExpr()); 186*5ffd83dbSDimitry Andric return; 187*5ffd83dbSDimitry Andric } 188*5ffd83dbSDimitry Andric 189*5ffd83dbSDimitry Andric const OneItParamFn *Handler1 = OneIterParamFunctions.lookup(Call); 190*5ffd83dbSDimitry Andric if (Handler1) { 191*5ffd83dbSDimitry Andric (this->**Handler1)(C, InstCall->getCXXThisVal(), Call.getArgSVal(0)); 192*5ffd83dbSDimitry Andric return; 193*5ffd83dbSDimitry Andric } 194*5ffd83dbSDimitry Andric 195*5ffd83dbSDimitry Andric const TwoItParamFn *Handler2 = TwoIterParamFunctions.lookup(Call); 196*5ffd83dbSDimitry Andric if (Handler2) { 197*5ffd83dbSDimitry Andric (this->**Handler2)(C, InstCall->getCXXThisVal(), Call.getArgSVal(0), 198*5ffd83dbSDimitry Andric Call.getArgSVal(1)); 199*5ffd83dbSDimitry Andric return; 200*5ffd83dbSDimitry Andric } 201*5ffd83dbSDimitry Andric 202*5ffd83dbSDimitry Andric const auto *OrigExpr = Call.getOriginExpr(); 203*5ffd83dbSDimitry Andric if (!OrigExpr) 204*5ffd83dbSDimitry Andric return; 205*5ffd83dbSDimitry Andric 206*5ffd83dbSDimitry Andric if (isBeginCall(Func)) { 207*5ffd83dbSDimitry Andric handleBegin(C, OrigExpr, Call.getReturnValue(), 208*5ffd83dbSDimitry Andric InstCall->getCXXThisVal()); 209*5ffd83dbSDimitry Andric return; 210*5ffd83dbSDimitry Andric } 211*5ffd83dbSDimitry Andric 212*5ffd83dbSDimitry Andric if (isEndCall(Func)) { 213*5ffd83dbSDimitry Andric handleEnd(C, OrigExpr, Call.getReturnValue(), 214*5ffd83dbSDimitry Andric InstCall->getCXXThisVal()); 215*5ffd83dbSDimitry Andric return; 216*5ffd83dbSDimitry Andric } 217*5ffd83dbSDimitry Andric } 218*5ffd83dbSDimitry Andric } 219*5ffd83dbSDimitry Andric } 220*5ffd83dbSDimitry Andric 221*5ffd83dbSDimitry Andric void ContainerModeling::checkLiveSymbols(ProgramStateRef State, 222*5ffd83dbSDimitry Andric SymbolReaper &SR) const { 223*5ffd83dbSDimitry Andric // Keep symbolic expressions of container begins and ends alive 224*5ffd83dbSDimitry Andric auto ContMap = State->get<ContainerMap>(); 225*5ffd83dbSDimitry Andric for (const auto &Cont : ContMap) { 226*5ffd83dbSDimitry Andric const auto CData = Cont.second; 227*5ffd83dbSDimitry Andric if (CData.getBegin()) { 228*5ffd83dbSDimitry Andric SR.markLive(CData.getBegin()); 229*5ffd83dbSDimitry Andric if(const auto *SIE = dyn_cast<SymIntExpr>(CData.getBegin())) 230*5ffd83dbSDimitry Andric SR.markLive(SIE->getLHS()); 231*5ffd83dbSDimitry Andric } 232*5ffd83dbSDimitry Andric if (CData.getEnd()) { 233*5ffd83dbSDimitry Andric SR.markLive(CData.getEnd()); 234*5ffd83dbSDimitry Andric if(const auto *SIE = dyn_cast<SymIntExpr>(CData.getEnd())) 235*5ffd83dbSDimitry Andric SR.markLive(SIE->getLHS()); 236*5ffd83dbSDimitry Andric } 237*5ffd83dbSDimitry Andric } 238*5ffd83dbSDimitry Andric } 239*5ffd83dbSDimitry Andric 240*5ffd83dbSDimitry Andric void ContainerModeling::checkDeadSymbols(SymbolReaper &SR, 241*5ffd83dbSDimitry Andric CheckerContext &C) const { 242*5ffd83dbSDimitry Andric // Cleanup 243*5ffd83dbSDimitry Andric auto State = C.getState(); 244*5ffd83dbSDimitry Andric 245*5ffd83dbSDimitry Andric auto ContMap = State->get<ContainerMap>(); 246*5ffd83dbSDimitry Andric for (const auto &Cont : ContMap) { 247*5ffd83dbSDimitry Andric if (!SR.isLiveRegion(Cont.first)) { 248*5ffd83dbSDimitry Andric // We must keep the container data while it has live iterators to be able 249*5ffd83dbSDimitry Andric // to compare them to the begin and the end of the container. 250*5ffd83dbSDimitry Andric if (!hasLiveIterators(State, Cont.first)) { 251*5ffd83dbSDimitry Andric State = State->remove<ContainerMap>(Cont.first); 252*5ffd83dbSDimitry Andric } 253*5ffd83dbSDimitry Andric } 254*5ffd83dbSDimitry Andric } 255*5ffd83dbSDimitry Andric 256*5ffd83dbSDimitry Andric C.addTransition(State); 257*5ffd83dbSDimitry Andric } 258*5ffd83dbSDimitry Andric 259*5ffd83dbSDimitry Andric void ContainerModeling::handleBegin(CheckerContext &C, const Expr *CE, 260*5ffd83dbSDimitry Andric SVal RetVal, SVal Cont) const { 261*5ffd83dbSDimitry Andric const auto *ContReg = Cont.getAsRegion(); 262*5ffd83dbSDimitry Andric if (!ContReg) 263*5ffd83dbSDimitry Andric return; 264*5ffd83dbSDimitry Andric 265*5ffd83dbSDimitry Andric ContReg = ContReg->getMostDerivedObjectRegion(); 266*5ffd83dbSDimitry Andric 267*5ffd83dbSDimitry Andric // If the container already has a begin symbol then use it. Otherwise first 268*5ffd83dbSDimitry Andric // create a new one. 269*5ffd83dbSDimitry Andric auto State = C.getState(); 270*5ffd83dbSDimitry Andric auto BeginSym = getContainerBegin(State, ContReg); 271*5ffd83dbSDimitry Andric if (!BeginSym) { 272*5ffd83dbSDimitry Andric State = createContainerBegin(State, ContReg, CE, C.getASTContext().LongTy, 273*5ffd83dbSDimitry Andric C.getLocationContext(), C.blockCount()); 274*5ffd83dbSDimitry Andric BeginSym = getContainerBegin(State, ContReg); 275*5ffd83dbSDimitry Andric } 276*5ffd83dbSDimitry Andric State = setIteratorPosition(State, RetVal, 277*5ffd83dbSDimitry Andric IteratorPosition::getPosition(ContReg, BeginSym)); 278*5ffd83dbSDimitry Andric C.addTransition(State); 279*5ffd83dbSDimitry Andric } 280*5ffd83dbSDimitry Andric 281*5ffd83dbSDimitry Andric void ContainerModeling::handleEnd(CheckerContext &C, const Expr *CE, 282*5ffd83dbSDimitry Andric SVal RetVal, SVal Cont) const { 283*5ffd83dbSDimitry Andric const auto *ContReg = Cont.getAsRegion(); 284*5ffd83dbSDimitry Andric if (!ContReg) 285*5ffd83dbSDimitry Andric return; 286*5ffd83dbSDimitry Andric 287*5ffd83dbSDimitry Andric ContReg = ContReg->getMostDerivedObjectRegion(); 288*5ffd83dbSDimitry Andric 289*5ffd83dbSDimitry Andric // If the container already has an end symbol then use it. Otherwise first 290*5ffd83dbSDimitry Andric // create a new one. 291*5ffd83dbSDimitry Andric auto State = C.getState(); 292*5ffd83dbSDimitry Andric auto EndSym = getContainerEnd(State, ContReg); 293*5ffd83dbSDimitry Andric if (!EndSym) { 294*5ffd83dbSDimitry Andric State = createContainerEnd(State, ContReg, CE, C.getASTContext().LongTy, 295*5ffd83dbSDimitry Andric C.getLocationContext(), C.blockCount()); 296*5ffd83dbSDimitry Andric EndSym = getContainerEnd(State, ContReg); 297*5ffd83dbSDimitry Andric } 298*5ffd83dbSDimitry Andric State = setIteratorPosition(State, RetVal, 299*5ffd83dbSDimitry Andric IteratorPosition::getPosition(ContReg, EndSym)); 300*5ffd83dbSDimitry Andric C.addTransition(State); 301*5ffd83dbSDimitry Andric } 302*5ffd83dbSDimitry Andric 303*5ffd83dbSDimitry Andric void ContainerModeling::handleAssignment(CheckerContext &C, SVal Cont, 304*5ffd83dbSDimitry Andric const Expr *CE, SVal OldCont) const { 305*5ffd83dbSDimitry Andric const auto *ContReg = Cont.getAsRegion(); 306*5ffd83dbSDimitry Andric if (!ContReg) 307*5ffd83dbSDimitry Andric return; 308*5ffd83dbSDimitry Andric 309*5ffd83dbSDimitry Andric ContReg = ContReg->getMostDerivedObjectRegion(); 310*5ffd83dbSDimitry Andric 311*5ffd83dbSDimitry Andric // Assignment of a new value to a container always invalidates all its 312*5ffd83dbSDimitry Andric // iterators 313*5ffd83dbSDimitry Andric auto State = C.getState(); 314*5ffd83dbSDimitry Andric const auto CData = getContainerData(State, ContReg); 315*5ffd83dbSDimitry Andric if (CData) { 316*5ffd83dbSDimitry Andric State = invalidateAllIteratorPositions(State, ContReg); 317*5ffd83dbSDimitry Andric } 318*5ffd83dbSDimitry Andric 319*5ffd83dbSDimitry Andric // In case of move, iterators of the old container (except the past-end 320*5ffd83dbSDimitry Andric // iterators) remain valid but refer to the new container 321*5ffd83dbSDimitry Andric if (!OldCont.isUndef()) { 322*5ffd83dbSDimitry Andric const auto *OldContReg = OldCont.getAsRegion(); 323*5ffd83dbSDimitry Andric if (OldContReg) { 324*5ffd83dbSDimitry Andric OldContReg = OldContReg->getMostDerivedObjectRegion(); 325*5ffd83dbSDimitry Andric const auto OldCData = getContainerData(State, OldContReg); 326*5ffd83dbSDimitry Andric if (OldCData) { 327*5ffd83dbSDimitry Andric if (const auto OldEndSym = OldCData->getEnd()) { 328*5ffd83dbSDimitry Andric // If we already assigned an "end" symbol to the old container, then 329*5ffd83dbSDimitry Andric // first reassign all iterator positions to the new container which 330*5ffd83dbSDimitry Andric // are not past the container (thus not greater or equal to the 331*5ffd83dbSDimitry Andric // current "end" symbol). 332*5ffd83dbSDimitry Andric State = reassignAllIteratorPositionsUnless(State, OldContReg, ContReg, 333*5ffd83dbSDimitry Andric OldEndSym, BO_GE); 334*5ffd83dbSDimitry Andric auto &SymMgr = C.getSymbolManager(); 335*5ffd83dbSDimitry Andric auto &SVB = C.getSValBuilder(); 336*5ffd83dbSDimitry Andric // Then generate and assign a new "end" symbol for the new container. 337*5ffd83dbSDimitry Andric auto NewEndSym = 338*5ffd83dbSDimitry Andric SymMgr.conjureSymbol(CE, C.getLocationContext(), 339*5ffd83dbSDimitry Andric C.getASTContext().LongTy, C.blockCount()); 340*5ffd83dbSDimitry Andric State = assumeNoOverflow(State, NewEndSym, 4); 341*5ffd83dbSDimitry Andric if (CData) { 342*5ffd83dbSDimitry Andric State = setContainerData(State, ContReg, CData->newEnd(NewEndSym)); 343*5ffd83dbSDimitry Andric } else { 344*5ffd83dbSDimitry Andric State = setContainerData(State, ContReg, 345*5ffd83dbSDimitry Andric ContainerData::fromEnd(NewEndSym)); 346*5ffd83dbSDimitry Andric } 347*5ffd83dbSDimitry Andric // Finally, replace the old "end" symbol in the already reassigned 348*5ffd83dbSDimitry Andric // iterator positions with the new "end" symbol. 349*5ffd83dbSDimitry Andric State = rebaseSymbolInIteratorPositionsIf( 350*5ffd83dbSDimitry Andric State, SVB, OldEndSym, NewEndSym, OldEndSym, BO_LT); 351*5ffd83dbSDimitry Andric } else { 352*5ffd83dbSDimitry Andric // There was no "end" symbol assigned yet to the old container, 353*5ffd83dbSDimitry Andric // so reassign all iterator positions to the new container. 354*5ffd83dbSDimitry Andric State = reassignAllIteratorPositions(State, OldContReg, ContReg); 355*5ffd83dbSDimitry Andric } 356*5ffd83dbSDimitry Andric if (const auto OldBeginSym = OldCData->getBegin()) { 357*5ffd83dbSDimitry Andric // If we already assigned a "begin" symbol to the old container, then 358*5ffd83dbSDimitry Andric // assign it to the new container and remove it from the old one. 359*5ffd83dbSDimitry Andric if (CData) { 360*5ffd83dbSDimitry Andric State = 361*5ffd83dbSDimitry Andric setContainerData(State, ContReg, CData->newBegin(OldBeginSym)); 362*5ffd83dbSDimitry Andric } else { 363*5ffd83dbSDimitry Andric State = setContainerData(State, ContReg, 364*5ffd83dbSDimitry Andric ContainerData::fromBegin(OldBeginSym)); 365*5ffd83dbSDimitry Andric } 366*5ffd83dbSDimitry Andric State = 367*5ffd83dbSDimitry Andric setContainerData(State, OldContReg, OldCData->newBegin(nullptr)); 368*5ffd83dbSDimitry Andric } 369*5ffd83dbSDimitry Andric } else { 370*5ffd83dbSDimitry Andric // There was neither "begin" nor "end" symbol assigned yet to the old 371*5ffd83dbSDimitry Andric // container, so reassign all iterator positions to the new container. 372*5ffd83dbSDimitry Andric State = reassignAllIteratorPositions(State, OldContReg, ContReg); 373*5ffd83dbSDimitry Andric } 374*5ffd83dbSDimitry Andric } 375*5ffd83dbSDimitry Andric } 376*5ffd83dbSDimitry Andric C.addTransition(State); 377*5ffd83dbSDimitry Andric } 378*5ffd83dbSDimitry Andric 379*5ffd83dbSDimitry Andric void ContainerModeling::handleAssign(CheckerContext &C, SVal Cont, 380*5ffd83dbSDimitry Andric const Expr *ContE) const { 381*5ffd83dbSDimitry Andric const auto *ContReg = Cont.getAsRegion(); 382*5ffd83dbSDimitry Andric if (!ContReg) 383*5ffd83dbSDimitry Andric return; 384*5ffd83dbSDimitry Andric 385*5ffd83dbSDimitry Andric ContReg = ContReg->getMostDerivedObjectRegion(); 386*5ffd83dbSDimitry Andric 387*5ffd83dbSDimitry Andric // The assign() operation invalidates all the iterators 388*5ffd83dbSDimitry Andric auto State = C.getState(); 389*5ffd83dbSDimitry Andric State = invalidateAllIteratorPositions(State, ContReg); 390*5ffd83dbSDimitry Andric C.addTransition(State); 391*5ffd83dbSDimitry Andric } 392*5ffd83dbSDimitry Andric 393*5ffd83dbSDimitry Andric void ContainerModeling::handleClear(CheckerContext &C, SVal Cont, 394*5ffd83dbSDimitry Andric const Expr *ContE) const { 395*5ffd83dbSDimitry Andric const auto *ContReg = Cont.getAsRegion(); 396*5ffd83dbSDimitry Andric if (!ContReg) 397*5ffd83dbSDimitry Andric return; 398*5ffd83dbSDimitry Andric 399*5ffd83dbSDimitry Andric ContReg = ContReg->getMostDerivedObjectRegion(); 400*5ffd83dbSDimitry Andric 401*5ffd83dbSDimitry Andric // The clear() operation invalidates all the iterators, except the past-end 402*5ffd83dbSDimitry Andric // iterators of list-like containers 403*5ffd83dbSDimitry Andric auto State = C.getState(); 404*5ffd83dbSDimitry Andric if (!hasSubscriptOperator(State, ContReg) || 405*5ffd83dbSDimitry Andric !backModifiable(State, ContReg)) { 406*5ffd83dbSDimitry Andric const auto CData = getContainerData(State, ContReg); 407*5ffd83dbSDimitry Andric if (CData) { 408*5ffd83dbSDimitry Andric if (const auto EndSym = CData->getEnd()) { 409*5ffd83dbSDimitry Andric State = 410*5ffd83dbSDimitry Andric invalidateAllIteratorPositionsExcept(State, ContReg, EndSym, BO_GE); 411*5ffd83dbSDimitry Andric C.addTransition(State); 412*5ffd83dbSDimitry Andric return; 413*5ffd83dbSDimitry Andric } 414*5ffd83dbSDimitry Andric } 415*5ffd83dbSDimitry Andric } 416*5ffd83dbSDimitry Andric const NoteTag *ChangeTag = 417*5ffd83dbSDimitry Andric getChangeTag(C, "became empty", ContReg, ContE); 418*5ffd83dbSDimitry Andric State = invalidateAllIteratorPositions(State, ContReg); 419*5ffd83dbSDimitry Andric C.addTransition(State, ChangeTag); 420*5ffd83dbSDimitry Andric } 421*5ffd83dbSDimitry Andric 422*5ffd83dbSDimitry Andric void ContainerModeling::handlePushBack(CheckerContext &C, SVal Cont, 423*5ffd83dbSDimitry Andric const Expr *ContE) const { 424*5ffd83dbSDimitry Andric const auto *ContReg = Cont.getAsRegion(); 425*5ffd83dbSDimitry Andric if (!ContReg) 426*5ffd83dbSDimitry Andric return; 427*5ffd83dbSDimitry Andric 428*5ffd83dbSDimitry Andric ContReg = ContReg->getMostDerivedObjectRegion(); 429*5ffd83dbSDimitry Andric 430*5ffd83dbSDimitry Andric // For deque-like containers invalidate all iterator positions 431*5ffd83dbSDimitry Andric auto State = C.getState(); 432*5ffd83dbSDimitry Andric if (hasSubscriptOperator(State, ContReg) && frontModifiable(State, ContReg)) { 433*5ffd83dbSDimitry Andric State = invalidateAllIteratorPositions(State, ContReg); 434*5ffd83dbSDimitry Andric C.addTransition(State); 435*5ffd83dbSDimitry Andric return; 436*5ffd83dbSDimitry Andric } 437*5ffd83dbSDimitry Andric 438*5ffd83dbSDimitry Andric const auto CData = getContainerData(State, ContReg); 439*5ffd83dbSDimitry Andric if (!CData) 440*5ffd83dbSDimitry Andric return; 441*5ffd83dbSDimitry Andric 442*5ffd83dbSDimitry Andric // For vector-like containers invalidate the past-end iterator positions 443*5ffd83dbSDimitry Andric if (const auto EndSym = CData->getEnd()) { 444*5ffd83dbSDimitry Andric if (hasSubscriptOperator(State, ContReg)) { 445*5ffd83dbSDimitry Andric State = invalidateIteratorPositions(State, EndSym, BO_GE); 446*5ffd83dbSDimitry Andric } 447*5ffd83dbSDimitry Andric auto &SymMgr = C.getSymbolManager(); 448*5ffd83dbSDimitry Andric auto &BVF = SymMgr.getBasicVals(); 449*5ffd83dbSDimitry Andric auto &SVB = C.getSValBuilder(); 450*5ffd83dbSDimitry Andric const auto newEndSym = 451*5ffd83dbSDimitry Andric SVB.evalBinOp(State, BO_Add, 452*5ffd83dbSDimitry Andric nonloc::SymbolVal(EndSym), 453*5ffd83dbSDimitry Andric nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))), 454*5ffd83dbSDimitry Andric SymMgr.getType(EndSym)).getAsSymbol(); 455*5ffd83dbSDimitry Andric const NoteTag *ChangeTag = 456*5ffd83dbSDimitry Andric getChangeTag(C, "extended to the back by 1 position", ContReg, ContE); 457*5ffd83dbSDimitry Andric State = setContainerData(State, ContReg, CData->newEnd(newEndSym)); 458*5ffd83dbSDimitry Andric C.addTransition(State, ChangeTag); 459*5ffd83dbSDimitry Andric } 460*5ffd83dbSDimitry Andric } 461*5ffd83dbSDimitry Andric 462*5ffd83dbSDimitry Andric void ContainerModeling::handlePopBack(CheckerContext &C, SVal Cont, 463*5ffd83dbSDimitry Andric const Expr *ContE) const { 464*5ffd83dbSDimitry Andric const auto *ContReg = Cont.getAsRegion(); 465*5ffd83dbSDimitry Andric if (!ContReg) 466*5ffd83dbSDimitry Andric return; 467*5ffd83dbSDimitry Andric 468*5ffd83dbSDimitry Andric ContReg = ContReg->getMostDerivedObjectRegion(); 469*5ffd83dbSDimitry Andric 470*5ffd83dbSDimitry Andric auto State = C.getState(); 471*5ffd83dbSDimitry Andric const auto CData = getContainerData(State, ContReg); 472*5ffd83dbSDimitry Andric if (!CData) 473*5ffd83dbSDimitry Andric return; 474*5ffd83dbSDimitry Andric 475*5ffd83dbSDimitry Andric if (const auto EndSym = CData->getEnd()) { 476*5ffd83dbSDimitry Andric auto &SymMgr = C.getSymbolManager(); 477*5ffd83dbSDimitry Andric auto &BVF = SymMgr.getBasicVals(); 478*5ffd83dbSDimitry Andric auto &SVB = C.getSValBuilder(); 479*5ffd83dbSDimitry Andric const auto BackSym = 480*5ffd83dbSDimitry Andric SVB.evalBinOp(State, BO_Sub, 481*5ffd83dbSDimitry Andric nonloc::SymbolVal(EndSym), 482*5ffd83dbSDimitry Andric nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))), 483*5ffd83dbSDimitry Andric SymMgr.getType(EndSym)).getAsSymbol(); 484*5ffd83dbSDimitry Andric const NoteTag *ChangeTag = 485*5ffd83dbSDimitry Andric getChangeTag(C, "shrank from the back by 1 position", ContReg, ContE); 486*5ffd83dbSDimitry Andric // For vector-like and deque-like containers invalidate the last and the 487*5ffd83dbSDimitry Andric // past-end iterator positions. For list-like containers only invalidate 488*5ffd83dbSDimitry Andric // the last position 489*5ffd83dbSDimitry Andric if (hasSubscriptOperator(State, ContReg) && 490*5ffd83dbSDimitry Andric backModifiable(State, ContReg)) { 491*5ffd83dbSDimitry Andric State = invalidateIteratorPositions(State, BackSym, BO_GE); 492*5ffd83dbSDimitry Andric State = setContainerData(State, ContReg, CData->newEnd(nullptr)); 493*5ffd83dbSDimitry Andric } else { 494*5ffd83dbSDimitry Andric State = invalidateIteratorPositions(State, BackSym, BO_EQ); 495*5ffd83dbSDimitry Andric } 496*5ffd83dbSDimitry Andric auto newEndSym = BackSym; 497*5ffd83dbSDimitry Andric State = setContainerData(State, ContReg, CData->newEnd(newEndSym)); 498*5ffd83dbSDimitry Andric C.addTransition(State, ChangeTag); 499*5ffd83dbSDimitry Andric } 500*5ffd83dbSDimitry Andric } 501*5ffd83dbSDimitry Andric 502*5ffd83dbSDimitry Andric void ContainerModeling::handlePushFront(CheckerContext &C, SVal Cont, 503*5ffd83dbSDimitry Andric const Expr *ContE) const { 504*5ffd83dbSDimitry Andric const auto *ContReg = Cont.getAsRegion(); 505*5ffd83dbSDimitry Andric if (!ContReg) 506*5ffd83dbSDimitry Andric return; 507*5ffd83dbSDimitry Andric 508*5ffd83dbSDimitry Andric ContReg = ContReg->getMostDerivedObjectRegion(); 509*5ffd83dbSDimitry Andric 510*5ffd83dbSDimitry Andric // For deque-like containers invalidate all iterator positions 511*5ffd83dbSDimitry Andric auto State = C.getState(); 512*5ffd83dbSDimitry Andric if (hasSubscriptOperator(State, ContReg)) { 513*5ffd83dbSDimitry Andric State = invalidateAllIteratorPositions(State, ContReg); 514*5ffd83dbSDimitry Andric C.addTransition(State); 515*5ffd83dbSDimitry Andric } else { 516*5ffd83dbSDimitry Andric const auto CData = getContainerData(State, ContReg); 517*5ffd83dbSDimitry Andric if (!CData) 518*5ffd83dbSDimitry Andric return; 519*5ffd83dbSDimitry Andric 520*5ffd83dbSDimitry Andric if (const auto BeginSym = CData->getBegin()) { 521*5ffd83dbSDimitry Andric auto &SymMgr = C.getSymbolManager(); 522*5ffd83dbSDimitry Andric auto &BVF = SymMgr.getBasicVals(); 523*5ffd83dbSDimitry Andric auto &SVB = C.getSValBuilder(); 524*5ffd83dbSDimitry Andric const auto newBeginSym = 525*5ffd83dbSDimitry Andric SVB.evalBinOp(State, BO_Sub, 526*5ffd83dbSDimitry Andric nonloc::SymbolVal(BeginSym), 527*5ffd83dbSDimitry Andric nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))), 528*5ffd83dbSDimitry Andric SymMgr.getType(BeginSym)).getAsSymbol(); 529*5ffd83dbSDimitry Andric const NoteTag *ChangeTag = 530*5ffd83dbSDimitry Andric getChangeTag(C, "extended to the front by 1 position", ContReg, ContE); 531*5ffd83dbSDimitry Andric State = setContainerData(State, ContReg, CData->newBegin(newBeginSym)); 532*5ffd83dbSDimitry Andric C.addTransition(State, ChangeTag); 533*5ffd83dbSDimitry Andric } 534*5ffd83dbSDimitry Andric } 535*5ffd83dbSDimitry Andric } 536*5ffd83dbSDimitry Andric 537*5ffd83dbSDimitry Andric void ContainerModeling::handlePopFront(CheckerContext &C, SVal Cont, 538*5ffd83dbSDimitry Andric const Expr *ContE) const { 539*5ffd83dbSDimitry Andric const auto *ContReg = Cont.getAsRegion(); 540*5ffd83dbSDimitry Andric if (!ContReg) 541*5ffd83dbSDimitry Andric return; 542*5ffd83dbSDimitry Andric 543*5ffd83dbSDimitry Andric ContReg = ContReg->getMostDerivedObjectRegion(); 544*5ffd83dbSDimitry Andric 545*5ffd83dbSDimitry Andric auto State = C.getState(); 546*5ffd83dbSDimitry Andric const auto CData = getContainerData(State, ContReg); 547*5ffd83dbSDimitry Andric if (!CData) 548*5ffd83dbSDimitry Andric return; 549*5ffd83dbSDimitry Andric 550*5ffd83dbSDimitry Andric // For deque-like containers invalidate all iterator positions. For list-like 551*5ffd83dbSDimitry Andric // iterators only invalidate the first position 552*5ffd83dbSDimitry Andric if (const auto BeginSym = CData->getBegin()) { 553*5ffd83dbSDimitry Andric if (hasSubscriptOperator(State, ContReg)) { 554*5ffd83dbSDimitry Andric State = invalidateIteratorPositions(State, BeginSym, BO_LE); 555*5ffd83dbSDimitry Andric } else { 556*5ffd83dbSDimitry Andric State = invalidateIteratorPositions(State, BeginSym, BO_EQ); 557*5ffd83dbSDimitry Andric } 558*5ffd83dbSDimitry Andric auto &SymMgr = C.getSymbolManager(); 559*5ffd83dbSDimitry Andric auto &BVF = SymMgr.getBasicVals(); 560*5ffd83dbSDimitry Andric auto &SVB = C.getSValBuilder(); 561*5ffd83dbSDimitry Andric const auto newBeginSym = 562*5ffd83dbSDimitry Andric SVB.evalBinOp(State, BO_Add, 563*5ffd83dbSDimitry Andric nonloc::SymbolVal(BeginSym), 564*5ffd83dbSDimitry Andric nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))), 565*5ffd83dbSDimitry Andric SymMgr.getType(BeginSym)).getAsSymbol(); 566*5ffd83dbSDimitry Andric const NoteTag *ChangeTag = 567*5ffd83dbSDimitry Andric getChangeTag(C, "shrank from the front by 1 position", ContReg, ContE); 568*5ffd83dbSDimitry Andric State = setContainerData(State, ContReg, CData->newBegin(newBeginSym)); 569*5ffd83dbSDimitry Andric C.addTransition(State, ChangeTag); 570*5ffd83dbSDimitry Andric } 571*5ffd83dbSDimitry Andric } 572*5ffd83dbSDimitry Andric 573*5ffd83dbSDimitry Andric void ContainerModeling::handleInsert(CheckerContext &C, SVal Cont, 574*5ffd83dbSDimitry Andric SVal Iter) const { 575*5ffd83dbSDimitry Andric const auto *ContReg = Cont.getAsRegion(); 576*5ffd83dbSDimitry Andric if (!ContReg) 577*5ffd83dbSDimitry Andric return; 578*5ffd83dbSDimitry Andric 579*5ffd83dbSDimitry Andric ContReg = ContReg->getMostDerivedObjectRegion(); 580*5ffd83dbSDimitry Andric 581*5ffd83dbSDimitry Andric auto State = C.getState(); 582*5ffd83dbSDimitry Andric const auto *Pos = getIteratorPosition(State, Iter); 583*5ffd83dbSDimitry Andric if (!Pos) 584*5ffd83dbSDimitry Andric return; 585*5ffd83dbSDimitry Andric 586*5ffd83dbSDimitry Andric // For deque-like containers invalidate all iterator positions. For 587*5ffd83dbSDimitry Andric // vector-like containers invalidate iterator positions after the insertion. 588*5ffd83dbSDimitry Andric if (hasSubscriptOperator(State, ContReg) && backModifiable(State, ContReg)) { 589*5ffd83dbSDimitry Andric if (frontModifiable(State, ContReg)) { 590*5ffd83dbSDimitry Andric State = invalidateAllIteratorPositions(State, ContReg); 591*5ffd83dbSDimitry Andric } else { 592*5ffd83dbSDimitry Andric State = invalidateIteratorPositions(State, Pos->getOffset(), BO_GE); 593*5ffd83dbSDimitry Andric } 594*5ffd83dbSDimitry Andric if (const auto *CData = getContainerData(State, ContReg)) { 595*5ffd83dbSDimitry Andric if (const auto EndSym = CData->getEnd()) { 596*5ffd83dbSDimitry Andric State = invalidateIteratorPositions(State, EndSym, BO_GE); 597*5ffd83dbSDimitry Andric State = setContainerData(State, ContReg, CData->newEnd(nullptr)); 598*5ffd83dbSDimitry Andric } 599*5ffd83dbSDimitry Andric } 600*5ffd83dbSDimitry Andric C.addTransition(State); 601*5ffd83dbSDimitry Andric } 602*5ffd83dbSDimitry Andric } 603*5ffd83dbSDimitry Andric 604*5ffd83dbSDimitry Andric void ContainerModeling::handleErase(CheckerContext &C, SVal Cont, 605*5ffd83dbSDimitry Andric SVal Iter) const { 606*5ffd83dbSDimitry Andric const auto *ContReg = Cont.getAsRegion(); 607*5ffd83dbSDimitry Andric if (!ContReg) 608*5ffd83dbSDimitry Andric return; 609*5ffd83dbSDimitry Andric 610*5ffd83dbSDimitry Andric ContReg = ContReg->getMostDerivedObjectRegion(); 611*5ffd83dbSDimitry Andric 612*5ffd83dbSDimitry Andric auto State = C.getState(); 613*5ffd83dbSDimitry Andric const auto *Pos = getIteratorPosition(State, Iter); 614*5ffd83dbSDimitry Andric if (!Pos) 615*5ffd83dbSDimitry Andric return; 616*5ffd83dbSDimitry Andric 617*5ffd83dbSDimitry Andric // For deque-like containers invalidate all iterator positions. For 618*5ffd83dbSDimitry Andric // vector-like containers invalidate iterator positions at and after the 619*5ffd83dbSDimitry Andric // deletion. For list-like containers only invalidate the deleted position. 620*5ffd83dbSDimitry Andric if (hasSubscriptOperator(State, ContReg) && backModifiable(State, ContReg)) { 621*5ffd83dbSDimitry Andric if (frontModifiable(State, ContReg)) { 622*5ffd83dbSDimitry Andric State = invalidateAllIteratorPositions(State, ContReg); 623*5ffd83dbSDimitry Andric } else { 624*5ffd83dbSDimitry Andric State = invalidateIteratorPositions(State, Pos->getOffset(), BO_GE); 625*5ffd83dbSDimitry Andric } 626*5ffd83dbSDimitry Andric if (const auto *CData = getContainerData(State, ContReg)) { 627*5ffd83dbSDimitry Andric if (const auto EndSym = CData->getEnd()) { 628*5ffd83dbSDimitry Andric State = invalidateIteratorPositions(State, EndSym, BO_GE); 629*5ffd83dbSDimitry Andric State = setContainerData(State, ContReg, CData->newEnd(nullptr)); 630*5ffd83dbSDimitry Andric } 631*5ffd83dbSDimitry Andric } 632*5ffd83dbSDimitry Andric } else { 633*5ffd83dbSDimitry Andric State = invalidateIteratorPositions(State, Pos->getOffset(), BO_EQ); 634*5ffd83dbSDimitry Andric } 635*5ffd83dbSDimitry Andric C.addTransition(State); 636*5ffd83dbSDimitry Andric } 637*5ffd83dbSDimitry Andric 638*5ffd83dbSDimitry Andric void ContainerModeling::handleErase(CheckerContext &C, SVal Cont, SVal Iter1, 639*5ffd83dbSDimitry Andric SVal Iter2) const { 640*5ffd83dbSDimitry Andric const auto *ContReg = Cont.getAsRegion(); 641*5ffd83dbSDimitry Andric if (!ContReg) 642*5ffd83dbSDimitry Andric return; 643*5ffd83dbSDimitry Andric 644*5ffd83dbSDimitry Andric ContReg = ContReg->getMostDerivedObjectRegion(); 645*5ffd83dbSDimitry Andric auto State = C.getState(); 646*5ffd83dbSDimitry Andric const auto *Pos1 = getIteratorPosition(State, Iter1); 647*5ffd83dbSDimitry Andric const auto *Pos2 = getIteratorPosition(State, Iter2); 648*5ffd83dbSDimitry Andric if (!Pos1 || !Pos2) 649*5ffd83dbSDimitry Andric return; 650*5ffd83dbSDimitry Andric 651*5ffd83dbSDimitry Andric // For deque-like containers invalidate all iterator positions. For 652*5ffd83dbSDimitry Andric // vector-like containers invalidate iterator positions at and after the 653*5ffd83dbSDimitry Andric // deletion range. For list-like containers only invalidate the deleted 654*5ffd83dbSDimitry Andric // position range [first..last]. 655*5ffd83dbSDimitry Andric if (hasSubscriptOperator(State, ContReg) && backModifiable(State, ContReg)) { 656*5ffd83dbSDimitry Andric if (frontModifiable(State, ContReg)) { 657*5ffd83dbSDimitry Andric State = invalidateAllIteratorPositions(State, ContReg); 658*5ffd83dbSDimitry Andric } else { 659*5ffd83dbSDimitry Andric State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GE); 660*5ffd83dbSDimitry Andric } 661*5ffd83dbSDimitry Andric if (const auto *CData = getContainerData(State, ContReg)) { 662*5ffd83dbSDimitry Andric if (const auto EndSym = CData->getEnd()) { 663*5ffd83dbSDimitry Andric State = invalidateIteratorPositions(State, EndSym, BO_GE); 664*5ffd83dbSDimitry Andric State = setContainerData(State, ContReg, CData->newEnd(nullptr)); 665*5ffd83dbSDimitry Andric } 666*5ffd83dbSDimitry Andric } 667*5ffd83dbSDimitry Andric } else { 668*5ffd83dbSDimitry Andric State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GE, 669*5ffd83dbSDimitry Andric Pos2->getOffset(), BO_LT); 670*5ffd83dbSDimitry Andric } 671*5ffd83dbSDimitry Andric C.addTransition(State); 672*5ffd83dbSDimitry Andric } 673*5ffd83dbSDimitry Andric 674*5ffd83dbSDimitry Andric void ContainerModeling::handleEraseAfter(CheckerContext &C, SVal Cont, 675*5ffd83dbSDimitry Andric SVal Iter) const { 676*5ffd83dbSDimitry Andric auto State = C.getState(); 677*5ffd83dbSDimitry Andric const auto *Pos = getIteratorPosition(State, Iter); 678*5ffd83dbSDimitry Andric if (!Pos) 679*5ffd83dbSDimitry Andric return; 680*5ffd83dbSDimitry Andric 681*5ffd83dbSDimitry Andric // Invalidate the deleted iterator position, which is the position of the 682*5ffd83dbSDimitry Andric // parameter plus one. 683*5ffd83dbSDimitry Andric auto &SymMgr = C.getSymbolManager(); 684*5ffd83dbSDimitry Andric auto &BVF = SymMgr.getBasicVals(); 685*5ffd83dbSDimitry Andric auto &SVB = C.getSValBuilder(); 686*5ffd83dbSDimitry Andric const auto NextSym = 687*5ffd83dbSDimitry Andric SVB.evalBinOp(State, BO_Add, 688*5ffd83dbSDimitry Andric nonloc::SymbolVal(Pos->getOffset()), 689*5ffd83dbSDimitry Andric nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))), 690*5ffd83dbSDimitry Andric SymMgr.getType(Pos->getOffset())).getAsSymbol(); 691*5ffd83dbSDimitry Andric State = invalidateIteratorPositions(State, NextSym, BO_EQ); 692*5ffd83dbSDimitry Andric C.addTransition(State); 693*5ffd83dbSDimitry Andric } 694*5ffd83dbSDimitry Andric 695*5ffd83dbSDimitry Andric void ContainerModeling::handleEraseAfter(CheckerContext &C, SVal Cont, 696*5ffd83dbSDimitry Andric SVal Iter1, SVal Iter2) const { 697*5ffd83dbSDimitry Andric auto State = C.getState(); 698*5ffd83dbSDimitry Andric const auto *Pos1 = getIteratorPosition(State, Iter1); 699*5ffd83dbSDimitry Andric const auto *Pos2 = getIteratorPosition(State, Iter2); 700*5ffd83dbSDimitry Andric if (!Pos1 || !Pos2) 701*5ffd83dbSDimitry Andric return; 702*5ffd83dbSDimitry Andric 703*5ffd83dbSDimitry Andric // Invalidate the deleted iterator position range (first..last) 704*5ffd83dbSDimitry Andric State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GT, 705*5ffd83dbSDimitry Andric Pos2->getOffset(), BO_LT); 706*5ffd83dbSDimitry Andric C.addTransition(State); 707*5ffd83dbSDimitry Andric } 708*5ffd83dbSDimitry Andric 709*5ffd83dbSDimitry Andric const NoteTag *ContainerModeling::getChangeTag(CheckerContext &C, 710*5ffd83dbSDimitry Andric StringRef Text, 711*5ffd83dbSDimitry Andric const MemRegion *ContReg, 712*5ffd83dbSDimitry Andric const Expr *ContE) const { 713*5ffd83dbSDimitry Andric StringRef Name; 714*5ffd83dbSDimitry Andric // First try to get the name of the variable from the region 715*5ffd83dbSDimitry Andric if (const auto *DR = dyn_cast<DeclRegion>(ContReg)) { 716*5ffd83dbSDimitry Andric Name = DR->getDecl()->getName(); 717*5ffd83dbSDimitry Andric // If the region is not a `DeclRegion` then use the expression instead 718*5ffd83dbSDimitry Andric } else if (const auto *DRE = 719*5ffd83dbSDimitry Andric dyn_cast<DeclRefExpr>(ContE->IgnoreParenCasts())) { 720*5ffd83dbSDimitry Andric Name = DRE->getDecl()->getName(); 721*5ffd83dbSDimitry Andric } 722*5ffd83dbSDimitry Andric 723*5ffd83dbSDimitry Andric return C.getNoteTag( 724*5ffd83dbSDimitry Andric [Text, Name, ContReg](PathSensitiveBugReport &BR) -> std::string { 725*5ffd83dbSDimitry Andric if (!BR.isInteresting(ContReg)) 726*5ffd83dbSDimitry Andric return ""; 727*5ffd83dbSDimitry Andric 728*5ffd83dbSDimitry Andric SmallString<256> Msg; 729*5ffd83dbSDimitry Andric llvm::raw_svector_ostream Out(Msg); 730*5ffd83dbSDimitry Andric Out << "Container " << (!Name.empty() ? ("'" + Name.str() + "' ") : "" ) 731*5ffd83dbSDimitry Andric << Text; 732*5ffd83dbSDimitry Andric return std::string(Out.str()); 733*5ffd83dbSDimitry Andric }); 734*5ffd83dbSDimitry Andric } 735*5ffd83dbSDimitry Andric 736*5ffd83dbSDimitry Andric void ContainerModeling::printState(raw_ostream &Out, ProgramStateRef State, 737*5ffd83dbSDimitry Andric const char *NL, const char *Sep) const { 738*5ffd83dbSDimitry Andric auto ContMap = State->get<ContainerMap>(); 739*5ffd83dbSDimitry Andric 740*5ffd83dbSDimitry Andric if (!ContMap.isEmpty()) { 741*5ffd83dbSDimitry Andric Out << Sep << "Container Data :" << NL; 742*5ffd83dbSDimitry Andric for (const auto &Cont : ContMap) { 743*5ffd83dbSDimitry Andric Cont.first->dumpToStream(Out); 744*5ffd83dbSDimitry Andric Out << " : [ "; 745*5ffd83dbSDimitry Andric const auto CData = Cont.second; 746*5ffd83dbSDimitry Andric if (CData.getBegin()) 747*5ffd83dbSDimitry Andric CData.getBegin()->dumpToStream(Out); 748*5ffd83dbSDimitry Andric else 749*5ffd83dbSDimitry Andric Out << "<Unknown>"; 750*5ffd83dbSDimitry Andric Out << " .. "; 751*5ffd83dbSDimitry Andric if (CData.getEnd()) 752*5ffd83dbSDimitry Andric CData.getEnd()->dumpToStream(Out); 753*5ffd83dbSDimitry Andric else 754*5ffd83dbSDimitry Andric Out << "<Unknown>"; 755*5ffd83dbSDimitry Andric Out << " ]"; 756*5ffd83dbSDimitry Andric } 757*5ffd83dbSDimitry Andric } 758*5ffd83dbSDimitry Andric } 759*5ffd83dbSDimitry Andric 760*5ffd83dbSDimitry Andric namespace { 761*5ffd83dbSDimitry Andric 762*5ffd83dbSDimitry Andric bool isBeginCall(const FunctionDecl *Func) { 763*5ffd83dbSDimitry Andric const auto *IdInfo = Func->getIdentifier(); 764*5ffd83dbSDimitry Andric if (!IdInfo) 765*5ffd83dbSDimitry Andric return false; 766*5ffd83dbSDimitry Andric return IdInfo->getName().endswith_lower("begin"); 767*5ffd83dbSDimitry Andric } 768*5ffd83dbSDimitry Andric 769*5ffd83dbSDimitry Andric bool isEndCall(const FunctionDecl *Func) { 770*5ffd83dbSDimitry Andric const auto *IdInfo = Func->getIdentifier(); 771*5ffd83dbSDimitry Andric if (!IdInfo) 772*5ffd83dbSDimitry Andric return false; 773*5ffd83dbSDimitry Andric return IdInfo->getName().endswith_lower("end"); 774*5ffd83dbSDimitry Andric } 775*5ffd83dbSDimitry Andric 776*5ffd83dbSDimitry Andric const CXXRecordDecl *getCXXRecordDecl(ProgramStateRef State, 777*5ffd83dbSDimitry Andric const MemRegion *Reg) { 778*5ffd83dbSDimitry Andric auto TI = getDynamicTypeInfo(State, Reg); 779*5ffd83dbSDimitry Andric if (!TI.isValid()) 780*5ffd83dbSDimitry Andric return nullptr; 781*5ffd83dbSDimitry Andric 782*5ffd83dbSDimitry Andric auto Type = TI.getType(); 783*5ffd83dbSDimitry Andric if (const auto *RefT = Type->getAs<ReferenceType>()) { 784*5ffd83dbSDimitry Andric Type = RefT->getPointeeType(); 785*5ffd83dbSDimitry Andric } 786*5ffd83dbSDimitry Andric 787*5ffd83dbSDimitry Andric return Type->getUnqualifiedDesugaredType()->getAsCXXRecordDecl(); 788*5ffd83dbSDimitry Andric } 789*5ffd83dbSDimitry Andric 790*5ffd83dbSDimitry Andric bool hasSubscriptOperator(ProgramStateRef State, const MemRegion *Reg) { 791*5ffd83dbSDimitry Andric const auto *CRD = getCXXRecordDecl(State, Reg); 792*5ffd83dbSDimitry Andric if (!CRD) 793*5ffd83dbSDimitry Andric return false; 794*5ffd83dbSDimitry Andric 795*5ffd83dbSDimitry Andric for (const auto *Method : CRD->methods()) { 796*5ffd83dbSDimitry Andric if (!Method->isOverloadedOperator()) 797*5ffd83dbSDimitry Andric continue; 798*5ffd83dbSDimitry Andric const auto OPK = Method->getOverloadedOperator(); 799*5ffd83dbSDimitry Andric if (OPK == OO_Subscript) { 800*5ffd83dbSDimitry Andric return true; 801*5ffd83dbSDimitry Andric } 802*5ffd83dbSDimitry Andric } 803*5ffd83dbSDimitry Andric return false; 804*5ffd83dbSDimitry Andric } 805*5ffd83dbSDimitry Andric 806*5ffd83dbSDimitry Andric bool frontModifiable(ProgramStateRef State, const MemRegion *Reg) { 807*5ffd83dbSDimitry Andric const auto *CRD = getCXXRecordDecl(State, Reg); 808*5ffd83dbSDimitry Andric if (!CRD) 809*5ffd83dbSDimitry Andric return false; 810*5ffd83dbSDimitry Andric 811*5ffd83dbSDimitry Andric for (const auto *Method : CRD->methods()) { 812*5ffd83dbSDimitry Andric if (!Method->getDeclName().isIdentifier()) 813*5ffd83dbSDimitry Andric continue; 814*5ffd83dbSDimitry Andric if (Method->getName() == "push_front" || Method->getName() == "pop_front") { 815*5ffd83dbSDimitry Andric return true; 816*5ffd83dbSDimitry Andric } 817*5ffd83dbSDimitry Andric } 818*5ffd83dbSDimitry Andric return false; 819*5ffd83dbSDimitry Andric } 820*5ffd83dbSDimitry Andric 821*5ffd83dbSDimitry Andric bool backModifiable(ProgramStateRef State, const MemRegion *Reg) { 822*5ffd83dbSDimitry Andric const auto *CRD = getCXXRecordDecl(State, Reg); 823*5ffd83dbSDimitry Andric if (!CRD) 824*5ffd83dbSDimitry Andric return false; 825*5ffd83dbSDimitry Andric 826*5ffd83dbSDimitry Andric for (const auto *Method : CRD->methods()) { 827*5ffd83dbSDimitry Andric if (!Method->getDeclName().isIdentifier()) 828*5ffd83dbSDimitry Andric continue; 829*5ffd83dbSDimitry Andric if (Method->getName() == "push_back" || Method->getName() == "pop_back") { 830*5ffd83dbSDimitry Andric return true; 831*5ffd83dbSDimitry Andric } 832*5ffd83dbSDimitry Andric } 833*5ffd83dbSDimitry Andric return false; 834*5ffd83dbSDimitry Andric } 835*5ffd83dbSDimitry Andric 836*5ffd83dbSDimitry Andric SymbolRef getContainerBegin(ProgramStateRef State, const MemRegion *Cont) { 837*5ffd83dbSDimitry Andric const auto *CDataPtr = getContainerData(State, Cont); 838*5ffd83dbSDimitry Andric if (!CDataPtr) 839*5ffd83dbSDimitry Andric return nullptr; 840*5ffd83dbSDimitry Andric 841*5ffd83dbSDimitry Andric return CDataPtr->getBegin(); 842*5ffd83dbSDimitry Andric } 843*5ffd83dbSDimitry Andric 844*5ffd83dbSDimitry Andric SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont) { 845*5ffd83dbSDimitry Andric const auto *CDataPtr = getContainerData(State, Cont); 846*5ffd83dbSDimitry Andric if (!CDataPtr) 847*5ffd83dbSDimitry Andric return nullptr; 848*5ffd83dbSDimitry Andric 849*5ffd83dbSDimitry Andric return CDataPtr->getEnd(); 850*5ffd83dbSDimitry Andric } 851*5ffd83dbSDimitry Andric 852*5ffd83dbSDimitry Andric ProgramStateRef createContainerBegin(ProgramStateRef State, 853*5ffd83dbSDimitry Andric const MemRegion *Cont, const Expr *E, 854*5ffd83dbSDimitry Andric QualType T, const LocationContext *LCtx, 855*5ffd83dbSDimitry Andric unsigned BlockCount) { 856*5ffd83dbSDimitry Andric // Only create if it does not exist 857*5ffd83dbSDimitry Andric const auto *CDataPtr = getContainerData(State, Cont); 858*5ffd83dbSDimitry Andric if (CDataPtr && CDataPtr->getBegin()) 859*5ffd83dbSDimitry Andric return State; 860*5ffd83dbSDimitry Andric 861*5ffd83dbSDimitry Andric auto &SymMgr = State->getSymbolManager(); 862*5ffd83dbSDimitry Andric const SymbolConjured *Sym = SymMgr.conjureSymbol(E, LCtx, T, BlockCount, 863*5ffd83dbSDimitry Andric "begin"); 864*5ffd83dbSDimitry Andric State = assumeNoOverflow(State, Sym, 4); 865*5ffd83dbSDimitry Andric 866*5ffd83dbSDimitry Andric if (CDataPtr) { 867*5ffd83dbSDimitry Andric const auto CData = CDataPtr->newBegin(Sym); 868*5ffd83dbSDimitry Andric return setContainerData(State, Cont, CData); 869*5ffd83dbSDimitry Andric } 870*5ffd83dbSDimitry Andric 871*5ffd83dbSDimitry Andric const auto CData = ContainerData::fromBegin(Sym); 872*5ffd83dbSDimitry Andric return setContainerData(State, Cont, CData); 873*5ffd83dbSDimitry Andric } 874*5ffd83dbSDimitry Andric 875*5ffd83dbSDimitry Andric ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont, 876*5ffd83dbSDimitry Andric const Expr *E, QualType T, 877*5ffd83dbSDimitry Andric const LocationContext *LCtx, 878*5ffd83dbSDimitry Andric unsigned BlockCount) { 879*5ffd83dbSDimitry Andric // Only create if it does not exist 880*5ffd83dbSDimitry Andric const auto *CDataPtr = getContainerData(State, Cont); 881*5ffd83dbSDimitry Andric if (CDataPtr && CDataPtr->getEnd()) 882*5ffd83dbSDimitry Andric return State; 883*5ffd83dbSDimitry Andric 884*5ffd83dbSDimitry Andric auto &SymMgr = State->getSymbolManager(); 885*5ffd83dbSDimitry Andric const SymbolConjured *Sym = SymMgr.conjureSymbol(E, LCtx, T, BlockCount, 886*5ffd83dbSDimitry Andric "end"); 887*5ffd83dbSDimitry Andric State = assumeNoOverflow(State, Sym, 4); 888*5ffd83dbSDimitry Andric 889*5ffd83dbSDimitry Andric if (CDataPtr) { 890*5ffd83dbSDimitry Andric const auto CData = CDataPtr->newEnd(Sym); 891*5ffd83dbSDimitry Andric return setContainerData(State, Cont, CData); 892*5ffd83dbSDimitry Andric } 893*5ffd83dbSDimitry Andric 894*5ffd83dbSDimitry Andric const auto CData = ContainerData::fromEnd(Sym); 895*5ffd83dbSDimitry Andric return setContainerData(State, Cont, CData); 896*5ffd83dbSDimitry Andric } 897*5ffd83dbSDimitry Andric 898*5ffd83dbSDimitry Andric ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont, 899*5ffd83dbSDimitry Andric const ContainerData &CData) { 900*5ffd83dbSDimitry Andric return State->set<ContainerMap>(Cont, CData); 901*5ffd83dbSDimitry Andric } 902*5ffd83dbSDimitry Andric 903*5ffd83dbSDimitry Andric template <typename Condition, typename Process> 904*5ffd83dbSDimitry Andric ProgramStateRef processIteratorPositions(ProgramStateRef State, Condition Cond, 905*5ffd83dbSDimitry Andric Process Proc) { 906*5ffd83dbSDimitry Andric auto &RegionMapFactory = State->get_context<IteratorRegionMap>(); 907*5ffd83dbSDimitry Andric auto RegionMap = State->get<IteratorRegionMap>(); 908*5ffd83dbSDimitry Andric bool Changed = false; 909*5ffd83dbSDimitry Andric for (const auto &Reg : RegionMap) { 910*5ffd83dbSDimitry Andric if (Cond(Reg.second)) { 911*5ffd83dbSDimitry Andric RegionMap = RegionMapFactory.add(RegionMap, Reg.first, Proc(Reg.second)); 912*5ffd83dbSDimitry Andric Changed = true; 913*5ffd83dbSDimitry Andric } 914*5ffd83dbSDimitry Andric } 915*5ffd83dbSDimitry Andric 916*5ffd83dbSDimitry Andric if (Changed) 917*5ffd83dbSDimitry Andric State = State->set<IteratorRegionMap>(RegionMap); 918*5ffd83dbSDimitry Andric 919*5ffd83dbSDimitry Andric auto &SymbolMapFactory = State->get_context<IteratorSymbolMap>(); 920*5ffd83dbSDimitry Andric auto SymbolMap = State->get<IteratorSymbolMap>(); 921*5ffd83dbSDimitry Andric Changed = false; 922*5ffd83dbSDimitry Andric for (const auto &Sym : SymbolMap) { 923*5ffd83dbSDimitry Andric if (Cond(Sym.second)) { 924*5ffd83dbSDimitry Andric SymbolMap = SymbolMapFactory.add(SymbolMap, Sym.first, Proc(Sym.second)); 925*5ffd83dbSDimitry Andric Changed = true; 926*5ffd83dbSDimitry Andric } 927*5ffd83dbSDimitry Andric } 928*5ffd83dbSDimitry Andric 929*5ffd83dbSDimitry Andric if (Changed) 930*5ffd83dbSDimitry Andric State = State->set<IteratorSymbolMap>(SymbolMap); 931*5ffd83dbSDimitry Andric 932*5ffd83dbSDimitry Andric return State; 933*5ffd83dbSDimitry Andric } 934*5ffd83dbSDimitry Andric 935*5ffd83dbSDimitry Andric ProgramStateRef invalidateAllIteratorPositions(ProgramStateRef State, 936*5ffd83dbSDimitry Andric const MemRegion *Cont) { 937*5ffd83dbSDimitry Andric auto MatchCont = [&](const IteratorPosition &Pos) { 938*5ffd83dbSDimitry Andric return Pos.getContainer() == Cont; 939*5ffd83dbSDimitry Andric }; 940*5ffd83dbSDimitry Andric auto Invalidate = [&](const IteratorPosition &Pos) { 941*5ffd83dbSDimitry Andric return Pos.invalidate(); 942*5ffd83dbSDimitry Andric }; 943*5ffd83dbSDimitry Andric return processIteratorPositions(State, MatchCont, Invalidate); 944*5ffd83dbSDimitry Andric } 945*5ffd83dbSDimitry Andric 946*5ffd83dbSDimitry Andric ProgramStateRef 947*5ffd83dbSDimitry Andric invalidateAllIteratorPositionsExcept(ProgramStateRef State, 948*5ffd83dbSDimitry Andric const MemRegion *Cont, SymbolRef Offset, 949*5ffd83dbSDimitry Andric BinaryOperator::Opcode Opc) { 950*5ffd83dbSDimitry Andric auto MatchContAndCompare = [&](const IteratorPosition &Pos) { 951*5ffd83dbSDimitry Andric return Pos.getContainer() == Cont && 952*5ffd83dbSDimitry Andric !compare(State, Pos.getOffset(), Offset, Opc); 953*5ffd83dbSDimitry Andric }; 954*5ffd83dbSDimitry Andric auto Invalidate = [&](const IteratorPosition &Pos) { 955*5ffd83dbSDimitry Andric return Pos.invalidate(); 956*5ffd83dbSDimitry Andric }; 957*5ffd83dbSDimitry Andric return processIteratorPositions(State, MatchContAndCompare, Invalidate); 958*5ffd83dbSDimitry Andric } 959*5ffd83dbSDimitry Andric 960*5ffd83dbSDimitry Andric ProgramStateRef invalidateIteratorPositions(ProgramStateRef State, 961*5ffd83dbSDimitry Andric SymbolRef Offset, 962*5ffd83dbSDimitry Andric BinaryOperator::Opcode Opc) { 963*5ffd83dbSDimitry Andric auto Compare = [&](const IteratorPosition &Pos) { 964*5ffd83dbSDimitry Andric return compare(State, Pos.getOffset(), Offset, Opc); 965*5ffd83dbSDimitry Andric }; 966*5ffd83dbSDimitry Andric auto Invalidate = [&](const IteratorPosition &Pos) { 967*5ffd83dbSDimitry Andric return Pos.invalidate(); 968*5ffd83dbSDimitry Andric }; 969*5ffd83dbSDimitry Andric return processIteratorPositions(State, Compare, Invalidate); 970*5ffd83dbSDimitry Andric } 971*5ffd83dbSDimitry Andric 972*5ffd83dbSDimitry Andric ProgramStateRef invalidateIteratorPositions(ProgramStateRef State, 973*5ffd83dbSDimitry Andric SymbolRef Offset1, 974*5ffd83dbSDimitry Andric BinaryOperator::Opcode Opc1, 975*5ffd83dbSDimitry Andric SymbolRef Offset2, 976*5ffd83dbSDimitry Andric BinaryOperator::Opcode Opc2) { 977*5ffd83dbSDimitry Andric auto Compare = [&](const IteratorPosition &Pos) { 978*5ffd83dbSDimitry Andric return compare(State, Pos.getOffset(), Offset1, Opc1) && 979*5ffd83dbSDimitry Andric compare(State, Pos.getOffset(), Offset2, Opc2); 980*5ffd83dbSDimitry Andric }; 981*5ffd83dbSDimitry Andric auto Invalidate = [&](const IteratorPosition &Pos) { 982*5ffd83dbSDimitry Andric return Pos.invalidate(); 983*5ffd83dbSDimitry Andric }; 984*5ffd83dbSDimitry Andric return processIteratorPositions(State, Compare, Invalidate); 985*5ffd83dbSDimitry Andric } 986*5ffd83dbSDimitry Andric 987*5ffd83dbSDimitry Andric ProgramStateRef reassignAllIteratorPositions(ProgramStateRef State, 988*5ffd83dbSDimitry Andric const MemRegion *Cont, 989*5ffd83dbSDimitry Andric const MemRegion *NewCont) { 990*5ffd83dbSDimitry Andric auto MatchCont = [&](const IteratorPosition &Pos) { 991*5ffd83dbSDimitry Andric return Pos.getContainer() == Cont; 992*5ffd83dbSDimitry Andric }; 993*5ffd83dbSDimitry Andric auto ReAssign = [&](const IteratorPosition &Pos) { 994*5ffd83dbSDimitry Andric return Pos.reAssign(NewCont); 995*5ffd83dbSDimitry Andric }; 996*5ffd83dbSDimitry Andric return processIteratorPositions(State, MatchCont, ReAssign); 997*5ffd83dbSDimitry Andric } 998*5ffd83dbSDimitry Andric 999*5ffd83dbSDimitry Andric ProgramStateRef reassignAllIteratorPositionsUnless(ProgramStateRef State, 1000*5ffd83dbSDimitry Andric const MemRegion *Cont, 1001*5ffd83dbSDimitry Andric const MemRegion *NewCont, 1002*5ffd83dbSDimitry Andric SymbolRef Offset, 1003*5ffd83dbSDimitry Andric BinaryOperator::Opcode Opc) { 1004*5ffd83dbSDimitry Andric auto MatchContAndCompare = [&](const IteratorPosition &Pos) { 1005*5ffd83dbSDimitry Andric return Pos.getContainer() == Cont && 1006*5ffd83dbSDimitry Andric !compare(State, Pos.getOffset(), Offset, Opc); 1007*5ffd83dbSDimitry Andric }; 1008*5ffd83dbSDimitry Andric auto ReAssign = [&](const IteratorPosition &Pos) { 1009*5ffd83dbSDimitry Andric return Pos.reAssign(NewCont); 1010*5ffd83dbSDimitry Andric }; 1011*5ffd83dbSDimitry Andric return processIteratorPositions(State, MatchContAndCompare, ReAssign); 1012*5ffd83dbSDimitry Andric } 1013*5ffd83dbSDimitry Andric 1014*5ffd83dbSDimitry Andric // This function rebases symbolic expression `OldSym + Int` to `NewSym + Int`, 1015*5ffd83dbSDimitry Andric // `OldSym - Int` to `NewSym - Int` and `OldSym` to `NewSym` in any iterator 1016*5ffd83dbSDimitry Andric // position offsets where `CondSym` is true. 1017*5ffd83dbSDimitry Andric ProgramStateRef rebaseSymbolInIteratorPositionsIf( 1018*5ffd83dbSDimitry Andric ProgramStateRef State, SValBuilder &SVB, SymbolRef OldSym, 1019*5ffd83dbSDimitry Andric SymbolRef NewSym, SymbolRef CondSym, BinaryOperator::Opcode Opc) { 1020*5ffd83dbSDimitry Andric auto LessThanEnd = [&](const IteratorPosition &Pos) { 1021*5ffd83dbSDimitry Andric return compare(State, Pos.getOffset(), CondSym, Opc); 1022*5ffd83dbSDimitry Andric }; 1023*5ffd83dbSDimitry Andric auto RebaseSymbol = [&](const IteratorPosition &Pos) { 1024*5ffd83dbSDimitry Andric return Pos.setTo(rebaseSymbol(State, SVB, Pos.getOffset(), OldSym, 1025*5ffd83dbSDimitry Andric NewSym)); 1026*5ffd83dbSDimitry Andric }; 1027*5ffd83dbSDimitry Andric return processIteratorPositions(State, LessThanEnd, RebaseSymbol); 1028*5ffd83dbSDimitry Andric } 1029*5ffd83dbSDimitry Andric 1030*5ffd83dbSDimitry Andric // This function rebases symbolic expression `OldExpr + Int` to `NewExpr + Int`, 1031*5ffd83dbSDimitry Andric // `OldExpr - Int` to `NewExpr - Int` and `OldExpr` to `NewExpr` in expression 1032*5ffd83dbSDimitry Andric // `OrigExpr`. 1033*5ffd83dbSDimitry Andric SymbolRef rebaseSymbol(ProgramStateRef State, SValBuilder &SVB, 1034*5ffd83dbSDimitry Andric SymbolRef OrigExpr, SymbolRef OldExpr, 1035*5ffd83dbSDimitry Andric SymbolRef NewSym) { 1036*5ffd83dbSDimitry Andric auto &SymMgr = SVB.getSymbolManager(); 1037*5ffd83dbSDimitry Andric auto Diff = SVB.evalBinOpNN(State, BO_Sub, nonloc::SymbolVal(OrigExpr), 1038*5ffd83dbSDimitry Andric nonloc::SymbolVal(OldExpr), 1039*5ffd83dbSDimitry Andric SymMgr.getType(OrigExpr)); 1040*5ffd83dbSDimitry Andric 1041*5ffd83dbSDimitry Andric const auto DiffInt = Diff.getAs<nonloc::ConcreteInt>(); 1042*5ffd83dbSDimitry Andric if (!DiffInt) 1043*5ffd83dbSDimitry Andric return OrigExpr; 1044*5ffd83dbSDimitry Andric 1045*5ffd83dbSDimitry Andric return SVB.evalBinOpNN(State, BO_Add, *DiffInt, nonloc::SymbolVal(NewSym), 1046*5ffd83dbSDimitry Andric SymMgr.getType(OrigExpr)).getAsSymbol(); 1047*5ffd83dbSDimitry Andric } 1048*5ffd83dbSDimitry Andric 1049*5ffd83dbSDimitry Andric bool hasLiveIterators(ProgramStateRef State, const MemRegion *Cont) { 1050*5ffd83dbSDimitry Andric auto RegionMap = State->get<IteratorRegionMap>(); 1051*5ffd83dbSDimitry Andric for (const auto &Reg : RegionMap) { 1052*5ffd83dbSDimitry Andric if (Reg.second.getContainer() == Cont) 1053*5ffd83dbSDimitry Andric return true; 1054*5ffd83dbSDimitry Andric } 1055*5ffd83dbSDimitry Andric 1056*5ffd83dbSDimitry Andric auto SymbolMap = State->get<IteratorSymbolMap>(); 1057*5ffd83dbSDimitry Andric for (const auto &Sym : SymbolMap) { 1058*5ffd83dbSDimitry Andric if (Sym.second.getContainer() == Cont) 1059*5ffd83dbSDimitry Andric return true; 1060*5ffd83dbSDimitry Andric } 1061*5ffd83dbSDimitry Andric 1062*5ffd83dbSDimitry Andric return false; 1063*5ffd83dbSDimitry Andric } 1064*5ffd83dbSDimitry Andric 1065*5ffd83dbSDimitry Andric } // namespace 1066*5ffd83dbSDimitry Andric 1067*5ffd83dbSDimitry Andric void ento::registerContainerModeling(CheckerManager &mgr) { 1068*5ffd83dbSDimitry Andric mgr.registerChecker<ContainerModeling>(); 1069*5ffd83dbSDimitry Andric } 1070*5ffd83dbSDimitry Andric 1071*5ffd83dbSDimitry Andric bool ento::shouldRegisterContainerModeling(const CheckerManager &mgr) { 1072*5ffd83dbSDimitry Andric if (!mgr.getLangOpts().CPlusPlus) 1073*5ffd83dbSDimitry Andric return false; 1074*5ffd83dbSDimitry Andric 1075*5ffd83dbSDimitry Andric if (!mgr.getAnalyzerOptions().ShouldAggressivelySimplifyBinaryOperation) { 1076*5ffd83dbSDimitry Andric mgr.getASTContext().getDiagnostics().Report( 1077*5ffd83dbSDimitry Andric diag::err_analyzer_checker_incompatible_analyzer_option) 1078*5ffd83dbSDimitry Andric << "aggressive-binary-operation-simplification" << "false"; 1079*5ffd83dbSDimitry Andric return false; 1080*5ffd83dbSDimitry Andric } 1081*5ffd83dbSDimitry Andric 1082*5ffd83dbSDimitry Andric return true; 1083*5ffd83dbSDimitry Andric } 1084