Coverage Report

Created: 2023-09-21 18:56

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- CheckerManager.cpp - Static Analyzer Checker Manager ---------------===//
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 the Static Analyzer Checker Manager.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
14
#include "clang/AST/DeclBase.h"
15
#include "clang/AST/Stmt.h"
16
#include "clang/Analysis/ProgramPoint.h"
17
#include "clang/Basic/JsonSupport.h"
18
#include "clang/Basic/LLVM.h"
19
#include "clang/Driver/DriverDiagnostic.h"
20
#include "clang/StaticAnalyzer/Core/Checker.h"
21
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
22
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
23
#include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h"
24
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
25
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
26
#include "llvm/ADT/SmallVector.h"
27
#include "llvm/Support/Casting.h"
28
#include "llvm/Support/ErrorHandling.h"
29
#include "llvm/Support/FormatVariadic.h"
30
#include <cassert>
31
#include <optional>
32
#include <vector>
33
34
using namespace clang;
35
using namespace ento;
36
37
17.7k
bool CheckerManager::hasPathSensitiveCheckers() const {
38
17.7k
  const auto IfAnyAreNonEmpty = [](const auto &... Callbacks) -> bool {
39
88.1k
    return (!Callbacks.empty() || ...);
40
17.7k
  };
41
17.7k
  return IfAnyAreNonEmpty(
42
17.7k
      StmtCheckers, PreObjCMessageCheckers, ObjCMessageNilCheckers,
43
17.7k
      PostObjCMessageCheckers, PreCallCheckers, PostCallCheckers,
44
17.7k
      LocationCheckers, BindCheckers, EndAnalysisCheckers,
45
17.7k
      BeginFunctionCheckers, EndFunctionCheckers, BranchConditionCheckers,
46
17.7k
      NewAllocatorCheckers, LiveSymbolsCheckers, DeadSymbolsCheckers,
47
17.7k
      RegionChangesCheckers, PointerEscapeCheckers, EvalAssumeCheckers,
48
17.7k
      EvalCallCheckers, EndOfTranslationUnitCheckers);
49
17.7k
}
50
51
1.82k
void CheckerManager::finishedCheckerRegistration() {
52
1.82k
#ifndef NDEBUG
53
  // Make sure that for every event that has listeners, there is at least
54
  // one dispatcher registered for it.
55
1.82k
  for (const auto &Event : Events)
56
1.28k
    assert(Event.second.HasDispatcher &&
57
1.82k
           "No dispatcher registered for an event");
58
1.82k
#endif
59
1.82k
}
60
61
void CheckerManager::reportInvalidCheckerOptionValue(
62
    const CheckerBase *C, StringRef OptionName,
63
6
    StringRef ExpectedValueDesc) const {
64
65
6
  getDiagnostics().Report(diag::err_analyzer_checker_option_invalid_input)
66
6
      << (llvm::Twine() + C->getTagDescription() + ":" + OptionName).str()
67
6
      << ExpectedValueDesc;
68
6
}
69
70
//===----------------------------------------------------------------------===//
71
// Functions for running checkers for AST traversing..
72
//===----------------------------------------------------------------------===//
73
74
void CheckerManager::runCheckersOnASTDecl(const Decl *D, AnalysisManager& mgr,
75
97.5k
                                          BugReporter &BR) {
76
97.5k
  assert(D);
77
78
97.5k
  unsigned DeclKind = D->getKind();
79
97.5k
  CachedDeclCheckers *checkers = nullptr;
80
97.5k
  CachedDeclCheckersMapTy::iterator CCI = CachedDeclCheckersMap.find(DeclKind);
81
97.5k
  if (CCI != CachedDeclCheckersMap.end()) {
82
85.7k
    checkers = &(CCI->second);
83
85.7k
  } else {
84
    // Find the checkers that should run for this Decl and cache them.
85
11.7k
    checkers = &CachedDeclCheckersMap[DeclKind];
86
11.7k
    for (const auto &info : DeclCheckers)
87
2.22k
      if (info.IsForDeclFn(D))
88
180
        checkers->push_back(info.CheckFn);
89
11.7k
  }
90
91
97.5k
  assert(checkers);
92
97.5k
  for (const auto &checker : *checkers)
93
835
    checker(D, mgr, BR);
94
97.5k
}
95
96
void CheckerManager::runCheckersOnASTBody(const Decl *D, AnalysisManager& mgr,
97
20.2k
                                          BugReporter &BR) {
98
20.2k
  assert(D && D->hasBody());
99
100
20.2k
  for (const auto &BodyChecker : BodyCheckers)
101
9.17k
    BodyChecker(D, mgr, BR);
102
20.2k
}
103
104
//===----------------------------------------------------------------------===//
105
// Functions for running checkers for path-sensitive checking.
106
//===----------------------------------------------------------------------===//
107
108
template <typename CHECK_CTX>
109
static void expandGraphWithCheckers(CHECK_CTX checkCtx,
110
                                    ExplodedNodeSet &Dst,
111
3.14M
                                    const ExplodedNodeSet &Src) {
112
3.14M
  const NodeBuilderContext &BldrCtx = checkCtx.Eng.getBuilderContext();
113
3.14M
  if (Src.empty())
114
76.4k
    return;
115
116
3.06M
  typename CHECK_CTX::CheckersTy::const_iterator
117
3.06M
      I = checkCtx.checkers_begin(), E = checkCtx.checkers_end();
118
3.06M
  if (I == E) {
119
1.01M
    Dst.insert(Src);
120
1.01M
    return;
121
1.01M
  }
122
123
2.05M
  ExplodedNodeSet Tmp1, Tmp2;
124
2.05M
  const ExplodedNodeSet *PrevSet = &Src;
125
126
7.04M
  for (; I != E; 
++I4.99M
) {
127
5.00M
    ExplodedNodeSet *CurrSet = nullptr;
128
5.00M
    if (I+1 == E)
129
2.04M
      CurrSet = &Dst;
130
2.95M
    else {
131
2.95M
      CurrSet = (PrevSet == &Tmp1) ? 
&Tmp21.08M
:
&Tmp11.86M
;
132
2.95M
      CurrSet->clear();
133
2.95M
    }
134
135
5.00M
    NodeBuilder B(*PrevSet, *CurrSet, BldrCtx);
136
5.00M
    for (const auto &NI : *PrevSet)
137
5.00M
      checkCtx.runChecker(*I, B, NI);
138
139
    // If all the produced transitions are sinks, stop.
140
5.00M
    if (CurrSet->empty())
141
4.83k
      return;
142
143
    // Update which NodeSet is the current one.
144
4.99M
    PrevSet = CurrSet;
145
4.99M
  }
146
2.05M
}
CheckerManager.cpp:void expandGraphWithCheckers<(anonymous namespace)::CheckStmtContext>((anonymous namespace)::CheckStmtContext, clang::ento::ExplodedNodeSet&, clang::ento::ExplodedNodeSet const&)
Line
Count
Source
111
1.97M
                                    const ExplodedNodeSet &Src) {
112
1.97M
  const NodeBuilderContext &BldrCtx = checkCtx.Eng.getBuilderContext();
113
1.97M
  if (Src.empty())
114
38.5k
    return;
115
116
1.93M
  typename CHECK_CTX::CheckersTy::const_iterator
117
1.93M
      I = checkCtx.checkers_begin(), E = checkCtx.checkers_end();
118
1.93M
  if (I == E) {
119
982k
    Dst.insert(Src);
120
982k
    return;
121
982k
  }
122
123
949k
  ExplodedNodeSet Tmp1, Tmp2;
124
949k
  const ExplodedNodeSet *PrevSet = &Src;
125
126
2.29M
  for (; I != E; 
++I1.34M
) {
127
1.34M
    ExplodedNodeSet *CurrSet = nullptr;
128
1.34M
    if (I+1 == E)
129
948k
      CurrSet = &Dst;
130
398k
    else {
131
398k
      CurrSet = (PrevSet == &Tmp1) ? 
&Tmp264.7k
:
&Tmp1333k
;
132
398k
      CurrSet->clear();
133
398k
    }
134
135
1.34M
    NodeBuilder B(*PrevSet, *CurrSet, BldrCtx);
136
1.34M
    for (const auto &NI : *PrevSet)
137
1.34M
      checkCtx.runChecker(*I, B, NI);
138
139
    // If all the produced transitions are sinks, stop.
140
1.34M
    if (CurrSet->empty())
141
818
      return;
142
143
    // Update which NodeSet is the current one.
144
1.34M
    PrevSet = CurrSet;
145
1.34M
  }
146
949k
}
CheckerManager.cpp:void expandGraphWithCheckers<(anonymous namespace)::CheckObjCMessageContext>((anonymous namespace)::CheckObjCMessageContext, clang::ento::ExplodedNodeSet&, clang::ento::ExplodedNodeSet const&)
Line
Count
Source
111
9.31k
                                    const ExplodedNodeSet &Src) {
112
9.31k
  const NodeBuilderContext &BldrCtx = checkCtx.Eng.getBuilderContext();
113
9.31k
  if (Src.empty())
114
720
    return;
115
116
8.59k
  typename CHECK_CTX::CheckersTy::const_iterator
117
8.59k
      I = checkCtx.checkers_begin(), E = checkCtx.checkers_end();
118
8.59k
  if (I == E) {
119
112
    Dst.insert(Src);
120
112
    return;
121
112
  }
122
123
8.48k
  ExplodedNodeSet Tmp1, Tmp2;
124
8.48k
  const ExplodedNodeSet *PrevSet = &Src;
125
126
27.8k
  for (; I != E; 
++I19.3k
) {
127
19.4k
    ExplodedNodeSet *CurrSet = nullptr;
128
19.4k
    if (I+1 == E)
129
8.46k
      CurrSet = &Dst;
130
10.9k
    else {
131
10.9k
      CurrSet = (PrevSet == &Tmp1) ? 
&Tmp23.27k
:
&Tmp17.67k
;
132
10.9k
      CurrSet->clear();
133
10.9k
    }
134
135
19.4k
    NodeBuilder B(*PrevSet, *CurrSet, BldrCtx);
136
19.4k
    for (const auto &NI : *PrevSet)
137
19.4k
      checkCtx.runChecker(*I, B, NI);
138
139
    // If all the produced transitions are sinks, stop.
140
19.4k
    if (CurrSet->empty())
141
83
      return;
142
143
    // Update which NodeSet is the current one.
144
19.3k
    PrevSet = CurrSet;
145
19.3k
  }
146
8.48k
}
CheckerManager.cpp:void expandGraphWithCheckers<(anonymous namespace)::CheckCallContext>((anonymous namespace)::CheckCallContext, clang::ento::ExplodedNodeSet&, clang::ento::ExplodedNodeSet const&)
Line
Count
Source
111
265k
                                    const ExplodedNodeSet &Src) {
112
265k
  const NodeBuilderContext &BldrCtx = checkCtx.Eng.getBuilderContext();
113
265k
  if (Src.empty())
114
37.2k
    return;
115
116
227k
  typename CHECK_CTX::CheckersTy::const_iterator
117
227k
      I = checkCtx.checkers_begin(), E = checkCtx.checkers_end();
118
227k
  if (I == E) {
119
11.5k
    Dst.insert(Src);
120
11.5k
    return;
121
11.5k
  }
122
123
216k
  ExplodedNodeSet Tmp1, Tmp2;
124
216k
  const ExplodedNodeSet *PrevSet = &Src;
125
126
1.27M
  for (; I != E; 
++I1.05M
) {
127
1.06M
    ExplodedNodeSet *CurrSet = nullptr;
128
1.06M
    if (I+1 == E)
129
215k
      CurrSet = &Dst;
130
845k
    else {
131
845k
      CurrSet = (PrevSet == &Tmp1) ? 
&Tmp2386k
:
&Tmp1458k
;
132
845k
      CurrSet->clear();
133
845k
    }
134
135
1.06M
    NodeBuilder B(*PrevSet, *CurrSet, BldrCtx);
136
1.06M
    for (const auto &NI : *PrevSet)
137
1.06M
      checkCtx.runChecker(*I, B, NI);
138
139
    // If all the produced transitions are sinks, stop.
140
1.06M
    if (CurrSet->empty())
141
2.27k
      return;
142
143
    // Update which NodeSet is the current one.
144
1.05M
    PrevSet = CurrSet;
145
1.05M
  }
146
216k
}
CheckerManager.cpp:void expandGraphWithCheckers<(anonymous namespace)::CheckLocationContext>((anonymous namespace)::CheckLocationContext, clang::ento::ExplodedNodeSet&, clang::ento::ExplodedNodeSet const&)
Line
Count
Source
111
276k
                                    const ExplodedNodeSet &Src) {
112
276k
  const NodeBuilderContext &BldrCtx = checkCtx.Eng.getBuilderContext();
113
276k
  if (Src.empty())
114
0
    return;
115
116
276k
  typename CHECK_CTX::CheckersTy::const_iterator
117
276k
      I = checkCtx.checkers_begin(), E = checkCtx.checkers_end();
118
276k
  if (I == E) {
119
11.4k
    Dst.insert(Src);
120
11.4k
    return;
121
11.4k
  }
122
123
264k
  ExplodedNodeSet Tmp1, Tmp2;
124
264k
  const ExplodedNodeSet *PrevSet = &Src;
125
126
947k
  for (; I != E; 
++I682k
) {
127
683k
    ExplodedNodeSet *CurrSet = nullptr;
128
683k
    if (I+1 == E)
129
264k
      CurrSet = &Dst;
130
419k
    else {
131
419k
      CurrSet = (PrevSet == &Tmp1) ? 
&Tmp2154k
:
&Tmp1265k
;
132
419k
      CurrSet->clear();
133
419k
    }
134
135
683k
    NodeBuilder B(*PrevSet, *CurrSet, BldrCtx);
136
683k
    for (const auto &NI : *PrevSet)
137
683k
      checkCtx.runChecker(*I, B, NI);
138
139
    // If all the produced transitions are sinks, stop.
140
683k
    if (CurrSet->empty())
141
1.13k
      return;
142
143
    // Update which NodeSet is the current one.
144
682k
    PrevSet = CurrSet;
145
682k
  }
146
264k
}
CheckerManager.cpp:void expandGraphWithCheckers<(anonymous namespace)::CheckBindContext>((anonymous namespace)::CheckBindContext, clang::ento::ExplodedNodeSet&, clang::ento::ExplodedNodeSet const&)
Line
Count
Source
111
85.7k
                                    const ExplodedNodeSet &Src) {
112
85.7k
  const NodeBuilderContext &BldrCtx = checkCtx.Eng.getBuilderContext();
113
85.7k
  if (Src.empty())
114
0
    return;
115
116
85.7k
  typename CHECK_CTX::CheckersTy::const_iterator
117
85.7k
      I = checkCtx.checkers_begin(), E = checkCtx.checkers_end();
118
85.7k
  if (I == E) {
119
2.69k
    Dst.insert(Src);
120
2.69k
    return;
121
2.69k
  }
122
123
83.0k
  ExplodedNodeSet Tmp1, Tmp2;
124
83.0k
  const ExplodedNodeSet *PrevSet = &Src;
125
126
257k
  for (; I != E; 
++I174k
) {
127
174k
    ExplodedNodeSet *CurrSet = nullptr;
128
174k
    if (I+1 == E)
129
82.9k
      CurrSet = &Dst;
130
91.6k
    else {
131
91.6k
      CurrSet = (PrevSet == &Tmp1) ? 
&Tmp28.82k
:
&Tmp182.8k
;
132
91.6k
      CurrSet->clear();
133
91.6k
    }
134
135
174k
    NodeBuilder B(*PrevSet, *CurrSet, BldrCtx);
136
174k
    for (const auto &NI : *PrevSet)
137
174k
      checkCtx.runChecker(*I, B, NI);
138
139
    // If all the produced transitions are sinks, stop.
140
174k
    if (CurrSet->empty())
141
420
      return;
142
143
    // Update which NodeSet is the current one.
144
174k
    PrevSet = CurrSet;
145
174k
  }
146
83.0k
}
CheckerManager.cpp:void expandGraphWithCheckers<(anonymous namespace)::CheckBeginFunctionContext>((anonymous namespace)::CheckBeginFunctionContext, clang::ento::ExplodedNodeSet&, clang::ento::ExplodedNodeSet const&)
Line
Count
Source
111
51.3k
                                    const ExplodedNodeSet &Src) {
112
51.3k
  const NodeBuilderContext &BldrCtx = checkCtx.Eng.getBuilderContext();
113
51.3k
  if (Src.empty())
114
0
    return;
115
116
51.3k
  typename CHECK_CTX::CheckersTy::const_iterator
117
51.3k
      I = checkCtx.checkers_begin(), E = checkCtx.checkers_end();
118
51.3k
  if (I == E) {
119
2.47k
    Dst.insert(Src);
120
2.47k
    return;
121
2.47k
  }
122
123
48.8k
  ExplodedNodeSet Tmp1, Tmp2;
124
48.8k
  const ExplodedNodeSet *PrevSet = &Src;
125
126
119k
  for (; I != E; 
++I71.0k
) {
127
71.0k
    ExplodedNodeSet *CurrSet = nullptr;
128
71.0k
    if (I+1 == E)
129
48.8k
      CurrSet = &Dst;
130
22.1k
    else {
131
22.1k
      CurrSet = (PrevSet == &Tmp1) ? 
&Tmp29.84k
:
&Tmp112.3k
;
132
22.1k
      CurrSet->clear();
133
22.1k
    }
134
135
71.0k
    NodeBuilder B(*PrevSet, *CurrSet, BldrCtx);
136
71.0k
    for (const auto &NI : *PrevSet)
137
71.0k
      checkCtx.runChecker(*I, B, NI);
138
139
    // If all the produced transitions are sinks, stop.
140
71.0k
    if (CurrSet->empty())
141
0
      return;
142
143
    // Update which NodeSet is the current one.
144
71.0k
    PrevSet = CurrSet;
145
71.0k
  }
146
48.8k
}
CheckerManager.cpp:void expandGraphWithCheckers<(anonymous namespace)::CheckBranchConditionContext>((anonymous namespace)::CheckBranchConditionContext, clang::ento::ExplodedNodeSet&, clang::ento::ExplodedNodeSet const&)
Line
Count
Source
111
60.4k
                                    const ExplodedNodeSet &Src) {
112
60.4k
  const NodeBuilderContext &BldrCtx = checkCtx.Eng.getBuilderContext();
113
60.4k
  if (Src.empty())
114
0
    return;
115
116
60.4k
  typename CHECK_CTX::CheckersTy::const_iterator
117
60.4k
      I = checkCtx.checkers_begin(), E = checkCtx.checkers_end();
118
60.4k
  if (I == E) {
119
1.48k
    Dst.insert(Src);
120
1.48k
    return;
121
1.48k
  }
122
123
58.9k
  ExplodedNodeSet Tmp1, Tmp2;
124
58.9k
  const ExplodedNodeSet *PrevSet = &Src;
125
126
119k
  for (; I != E; 
++I60.3k
) {
127
60.4k
    ExplodedNodeSet *CurrSet = nullptr;
128
60.4k
    if (I+1 == E)
129
58.9k
      CurrSet = &Dst;
130
1.49k
    else {
131
1.49k
      CurrSet = (PrevSet == &Tmp1) ? 
&Tmp20
: &Tmp1;
132
1.49k
      CurrSet->clear();
133
1.49k
    }
134
135
60.4k
    NodeBuilder B(*PrevSet, *CurrSet, BldrCtx);
136
60.4k
    for (const auto &NI : *PrevSet)
137
60.4k
      checkCtx.runChecker(*I, B, NI);
138
139
    // If all the produced transitions are sinks, stop.
140
60.4k
    if (CurrSet->empty())
141
61
      return;
142
143
    // Update which NodeSet is the current one.
144
60.3k
    PrevSet = CurrSet;
145
60.3k
  }
146
58.9k
}
CheckerManager.cpp:void expandGraphWithCheckers<(anonymous namespace)::CheckNewAllocatorContext>((anonymous namespace)::CheckNewAllocatorContext, clang::ento::ExplodedNodeSet&, clang::ento::ExplodedNodeSet const&)
Line
Count
Source
111
1.08k
                                    const ExplodedNodeSet &Src) {
112
1.08k
  const NodeBuilderContext &BldrCtx = checkCtx.Eng.getBuilderContext();
113
1.08k
  if (Src.empty())
114
0
    return;
115
116
1.08k
  typename CHECK_CTX::CheckersTy::const_iterator
117
1.08k
      I = checkCtx.checkers_begin(), E = checkCtx.checkers_end();
118
1.08k
  if (I == E) {
119
453
    Dst.insert(Src);
120
453
    return;
121
453
  }
122
123
628
  ExplodedNodeSet Tmp1, Tmp2;
124
628
  const ExplodedNodeSet *PrevSet = &Src;
125
126
1.25k
  for (; I != E; 
++I628
) {
127
628
    ExplodedNodeSet *CurrSet = nullptr;
128
628
    if (I+1 == E)
129
628
      CurrSet = &Dst;
130
0
    else {
131
0
      CurrSet = (PrevSet == &Tmp1) ? &Tmp2 : &Tmp1;
132
0
      CurrSet->clear();
133
0
    }
134
135
628
    NodeBuilder B(*PrevSet, *CurrSet, BldrCtx);
136
628
    for (const auto &NI : *PrevSet)
137
628
      checkCtx.runChecker(*I, B, NI);
138
139
    // If all the produced transitions are sinks, stop.
140
628
    if (CurrSet->empty())
141
0
      return;
142
143
    // Update which NodeSet is the current one.
144
628
    PrevSet = CurrSet;
145
628
  }
146
628
}
CheckerManager.cpp:void expandGraphWithCheckers<(anonymous namespace)::CheckDeadSymbolsContext>((anonymous namespace)::CheckDeadSymbolsContext, clang::ento::ExplodedNodeSet&, clang::ento::ExplodedNodeSet const&)
Line
Count
Source
111
426k
                                    const ExplodedNodeSet &Src) {
112
426k
  const NodeBuilderContext &BldrCtx = checkCtx.Eng.getBuilderContext();
113
426k
  if (Src.empty())
114
0
    return;
115
116
426k
  typename CHECK_CTX::CheckersTy::const_iterator
117
426k
      I = checkCtx.checkers_begin(), E = checkCtx.checkers_end();
118
426k
  if (I == E) {
119
6.22k
    Dst.insert(Src);
120
6.22k
    return;
121
6.22k
  }
122
123
420k
  ExplodedNodeSet Tmp1, Tmp2;
124
420k
  const ExplodedNodeSet *PrevSet = &Src;
125
126
2.00M
  for (; I != E; 
++I1.58M
) {
127
1.58M
    ExplodedNodeSet *CurrSet = nullptr;
128
1.58M
    if (I+1 == E)
129
420k
      CurrSet = &Dst;
130
1.16M
    else {
131
1.16M
      CurrSet = (PrevSet == &Tmp1) ? 
&Tmp2460k
:
&Tmp1702k
;
132
1.16M
      CurrSet->clear();
133
1.16M
    }
134
135
1.58M
    NodeBuilder B(*PrevSet, *CurrSet, BldrCtx);
136
1.58M
    for (const auto &NI : *PrevSet)
137
1.58M
      checkCtx.runChecker(*I, B, NI);
138
139
    // If all the produced transitions are sinks, stop.
140
1.58M
    if (CurrSet->empty())
141
46
      return;
142
143
    // Update which NodeSet is the current one.
144
1.58M
    PrevSet = CurrSet;
145
1.58M
  }
146
420k
}
147
148
namespace {
149
150
  struct CheckStmtContext {
151
    using CheckersTy = SmallVectorImpl<CheckerManager::CheckStmtFunc>;
152
153
    bool IsPreVisit;
154
    const CheckersTy &Checkers;
155
    const Stmt *S;
156
    ExprEngine &Eng;
157
    bool WasInlined;
158
159
    CheckStmtContext(bool isPreVisit, const CheckersTy &checkers,
160
                     const Stmt *s, ExprEngine &eng, bool wasInlined = false)
161
1.97M
        : IsPreVisit(isPreVisit), Checkers(checkers), S(s), Eng(eng),
162
1.97M
          WasInlined(wasInlined) {}
163
164
1.93M
    CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
165
1.93M
    CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
166
167
    void runChecker(CheckerManager::CheckStmtFunc checkFn,
168
1.34M
                    NodeBuilder &Bldr, ExplodedNode *Pred) {
169
      // FIXME: Remove respondsToCallback from CheckerContext;
170
1.34M
      ProgramPoint::Kind K =  IsPreVisit ? 
ProgramPoint::PreStmtKind609k
:
171
1.34M
                                           
ProgramPoint::PostStmtKind737k
;
172
1.34M
      const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
173
1.34M
                                Pred->getLocationContext(), checkFn.Checker);
174
1.34M
      CheckerContext C(Bldr, Eng, Pred, L, WasInlined);
175
1.34M
      checkFn(S, C);
176
1.34M
    }
177
  };
