/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===-- DebugIteratorModeling.cpp ---------------------------------*- C++ -*--// |
2 | | // |
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 |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | // |
9 | | // Defines a checker for debugging iterator modeling. |
10 | | // |
11 | | //===----------------------------------------------------------------------===// |
12 | | |
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" |
19 | | |
20 | | #include "Iterator.h" |
21 | | |
22 | | using namespace clang; |
23 | | using namespace ento; |
24 | | using namespace iterator; |
25 | | |
26 | | namespace { |
27 | | |
28 | | class DebugIteratorModeling |
29 | | : public Checker<eval::Call> { |
30 | | |
31 | | std::unique_ptr<BugType> DebugMsgBugType; |
32 | | |
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; |
40 | | |
41 | | typedef void (DebugIteratorModeling::*FnCheck)(const CallExpr *, |
42 | | CheckerContext &) const; |
43 | | |
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}, |
51 | | }; |
52 | | |
53 | | public: |
54 | | DebugIteratorModeling(); |
55 | | |
56 | | bool evalCall(const CallEvent &Call, CheckerContext &C) const; |
57 | | }; |
58 | | |
59 | | } //namespace |
60 | | |
61 | 11 | DebugIteratorModeling::DebugIteratorModeling() { |
62 | 11 | DebugMsgBugType.reset( |
63 | 11 | new BugType(this, "Checking analyzer assumptions", "debug", |
64 | 11 | /*SuppressOnSink=*/true)); |
65 | 11 | } |
66 | | |
67 | | bool DebugIteratorModeling::evalCall(const CallEvent &Call, |
68 | 12.0k | CheckerContext &C) const { |
69 | 12.0k | const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr()); |
70 | 12.0k | if (!CE) |
71 | 1.49k | return false; |
72 | | |
73 | 10.5k | const FnCheck *Handler = Callbacks.lookup(Call); |
74 | 10.5k | if (!Handler) |
75 | 7.90k | return false; |
76 | | |
77 | 2.68k | (this->**Handler)(CE, C); |
78 | 2.68k | return true; |
79 | 10.5k | } |
80 | | |
81 | | template <typename Getter> |
82 | | void DebugIteratorModeling::analyzerIteratorDataField(const CallExpr *CE, |
83 | | CheckerContext &C, |
84 | | Getter get, |
85 | 2.68k | SVal Default) const { |
86 | 2.68k | if (CE->getNumArgs() == 0) { |
87 | 0 | reportDebugMsg("Missing iterator argument", C); |
88 | 0 | return; |
89 | 0 | } |
90 | | |
91 | 2.68k | auto State = C.getState(); |
92 | 2.68k | SVal V = C.getSVal(CE->getArg(0)); |
93 | 2.68k | const auto *Pos = getIteratorPosition(State, V); |
94 | 2.68k | if (Pos) { |
95 | 2.68k | State = State->BindExpr(CE, C.getLocationContext(), get(Pos)); |
96 | 2.68k | } else { |
97 | 0 | State = State->BindExpr(CE, C.getLocationContext(), Default); |
98 | 0 | } |
99 | 2.68k | C.addTransition(State); |
100 | 2.68k | } DebugIteratorModeling.cpp:void (anonymous namespace)::DebugIteratorModeling::analyzerIteratorDataField<(anonymous namespace)::DebugIteratorModeling::analyzerIteratorPosition(clang::CallExpr const*, clang::ento::CheckerContext&) const::$_0>(clang::CallExpr const*, clang::ento::CheckerContext&, (anonymous namespace)::DebugIteratorModeling::analyzerIteratorPosition(clang::CallExpr const*, clang::ento::CheckerContext&) const::$_0, clang::ento::SVal) const Line | Count | Source | 85 | 1.40k | SVal Default) const { | 86 | 1.40k | if (CE->getNumArgs() == 0) { | 87 | 0 | reportDebugMsg("Missing iterator argument", C); | 88 | 0 | return; | 89 | 0 | } | 90 | | | 91 | 1.40k | auto State = C.getState(); | 92 | 1.40k | SVal V = C.getSVal(CE->getArg(0)); | 93 | 1.40k | const auto *Pos = getIteratorPosition(State, V); | 94 | 1.40k | if (Pos) { | 95 | 1.40k | State = State->BindExpr(CE, C.getLocationContext(), get(Pos)); | 96 | 1.40k | } else { | 97 | 0 | State = State->BindExpr(CE, C.getLocationContext(), Default); | 98 | 0 | } | 99 | 1.40k | C.addTransition(State); | 100 | 1.40k | } |
DebugIteratorModeling.cpp:void (anonymous namespace)::DebugIteratorModeling::analyzerIteratorDataField<(anonymous namespace)::DebugIteratorModeling::analyzerIteratorContainer(clang::CallExpr const*, clang::ento::CheckerContext&) const::$_0>(clang::CallExpr const*, clang::ento::CheckerContext&, (anonymous namespace)::DebugIteratorModeling::analyzerIteratorContainer(clang::CallExpr const*, clang::ento::CheckerContext&) const::$_0, clang::ento::SVal) const Line | Count | Source | 85 | 102 | SVal Default) const { | 86 | 102 | if (CE->getNumArgs() == 0) { | 87 | 0 | reportDebugMsg("Missing iterator argument", C); | 88 | 0 | return; | 89 | 0 | } | 90 | | | 91 | 102 | auto State = C.getState(); | 92 | 102 | SVal V = C.getSVal(CE->getArg(0)); | 93 | 102 | const auto *Pos = getIteratorPosition(State, V); | 94 | 102 | if (Pos) { | 95 | 102 | State = State->BindExpr(CE, C.getLocationContext(), get(Pos)); | 96 | 102 | } else { | 97 | 0 | State = State->BindExpr(CE, C.getLocationContext(), Default); | 98 | 0 | } | 99 | 102 | C.addTransition(State); | 100 | 102 | } |
DebugIteratorModeling.cpp:void (anonymous namespace)::DebugIteratorModeling::analyzerIteratorDataField<(anonymous namespace)::DebugIteratorModeling::analyzerIteratorValidity(clang::CallExpr const*, clang::ento::CheckerContext&) const::$_0>(clang::CallExpr const*, clang::ento::CheckerContext&, (anonymous namespace)::DebugIteratorModeling::analyzerIteratorValidity(clang::CallExpr const*, clang::ento::CheckerContext&) const::$_0, clang::ento::SVal) const Line | Count | Source | 85 | 1.17k | SVal Default) const { | 86 | 1.17k | if (CE->getNumArgs() == 0) { | 87 | 0 | reportDebugMsg("Missing iterator argument", C); | 88 | 0 | return; | 89 | 0 | } | 90 | | | 91 | 1.17k | auto State = C.getState(); | 92 | 1.17k | SVal V = C.getSVal(CE->getArg(0)); | 93 | 1.17k | const auto *Pos = getIteratorPosition(State, V); | 94 | 1.17k | if (Pos) { | 95 | 1.17k | State = State->BindExpr(CE, C.getLocationContext(), get(Pos)); | 96 | 1.17k | } else { | 97 | 0 | State = State->BindExpr(CE, C.getLocationContext(), Default); | 98 | 0 | } | 99 | 1.17k | C.addTransition(State); | 100 | 1.17k | } |
|
101 | | |
102 | | void DebugIteratorModeling::analyzerIteratorPosition(const CallExpr *CE, |
103 | 1.40k | CheckerContext &C) const { |
104 | 1.40k | auto &BVF = C.getSValBuilder().getBasicValueFactory(); |
105 | 1.40k | analyzerIteratorDataField(CE, C, [](const IteratorPosition *P) { |
106 | 1.40k | return nonloc::SymbolVal(P->getOffset()); |
107 | 1.40k | }, nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0)))); |
108 | 1.40k | } |
109 | | |
110 | | void DebugIteratorModeling::analyzerIteratorContainer(const CallExpr *CE, |
111 | 102 | CheckerContext &C) const { |
112 | 102 | auto &BVF = C.getSValBuilder().getBasicValueFactory(); |
113 | 102 | analyzerIteratorDataField(CE, C, [](const IteratorPosition *P) { |
114 | 102 | return loc::MemRegionVal(P->getContainer()); |
115 | 102 | }, loc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0)))); |
116 | 102 | } |
117 | | |
118 | | void DebugIteratorModeling::analyzerIteratorValidity(const CallExpr *CE, |
119 | 1.17k | CheckerContext &C) const { |
120 | 1.17k | auto &BVF = C.getSValBuilder().getBasicValueFactory(); |
121 | 1.17k | analyzerIteratorDataField(CE, C, [&BVF](const IteratorPosition *P) { |
122 | 1.17k | return |
123 | 1.17k | nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get((P->isValid())))); |
124 | 1.17k | }, nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0)))); |
125 | 1.17k | } |
126 | | |
127 | | ExplodedNode *DebugIteratorModeling::reportDebugMsg(llvm::StringRef Msg, |
128 | 0 | CheckerContext &C) const { |
129 | 0 | ExplodedNode *N = C.generateNonFatalErrorNode(); |
130 | 0 | if (!N) |
131 | 0 | return nullptr; |
132 | | |
133 | 0 | auto &BR = C.getBugReporter(); |
134 | 0 | BR.emitReport(std::make_unique<PathSensitiveBugReport>(*DebugMsgBugType, |
135 | 0 | Msg, N)); |
136 | 0 | return N; |
137 | 0 | } |
138 | | |
139 | 11 | void ento::registerDebugIteratorModeling(CheckerManager &mgr) { |
140 | 11 | mgr.registerChecker<DebugIteratorModeling>(); |
141 | 11 | } |
142 | | |
143 | 24 | bool ento::shouldRegisterDebugIteratorModeling(const CheckerManager &mgr) { |
144 | 24 | return true; |
145 | 24 | } |