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