Skip to content

Commit b177ac4

Browse files
[compiler-rt][rtsan] Use sanitizer internal allocator during rtsan init to avoid segfault in dlsym (#98679)
Follows #98268 with a fix for a segfault during preinit on `ubuntu:20.04` environments. Previously, `rtsan` was not handling the situation where `dlsym` calls `calloc` during the interceptors initialization, resulting in a call to a function at a null address. @cjappl and I took inspiration from the solution in `nsan`, but we re-used the sanitizer internal allocator instead of our own static buffer. This PR also re-enables the existing non-instrumented `rtsan` tests for `x86_64` and `arm64` architectures. --------- Co-authored-by: Chris Apple <cja-private@pm.me>
1 parent aac3a2a commit b177ac4

File tree

4 files changed

+47
-4
lines changed

4 files changed

+47
-4
lines changed

compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,7 @@ set(ALL_ASAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${RISCV64}
3232
${LOONGARCH64})
3333
set(ALL_ASAN_ABI_SUPPORTED_ARCH ${X86_64} ${ARM64} ${ARM64_32})
3434
set(ALL_DFSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${LOONGARCH64})
35-
#set(ALL_RTSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${RISCV64}
36-
# ${MIPS32} ${MIPS64} ${PPC64} ${S390X} ${SPARC} ${SPARCV9} ${HEXAGON}
37-
# ${LOONGARCH64})
35+
set(ALL_RTSAN_SUPPORTED_ARCH ${X86_64} ${ARM64})
3836

3937
if(ANDROID)
4038
set(OS_NAME "Android")

compiler-rt/lib/rtsan/rtsan.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,23 @@
1212
#include <rtsan/rtsan_context.h>
1313
#include <rtsan/rtsan_interceptors.h>
1414

15+
using namespace __rtsan;
16+
17+
bool __rtsan::rtsan_initialized;
18+
bool __rtsan::rtsan_init_is_running;
19+
1520
extern "C" {
1621

1722
SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_init() {
18-
__rtsan::InitializeInterceptors();
23+
CHECK(!rtsan_init_is_running);
24+
if (rtsan_initialized)
25+
return;
26+
rtsan_init_is_running = true;
27+
28+
InitializeInterceptors();
29+
30+
rtsan_init_is_running = false;
31+
rtsan_initialized = true;
1932
}
2033

2134
SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_realtime_enter() {

compiler-rt/lib/rtsan/rtsan.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@
1414

1515
extern "C" {
1616

17+
namespace __rtsan {
18+
19+
extern bool rtsan_initialized;
20+
extern bool rtsan_init_is_running;
21+
22+
} // namespace __rtsan
23+
1724
// Initialise rtsan interceptors.
1825
// A call to this method is added to the preinit array on Linux systems.
1926
SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_init();

compiler-rt/lib/rtsan/rtsan_interceptors.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,14 @@
1010

1111
#include "rtsan/rtsan_interceptors.h"
1212

13+
#include "interception/interception.h"
14+
#include "sanitizer_common/sanitizer_allocator_dlsym.h"
15+
#include "sanitizer_common/sanitizer_allocator_internal.h"
1316
#include "sanitizer_common/sanitizer_platform.h"
1417
#include "sanitizer_common/sanitizer_platform_interceptors.h"
1518

1619
#include "interception/interception.h"
20+
#include "rtsan/rtsan.h"
1721
#include "rtsan/rtsan_context.h"
1822

1923
#if SANITIZER_APPLE
@@ -35,6 +39,15 @@
3539

3640
using namespace __sanitizer;
3741

42+
using __rtsan::rtsan_init_is_running;
43+
using __rtsan::rtsan_initialized;
44+
45+
namespace {
46+
struct DlsymAlloc : public DlSymAllocator<DlsymAlloc> {
47+
static bool UseImpl() { return !rtsan_initialized; }
48+
};
49+
} // namespace
50+
3851
void ExpectNotRealtime(const char *intercepted_function_name) {
3952
__rtsan::GetContextForThisThread().ExpectNotRealtime(
4053
intercepted_function_name);
@@ -238,23 +251,35 @@ INTERCEPTOR(int, nanosleep, const struct timespec *rqtp,
238251
// Memory
239252

240253
INTERCEPTOR(void *, calloc, SIZE_T num, SIZE_T size) {
254+
if (DlsymAlloc::Use())
255+
return DlsymAlloc::Callocate(num, size);
256+
241257
ExpectNotRealtime("calloc");
242258
return REAL(calloc)(num, size);
243259
}
244260

245261
INTERCEPTOR(void, free, void *ptr) {
262+
if (DlsymAlloc::PointerIsMine(ptr))
263+
return DlsymAlloc::Free(ptr);
264+
246265
if (ptr != NULL) {
247266
ExpectNotRealtime("free");
248267
}
249268
return REAL(free)(ptr);
250269
}
251270

252271
INTERCEPTOR(void *, malloc, SIZE_T size) {
272+
if (DlsymAlloc::Use())
273+
return DlsymAlloc::Allocate(size);
274+
253275
ExpectNotRealtime("malloc");
254276
return REAL(malloc)(size);
255277
}
256278

257279
INTERCEPTOR(void *, realloc, void *ptr, SIZE_T size) {
280+
if (DlsymAlloc::Use() || DlsymAlloc::PointerIsMine(ptr))
281+
return DlsymAlloc::Realloc(ptr, size);
282+
258283
ExpectNotRealtime("realloc");
259284
return REAL(realloc)(ptr, size);
260285
}

0 commit comments

Comments
 (0)