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