diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -4404,12 +4404,16 @@ INTERCEPTOR(int, backtrace, void **buffer, int size) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, backtrace, buffer, size); - // FIXME: under ASan the call below may write to freed memory and corrupt - // its metadata. See - // https://github.com/google/sanitizers/issues/321. - int res = REAL(backtrace)(buffer, size); - if (res && buffer) + // 'buffer' might be freed memory, hence it is unsafe to directly call + // REAL(backtrace)(buffer, size). Instead, we use our own known-good + // scratch buffer. + void **scratch = (void**)InternalAlloc(sizeof(void*) * size); + int res = REAL(backtrace)(scratch, size); + if (res && buffer) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buffer, res * sizeof(*buffer)); + internal_memcpy(buffer, scratch, res * sizeof(*buffer)); + } + InternalFree(scratch); return res; } diff --git a/compiler-rt/test/asan/TestCases/backtrace_interceptor.cpp b/compiler-rt/test/asan/TestCases/backtrace_interceptor.cpp --- a/compiler-rt/test/asan/TestCases/backtrace_interceptor.cpp +++ b/compiler-rt/test/asan/TestCases/backtrace_interceptor.cpp @@ -4,10 +4,6 @@ // restrict the test to glibc. // REQUIRES: glibc-2.27 -// Interceptor can cause use-after-free -// (https://github.com/google/sanitizers/issues/321) -// XFAIL: * - // Test the backtrace() interceptor. #include @@ -23,6 +19,8 @@ assert(buffer != NULL); free(buffer); + // Deliberate use-after-free of 'buffer'. We expect ASan to + // catch this, without triggering internal sanitizer errors. int numEntries = backtrace(buffer, MAX_BT); printf("backtrace returned %d entries\n", numEntries);