1*480093f4SDimitry Andric //===-- DebugIteratorModeling.cpp ---------------------------------*- C++ -*--// 2*480093f4SDimitry Andric // 3*480093f4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*480093f4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*480093f4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*480093f4SDimitry Andric // 7*480093f4SDimitry Andric //===----------------------------------------------------------------------===// 8*480093f4SDimitry Andric // 9*480093f4SDimitry Andric // Defines a checker for debugging iterator modeling. 10*480093f4SDimitry Andric // 11*480093f4SDimitry Andric //===----------------------------------------------------------------------===// 12*480093f4SDimitry Andric 13*480093f4SDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 14*480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 15*480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h" 16*480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 17*480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 18*480093f4SDimitry Andric 19*480093f4SDimitry Andric #include "Iterator.h" 20*480093f4SDimitry Andric 21*480093f4SDimitry Andric using namespace clang; 22*480093f4SDimitry Andric using namespace ento; 23*480093f4SDimitry Andric using namespace iterator; 24*480093f4SDimitry Andric 25*480093f4SDimitry Andric namespace { 26*480093f4SDimitry Andric 27*480093f4SDimitry Andric class DebugIteratorModeling 28*480093f4SDimitry Andric : public Checker<eval::Call> { 29*480093f4SDimitry Andric 30*480093f4SDimitry Andric std::unique_ptr<BugType> DebugMsgBugType; 31*480093f4SDimitry Andric 32*480093f4SDimitry Andric template <typename Getter> 33*480093f4SDimitry Andric void analyzerContainerDataField(const CallExpr *CE, CheckerContext &C, 34*480093f4SDimitry Andric Getter get) const; 35*480093f4SDimitry Andric void analyzerContainerBegin(const CallExpr *CE, CheckerContext &C) const; 36*480093f4SDimitry Andric void analyzerContainerEnd(const CallExpr *CE, CheckerContext &C) const; 37*480093f4SDimitry Andric template <typename Getter> 38*480093f4SDimitry Andric void analyzerIteratorDataField(const CallExpr *CE, CheckerContext &C, 39*480093f4SDimitry Andric Getter get, SVal Default) const; 40*480093f4SDimitry Andric void analyzerIteratorPosition(const CallExpr *CE, CheckerContext &C) const; 41*480093f4SDimitry Andric void analyzerIteratorContainer(const CallExpr *CE, CheckerContext &C) const; 42*480093f4SDimitry Andric void analyzerIteratorValidity(const CallExpr *CE, CheckerContext &C) const; 43*480093f4SDimitry Andric ExplodedNode *reportDebugMsg(llvm::StringRef Msg, CheckerContext &C) const; 44*480093f4SDimitry Andric 45*480093f4SDimitry Andric typedef void (DebugIteratorModeling::*FnCheck)(const CallExpr *, 46*480093f4SDimitry Andric CheckerContext &) const; 47*480093f4SDimitry Andric 48*480093f4SDimitry Andric CallDescriptionMap<FnCheck> Callbacks = { 49*480093f4SDimitry Andric {{0, "clang_analyzer_container_begin", 1}, 50*480093f4SDimitry Andric &DebugIteratorModeling::analyzerContainerBegin}, 51*480093f4SDimitry Andric {{0, "clang_analyzer_container_end", 1}, 52*480093f4SDimitry Andric &DebugIteratorModeling::analyzerContainerEnd}, 53*480093f4SDimitry Andric {{0, "clang_analyzer_iterator_position", 1}, 54*480093f4SDimitry Andric &DebugIteratorModeling::analyzerIteratorPosition}, 55*480093f4SDimitry Andric {{0, "clang_analyzer_iterator_container", 1}, 56*480093f4SDimitry Andric &DebugIteratorModeling::analyzerIteratorContainer}, 57*480093f4SDimitry Andric {{0, "clang_analyzer_iterator_validity", 1}, 58*480093f4SDimitry Andric &DebugIteratorModeling::analyzerIteratorValidity}, 59*480093f4SDimitry Andric }; 60*480093f4SDimitry Andric 61*480093f4SDimitry Andric public: 62*480093f4SDimitry Andric DebugIteratorModeling(); 63*480093f4SDimitry Andric 64*480093f4SDimitry Andric bool evalCall(const CallEvent &Call, CheckerContext &C) const; 65*480093f4SDimitry Andric }; 66*480093f4SDimitry Andric 67*480093f4SDimitry Andric } //namespace 68*480093f4SDimitry Andric 69*480093f4SDimitry Andric DebugIteratorModeling::DebugIteratorModeling() { 70*480093f4SDimitry Andric DebugMsgBugType.reset( 71*480093f4SDimitry Andric new BugType(this, "Checking analyzer assumptions", "debug", 72*480093f4SDimitry Andric /*SuppressOnSink=*/true)); 73*480093f4SDimitry Andric } 74*480093f4SDimitry Andric 75*480093f4SDimitry Andric bool DebugIteratorModeling::evalCall(const CallEvent &Call, 76*480093f4SDimitry Andric CheckerContext &C) const { 77*480093f4SDimitry Andric const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr()); 78*480093f4SDimitry Andric if (!CE) 79*480093f4SDimitry Andric return false; 80*480093f4SDimitry Andric 81*480093f4SDimitry Andric const FnCheck *Handler = Callbacks.lookup(Call); 82*480093f4SDimitry Andric if (!Handler) 83*480093f4SDimitry Andric return false; 84*480093f4SDimitry Andric 85*480093f4SDimitry Andric (this->**Handler)(CE, C); 86*480093f4SDimitry Andric return true; 87*480093f4SDimitry Andric } 88*480093f4SDimitry Andric 89*480093f4SDimitry Andric template <typename Getter> 90*480093f4SDimitry Andric void DebugIteratorModeling::analyzerContainerDataField(const CallExpr *CE, 91*480093f4SDimitry Andric CheckerContext &C, 92*480093f4SDimitry Andric Getter get) const { 93*480093f4SDimitry Andric if (CE->getNumArgs() == 0) { 94*480093f4SDimitry Andric reportDebugMsg("Missing container argument", C); 95*480093f4SDimitry Andric return; 96*480093f4SDimitry Andric } 97*480093f4SDimitry Andric 98*480093f4SDimitry Andric auto State = C.getState(); 99*480093f4SDimitry Andric const MemRegion *Cont = C.getSVal(CE->getArg(0)).getAsRegion(); 100*480093f4SDimitry Andric if (Cont) { 101*480093f4SDimitry Andric const auto *Data = getContainerData(State, Cont); 102*480093f4SDimitry Andric if (Data) { 103*480093f4SDimitry Andric SymbolRef Field = get(Data); 104*480093f4SDimitry Andric if (Field) { 105*480093f4SDimitry Andric State = State->BindExpr(CE, C.getLocationContext(), 106*480093f4SDimitry Andric nonloc::SymbolVal(Field)); 107*480093f4SDimitry Andric C.addTransition(State); 108*480093f4SDimitry Andric return; 109*480093f4SDimitry Andric } 110*480093f4SDimitry Andric } 111*480093f4SDimitry Andric } 112*480093f4SDimitry Andric 113*480093f4SDimitry Andric auto &BVF = C.getSValBuilder().getBasicValueFactory(); 114*480093f4SDimitry Andric State = State->BindExpr(CE, C.getLocationContext(), 115*480093f4SDimitry Andric nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0)))); 116*480093f4SDimitry Andric } 117*480093f4SDimitry Andric 118*480093f4SDimitry Andric void DebugIteratorModeling::analyzerContainerBegin(const CallExpr *CE, 119*480093f4SDimitry Andric CheckerContext &C) const { 120*480093f4SDimitry Andric analyzerContainerDataField(CE, C, [](const ContainerData *D) { 121*480093f4SDimitry Andric return D->getBegin(); 122*480093f4SDimitry Andric }); 123*480093f4SDimitry Andric } 124*480093f4SDimitry Andric 125*480093f4SDimitry Andric void DebugIteratorModeling::analyzerContainerEnd(const CallExpr *CE, 126*480093f4SDimitry Andric CheckerContext &C) const { 127*480093f4SDimitry Andric analyzerContainerDataField(CE, C, [](const ContainerData *D) { 128*480093f4SDimitry Andric return D->getEnd(); 129*480093f4SDimitry Andric }); 130*480093f4SDimitry Andric } 131*480093f4SDimitry Andric 132*480093f4SDimitry Andric template <typename Getter> 133*480093f4SDimitry Andric void DebugIteratorModeling::analyzerIteratorDataField(const CallExpr *CE, 134*480093f4SDimitry Andric CheckerContext &C, 135*480093f4SDimitry Andric Getter get, 136*480093f4SDimitry Andric SVal Default) const { 137*480093f4SDimitry Andric if (CE->getNumArgs() == 0) { 138*480093f4SDimitry Andric reportDebugMsg("Missing iterator argument", C); 139*480093f4SDimitry Andric return; 140*480093f4SDimitry Andric } 141*480093f4SDimitry Andric 142*480093f4SDimitry Andric auto State = C.getState(); 143*480093f4SDimitry Andric SVal V = C.getSVal(CE->getArg(0)); 144*480093f4SDimitry Andric const auto *Pos = getIteratorPosition(State, V); 145*480093f4SDimitry Andric if (Pos) { 146*480093f4SDimitry Andric State = State->BindExpr(CE, C.getLocationContext(), get(Pos)); 147*480093f4SDimitry Andric } else { 148*480093f4SDimitry Andric State = State->BindExpr(CE, C.getLocationContext(), Default); 149*480093f4SDimitry Andric } 150*480093f4SDimitry Andric C.addTransition(State); 151*480093f4SDimitry Andric } 152*480093f4SDimitry Andric 153*480093f4SDimitry Andric void DebugIteratorModeling::analyzerIteratorPosition(const CallExpr *CE, 154*480093f4SDimitry Andric CheckerContext &C) const { 155*480093f4SDimitry Andric auto &BVF = C.getSValBuilder().getBasicValueFactory(); 156*480093f4SDimitry Andric analyzerIteratorDataField(CE, C, [](const IteratorPosition *P) { 157*480093f4SDimitry Andric return nonloc::SymbolVal(P->getOffset()); 158*480093f4SDimitry Andric }, nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0)))); 159*480093f4SDimitry Andric } 160*480093f4SDimitry Andric 161*480093f4SDimitry Andric void DebugIteratorModeling::analyzerIteratorContainer(const CallExpr *CE, 162*480093f4SDimitry Andric CheckerContext &C) const { 163*480093f4SDimitry Andric auto &BVF = C.getSValBuilder().getBasicValueFactory(); 164*480093f4SDimitry Andric analyzerIteratorDataField(CE, C, [](const IteratorPosition *P) { 165*480093f4SDimitry Andric return loc::MemRegionVal(P->getContainer()); 166*480093f4SDimitry Andric }, loc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0)))); 167*480093f4SDimitry Andric } 168*480093f4SDimitry Andric 169*480093f4SDimitry Andric void DebugIteratorModeling::analyzerIteratorValidity(const CallExpr *CE, 170*480093f4SDimitry Andric CheckerContext &C) const { 171*480093f4SDimitry Andric auto &BVF = C.getSValBuilder().getBasicValueFactory(); 172*480093f4SDimitry Andric analyzerIteratorDataField(CE, C, [&BVF](const IteratorPosition *P) { 173*480093f4SDimitry Andric return 174*480093f4SDimitry Andric nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get((P->isValid())))); 175*480093f4SDimitry Andric }, nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0)))); 176*480093f4SDimitry Andric } 177*480093f4SDimitry Andric 178*480093f4SDimitry Andric ExplodedNode *DebugIteratorModeling::reportDebugMsg(llvm::StringRef Msg, 179*480093f4SDimitry Andric CheckerContext &C) const { 180*480093f4SDimitry Andric ExplodedNode *N = C.generateNonFatalErrorNode(); 181*480093f4SDimitry Andric if (!N) 182*480093f4SDimitry Andric return nullptr; 183*480093f4SDimitry Andric 184*480093f4SDimitry Andric auto &BR = C.getBugReporter(); 185*480093f4SDimitry Andric BR.emitReport(std::make_unique<PathSensitiveBugReport>(*DebugMsgBugType, 186*480093f4SDimitry Andric Msg, N)); 187*480093f4SDimitry Andric return N; 188*480093f4SDimitry Andric } 189*480093f4SDimitry Andric 190*480093f4SDimitry Andric void ento::registerDebugIteratorModeling(CheckerManager &mgr) { 191*480093f4SDimitry Andric mgr.registerChecker<DebugIteratorModeling>(); 192*480093f4SDimitry Andric } 193*480093f4SDimitry Andric 194*480093f4SDimitry Andric bool ento::shouldRegisterDebugIteratorModeling(const LangOptions &LO) { 195*480093f4SDimitry Andric return true; 196*480093f4SDimitry Andric } 197