[clang] [compiler-rt] [compiler-rt][rtsan] Introduce rtsan_interface.h and ScopedDisabler (PR #106736)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Aug 30 07:12:03 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Chris Apple (cjappl)
<details>
<summary>Changes</summary>
Follows #<!-- -->106650 - that's why that change is in this PR, that will disappear when that is approved and merged.
To disable rtsan, we are following the same approach as lsan: https://github.com/llvm/llvm-project/blob/c792de28dfaf3a13703e83e4eb09dd44574b3a3e/compiler-rt/include/sanitizer/lsan_interface.h#L80-L87
We needed to do a little groundwork to:
- Expose the rtsan_interface.h file, which didn't exist before
- Hide this behind a `#if defined(__has_feature) && __has_feature(realtime_sanitizer)`
---
Full diff: https://github.com/llvm/llvm-project/pull/106736.diff
7 Files Affected:
- (modified) clang/include/clang/Basic/Features.def (+2)
- (added) clang/test/Lexer/has_feature_realtime_sanitizer.cpp (+12)
- (modified) compiler-rt/include/CMakeLists.txt (+1)
- (added) compiler-rt/include/sanitizer/rtsan_interface.h (+115)
- (modified) compiler-rt/lib/rtsan/rtsan.h (+6-14)
- (added) compiler-rt/test/rtsan/disabler.cpp (+35)
- (added) compiler-rt/test/rtsan/enabler.cpp (+35)
``````````diff
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
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.*}}
``````````
</details>
https://github.com/llvm/llvm-project/pull/106736
More information about the cfe-commits
mailing list