xref: /freebsd-src/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp (revision 480093f4440d54b30b3025afeac24b48f2ba7a2e)
1*480093f4SDimitry Andric //===-- DebugIteratorModeling.cpp ---------------------------------*- C++ -*--//
2*480093f4SDimitry Andric //
3*480093f4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*480093f4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*480093f4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*480093f4SDimitry Andric //
7*480093f4SDimitry Andric //===----------------------------------------------------------------------===//
8*480093f4SDimitry Andric //
9*480093f4SDimitry Andric // Defines a checker for debugging iterator modeling.
10*480093f4SDimitry Andric //
11*480093f4SDimitry Andric //===----------------------------------------------------------------------===//
12*480093f4SDimitry Andric 
13*480093f4SDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
14*480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
15*480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h"
16*480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
17*480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
18*480093f4SDimitry Andric 
19*480093f4SDimitry Andric #include "Iterator.h"
20*480093f4SDimitry Andric 
21*480093f4SDimitry Andric using namespace clang;
22*480093f4SDimitry Andric using namespace ento;
23*480093f4SDimitry Andric using namespace iterator;
24*480093f4SDimitry Andric 
25*480093f4SDimitry Andric namespace {
26*480093f4SDimitry Andric 
27*480093f4SDimitry Andric class DebugIteratorModeling
28*480093f4SDimitry Andric   : public Checker<eval::Call> {
29*480093f4SDimitry Andric 
30*480093f4SDimitry Andric   std::unique_ptr<BugType> DebugMsgBugType;
31*480093f4SDimitry Andric 
32*480093f4SDimitry Andric   template <typename Getter>
33*480093f4SDimitry Andric   void analyzerContainerDataField(const CallExpr *CE, CheckerContext &C,
34*480093f4SDimitry Andric                                   Getter get) const;
35*480093f4SDimitry Andric   void analyzerContainerBegin(const CallExpr *CE, CheckerContext &C) const;
36*480093f4SDimitry Andric   void analyzerContainerEnd(const CallExpr *CE, CheckerContext &C) const;
37*480093f4SDimitry Andric   template <typename Getter>
38*480093f4SDimitry Andric   void analyzerIteratorDataField(const CallExpr *CE, CheckerContext &C,
39*480093f4SDimitry Andric                                  Getter get, SVal Default) const;
40*480093f4SDimitry Andric   void analyzerIteratorPosition(const CallExpr *CE, CheckerContext &C) const;
41*480093f4SDimitry Andric   void analyzerIteratorContainer(const CallExpr *CE, CheckerContext &C) const;
42*480093f4SDimitry Andric   void analyzerIteratorValidity(const CallExpr *CE, CheckerContext &C) const;
43*480093f4SDimitry Andric   ExplodedNode *reportDebugMsg(llvm::StringRef Msg, CheckerContext &C) const;
44*480093f4SDimitry Andric 
45*480093f4SDimitry Andric   typedef void (DebugIteratorModeling::*FnCheck)(const CallExpr *,
46*480093f4SDimitry Andric                                                  CheckerContext &) const;
47*480093f4SDimitry Andric 
48*480093f4SDimitry Andric   CallDescriptionMap<FnCheck> Callbacks = {
49*480093f4SDimitry Andric     {{0, "clang_analyzer_container_begin", 1},
50*480093f4SDimitry Andric      &DebugIteratorModeling::analyzerContainerBegin},
51*480093f4SDimitry Andric     {{0, "clang_analyzer_container_end", 1},
52*480093f4SDimitry Andric      &DebugIteratorModeling::analyzerContainerEnd},
53*480093f4SDimitry Andric     {{0, "clang_analyzer_iterator_position", 1},
54*480093f4SDimitry Andric      &DebugIteratorModeling::analyzerIteratorPosition},
55*480093f4SDimitry Andric     {{0, "clang_analyzer_iterator_container", 1},
56*480093f4SDimitry Andric      &DebugIteratorModeling::analyzerIteratorContainer},
57*480093f4SDimitry Andric     {{0, "clang_analyzer_iterator_validity", 1},
58*480093f4SDimitry Andric      &DebugIteratorModeling::analyzerIteratorValidity},
59*480093f4SDimitry Andric   };
60*480093f4SDimitry Andric 
61*480093f4SDimitry Andric public:
62*480093f4SDimitry Andric   DebugIteratorModeling();
63*480093f4SDimitry Andric 
64*480093f4SDimitry Andric   bool evalCall(const CallEvent &Call, CheckerContext &C) const;
65*480093f4SDimitry Andric };
66*480093f4SDimitry Andric 
67*480093f4SDimitry Andric } //namespace
68*480093f4SDimitry Andric 
69*480093f4SDimitry Andric DebugIteratorModeling::DebugIteratorModeling() {
70*480093f4SDimitry Andric   DebugMsgBugType.reset(
71*480093f4SDimitry Andric       new BugType(this, "Checking analyzer assumptions", "debug",
72*480093f4SDimitry Andric                   /*SuppressOnSink=*/true));
73*480093f4SDimitry Andric }
74*480093f4SDimitry Andric 
75*480093f4SDimitry Andric bool DebugIteratorModeling::evalCall(const CallEvent &Call,
76*480093f4SDimitry Andric                                      CheckerContext &C) const {
77*480093f4SDimitry Andric   const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
78*480093f4SDimitry Andric   if (!CE)
79*480093f4SDimitry Andric     return false;
80*480093f4SDimitry Andric 
81*480093f4SDimitry Andric   const FnCheck *Handler = Callbacks.lookup(Call);
82*480093f4SDimitry Andric   if (!Handler)
83*480093f4SDimitry Andric     return false;
84*480093f4SDimitry Andric 
85*480093f4SDimitry Andric   (this->**Handler)(CE, C);
86*480093f4SDimitry Andric   return true;
87*480093f4SDimitry Andric }
88*480093f4SDimitry Andric 
89*480093f4SDimitry Andric template <typename Getter>
90*480093f4SDimitry Andric void DebugIteratorModeling::analyzerContainerDataField(const CallExpr *CE,
91*480093f4SDimitry Andric                                                        CheckerContext &C,
92*480093f4SDimitry Andric                                                        Getter get) const {
93*480093f4SDimitry Andric   if (CE->getNumArgs() == 0) {
94*480093f4SDimitry Andric     reportDebugMsg("Missing container argument", C);
95*480093f4SDimitry Andric     return;
96*480093f4SDimitry Andric   }
97*480093f4SDimitry Andric 
98*480093f4SDimitry Andric   auto State = C.getState();
99*480093f4SDimitry Andric   const MemRegion *Cont = C.getSVal(CE->getArg(0)).getAsRegion();
100*480093f4SDimitry Andric   if (Cont) {
101*480093f4SDimitry Andric     const auto *Data = getContainerData(State, Cont);
102*480093f4SDimitry Andric     if (Data) {
103*480093f4SDimitry Andric       SymbolRef Field = get(Data);
104*480093f4SDimitry Andric       if (Field) {
105*480093f4SDimitry Andric         State = State->BindExpr(CE, C.getLocationContext(),
106*480093f4SDimitry Andric                                 nonloc::SymbolVal(Field));
107*480093f4SDimitry Andric         C.addTransition(State);
108*480093f4SDimitry Andric         return;
109*480093f4SDimitry Andric       }
110*480093f4SDimitry Andric     }
111*480093f4SDimitry Andric   }
112*480093f4SDimitry Andric 
113*480093f4SDimitry Andric   auto &BVF = C.getSValBuilder().getBasicValueFactory();
114*480093f4SDimitry Andric   State = State->BindExpr(CE, C.getLocationContext(),
115*480093f4SDimitry Andric                    nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));
116*480093f4SDimitry Andric }
117*480093f4SDimitry Andric 
118*480093f4SDimitry Andric void DebugIteratorModeling::analyzerContainerBegin(const CallExpr *CE,
119*480093f4SDimitry Andric                                                    CheckerContext &C) const {
120*480093f4SDimitry Andric   analyzerContainerDataField(CE, C, [](const ContainerData *D) {
121*480093f4SDimitry Andric       return D->getBegin();
122*480093f4SDimitry Andric     });
123*480093f4SDimitry Andric }
124*480093f4SDimitry Andric 
125*480093f4SDimitry Andric void DebugIteratorModeling::analyzerContainerEnd(const CallExpr *CE,
126*480093f4SDimitry Andric                                                  CheckerContext &C) const {
127*480093f4SDimitry Andric   analyzerContainerDataField(CE, C, [](const ContainerData *D) {
128*480093f4SDimitry Andric       return D->getEnd();
129*480093f4SDimitry Andric     });
130*480093f4SDimitry Andric }
131*480093f4SDimitry Andric 
132*480093f4SDimitry Andric template <typename Getter>
133*480093f4SDimitry Andric void DebugIteratorModeling::analyzerIteratorDataField(const CallExpr *CE,
134*480093f4SDimitry Andric                                                       CheckerContext &C,
135*480093f4SDimitry Andric                                                       Getter get,
136*480093f4SDimitry Andric                                                       SVal Default) const {
137*480093f4SDimitry Andric   if (CE->getNumArgs() == 0) {
138*480093f4SDimitry Andric     reportDebugMsg("Missing iterator argument", C);
139*480093f4SDimitry Andric     return;
140*480093f4SDimitry Andric   }
141*480093f4SDimitry Andric 
142*480093f4SDimitry Andric   auto State = C.getState();
143*480093f4SDimitry Andric   SVal V = C.getSVal(CE->getArg(0));
144*480093f4SDimitry Andric   const auto *Pos = getIteratorPosition(State, V);
145*480093f4SDimitry Andric   if (Pos) {
146*480093f4SDimitry Andric     State = State->BindExpr(CE, C.getLocationContext(), get(Pos));
147*480093f4SDimitry Andric   } else {
148*480093f4SDimitry Andric     State = State->BindExpr(CE, C.getLocationContext(), Default);
149*480093f4SDimitry Andric   }
150*480093f4SDimitry Andric   C.addTransition(State);
151*480093f4SDimitry Andric }
152*480093f4SDimitry Andric 
153*480093f4SDimitry Andric void DebugIteratorModeling::analyzerIteratorPosition(const CallExpr *CE,
154*480093f4SDimitry Andric                                                      CheckerContext &C) const {
155*480093f4SDimitry Andric   auto &BVF = C.getSValBuilder().getBasicValueFactory();
156*480093f4SDimitry Andric   analyzerIteratorDataField(CE, C, [](const IteratorPosition *P) {
157*480093f4SDimitry Andric       return nonloc::SymbolVal(P->getOffset());
158*480093f4SDimitry Andric     }, nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));
159*480093f4SDimitry Andric }
160*480093f4SDimitry Andric 
161*480093f4SDimitry Andric void DebugIteratorModeling::analyzerIteratorContainer(const CallExpr *CE,
162*480093f4SDimitry Andric                                                       CheckerContext &C) const {
163*480093f4SDimitry Andric   auto &BVF = C.getSValBuilder().getBasicValueFactory();
164*480093f4SDimitry Andric   analyzerIteratorDataField(CE, C, [](const IteratorPosition *P) {
165*480093f4SDimitry Andric       return loc::MemRegionVal(P->getContainer());
166*480093f4SDimitry Andric     }, loc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));
167*480093f4SDimitry Andric }
168*480093f4SDimitry Andric 
169*480093f4SDimitry Andric void DebugIteratorModeling::analyzerIteratorValidity(const CallExpr *CE,
170*480093f4SDimitry Andric                                                      CheckerContext &C) const {
171*480093f4SDimitry Andric   auto &BVF = C.getSValBuilder().getBasicValueFactory();
172*480093f4SDimitry Andric   analyzerIteratorDataField(CE, C, [&BVF](const IteratorPosition *P) {
173*480093f4SDimitry Andric       return
174*480093f4SDimitry Andric         nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get((P->isValid()))));
175*480093f4SDimitry Andric     }, nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));
176*480093f4SDimitry Andric }
177*480093f4SDimitry Andric 
178*480093f4SDimitry Andric ExplodedNode *DebugIteratorModeling::reportDebugMsg(llvm::StringRef Msg,
179*480093f4SDimitry Andric                                                     CheckerContext &C) const {
180*480093f4SDimitry Andric   ExplodedNode *N = C.generateNonFatalErrorNode();
181*480093f4SDimitry Andric   if (!N)
182*480093f4SDimitry Andric     return nullptr;
183*480093f4SDimitry Andric 
184*480093f4SDimitry Andric   auto &BR = C.getBugReporter();
185*480093f4SDimitry Andric   BR.emitReport(std::make_unique<PathSensitiveBugReport>(*DebugMsgBugType,
186*480093f4SDimitry Andric                                                          Msg, N));
187*480093f4SDimitry Andric   return N;
188*480093f4SDimitry Andric }
189*480093f4SDimitry Andric 
190*480093f4SDimitry Andric void ento::registerDebugIteratorModeling(CheckerManager &mgr) {
191*480093f4SDimitry Andric   mgr.registerChecker<DebugIteratorModeling>();
192*480093f4SDimitry Andric }
193*480093f4SDimitry Andric 
194*480093f4SDimitry Andric bool ento::shouldRegisterDebugIteratorModeling(const LangOptions &LO) {
195*480093f4SDimitry Andric   return true;
196*480093f4SDimitry Andric }
197