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/CallEvent.h"
17 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
21 using namespace clang;
23 using namespace iterator;
27 class DebugIteratorModeling
28 : public Checker<eval::Call> {
30 std::unique_ptr<BugType> DebugMsgBugType;
32 template <typename Getter>
33 void analyzerIteratorDataField(const CallExpr *CE, CheckerContext &C,
34 Getter get, SVal Default) const;
35 void analyzerIteratorPosition(const CallExpr *CE, CheckerContext &C) const;
36 void analyzerIteratorContainer(const CallExpr *CE, CheckerContext &C) const;
37 void analyzerIteratorValidity(const CallExpr *CE, CheckerContext &C) const;
38 ExplodedNode *reportDebugMsg(llvm::StringRef Msg, CheckerContext &C) const;
40 typedef void (DebugIteratorModeling::*FnCheck)(const CallExpr *,
41 CheckerContext &) const;
43 CallDescriptionMap<FnCheck> Callbacks = {
44 {{0, "clang_analyzer_iterator_position", 1},
45 &DebugIteratorModeling::analyzerIteratorPosition},
46 {{0, "clang_analyzer_iterator_container", 1},
47 &DebugIteratorModeling::analyzerIteratorContainer},
48 {{0, "clang_analyzer_iterator_validity", 1},
49 &DebugIteratorModeling::analyzerIteratorValidity},
53 DebugIteratorModeling();
55 bool evalCall(const CallEvent &Call, CheckerContext &C) const;
60 DebugIteratorModeling::DebugIteratorModeling() {
61 DebugMsgBugType.reset(
62 new BugType(this, "Checking analyzer assumptions", "debug",
63 /*SuppressOnSink=*/true));
66 bool DebugIteratorModeling::evalCall(const CallEvent &Call,
67 CheckerContext &C) const {
68 const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
72 const FnCheck *Handler = Callbacks.lookup(Call);
76 (this->**Handler)(CE, C);
80 template <typename Getter>
81 void DebugIteratorModeling::analyzerIteratorDataField(const CallExpr *CE,
85 if (CE->getNumArgs() == 0) {
86 reportDebugMsg("Missing iterator argument", C);
90 auto State = C.getState();
91 SVal V = C.getSVal(CE->getArg(0));
92 const auto *Pos = getIteratorPosition(State, V);
94 State = State->BindExpr(CE, C.getLocationContext(), get(Pos));
96 State = State->BindExpr(CE, C.getLocationContext(), Default);
98 C.addTransition(State);
101 void DebugIteratorModeling::analyzerIteratorPosition(const CallExpr *CE,
102 CheckerContext &C) const {
103 auto &BVF = C.getSValBuilder().getBasicValueFactory();
104 analyzerIteratorDataField(CE, C, [](const IteratorPosition *P) {
105 return nonloc::SymbolVal(P->getOffset());
106 }, nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));
109 void DebugIteratorModeling::analyzerIteratorContainer(const CallExpr *CE,
110 CheckerContext &C) const {
111 auto &BVF = C.getSValBuilder().getBasicValueFactory();
112 analyzerIteratorDataField(CE, C, [](const IteratorPosition *P) {
113 return loc::MemRegionVal(P->getContainer());
114 }, loc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));
117 void DebugIteratorModeling::analyzerIteratorValidity(const CallExpr *CE,
118 CheckerContext &C) const {
119 auto &BVF = C.getSValBuilder().getBasicValueFactory();
120 analyzerIteratorDataField(CE, C, [&BVF](const IteratorPosition *P) {
122 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get((P->isValid()))));
123 }, nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));
126 ExplodedNode *DebugIteratorModeling::reportDebugMsg(llvm::StringRef Msg,
127 CheckerContext &C) const {
128 ExplodedNode *N = C.generateNonFatalErrorNode();
132 auto &BR = C.getBugReporter();
133 BR.emitReport(std::make_unique<PathSensitiveBugReport>(*DebugMsgBugType,
138 void ento::registerDebugIteratorModeling(CheckerManager &mgr) {
139 mgr.registerChecker<DebugIteratorModeling>();
142 bool ento::shouldRegisterDebugIteratorModeling(const CheckerManager &mgr) {