1 //==-- DebugContainerModeling.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 DebugContainerModeling 29 : public Checker<eval::Call> { 30 31 std::unique_ptr<BugType> DebugMsgBugType; 32 33 template <typename Getter> 34 void analyzerContainerDataField(const CallExpr *CE, CheckerContext &C, 35 Getter get) const; 36 void analyzerContainerBegin(const CallExpr *CE, CheckerContext &C) const; 37 void analyzerContainerEnd(const CallExpr *CE, CheckerContext &C) const; 38 ExplodedNode *reportDebugMsg(llvm::StringRef Msg, CheckerContext &C) const; 39 40 typedef void (DebugContainerModeling::*FnCheck)(const CallExpr *, 41 CheckerContext &) const; 42 43 CallDescriptionMap<FnCheck> Callbacks = { 44 {{"clang_analyzer_container_begin", 1}, 45 &DebugContainerModeling::analyzerContainerBegin}, 46 {{"clang_analyzer_container_end", 1}, 47 &DebugContainerModeling::analyzerContainerEnd}, 48 }; 49 50 public: 51 DebugContainerModeling(); 52 53 bool evalCall(const CallEvent &Call, CheckerContext &C) const; 54 }; 55 56 } //namespace 57 58 DebugContainerModeling::DebugContainerModeling() { 59 DebugMsgBugType.reset( 60 new BugType(this, "Checking analyzer assumptions", "debug", 61 /*SuppressOnSink=*/true)); 62 } 63 64 bool DebugContainerModeling::evalCall(const CallEvent &Call, 65 CheckerContext &C) const { 66 const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr()); 67 if (!CE) 68 return false; 69 70 const FnCheck *Handler = Callbacks.lookup(Call); 71 if (!Handler) 72 return false; 73 74 (this->**Handler)(CE, C); 75 return true; 76 } 77 78 template <typename Getter> 79 void DebugContainerModeling::analyzerContainerDataField(const CallExpr *CE, 80 CheckerContext &C, 81 Getter get) const { 82 if (CE->getNumArgs() == 0) { 83 reportDebugMsg("Missing container argument", C); 84 return; 85 } 86 87 auto State = C.getState(); 88 const MemRegion *Cont = C.getSVal(CE->getArg(0)).getAsRegion(); 89 if (Cont) { 90 const auto *Data = getContainerData(State, Cont); 91 if (Data) { 92 SymbolRef Field = get(Data); 93 if (Field) { 94 State = State->BindExpr(CE, C.getLocationContext(), 95 nonloc::SymbolVal(Field)); 96 97 // Progpagate interestingness from the container's data (marked 98 // interesting by an `ExprInspection` debug call to the container 99 // itself. 100 const NoteTag *InterestingTag = 101 C.getNoteTag( 102 [Cont, Field](PathSensitiveBugReport &BR) -> std::string { 103 if (BR.isInteresting(Field)) { 104 BR.markInteresting(Cont); 105 } 106 return ""; 107 }); 108 C.addTransition(State, InterestingTag); 109 return; 110 } 111 } 112 } 113 114 auto &BVF = C.getSValBuilder().getBasicValueFactory(); 115 State = State->BindExpr(CE, C.getLocationContext(), 116 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0)))); 117 } 118 119 void DebugContainerModeling::analyzerContainerBegin(const CallExpr *CE, 120 CheckerContext &C) const { 121 analyzerContainerDataField(CE, C, [](const ContainerData *D) { 122 return D->getBegin(); 123 }); 124 } 125 126 void DebugContainerModeling::analyzerContainerEnd(const CallExpr *CE, 127 CheckerContext &C) const { 128 analyzerContainerDataField(CE, C, [](const ContainerData *D) { 129 return D->getEnd(); 130 }); 131 } 132 133 ExplodedNode *DebugContainerModeling::reportDebugMsg(llvm::StringRef Msg, 134 CheckerContext &C) const { 135 ExplodedNode *N = C.generateNonFatalErrorNode(); 136 if (!N) 137 return nullptr; 138 139 auto &BR = C.getBugReporter(); 140 BR.emitReport(std::make_unique<PathSensitiveBugReport>(*DebugMsgBugType, 141 Msg, N)); 142 return N; 143 } 144 145 void ento::registerDebugContainerModeling(CheckerManager &mgr) { 146 mgr.registerChecker<DebugContainerModeling>(); 147 } 148 149 bool ento::shouldRegisterDebugContainerModeling(const CheckerManager &mgr) { 150 return true; 151 } 152