From 646b51833f0397d56f3018a56340098172bde35b Mon Sep 17 00:00:00 2001 From: Kirill Smelkov Date: Tue, 13 Nov 2012 00:34:16 +0400 Subject: [PATCH] lib/bcheck: Prevent libc_malloc/libc_free etc from being miscompiled On i386 and gcc-4.7 I found that libc_malloc was miscompiled - look: static void *libc_malloc(size_t size) { void *ptr; restore_malloc_hooks(); // __malloc_hook = saved_malloc_hook ptr = malloc(size); install_malloc_hooks(); // saved_malloc_hook = __malloc_hook, __malloc_hook = __bound_malloc return ptr; } .type libc_malloc, @function libc_malloc: .LFB56: .cfi_startproc pushl %edx .cfi_def_cfa_offset 8 movl %eax, (%esp) call malloc movl $__bound_malloc, __malloc_hook movl $__bound_free, __free_hook movl $__bound_realloc, __realloc_hook movl $__bound_memalign, __memalign_hook popl %ecx .cfi_def_cfa_offset 4 ret Here gcc inlined both restore_malloc_hooks() and install_malloc_hooks() and decided that saved_malloc_hook -> __malloc_hook -> saved_malloc_hook stores are not needed and could be ommitted. Only it did not know __molloc_hook affects malloc()... So add compiler barrier to both install and restore hooks functions and be done with it - the code is now ok: diff --git a/bcheck0.s b/bcheck1.s index 5f50293..4c02a5f 100644 --- a/bcheck0.s +++ b/bcheck1.s @@ -42,8 +42,24 @@ libc_malloc: .cfi_startproc pushl %edx .cfi_def_cfa_offset 8 + movl saved_malloc_hook, %edx + movl %edx, __malloc_hook + movl saved_free_hook, %edx + movl %edx, __free_hook + movl saved_realloc_hook, %edx + movl %edx, __realloc_hook + movl saved_memalign_hook, %edx + movl %edx, __memalign_hook movl %eax, (%esp) call malloc + movl __malloc_hook, %edx + movl %edx, saved_malloc_hook + movl __free_hook, %edx + movl %edx, saved_free_hook + movl __realloc_hook, %edx + movl %edx, saved_realloc_hook + movl __memalign_hook, %edx + movl %edx, saved_memalign_hook movl $__bound_malloc, __malloc_hook movl $__bound_free, __free_hook movl $__bound_realloc, __realloc_hook For barrier I use __asm__ __volatile__ ("": : : "memory") which is used as compiler barrier by Linux kernel, and mentioned in gcc docs and in wikipedia [1]. Without this patch any program compiled with tcc -b crashes in startup because of infinite recursion in libc_malloc. [1] http://en.wikipedia.org/wiki/Memory_ordering#Compiler_memory_barrier --- lib/bcheck.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/bcheck.c b/lib/bcheck.c index 48d76061..700ceda6 100644 --- a/lib/bcheck.c +++ b/lib/bcheck.c @@ -638,6 +638,9 @@ static unsigned long get_region_size(void *p) /* patched memory functions */ +/* force compiler to perform stores coded up to this point */ +#define barrier() __asm__ __volatile__ ("": : : "memory") + static void install_malloc_hooks(void) { #ifdef CONFIG_TCC_MALLOC_HOOKS @@ -649,6 +652,8 @@ static void install_malloc_hooks(void) __free_hook = __bound_free; __realloc_hook = __bound_realloc; __memalign_hook = __bound_memalign; + + barrier(); #endif } @@ -659,6 +664,8 @@ static void restore_malloc_hooks(void) __free_hook = saved_free_hook; __realloc_hook = saved_realloc_hook; __memalign_hook = saved_memalign_hook; + + barrier(); #endif } -- 2.11.4.GIT