• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tudasc / TypeART / 21639007075

03 Feb 2026 04:44PM UTC coverage: 88.438% (-1.8%) from 90.245%
21639007075

Pull #183

github

web-flow
Merge 4594bc77c into 8ae76f97d
Pull Request #183: Argument-granular whole program dataflow filtering

209 of 363 new or added lines in 10 files covered. (57.58%)

8 existing lines in 3 files now uncovered.

4903 of 5544 relevant lines covered (88.44%)

32492.57 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.49
/lib/passes/analysis/MemInstFinder.cpp
1
// TypeART library
2
//
3
// Copyright (c) 2017-2025 TypeART Authors
4
// Distributed under the BSD 3-Clause license.
5
// (See accompanying file LICENSE.txt or copy at
6
// https://opensource.org/licenses/BSD-3-Clause)
7
//
8
// Project home: https://github.com/tudasc/TypeART
9
//
10
// SPDX-License-Identifier: BSD-3-Clause
11
//
12

13
#include "MemInstFinder.h"
14

15
#include "MemOpVisitor.h"
16
#include "TypeARTConfiguration.h"
17
#include "analysis/MemOpData.h"
18
#include "configuration/Configuration.h"
19
#include "configuration/TypeARTOptions.h"
20
#include "filter/ACGFilter.h"
21
#include "filter/CGForwardFilter.h"
22
#include "filter/CGInterface.h"
23
#include "filter/Filter.h"
24
#include "filter/Matcher.h"
25
#include "filter/MetaCG.h"
26
#include "filter/StdForwardFilter.h"
27
#include "support/ConfigurationBase.h"
28
#include "support/Logger.h"
29
#include "support/Table.h"
30
#include "support/TypeUtil.h"
31
#include "support/Util.h"
32

33
#include "llvm/ADT/STLExtras.h"
34
#include "llvm/ADT/Statistic.h"
35
#include "llvm/ADT/StringRef.h"
36
#include "llvm/IR/BasicBlock.h"
37
#include "llvm/IR/DerivedTypes.h"
38
#include "llvm/IR/Function.h"
39
#include "llvm/IR/GlobalValue.h"
40
#include "llvm/IR/Instructions.h"
41
#include "llvm/IR/Module.h"
42
#include "llvm/IR/Type.h"
43
#include "llvm/Support/Casting.h"
44
#include "llvm/Support/raw_ostream.h"
45

46
#include <algorithm>
47
#include <cstdlib>
48
#include <llvm/ADT/ScopeExit.h>
49
#include <llvm/Support/MemoryBuffer.h>
50
#include <sstream>
51
#include <string>
52
#include <utility>
53

54
using namespace llvm;
55

56
#define DEBUG_TYPE "MemInstFinder"
57
ALWAYS_ENABLED_STATISTIC(NumDetectedHeap, "Number of detected heap allocs");
58
ALWAYS_ENABLED_STATISTIC(NumFilteredDetectedHeap, "Number of filtered heap allocs");
59
ALWAYS_ENABLED_STATISTIC(NumDetectedAllocs, "Number of detected allocs");
60
ALWAYS_ENABLED_STATISTIC(NumFilteredPointerAllocs, "Number of filtered pointer allocs");
61
ALWAYS_ENABLED_STATISTIC(NumCallFilteredAllocs, "Number of call filtered allocs");
62
ALWAYS_ENABLED_STATISTIC(NumFilteredMallocAllocs, "Number of  filtered  malloc-related allocs");
63
ALWAYS_ENABLED_STATISTIC(NumFilteredNonArrayAllocs, "Number of filtered non-array allocs");
64
ALWAYS_ENABLED_STATISTIC(NumDetectedGlobals, "Number of detected globals");
65
ALWAYS_ENABLED_STATISTIC(NumFilteredGlobals, "Number of filtered globals");
66
ALWAYS_ENABLED_STATISTIC(NumCallFilteredGlobals, "Number of filtered globals");
67

