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