178
179
} // namespace
180
181
/// Run checkers for visiting Stmts.
182
void CheckerManager::runCheckersForStmt(bool isPreVisit,
183
                                        ExplodedNodeSet &Dst,
184
                                        const ExplodedNodeSet &Src,
185
                                        const Stmt *S,
186
                                        ExprEngine &Eng,
187
1.97M
                                        bool WasInlined) {
188
1.97M
  CheckStmtContext C(isPreVisit, getCachedStmtCheckersFor(S, isPreVisit),
189
1.97M
                     S, Eng, WasInlined);
190
1.97M
  expandGraphWithCheckers(C, Dst, Src);
191
1.97M
}
192
193
namespace {
194
195
  struct CheckObjCMessageContext {
196
    using CheckersTy = std::vector<CheckerManager::CheckObjCMessageFunc>;
197
198
    ObjCMessageVisitKind Kind;
199
    bool WasInlined;
200
    const CheckersTy &Checkers;
201
    const ObjCMethodCall &Msg;
202
    ExprEngine &Eng;
203
204
    CheckObjCMessageContext(ObjCMessageVisitKind visitKind,
205
                            const CheckersTy &checkers,
206
                            const ObjCMethodCall &msg, ExprEngine &eng,
207
                            bool wasInlined)
208
9.31k
        : Kind(visitKind), WasInlined(wasInlined), Checkers(checkers), Msg(msg),
209
9.31k
          Eng(eng) {}
210
211
8.59k
    CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
212
8.59k
    CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
213
214
    void runChecker(CheckerManager::CheckObjCMessageFunc checkFn,
215
19.4k
                    NodeBuilder &Bldr, ExplodedNode *Pred) {
216
19.4k
      bool IsPreVisit;
217
218
19.4k
      switch (Kind) {
219
10.2k
        case ObjCMessageVisitKind::Pre:
220
10.2k
          IsPreVisit = true;
221
10.2k
          break;
222
96
        case ObjCMessageVisitKind::MessageNil:
223
9.14k
        case ObjCMessageVisitKind::Post:
224
9.14k
          IsPreVisit = false;
225
9.14k
          break;
226
19.4k
      }
227
228
19.4k
      const ProgramPoint &L = Msg.getProgramPoint(IsPreVisit,checkFn.Checker);
229
19.4k
      CheckerContext C(Bldr, Eng, Pred, L, WasInlined);
230
231
19.4k
      checkFn(*Msg.cloneWithState<ObjCMethodCall>(Pred->getState()), C);
232
19.4k
    }
233
  };
234
235
} // namespace
236
237
/// Run checkers for visiting obj-c messages.
238
void CheckerManager::runCheckersForObjCMessage(ObjCMessageVisitKind visitKind,
239
                                               ExplodedNodeSet &Dst,
240
                                               const ExplodedNodeSet &Src,
241
                                               const ObjCMethodCall &msg,
242
                                               ExprEngine &Eng,
243
9.31k
                                               bool WasInlined) {
244
9.31k
  const auto &checkers = getObjCMessageCheckers(visitKind);
245
9.31k
  CheckObjCMessageContext C(visitKind, checkers, msg, Eng, WasInlined);
246
9.31k
  expandGraphWithCheckers(C, Dst, Src);
247
9.31k
}
248
249
const std::vector<CheckerManager::CheckObjCMessageFunc> &
250
9.31k
CheckerManager::getObjCMessageCheckers(ObjCMessageVisitKind Kind) const {
251
9.31k
  switch (Kind) {
252
4.29k
  case ObjCMessageVisitKind::Pre:
253
4.29k
    return PreObjCMessageCheckers;
254
0
    break;
255
4.92k
  case ObjCMessageVisitKind::Post:
256
4.92k
    return PostObjCMessageCheckers;
257
96
  case ObjCMessageVisitKind::MessageNil:
258
96
    return ObjCMessageNilCheckers;
259
9.31k
  }
260
0
  llvm_unreachable("Unknown Kind");
261
0
}
262
263
namespace {
264
265
  // FIXME: This has all the same signatures as CheckObjCMessageContext.
266
  // Is there a way we can merge the two?
267
  struct CheckCallContext {
268
    using CheckersTy = std::vector<CheckerManager::CheckCallFunc>;
269
270
    bool IsPreVisit, WasInlined;
271
    const CheckersTy &Checkers;
272
    const CallEvent &Call;
273
    ExprEngine &Eng;
274
275
    CheckCallContext(bool isPreVisit, const CheckersTy &checkers,
276
                     const CallEvent &call, ExprEngine &eng,
277
                     bool wasInlined)
278
265k
        : IsPreVisit(isPreVisit), WasInlined(wasInlined), Checkers(checkers),
279
265k
          Call(call), Eng(eng) {}
280
281
227k
    CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
282
227k
    CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
283
284
    void runChecker(CheckerManager::CheckCallFunc checkFn,
285
1.06M
                    NodeBuilder &Bldr, ExplodedNode *Pred) {
286
1.06M
      const ProgramPoint &L = Call.getProgramPoint(IsPreVisit,checkFn.Checker);
287
1.06M
      CheckerContext C(Bldr, Eng, Pred, L, WasInlined);
288
289
1.06M
      checkFn(*Call.cloneWithState(Pred->getState()), C);
290
1.06M
    }
291
  };
292
293
} // namespace
294
295
/// Run checkers for visiting an abstract call event.
296
void CheckerManager::runCheckersForCallEvent(bool isPreVisit,
297
                                             ExplodedNodeSet &Dst,
298
                                             const ExplodedNodeSet &Src,
299
                                             const CallEvent &Call,
300
                                             ExprEngine &Eng,
301
265k
                                             bool WasInlined) {
302
265k
  CheckCallContext C(isPreVisit,
303
265k
                     isPreVisit ? 
PreCallCheckers112k
304
265k
                                : 
PostCallCheckers153k
,
305
265k
                     Call, Eng, WasInlined);
306
265k
  expandGraphWithCheckers(C, Dst, Src);
307
265k
}
308
309
namespace {
310
311
  struct CheckLocationContext {
312
    using CheckersTy = std::vector<CheckerManager::CheckLocationFunc>;
313
314
    const CheckersTy &Checkers;
315
    SVal Loc;
316
    bool IsLoad;
317
    const Stmt *NodeEx; /* Will become a CFGStmt */
318
    const Stmt *BoundEx;
319
    ExprEngine &Eng;
320
321
    CheckLocationContext(const CheckersTy &checkers,
322
                         SVal loc, bool isLoad, const Stmt *NodeEx,
323
                         const Stmt *BoundEx,
324
                         ExprEngine &eng)
325
276k
        : Checkers(checkers), Loc(loc), IsLoad(isLoad), NodeEx(NodeEx),
326
276k
          BoundEx(BoundEx), Eng(eng) {}
327
328
276k
    CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
329
276k
    CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
330
331
    void runChecker(CheckerManager::CheckLocationFunc checkFn,
332
683k
                    NodeBuilder &Bldr, ExplodedNode *Pred) {
333
683k
      ProgramPoint::Kind K =  IsLoad ? 
ProgramPoint::PreLoadKind603k
:
334
683k
                                       
ProgramPoint::PreStoreKind80.1k
;
335
683k
      const ProgramPoint &L =
336
683k
        ProgramPoint::getProgramPoint(NodeEx, K,
337
683k
                                      Pred->getLocationContext(),
338
683k
                                      checkFn.Checker);
339
683k
      CheckerContext C(Bldr, Eng, Pred, L);
340
683k
      checkFn(Loc, IsLoad, BoundEx, C);
341
683k
    }
342
  };
343
344
} // namespace
345
346
/// Run checkers for load/store of a location.
347
348
void CheckerManager::runCheckersForLocation(ExplodedNodeSet &Dst,
349
                                            const ExplodedNodeSet &Src,
350
                                            SVal location, bool isLoad,
351
                                            const Stmt *NodeEx,
352
                                            const Stmt *BoundEx,
353
276k
                                            ExprEngine &Eng) {
354
276k
  CheckLocationContext C(LocationCheckers, location, isLoad, NodeEx,
355
276k
                         BoundEx, Eng);
356
276k
  expandGraphWithCheckers(C, Dst, Src);
357
276k
}
358
359
namespace {
360
361
  struct CheckBindContext {
362
    using CheckersTy = std::vector<CheckerManager::CheckBindFunc>;
363
364
    const CheckersTy &Checkers;
365
    SVal Loc;
366
    SVal Val;
367
    const Stmt *S;
368
    ExprEngine &Eng;
369
    const ProgramPoint &PP;
370
371
    CheckBindContext(const CheckersTy &checkers,
372
                     SVal loc, SVal val, const Stmt *s, ExprEngine &eng,
373
                     const ProgramPoint &pp)
374
85.7k
        : Checkers(checkers), Loc(loc), Val(val), S(s), Eng(eng), PP(pp) {}
375
376
85.7k
    CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
377
85.7k
    CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
378
379
    void runChecker(CheckerManager::CheckBindFunc checkFn,
380
174k
                    NodeBuilder &Bldr, ExplodedNode *Pred) {
381
174k
      const ProgramPoint &L = PP.withTag(checkFn.Checker);
382
174k
      CheckerContext C(Bldr, Eng, Pred, L);
383
384
174k
      checkFn(Loc, Val, S, C);
385
174k
    }
386
  };
387
388
} // namespace
389
390
/// Run checkers for binding of a value to a location.
391
void CheckerManager::runCheckersForBind(ExplodedNodeSet &Dst,
392
                                        const ExplodedNodeSet &Src,
393
                                        SVal location, SVal val,
394
                                        const Stmt *S, ExprEngine &Eng,
395
85.7k
                                        const ProgramPoint &PP) {
396
85.7k
  CheckBindContext C(BindCheckers, location, val, S, Eng, PP);
397
85.7k
  expandGraphWithCheckers(C, Dst, Src);
398
85.7k
}
399
400
void CheckerManager::runCheckersForEndAnalysis(ExplodedGraph &G,
401
                                               BugReporter &BR,
402
16.1k
                                               ExprEngine &Eng) {
403
16.1k
  for (const auto &EndAnalysisChecker : EndAnalysisCheckers)
404
9.58k
    EndAnalysisChecker(G, BR, Eng);
405
16.1k
}
406
407
namespace {
408
409
struct CheckBeginFunctionContext {
410
  using CheckersTy = std::vector<CheckerManager::CheckBeginFunctionFunc>;
411
412
  const CheckersTy &Checkers;
413
  ExprEngine &Eng;
414
  const ProgramPoint &PP;
415
416
  CheckBeginFunctionContext(const CheckersTy &Checkers, ExprEngine &Eng,
417
                            const ProgramPoint &PP)
418
51.3k
      : Checkers(Checkers), Eng(Eng), PP(PP) {}
419
420
51.3k
  CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
421
51.3k
  CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
422
423
  void runChecker(CheckerManager::CheckBeginFunctionFunc checkFn,
424
71.0k
                  NodeBuilder &Bldr, ExplodedNode *Pred) {
425
71.0k
    const ProgramPoint &L = PP.withTag(checkFn.Checker);
426
71.0k
    CheckerContext C(Bldr, Eng, Pred, L);
427
428
71.0k
    checkFn(C);
429
71.0k
  }
430
};
431
432
} // namespace
433
434
void CheckerManager::runCheckersForBeginFunction(ExplodedNodeSet &Dst,
435
                                                 const BlockEdge &L,
436
                                                 ExplodedNode *Pred,
437
51.3k
                                                 ExprEngine &Eng) {
438
51.3k
  ExplodedNodeSet Src;
439
51.3k
  Src.insert(Pred);
440
51.3k
  CheckBeginFunctionContext C(BeginFunctionCheckers, Eng, L);
441
51.3k
  expandGraphWithCheckers(C, Dst, Src);
442
51.3k
}
443
444
/// Run checkers for end of path.
445
// Note, We do not chain the checker output (like in expandGraphWithCheckers)
446
// for this callback since end of path nodes are expected to be final.
447
void CheckerManager::runCheckersForEndFunction(NodeBuilderContext &BC,
448
                                               ExplodedNodeSet &Dst,
449
                                               ExplodedNode *Pred,
450
                                               ExprEngine &Eng,
451
65.8k
                                               const ReturnStmt *RS) {
452
  // We define the builder outside of the loop because if at least one checker
453
  // creates a successor for Pred, we do not need to generate an
454
  // autotransition for it.
455
65.8k
  NodeBuilder Bldr(Pred, Dst, BC);
456
107k
  for (const auto &checkFn : EndFunctionCheckers) {
457
107k
    const ProgramPoint &L =
458
107k
        FunctionExitPoint(RS, Pred->getLocationContext(), checkFn.Checker);
459
107k
    CheckerContext C(Bldr, Eng, Pred, L);
460
107k
    checkFn(RS, C);
461
107k
  }
462
65.8k
}
463
464
namespace {
465
466
  struct CheckBranchConditionContext {
467
    using CheckersTy = std::vector<CheckerManager::CheckBranchConditionFunc>;
468
469
    const CheckersTy &Checkers;
470
    const Stmt *Condition;
471
    ExprEngine &Eng;
472
473
    CheckBranchConditionContext(const CheckersTy &checkers,
474
                                const Stmt *Cond, ExprEngine &eng)
475
60.4k
        : Checkers(checkers), Condition(Cond), Eng(eng) {}
476
477
60.4k
    CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
478
60.4k
    CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
479
480
    void runChecker(CheckerManager::CheckBranchConditionFunc checkFn,
481
60.4k
                    NodeBuilder &Bldr, ExplodedNode *Pred) {
482
60.4k
      ProgramPoint L = PostCondition(Condition, Pred->getLocationContext(),
483
60.4k
                                     checkFn.Checker);
484
60.4k
      CheckerContext C(Bldr, Eng, Pred, L);
485
60.4k
      checkFn(Condition, C);
486
60.4k
    }
487
  };
488
489
} // namespace
490
491
/// Run checkers for branch condition.
492
void CheckerManager::runCheckersForBranchCondition(const Stmt *Condition,
493
                                                   ExplodedNodeSet &Dst,
494
                                                   ExplodedNode *Pred,
495
60.4k
                                                   ExprEngine &Eng) {
496
60.4k
  ExplodedNodeSet Src;
497
60.4k
  Src.insert(Pred);
498
60.4k
  CheckBranchConditionContext C(BranchConditionCheckers, Condition, Eng);
499
60.4k
  expandGraphWithCheckers(C, Dst, Src);
500
60.4k
}
501
502
namespace {
503
504
  struct CheckNewAllocatorContext {
505
    using CheckersTy = std::vector<CheckerManager::CheckNewAllocatorFunc>;
506
507
    const CheckersTy &Checkers;
508
    const CXXAllocatorCall &Call;
509
    bool WasInlined;
510
    ExprEngine &Eng;
511
512
    CheckNewAllocatorContext(const CheckersTy &Checkers,
513
                             const CXXAllocatorCall &Call, bool WasInlined,
514
                             ExprEngine &Eng)
515
1.08k
        : Checkers(Checkers), Call(Call), WasInlined(WasInlined), Eng(Eng) {}
516
517
1.08k
    CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
518
1.08k
    CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
519
520
    void runChecker(CheckerManager::CheckNewAllocatorFunc checkFn,
521
628
                    NodeBuilder &Bldr, ExplodedNode *Pred) {
522
628
      ProgramPoint L =
523
628
          PostAllocatorCall(Call.getOriginExpr(), Pred->getLocationContext());
524
628
      CheckerContext C(Bldr, Eng, Pred, L, WasInlined);
525
628
      checkFn(cast<CXXAllocatorCall>(*Call.cloneWithState(Pred->getState())),
526
628
              C);
527
628
    }
528
  };
529
530
} // namespace
531
532
void CheckerManager::runCheckersForNewAllocator(const CXXAllocatorCall &Call,
533
                                                ExplodedNodeSet &Dst,
534
                                                ExplodedNode *Pred,
535
                                                ExprEngine &Eng,
536
1.08k
                                                bool WasInlined) {
537
1.08k
  ExplodedNodeSet Src;
538
1.08k
  Src.insert(Pred);
539
1.08k
  CheckNewAllocatorContext C(NewAllocatorCheckers, Call, WasInlined, Eng);
540
1.08k
  expandGraphWithCheckers(C, Dst, Src);
541
1.08k
}
542
543
/// Run checkers for live symbols.
544
void CheckerManager::runCheckersForLiveSymbols(ProgramStateRef state,
545
426k
                                               SymbolReaper &SymReaper) {
546
426k
  for (const auto &LiveSymbolsChecker : LiveSymbolsCheckers)
547
389k
    LiveSymbolsChecker(state, SymReaper);
548
426k
}
549
550
namespace {
551
552
  struct CheckDeadSymbolsContext {
553
    using CheckersTy = std::vector<CheckerManager::CheckDeadSymbolsFunc>;
554
555
    const CheckersTy &Checkers;
556
    SymbolReaper &SR;
557
    const Stmt *S;
558
    ExprEngine &Eng;
559
    ProgramPoint::Kind ProgarmPointKind;
560
561
    CheckDeadSymbolsContext(const CheckersTy &checkers, SymbolReaper &sr,
562
                            const Stmt *s, ExprEngine &eng,
563
                            ProgramPoint::Kind K)
564
426k
        : Checkers(checkers), SR(sr), S(s), Eng(eng), ProgarmPointKind(K) {}
565
566
426k
    CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
567
426k
    CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
568
569
    void runChecker(CheckerManager::CheckDeadSymbolsFunc checkFn,
570
1.58M
                    NodeBuilder &Bldr, ExplodedNode *Pred) {
571
1.58M
      const ProgramPoint &L = ProgramPoint::getProgramPoint(S, ProgarmPointKind,
572
1.58M
                                Pred->getLocationContext(), checkFn.Checker);
573
1.58M
      CheckerContext C(Bldr, Eng, Pred, L);
574
575
      // Note, do not pass the statement to the checkers without letting them
576
      // differentiate if we ran remove dead bindings before or after the
577
      // statement.
578
1.58M
      checkFn(SR, C);
579
1.58M
    }
580
  };
581
582
} // namespace
583
584
/// Run checkers for dead symbols.
585
void CheckerManager::runCheckersForDeadSymbols(ExplodedNodeSet &Dst,
586
                                               const ExplodedNodeSet &Src,
587
                                               SymbolReaper &SymReaper,
588
                                               const Stmt *S,
589
                                               ExprEngine &Eng,
590
426k
                                               ProgramPoint::Kind K) {
591
426k
  CheckDeadSymbolsContext C(DeadSymbolsCheckers, SymReaper, S, Eng, K);
592
426k
  expandGraphWithCheckers(C, Dst, Src);
593
426k
}
594
595
/// Run checkers for region changes.
596
ProgramStateRef
597
CheckerManager::runCheckersForRegionChanges(ProgramStateRef state,
598
                                            const InvalidatedSymbols *invalidated,
599
                                            ArrayRef<const MemRegion *> ExplicitRegions,
600
                                            ArrayRef<const MemRegion *> Regions,
601
                                            const LocationContext *LCtx,
602
154k
                                            const CallEvent *Call) {
603
162k
  for (const auto &RegionChangesChecker : RegionChangesCheckers) {
604
    // If any checker declares the state infeasible (or if it starts that way),
605
    // bail out.
606
162k
    if (!state)
607
0
      return nullptr;
608
162k
    state = RegionChangesChecker(state, invalidated, ExplicitRegions, Regions,
609
162k
                                 LCtx, Call);
610
162k
  }
611
154k
  return state;
612
154k
}
613
614
/// Run checkers to process symbol escape event.
615
ProgramStateRef
616
CheckerManager::runCheckersForPointerEscape(ProgramStateRef State,
617
                                   const InvalidatedSymbols &Escaped,
618
                                   const CallEvent *Call,
619
                                   PointerEscapeKind Kind,
620
61.6k
                                   RegionAndSymbolInvalidationTraits *ETraits) {
621
61.6k
  assert((Call != nullptr ||
622
61.6k
          (Kind != PSK_DirectEscapeOnCall &&
623
61.6k
           Kind != PSK_IndirectEscapeOnCall)) &&
624
61.6k
         "Call must not be NULL when escaping on call");
625
61.6k
  for (const auto &PointerEscapeChecker : PointerEscapeCheckers) {
626
    // If any checker declares the state infeasible (or if it starts that
627
    //  way), bail out.
628
34.8k
    if (!State)
629
0
      return nullptr;
630
34.8k
    State = PointerEscapeChecker(State, Escaped, Call, Kind, ETraits);
631
34.8k
  }
632
61.6k
  return State;
633
61.6k
}
634
635
/// Run checkers for handling assumptions on symbolic values.
636
ProgramStateRef
637
CheckerManager::runCheckersForEvalAssume(ProgramStateRef state,
638
1.32M
                                         SVal Cond, bool Assumption) {
639
1.32M
  for (const auto &EvalAssumeChecker : EvalAssumeCheckers) {
640
    // If any checker declares the state infeasible (or if it starts that way),
641
    // bail out.
642
401k
    if (!state)
643
167k
      return nullptr;
644
233k
    state = EvalAssumeChecker(state, Cond, Assumption);
645
233k
  }
646
1.15M
  return state;
647
1.32M
}
648
649
/// Run checkers for evaluating a call.
650
/// Only one checker will evaluate the call.
651
void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,
652
                                            const ExplodedNodeSet &Src,
