From 7c85caf090c37ec645196bc13a33a304a2c24a1b Mon Sep 17 00:00:00 2001 From: Chris Apple 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 #include +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 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 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 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 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 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 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 { + 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);