forked from OSchip/llvm-project
[asan] Correctly release memory allocated during early startup.
Calloc interceptor initially allocates memory from temp buffer (to serve dlsyms called during asan_init). There is a chance that some non-instrumented library (or executable) has allocated memory with calloc before asan_init and got pointer from the same temporary buffer which later caused problems with free. Inspired by https://github.com/google/sanitizers/issues/626 Differential Revision: http://reviews.llvm.org/D14979 llvm-svn: 254395
This commit is contained in:
parent
fe2c0ff942
commit
67a001fd17
|
@ -26,13 +26,25 @@
|
|||
// ---------------------- Replacement functions ---------------- {{{1
|
||||
using namespace __asan; // NOLINT
|
||||
|
||||
static const uptr kCallocPoolSize = 1024;
|
||||
static uptr calloc_memory_for_dlsym[kCallocPoolSize];
|
||||
|
||||
static bool IsInCallocPool(const void *ptr) {
|
||||
sptr off = (sptr)ptr - (sptr)calloc_memory_for_dlsym;
|
||||
return 0 <= off && off < (sptr)kCallocPoolSize;
|
||||
}
|
||||
|
||||
INTERCEPTOR(void, free, void *ptr) {
|
||||
GET_STACK_TRACE_FREE;
|
||||
if (UNLIKELY(IsInCallocPool(ptr)))
|
||||
return;
|
||||
asan_free(ptr, &stack, FROM_MALLOC);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void, cfree, void *ptr) {
|
||||
GET_STACK_TRACE_FREE;
|
||||
if (UNLIKELY(IsInCallocPool(ptr)))
|
||||
return;
|
||||
asan_free(ptr, &stack, FROM_MALLOC);
|
||||
}
|
||||
|
||||
|
@ -44,8 +56,6 @@ INTERCEPTOR(void*, malloc, uptr size) {
|
|||
INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
|
||||
if (UNLIKELY(!asan_inited)) {
|
||||
// Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
|
||||
const uptr kCallocPoolSize = 1024;
|
||||
static uptr calloc_memory_for_dlsym[kCallocPoolSize];
|
||||
static uptr allocated;
|
||||
uptr size_in_words = ((nmemb * size) + kWordSize - 1) / kWordSize;
|
||||
void *mem = (void*)&calloc_memory_for_dlsym[allocated];
|
||||
|
@ -59,6 +69,13 @@ INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
|
|||
|
||||
INTERCEPTOR(void*, realloc, void *ptr, uptr size) {
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
if (UNLIKELY(IsInCallocPool(ptr))) {
|
||||
uptr offset = (uptr)ptr - (uptr)calloc_memory_for_dlsym;
|
||||
uptr copy_size = Min(size, kCallocPoolSize - offset);
|
||||
void *new_ptr = asan_malloc(size, &stack);
|
||||
internal_memcpy(new_ptr, ptr, copy_size);
|
||||
return new_ptr;
|
||||
}
|
||||
return asan_realloc(ptr, size, &stack);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
// Test that initially callocked memory is properly freed
|
||||
// (see https://github.com/google/sanitizers/issues/626).
|
||||
//
|
||||
// RUN: %clang %s -o %t
|
||||
// RUN: env LD_PRELOAD=%shared_libasan %run %t
|
||||
//
|
||||
// REQUIRES: asan-dynamic-runtime
|
||||
//
|
||||
// This way of setting LD_PRELOAD does not work with Android test runner.
|
||||
// REQUIRES: not-android
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static void *ptr;
|
||||
|
||||
// This constructor will run before __asan_init
|
||||
// so calloc will allocate memory from special pool.
|
||||
static void init() {
|
||||
ptr = calloc(10, 1);
|
||||
}
|
||||
|
||||
__attribute__((section(".preinit_array"), used))
|
||||
void *dummy = init;
|
||||
|
||||
void free_memory() {
|
||||
// This used to abort because
|
||||
// Asan's free didn't recognize ptr.
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
int main() {
|
||||
free_memory();
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue