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
DebugIteratorModeling()60 DebugIteratorModeling::DebugIteratorModeling() {
61 DebugMsgBugType.reset(
62 new BugType(this, "Checking analyzer assumptions", "debug",
63 /*SuppressOnSink=*/true));
64 }
65
evalCall(const CallEvent & Call,CheckerContext & C) const66 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>
analyzerIteratorDataField(const CallExpr * CE,CheckerContext & C,Getter get,SVal Default) const81 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
analyzerIteratorPosition(const CallExpr * CE,CheckerContext & C) const101 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
analyzerIteratorContainer(const CallExpr * CE,CheckerContext & C) const109 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
analyzerIteratorValidity(const CallExpr * CE,CheckerContext & C) const117 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
reportDebugMsg(llvm::StringRef Msg,CheckerContext & C) const126 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
registerDebugIteratorModeling(CheckerManager & mgr)138 void ento::registerDebugIteratorModeling(CheckerManager &mgr) {
139 mgr.registerChecker<DebugIteratorModeling>();
140 }
141
shouldRegisterDebugIteratorModeling(const CheckerManager & mgr)142 bool ento::shouldRegisterDebugIteratorModeling(const CheckerManager &mgr) {
143 return true;
144 }
145