[clang] [compiler-rt] [rtsan] Enable RealtimeSanitizer for FreeBSD (PR #125389)

David CARLIER via llvm-commits llvm-commits at lists.llvm.org
Fri Feb 7 05:21:43 PST 2025


https://github.com/devnexen updated https://github.com/llvm/llvm-project/pull/125389

>From e40672e8137c0546b1604795901ccea8b15f7932 Mon Sep 17 00:00:00 2001
From: David Carlier <devnexen at gmail.com>
Date: Sun, 2 Feb 2025 09:36:50 +0000
Subject: [PATCH 1/3] [compiler-rt][rtsan] porting the sanitizer to FreeBSD.

Most of the apple api exceptions also apply to freebsd, however
to create a per-thread realtime context pthread api cannot be used
since freebsd calls calloc in _thr_alloc().
---
 compiler-rt/lib/rtsan/rtsan_context.cpp          | 16 ++++++++++++++++
 .../lib/rtsan/rtsan_interceptors_posix.cpp       |  4 ++--
 .../tests/rtsan_test_interceptors_posix.cpp      |  4 +++-
 3 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/compiler-rt/lib/rtsan/rtsan_context.cpp b/compiler-rt/lib/rtsan/rtsan_context.cpp
index 536d62e81e2fb66..dacc9b6dedf4029 100644
--- a/compiler-rt/lib/rtsan/rtsan_context.cpp
+++ b/compiler-rt/lib/rtsan/rtsan_context.cpp
@@ -19,6 +19,7 @@
 using namespace __sanitizer;
 using namespace __rtsan;
 
+#if !SANITIZER_FREEBSD
 static pthread_key_t context_key;
 static pthread_once_t key_once = PTHREAD_ONCE_INIT;
 
@@ -43,6 +44,21 @@ static __rtsan::Context &GetContextForThisThreadImpl() {
 
   return *current_thread_context;
 }
+#else
+
+// On FreeBSD, pthread api cannot be used as calloc is called under the hood
+// at library initialization time.
+static __thread Context *ctx = nullptr;
+
+static __rtsan::Context &GetContextForThisThreadImpl() {
+  if (ctx == nullptr) {
+    ctx = static_cast<Context *>(MmapOrDie(sizeof(Context), "RtsanContext"));
+    new (ctx) Context();
+  }
+
+  return *ctx;
+}
+#endif
 
 __rtsan::Context::Context() = default;
 
diff --git a/compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp b/compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp
index 83e6cdd4a009410..b76413dc2e462f1 100644
--- a/compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp
+++ b/compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp
@@ -939,7 +939,7 @@ INTERCEPTOR(int, msync, void *addr, size_t length, int flag) {
   return REAL(msync)(addr, length, flag);
 }
 
-#if SANITIZER_APPLE
+#if SANITIZER_APPLE || SANITIZER_FREEBSD
 INTERCEPTOR(int, mincore, const void *addr, size_t length, char *vec) {
 #else
 INTERCEPTOR(int, mincore, void *addr, size_t length, unsigned char *vec) {
@@ -1334,7 +1334,7 @@ INTERCEPTOR(ssize_t, process_vm_writev, pid_t pid,
 // the test. Revisit this in the future, but hopefully intercepting fork/exec is
 // enough to dissuade usage of wait by proxy.
 
-#if SANITIZER_APPLE
+#if SANITIZER_APPLE || SANITIZER_FREEBSD
 #define INT_TYPE_SYSCALL int
 #else
 #define INT_TYPE_SYSCALL long
diff --git a/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors_posix.cpp b/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors_posix.cpp
index 075f5974b7562a8..e5290ababec6685 100644
--- a/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors_posix.cpp
+++ b/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors_posix.cpp
@@ -280,7 +280,7 @@ TEST_F(RtsanOpenedMmapTest, MsyncDiesWhenRealtime) {
 }
 
 TEST_F(RtsanOpenedMmapTest, MincoreDiesWhenRealtime) {
-#if SANITIZER_APPLE
+#if SANITIZER_APPLE || SANITIZER_FREEBSD
   std::vector<char> vec(GetSize() / 1024);
 #else
   std::vector<unsigned char> vec(GetSize() / 1024);
@@ -1539,6 +1539,7 @@ TEST_F(KqueueTest, KeventDiesWhenRealtime) {
   ExpectNonRealtimeSurvival(Func);
 }
 
+#if SANITIZER_APPLE
 TEST_F(KqueueTest, Kevent64DiesWhenRealtime) {
   struct kevent64_s event;
   EV_SET64(&event, 0, EVFILT_READ, EV_ADD, 0, 0, 0, 0, 0);
@@ -1551,6 +1552,7 @@ TEST_F(KqueueTest, Kevent64DiesWhenRealtime) {
   ExpectRealtimeDeath(Func, "kevent64");
   ExpectNonRealtimeSurvival(Func);
 }
+#endif // SANITIZER_APPLE
 #endif // SANITIZER_INTERCEPT_KQUEUE
 
 #if SANITIZER_LINUX

>From 05ad49c3ff4fd185ab0618a1cfd05c2a86f36dcc Mon Sep 17 00:00:00 2001
From: David Carlier <devnexen at gmail.com>
Date: Sun, 2 Feb 2025 09:38:52 +0000
Subject: [PATCH 2/3] freebsd clang frontend update.

---
 clang/lib/Driver/ToolChains/FreeBSD.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/clang/lib/Driver/ToolChains/FreeBSD.cpp b/clang/lib/Driver/ToolChains/FreeBSD.cpp
index a6d859f0ebfec23..baabfabf26267f6 100644
--- a/clang/lib/Driver/ToolChains/FreeBSD.cpp
+++ b/clang/lib/Driver/ToolChains/FreeBSD.cpp
@@ -497,6 +497,7 @@ SanitizerMask FreeBSD::getSupportedSanitizers() const {
   Res |= SanitizerKind::PointerCompare;
   Res |= SanitizerKind::PointerSubtract;
   Res |= SanitizerKind::Vptr;
+  Res |= SanitizerKind::Realtime;
   if (IsAArch64 || IsX86_64 || IsMIPS64) {
     Res |= SanitizerKind::Leak;
     Res |= SanitizerKind::Thread;

>From 49a4564ac7a3e3042178817c407d32086bb543d3 Mon Sep 17 00:00:00 2001
From: David Carlier <devnexen at gmail.com>
Date: Fri, 7 Feb 2025 13:19:37 +0000
Subject: [PATCH 3/3] using pthread api for context creation.

but disabling mmap interception for this platform, which is the root
cause of the previous infinite call recursion.
---
 compiler-rt/cmake/config-ix.cmake                |  4 ++--
 compiler-rt/lib/rtsan/rtsan_context.cpp          | 16 ----------------
 .../lib/rtsan/rtsan_interceptors_posix.cpp       | 16 ++++++++++++++--
 .../tests/rtsan_test_interceptors_posix.cpp      |  4 ++++
 4 files changed, 20 insertions(+), 20 deletions(-)

diff --git a/compiler-rt/cmake/config-ix.cmake b/compiler-rt/cmake/config-ix.cmake
index cf729c3adb1f5f5..b981db24942217f 100644
--- a/compiler-rt/cmake/config-ix.cmake
+++ b/compiler-rt/cmake/config-ix.cmake
@@ -793,7 +793,7 @@ else()
 endif()
 
 if (COMPILER_RT_HAS_SANITIZER_COMMON AND RTSAN_SUPPORTED_ARCH AND
-    OS_NAME MATCHES "Darwin|Linux")
+    OS_NAME MATCHES "Darwin|Linux|FreeBSD")
   set(COMPILER_RT_HAS_RTSAN TRUE)
 else()
   set(COMPILER_RT_HAS_RTSAN FALSE)
@@ -850,7 +850,7 @@ else()
 endif()
 
 if (COMPILER_RT_HAS_SANITIZER_COMMON AND TYSAN_SUPPORTED_ARCH AND
-        OS_NAME MATCHES "Linux|Darwin")
+    OS_NAME MATCHES "Linux|Darwin")
   set(COMPILER_RT_HAS_TYSAN TRUE)
 else()
   set(COMPILER_RT_HAS_TYSAN FALSE)
diff --git a/compiler-rt/lib/rtsan/rtsan_context.cpp b/compiler-rt/lib/rtsan/rtsan_context.cpp
index dacc9b6dedf4029..536d62e81e2fb66 100644
--- a/compiler-rt/lib/rtsan/rtsan_context.cpp
+++ b/compiler-rt/lib/rtsan/rtsan_context.cpp
@@ -19,7 +19,6 @@
 using namespace __sanitizer;
 using namespace __rtsan;
 
-#if !SANITIZER_FREEBSD
 static pthread_key_t context_key;
 static pthread_once_t key_once = PTHREAD_ONCE_INIT;
 
@@ -44,21 +43,6 @@ static __rtsan::Context &GetContextForThisThreadImpl() {
 
   return *current_thread_context;
 }
-#else
-
-// On FreeBSD, pthread api cannot be used as calloc is called under the hood
-// at library initialization time.
-static __thread Context *ctx = nullptr;
-
-static __rtsan::Context &GetContextForThisThreadImpl() {
-  if (ctx == nullptr) {
-    ctx = static_cast<Context *>(MmapOrDie(sizeof(Context), "RtsanContext"));
-    new (ctx) Context();
-  }
-
-  return *ctx;
-}
-#endif
 
 __rtsan::Context::Context() = default;
 
diff --git a/compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp b/compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp
index b76413dc2e462f1..8d4a16edb2ca8b6 100644
--- a/compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp
+++ b/compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp
@@ -864,11 +864,18 @@ INTERCEPTOR(void *, pvalloc, size_t size) {
 #define RTSAN_MAYBE_INTERCEPT_PVALLOC
 #endif
 
+#if !SANITIZER_FREEBSD
+// enabling this interception on freebsd leads to infinite recursion
+// on pthread lib initialization
 INTERCEPTOR(void *, mmap, void *addr, size_t length, int prot, int flags,
             int fd, off_t offset) {
   __rtsan_notify_intercepted_call("mmap");
   return REAL(mmap)(addr, length, prot, flags, fd, offset);
 }
+#define RTSAN_MAYBE_INTERCEPT_MMAP INTERCEPT_FUNCTION(mmap)
+#else
+#define RTSAN_MAYBE_INTERCEPT_MMAP
+#endif // !SANITIZER_FREEBSD
 
 #if SANITIZER_INTERCEPT_MMAP64
 INTERCEPTOR(void *, mmap64, void *addr, size_t length, int prot, int flags,
@@ -907,10 +914,15 @@ INTERCEPTOR(void *, mremap, void *oaddr, size_t olength, size_t nlength,
 #define RTSAN_MAYBE_INTERCEPT_MREMAP
 #endif
 
+#if !SANITIZER_FREEBSD
 INTERCEPTOR(int, munmap, void *addr, size_t length) {
   __rtsan_notify_intercepted_call("munmap");
   return REAL(munmap)(addr, length);
 }
+#define RTSAN_MAYBE_INTERCEPT_MUNMAP INTERCEPT_FUNCTION(munmap)
+#else
+#define RTSAN_MAYBE_INTERCEPT_MUNMAP
+#endif
 
 #if !SANITIZER_APPLE
 INTERCEPTOR(int, madvise, void *addr, size_t length, int flag) {
@@ -1381,10 +1393,10 @@ void __rtsan::InitializeInterceptors() {
   INTERCEPT_FUNCTION(valloc);
   RTSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC;
   INTERCEPT_FUNCTION(posix_memalign);
-  INTERCEPT_FUNCTION(mmap);
+  RTSAN_MAYBE_INTERCEPT_MMAP;
   RTSAN_MAYBE_INTERCEPT_MMAP64;
   RTSAN_MAYBE_INTERCEPT_MREMAP;
-  INTERCEPT_FUNCTION(munmap);
+  RTSAN_MAYBE_INTERCEPT_MUNMAP;
   RTSAN_MAYBE_INTERCEPT_MADVISE;
   RTSAN_MAYBE_INTERCEPT_POSIX_MADVISE;
   INTERCEPT_FUNCTION(mprotect);
diff --git a/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors_posix.cpp b/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors_posix.cpp
index e5290ababec6685..6047a16aa1ff760 100644
--- a/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors_posix.cpp
+++ b/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors_posix.cpp
@@ -188,6 +188,7 @@ TEST(TestRtsanInterceptors, PvallocDiesWhenRealtime) {
 }
 #endif
 
+#if !SANITIZER_FREEBSD
 TEST(TestRtsanInterceptors, MmapDiesWhenRealtime) {
   auto Func = []() {
     void *_ = mmap(nullptr, 8, PROT_READ | PROT_WRITE,
@@ -196,6 +197,7 @@ TEST(TestRtsanInterceptors, MmapDiesWhenRealtime) {
   ExpectRealtimeDeath(Func, MAYBE_APPEND_64("mmap"));
   ExpectNonRealtimeSurvival(Func);
 }
+#endif
 
 #if SANITIZER_LINUX
 TEST(TestRtsanInterceptors, MremapDiesWhenRealtime) {
@@ -207,6 +209,7 @@ TEST(TestRtsanInterceptors, MremapDiesWhenRealtime) {
 }
 #endif
 
+#if !SANITIZER_FREEBSD
 TEST(TestRtsanInterceptors, MunmapDiesWhenRealtime) {
   void *ptr = mmap(nullptr, 8, PROT_READ | PROT_WRITE,
                    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
@@ -216,6 +219,7 @@ TEST(TestRtsanInterceptors, MunmapDiesWhenRealtime) {
   ExpectRealtimeDeath(Func, "munmap");
   ExpectNonRealtimeSurvival(Func);
 }
+#endif
 
 class RtsanOpenedMmapTest : public RtsanFileTest {
 protected:



More information about the llvm-commits mailing list