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 22using namespace clang; 23using namespace ento; 24using namespace iterator; 25 26namespace { 27 28class 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 53public: 54 DebugIteratorModeling(); 55 56 bool evalCall(const CallEvent &Call, CheckerContext &C) const; 57}; 58 59} //namespace 60 61DebugIteratorModeling::DebugIteratorModeling() { 62 DebugMsgBugType.reset( 63 new BugType(this, "Checking analyzer assumptions", "debug", 64 /*SuppressOnSink=*/true)); 65} 66 67bool 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 81template <typename Getter> 82void 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 102void 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 110void 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 118void 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 127ExplodedNode *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 139void ento::registerDebugIteratorModeling(CheckerManager &mgr) { 140 mgr.registerChecker<DebugIteratorModeling>(); 141} 142 143bool ento::shouldRegisterDebugIteratorModeling(const CheckerManager &mgr) { 144 return true; 145} 146