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