From 19b53fe639df77a96173abb0e2a58bdb251ed997 Mon Sep 17 00:00:00 2001 From: Chris Apple Date: Thu, 26 Sep 2024 10:53:37 -0700 Subject: [PATCH 1/5] [rtsan] Support suppressions list --- compiler-rt/lib/rtsan/CMakeLists.txt | 3 + compiler-rt/lib/rtsan/rtsan.cpp | 4 +- compiler-rt/lib/rtsan/rtsan_assertions.h | 4 + compiler-rt/lib/rtsan/rtsan_checks.inc | 19 ++++ compiler-rt/lib/rtsan/rtsan_flags.inc | 1 + compiler-rt/lib/rtsan/rtsan_suppressions.cpp | 94 +++++++++++++++++++ compiler-rt/lib/rtsan/rtsan_suppressions.h | 22 +++++ compiler-rt/test/rtsan/stack_suppressions.cpp | 53 +++++++++++ .../test/rtsan/stack_suppressions.cpp.supp | 4 + 9 files changed, 203 insertions(+), 1 deletion(-) create mode 100644 compiler-rt/lib/rtsan/rtsan_checks.inc create mode 100644 compiler-rt/lib/rtsan/rtsan_suppressions.cpp create mode 100644 compiler-rt/lib/rtsan/rtsan_suppressions.h create mode 100644 compiler-rt/test/rtsan/stack_suppressions.cpp create mode 100644 compiler-rt/test/rtsan/stack_suppressions.cpp.supp diff --git a/compiler-rt/lib/rtsan/CMakeLists.txt b/compiler-rt/lib/rtsan/CMakeLists.txt index af34fb63cf53c..f8dd4d735bc2a 100644 --- a/compiler-rt/lib/rtsan/CMakeLists.txt +++ b/compiler-rt/lib/rtsan/CMakeLists.txt @@ -7,6 +7,7 @@ set(RTSAN_CXX_SOURCES rtsan_flags.cpp rtsan_interceptors.cpp rtsan_stats.cpp + rtsan_suppressions.cpp ) set(RTSAN_PREINIT_SOURCES @@ -14,12 +15,14 @@ set(RTSAN_PREINIT_SOURCES set(RTSAN_HEADERS rtsan.h + rtsan_checks.inc rtsan_assertions.h rtsan_context.h rtsan_diagnostics.h rtsan_flags.h rtsan_flags.inc rtsan_stats.h + rtsan_suppressions.h ) set(RTSAN_DEPS) diff --git a/compiler-rt/lib/rtsan/rtsan.cpp b/compiler-rt/lib/rtsan/rtsan.cpp index 7691815fd5c1d..e9f42d3760aa8 100644 --- a/compiler-rt/lib/rtsan/rtsan.cpp +++ b/compiler-rt/lib/rtsan/rtsan.cpp @@ -14,12 +14,12 @@ #include "rtsan/rtsan_flags.h" #include "rtsan/rtsan_interceptors.h" #include "rtsan/rtsan_stats.h" +#include "rtsan/rtsan_suppressions.h" #include "sanitizer_common/sanitizer_atomic.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_mutex.h" #include "sanitizer_common/sanitizer_stackdepot.h" -#include "sanitizer_common/sanitizer_stacktrace.h" using namespace __rtsan; using namespace __sanitizer; @@ -85,6 +85,8 @@ SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_init() { InitializeFlags(); InitializeInterceptors(); + InitializeSuppressions(); + if (flags().print_stats_on_exit) Atexit(PrintStatisticsSummary); diff --git a/compiler-rt/lib/rtsan/rtsan_assertions.h b/compiler-rt/lib/rtsan/rtsan_assertions.h index 745cbea0eb3a2..8183a8202478f 100644 --- a/compiler-rt/lib/rtsan/rtsan_assertions.h +++ b/compiler-rt/lib/rtsan/rtsan_assertions.h @@ -15,6 +15,7 @@ #include "rtsan/rtsan.h" #include "rtsan/rtsan_context.h" #include "rtsan/rtsan_diagnostics.h" +#include "rtsan/rtsan_suppressions.h" #include "sanitizer_common/sanitizer_stacktrace.h" @@ -34,6 +35,9 @@ void ExpectNotRealtime(Context &context, const DiagnosticsInfo &info, stack.Unwind(info.pc, info.bp, nullptr, __sanitizer::common_flags()->fast_unwind_on_fatal); + if (IsStackTraceSuppressed(stack)) + return; + OnViolation(stack, info); } } diff --git a/compiler-rt/lib/rtsan/rtsan_checks.inc b/compiler-rt/lib/rtsan/rtsan_checks.inc new file mode 100644 index 0000000000000..d0a720c4575d2 --- /dev/null +++ b/compiler-rt/lib/rtsan/rtsan_checks.inc @@ -0,0 +1,19 @@ +//===-- rtsan_checks.inc ----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// List of suppression checks handled by RTSan runtime. +// +//===----------------------------------------------------------------------===// +#ifndef RTSAN_CHECK +#error "Define RTSAN_CHECK prior to including this file!" +#endif + +// RTSAN_CHECK(Name, SummaryKind) +// SummaryKind should be a string literal. + +RTSAN_CHECK(InCallStack, "in-call-stack") diff --git a/compiler-rt/lib/rtsan/rtsan_flags.inc b/compiler-rt/lib/rtsan/rtsan_flags.inc index 1df71127d19d3..5c3eb3f53a5eb 100644 --- a/compiler-rt/lib/rtsan/rtsan_flags.inc +++ b/compiler-rt/lib/rtsan/rtsan_flags.inc @@ -18,3 +18,4 @@ RTSAN_FLAG(bool, halt_on_error, true, "Exit after first reported error.") RTSAN_FLAG(bool, print_stats_on_exit, false, "Print stats on exit.") +RTSAN_FLAG(const char *, suppressions, "", "Suppressions file name.") diff --git a/compiler-rt/lib/rtsan/rtsan_suppressions.cpp b/compiler-rt/lib/rtsan/rtsan_suppressions.cpp new file mode 100644 index 0000000000000..a1f9c316f98d6 --- /dev/null +++ b/compiler-rt/lib/rtsan/rtsan_suppressions.cpp @@ -0,0 +1,94 @@ +//===--- rtsan_suppressions.cpp - Realtime Sanitizer ------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of the RTSan runtime, providing support for suppressions +// +//===----------------------------------------------------------------------===// + +#include "rtsan/rtsan_suppressions.h" + +#include "rtsan/rtsan_flags.h" + +#include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_internal_defs.h" +#include "sanitizer_common/sanitizer_suppressions.h" +#include "sanitizer_common/sanitizer_symbolizer.h" + +#include + +using namespace __sanitizer; +using namespace __rtsan; + +namespace { +enum class ErrorType { +#define RTSAN_CHECK(Name, FSanitizeFlagName) Name, +#include "rtsan_checks.inc" +#undef RTSAN_CHECK +}; +} // namespace + +alignas(64) static char suppression_placeholder[sizeof(SuppressionContext)]; +static SuppressionContext *suppression_ctx = nullptr; + +static const char *kSuppressionTypes[] = { +#define RTSAN_CHECK(Name, FSanitizeFlagName) FSanitizeFlagName, +#include "rtsan_checks.inc" +#undef RTSAN_CHECK +}; + +static const char *ConvertTypeToFlagName(ErrorType Type) { + switch (Type) { +#define RTSAN_CHECK(Name, FSanitizeFlagName) \ + case ErrorType::Name: \ + return FSanitizeFlagName; +#include "rtsan_checks.inc" +#undef RTSAN_CHECK + } + UNREACHABLE("unknown ErrorType!"); +} + +void __rtsan::InitializeSuppressions() { + CHECK_EQ(nullptr, suppression_ctx); + + // We will use suppression_ctx == nullptr as an early out + if (flags().suppressions[0] == 0) + return; + + suppression_ctx = new (suppression_placeholder) + SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes)); + suppression_ctx->ParseFromFile(flags().suppressions); +} + +bool __rtsan::IsStackTraceSuppressed(const StackTrace &stack) { + if (suppression_ctx == nullptr) + return false; + + const char *call_stack_flag = ConvertTypeToFlagName(ErrorType::InCallStack); + if (!suppression_ctx->HasSuppressionType(call_stack_flag)) + return false; + + Symbolizer *symbolizer = Symbolizer::GetOrInit(); + Suppression *s; + + for (uptr i = 0; i < stack.size && stack.trace[i]; i++) { + const uptr addr = stack.trace[i]; + + SymbolizedStackHolder symbolized_stack(symbolizer->SymbolizePC(addr)); + const SymbolizedStack *frames = symbolized_stack.get(); + CHECK(frames); + for (const SymbolizedStack *cur = frames; cur; cur = cur->next) { + const char *function_name = cur->info.function; + if (!function_name) + continue; + + if (suppression_ctx->Match(function_name, call_stack_flag, &s)) + return true; + } + } + return false; +} diff --git a/compiler-rt/lib/rtsan/rtsan_suppressions.h b/compiler-rt/lib/rtsan/rtsan_suppressions.h new file mode 100644 index 0000000000000..45545f8c0e0b6 --- /dev/null +++ b/compiler-rt/lib/rtsan/rtsan_suppressions.h @@ -0,0 +1,22 @@ +//===--- rtsan_suppressions.h - Realtime Sanitizer --------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of the RTSan runtime, providing support for suppressions +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "sanitizer_common/sanitizer_stacktrace.h" + +namespace __rtsan { + +void InitializeSuppressions(); +bool IsStackTraceSuppressed(const __sanitizer::StackTrace &stack); + +} // namespace __rtsan diff --git a/compiler-rt/test/rtsan/stack_suppressions.cpp b/compiler-rt/test/rtsan/stack_suppressions.cpp new file mode 100644 index 0000000000000..2aceedbb313b1 --- /dev/null +++ b/compiler-rt/test/rtsan/stack_suppressions.cpp @@ -0,0 +1,53 @@ +// RUN: %clangxx -fsanitize=realtime %s -o %t +// RUN: %env_rtsan_opts=suppressions='%s.supp' not %run %t 2>&1 | FileCheck %s +// UNSUPPORTED: ios + +// Intent: Ensure that suppressions work as intended + +#include +#include +#include + +#include + +void *MallocViolation() { return malloc(10); } + +void VectorViolations() { + // All of these should be suppressed by *vector* + std::vector v(10); + v.resize(20); + v.clear(); + v.resize(0); + v.push_back(1); + v.reserve(10); +} + +void BlockFunc() [[clang::blocking]] { usleep(1); } + +void *process() [[clang::nonblocking]] { + void *ptr = MallocViolation(); + VectorViolations(); + BlockFunc(); + free(ptr); + + // This is the one that should abort the program + // Everything else is suppressed + usleep(1); + + return ptr; +} + +int main() { + process(); + return 0; +} + +// CHECK-NOT: failed to open suppressions file +// CHECK: Intercepted call to real-time unsafe function +// CHECK-SAME: usleep + +// CHECK-NOT: Intercepted call to real-time unsafe function +// CHECK-NOT: malloc +// CHECK-NOT: vector +// CHECK-NOT: free +// CHECK-NOT: BlockFunc diff --git a/compiler-rt/test/rtsan/stack_suppressions.cpp.supp b/compiler-rt/test/rtsan/stack_suppressions.cpp.supp new file mode 100644 index 0000000000000..73e1a935c741d --- /dev/null +++ b/compiler-rt/test/rtsan/stack_suppressions.cpp.supp @@ -0,0 +1,4 @@ +in-call-stack:MallocViolation +in-call-stack:std::*vector +in-call-stack:free +in-call-stack:BlockFunc From 36880be472e54943ee536713eec7699fda448bbd Mon Sep 17 00:00:00 2001 From: Chris Apple Date: Thu, 10 Oct 2024 14:30:16 -0700 Subject: [PATCH 2/5] [PR] fmayer - null char, make scope of symbolizer smaller --- compiler-rt/lib/rtsan/rtsan_suppressions.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/compiler-rt/lib/rtsan/rtsan_suppressions.cpp b/compiler-rt/lib/rtsan/rtsan_suppressions.cpp index a1f9c316f98d6..867e5189c2e79 100644 --- a/compiler-rt/lib/rtsan/rtsan_suppressions.cpp +++ b/compiler-rt/lib/rtsan/rtsan_suppressions.cpp @@ -56,7 +56,7 @@ void __rtsan::InitializeSuppressions() { CHECK_EQ(nullptr, suppression_ctx); // We will use suppression_ctx == nullptr as an early out - if (flags().suppressions[0] == 0) + if (flags().suppressions[0] == '\0') return; suppression_ctx = new (suppression_placeholder) @@ -72,12 +72,10 @@ bool __rtsan::IsStackTraceSuppressed(const StackTrace &stack) { if (!suppression_ctx->HasSuppressionType(call_stack_flag)) return false; - Symbolizer *symbolizer = Symbolizer::GetOrInit(); - Suppression *s; - for (uptr i = 0; i < stack.size && stack.trace[i]; i++) { const uptr addr = stack.trace[i]; + Symbolizer *symbolizer = Symbolizer::GetOrInit(); SymbolizedStackHolder symbolized_stack(symbolizer->SymbolizePC(addr)); const SymbolizedStack *frames = symbolized_stack.get(); CHECK(frames); @@ -86,6 +84,7 @@ bool __rtsan::IsStackTraceSuppressed(const StackTrace &stack) { if (!function_name) continue; + Suppression *s; if (suppression_ctx->Match(function_name, call_stack_flag, &s)) return true; } From 17d99d66c87e7fccb9edbaf492f894c9221dad54 Mon Sep 17 00:00:00 2001 From: Chris Apple Date: Thu, 10 Oct 2024 14:39:12 -0700 Subject: [PATCH 3/5] [PR] fmayer - fix location of symbolizer init --- compiler-rt/lib/rtsan/rtsan_suppressions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler-rt/lib/rtsan/rtsan_suppressions.cpp b/compiler-rt/lib/rtsan/rtsan_suppressions.cpp index 867e5189c2e79..7a0a01d6c38d3 100644 --- a/compiler-rt/lib/rtsan/rtsan_suppressions.cpp +++ b/compiler-rt/lib/rtsan/rtsan_suppressions.cpp @@ -72,10 +72,10 @@ bool __rtsan::IsStackTraceSuppressed(const StackTrace &stack) { if (!suppression_ctx->HasSuppressionType(call_stack_flag)) return false; + Symbolizer *symbolizer = Symbolizer::GetOrInit(); for (uptr i = 0; i < stack.size && stack.trace[i]; i++) { const uptr addr = stack.trace[i]; - Symbolizer *symbolizer = Symbolizer::GetOrInit(); SymbolizedStackHolder symbolized_stack(symbolizer->SymbolizePC(addr)); const SymbolizedStack *frames = symbolized_stack.get(); CHECK(frames); From 888b53def34f6ce63ced0ce031034c8a7e2e820b Mon Sep 17 00:00:00 2001 From: Chris Apple Date: Fri, 11 Oct 2024 07:14:14 -0700 Subject: [PATCH 4/5] [PR] dtraev/fmayer - call-stack-contains, small refactor of nullptr check --- compiler-rt/lib/rtsan/rtsan_assertions.h | 2 +- compiler-rt/lib/rtsan/rtsan_checks.inc | 2 +- compiler-rt/lib/rtsan/rtsan_suppressions.cpp | 8 +++++--- compiler-rt/lib/rtsan/rtsan_suppressions.h | 1 + compiler-rt/test/rtsan/stack_suppressions.cpp.supp | 8 ++++---- 5 files changed, 12 insertions(+), 9 deletions(-) diff --git a/compiler-rt/lib/rtsan/rtsan_assertions.h b/compiler-rt/lib/rtsan/rtsan_assertions.h index 8183a8202478f..0ec06363489ec 100644 --- a/compiler-rt/lib/rtsan/rtsan_assertions.h +++ b/compiler-rt/lib/rtsan/rtsan_assertions.h @@ -35,7 +35,7 @@ void ExpectNotRealtime(Context &context, const DiagnosticsInfo &info, stack.Unwind(info.pc, info.bp, nullptr, __sanitizer::common_flags()->fast_unwind_on_fatal); - if (IsStackTraceSuppressed(stack)) + if (HasSuppressions() && IsStackTraceSuppressed(stack)) return; OnViolation(stack, info); diff --git a/compiler-rt/lib/rtsan/rtsan_checks.inc b/compiler-rt/lib/rtsan/rtsan_checks.inc index d0a720c4575d2..f5f23e044bd5d 100644 --- a/compiler-rt/lib/rtsan/rtsan_checks.inc +++ b/compiler-rt/lib/rtsan/rtsan_checks.inc @@ -16,4 +16,4 @@ // RTSAN_CHECK(Name, SummaryKind) // SummaryKind should be a string literal. -RTSAN_CHECK(InCallStack, "in-call-stack") +RTSAN_CHECK(CallStackContains, "call-stack-contains") diff --git a/compiler-rt/lib/rtsan/rtsan_suppressions.cpp b/compiler-rt/lib/rtsan/rtsan_suppressions.cpp index 7a0a01d6c38d3..2ffbdb66628a6 100644 --- a/compiler-rt/lib/rtsan/rtsan_suppressions.cpp +++ b/compiler-rt/lib/rtsan/rtsan_suppressions.cpp @@ -52,6 +52,8 @@ static const char *ConvertTypeToFlagName(ErrorType Type) { UNREACHABLE("unknown ErrorType!"); } +bool __rtsan::HasSuppressions() { return suppression_ctx != nullptr; } + void __rtsan::InitializeSuppressions() { CHECK_EQ(nullptr, suppression_ctx); @@ -65,10 +67,10 @@ void __rtsan::InitializeSuppressions() { } bool __rtsan::IsStackTraceSuppressed(const StackTrace &stack) { - if (suppression_ctx == nullptr) - return false; + CHECK(HasSuppressions()); - const char *call_stack_flag = ConvertTypeToFlagName(ErrorType::InCallStack); + const char *call_stack_flag = + ConvertTypeToFlagName(ErrorType::CallStackContains); if (!suppression_ctx->HasSuppressionType(call_stack_flag)) return false; diff --git a/compiler-rt/lib/rtsan/rtsan_suppressions.h b/compiler-rt/lib/rtsan/rtsan_suppressions.h index 45545f8c0e0b6..ec660ca666f92 100644 --- a/compiler-rt/lib/rtsan/rtsan_suppressions.h +++ b/compiler-rt/lib/rtsan/rtsan_suppressions.h @@ -17,6 +17,7 @@ namespace __rtsan { void InitializeSuppressions(); +bool HasSuppressions(); bool IsStackTraceSuppressed(const __sanitizer::StackTrace &stack); } // namespace __rtsan diff --git a/compiler-rt/test/rtsan/stack_suppressions.cpp.supp b/compiler-rt/test/rtsan/stack_suppressions.cpp.supp index 73e1a935c741d..bec4db259a3e0 100644 --- a/compiler-rt/test/rtsan/stack_suppressions.cpp.supp +++ b/compiler-rt/test/rtsan/stack_suppressions.cpp.supp @@ -1,4 +1,4 @@ -in-call-stack:MallocViolation -in-call-stack:std::*vector -in-call-stack:free -in-call-stack:BlockFunc +call-stack-contains:MallocViolation +call-stack-contains:std::*vector +call-stack-contains:free +call-stack-contains:BlockFunc From 87b29f029bea46a5471061faba6c7ae94929dc84 Mon Sep 17 00:00:00 2001 From: Chris Apple Date: Sat, 12 Oct 2024 07:55:52 -0700 Subject: [PATCH 5/5] [PR] vitalybuka - revert 'HasSuppressions' function --- compiler-rt/lib/rtsan/rtsan_assertions.h | 2 +- compiler-rt/lib/rtsan/rtsan_suppressions.cpp | 5 ++--- compiler-rt/lib/rtsan/rtsan_suppressions.h | 1 - 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/compiler-rt/lib/rtsan/rtsan_assertions.h b/compiler-rt/lib/rtsan/rtsan_assertions.h index 0ec06363489ec..8183a8202478f 100644 --- a/compiler-rt/lib/rtsan/rtsan_assertions.h +++ b/compiler-rt/lib/rtsan/rtsan_assertions.h @@ -35,7 +35,7 @@ void ExpectNotRealtime(Context &context, const DiagnosticsInfo &info, stack.Unwind(info.pc, info.bp, nullptr, __sanitizer::common_flags()->fast_unwind_on_fatal); - if (HasSuppressions() && IsStackTraceSuppressed(stack)) + if (IsStackTraceSuppressed(stack)) return; OnViolation(stack, info); diff --git a/compiler-rt/lib/rtsan/rtsan_suppressions.cpp b/compiler-rt/lib/rtsan/rtsan_suppressions.cpp index 2ffbdb66628a6..c5051dd191023 100644 --- a/compiler-rt/lib/rtsan/rtsan_suppressions.cpp +++ b/compiler-rt/lib/rtsan/rtsan_suppressions.cpp @@ -52,8 +52,6 @@ static const char *ConvertTypeToFlagName(ErrorType Type) { UNREACHABLE("unknown ErrorType!"); } -bool __rtsan::HasSuppressions() { return suppression_ctx != nullptr; } - void __rtsan::InitializeSuppressions() { CHECK_EQ(nullptr, suppression_ctx); @@ -67,7 +65,8 @@ void __rtsan::InitializeSuppressions() { } bool __rtsan::IsStackTraceSuppressed(const StackTrace &stack) { - CHECK(HasSuppressions()); + if (suppression_ctx == nullptr) + return false; const char *call_stack_flag = ConvertTypeToFlagName(ErrorType::CallStackContains); diff --git a/compiler-rt/lib/rtsan/rtsan_suppressions.h b/compiler-rt/lib/rtsan/rtsan_suppressions.h index ec660ca666f92..45545f8c0e0b6 100644 --- a/compiler-rt/lib/rtsan/rtsan_suppressions.h +++ b/compiler-rt/lib/rtsan/rtsan_suppressions.h @@ -17,7 +17,6 @@ namespace __rtsan { void InitializeSuppressions(); -bool HasSuppressions(); bool IsStackTraceSuppressed(const __sanitizer::StackTrace &stack); } // namespace __rtsan