Coverage Report

Created: 2023-09-30 09:22

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp
Line
Count
Source (jump to first uncovered line)
1
//==-- DebugContainerModeling.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 DebugContainerModeling
29
  : public Checker<eval::Call> {
30
31
  std::unique_ptr<BugType> DebugMsgBugType;
32
33
  template <typename Getter>
34
  void analyzerContainerDataField(const CallExpr *CE, CheckerContext &C,
35
                                  Getter get) const;
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;
39
40
  typedef void (DebugContainerModeling::*FnCheck)(const CallExpr *,
41
                                                 CheckerContext &) const;
42
43
  CallDescriptionMap<FnCheck> Callbacks = {
44
      {{{"clang_analyzer_container_begin"}, 1},
45
       &DebugContainerModeling::analyzerContainerBegin},
46
      {{{"clang_analyzer_container_end"}, 1},
47
       &DebugContainerModeling::analyzerContainerEnd},
48
  };
49
50
public:
51
  DebugContainerModeling();
52
53
  bool evalCall(const CallEvent &Call, CheckerContext &C) const;
54
};
55
56
} //namespace
57
58
13
DebugContainerModeling::DebugContainerModeling() {
59
13
  DebugMsgBugType.reset(
60
13
      new BugType(this, "Checking analyzer assumptions", "debug",
61
13
                  /*SuppressOnSink=*/true));
62
13
}
63
64
bool DebugContainerModeling::evalCall(const CallEvent &Call,
65
12.1k
                                      CheckerContext &C) const {
66
12.1k
  const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
67
12.1k
  if (!CE)
68
1.49k
    return false;
69
70
10.6k
  const FnCheck *Handler = Callbacks.lookup(Call);
71
10.6k
  if (!Handler)
72
9.52k
    return false;
73
74
1.08k
  (this->**Handler)(CE, C);
75
1.08k
  return true;
76
10.6k
}
77
78
template <typename Getter>
79
void DebugContainerModeling::analyzerContainerDataField(const CallExpr *CE,
80
                                                        CheckerContext &C,
81
1.08k
                                                        Getter get) const {
82
1.08k
  if (CE->getNumArgs() == 0) {
83
0
    reportDebugMsg("Missing container argument", C);
84
0
    return;
85
0
  }
86
87
1.08k
  auto State = C.getState();
88
1.08k
  const MemRegion *Cont = C.getSVal(CE->getArg(0)).getAsRegion();
89
1.08k
  if (Cont) {
90
1.08k
    const auto *Data = getContainerData(State, Cont);
91
1.08k
    if (Data) {
92
1.08k
      SymbolRef Field = get(Data);
93
1.08k
      if (Field) {
94
1.08k
        State = State->BindExpr(CE, C.getLocationContext(),
95
1.08k
                                nonloc::SymbolVal(Field));
96
97
        // Progpagate interestingness from the container's data (marked
98
        // interesting by an `ExprInspection` debug call to the container
99
        // itself.
100
1.08k
        const NoteTag *InterestingTag =
101
1.08k
          C.getNoteTag(
102
3.65k
              [Cont, Field](PathSensitiveBugReport &BR) -> std::string {
103
3.65k
                if (BR.isInteresting(Field)) {
104
575
                  BR.markInteresting(Cont);
105
575
                }
106
3.65k
                return "";
107
3.65k
              });
DebugContainerModeling.cpp:void (anonymous namespace)::DebugContainerModeling::analyzerContainerDataField<(anonymous namespace)::DebugContainerModeling::analyzerContainerBegin(clang::CallExpr const*, clang::ento::CheckerContext&) const::$_0>(clang::CallExpr const*, clang::ento::CheckerContext&, (anonymous namespace)::DebugContainerModeling::analyzerContainerBegin(clang::CallExpr const*, clang::ento::CheckerContext&) const::$_0) const::'lambda'(clang::ento::PathSensitiveBugReport&)::operator()(clang::ento::PathSensitiveBugReport&) const
Line
Count
Source
102
1.87k
              [Cont, Field](PathSensitiveBugReport &BR) -> std::string {
103
1.87k
                if (BR.isInteresting(Field)) {
104
330
                  BR.markInteresting(Cont);
105
330
                }
106
1.87k
                return "";
107
1.87k
              });
DebugContainerModeling.cpp:void (anonymous namespace)::DebugContainerModeling::analyzerContainerDataField<(anonymous namespace)::DebugContainerModeling::analyzerContainerEnd(clang::CallExpr const*, clang::ento::CheckerContext&) const::$_0>(clang::CallExpr const*, clang::ento::CheckerContext&, (anonymous namespace)::DebugContainerModeling::analyzerContainerEnd(clang::CallExpr const*, clang::ento::CheckerContext&) const::$_0) const::'lambda'(clang::ento::PathSensitiveBugReport&)::operator()(clang::ento::PathSensitiveBugReport&) const
Line
Count
Source
102
1.77k
              [Cont, Field](PathSensitiveBugReport &BR) -> std::string {
103
1.77k
                if (BR.isInteresting(Field)) {
104
245
                  BR.markInteresting(Cont);
105
245
                }
106
1.77k
                return "";
107
1.77k
              });
108
1.08k
        C.addTransition(State, InterestingTag);
109
1.08k
        return;
110
1.08k
      }
111
1.08k
    }
112
1.08k
  }
113
114
0
  auto &BVF = C.getSValBuilder().getBasicValueFactory();
115
0
  State = State->BindExpr(CE, C.getLocationContext(),
116
0
                   nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));
