[ASAN] fix startup crash in dlsym for long paths since glibc 2.27
Summary:
Error messages for dlsym used to be stored on the stack, but since
commit 2449ae7b ("ld.so: Introduce struct dl_exception") in glibc 2.27
these are now stored on the heap (and thus use the dlsym alloc pool).
Messages look like "undefined symbol: __isoc99_printf\0/path/to/a.out".
With many missing library functions and long object paths, the pool is
quickly exhausted. Implement a simple mechanism to return freed memory
to the pool (clear it in case it is used for calloc).
Fixes https://github.com/google/sanitizers/issues/957
Reviewed By: vitalybuka
Differential Revision: https://reviews.llvm.org/D47995
llvm-svn: 334703
This commit is contained in:
parent
2e6384038c
commit
1bbab1e558
|
|
@ -31,6 +31,7 @@
|
|||
using namespace __asan; // NOLINT
|
||||
|
||||
static uptr allocated_for_dlsym;
|
||||
static uptr last_dlsym_alloc_size_in_words;
|
||||
static const uptr kDlsymAllocPoolSize = SANITIZER_RTEMS ? 4096 : 1024;
|
||||
static uptr alloc_memory_for_dlsym[kDlsymAllocPoolSize];
|
||||
|
||||
|
|
@ -42,11 +43,25 @@ static INLINE bool IsInDlsymAllocPool(const void *ptr) {
|
|||
static void *AllocateFromLocalPool(uptr size_in_bytes) {
|
||||
uptr size_in_words = RoundUpTo(size_in_bytes, kWordSize) / kWordSize;
|
||||
void *mem = (void*)&alloc_memory_for_dlsym[allocated_for_dlsym];
|
||||
last_dlsym_alloc_size_in_words = size_in_words;
|
||||
allocated_for_dlsym += size_in_words;
|
||||
CHECK_LT(allocated_for_dlsym, kDlsymAllocPoolSize);
|
||||
return mem;
|
||||
}
|
||||
|
||||
static void DeallocateFromLocalPool(const void *ptr) {
|
||||
// Hack: since glibc 2.27, dlsym longer use stack-allocated memory to store
|
||||
// error messages and instead use malloc followed by free. To avoid pool
|
||||
// exhaustion due to long object filenames, handle that special case here.
|
||||
uptr prev_offset = allocated_for_dlsym - last_dlsym_alloc_size_in_words;
|
||||
void *prev_mem = (void*)&alloc_memory_for_dlsym[prev_offset];
|
||||
if (prev_mem == ptr) {
|
||||
REAL(memset)(prev_mem, 0, last_dlsym_alloc_size_in_words * kWordSize);
|
||||
allocated_for_dlsym = prev_offset;
|
||||
last_dlsym_alloc_size_in_words = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int PosixMemalignFromLocalPool(void **memptr, uptr alignment,
|
||||
uptr size_in_bytes) {
|
||||
if (UNLIKELY(!CheckPosixMemalignAlignment(alignment)))
|
||||
|
|
@ -107,8 +122,10 @@ static void *ReallocFromLocalPool(void *ptr, uptr size) {
|
|||
|
||||
INTERCEPTOR(void, free, void *ptr) {
|
||||
GET_STACK_TRACE_FREE;
|
||||
if (UNLIKELY(IsInDlsymAllocPool(ptr)))
|
||||
if (UNLIKELY(IsInDlsymAllocPool(ptr))) {
|
||||
DeallocateFromLocalPool(ptr);
|
||||
return;
|
||||
}
|
||||
asan_free(ptr, &stack, FROM_MALLOC);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
// RUN: mkdir -p %T/a-long-directory-name-to-test-allocations-for-exceptions-in-_dl_lookup_symbol_x-since-glibc-2.27
|
||||
// RUN: %clangxx_asan -g %s -o %T/long-object-path
|
||||
// RUN: %run %T/a-*/../a-*/../a-*/../a-*/../a-*/../a-*/../a-*/../a-*/../long-object-path
|
||||
|
||||
int main(void) {
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in New Issue