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