1 //===-- DebugIteratorModeling.cpp ---------------------------------*- C++ -*--//
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
7 //===----------------------------------------------------------------------===//
9 // Defines a checker for debugging iterator modeling.
11 //===----------------------------------------------------------------------===//
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"
21 using namespace clang;
23 using namespace iterator;
27 class DebugIteratorModeling
28 : public Checker<eval::Call> {
30 std::unique_ptr<BugType> DebugMsgBugType;
32 template <typename Getter>
33 void analyzerContainerDataField(const CallExpr *CE, CheckerContext &C,
35 void analyzerContainerBegin(const CallExpr *CE, CheckerContext &C) const;
36 void analyzerContainerEnd(const CallExpr *CE, CheckerContext &C) const;
37 template <typename Getter>
38 void analyzerIteratorDataField(const CallExpr *CE, CheckerContext &C,
39 Getter get, SVal Default) const;
40 void analyzerIteratorPosition(const CallExpr *CE, CheckerContext &C) const;
41 void analyzerIteratorContainer(const CallExpr *CE, CheckerContext &C) const;
42 void analyzerIteratorValidity(const CallExpr *CE, CheckerContext &C) const;
43 ExplodedNode *reportDebugMsg(llvm::StringRef Msg, CheckerContext &C) const;
45 typedef void (DebugIteratorModeling::*FnCheck)(const CallExpr *,
46 CheckerContext &) const;
48 CallDescriptionMap<FnCheck> Callbacks = {
49 {{0, "clang_analyzer_container_begin", 1},
50 &DebugIteratorModeling::analyzerContainerBegin},
51 {{0, "clang_analyzer_container_end", 1},
52 &DebugIteratorModeling::analyzerContainerEnd},
53 {{0, "clang_analyzer_iterator_position", 1},
54 &DebugIteratorModeling::analyzerIteratorPosition},
55 {{0, "clang_analyzer_iterator_container", 1},
56 &DebugIteratorModeling::analyzerIteratorContainer},
57 {{0, "clang_analyzer_iterator_validity", 1},
58 &DebugIteratorModeling::analyzerIteratorValidity},
62 DebugIteratorModeling();
64 bool evalCall(const CallEvent &Call, CheckerContext &C) const;
69 DebugIteratorModeling::DebugIteratorModeling() {
70 DebugMsgBugType.reset(
71 new BugType(this, "Checking analyzer assumptions", "debug",
72 /*SuppressOnSink=*/true));
75 bool DebugIteratorModeling::evalCall(const CallEvent &Call,
76 CheckerContext &C) const {
77 const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
81 const FnCheck *Handler = Callbacks.lookup(Call);
85 (this->**Handler)(CE, C);
89 template <typename Getter>
90 void DebugIteratorModeling::analyzerContainerDataField(const CallExpr *CE,
93 if (CE->getNumArgs() == 0) {
94 reportDebugMsg("Missing container argument", C);
98 auto State = C.getState();
99 const MemRegion *Cont = C.getSVal(CE->getArg(0)).getAsRegion();
101 const auto *Data = getContainerData(State, Cont);
103 SymbolRef Field = get(Data);
105 State = State->BindExpr(CE, C.getLocationContext(),
106 nonloc::SymbolVal(Field));
107 C.addTransition(State);
113 auto &BVF = C.getSValBuilder().getBasicValueFactory();
114 State = State->BindExpr(CE, C.getLocationContext(),
115 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));
118 void DebugIteratorModeling::analyzerContainerBegin(const CallExpr *CE,
119 CheckerContext &C) const {
120 analyzerContainerDataField(CE, C, [](const ContainerData *D) {
121 return D->getBegin();
125 void DebugIteratorModeling::analyzerContainerEnd(const CallExpr *CE,
126 CheckerContext &C) const {
127 analyzerContainerDataField(CE, C, [](const ContainerData *D) {
132 template <typename Getter>
133 void DebugIteratorModeling::analyzerIteratorDataField(const CallExpr *CE,
136 SVal Default) const {
137 if (CE->getNumArgs() == 0) {
138 reportDebugMsg("Missing iterator argument", C);
142 auto State = C.getState();
143 SVal V = C.getSVal(CE->getArg(0));
144 const auto *Pos = getIteratorPosition(State, V);
146 State = State->BindExpr(CE, C.getLocationContext(), get(Pos));
148 State = State->BindExpr(CE, C.getLocationContext(), Default);
150 C.addTransition(State);
153 void DebugIteratorModeling::analyzerIteratorPosition(const CallExpr *CE,
154 CheckerContext &C) const {
155 auto &BVF = C.getSValBuilder().getBasicValueFactory();
156 analyzerIteratorDataField(CE, C, [](const IteratorPosition *P) {
157 return nonloc::SymbolVal(P->getOffset());
158 }, nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));
161 void DebugIteratorModeling::analyzerIteratorContainer(const CallExpr *CE,
162 CheckerContext &C) const {
163 auto &BVF = C.getSValBuilder().getBasicValueFactory();
164 analyzerIteratorDataField(CE, C, [](const IteratorPosition *P) {
165 return loc::MemRegionVal(P->getContainer());
166 }, loc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));
169 void DebugIteratorModeling::analyzerIteratorValidity(const CallExpr *CE,
170 CheckerContext &C) const {
171 auto &BVF = C.getSValBuilder().getBasicValueFactory();
172 analyzerIteratorDataField(CE, C, [&BVF](const IteratorPosition *P) {
174 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get((P->isValid()))));
175 }, nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));
178 ExplodedNode *DebugIteratorModeling::reportDebugMsg(llvm::StringRef Msg,
179 CheckerContext &C) const {
180 ExplodedNode *N = C.generateNonFatalErrorNode();
184 auto &BR = C.getBugReporter();
185 BR.emitReport(std::make_unique<PathSensitiveBugReport>(*DebugMsgBugType,
190 void ento::registerDebugIteratorModeling(CheckerManager &mgr) {
191 mgr.registerChecker<DebugIteratorModeling>();
194 bool ento::shouldRegisterDebugIteratorModeling(const LangOptions &LO) {