-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[compiler-rt][rtsan] Introduce rtsan_interface.h and ScopedDisabler #106736
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-compiler-rt-sanitizer @llvm/pr-subscribers-clang Author: Chris Apple (cjappl) ChangesFollows #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: llvm-project/compiler-rt/include/sanitizer/lsan_interface.h Lines 80 to 87 in c792de2
We needed to do a little groundwork to:
Full diff: https://github.com/llvm/llvm-project/pull/106736.diff 7 Files Affected:
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.*}}
|
CC @davidtrevelyan for review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
Just saw the test failure, but it is unrelated:
|
Weekly reviewer ping @vitalybuka @MaskRay @pcc |
Allows us to introduce the scoped disabler in #106736
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, with addressed comments
7875896
to
aac11a1
Compare
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:
llvm-project/compiler-rt/include/sanitizer/lsan_interface.h
Lines 80 to 87 in c792de2
We needed to do a little groundwork to:
#if defined(__has_feature) && __has_feature(realtime_sanitizer)