[clang] [compiler-rt] PREVIEW: Introduce realtime sanitizer backend (PR #91529)

via cfe-commits cfe-commits at lists.llvm.org
Wed May 8 13:19:22 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-driver

@llvm/pr-subscribers-clang

Author: Chris Apple (cjappl)

<details>
<summary>Changes</summary>



This introduces a nice self contained piece

    All interceptors
    All infrastructure "boilerplate" cmake
    All unit tests (no lit tests)
    Minimal meddling in clang, just to get the tests running

Unit tests for this RUN which I think is what makes this a great chunk.


---

Patch is 70.54 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/91529.diff


30 Files Affected:

- (modified) clang/include/clang/Basic/Sanitizers.def (+3) 
- (modified) clang/include/clang/Driver/SanitizerArgs.h (+1) 
- (modified) clang/lib/Driver/ToolChains/CommonArgs.cpp (+6) 
- (modified) clang/lib/Driver/ToolChains/Darwin.cpp (+8) 
- (modified) clang/lib/Driver/ToolChains/Linux.cpp (+1) 
- (modified) clang/runtime/CMakeLists.txt (+1) 
- (modified) compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake (+3) 
- (modified) compiler-rt/cmake/config-ix.cmake (+11-1) 
- (added) compiler-rt/lib/radsan/CMakeLists.txt (+92) 
- (added) compiler-rt/lib/radsan/radsan.cpp (+38) 
- (added) compiler-rt/lib/radsan/radsan.h (+76) 
- (added) compiler-rt/lib/radsan/radsan_context.cpp (+82) 
- (added) compiler-rt/lib/radsan/radsan_context.h (+38) 
- (added) compiler-rt/lib/radsan/radsan_interceptors.cpp (+412) 
- (added) compiler-rt/lib/radsan/radsan_interceptors.h (+15) 
- (added) compiler-rt/lib/radsan/radsan_preinit.cpp (+23) 
- (added) compiler-rt/lib/radsan/radsan_stack.cpp (+52) 
- (added) compiler-rt/lib/radsan/radsan_stack.h (+15) 
- (added) compiler-rt/lib/radsan/tests/CMakeLists.txt (+103) 
- (added) compiler-rt/lib/radsan/tests/radsan_test.cpp (+203) 
- (added) compiler-rt/lib/radsan/tests/radsan_test_context.cpp (+69) 
- (added) compiler-rt/lib/radsan/tests/radsan_test_interceptors.cpp (+454) 
- (added) compiler-rt/lib/radsan/tests/radsan_test_main.cpp (+17) 
- (added) compiler-rt/lib/radsan/tests/radsan_test_utilities.h (+49) 
- (added) compiler-rt/test/radsan/CMakeLists.txt (+47) 
- (added) compiler-rt/test/radsan/Unit/lit.site.cfg.py.in (+25) 
- (added) compiler-rt/test/radsan/lit.cfg.py (+69) 
- (added) compiler-rt/test/radsan/lit.site.cfg.py.in (+17) 
- (modified) compiler-rt/test/sanitizer_common/CMakeLists.txt (+1-1) 
- (modified) compiler-rt/test/sanitizer_common/lit.common.cfg.py (+3) 


``````````diff
diff --git a/clang/include/clang/Basic/Sanitizers.def b/clang/include/clang/Basic/Sanitizers.def
index b228ffd07ee74..ffb23974fe371 100644
--- a/clang/include/clang/Basic/Sanitizers.def
+++ b/clang/include/clang/Basic/Sanitizers.def
@@ -37,6 +37,9 @@
 #endif
 
 
+// RealtimeSanitizer
+SANITIZER("realtime", Realtime)
+
 // AddressSanitizer
 SANITIZER("address", Address)
 
diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h
index 07070ec4fc065..dd7c128232772 100644
--- a/clang/include/clang/Driver/SanitizerArgs.h
+++ b/clang/include/clang/Driver/SanitizerArgs.h
@@ -79,6 +79,7 @@ class SanitizerArgs {
   bool needsStableAbi() const { return StableABI; }
 
   bool needsMemProfRt() const { return NeedsMemProfRt; }
+  bool needsRadsanRt() const { return Sanitizers.has(SanitizerKind::Realtime); }
   bool needsAsanRt() const { return Sanitizers.has(SanitizerKind::Address); }
   bool needsHwasanRt() const {
     return Sanitizers.has(SanitizerKind::HWAddress);
diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp
index 6796b43a15502..6508c4ca690b5 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -1357,6 +1357,8 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
       if (!Args.hasArg(options::OPT_shared))
         HelperStaticRuntimes.push_back("hwasan-preinit");
     }
+    if (SanArgs.needsRadsanRt() && SanArgs.linkRuntimes())
+      SharedRuntimes.push_back("radsan");
   }
 
   // The stats_client library is also statically linked into DSOs.
@@ -1382,6 +1384,10 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
       StaticRuntimes.push_back("asan_cxx");
   }
 
