Coverage Report

Created: 2020-10-24 06:27

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