DebugIteratorModeling.cpp revision 360784
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 21using namespace clang; 22using namespace ento; 23using namespace iterator; 24 25namespace { 26 27class 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 61public: 62 DebugIteratorModeling(); 63 64 bool evalCall(const CallEvent &Call, CheckerContext &C) const; 65}; 66 67} //namespace 68 69DebugIteratorModeling::DebugIteratorModeling() { 70 DebugMsgBugType.reset( 71 new BugType(this, "Checking analyzer assumptions", "debug", 72 /*SuppressOnSink=*/true)); 73} 74 75bool 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 89template <typename Getter> 90void 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 118void DebugIteratorModeling::analyzerContainerBegin(const CallExpr *CE, 119 CheckerContext &C) const { 120 analyzerContainerDataField(CE, C, [](const ContainerData *D) { 121 return D->getBegin(); 122 }); 123} 124 125void DebugIteratorModeling::analyzerContainerEnd(const CallExpr *CE, 126 CheckerContext &C) const { 127 analyzerContainerDataField(CE, C, [](const ContainerData *D) { 128 return D->getEnd(); 129 }); 130} 131 132template <typename Getter> 133void 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 153void 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 161void 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 169void 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 178ExplodedNode *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 190void ento::registerDebugIteratorModeling(CheckerManager &mgr) { 191 mgr.registerChecker<DebugIteratorModeling>(); 192} 193 194bool ento::shouldRegisterDebugIteratorModeling(const LangOptions &LO) { 195 return true; 196} 197