Skip to content

Commit

Permalink
[compiler-rt][rtsan] Use sanitizer internal allocator during rtsan in…
Browse files Browse the repository at this point in the history
…it to avoid segfault in dlsym (llvm#98679)

Follows llvm#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>
  • Loading branch information
davidtrevelyan and cjappl committed Jul 22, 2024
1 parent aac3a2a commit b177ac4
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 4 deletions.
4 changes: 1 addition & 3 deletions compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
15 changes: 14 additions & 1 deletion compiler-rt/lib/rtsan/rtsan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,23 @@
#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() {
Expand Down
7 changes: 7 additions & 0 deletions compiler-rt/lib/rtsan/rtsan.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@

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();
Expand Down
25 changes: 25 additions & 0 deletions compiler-rt/lib/rtsan/rtsan_interceptors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,14 @@

#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"

#include "interception/interception.h"
#include "rtsan/rtsan.h"
#include "rtsan/rtsan_context.h"

#if SANITIZER_APPLE
Expand All @@ -35,6 +39,15 @@

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);
Expand Down Expand Up @@ -238,23 +251,35 @@ INTERCEPTOR(int, nanosleep, const struct timespec *rqtp,
// Memory

INTERCEPTOR(void *, calloc, SIZE_T num, SIZE_T size) {
if (DlsymAlloc::Use())
return DlsymAlloc::Callocate(num, size);

ExpectNotRealtime("calloc");
return REAL(calloc)(num, size);
}

INTERCEPTOR(void, free, void *ptr) {
if (DlsymAlloc::PointerIsMine(ptr))
return DlsymAlloc::Free(ptr);

if (ptr != NULL) {
ExpectNotRealtime("free");
}
return REAL(free)(ptr);
}

INTERCEPTOR(void *, malloc, SIZE_T size) {
if (DlsymAlloc::Use())
return DlsymAlloc::Allocate(size);

ExpectNotRealtime("malloc");
return REAL(malloc)(size);
}

INTERCEPTOR(void *, realloc, void *ptr, SIZE_T size) {
if (DlsymAlloc::Use() || DlsymAlloc::PointerIsMine(ptr))
return DlsymAlloc::Realloc(ptr, size);

ExpectNotRealtime("realloc");
return REAL(realloc)(ptr, size);
}
Expand Down

0 comments on commit b177ac4

Please sign in to comment.