[compiler-rt] [rtsan] Support basic call stack suppressions (PR #111608)
Chris Apple via llvm-commits
llvm-commits at lists.llvm.org
Thu Oct 10 14:33:58 PDT 2024
https://github.com/cjappl updated https://github.com/llvm/llvm-project/pull/111608
>From 19b53fe639df77a96173abb0e2a58bdb251ed997 Mon Sep 17 00:00:00 2001
From: Chris Apple <cja-private at pm.me>
Date: Thu, 26 Sep 2024 10:53:37 -0700
Subject: [PATCH 1/2] [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 af34fb63cf53cc..f8dd4d735bc2a3 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 7691815fd5c1dc..e9f42d3760aa82 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 745cbea0eb3a29..8183a8202478ff 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 00000000000000..d0a720c4575d27
--- /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 1df71127d19d37..5c3eb3f53a5eb4 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 00000000000000..a1f9c316f98d6e
--- /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 <new>
+
+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 00000000000000..45545f8c0e0b65
--- /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 00000000000000..2aceedbb313b11
--- /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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <vector>
+
+void *MallocViolation() { return malloc(10); }
+
+void VectorViolations() {
+ // All of these should be suppressed by *vector*
+ std::vector<int> 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 00000000000000..73e1a935c741d8
--- /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 <cja-private at pm.me>
Date: Thu, 10 Oct 2024 14:30:16 -0700
Subject: [PATCH 2/2] [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 a1f9c316f98d6e..867e5189c2e79f 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;
}
More information about the llvm-commits
mailing list