[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