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