[clang] [compiler-rt] [compiler-rt][rtsan] Introduce rtsan_interface.h and ScopedDisabler (PR #106736)

Chris Apple via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 30 08:20:19 PDT 2024


https://github.com/cjappl updated https://github.com/llvm/llvm-project/pull/106736

>From c9d3d6c256b763bc99e7bf2d2dca43cb1e88adb8 Mon Sep 17 00:00:00 2001
From: Chris Apple <cja-private at pm.me>
Date: Thu, 29 Aug 2024 17:16:37 -0700
Subject: [PATCH 1/3] [clang][rtsan] Add realtime sanitizer to Features.def

---
 clang/include/clang/Basic/Features.def              |  2 ++
 clang/test/Lexer/has_feature_realtime_sanitizer.cpp | 12 ++++++++++++
 2 files changed, 14 insertions(+)
 create mode 100644 clang/test/Lexer/has_feature_realtime_sanitizer.cpp

diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def
index 10538f555b418e..7f5d26118bdc71 100644
--- a/clang/include/clang/Basic/Features.def
+++ b/clang/include/clang/Basic/Features.def
@@ -54,6 +54,8 @@ FEATURE(memtag_globals,
 FEATURE(xray_instrument, LangOpts.XRayInstrument)
 FEATURE(undefined_behavior_sanitizer,
         LangOpts.Sanitize.hasOneOf(SanitizerKind::Undefined))
+FEATURE(realtime_sanitizer,
+        LangOpts.Sanitize.has(SanitizerKind::Realtime))
 FEATURE(coverage_sanitizer, LangOpts.SanitizeCoverage)
 FEATURE(assume_nonnull, true)
 FEATURE(attribute_analyzer_noreturn, true)
diff --git a/clang/test/Lexer/has_feature_realtime_sanitizer.cpp b/clang/test/Lexer/has_feature_realtime_sanitizer.cpp
new file mode 100644
index 00000000000000..76febeb6473a4b
--- /dev/null
+++ b/clang/test/Lexer/has_feature_realtime_sanitizer.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -E -fsanitize=realtime %s -o - | FileCheck --check-prefix=CHECK-RTSAN %s
+// RUN: %clang_cc1 -E  %s -o - | FileCheck --check-prefix=CHECK-NO-RTSAN %s
+
+#if __has_feature(realtime_sanitizer)
+int RealtimeSanitizerEnabled();
+#else
+int RealtimeSanitizerDisabled();
+#endif
+
+// CHECK-RTSAN: RealtimeSanitizerEnabled
+
+// CHECK-NO-RTSAN: RealtimeSanitizerDisabled

>From 3d1598edfde8b349bb65d9f132fdfdae988a4aa5 Mon Sep 17 00:00:00 2001
From: Chris Apple <cja-private at pm.me>
Date: Thu, 29 Aug 2024 17:17:12 -0700
Subject: [PATCH 2/3] [compiler-rt][rtsan] Introduce rtsan_interface.h and
 ScopedDisabler

---
 compiler-rt/include/CMakeLists.txt            |   1 +
 .../include/sanitizer/rtsan_interface.h       | 115 ++++++++++++++++++
 compiler-rt/lib/rtsan/rtsan.h                 |  20 +--
 compiler-rt/test/rtsan/disabler.cpp           |  35 ++++++
 compiler-rt/test/rtsan/enabler.cpp            |  35 ++++++
 5 files changed, 192 insertions(+), 14 deletions(-)
 create mode 100644 compiler-rt/include/sanitizer/rtsan_interface.h
 create mode 100644 compiler-rt/test/rtsan/disabler.cpp
 create mode 100644 compiler-rt/test/rtsan/enabler.cpp

diff --git a/compiler-rt/include/CMakeLists.txt b/compiler-rt/include/CMakeLists.txt
index d598a94ee2e237..242d62b9b447b1 100644
--- a/compiler-rt/include/CMakeLists.txt
+++ b/compiler-rt/include/CMakeLists.txt
@@ -10,6 +10,7 @@ if (COMPILER_RT_BUILD_SANITIZERS)
     sanitizer/lsan_interface.h
     sanitizer/msan_interface.h
     sanitizer/netbsd_syscall_hooks.h
+    sanitizer/rtsan_interface.h
     sanitizer/scudo_interface.h
     sanitizer/tsan_interface.h
     sanitizer/tsan_interface_atomic.h
diff --git a/compiler-rt/include/sanitizer/rtsan_interface.h b/compiler-rt/include/sanitizer/rtsan_interface.h
new file mode 100644
index 00000000000000..399cbfd294dacd
--- /dev/null
+++ b/compiler-rt/include/sanitizer/rtsan_interface.h
@@ -0,0 +1,115 @@
+//===-- sanitizer/rtsan_interface.h -----------------------------*- 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 RealtimeSanitizer.
+//
+// Public interface header.
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_RTSAN_INTERFACE_H
+#define SANITIZER_RTSAN_INTERFACE_H
+
+#if __has_include(<sanitizer/common_interface_defs.h>)
+#include <sanitizer/common_interface_defs.h>
+#else
+#define SANITIZER_CDECL
+#endif // __has_include(<sanitizer/common_interface_defs.h>)
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+// Initializes rtsan if it has not been initialized yet.
+// Used by the RTSan runtime to ensure that rtsan is initialized before any
+// other rtsan functions are called.
+void SANITIZER_CDECL __rtsan_ensure_initialized();
+
+// Enter real-time context.
+// When in a real-time context, RTSan interceptors will error if realtime
+// violations are detected. Calls to this method are injected at the code
+// generation stage when RTSan is enabled.
+void SANITIZER_CDECL __rtsan_realtime_enter();
+
+// Exit the real-time context.
+// When not in a real-time context, RTSan interceptors will simply forward
+// intercepted method calls to the real methods.
+void SANITIZER_CDECL __rtsan_realtime_exit();
+
+// Disable all RTSan error reporting.
+void SANITIZER_CDECL __rtsan_disable(void);
+
+// Re-enable all RTSan error reporting.
+// The counterpart to `__rtsan_disable`.
+void SANITIZER_CDECL __rtsan_enable(void);
+
+// Expect that the next call to a function with the given name will not be
+// called from a realtime context.
+void SANITIZER_CDECL
+__rtsan_expect_not_realtime(const char *intercepted_function_name);
+
+#ifdef __cplusplus
+} // extern "C"
+
+namespace __rtsan {
+#if defined(__has_feature) && __has_feature(realtime_sanitizer)
+
+void Initialize() { __rtsan_ensure_initialized(); }
+
+class ScopedEnabler {
+public:
+  ScopedEnabler() { __rtsan_realtime_enter(); }
+  ~ScopedEnabler() { __rtsan_realtime_exit(); }
+
+#if __cplusplus >= 201103L
+  ScopedEnabler(const ScopedEnabler &) = delete;
+  ScopedEnabler &operator=(const ScopedEnabler &) = delete;
+  ScopedEnabler(ScopedEnabler &&) = delete;
+  ScopedEnabler &operator=(ScopedEnabler &&) = delete;
+#else
+private:
+  ScopedEnabler(const ScopedEnabler &);
+  ScopedEnabler &operator=(const ScopedEnabler &);
+#endif // __cplusplus >= 201103L
+};
+
+class ScopedDisabler {
+public:
+  ScopedDisabler() { __rtsan_disable(); }
+  ~ScopedDisabler() { __rtsan_enable(); }
+
+#if __cplusplus >= 201103L
+  ScopedDisabler(const ScopedDisabler &) = delete;
+  ScopedDisabler &operator=(const ScopedDisabler &) = delete;
+  ScopedDisabler(ScopedDisabler &&) = delete;
+  ScopedDisabler &operator=(ScopedDisabler &&) = delete;
+#else
+private:
+  ScopedDisabler(const ScopedDisabler &);
+  ScopedDisabler &operator=(const ScopedDisabler &);
+#endif // __cplusplus >= 201103L
+};
+
+#else // doesn't have realtime_sanitizer
+
+void Initialize() {}
+
+class ScopedEnabler {
+public:
+  ScopedEnabler() {}
+};
+
+class ScopedDisabler {
+public:
+  ScopedDisabler() {}
+};
+
+#endif // defined(__has_feature) && __has_feature(realtime_sanitizer)
+} // namespace __rtsan
+#endif // __cplusplus
+
+#endif // SANITIZER_RTSAN_INTERFACE_H
diff --git a/compiler-rt/lib/rtsan/rtsan.h b/compiler-rt/lib/rtsan/rtsan.h
index ae23609f97d2dc..80fcb1dec2ff1c 100644
--- a/compiler-rt/lib/rtsan/rtsan.h
+++ b/compiler-rt/lib/rtsan/rtsan.h
@@ -18,32 +18,24 @@ extern "C" {
 // A call to this method is added to the preinit array on Linux systems.
 SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_init();
 
-// Initializes rtsan if it has not been initialized yet.
-// Used by the RTSan runtime to ensure that rtsan is initialized before any
-// other rtsan functions are called.
+// See documentation in rtsan_interface.h.
 SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_ensure_initialized();
 
 SANITIZER_INTERFACE_ATTRIBUTE bool __rtsan_is_initialized();
 
-// Enter real-time context.
-// When in a real-time context, RTSan interceptors will error if realtime
-// violations are detected. Calls to this method are injected at the code
-// generation stage when RTSan is enabled.
+// See documentation in rtsan_interface.h.
 SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_realtime_enter();
 
-// Exit the real-time context.
-// When not in a real-time context, RTSan interceptors will simply forward
-// intercepted method calls to the real methods.
+// See documentation in rtsan_interface.h.
 SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_realtime_exit();
 
-// Disable all RTSan error reporting.
-// Injected into the code if "nosanitize(realtime)" is on a function.
+// See documentation in rtsan_interface.h.
 SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_disable();
 
-// Re-enable all RTSan error reporting.
-// The counterpart to `__rtsan_disable`.
+// See documentation in rtsan_interface.h.
 SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_enable();
 
+// See documentation in rtsan_interface.h.
 SANITIZER_INTERFACE_ATTRIBUTE void
 __rtsan_expect_not_realtime(const char *intercepted_function_name);
 
diff --git a/compiler-rt/test/rtsan/disabler.cpp b/compiler-rt/test/rtsan/disabler.cpp
new file mode 100644
index 00000000000000..1fc14b0bac4e01
--- /dev/null
+++ b/compiler-rt/test/rtsan/disabler.cpp
@@ -0,0 +1,35 @@
+// RUN: %clangxx -fsanitize=realtime %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx %s -fsanitize=realtime -o - -S -emit-llvm | FileCheck %s --check-prefix=CHECK-ENABLED-IR
+// RUN: %clangxx %s -o - -S -emit-llvm | FileCheck %s --check-prefix=CHECK-DISABLED-IR
+// UNSUPPORTED: ios
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "sanitizer/rtsan_interface.h"
+
+void violation() [[clang::nonblocking]] {
+  void *ptr;
+  {
+    __rtsan::ScopedDisabler disabler{};
+    ptr = malloc(2);
+    printf("ptr: %p\n", ptr); // ensure we don't optimize out the malloc
+  }
+
+  free(ptr);
+}
+
+int main() {
+  violation();
+  return 0;
+  // CHECK: {{.*Real-time violation.*}}
+  // CHECK-NOT: {{.*malloc*}}
+  // CHECK: {{.*free*}}
+}
+
+// CHECK-ENABLED-IR: {{.*@__rtsan_disable.*}}
+// CHECK-ENABLED-IR: {{.*@__rtsan_enable.*}}
+
+// CHECK-DISABLED-IR-NOT: {{.*__rtsan_disable.*}}
+// CHECK-DISABLED-IR-NOT: {{.*__rtsan_enable.*}}
diff --git a/compiler-rt/test/rtsan/enabler.cpp b/compiler-rt/test/rtsan/enabler.cpp
new file mode 100644
index 00000000000000..0ae8ba6e792839
--- /dev/null
+++ b/compiler-rt/test/rtsan/enabler.cpp
@@ -0,0 +1,35 @@
+// RUN: %clangxx -fsanitize=realtime %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx %s -fsanitize=realtime -o - -S -emit-llvm | FileCheck %s --check-prefix=CHECK-ENABLED-IR
+// RUN: %clangxx %s -o - -S -emit-llvm | FileCheck %s --check-prefix=CHECK-DISABLED-IR
+// UNSUPPORTED: ios
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "sanitizer/rtsan_interface.h"
+
+void violation() {
+  void *ptr = malloc(2);
+  ptr = malloc(2);
+  printf("ptr: %p\n", ptr); // ensure we don't optimize out the malloc
+
+  {
+    __rtsan::ScopedEnabler rtsan{};
+    free(ptr);
+  }
+}
+
+int main() {
+  violation();
+  return 0;
+  // CHECK: {{.*Real-time violation.*}}
+  // CHECK-NOT: {{.*malloc*}}
+  // CHECK: {{.*free*}}
+}
+
+// CHECK-ENABLED-IR: {{.*@__rtsan_realtime_enter.*}}
+// CHECK-ENABLED-IR: {{.*@__rtsan_realtime_exit.*}}
+
+// CHECK-DISABLED-IR-NOT: {{.*__rtsan_realtime_enter.*}}
+// CHECK-DISABLED-IR-NOT: {{.*__rtsan_realtime_exit.*}}

>From 62aee5adb5739a34d7c5ef0b37488b41eca06e3d Mon Sep 17 00:00:00 2001
From: Chris Apple <cja-private at pm.me>
Date: Fri, 30 Aug 2024 08:20:03 -0700
Subject: [PATCH 3/3] Add rtsan_enabled define

---
 compiler-rt/include/sanitizer/rtsan_interface.h | 6 ++++--
 compiler-rt/test/rtsan/enabler.cpp              | 7 +++++--
 2 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/compiler-rt/include/sanitizer/rtsan_interface.h b/compiler-rt/include/sanitizer/rtsan_interface.h
index 399cbfd294dacd..b816d5a8b419ee 100644
--- a/compiler-rt/include/sanitizer/rtsan_interface.h
+++ b/compiler-rt/include/sanitizer/rtsan_interface.h
@@ -56,7 +56,8 @@ __rtsan_expect_not_realtime(const char *intercepted_function_name);
 } // extern "C"
 
 namespace __rtsan {
-#if defined(__has_feature) && __has_feature(realtime_sanitizer)
+#if (defined(__has_feature) && __has_feature(realtime_sanitizer)) ||           \
+    defined(RTSAN_ENABLED)
 
 void Initialize() { __rtsan_ensure_initialized(); }
 
@@ -108,7 +109,8 @@ class ScopedDisabler {
   ScopedDisabler() {}
 };
 
-#endif // defined(__has_feature) && __has_feature(realtime_sanitizer)
+#endif // defined(__has_feature) && __has_feature(realtime_sanitizer) ||
+       // defined(RTSAN_ENABLED)
 } // namespace __rtsan
 #endif // __cplusplus
 
diff --git a/compiler-rt/test/rtsan/enabler.cpp b/compiler-rt/test/rtsan/enabler.cpp
index 0ae8ba6e792839..f26116ba274e5f 100644
--- a/compiler-rt/test/rtsan/enabler.cpp
+++ b/compiler-rt/test/rtsan/enabler.cpp
@@ -1,6 +1,6 @@
-// RUN: %clangxx -fsanitize=realtime %s -o %t
+// RUN: %clangxx -DRTSAN_ENABLED -fsanitize=realtime %s -o %t
 // RUN: not %run %t 2>&1 | FileCheck %s
-// RUN: %clangxx %s -fsanitize=realtime -o - -S -emit-llvm | FileCheck %s --check-prefix=CHECK-ENABLED-IR
+// RUN: %clangxx %s -DRTSAN_ENABLED -o - -S -emit-llvm | FileCheck %s --check-prefix=CHECK-ENABLED-IR
 // RUN: %clangxx %s -o - -S -emit-llvm | FileCheck %s --check-prefix=CHECK-DISABLED-IR
 // UNSUPPORTED: ios
 
@@ -21,6 +21,7 @@ void violation() {
 }
 
 int main() {
+  __rtsan::Initialize();
   violation();
   return 0;
   // CHECK: {{.*Real-time violation.*}}
@@ -28,8 +29,10 @@ int main() {
   // CHECK: {{.*free*}}
 }
 
+// CHECK-ENABLED-IR: {{.*__rtsan_ensure_initialized.*}}
 // CHECK-ENABLED-IR: {{.*@__rtsan_realtime_enter.*}}
 // CHECK-ENABLED-IR: {{.*@__rtsan_realtime_exit.*}}
 
+// CHECK-DISABLED-IR-NOT: {{.*__rtsan_ensure_initialized.*}}
 // CHECK-DISABLED-IR-NOT: {{.*__rtsan_realtime_enter.*}}
 // CHECK-DISABLED-IR-NOT: {{.*__rtsan_realtime_exit.*}}



More information about the llvm-commits mailing list