aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKirill Smelkov <kirr@navytux.spb.ru>2012-11-13 00:34:16 +0400
committerKirill Smelkov <kirr@navytux.spb.ru>2012-11-13 22:17:51 +0400
commit646b51833f0397d56f3018a56340098172bde35b (patch)
treef79601eaf9ab8fc270f1982bb3d4761d14a5ef99
parent14c99236da35f393e25d08868126284b687008f7 (diff)
downloadtinycc-646b51833f0397d56f3018a56340098172bde35b.tar.gz
tinycc-646b51833f0397d56f3018a56340098172bde35b.tar.bz2
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
-rw-r--r--lib/bcheck.c7
1 files changed, 7 insertions, 0 deletions
diff --git a/lib/bcheck.c b/lib/bcheck.c
index 48d7606..700ceda 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
}