1 //==-- DebugContainerModeling.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 DebugContainerModeling
29 : public Checker
<eval::Call
> {
31 std::unique_ptr
<BugType
> DebugMsgBugType
;
33 template <typename Getter
>
34 void analyzerContainerDataField(const CallExpr
*CE
, CheckerContext
&C
,
36 void analyzerContainerBegin(const CallExpr
*CE
, CheckerContext
&C
) const;
37 void analyzerContainerEnd(const CallExpr
*CE
, CheckerContext
&C
) const;
38 ExplodedNode
*reportDebugMsg(llvm::StringRef Msg
, CheckerContext
&C
) const;
40 typedef void (DebugContainerModeling::*FnCheck
)(const CallExpr
*,
41 CheckerContext
&) const;
43 CallDescriptionMap
<FnCheck
> Callbacks
= {
44 {{{"clang_analyzer_container_begin"}, 1},
45 &DebugContainerModeling::analyzerContainerBegin
},
46 {{{"clang_analyzer_container_end"}, 1},
47 &DebugContainerModeling::analyzerContainerEnd
},
51 DebugContainerModeling();
53 bool evalCall(const CallEvent
&Call
, CheckerContext
&C
) const;
58 DebugContainerModeling::DebugContainerModeling() {
59 DebugMsgBugType
.reset(
60 new BugType(this, "Checking analyzer assumptions", "debug",
61 /*SuppressOnSink=*/true));
64 bool DebugContainerModeling::evalCall(const CallEvent
&Call
,
65 CheckerContext
&C
) const {
66 const auto *CE
= dyn_cast_or_null
<CallExpr
>(Call
.getOriginExpr());
70 const FnCheck
*Handler
= Callbacks
.lookup(Call
);
74 (this->**Handler
)(CE
, C
);
78 template <typename Getter
>
79 void DebugContainerModeling::analyzerContainerDataField(const CallExpr
*CE
,
82 if (CE
->getNumArgs() == 0) {
83 reportDebugMsg("Missing container argument", C
);
87 auto State
= C
.getState();
88 const MemRegion
*Cont
= C
.getSVal(CE
->getArg(0)).getAsRegion();
90 const auto *Data
= getContainerData(State
, Cont
);
92 SymbolRef Field
= get(Data
);
94 State
= State
->BindExpr(CE
, C
.getLocationContext(),
95 nonloc::SymbolVal(Field
));
97 // Progpagate interestingness from the container's data (marked
98 // interesting by an `ExprInspection` debug call to the container
100 const NoteTag
*InterestingTag
=
102 [Cont
, Field
](PathSensitiveBugReport
&BR
) -> std::string
{
103 if (BR
.isInteresting(Field
)) {
104 BR
.markInteresting(Cont
);
108 C
.addTransition(State
, InterestingTag
);
114 auto &BVF
= C
.getSValBuilder().getBasicValueFactory();
115 State
= State
->BindExpr(CE
, C
.getLocationContext(),
116 nonloc::ConcreteInt(BVF
.getValue(llvm::APSInt::get(0))));
119 void DebugContainerModeling::analyzerContainerBegin(const CallExpr
*CE
,
120 CheckerContext
&C
) const {
121 analyzerContainerDataField(CE
, C
, [](const ContainerData
*D
) {
122 return D
->getBegin();
126 void DebugContainerModeling::analyzerContainerEnd(const CallExpr
*CE
,
127 CheckerContext
&C
) const {
128 analyzerContainerDataField(CE
, C
, [](const ContainerData
*D
) {
133 ExplodedNode
*DebugContainerModeling::reportDebugMsg(llvm::StringRef Msg
,
134 CheckerContext
&C
) const {
135 ExplodedNode
*N
= C
.generateNonFatalErrorNode();
139 auto &BR
= C
.getBugReporter();
140 BR
.emitReport(std::make_unique
<PathSensitiveBugReport
>(*DebugMsgBugType
,
145 void ento::registerDebugContainerModeling(CheckerManager
&mgr
) {
146 mgr
.registerChecker
<DebugContainerModeling
>();
149 bool ento::shouldRegisterDebugContainerModeling(const CheckerManager
&mgr
) {