[compiler-rt] [compiler-rt][rtsan] Use sanitizer internal allocator during rtsan init to avoid segfault in dlsym (PR #98679)
Chris Apple via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 18 21:33:19 PDT 2024
https://github.com/cjappl updated https://github.com/llvm/llvm-project/pull/98679
>From 7c85caf090c37ec645196bc13a33a304a2c24a1b Mon Sep 17 00:00:00 2001
From: Chris Apple <cja-private at pm.me>
Date: Fri, 12 Jul 2024 10:06:55 +0200
Subject: [PATCH 1/5] Init check
---
compiler-rt/lib/rtsan/rtsan.cpp | 16 ++++++++-
compiler-rt/lib/rtsan/rtsan.h | 8 +++++
compiler-rt/lib/rtsan/rtsan_interceptors.cpp | 37 ++++++++++++++++++++
3 files changed, 60 insertions(+), 1 deletion(-)
diff --git a/compiler-rt/lib/rtsan/rtsan.cpp b/compiler-rt/lib/rtsan/rtsan.cpp
index 43a63b4636f1e..fae4de12f344d 100644
--- a/compiler-rt/lib/rtsan/rtsan.cpp
+++ b/compiler-rt/lib/rtsan/rtsan.cpp
@@ -12,10 +12,24 @@
#include <rtsan/rtsan_context.h>
#include <rtsan/rtsan_interceptors.h>
+using namespace __rtsan;
+
+bool __rtsan::rtsan_initialized;
+bool __rtsan::rtsan_init_is_running;
+
+
extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_init() {
- __rtsan::InitializeInterceptors();
+ CHECK(!rtsan_init_is_running);
+ if (rtsan_initialized)
+ return;
+ rtsan_init_is_running = true;
+
+ InitializeInterceptors();
+
+ rtsan_init_is_running = false;
+ rtsan_initialized = true;
}
SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_realtime_enter() {
diff --git a/compiler-rt/lib/rtsan/rtsan.h b/compiler-rt/lib/rtsan/rtsan.h
index 8b1219c13cbd3..c2f8c3a917fa4 100644
--- a/compiler-rt/lib/rtsan/rtsan.h
+++ b/compiler-rt/lib/rtsan/rtsan.h
@@ -14,6 +14,14 @@
extern "C" {
+namespace __rtsan {
+
+extern bool rtsan_initialized;
+extern bool rtsan_init_is_running;
+
+} // namespace __rtsan
+
+
// Initialise rtsan interceptors.
// A call to this method is added to the preinit array on Linux systems.
SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_init();
diff --git a/compiler-rt/lib/rtsan/rtsan_interceptors.cpp b/compiler-rt/lib/rtsan/rtsan_interceptors.cpp
index 3a65f9d3f779d..671f7ec8b9f2d 100644
--- a/compiler-rt/lib/rtsan/rtsan_interceptors.cpp
+++ b/compiler-rt/lib/rtsan/rtsan_interceptors.cpp
@@ -14,6 +14,7 @@
#include "sanitizer_common/sanitizer_platform_interceptors.h"
#include "interception/interception.h"
+#include "rtsan/rtsan.h"
#include "rtsan/rtsan_context.h"
#if SANITIZER_APPLE
@@ -35,6 +36,30 @@
using namespace __sanitizer;
+using __rtsan::rtsan_init_is_running;
+using __rtsan::rtsan_initialized;
+
+constexpr uptr kEarlyAllocBufSize = 16384;
+static uptr allocated_bytes;
+static char early_alloc_buf[kEarlyAllocBufSize];
+
+static bool IsInEarlyAllocBuf(const void *ptr) {
+ return ((uptr)ptr >= (uptr)early_alloc_buf &&
+ ((uptr)ptr - (uptr)early_alloc_buf) < sizeof(early_alloc_buf));
+}
+
+template <typename T> T min(T a, T b) { return a < b ? a : b; }
+
+// Handle allocation requests early (before all interceptors are setup). dlsym,
+// for example, calls calloc.
+static void *HandleEarlyAlloc(uptr size) {
+ void *Mem = (void *)&early_alloc_buf[allocated_bytes];
+ allocated_bytes += size;
+ CHECK_LT(allocated_bytes, kEarlyAllocBufSize);
+ return Mem;
+}
+
+
void ExpectNotRealtime(const char *intercepted_function_name) {
__rtsan::GetContextForThisThread().ExpectNotRealtime(
intercepted_function_name);
@@ -238,11 +263,19 @@ INTERCEPTOR(int, nanosleep, const struct timespec *rqtp,
// Memory
INTERCEPTOR(void *, calloc, SIZE_T num, SIZE_T size) {
+ if (rtsan_init_is_running && REAL(calloc) == nullptr) {
+ // Note: EarlyAllocBuf is initialized with zeros.
+ return HandleEarlyAlloc(num * size);
+ }
+
ExpectNotRealtime("calloc");
return REAL(calloc)(num, size);
}
INTERCEPTOR(void, free, void *ptr) {
+ if (IsInEarlyAllocBuf(ptr))
+ return;
+
if (ptr != NULL) {
ExpectNotRealtime("free");
}
@@ -250,6 +283,10 @@ INTERCEPTOR(void, free, void *ptr) {
}
INTERCEPTOR(void *, malloc, SIZE_T size) {
+ if (rtsan_init_is_running && REAL(malloc) == nullptr) {
+ return HandleEarlyAlloc(size);
+ }
+
ExpectNotRealtime("malloc");
return REAL(malloc)(size);
}
>From 23303791dad5ba1126cff10de0f28f7508b17015 Mon Sep 17 00:00:00 2001
From: Chris Apple <cja-private at pm.me>
Date: Fri, 12 Jul 2024 10:37:36 +0200
Subject: [PATCH 2/5] Clang tidy run
---
compiler-rt/lib/rtsan/rtsan.cpp | 1 -
compiler-rt/lib/rtsan/rtsan.h | 1 -
compiler-rt/lib/rtsan/rtsan_interceptors.cpp | 1 -
3 files changed, 3 deletions(-)
diff --git a/compiler-rt/lib/rtsan/rtsan.cpp b/compiler-rt/lib/rtsan/rtsan.cpp
index fae4de12f344d..cf7fbddd9eb9c 100644
--- a/compiler-rt/lib/rtsan/rtsan.cpp
+++ b/compiler-rt/lib/rtsan/rtsan.cpp
@@ -17,7 +17,6 @@ using namespace __rtsan;
bool __rtsan::rtsan_initialized;
bool __rtsan::rtsan_init_is_running;
-
extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_init() {
diff --git a/compiler-rt/lib/rtsan/rtsan.h b/compiler-rt/lib/rtsan/rtsan.h
index c2f8c3a917fa4..ccddaf2c893ef 100644
--- a/compiler-rt/lib/rtsan/rtsan.h
+++ b/compiler-rt/lib/rtsan/rtsan.h
@@ -21,7 +21,6 @@ extern bool rtsan_init_is_running;
} // namespace __rtsan
-
// Initialise rtsan interceptors.
// A call to this method is added to the preinit array on Linux systems.
SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_init();
diff --git a/compiler-rt/lib/rtsan/rtsan_interceptors.cpp b/compiler-rt/lib/rtsan/rtsan_interceptors.cpp
index 671f7ec8b9f2d..800cac189db11 100644
--- a/compiler-rt/lib/rtsan/rtsan_interceptors.cpp
+++ b/compiler-rt/lib/rtsan/rtsan_interceptors.cpp
@@ -59,7 +59,6 @@ static void *HandleEarlyAlloc(uptr size) {
return Mem;
}
-
void ExpectNotRealtime(const char *intercepted_function_name) {
__rtsan::GetContextForThisThread().ExpectNotRealtime(
intercepted_function_name);
>From d885917c7c6d02895988557525ff8fc44ffe9167 Mon Sep 17 00:00:00 2001
From: David Trevelyan <david.trevelyan at gmail.com>
Date: Fri, 12 Jul 2024 13:18:42 +0100
Subject: [PATCH 3/5] Use sanitizer internal allocator during rtsan init
---
compiler-rt/lib/rtsan/rtsan_interceptors.cpp | 39 +++++---------------
1 file changed, 10 insertions(+), 29 deletions(-)
diff --git a/compiler-rt/lib/rtsan/rtsan_interceptors.cpp b/compiler-rt/lib/rtsan/rtsan_interceptors.cpp
index 800cac189db11..f7e75b15ca33e 100644
--- a/compiler-rt/lib/rtsan/rtsan_interceptors.cpp
+++ b/compiler-rt/lib/rtsan/rtsan_interceptors.cpp
@@ -10,6 +10,7 @@
#include "rtsan/rtsan_interceptors.h"
+#include "sanitizer_common/sanitizer_allocator_internal.h"
#include "sanitizer_common/sanitizer_platform.h"
#include "sanitizer_common/sanitizer_platform_interceptors.h"
@@ -39,26 +40,6 @@ using namespace __sanitizer;
using __rtsan::rtsan_init_is_running;
using __rtsan::rtsan_initialized;
-constexpr uptr kEarlyAllocBufSize = 16384;
-static uptr allocated_bytes;
-static char early_alloc_buf[kEarlyAllocBufSize];
-
-static bool IsInEarlyAllocBuf(const void *ptr) {
- return ((uptr)ptr >= (uptr)early_alloc_buf &&
- ((uptr)ptr - (uptr)early_alloc_buf) < sizeof(early_alloc_buf));
-}
-
-template <typename T> T min(T a, T b) { return a < b ? a : b; }
-
-// Handle allocation requests early (before all interceptors are setup). dlsym,
-// for example, calls calloc.
-static void *HandleEarlyAlloc(uptr size) {
- void *Mem = (void *)&early_alloc_buf[allocated_bytes];
- allocated_bytes += size;
- CHECK_LT(allocated_bytes, kEarlyAllocBufSize);
- return Mem;
-}
-
void ExpectNotRealtime(const char *intercepted_function_name) {
__rtsan::GetContextForThisThread().ExpectNotRealtime(
intercepted_function_name);
@@ -262,18 +243,16 @@ INTERCEPTOR(int, nanosleep, const struct timespec *rqtp,
// Memory
INTERCEPTOR(void *, calloc, SIZE_T num, SIZE_T size) {
- if (rtsan_init_is_running && REAL(calloc) == nullptr) {
- // Note: EarlyAllocBuf is initialized with zeros.
- return HandleEarlyAlloc(num * size);
- }
+ if (rtsan_init_is_running && REAL(calloc) == nullptr)
+ return __sanitizer::InternalCalloc(num, size);
ExpectNotRealtime("calloc");
return REAL(calloc)(num, size);
}
INTERCEPTOR(void, free, void *ptr) {
- if (IsInEarlyAllocBuf(ptr))
- return;
+ if (__sanitizer::internal_allocator()->PointerIsMine(ptr))
+ return __sanitizer::InternalFree(ptr);
if (ptr != NULL) {
ExpectNotRealtime("free");
@@ -282,15 +261,17 @@ INTERCEPTOR(void, free, void *ptr) {
}
INTERCEPTOR(void *, malloc, SIZE_T size) {
- if (rtsan_init_is_running && REAL(malloc) == nullptr) {
- return HandleEarlyAlloc(size);
- }
+ if (rtsan_init_is_running && REAL(malloc) == nullptr)
+ return __sanitizer::InternalAlloc(size);
ExpectNotRealtime("malloc");
return REAL(malloc)(size);
}
INTERCEPTOR(void *, realloc, void *ptr, SIZE_T size) {
+ if (rtsan_init_is_running && REAL(realloc) == nullptr)
+ return __sanitizer::InternalRealloc(ptr, size);
+
ExpectNotRealtime("realloc");
return REAL(realloc)(ptr, size);
}
>From 01190d9ca1a67b39d46e687e76680e09f3340d35 Mon Sep 17 00:00:00 2001
From: David Trevelyan <david.trevelyan at gmail.com>
Date: Fri, 12 Jul 2024 19:24:11 +0100
Subject: [PATCH 4/5] Re-enable rtsan tests
---
compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
index 02ff92f693810..29e5beb6182ba 100644
--- a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
+++ b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
@@ -32,9 +32,7 @@ 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_RTSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${RISCV64}
-# ${MIPS32} ${MIPS64} ${PPC64} ${S390X} ${SPARC} ${SPARCV9} ${HEXAGON}
-# ${LOONGARCH64})
+set(ALL_RTSAN_SUPPORTED_ARCH ${X86_64} ${ARM64})
if(ANDROID)
set(OS_NAME "Android")
>From be6d493c9b8002fe75cd3a5947bc9bf28230c8a9 Mon Sep 17 00:00:00 2001
From: Chris Apple <cja-private at pm.me>
Date: Fri, 19 Jul 2024 06:11:11 +0200
Subject: [PATCH 5/5] PR Comments: Introduce dlsym allocator
---
compiler-rt/lib/rtsan/rtsan_interceptors.cpp | 24 +++++++++++++-------
1 file changed, 16 insertions(+), 8 deletions(-)
diff --git a/compiler-rt/lib/rtsan/rtsan_interceptors.cpp b/compiler-rt/lib/rtsan/rtsan_interceptors.cpp
index f7e75b15ca33e..4d5423ec629d2 100644
--- a/compiler-rt/lib/rtsan/rtsan_interceptors.cpp
+++ b/compiler-rt/lib/rtsan/rtsan_interceptors.cpp
@@ -10,6 +10,8 @@
#include "rtsan/rtsan_interceptors.h"
+#include "interception/interception.h"
+#include "sanitizer_common/sanitizer_allocator_dlsym.h"
#include "sanitizer_common/sanitizer_allocator_internal.h"
#include "sanitizer_common/sanitizer_platform.h"
#include "sanitizer_common/sanitizer_platform_interceptors.h"
@@ -40,6 +42,12 @@ using namespace __sanitizer;
using __rtsan::rtsan_init_is_running;
using __rtsan::rtsan_initialized;
+namespace {
+struct DlsymAlloc : public DlSymAllocator<DlsymAlloc> {
+ static bool UseImpl() { return !rtsan_initialized; }
+};
+} // namespace
+
void ExpectNotRealtime(const char *intercepted_function_name) {
__rtsan::GetContextForThisThread().ExpectNotRealtime(
intercepted_function_name);
@@ -243,16 +251,16 @@ INTERCEPTOR(int, nanosleep, const struct timespec *rqtp,
// Memory
INTERCEPTOR(void *, calloc, SIZE_T num, SIZE_T size) {
- if (rtsan_init_is_running && REAL(calloc) == nullptr)
- return __sanitizer::InternalCalloc(num, size);
+ if (DlsymAlloc::Use())
+ return DlsymAlloc::Callocate(num, size);
ExpectNotRealtime("calloc");
return REAL(calloc)(num, size);
}
INTERCEPTOR(void, free, void *ptr) {
- if (__sanitizer::internal_allocator()->PointerIsMine(ptr))
- return __sanitizer::InternalFree(ptr);
+ if (DlsymAlloc::PointerIsMine(ptr))
+ return DlsymAlloc::Free(ptr);
if (ptr != NULL) {
ExpectNotRealtime("free");
@@ -261,16 +269,16 @@ INTERCEPTOR(void, free, void *ptr) {
}
INTERCEPTOR(void *, malloc, SIZE_T size) {
- if (rtsan_init_is_running && REAL(malloc) == nullptr)
- return __sanitizer::InternalAlloc(size);
+ if (DlsymAlloc::Use())
+ return DlsymAlloc::Allocate(size);
ExpectNotRealtime("malloc");
return REAL(malloc)(size);
}
INTERCEPTOR(void *, realloc, void *ptr, SIZE_T size) {
- if (rtsan_init_is_running && REAL(realloc) == nullptr)
- return __sanitizer::InternalRealloc(ptr, size);
+ if (DlsymAlloc::Use() || DlsymAlloc::PointerIsMine(ptr))
+ return DlsymAlloc::Realloc(ptr, size);
ExpectNotRealtime("realloc");
return REAL(realloc)(ptr, size);
More information about the llvm-commits
mailing list