+  if (!SanArgs.needsSharedRt() && SanArgs.needsRadsanRt() && SanArgs.linkRuntimes()) {
+    StaticRuntimes.push_back("radsan");
+  }
+
   if (!SanArgs.needsSharedRt() && SanArgs.needsMemProfRt()) {
     StaticRuntimes.push_back("memprof");
     if (SanArgs.linkCXXRuntimes())
diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp
index caf6c4a444fdc..cb96f9992ab7f 100644
--- a/clang/lib/Driver/ToolChains/Darwin.cpp
+++ b/clang/lib/Driver/ToolChains/Darwin.cpp
@@ -1487,6 +1487,8 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
     const char *sanitizer = nullptr;
     if (Sanitize.needsUbsanRt()) {
       sanitizer = "UndefinedBehaviorSanitizer";
+    } else if (Sanitize.needsRadsanRt()) {
+      sanitizer = "RealtimeSanitizer";
     } else if (Sanitize.needsAsanRt()) {
       sanitizer = "AddressSanitizer";
     } else if (Sanitize.needsTsanRt()) {
@@ -1509,6 +1511,11 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
         AddLinkSanitizerLibArgs(Args, CmdArgs, "asan");
       }
     }
+    if(Sanitize.needsRadsanRt())
+    {
+      assert(Sanitize.needsSharedRt() && "Static sanitizer runtimes not supported");
+      AddLinkSanitizerLibArgs(Args, CmdArgs, "radsan");
+    }
     if (Sanitize.needsLsanRt())
       AddLinkSanitizerLibArgs(Args, CmdArgs, "lsan");
     if (Sanitize.needsUbsanRt()) {
@@ -3393,6 +3400,7 @@ SanitizerMask Darwin::getSupportedSanitizers() const {
   const bool IsAArch64 = getTriple().getArch() == llvm::Triple::aarch64;
   SanitizerMask Res = ToolChain::getSupportedSanitizers();
   Res |= SanitizerKind::Address;
+  Res |= SanitizerKind::Realtime;
   Res |= SanitizerKind::PointerCompare;
   Res |= SanitizerKind::PointerSubtract;
   Res |= SanitizerKind::Leak;
diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp
index db2c20d7b461d..416d530a36ff7 100644
--- a/clang/lib/Driver/ToolChains/Linux.cpp
+++ b/clang/lib/Driver/ToolChains/Linux.cpp
@@ -799,6 +799,7 @@ SanitizerMask Linux::getSupportedSanitizers() const {
   const bool IsHexagon = getTriple().getArch() == llvm::Triple::hexagon;
   SanitizerMask Res = ToolChain::getSupportedSanitizers();
   Res |= SanitizerKind::Address;
+  Res |= SanitizerKind::Realtime;
   Res |= SanitizerKind::PointerCompare;
   Res |= SanitizerKind::PointerSubtract;
   Res |= SanitizerKind::Fuzzer;
diff --git a/clang/runtime/CMakeLists.txt b/clang/runtime/CMakeLists.txt
index 65fcdc2868f03..c56bff11d476b 100644
--- a/clang/runtime/CMakeLists.txt
+++ b/clang/runtime/CMakeLists.txt
@@ -150,6 +150,7 @@ if(LLVM_BUILD_EXTERNAL_COMPILER_RT AND EXISTS ${COMPILER_RT_SRC_ROOT}/)
         check-lsan
         check-msan
         check-profile
+        check-radsan
         check-safestack
         check-sanitizer
         check-tsan
diff --git a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
index 2fe06273a814c..5017d236c1369 100644
--- a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
+++ b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
@@ -32,6 +32,9 @@ set(ALL_ASAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${RISCV64}
     ${LOONGARCH64})
 set(ALL_ASAN_ABI_SUPPORTED_ARCH ${X86_64} ${ARM64} ${ARM64_32})
 set(ALL_DFSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${LOONGARCH64})
+set(ALL_RADSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${RISCV64}
+    ${MIPS32} ${MIPS64} ${PPC64} ${S390X} ${SPARC} ${SPARCV9} ${HEXAGON}
+    ${LOONGARCH64})
 
 if(ANDROID)
   set(OS_NAME "Android")
diff --git a/compiler-rt/cmake/config-ix.cmake b/compiler-rt/cmake/config-ix.cmake
index ba740af9e1d60..9b758227d97cb 100644
--- a/compiler-rt/cmake/config-ix.cmake
+++ b/compiler-rt/cmake/config-ix.cmake
@@ -611,6 +611,9 @@ if(APPLE)
   list_intersect(ASAN_SUPPORTED_ARCH
     ALL_ASAN_SUPPORTED_ARCH
     SANITIZER_COMMON_SUPPORTED_ARCH)
+  list_intersect(RADSAN_SUPPORTED_ARCH
+    ALL_RADSAN_SUPPORTED_ARCH
+    SANITIZER_COMMON_SUPPORTED_ARCH)
   list_intersect(DFSAN_SUPPORTED_ARCH
     ALL_DFSAN_SUPPORTED_ARCH
     SANITIZER_COMMON_SUPPORTED_ARCH)
@@ -674,6 +677,7 @@ else()
   filter_available_targets(UBSAN_COMMON_SUPPORTED_ARCH
     ${SANITIZER_COMMON_SUPPORTED_ARCH})
   filter_available_targets(ASAN_SUPPORTED_ARCH ${ALL_ASAN_SUPPORTED_ARCH})
+  filter_available_targets(RADSAN_SUPPORTED_ARCH ${ALL_RADSAN_SUPPORTED_ARCH})
   filter_available_targets(FUZZER_SUPPORTED_ARCH ${ALL_FUZZER_SUPPORTED_ARCH})
   filter_available_targets(DFSAN_SUPPORTED_ARCH ${ALL_DFSAN_SUPPORTED_ARCH})
   filter_available_targets(LSAN_SUPPORTED_ARCH ${ALL_LSAN_SUPPORTED_ARCH})
@@ -726,7 +730,7 @@ if(COMPILER_RT_SUPPORTED_ARCH)
 endif()
 message(STATUS "Compiler-RT supported architectures: ${COMPILER_RT_SUPPORTED_ARCH}")
 
-set(ALL_SANITIZERS asan;dfsan;msan;hwasan;tsan;safestack;cfi;scudo_standalone;ubsan_minimal;gwp_asan;asan_abi)
+set(ALL_SANITIZERS asan;radsan;dfsan;msan;hwasan;tsan;safestack;cfi;scudo_standalone;ubsan_minimal;gwp_asan;asan_abi)
 set(COMPILER_RT_SANITIZERS_TO_BUILD all CACHE STRING
     "sanitizers to build if supported on the target (all;${ALL_SANITIZERS})")
 list_replace(COMPILER_RT_SANITIZERS_TO_BUILD all "${ALL_SANITIZERS}")
@@ -757,6 +761,12 @@ else()
   set(COMPILER_RT_HAS_ASAN FALSE)
 endif()
 
+if (COMPILER_RT_HAS_SANITIZER_COMMON AND RADSAN_SUPPORTED_ARCH)
+  set(COMPILER_RT_HAS_RADSAN TRUE)
+else()
+  set(COMPILER_RT_HAS_RADSAN FALSE)
+endif()
+
 if (OS_NAME MATCHES "Linux|FreeBSD|Windows|NetBSD|SunOS")
   set(COMPILER_RT_ASAN_HAS_STATIC_RUNTIME TRUE)
 else()
diff --git a/compiler-rt/lib/radsan/CMakeLists.txt b/compiler-rt/lib/radsan/CMakeLists.txt
new file mode 100644
index 0000000000000..c7d1dacf3dbc7
--- /dev/null
+++ b/compiler-rt/lib/radsan/CMakeLists.txt
@@ -0,0 +1,92 @@
+include_directories(..)
+
+set(RADSAN_CXX_SOURCES
+  radsan.cpp
+  radsan_context.cpp
+  radsan_stack.cpp
+  radsan_interceptors.cpp)
+
+set(RADSAN_PREINIT_SOURCES
+  radsan_preinit.cpp)
+
+set(RADSAN_HEADERS
+  radsan.h
+  radsan_context.h
+  radsan_stack.h)
+
+set(RADSAN_DEPS)
+
+set(RADSAN_CFLAGS
+  ${COMPILER_RT_COMMON_CFLAGS}
+  ${COMPILER_RT_CXX_CFLAGS}
+  -DSANITIZER_COMMON_NO_REDEFINE_BUILTINS)
+set(RADSAN_LINK_FLAGS ${COMPILER_RT_COMMON_LINK_FLAGS})
+set(RADSAN_LINK_LIBS
+  ${COMPILER_RT_UNWINDER_LINK_LIBS}
+  ${COMPILER_RT_CXX_LINK_LIBS})
+
+if(APPLE)
+  add_compiler_rt_object_libraries(RTRadsan
+    OS ${SANITIZER_COMMON_SUPPORTED_OS}
+    ARCHS ${RADSAN_SUPPORTED_ARCH}
+    SOURCES ${RADSAN_CXX_SOURCES}
+    ADDITIONAL_HEADERS ${RADSAN_HEADERS}
+    CFLAGS ${RADSAN_CFLAGS}
+    DEPS ${RADSAN_DEPS})
+else()
+  add_compiler_rt_object_libraries(RTRadsan
+    ARCHS ${RADSAN_SUPPORTED_ARCH}
+    SOURCES ${RADSAN_CXX_SOURCES}
+    ADDITIONAL_HEADERS ${RADSAN_HEADERS}
+    CFLAGS ${RADSAN_CFLAGS}
+    DEPS ${RADSAN_DEPS})
+  add_compiler_rt_object_libraries(RTRadsan_preinit
+    ARCHS ${RADSAN_SUPPORTED_ARCH}
+    SOURCES ${RADSAN_PREINIT_SOURCES}
+    ADDITIONAL_HEADERS ${RADSAN_HEADERS}
+    CFLAGS ${RADSAN_CFLAGS})
+endif()
+
+set(RADSAN_COMMON_RUNTIME_OBJECT_LIBS
+  RTInterception
+  RTSanitizerCommon
+  RTSanitizerCommonLibc
+  RTSanitizerCommonCoverage
+  RTSanitizerCommonSymbolizer)
+
+append_list_if(COMPILER_RT_HAS_LIBDL dl RADSAN_LINK_LIBS)
+append_list_if(COMPILER_RT_HAS_LIBRT rt RADSAN_LINK_LIBS)
+append_list_if(COMPILER_RT_HAS_LIBM m RADSAN_LINK_LIBS)
+append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread RADSAN_LINK_LIBS)
+append_list_if(COMPILER_RT_HAS_LIBLOG log RADSAN_LINK_LIBS)
+
+add_compiler_rt_component(radsan)
+
+if (APPLE)
+  add_weak_symbols("sanitizer_common" WEAK_SYMBOL_LINK_FLAGS)
+  set(RADSAN_LINK_FLAGS ${RADSAN_LINK_FLAGS} ${WEAK_SYMBOL_LINK_FLAGS})
+
+  add_compiler_rt_runtime(clang_rt.radsan
+    SHARED
+    OS ${SANITIZER_COMMON_SUPPORTED_OS}
+    ARCHS ${RADSAN_SUPPORTED_ARCH}
+    OBJECT_LIBS RTRadsan
+                ${RADSAN_COMMON_RUNTIME_OBJECT_LIBS}
+    LINK_FLAGS ${RADSAN_LINK_FLAGS}
+    LINK_LIBS ${RADSAN_LINK_LIBS}
+    PARENT_TARGET radsan)
+else()
+  add_compiler_rt_runtime(clang_rt.radsan
+    STATIC
+    ARCHS ${RADSAN_SUPPORTED_ARCH}
+    OBJECT_LIBS RTRadsan_preinit
+                RTRadsan
+                ${RADSAN_COMMON_RUNTIME_OBJECT_LIBS}
+    LINK_FLAGS ${RADSAN_LINK_FLAGS}
+    CFLAGS ${RADSAN_CFLAGS}
+    PARENT_TARGET radsan)
+endif()
+
+if(COMPILER_RT_INCLUDE_TESTS)
+  add_subdirectory(tests)
+endif()
diff --git a/compiler-rt/lib/radsan/radsan.cpp b/compiler-rt/lib/radsan/radsan.cpp
new file mode 100644
index 0000000000000..dbe787ea6f6e4
--- /dev/null
+++ b/compiler-rt/lib/radsan/radsan.cpp
@@ -0,0 +1,38 @@
+//===--- radsan.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
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+#include <radsan/radsan.h>
+#include <radsan/radsan_context.h>
+#include <radsan/radsan_interceptors.h>
+#include <unistd.h>
+
+extern "C" {
+
+SANITIZER_INTERFACE_ATTRIBUTE void radsan_init() { 
+  radsan::InitializeInterceptors(); 
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE void radsan_realtime_enter() {
+  radsan::GetContextForThisThread().RealtimePush();
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE void radsan_realtime_exit() {
+  radsan::GetContextForThisThread().RealtimePop();
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE void radsan_off() {
+  radsan::GetContextForThisThread().BypassPush();
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE void radsan_on() {
+  radsan::GetContextForThisThread().BypassPop();
+}
+
+} // extern "C"
diff --git a/compiler-rt/lib/radsan/radsan.h b/compiler-rt/lib/radsan/radsan.h
new file mode 100644
index 0000000000000..61205e93e29ed
--- /dev/null
+++ b/compiler-rt/lib/radsan/radsan.h
@@ -0,0 +1,76 @@
+//===--- radsan.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
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+#pragma once
+
+#include "sanitizer_common/sanitizer_internal_defs.h"
+
+extern "C" {
+
+/**
+    Initialise radsan interceptors. A call to this method is added to the
+    preinit array on Linux systems.
+
+    @warning Do not call this method as a user.
+*/
+SANITIZER_INTERFACE_ATTRIBUTE void radsan_init();
+
+/** Enter real-time context.
+
+    When in a real-time context, RADSan interceptors will error if realtime
+    violations are detected. Calls to this method are injected at the code
+    generation stage when RADSan is enabled.
+
+    @warning Do not call this method as a user
+*/
+SANITIZER_INTERFACE_ATTRIBUTE void radsan_realtime_enter();
+
+/** Exit the real-time context.
+
+    When not in a real-time context, RADSan interceptors will simply forward
+    intercepted method calls to the real methods.
+
+    @warning Do not call this method as a user
+*/
+SANITIZER_INTERFACE_ATTRIBUTE void radsan_realtime_exit();
+
+/** Disable all RADSan error reporting.
+
+    This method might be useful to you if RADSan is presenting you with an error
+    for some code you are confident is realtime safe. For example, you might
+    know that a mutex is never contested, and that locking it will never block
+    on your particular system. Be careful!
+
+    A call to `radsan_off()` MUST be paired with a corresponding `radsan_on()`
+    to reactivate interception after the code in question. If you don't, radsan
+    will cease to work.
+
+    Example:
+
+        float process (float x) [[clang::nonblocking]] 
+        {
+            auto const y = 2.0f * x;
+
+            radsan_off();
+            i_know_this_method_is_realtime_safe_but_radsan_complains_about_it();
+            radsan_on();
+        }
+
+*/
+SANITIZER_INTERFACE_ATTRIBUTE void radsan_off();
+
+/** Re-enable all RADSan error reporting.
+
+    The counterpart to `radsan_off`. See the description for `radsan_off` for
+    details about how to use this method.
+*/
+SANITIZER_INTERFACE_ATTRIBUTE void radsan_on();
+
+} // extern "C"
diff --git a/compiler-rt/lib/radsan/radsan_context.cpp b/compiler-rt/lib/radsan/radsan_context.cpp
new file mode 100644
index 0000000000000..16fdf967ff4d8
--- /dev/null
+++ b/compiler-rt/lib/radsan/radsan_context.cpp
@@ -0,0 +1,82 @@
+//===--- radsan_context.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
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+#include <radsan/radsan_context.h>
+
+#include <radsan/radsan_stack.h>
+
+#include <sanitizer_common/sanitizer_allocator_internal.h>
+#include <sanitizer_common/sanitizer_stacktrace.h>
+
+#include <new>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+using namespace __sanitizer;
+
+namespace detail {
+
+static pthread_key_t Key;
+static pthread_once_t KeyOnce = PTHREAD_ONCE_INIT;
+void internalFree(void *Ptr) { __sanitizer::InternalFree(Ptr); }
+
+} // namespace detail
+
+namespace radsan {
+
+Context::Context() = default;
+
+void Context::RealtimePush() { RealtimeDepth++; }
+
+void Context::RealtimePop() { RealtimeDepth--; }
+
+void Context::BypassPush() { BypassDepth++; }
+
+void Context::BypassPop() { BypassDepth--; }
+
+void Context::ExpectNotRealtime(const char *InterceptedFunctionName) {
+  if (InRealtimeContext() && !IsBypassed()) {
+    BypassPush();
+    PrintDiagnostics(InterceptedFunctionName);
+    exit(EXIT_FAILURE);
+    BypassPop();
+  }
+}
+
+bool Context::InRealtimeContext() const { return RealtimeDepth > 0; }
+
+bool Context::IsBypassed() const { return BypassDepth > 0; }
+
+void Context::PrintDiagnostics(const char *InterceptedFunctionName) {
+  fprintf(stderr,
+          "Real-time violation: intercepted call to real-time unsafe function "
+          "`%s` in real-time context! Stack trace:\n",
+          InterceptedFunctionName);
+  radsan::PrintStackTrace();
+}
+
+Context &GetContextForThisThread() {
+  auto MakeTlsKey = []() {
+    CHECK_EQ(pthread_key_create(&detail::Key, detail::internalFree), 0);
+  };
+
+  pthread_once(&detail::KeyOnce, MakeTlsKey);
+  Context *CurrentThreadContext = static_cast<Context *>(pthread_getspecific(detail::Key));
+  if (CurrentThreadContext == nullptr) {
+    CurrentThreadContext = static_cast<Context *>(InternalAlloc(sizeof(Context)));
+    new(CurrentThreadContext) Context();
+    pthread_setspecific(detail::Key, CurrentThreadContext);
+  }
+
+  return *CurrentThreadContext;
+}
+
+} // namespace radsan
diff --git a/compiler-rt/lib/radsan/radsan_context.h b/compiler-rt/lib/radsan/radsan_context.h
new file mode 100644
index 0000000000000..6f8f937ca0739
--- /dev/null
+++ b/compiler-rt/lib/radsan/radsan_context.h
@@ -0,0 +1,38 @@
+//===--- radsan_context.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
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+#pragma once
+
+namespace radsan {
+
+class Context {
+public:
+  Context();
+
+  void RealtimePush();
+  void RealtimePop();
+
+  void BypassPush();
+  void BypassPop();
+
+  void ExpectNotRealtime(const char *InterceptedFunctionName);
+
+private:
+  bool InRealtimeContext() const;
+  bool IsBypassed() const;
+  void PrintDiagnostics(const char *InterceptedFunctionName);
+
+  int RealtimeDepth{0};
+  int BypassDepth{0};
+};
+
+Context &GetContextForThisThread();
+
+} // namespace radsan
diff --git a/compiler-rt/lib/radsan/radsan_interceptors.cpp b/compiler-rt/lib/radsan/radsan_interceptors.cpp
new file mode 100644
index 0000000000000..f7fd005aa004d
--- /dev/null
+++ b/compiler-rt/lib/radsan/radsan_interceptors.cpp
@@ -0,0 +1,412 @@
+//===--- radsan_interceptors.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
+//
+//===----------------------------------------------------------------------===//
+//
+//===----------------------------------------------------------------------===//
+
+#include "radsan/radsan_interceptors.h"
+
+#include "sanitizer_common/sanitizer_platform.h"
+#include "sanitizer_common/sanitizer_platform_interceptors.h"
+
+#include "interception/interception.h"
+#include "radsan/radsan_context.h"
+
+#if !SANITIZER_LINUX && !SANITIZER_APPLE
+#error Sorry, radsan does not yet support this platform
+#endif
+
+#if SANITIZER_APPLE
+#include <libkern/OSAtomic.h>
+#include <os/lock.h>
+#endif
+
+#if SANITIZER_INTERCEPT_MEMALIGN || SANITIZER_INTERCEPT_PVALLOC
+#include <malloc.h>
+#endif
+
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <time.h>
+#include <unistd.h>
+
+using namespace __sanitizer;
+
+namespace radsan {
+void ExpectNotRealtime(const char *InterceptedFunctionName) {
+  GetContextForThisThread().ExpectNotRealtime(InterceptedFunctionName);
+}
+} // namespace radsan
+
+/*
+    Filesystem
+*/
+
+INTERCEPTOR(int, open, const char *path, int oflag, ...) {
+  // TODO Establish whether we should intercept here if the flag contains
+  // O_NONBLOCK
+  radsan::ExpectNotRealtime("open");
+  va_list args;
+  va_start(args, oflag);
+  const int result = REAL(open)(path, oflag, args);
+  va_end(args);
+  return result;
+}
+
+INTERCEPTOR(int, openat, int fd, const char *path, int oflag, ...) {
+  // TODO Establish whether we should intercept here if the flag contains
+  // O_NONBLOCK
+  radsan::ExpectNotRealtime("openat");
+  va_list args;
+  va_start(args, oflag);
+  const int result = REAL(openat)(fd, path, oflag, args);
+  va_end(args);
+  return result;
+}
+
+INTERCEPTOR(int, creat, const char *path, mode_t ...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/91529


More information about the cfe-commits mailing list