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/CallDescription.h" 17 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 18 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 19 20 #include "Iterator.h" 21 22 using namespace clang; 23 using namespace ento; 24 using namespace iterator; 25 26 namespace { 27 28 class DebugIteratorModeling 29 : public Checker<eval::Call> { 30 31 std::unique_ptr<BugType> DebugMsgBugType; 32 33 template <typename Getter> 34 void analyzerIteratorDataField(const CallExpr *CE, CheckerContext &C, 35 Getter get, SVal Default) const; 36 void analyzerIteratorPosition(const CallExpr *CE, CheckerContext &C) const; 37 void analyzerIteratorContainer(const CallExpr *CE, CheckerContext &C) const; 38 void analyzerIteratorValidity(const CallExpr *CE, CheckerContext &C) const; 39 ExplodedNode *reportDebugMsg(llvm::StringRef Msg, CheckerContext &C) const; 40 41 typedef void (DebugIteratorModeling::*FnCheck)(const CallExpr *, 42 CheckerContext &) const; 43 44 CallDescriptionMap<FnCheck> Callbacks = { 45 {{{"clang_analyzer_iterator_position"}, 1}, 46 &DebugIteratorModeling::analyzerIteratorPosition}, 47 {{{"clang_analyzer_iterator_container"}, 1}, 48 &DebugIteratorModeling::analyzerIteratorContainer}, 49 {{{"clang_analyzer_iterator_validity"}, 1}, 50 &DebugIteratorModeling::analyzerIteratorValidity}, 51 }; 52 53 public: 54 DebugIteratorModeling(); 55 56 bool evalCall(const CallEvent &Call, CheckerContext &C) const; 57 }; 58 59 } //namespace 60 61 DebugIteratorModeling::DebugIteratorModeling() { 62 DebugMsgBugType.reset( 63 new BugType(this, "Checking analyzer assumptions", "debug", 64 /*SuppressOnSink=*/true)); 65 } 66 67 bool DebugIteratorModeling::evalCall(const CallEvent &Call, 68 CheckerContext &C) const { 69 const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr()); 70 if (!CE) 71 return false; 72 73 const FnCheck *Handler = Callbacks.lookup(Call); 74 if (!Handler) 75 return false; 76 77 (this->**Handler)(CE, C); 78 return true; 79 } 80 81 template <typename Getter> 82 void DebugIteratorModeling::analyzerIteratorDataField(const CallExpr *CE, 83 CheckerContext &C, 84 Getter get, 85 SVal Default) const { 86 if (CE->getNumArgs() == 0) { 87 reportDebugMsg("Missing iterator argument", C); 88 return; 89 } 90 91 auto State = C.getState(); 92 SVal V = C.getSVal(CE->getArg(0)); 93 const auto *Pos = getIteratorPosition(State, V); 94 if (Pos) { 95 State = State->BindExpr(CE, C.getLocationContext(), get(Pos)); 96 } else { 97 State = State->BindExpr(CE, C.getLocationContext(), Default); 98 } 99 C.addTransition(State); 100 } 101 102 void DebugIteratorModeling::analyzerIteratorPosition(const CallExpr *CE, 103 CheckerContext &C) const { 104 auto &BVF = C.getSValBuilder().getBasicValueFactory(); 105 analyzerIteratorDataField(CE, C, [](const IteratorPosition *P) { 106 return nonloc::SymbolVal(P->getOffset()); 107 }, nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0)))); 108 } 109 110 void DebugIteratorModeling::analyzerIteratorContainer(const CallExpr *CE, 111 CheckerContext &C) const { 112 auto &BVF = C.getSValBuilder().getBasicValueFactory(); 113 analyzerIteratorDataField(CE, C, [](const IteratorPosition *P) { 114 return loc::MemRegionVal(P->getContainer()); 115 }, loc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0)))); 116 } 117 118 void DebugIteratorModeling::analyzerIteratorValidity(const CallExpr *CE, 119 CheckerContext &C) const { 120 auto &BVF = C.getSValBuilder().getBasicValueFactory(); 121 analyzerIteratorDataField(CE, C, [&BVF](const IteratorPosition *P) { 122 return 123 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get((P->isValid())))); 124 }, nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0)))); 125 } 126 127 ExplodedNode *DebugIteratorModeling::reportDebugMsg(llvm::StringRef Msg, 128 CheckerContext &C) const { 129 ExplodedNode *N = C.generateNonFatalErrorNode(); 130 if (!N) 131 return nullptr; 132 133 auto &BR = C.getBugReporter(); 134 BR.emitReport(std::make_unique<PathSensitiveBugReport>(*DebugMsgBugType, 135 Msg, N)); 136 return N; 137 } 138 139 void ento::registerDebugIteratorModeling(CheckerManager &mgr) { 140 mgr.registerChecker<DebugIteratorModeling>(); 141 } 142 143 bool ento::shouldRegisterDebugIteratorModeling(const CheckerManager &mgr) { 144 return true; 145 } 146