Coverage Report

Created: 2023-11-11 10:31

/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
}