xref: /openbsd-src/gnu/llvm/clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
1e5dd7070Spatrick //===-- DebugIteratorModeling.cpp ---------------------------------*- C++ -*--//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // Defines a checker for debugging iterator modeling.
10e5dd7070Spatrick //
11e5dd7070Spatrick //===----------------------------------------------------------------------===//
12e5dd7070Spatrick 
13e5dd7070Spatrick #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
14e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
15e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/Checker.h"
16*12c85518Srobert #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
17e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
18e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
19e5dd7070Spatrick 
20e5dd7070Spatrick #include "Iterator.h"
21e5dd7070Spatrick 
22e5dd7070Spatrick using namespace clang;
23e5dd7070Spatrick using namespace ento;
24e5dd7070Spatrick using namespace iterator;
25e5dd7070Spatrick 
26e5dd7070Spatrick namespace {
27e5dd7070Spatrick 
28e5dd7070Spatrick class DebugIteratorModeling
29e5dd7070Spatrick   : public Checker<eval::Call> {
30e5dd7070Spatrick 
31e5dd7070Spatrick   std::unique_ptr<BugType> DebugMsgBugType;
32e5dd7070Spatrick 
33e5dd7070Spatrick   template <typename Getter>
34e5dd7070Spatrick   void analyzerIteratorDataField(const CallExpr *CE, CheckerContext &C,
35e5dd7070Spatrick                                  Getter get, SVal Default) const;
36e5dd7070Spatrick   void analyzerIteratorPosition(const CallExpr *CE, CheckerContext &C) const;
37e5dd7070Spatrick   void analyzerIteratorContainer(const CallExpr *CE, CheckerContext &C) const;
38e5dd7070Spatrick   void analyzerIteratorValidity(const CallExpr *CE, CheckerContext &C) const;
39e5dd7070Spatrick   ExplodedNode *reportDebugMsg(llvm::StringRef Msg, CheckerContext &C) const;
40e5dd7070Spatrick 
41e5dd7070Spatrick   typedef void (DebugIteratorModeling::*FnCheck)(const CallExpr *,
42e5dd7070Spatrick                                                  CheckerContext &) const;
43e5dd7070Spatrick 
44e5dd7070Spatrick   CallDescriptionMap<FnCheck> Callbacks = {
45*12c85518Srobert       {{{"clang_analyzer_iterator_position"}, 1},
46e5dd7070Spatrick        &DebugIteratorModeling::analyzerIteratorPosition},
47*12c85518Srobert       {{{"clang_analyzer_iterator_container"}, 1},
48e5dd7070Spatrick        &DebugIteratorModeling::analyzerIteratorContainer},
49*12c85518Srobert       {{{"clang_analyzer_iterator_validity"}, 1},
50e5dd7070Spatrick        &DebugIteratorModeling::analyzerIteratorValidity},
51e5dd7070Spatrick   };
52e5dd7070Spatrick 
53e5dd7070Spatrick public:
54e5dd7070Spatrick   DebugIteratorModeling();
55e5dd7070Spatrick 
56e5dd7070Spatrick   bool evalCall(const CallEvent &Call, CheckerContext &C) const;
57e5dd7070Spatrick };
58e5dd7070Spatrick 
59e5dd7070Spatrick } //namespace
60e5dd7070Spatrick 
DebugIteratorModeling()61e5dd7070Spatrick DebugIteratorModeling::DebugIteratorModeling() {
62e5dd7070Spatrick   DebugMsgBugType.reset(
63e5dd7070Spatrick       new BugType(this, "Checking analyzer assumptions", "debug",
64e5dd7070Spatrick                   /*SuppressOnSink=*/true));
65e5dd7070Spatrick }
66e5dd7070Spatrick 
evalCall(const CallEvent & Call,CheckerContext & C) const67e5dd7070Spatrick bool DebugIteratorModeling::evalCall(const CallEvent &Call,
68e5dd7070Spatrick                                      CheckerContext &C) const {
69e5dd7070Spatrick   const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
70e5dd7070Spatrick   if (!CE)
71e5dd7070Spatrick     return false;
72e5dd7070Spatrick 
73e5dd7070Spatrick   const FnCheck *Handler = Callbacks.lookup(Call);
74e5dd7070Spatrick   if (!Handler)
75e5dd7070Spatrick     return false;
76e5dd7070Spatrick 
77e5dd7070Spatrick   (this->**Handler)(CE, C);
78e5dd7070Spatrick   return true;
79e5dd7070Spatrick }
80e5dd7070Spatrick 
81e5dd7070Spatrick template <typename Getter>
analyzerIteratorDataField(const CallExpr * CE,CheckerContext & C,Getter get,SVal Default) const82e5dd7070Spatrick void DebugIteratorModeling::analyzerIteratorDataField(const CallExpr *CE,
83e5dd7070Spatrick                                                       CheckerContext &C,
84e5dd7070Spatrick                                                       Getter get,
85e5dd7070Spatrick                                                       SVal Default) const {
86e5dd7070Spatrick   if (CE->getNumArgs() == 0) {
87e5dd7070Spatrick     reportDebugMsg("Missing iterator argument", C);
88e5dd7070Spatrick     return;
89e5dd7070Spatrick   }
90e5dd7070Spatrick 
91e5dd7070Spatrick   auto State = C.getState();
92e5dd7070Spatrick   SVal V = C.getSVal(CE->getArg(0));
93e5dd7070Spatrick   const auto *Pos = getIteratorPosition(State, V);
94e5dd7070Spatrick   if (Pos) {
95e5dd7070Spatrick     State = State->BindExpr(CE, C.getLocationContext(), get(Pos));
96e5dd7070Spatrick   } else {
97e5dd7070Spatrick     State = State->BindExpr(CE, C.getLocationContext(), Default);
98e5dd7070Spatrick   }
99e5dd7070Spatrick   C.addTransition(State);
100e5dd7070Spatrick }
101e5dd7070Spatrick 
analyzerIteratorPosition(const CallExpr * CE,CheckerContext & C) const102e5dd7070Spatrick void DebugIteratorModeling::analyzerIteratorPosition(const CallExpr *CE,
103e5dd7070Spatrick                                                      CheckerContext &C) const {
104e5dd7070Spatrick   auto &BVF = C.getSValBuilder().getBasicValueFactory();
105e5dd7070Spatrick   analyzerIteratorDataField(CE, C, [](const IteratorPosition *P) {
106e5dd7070Spatrick       return nonloc::SymbolVal(P->getOffset());
107e5dd7070Spatrick     }, nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));
108e5dd7070Spatrick }
109e5dd7070Spatrick 
analyzerIteratorContainer(const CallExpr * CE,CheckerContext & C) const110e5dd7070Spatrick void DebugIteratorModeling::analyzerIteratorContainer(const CallExpr *CE,
111e5dd7070Spatrick                                                       CheckerContext &C) const {
112e5dd7070Spatrick   auto &BVF = C.getSValBuilder().getBasicValueFactory();
113e5dd7070Spatrick   analyzerIteratorDataField(CE, C, [](const IteratorPosition *P) {
114e5dd7070Spatrick       return loc::MemRegionVal(P->getContainer());
115e5dd7070Spatrick     }, loc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));
116e5dd7070Spatrick }
117e5dd7070Spatrick 
analyzerIteratorValidity(const CallExpr * CE,CheckerContext & C) const118e5dd7070Spatrick void DebugIteratorModeling::analyzerIteratorValidity(const CallExpr *CE,
119e5dd7070Spatrick                                                      CheckerContext &C) const {
120e5dd7070Spatrick   auto &BVF = C.getSValBuilder().getBasicValueFactory();
121e5dd7070Spatrick   analyzerIteratorDataField(CE, C, [&BVF](const IteratorPosition *P) {
122e5dd7070Spatrick       return
123e5dd7070Spatrick         nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get((P->isValid()))));
124e5dd7070Spatrick     }, nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));
125e5dd7070Spatrick }
126e5dd7070Spatrick 
reportDebugMsg(llvm::StringRef Msg,CheckerContext & C) const127e5dd7070Spatrick ExplodedNode *DebugIteratorModeling::reportDebugMsg(llvm::StringRef Msg,
128e5dd7070Spatrick                                                     CheckerContext &C) const {
129e5dd7070Spatrick   ExplodedNode *N = C.generateNonFatalErrorNode();
130e5dd7070Spatrick   if (!N)
131e5dd7070Spatrick     return nullptr;
132e5dd7070Spatrick 
133e5dd7070Spatrick   auto &BR = C.getBugReporter();
134e5dd7070Spatrick   BR.emitReport(std::make_unique<PathSensitiveBugReport>(*DebugMsgBugType,
135e5dd7070Spatrick                                                          Msg, N));
136e5dd7070Spatrick   return N;
137e5dd7070Spatrick }
138e5dd7070Spatrick 
registerDebugIteratorModeling(CheckerManager & mgr)139e5dd7070Spatrick void ento::registerDebugIteratorModeling(CheckerManager &mgr) {
140e5dd7070Spatrick   mgr.registerChecker<DebugIteratorModeling>();
141e5dd7070Spatrick }
142e5dd7070Spatrick 
shouldRegisterDebugIteratorModeling(const CheckerManager & mgr)143ec727ea7Spatrick bool ento::shouldRegisterDebugIteratorModeling(const CheckerManager &mgr) {
144e5dd7070Spatrick   return true;
145e5dd7070Spatrick }
146