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