1//===--- rtsan_suppressions.cpp - Realtime Sanitizer ------------*- 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// This file is a part of the RTSan runtime, providing support for suppressions
10//
11//===----------------------------------------------------------------------===//
12
13#include "rtsan/rtsan_suppressions.h"
14
15#include "rtsan/rtsan_flags.h"
16
17#include "sanitizer_common/sanitizer_common.h"
18#include "sanitizer_common/sanitizer_internal_defs.h"
19#include "sanitizer_common/sanitizer_placement_new.h"
20#include "sanitizer_common/sanitizer_suppressions.h"
21#include "sanitizer_common/sanitizer_symbolizer.h"
22
23using namespace __sanitizer;
24using namespace __rtsan;
25
26namespace {
27enum class ErrorType {
28#define RTSAN_CHECK(Name, FSanitizeFlagName) Name,
29#include "rtsan_checks.inc"
30#undef RTSAN_CHECK
31};
32} // namespace
33
34alignas(64) static char suppression_placeholder[sizeof(SuppressionContext)];
35static SuppressionContext *suppression_ctx = nullptr;
36
37static const char *kSuppressionTypes[] = {
38#define RTSAN_CHECK(Name, FSanitizeFlagName) FSanitizeFlagName,
39#include "rtsan_checks.inc"
40#undef RTSAN_CHECK
41};
42
43static const char *ConvertTypeToFlagName(ErrorType Type) {
44 switch (Type) {
45#define RTSAN_CHECK(Name, FSanitizeFlagName) \
46 case ErrorType::Name: \
47 return FSanitizeFlagName;
48#include "rtsan_checks.inc"
49#undef RTSAN_CHECK
50 }
51 UNREACHABLE("unknown ErrorType!");
52}
53
54void __rtsan::InitializeSuppressions() {
55 CHECK_EQ(nullptr, suppression_ctx);
56
57 // We will use suppression_ctx == nullptr as an early out
58 if (!flags().ContainsSuppresionFile())
59 return;
60
61 suppression_ctx = new (suppression_placeholder)
62 SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes));
63 suppression_ctx->ParseFromFile(filename: flags().suppressions);
64}
65
66bool __rtsan::IsStackTraceSuppressed(const StackTrace &stack) {
67 if (suppression_ctx == nullptr)
68 return false;
69
70 const char *call_stack_flag =
71 ConvertTypeToFlagName(Type: ErrorType::CallStackContains);
72 if (!suppression_ctx->HasSuppressionType(type: call_stack_flag))
73 return false;
74
75 Symbolizer *symbolizer = Symbolizer::GetOrInit();
76 for (uptr i = 0; i < stack.size && stack.trace[i]; i++) {
77 const uptr addr = stack.trace[i];
78
79 SymbolizedStackHolder symbolized_stack(symbolizer->SymbolizePC(address: addr));
80 const SymbolizedStack *frames = symbolized_stack.get();
81 CHECK(frames);
82 for (const SymbolizedStack *cur = frames; cur; cur = cur->next) {
83 const char *function_name = cur->info.function;
84 if (!function_name)
85 continue;
86
87 Suppression *s;
88 if (suppression_ctx->Match(str: function_name, type: call_stack_flag, s: &s))
89 return true;
90 }
91 }
92 return false;
93}
94
95bool __rtsan::IsFunctionSuppressed(const char *function_name) {
96 if (suppression_ctx == nullptr)
97 return false;
98
99 const char *flag_name = ConvertTypeToFlagName(Type: ErrorType::FunctionNameMatches);
100
101 if (!suppression_ctx->HasSuppressionType(type: flag_name))
102 return false;
103
104 Suppression *s;
105 return suppression_ctx->Match(str: function_name, type: flag_name, s: &s);
106}
107