653
                                            const CallEvent &Call,
654
                                            ExprEngine &Eng,
655
91.9k
                                            const EvalCallOptions &CallOpts) {
656
91.9k
  for (auto *const Pred : Src) {
657
91.3k
    std::optional<CheckerNameRef> evaluatorChecker;
658
659
91.3k
    ExplodedNodeSet checkDst;
660
91.3k
    NodeBuilder B(Pred, checkDst, Eng.getBuilderContext());
661
662
    // Check if any of the EvalCall callbacks can evaluate the call.
663
256k
    for (const auto &EvalCallChecker : EvalCallCheckers) {
664
      // TODO: Support the situation when the call doesn't correspond
665
      // to any Expr.
666
256k
      ProgramPoint L = ProgramPoint::getProgramPoint(
667
256k
          Call.getOriginExpr(), ProgramPoint::PostStmtKind,
668
256k
          Pred->getLocationContext(), EvalCallChecker.Checker);
669
256k
      bool evaluated = false;
670
256k
      { // CheckerContext generates transitions(populates checkDest) on
671
        // destruction, so introduce the scope to make sure it gets properly
672
        // populated.
673
256k
        CheckerContext C(B, Eng, Pred, L);
674
256k
        evaluated = EvalCallChecker(Call, C);
675
256k
      }
676
256k
#ifndef NDEBUG
677
256k
      if (evaluated && 
evaluatorChecker28.1k
) {
678
0
        const auto toString = [](const CallEvent &Call) -> std::string {
679
0
          std::string Buf;
680
0
          llvm::raw_string_ostream OS(Buf);
681
0
          Call.dump(OS);
682
0
          OS.flush();
683
0
          return Buf;
684
0
        };
685
0
        std::string AssertionMessage = llvm::formatv(
686
0
            "The '{0}' call has been already evaluated by the {1} checker, "
687
0
            "while the {2} checker also tried to evaluate the same call. At "
688
0
            "most one checker supposed to evaluate a call.",
689
0
            toString(Call), evaluatorChecker->getName(),
690
0
            EvalCallChecker.Checker->getCheckerName());
691
0
        llvm_unreachable(AssertionMessage.c_str());
692
0
      }
693
256k
#endif
694
256k
      if (evaluated) {
695
28.1k
        evaluatorChecker = EvalCallChecker.Checker->getCheckerName();
696
28.1k
        Dst.insert(checkDst);
697
#ifdef NDEBUG
698
        break; // on release don't check that no other checker also evals.
699
#endif
700
28.1k
      }
701
256k
    }
702
703
    // If none of the checkers evaluated the call, ask ExprEngine to handle it.
704
91.3k
    if (!evaluatorChecker) {
705
63.2k
      NodeBuilder B(Pred, Dst, Eng.getBuilderContext());
706
63.2k
      Eng.defaultEvalCall(B, Pred, Call, CallOpts);
707
63.2k
    }
708
91.3k
  }
709
91.9k
}
710
711
/// Run checkers for the entire Translation Unit.
712
void CheckerManager::runCheckersOnEndOfTranslationUnit(
713
                                                  const TranslationUnitDecl *TU,
714
                                                  AnalysisManager &mgr,
715
1.77k
                                                  BugReporter &BR) {
716
1.77k
  for (const auto &EndOfTranslationUnitChecker : EndOfTranslationUnitCheckers)
717
32
    EndOfTranslationUnitChecker(TU, mgr, BR);
718
1.77k
}
719
720
void CheckerManager::runCheckersForPrintStateJson(raw_ostream &Out,
721
                                                  ProgramStateRef State,
722
                                                  const char *NL,
723
                                                  unsigned int Space,
724
158
                                                  bool IsDot) const {
725
158
  Indent(Out, Space, IsDot) << "\"checker_messages\": ";
726
727
  // Create a temporary stream to see whether we have any message.
728
158
  SmallString<1024> TempBuf;
729
158
  llvm::raw_svector_ostream TempOut(TempBuf);
730
158
  unsigned int InnerSpace = Space + 2;
731
732
  // Create the new-line in JSON with enough space.
733
158
  SmallString<128> NewLine;
734
158
  llvm::raw_svector_ostream NLOut(NewLine);
735
158
  NLOut << "\", " << NL;                     // Inject the ending and a new line
736
158
  Indent(NLOut, InnerSpace, IsDot) << "\"";  // then begin the next message.
737
738
158
  ++Space;
739
158
  bool HasMessage = false;
740
741
  // Store the last CheckerTag.
742
158
  const void *LastCT = nullptr;
743
3.04k
  for (const auto &CT : CheckerTags) {
744
    // See whether the current checker has a message.
745
3.04k
    CT.second->printState(TempOut, State, /*NL=*/NewLine.c_str(), /*Sep=*/"");
746
747
3.04k
    if (TempBuf.empty())
748
3.00k
      continue;
749
750
41
    if (!HasMessage) {
751
27
      Out << '[' << NL;
752
27
      HasMessage = true;
753
27
    }
754
755
41
    LastCT = &CT;
756
41
    TempBuf.clear();
757
41
  }
758
759
3.04k
  for (const auto &CT : CheckerTags) {
760
    // See whether the current checker has a message.
761
3.04k
    CT.second->printState(TempOut, State, /*NL=*/NewLine.c_str(), /*Sep=*/"");
762
763
3.04k
    if (TempBuf.empty())
764
3.00k
      continue;
765
766
41
    Indent(Out, Space, IsDot)
767
41
        << "{ \"checker\": \"" << CT.second->getCheckerName().getName()
768
41
        << "\", \"messages\": [" << NL;
769
41
    Indent(Out, InnerSpace, IsDot)
770
41
        << '\"' << TempBuf.str().trim() << '\"' << NL;
771
41
    Indent(Out, Space, IsDot) << "]}";
772
773
41
    if (&CT != LastCT)
774
14
      Out << ',';
775
41
    Out << NL;
776
777
41
    TempBuf.clear();
778
41
  }
779
780
  // It is the last element of the 'program_state' so do not add a comma.
781
158
  if (HasMessage)
782
27
    Indent(Out, --Space, IsDot) << "]";
783
131
  else
784
131
    Out << "null";
785
786
158
  Out << NL;
787
158
}
788
789
//===----------------------------------------------------------------------===//
790
// Internal registration functions for AST traversing.
791
//===----------------------------------------------------------------------===//
792
793
void CheckerManager::_registerForDecl(CheckDeclFunc checkfn,
794
417
                                      HandlesDeclFunc isForDeclFn) {
795
417
  DeclCheckerInfo info = { checkfn, isForDeclFn };
796
417
  DeclCheckers.push_back(info);
797
417
}
798
799
807
void CheckerManager::_registerForBody(CheckDeclFunc checkfn) {
800
807
  BodyCheckers.push_back(checkfn);
801
807
}
802
803
//===----------------------------------------------------------------------===//
804
// Internal registration functions for path-sensitive checking.
805
//===----------------------------------------------------------------------===//
806
807
void CheckerManager::_registerForPreStmt(CheckStmtFunc checkfn,
808
10.9k
                                         HandlesStmtFunc isForStmtFn) {
809
10.9k
  StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/true };
