1 //===-- DebugIteratorModeling.cpp ---------------------------------*- C++ -*--//
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
7 //===----------------------------------------------------------------------===//
9 // Defines a checker for debugging iterator modeling.
11 //===----------------------------------------------------------------------===//
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/CallDescription.h"
17 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
18 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
22 using namespace clang
;
24 using namespace iterator
;
28 class DebugIteratorModeling
29 : public Checker
<eval::Call
> {
31 std::unique_ptr
<BugType
> DebugMsgBugType
;
33 template <typename Getter
>
34 void analyzerIteratorDataField(const CallExpr
*CE
, CheckerContext
&C
,
35 Getter get
, SVal Default
) const;
36 void analyzerIteratorPosition(const CallExpr
*CE
, CheckerContext
&C
) const;
37 void analyzerIteratorContainer(const CallExpr
*CE
, CheckerContext
&C
) const;
38 void analyzerIteratorValidity(const CallExpr
*CE
, CheckerContext
&C
) const;
39 ExplodedNode
*reportDebugMsg(llvm::StringRef Msg
, CheckerContext
&C
) const;
41 typedef void (DebugIteratorModeling::*FnCheck
)(const CallExpr
*,
42 CheckerContext
&) const;
44 CallDescriptionMap
<FnCheck
> Callbacks
= {
45 {{{"clang_analyzer_iterator_position"}, 1},
46 &DebugIteratorModeling::analyzerIteratorPosition
},
47 {{{"clang_analyzer_iterator_container"}, 1},
48 &DebugIteratorModeling::analyzerIteratorContainer
},
49 {{{"clang_analyzer_iterator_validity"}, 1},
50 &DebugIteratorModeling::analyzerIteratorValidity
},
54 DebugIteratorModeling();
56 bool evalCall(const CallEvent
&Call
, CheckerContext
&C
) const;
61 DebugIteratorModeling::DebugIteratorModeling() {
62 DebugMsgBugType
.reset(
63 new BugType(this, "Checking analyzer assumptions", "debug",
64 /*SuppressOnSink=*/true));
67 bool DebugIteratorModeling::evalCall(const CallEvent
&Call
,
68 CheckerContext
&C
) const {
69 const auto *CE
= dyn_cast_or_null
<CallExpr
>(Call
.getOriginExpr());
73 const FnCheck
*Handler
= Callbacks
.lookup(Call
);
77 (this->**Handler
)(CE
, C
);
81 template <typename Getter
>
82 void DebugIteratorModeling::analyzerIteratorDataField(const CallExpr
*CE
,
86 if (CE
->getNumArgs() == 0) {
87 reportDebugMsg("Missing iterator argument", C
);
91 auto State
= C
.getState();
92 SVal V
= C
.getSVal(CE
->getArg(0));
93 const auto *Pos
= getIteratorPosition(State
, V
);
95 State
= State
->BindExpr(CE
, C
.getLocationContext(), get(Pos
));
97 State
= State
->BindExpr(CE
, C
.getLocationContext(), Default
);
99 C
.addTransition(State
);
102 void DebugIteratorModeling::analyzerIteratorPosition(const CallExpr
*CE
,
103 CheckerContext
&C
) const {
104 auto &BVF
= C
.getSValBuilder().getBasicValueFactory();
105 analyzerIteratorDataField(CE
, C
, [](const IteratorPosition
*P
) {
106 return nonloc::SymbolVal(P
->getOffset());
107 }, nonloc::ConcreteInt(BVF
.getValue(llvm::APSInt::get(0))));
110 void DebugIteratorModeling::analyzerIteratorContainer(const CallExpr
*CE
,
111 CheckerContext
&C
) const {
112 auto &BVF
= C
.getSValBuilder().getBasicValueFactory();
113 analyzerIteratorDataField(CE
, C
, [](const IteratorPosition
*P
) {
114 return loc::MemRegionVal(P
->getContainer());
115 }, loc::ConcreteInt(BVF
.getValue(llvm::APSInt::get(0))));
118 void DebugIteratorModeling::analyzerIteratorValidity(const CallExpr
*CE
,
119 CheckerContext
&C
) const {
120 auto &BVF
= C
.getSValBuilder().getBasicValueFactory();
121 analyzerIteratorDataField(CE
, C
, [&BVF
](const IteratorPosition
*P
) {
123 nonloc::ConcreteInt(BVF
.getValue(llvm::APSInt::get((P
->isValid()))));
124 }, nonloc::ConcreteInt(BVF
.getValue(llvm::APSInt::get(0))));
127 ExplodedNode
*DebugIteratorModeling::reportDebugMsg(llvm::StringRef Msg
,
128 CheckerContext
&C
) const {
129 ExplodedNode
*N
= C
.generateNonFatalErrorNode();
133 auto &BR
= C
.getBugReporter();
134 BR
.emitReport(std::make_unique
<PathSensitiveBugReport
>(*DebugMsgBugType
,
139 void ento::registerDebugIteratorModeling(CheckerManager
&mgr
) {
140 mgr
.registerChecker
<DebugIteratorModeling
>();
143 bool ento::shouldRegisterDebugIteratorModeling(const CheckerManager
&mgr
) {