117
0
}
DebugContainerModeling.cpp:void (anonymous namespace)::DebugContainerModeling::analyzerContainerDataField<(anonymous namespace)::DebugContainerModeling::analyzerContainerBegin(clang::CallExpr const*, clang::ento::CheckerContext&) const::$_0>(clang::CallExpr const*, clang::ento::CheckerContext&, (anonymous namespace)::DebugContainerModeling::analyzerContainerBegin(clang::CallExpr const*, clang::ento::CheckerContext&) const::$_0) const
Line
Count
Source
81
507
                                                        Getter get) const {
82
507
  if (CE->getNumArgs() == 0) {
83
0
    reportDebugMsg("Missing container argument", C);
84
0
    return;
85
0
  }
86
87
507
  auto State = C.getState();
88
507
  const MemRegion *Cont = C.getSVal(CE->getArg(0)).getAsRegion();
89
507
  if (Cont) {
90
507
    const auto *Data = getContainerData(State, Cont);
91
507
    if (Data) {
92
507
      SymbolRef Field = get(Data);
93
507
      if (Field) {
94
507
        State = State->BindExpr(CE, C.getLocationContext(),
95
507
                                nonloc::SymbolVal(Field));
96
97
        // Progpagate interestingness from the container's data (marked
98
        // interesting by an `ExprInspection` debug call to the container
99
        // itself.
100
507
        const NoteTag *InterestingTag =
101
507
          C.getNoteTag(
102
507
              [Cont, Field](PathSensitiveBugReport &BR) -> std::string {
103
507
                if (BR.isInteresting(Field)) {
104
507
                  BR.markInteresting(Cont);
105
507
                }
106
507
                return "";
107
507
              });
108
507
        C.addTransition(State, InterestingTag);
109
507
        return;
110
507
      }
111
507
    }
112
507
  }
113
114
0
  auto &BVF = C.getSValBuilder().getBasicValueFactory();
115
0
  State = State->BindExpr(CE, C.getLocationContext(),
116
0
                   nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));
117
0
}
DebugContainerModeling.cpp:void (anonymous namespace)::DebugContainerModeling::analyzerContainerDataField<(anonymous namespace)::DebugContainerModeling::analyzerContainerEnd(clang::CallExpr const*, clang::ento::CheckerContext&) const::$_0>(clang::CallExpr const*, clang::ento::CheckerContext&, (anonymous namespace)::DebugContainerModeling::analyzerContainerEnd(clang::CallExpr const*, clang::ento::CheckerContext&) const::$_0) const
Line
Count
Source
81
574
                                                        Getter get) const {
82
574
  if (CE->getNumArgs() == 0) {
83
0
    reportDebugMsg("Missing container argument", C);
84
0
    return;
85
0
  }
86
87
574
  auto State = C.getState();
88
574
  const MemRegion *Cont = C.getSVal(CE->getArg(0)).getAsRegion();
89
574
  if (Cont) {
90
574
    const auto *Data = getContainerData(State, Cont);
91
574
    if (Data) {
92
574
      SymbolRef Field = get(Data);
93
574
      if (Field) {
94
574
        State = State->BindExpr(CE, C.getLocationContext(),
95
574
                                nonloc::SymbolVal(Field));
96
97
        // Progpagate interestingness from the container's data (marked
98
        // interesting by an `ExprInspection` debug call to the container
99
        // itself.
100
574
        const NoteTag *InterestingTag =
101
574
          C.getNoteTag(
102
574
              [Cont, Field](PathSensitiveBugReport &BR) -> std::string {
103
574
                if (BR.isInteresting(Field)) {
104
574
                  BR.markInteresting(Cont);
105
574
                }
106
574
                return "";
107
574
              });
108
574
        C.addTransition(State, InterestingTag);
109
574
        return;
110
574
      }
111
574
    }
112
574
  }
113
114
0
  auto &BVF = C.getSValBuilder().getBasicValueFactory();
115
0
  State = State->BindExpr(CE, C.getLocationContext(),
116
0
                   nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));
117
0
}
118
119
void DebugContainerModeling::analyzerContainerBegin(const CallExpr *CE,
120
507
                                                    CheckerContext &C) const {
121
507
  analyzerContainerDataField(CE, C, [](const ContainerData *D) {
122
507
      return D->getBegin();
123
507
    });
124
507
}
125
126
void DebugContainerModeling::analyzerContainerEnd(const CallExpr *CE,
127
574
                                                  CheckerContext &C) const {
128
574
  analyzerContainerDataField(CE, C, [](const ContainerData *D) {
129
574
      return D->getEnd();
130
574
    });
131
574
}
132
133
ExplodedNode *DebugContainerModeling::reportDebugMsg(llvm::StringRef Msg,
134
0
                                                     CheckerContext &C) const {
135
0
  ExplodedNode *N = C.generateNonFatalErrorNode();
136
0
  if (!N)
137
0
    return nullptr;
138
139
0
  auto &BR = C.getBugReporter();
140
0
  BR.emitReport(std::make_unique<PathSensitiveBugReport>(*DebugMsgBugType,
141
0
                                                         Msg, N));
142
0
  return N;
143
0
}
144
145
13
void ento::registerDebugContainerModeling(CheckerManager &mgr) {
146
13
  mgr.registerChecker<DebugContainerModeling>();
147
13
}
148
149
28
bool ento::shouldRegisterDebugContainerModeling(const CheckerManager &mgr) {
150
28
  return true;
151
28
}