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