xref: /llvm-project/clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp (revision 9a08a3fab9993f9b93167de5c783dfed6dd7efc0)
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/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 DebugContainerModeling
28   : public Checker<eval::Call> {
29 
30   std::unique_ptr<BugType> DebugMsgBugType;
31 
32   template <typename Getter>
33   void analyzerContainerDataField(const CallExpr *CE, CheckerContext &C,
34                                   Getter get) const;
35   void analyzerContainerBegin(const CallExpr *CE, CheckerContext &C) const;
36   void analyzerContainerEnd(const CallExpr *CE, CheckerContext &C) const;
37   ExplodedNode *reportDebugMsg(llvm::StringRef Msg, CheckerContext &C) const;
38 
39   typedef void (DebugContainerModeling::*FnCheck)(const CallExpr *,
40                                                  CheckerContext &) const;
41 
42   CallDescriptionMap<FnCheck> Callbacks = {
43     {{0, "clang_analyzer_container_begin", 1},
44      &DebugContainerModeling::analyzerContainerBegin},
45     {{0, "clang_analyzer_container_end", 1},
46      &DebugContainerModeling::analyzerContainerEnd},
47   };
48 
49 public:
50   DebugContainerModeling();
51 
52   bool evalCall(const CallEvent &Call, CheckerContext &C) const;
53 };
54 
55 } //namespace
56 
57 DebugContainerModeling::DebugContainerModeling() {
58   DebugMsgBugType.reset(
59       new BugType(this, "Checking analyzer assumptions", "debug",
60                   /*SuppressOnSink=*/true));
61 }
62 
63 bool DebugContainerModeling::evalCall(const CallEvent &Call,
64                                       CheckerContext &C) const {
65   const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
66   if (!CE)
67     return false;
68 
69   const FnCheck *Handler = Callbacks.lookup(Call);
70   if (!Handler)
71     return false;
72 
73   (this->**Handler)(CE, C);
74   return true;
75 }
76 
77 template <typename Getter>
78 void DebugContainerModeling::analyzerContainerDataField(const CallExpr *CE,
79                                                         CheckerContext &C,
80                                                         Getter get) const {
81   if (CE->getNumArgs() == 0) {
82     reportDebugMsg("Missing container argument", C);
83     return;
84   }
85 
86   auto State = C.getState();
87   const MemRegion *Cont = C.getSVal(CE->getArg(0)).getAsRegion();
88   if (Cont) {
89     const auto *Data = getContainerData(State, Cont);
90     if (Data) {
91       SymbolRef Field = get(Data);
92       if (Field) {
93         State = State->BindExpr(CE, C.getLocationContext(),
94                                 nonloc::SymbolVal(Field));
95         C.addTransition(State);
96         return;
97       }
98     }
99   }
100 
101   auto &BVF = C.getSValBuilder().getBasicValueFactory();
102   State = State->BindExpr(CE, C.getLocationContext(),
103                    nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));
104 }
105 
106 void DebugContainerModeling::analyzerContainerBegin(const CallExpr *CE,
107                                                     CheckerContext &C) const {
108   analyzerContainerDataField(CE, C, [](const ContainerData *D) {
109       return D->getBegin();
110     });
111 }
112 
113 void DebugContainerModeling::analyzerContainerEnd(const CallExpr *CE,
114                                                   CheckerContext &C) const {
115   analyzerContainerDataField(CE, C, [](const ContainerData *D) {
116       return D->getEnd();
117     });
118 }
119 
120 ExplodedNode *DebugContainerModeling::reportDebugMsg(llvm::StringRef Msg,
121                                                      CheckerContext &C) const {
122   ExplodedNode *N = C.generateNonFatalErrorNode();
123   if (!N)
124     return nullptr;
125 
126   auto &BR = C.getBugReporter();
127   BR.emitReport(std::make_unique<PathSensitiveBugReport>(*DebugMsgBugType,
128                                                          Msg, N));
129   return N;
130 }
131 
132 void ento::registerDebugContainerModeling(CheckerManager &mgr) {
133   mgr.registerChecker<DebugContainerModeling>();
134 }
135 
136 bool ento::shouldRegisterDebugContainerModeling(const LangOptions &LO) {
137   return true;
138 }
139