diff options
| author | Peter Wu <peter@lekensteyn.nl> | 2018-06-14 10:42:54 +0000 |
|---|---|---|
| committer | Peter Wu <peter@lekensteyn.nl> | 2018-06-14 10:42:54 +0000 |
| commit | 1bbab1e558523e8a3acce350250fc85819a7ebf3 (patch) | |
| tree | 78afb297c470e7bc68f2b7da1d76d2ecd1173fe8 | |
| parent | 2e6384038cd89ad844deaa2e3e1854c8573ce262 (diff) | |
| download | bcm5719-llvm-1bbab1e558523e8a3acce350250fc85819a7ebf3.tar.gz bcm5719-llvm-1bbab1e558523e8a3acce350250fc85819a7ebf3.zip | |
[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
| -rw-r--r-- | compiler-rt/lib/asan/asan_malloc_linux.cc | 19 | ||||
| -rw-r--r-- | compiler-rt/test/asan/TestCases/long-object-path.cc | 7 |
2 files changed, 25 insertions, 1 deletions
diff --git a/compiler-rt/lib/asan/asan_malloc_linux.cc b/compiler-rt/lib/asan/asan_malloc_linux.cc index 726cc1f4637..7152fe06718 100644 --- a/compiler-rt/lib/asan/asan_malloc_linux.cc +++ b/compiler-rt/lib/asan/asan_malloc_linux.cc @@ -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); } diff --git a/compiler-rt/test/asan/TestCases/long-object-path.cc b/compiler-rt/test/asan/TestCases/long-object-path.cc new file mode 100644 index 00000000000..592b0abb07d --- /dev/null +++ b/compiler-rt/test/asan/TestCases/long-object-path.cc @@ -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; +} |

