1*e038c9c4Sjoerg //==-- DebugContainerModeling.cpp ---------------------------------*- C++ -*--//
2*e038c9c4Sjoerg //
3*e038c9c4Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*e038c9c4Sjoerg // See https://llvm.org/LICENSE.txt for license information.
5*e038c9c4Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*e038c9c4Sjoerg //
7*e038c9c4Sjoerg //===----------------------------------------------------------------------===//
8*e038c9c4Sjoerg //
9*e038c9c4Sjoerg // Defines a checker for debugging iterator modeling.
10*e038c9c4Sjoerg //
11*e038c9c4Sjoerg //===----------------------------------------------------------------------===//
12*e038c9c4Sjoerg
13*e038c9c4Sjoerg #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
14*e038c9c4Sjoerg #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
15*e038c9c4Sjoerg #include "clang/StaticAnalyzer/Core/Checker.h"
16*e038c9c4Sjoerg #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
17*e038c9c4Sjoerg #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
18*e038c9c4Sjoerg
19*e038c9c4Sjoerg #include "Iterator.h"
20*e038c9c4Sjoerg
21*e038c9c4Sjoerg using namespace clang;
22*e038c9c4Sjoerg using namespace ento;
23*e038c9c4Sjoerg using namespace iterator;
24*e038c9c4Sjoerg
25*e038c9c4Sjoerg namespace {
26*e038c9c4Sjoerg
27*e038c9c4Sjoerg class DebugContainerModeling
28*e038c9c4Sjoerg : public Checker<eval::Call> {
29*e038c9c4Sjoerg
30*e038c9c4Sjoerg std::unique_ptr<BugType> DebugMsgBugType;
31*e038c9c4Sjoerg
32*e038c9c4Sjoerg template <typename Getter>
33*e038c9c4Sjoerg void analyzerContainerDataField(const CallExpr *CE, CheckerContext &C,
34*e038c9c4Sjoerg Getter get) const;
35*e038c9c4Sjoerg void analyzerContainerBegin(const CallExpr *CE, CheckerContext &C) const;
36*e038c9c4Sjoerg void analyzerContainerEnd(const CallExpr *CE, CheckerContext &C) const;
37*e038c9c4Sjoerg ExplodedNode *reportDebugMsg(llvm::StringRef Msg, CheckerContext &C) const;
38*e038c9c4Sjoerg
39*e038c9c4Sjoerg typedef void (DebugContainerModeling::*FnCheck)(const CallExpr *,
40*e038c9c4Sjoerg CheckerContext &) const;
41*e038c9c4Sjoerg
42*e038c9c4Sjoerg CallDescriptionMap<FnCheck> Callbacks = {
43*e038c9c4Sjoerg {{0, "clang_analyzer_container_begin", 1},
44*e038c9c4Sjoerg &DebugContainerModeling::analyzerContainerBegin},
45*e038c9c4Sjoerg {{0, "clang_analyzer_container_end", 1},
46*e038c9c4Sjoerg &DebugContainerModeling::analyzerContainerEnd},
47*e038c9c4Sjoerg };
48*e038c9c4Sjoerg
49*e038c9c4Sjoerg public:
50*e038c9c4Sjoerg DebugContainerModeling();
51*e038c9c4Sjoerg
52*e038c9c4Sjoerg bool evalCall(const CallEvent &Call, CheckerContext &C) const;
53*e038c9c4Sjoerg };
54*e038c9c4Sjoerg
55*e038c9c4Sjoerg } //namespace
56*e038c9c4Sjoerg
DebugContainerModeling()57*e038c9c4Sjoerg DebugContainerModeling::DebugContainerModeling() {
58*e038c9c4Sjoerg DebugMsgBugType.reset(
59*e038c9c4Sjoerg new BugType(this, "Checking analyzer assumptions", "debug",
60*e038c9c4Sjoerg /*SuppressOnSink=*/true));
61*e038c9c4Sjoerg }
62*e038c9c4Sjoerg
evalCall(const CallEvent & Call,CheckerContext & C) const63*e038c9c4Sjoerg bool DebugContainerModeling::evalCall(const CallEvent &Call,
64*e038c9c4Sjoerg CheckerContext &C) const {
65*e038c9c4Sjoerg const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
66*e038c9c4Sjoerg if (!CE)
67*e038c9c4Sjoerg return false;
68*e038c9c4Sjoerg
69*e038c9c4Sjoerg const FnCheck *Handler = Callbacks.lookup(Call);
70*e038c9c4Sjoerg if (!Handler)
71*e038c9c4Sjoerg return false;
72*e038c9c4Sjoerg
73*e038c9c4Sjoerg (this->**Handler)(CE, C);
74*e038c9c4Sjoerg return true;
75*e038c9c4Sjoerg }
76*e038c9c4Sjoerg
77*e038c9c4Sjoerg template <typename Getter>
analyzerContainerDataField(const CallExpr * CE,CheckerContext & C,Getter get) const78*e038c9c4Sjoerg void DebugContainerModeling::analyzerContainerDataField(const CallExpr *CE,
79*e038c9c4Sjoerg CheckerContext &C,
80*e038c9c4Sjoerg Getter get) const {
81*e038c9c4Sjoerg if (CE->getNumArgs() == 0) {
82*e038c9c4Sjoerg reportDebugMsg("Missing container argument", C);
83*e038c9c4Sjoerg return;
84*e038c9c4Sjoerg }
85*e038c9c4Sjoerg
86*e038c9c4Sjoerg auto State = C.getState();
87*e038c9c4Sjoerg const MemRegion *Cont = C.getSVal(CE->getArg(0)).getAsRegion();
88*e038c9c4Sjoerg if (Cont) {
89*e038c9c4Sjoerg const auto *Data = getContainerData(State, Cont);
90*e038c9c4Sjoerg if (Data) {
91*e038c9c4Sjoerg SymbolRef Field = get(Data);
92*e038c9c4Sjoerg if (Field) {
93*e038c9c4Sjoerg State = State->BindExpr(CE, C.getLocationContext(),
94*e038c9c4Sjoerg nonloc::SymbolVal(Field));
95*e038c9c4Sjoerg
96*e038c9c4Sjoerg // Progpagate interestingness from the container's data (marked
97*e038c9c4Sjoerg // interesting by an `ExprInspection` debug call to the container
98*e038c9c4Sjoerg // itself.
99*e038c9c4Sjoerg const NoteTag *InterestingTag =
100*e038c9c4Sjoerg C.getNoteTag(
101*e038c9c4Sjoerg [Cont, Field](PathSensitiveBugReport &BR) -> std::string {
102*e038c9c4Sjoerg if (BR.isInteresting(Field)) {
103*e038c9c4Sjoerg BR.markInteresting(Cont);
104*e038c9c4Sjoerg }
105*e038c9c4Sjoerg return "";
106*e038c9c4Sjoerg });
107*e038c9c4Sjoerg C.addTransition(State, InterestingTag);
108*e038c9c4Sjoerg return;
109*e038c9c4Sjoerg }
110*e038c9c4Sjoerg }
111*e038c9c4Sjoerg }
112*e038c9c4Sjoerg
113*e038c9c4Sjoerg auto &BVF = C.getSValBuilder().getBasicValueFactory();
114*e038c9c4Sjoerg State = State->BindExpr(CE, C.getLocationContext(),
115*e038c9c4Sjoerg nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));
116*e038c9c4Sjoerg }
117*e038c9c4Sjoerg
analyzerContainerBegin(const CallExpr * CE,CheckerContext & C) const118*e038c9c4Sjoerg void DebugContainerModeling::analyzerContainerBegin(const CallExpr *CE,
119*e038c9c4Sjoerg CheckerContext &C) const {
120*e038c9c4Sjoerg analyzerContainerDataField(CE, C, [](const ContainerData *D) {
121*e038c9c4Sjoerg return D->getBegin();
122*e038c9c4Sjoerg });
123*e038c9c4Sjoerg }
124*e038c9c4Sjoerg
analyzerContainerEnd(const CallExpr * CE,CheckerContext & C) const125*e038c9c4Sjoerg void DebugContainerModeling::analyzerContainerEnd(const CallExpr *CE,
126*e038c9c4Sjoerg CheckerContext &C) const {
127*e038c9c4Sjoerg analyzerContainerDataField(CE, C, [](const ContainerData *D) {
128*e038c9c4Sjoerg return D->getEnd();
129*e038c9c4Sjoerg });
130*e038c9c4Sjoerg }
131*e038c9c4Sjoerg
reportDebugMsg(llvm::StringRef Msg,CheckerContext & C) const132*e038c9c4Sjoerg ExplodedNode *DebugContainerModeling::reportDebugMsg(llvm::StringRef Msg,
133*e038c9c4Sjoerg CheckerContext &C) const {
134*e038c9c4Sjoerg ExplodedNode *N = C.generateNonFatalErrorNode();
135*e038c9c4Sjoerg if (!N)
136*e038c9c4Sjoerg return nullptr;
137*e038c9c4Sjoerg
138*e038c9c4Sjoerg auto &BR = C.getBugReporter();
139*e038c9c4Sjoerg BR.emitReport(std::make_unique<PathSensitiveBugReport>(*DebugMsgBugType,
140*e038c9c4Sjoerg Msg, N));
141*e038c9c4Sjoerg return N;
142*e038c9c4Sjoerg }
143*e038c9c4Sjoerg
registerDebugContainerModeling(CheckerManager & mgr)144*e038c9c4Sjoerg void ento::registerDebugContainerModeling(CheckerManager &mgr) {
145*e038c9c4Sjoerg mgr.registerChecker<DebugContainerModeling>();
146*e038c9c4Sjoerg }
147*e038c9c4Sjoerg
shouldRegisterDebugContainerModeling(const CheckerManager & mgr)148*e038c9c4Sjoerg bool ento::shouldRegisterDebugContainerModeling(const CheckerManager &mgr) {
149*e038c9c4Sjoerg return true;
150*e038c9c4Sjoerg }
151