810
10.9k
  StmtCheckers.push_back(info);
811
10.9k
}
812
813
void CheckerManager::_registerForPostStmt(CheckStmtFunc checkfn,
814
6.87k
                                          HandlesStmtFunc isForStmtFn) {
815
6.87k
  StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/false };
816
6.87k
  StmtCheckers.push_back(info);
817
6.87k
}
818
819
2.81k
void CheckerManager::_registerForPreObjCMessage(CheckObjCMessageFunc checkfn) {
820
2.81k
  PreObjCMessageCheckers.push_back(checkfn);
821
2.81k
}
822
823
1.27k
void CheckerManager::_registerForObjCMessageNil(CheckObjCMessageFunc checkfn) {
824
1.27k
  ObjCMessageNilCheckers.push_back(checkfn);
825
1.27k
}
826
827
3.14k
void CheckerManager::_registerForPostObjCMessage(CheckObjCMessageFunc checkfn) {
828
3.14k
  PostObjCMessageCheckers.push_back(checkfn);
829
3.14k
}
830
831
6.83k
void CheckerManager::_registerForPreCall(CheckCallFunc checkfn) {
832
6.83k
  PreCallCheckers.push_back(checkfn);
833
6.83k
}
834
3.64k
void CheckerManager::_registerForPostCall(CheckCallFunc checkfn) {
835
3.64k
  PostCallCheckers.push_back(checkfn);
836
3.64k
}
837
838
3.04k
void CheckerManager::_registerForLocation(CheckLocationFunc checkfn) {
839
3.04k
  LocationCheckers.push_back(checkfn);
840
3.04k
}
841
842
3.12k
void CheckerManager::_registerForBind(CheckBindFunc checkfn) {
843
3.12k
  BindCheckers.push_back(checkfn);
844
3.12k
}
845
846
658
void CheckerManager::_registerForEndAnalysis(CheckEndAnalysisFunc checkfn) {
847
658
  EndAnalysisCheckers.push_back(checkfn);
848
658
}
849
850
1.67k
void CheckerManager::_registerForBeginFunction(CheckBeginFunctionFunc checkfn) {
851
1.67k
  BeginFunctionCheckers.push_back(checkfn);
852
1.67k
}
853
854
1.93k
void CheckerManager::_registerForEndFunction(CheckEndFunctionFunc checkfn) {
855
1.93k
  EndFunctionCheckers.push_back(checkfn);
856
1.93k
}
857
858
void CheckerManager::_registerForBranchCondition(
859
1.35k
                                             CheckBranchConditionFunc checkfn) {
860
1.35k
  BranchConditionCheckers.push_back(checkfn);
861
1.35k
}
862
863
256
void CheckerManager::_registerForNewAllocator(CheckNewAllocatorFunc checkfn) {
864
256
  NewAllocatorCheckers.push_back(checkfn);
865
256
}
866
867
458
void CheckerManager::_registerForLiveSymbols(CheckLiveSymbolsFunc checkfn) {
868
458
  LiveSymbolsCheckers.push_back(checkfn);
869
458
}
870
871
3.04k
void CheckerManager::_registerForDeadSymbols(CheckDeadSymbolsFunc checkfn) {
872
3.04k
  DeadSymbolsCheckers.push_back(checkfn);
873
3.04k
}
874
875
632
void CheckerManager::_registerForRegionChanges(CheckRegionChangesFunc checkfn) {
876
632
  RegionChangesCheckers.push_back(checkfn);
877
632
}
878
879
714
void CheckerManager::_registerForPointerEscape(CheckPointerEscapeFunc checkfn){
880
714
  PointerEscapeCheckers.push_back(checkfn);
881
714
}
882
883
void CheckerManager::_registerForConstPointerEscape(
884
0
                                          CheckPointerEscapeFunc checkfn) {
885
0
  PointerEscapeCheckers.push_back(checkfn);
886
0
}
887
888
532
void CheckerManager::_registerForEvalAssume(EvalAssumeFunc checkfn) {
889
532
  EvalAssumeCheckers.push_back(checkfn);
890
532
}
891
892
2.40k
void CheckerManager::_registerForEvalCall(EvalCallFunc checkfn) {
893
2.40k
  EvalCallCheckers.push_back(checkfn);
894
2.40k
}
895
896
void CheckerManager::_registerForEndOfTranslationUnit(
897
32
                                            CheckEndOfTranslationUnit checkfn) {
898
32
  EndOfTranslationUnitCheckers.push_back(checkfn);
899
32
}
900
901
//===----------------------------------------------------------------------===//
902
// Implementation details.
903
//===----------------------------------------------------------------------===//
904
905
const CheckerManager::CachedStmtCheckers &
906
1.97M
CheckerManager::getCachedStmtCheckersFor(const Stmt *S, bool isPreVisit) {
907
1.97M
  assert(S);
908
909
1.97M
  unsigned Key = (S->getStmtClass() << 1) | unsigned(isPreVisit);
910
1.97M
  CachedStmtCheckersMapTy::iterator CCI = CachedStmtCheckersMap.find(Key);
911
1.97M
  if (CCI != CachedStmtCheckersMap.end())
912
1.94M
    return CCI->second;
913
914
  // Find the checkers that should run for this Stmt and cache them.
915
24.3k
  CachedStmtCheckers &Checkers = CachedStmtCheckersMap[Key];
916
24.3k
  for (const auto &Info : StmtCheckers)
917
286k
    if (Info.IsPreVisit == isPreVisit && 
Info.IsForStmtFn(S)143k
)
918
9.33k
      Checkers.push_back(Info.CheckFn);
919
24.3k
  return Checkers;
920
1.97M
}