68
namespace typeart::analysis {
69

70
using MemInstFinderConfig = config::Configuration;
71

72
namespace filter {
73
class CallFilter {
74
  std::unique_ptr<typeart::filter::Filter> fImpl;
75

76
 public:
77
  explicit CallFilter(const MemInstFinderConfig& config);
78
  CallFilter(const CallFilter&) = delete;
79
  CallFilter(CallFilter&&)      = default;
80
  bool operator()(llvm::AllocaInst*);
81
  bool operator()(llvm::GlobalValue*);
82
  CallFilter& operator=(CallFilter&&) noexcept;
83
  CallFilter& operator=(const CallFilter&) = delete;
84
  virtual ~CallFilter();
85
};
86

87
}  // namespace filter
88

89
namespace filter {
90

91
namespace detail {
92
static std::unique_ptr<typeart::filter::Filter> make_filter(const MemInstFinderConfig& config) {
4,924✔
93
  using namespace typeart::filter;
94
  const bool filter                    = config[config::ConfigStdArgs::filter];
4,924✔
95
  const FilterImplementation filter_id = config[config::ConfigStdArgs::filter_impl];
4,924✔
96
  const std::string glob               = config[config::ConfigStdArgs::filter_glob];
4,924✔
97

98
  if (filter_id == FilterImplementation::none || !filter) {
4,924✔
99
    LOG_DEBUG("Return no-op filter")
100
    return std::make_unique<NoOpFilter>();
4,364✔
101
  } else if (filter_id == FilterImplementation::cg) {
560✔
102
    LOG_DEBUG("Return CGForward filter");
103

104
    std::string cg_file = config[config::ConfigStdArgs::filter_cg_file];
16✔
105
    const auto buf      = MemoryBuffer::getFile(std::move(cg_file), true);
16✔
106
    if (!buf) {
16✔
NEW
107
      LOG_FATAL("Failed to load MCG file");
×
NEW
108
      std::exit(1);
×
109
    }
110

111
    auto mcg = metacg::parse((*buf)->getBuffer());
16✔
112
    if (!mcg) {
16✔
NEW
113
      LOG_FATAL(mcg.takeError() << '\n');
×
NEW
114
      std::exit(1);
×
115
    }
116

117
    auto matcher         = std::make_unique<DefaultStringMatcher>(util::glob2regex(glob));
16✔
118
    const auto deep_glob = config[config::ConfigStdArgs::filter_glob_deep];
16✔
119
    auto deep_matcher    = std::make_unique<DefaultStringMatcher>(util::glob2regex(deep_glob));
16✔
120

121
    return std::make_unique<CGForwardFilter>(std::move(mcg.get()), std::move(matcher), std::move(deep_matcher));
16✔
122

123
  } else if (filter_id == FilterImplementation::acg) {
560✔
124
    LOG_DEBUG("Return Argflow filter");
125
    std::string cg_file = config[config::ConfigStdArgs::filter_cg_file];
36✔
126
    const auto buf      = MemoryBuffer::getFile(std::move(cg_file), true);
36✔
127
    if (!buf) {
36✔
NEW
128
      LOG_FATAL("Failed to load MCG file");
×
NEW
129
      std::exit(1);
×
130
    }
131

132
    auto mcg = metacg::parse((*buf)->getBuffer());
36✔
133
    if (!mcg) {
36✔
NEW
134
      LOG_FATAL(mcg.takeError() << '\n');
×
UNCOV
135
      std::exit(1);
×
136
    }
137

138
    auto matcher         = std::make_unique<DefaultStringMatcher>(util::glob2regex(glob));
36✔
139
    const auto deep_glob = config[config::ConfigStdArgs::filter_glob_deep];
36✔
140
    auto deep_matcher    = std::make_unique<DefaultStringMatcher>(util::glob2regex(deep_glob));
36✔
141

142
    return std::make_unique<AcgFilter>(std::move(mcg.get()), std::move(matcher), std::move(deep_matcher));
36✔
143
  } else {
36✔
144
    LOG_DEBUG("Return default filter")
145
    auto matcher         = std::make_unique<DefaultStringMatcher>(util::glob2regex(glob));
508✔
146
    const auto deep_glob = config[config::ConfigStdArgs::filter_glob_deep];
508✔
147
    auto deep_matcher    = std::make_unique<DefaultStringMatcher>(util::glob2regex(deep_glob));
508✔
148
    return std::make_unique<StandardForwardFilter>(std::move(matcher), std::move(deep_matcher));
508✔
149
  }
508✔
150
}
4,924✔
151
}  // namespace detail
152

153
CallFilter::CallFilter(const MemInstFinderConfig& config) : fImpl{detail::make_filter(config)} {
4,924✔
154
}
4,924✔
155

156
bool CallFilter::operator()(AllocaInst* allocation) {
4,006✔
157
  LOG_DEBUG("Analyzing value: " << util::dump(*allocation));
158
  fImpl->setMode(/*search mallocs = */ false);
4,006✔
159
  fImpl->setStartingFunction(allocation->getParent()->getParent());
4,006✔
160
  const auto filter_ = fImpl->filter(allocation);
4,006✔
161
  if (filter_) {
4,006✔
162
    LOG_DEBUG("Filtering value: " << util::dump(*allocation) << "\n");
163
  } else {
3,444✔
164
    LOG_DEBUG("Keeping value: " << util::dump(*allocation) << "\n");
165
  }
166
  return filter_;
4,006✔
167
}
168

169
bool CallFilter::operator()(GlobalValue* global_value) {
19,959✔
170
  LOG_DEBUG("Analyzing value: " << util::dump(*global_value));
171
  fImpl->setMode(/*search mallocs = */ false);
19,959✔
172
  fImpl->setStartingFunction(nullptr);
19,959✔
173
  const auto filter_ = fImpl->filter(global_value);
19,959✔
174
  if (filter_) {
19,959✔
175
    LOG_DEBUG("Filtering value: " << util::dump(*global_value) << "\n");
176
  } else {
495✔
177
    LOG_DEBUG("Keeping value: " << util::dump(*global_value) << "\n");
178
  }
179
  return filter_;
19,959✔
180
}
181

182
CallFilter& CallFilter::operator=(CallFilter&&) noexcept = default;
×
183

184
CallFilter::~CallFilter() = default;
4,924✔
185

186
}  // namespace filter
187

188
class MemInstFinderPass : public MemInstFinder {
189
 private:
190
  MemOpVisitor mOpsCollector;
191
  filter::CallFilter filter;
192
  llvm::DenseMap<const llvm::Function*, FunctionData> functionMap;
193
  const MemInstFinderConfig& config;
194

195
 public:
196
  explicit MemInstFinderPass(const MemInstFinderConfig&);
197
  bool runOnModule(llvm::Module&) override;
198
  [[nodiscard]] bool hasFunctionData(const llvm::Function&) const override;
199
  [[nodiscard]] const FunctionData& getFunctionData(const llvm::Function&) const override;
200
  const GlobalDataList& getModuleGlobals() const override;
201
  void printStats(llvm::raw_ostream&) const override;
202
  // void configure(MemInstFinderConfig&) override;
203
  ~MemInstFinderPass() override = default;
9,848✔
204

205
 private:
206
  bool runOnFunction(llvm::Function&);
207
};
208

209
MemInstFinderPass::MemInstFinderPass(const MemInstFinderConfig& conf_)
11,536✔
210
    : mOpsCollector(conf_), filter(conf_), config(conf_) {
11,536✔
211
}
4,924✔
212

213
bool MemInstFinderPass::runOnModule(Module& module) {
4,924✔
214
  mOpsCollector.collectGlobals(module);
4,924✔
215
  auto& globals = mOpsCollector.globals;
4,924✔
216
  NumDetectedGlobals += globals.size();
4,924✔
217
  if (config[config::ConfigStdArgs::analysis_filter_global]) {
4,924✔
218
    globals.erase(
9,848✔
219
        llvm::remove_if(
4,924✔
220
            globals,
4,924✔
221
            [&](const auto gdata) {  // NOLINT
176,338✔
222
              GlobalVariable* global = gdata.global;
176,338✔
223
              const auto name        = global->getName();
176,338✔
224

225
              LOG_DEBUG("Analyzing global: " << name);
226

227
              if (name.empty()) {
176,338✔
228
                return true;
129,881✔
229
              }
230

231
              if (util::starts_with_any_of(name, "llvm.", "__llvm_gcov", "__llvm_gcda", "__profn", "___asan", "__msan",
46,457✔
232
                                           "__tsan", "__typeart", "_typeart", "__tysan", "__dfsan", "__profc")) {
233
                LOG_DEBUG("Prefixed matched on " << name)
234
                return true;
24,956✔
235
              }
236

237
              if (global->hasInitializer()) {
21,501✔
238
                auto* ini            = global->getInitializer();
19,971✔
239
                std::string ini_name = util::dump(*ini);
19,971✔
240

241
                if (llvm::StringRef(ini_name).contains("std::ios_base::Init")) {
19,971✔
242
                  LOG_DEBUG("std::ios");
243
                  return true;
×
244
                }
245
              }
19,971✔
246

247
              if (global->hasSection()) {
21,501✔
248
                // for instance, filters:
249
                //   a) (Coverage) -fprofile-instr-generate -fcoverage-mapping
250
                //   b) (PGO) -fprofile-instr-generate
251
                StringRef Section = global->getSection();
12✔
252
                // Globals from llvm.metadata aren't emitted, do not instrument them.
253
                if (Section == "llvm.metadata") {
12✔
254
                  LOG_DEBUG("metadata");
255
                  return true;
×
256
                }
257
                // Do not instrument globals from special LLVM sections.
258
                if (Section.find("__llvm") != StringRef::npos || Section.find("__LLVM") != StringRef::npos) {
12✔
259
                  LOG_DEBUG("llvm section");
260
                  return true;
12✔
261
                }
262
              }
×
263

264
              if ((global->getLinkage() == GlobalValue::ExternalLinkage && global->isDeclaration())) {
21,489✔
265
                LOG_DEBUG("Linkage: External");
266
                return true;
1,530✔
267
              }
268

269
              Type* global_type = global->getValueType();
19,959✔
270
              if (!global_type->isSized()) {
19,959✔
271
                LOG_DEBUG("not sized");
272
                return true;
×
273
              }
274

275
              if (global_type->isArrayTy()) {
19,959✔
276
                global_type = global_type->getArrayElementType();
18,405✔
277
              }
18,405✔
278
              if (auto structType = dyn_cast<StructType>(global_type)) {
19,959✔
279
                if (structType->isOpaque()) {
1,173✔
280
                  LOG_DEBUG("Encountered opaque struct " << global_type->getStructName() << " - skipping...");
281
                  return true;
×
282
                }
283
              }
1,173✔
284
              return false;
19,959✔
285
            }),
176,338✔
286
        globals.end());
4,924✔
287

288
    const auto beforeCallFilter = globals.size();
4,924✔
289
    NumFilteredGlobals          = NumDetectedGlobals - beforeCallFilter;
4,924✔
290

291
    globals.erase(llvm::remove_if(globals, [&](const auto global) { return filter(global.global); }), globals.end());
24,883✔
292

293
    NumCallFilteredGlobals = beforeCallFilter - globals.size();
4,924✔
294
    NumFilteredGlobals += NumCallFilteredGlobals;
4,924✔
295
  }
4,924✔
296

297
  return llvm::count_if(module.functions(), [&](auto& function) { return runOnFunction(function); }) > 0;
145,649✔
298
}  // namespace typeart
×
299

300
bool MemInstFinderPass::runOnFunction(llvm::Function& function) {
140,725✔
301
  if (function.isDeclaration() || util::starts_with_any_of(function.getName(), "__typeart")) {
140,725✔
302
    return false;
109,519✔
303
  }
304

305
  LOG_DEBUG("Running on function: " << function.getName())
306

307
  mOpsCollector.collect(function);
31,206✔
308

309
#if LLVM_VERSION_MAJOR < 15
310
  const auto checkAmbigiousMalloc = [&function](const MallocData& mallocData) {
12,187✔
311
    using namespace typeart::util::type;
312
    auto primaryBitcast = mallocData.primary;
929✔
313
    if (primaryBitcast != nullptr) {
929✔
314
      const auto& bitcasts = mallocData.bitcasts;
815✔
315
      std::for_each(bitcasts.begin(), bitcasts.end(), [&](auto bitcastInst) {
1,699✔
316
        auto dest = bitcastInst->getDestTy();
884✔
317
        if (bitcastInst != primaryBitcast &&
896✔
318
            (!isVoidPtr(dest) && !isi64Ptr(dest) &&
69✔
319
             primaryBitcast->getDestTy() != dest)) {  // void* and i64* are used by LLVM
12✔
320
          // Second non-void* bitcast detected - semantics unclear
321
          LOG_WARNING("Encountered ambiguous pointer type in function: " << util::try_demangle(function));
12✔
322
          LOG_WARNING("  Allocation" << util::dump(*(mallocData.call)));
12✔
323
          LOG_WARNING("  Primary cast: " << util::dump(*primaryBitcast));
12✔
324
          LOG_WARNING("  Secondary cast: " << util::dump(*bitcastInst));
12✔
325
        }
12✔
326
      });
884✔
327
    }
815✔
328
  };
929✔
329
#endif
330

331
  NumDetectedAllocs += mOpsCollector.allocas.size();
31,206✔
332

333
  if (config[config::ConfigStdArgs::analysis_filter_alloca_non_array]) {
31,206✔
334
    auto& allocs = mOpsCollector.allocas;
576✔
335
    allocs.erase(llvm::remove_if(allocs,
1,152✔
336
                                 [&](const auto& data) {
1,638✔
337
                                   if (!data.alloca->getAllocatedType()->isArrayTy() && data.array_size == 1) {
1,638✔
338
                                     ++NumFilteredNonArrayAllocs;
1,584✔
339
                                     return true;
1,584✔
340
                                   }
341
                                   return false;
54✔
342
                                 }),
1,638✔
343
                 allocs.end());
576✔
344
  }
576✔
345

346
  if (config[config::ConfigStdArgs::analysis_filter_heap_alloc]) {
31,206✔
347
    auto& allocs  = mOpsCollector.allocas;
42✔
348
    auto& mallocs = mOpsCollector.mallocs;
42✔
349

350
    const auto filterMallocAllocPairing = [&mallocs](const auto alloc) {
72✔
351
      // Only look for the direct users of the alloc:
352
      // TODO is a deeper analysis required?
353
      for (auto inst : alloc->users()) {
108✔
354
        if (StoreInst* store = dyn_cast<StoreInst>(inst)) {
84✔
355
          const auto source = store->getValueOperand();
30✔
356
          if (isa<BitCastInst>(source)) {
30✔
357
            for (auto& mdata : mallocs) {
18✔
358
              // is it a bitcast we already collected? if yes, we can filter the alloc
359
              return std::any_of(mdata.bitcasts.begin(), mdata.bitcasts.end(),
12✔
360
                                 [&source](const auto bcast) { return bcast == source; });
12✔
361
            }
362
          } else if (isa<CallInst>(source)) {
24✔
363
            return std::any_of(mallocs.begin(), mallocs.end(),
×
364
                               [&source](const auto& mdata) { return mdata.call == source; });
×
365
          }
366
        }
24✔
367
      }
368
      return false;
24✔
369
    };
30✔
370

371
    allocs.erase(llvm::remove_if(allocs,
126✔
372
                                 [&](const auto& data) {
72✔
373
                                   if (filterMallocAllocPairing(data.alloca)) {
30✔
374
                                     ++NumFilteredMallocAllocs;
6✔
375
                                     return true;
6✔
376
                                   }
377
                                   return false;
24✔
378
                                 }),
30✔
379
                 allocs.end());
42✔
380
  }
42✔
381

382
  if (config[config::ConfigStdArgs::analysis_filter_pointer_alloc]) {
31,206✔
383
    auto& allocs = mOpsCollector.allocas;
30,308✔
384
    allocs.erase(llvm::remove_if(allocs,
60,616✔
385
                                 [&](const auto& data) {
27,629✔
386
                                   auto alloca = data.alloca;
27,629✔
387
                                   if (!data.is_vla && isa<llvm::PointerType>(alloca->getAllocatedType())) {
27,629✔
388
                                     ++NumFilteredPointerAllocs;
11,814✔
389
                                     return true;
11,814✔
390
                                   }
391
                                   return false;
15,815✔
392
                                 }),
27,629✔
393
                 allocs.end());
30,308✔
394
  }
30,308✔
395

396
  // if (config.filter.useCallFilter) {
397
  if (config[config::ConfigStdArgs::filter]) {
31,206✔
398
    auto& allocs = mOpsCollector.allocas;
2,018✔
399
    allocs.erase(llvm::remove_if(allocs,
6,054✔
400
                                 [&](const auto& data) {
6,024✔
401
                                   if (filter(data.alloca)) {
4,006✔
402
                                     ++NumCallFilteredAllocs;
3,444✔
403
                                     return true;
3,444✔
404
                                   }
405
                                   return false;
562✔
406
                                 }),
4,006✔
407
                 allocs.end());
2,018✔
408
    //    LOG_DEBUG(allocs.size() << " allocas to instrument : " << util::dump(allocs));
409
  }
2,018✔
410

411
  auto& mallocs = mOpsCollector.mallocs;
31,206✔
412
  NumDetectedHeap += mallocs.size();
31,206✔
413

414
#if LLVM_VERSION_MAJOR < 15
415
  for (const auto& mallocData : mallocs) {
12,187✔
416
    checkAmbigiousMalloc(mallocData);
929✔
417
  }
418
#endif
419

420
  FunctionData data{mOpsCollector.mallocs, mOpsCollector.frees, mOpsCollector.allocas};
31,206✔
421
  functionMap[&function] = data;
31,206✔
422

423
  mOpsCollector.clear();
31,206✔
424

425
  return true;
31,206✔
426
}  // namespace typeart
140,725✔
427

428
void MemInstFinderPass::printStats(llvm::raw_ostream& out) const {
4,870✔
429
  const auto scope_exit_cleanup_counter = llvm::make_scope_exit([&]() {
9,740✔
430
    NumDetectedAllocs         = 0;
4,870✔
431
    NumFilteredNonArrayAllocs = 0;
4,870✔
432
    NumFilteredMallocAllocs   = 0;
4,870✔
433
    NumCallFilteredAllocs     = 0;
4,870✔
434
    NumFilteredPointerAllocs  = 0;
4,870✔
435
    NumDetectedHeap           = 0;
4,870✔
436
    NumFilteredGlobals        = 0;
4,870✔
437
    NumDetectedGlobals        = 0;
4,870✔
438
  });
4,870✔
439
  auto all_stack                        = double(NumDetectedAllocs);
4,870✔
440
  auto nonarray_stack                   = double(NumFilteredNonArrayAllocs);
4,870✔
441
  auto malloc_alloc_stack               = double(NumFilteredMallocAllocs);
4,870✔
442
  auto call_filter_stack                = double(NumCallFilteredAllocs);
4,870✔
443
  auto filter_pointer_stack             = double(NumFilteredPointerAllocs);
4,870✔
444

445
  const auto call_filter_stack_p =
4,870✔
446
      (call_filter_stack /
4,870✔
447
       std::max<double>(1.0, all_stack - nonarray_stack - malloc_alloc_stack - filter_pointer_stack)) *
4,870✔
448
      100.0;
449

450
  const auto call_filter_heap_p =
4,870✔
451
      (double(NumFilteredDetectedHeap) / std::max<double>(1.0, double(NumDetectedHeap))) * 100.0;
4,870✔
452

453
  const auto call_filter_global_p =
4,870✔
454
      (double(NumCallFilteredGlobals) / std::max(1.0, double(NumDetectedGlobals))) * 100.0;
4,870✔
455

456
  const auto call_filter_global_nocallfilter_p =
4,870✔
457
      (double(NumFilteredGlobals) / std::max(1.0, double(NumDetectedGlobals))) * 100.0;
4,870✔
458

459
  Table stats("MemInstFinderPass");
4,870✔
460
  stats.wrap_header_ = true;
4,870✔
461
  stats.wrap_length_ = true;
4,870✔
462
  std::string glob   = config[config::ConfigStdArgs::filter_glob];
4,870✔
463
  stats.put(Row::make("Filter string", glob));
4,870✔
464
  stats.put(Row::make_row("> Heap Memory"));
4,870✔
465
  stats.put(Row::make("Heap alloc", NumDetectedHeap.getValue()));
4,870✔
466
  stats.put(Row::make("Heap call filtered %", call_filter_heap_p));
4,870✔
467
  stats.put(Row::make_row("> Stack Memory"));
4,870✔
468
  stats.put(Row::make("Alloca", all_stack));
4,870✔
469
  stats.put(Row::make("Stack call filtered %", call_filter_stack_p));
4,870✔
470
  stats.put(Row::make("Alloca of pointer discarded", filter_pointer_stack));
4,870✔
471
  stats.put(Row::make_row("> Global Memory"));
4,870✔
472
  stats.put(Row::make("Global", NumDetectedGlobals.getValue()));
4,870✔
473
  stats.put(Row::make("Global filter total", NumFilteredGlobals.getValue()));
4,870✔
474
  stats.put(Row::make("Global call filtered %", call_filter_global_p));
4,870✔
475
  stats.put(Row::make("Global filtered %", call_filter_global_nocallfilter_p));
4,870✔
476

477
  std::ostringstream stream;
4,870✔
478
  stats.print(stream);
4,870✔
479
  out << stream.str();
4,870✔
480
}
4,870✔
481

482
bool MemInstFinderPass::hasFunctionData(const Function& function) const {
31,194✔
483
  auto iter = functionMap.find(&function);
31,194✔
484
  return iter != functionMap.end();
31,194✔
485
}
486

487
const FunctionData& MemInstFinderPass::getFunctionData(const Function& function) const {
31,194✔
488
  auto iter = functionMap.find(&function);
31,194✔
489
  return iter->second;
31,194✔
490
}
491

492
const GlobalDataList& MemInstFinderPass::getModuleGlobals() const {
2,380✔
493
  return mOpsCollector.globals;
2,380✔
494
}
495

496
std::unique_ptr<MemInstFinder> create_finder(const config::Configuration& config) {
4,924✔
497
  LOG_DEBUG("Constructing MemInstFinder")
498
  // const auto meminst_conf = config::helper::config_to_options(config);
499
  return std::make_unique<MemInstFinderPass>(config);
4,924✔
500
}
501

502
}  // namespace typeart::analysis
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc