use malloc hooks to properly catch all mallocs

This commit is contained in:
bellard
2002-01-05 00:41:11 +00:00
parent 9eab1030f7
commit ad28d4c5b0

168
bcheck.c
View File

@ -56,17 +56,29 @@ void __bound_init(void);
void __bound_new_region(void *p, unsigned long size); void __bound_new_region(void *p, unsigned long size);
void __bound_delete_region(void *p); void __bound_delete_region(void *p);
/* currently, tcc cannot compile that because we use GNUC extensions */
#if !defined(__TINYC__)
void *__bound_ptr_add(void *p, int offset) __attribute__((regparm(2))); void *__bound_ptr_add(void *p, int offset) __attribute__((regparm(2)));
char __bound_ptr_indir_b(void *p, int offset) __attribute__((regparm(2))); char __bound_ptr_indir_b(void *p, int offset) __attribute__((regparm(2)));
unsigned char __bound_ptr_indir_ub(void *p, int offset) __attribute__((regparm(2))); unsigned char __bound_ptr_indir_ub(void *p, int offset) __attribute__((regparm(2)));
short __bound_ptr_indir_w(void *p, int offset) __attribute__((regparm(2))); short __bound_ptr_indir_w(void *p, int offset) __attribute__((regparm(2)));
unsigned short __bound_ptr_indir_uw(void *p, int offset) __attribute__((regparm(2))); unsigned short __bound_ptr_indir_uw(void *p, int offset) __attribute__((regparm(2)));
int __bound_ptr_indir_i(void *p, int offset) __attribute((regparm(2))); int __bound_ptr_indir_i(void *p, int offset) __attribute((regparm(2)));
#endif
void *__bound_calloc(size_t nmemb, size_t size); void *__bound_malloc(size_t size, const void *caller);
void *__bound_malloc(size_t size); void *__bound_memalign(size_t size, size_t align, const void *caller);
void __bound_free(void *ptr); void __bound_free(void *ptr, const void *caller);
void *__bound_realloc(void *ptr, size_t size); void *__bound_realloc(void *ptr, size_t size, const void *caller);
static void *libc_malloc(size_t size);
static void libc_free(void *ptr);
static void install_malloc_hooks(void);
static void restore_malloc_hooks(void);
static void *saved_malloc_hook;
static void *saved_free_hook;
static void *saved_realloc_hook;
static void *saved_memalign_hook;
extern char _end; extern char _end;
@ -122,12 +134,15 @@ static void bound_alloc_error(void)
bound_error("not enough memory for bound checking code\n"); bound_error("not enough memory for bound checking code\n");
} }
/* currently, tcc cannot compile that because we use GNUC extensions */
#if !defined(__TINYC__)
/* do: return (p + offset); */ /* do: return (p + offset); */
void *__bound_ptr_add(void *p, int offset) void *__bound_ptr_add(void *p, int offset)
{ {
unsigned long addr = (unsigned long)p; unsigned long addr = (unsigned long)p;
BoundEntry *e; BoundEntry *e;
#ifdef BOUND_DEBUG #if defined(BOUND_DEBUG)
printf("add: 0x%x %d\n", (int)p, offset); printf("add: 0x%x %d\n", (int)p, offset);
#endif #endif
@ -168,6 +183,21 @@ type __bound_ptr_indir_ ## suffix (void *p, int offset) \
return *(type *)(p + offset); \ return *(type *)(p + offset); \
} }
#else
void *__bound_ptr_add(void *p, int offset)
{
return p + offset;
}
#define BOUND_PTR_INDIR(suffix, type) \
type __bound_ptr_indir_ ## suffix (void *p, int offset) \
{ \
return *(type *)(p + offset); \
}
#endif
BOUND_PTR_INDIR(b, char) BOUND_PTR_INDIR(b, char)
BOUND_PTR_INDIR(ub, unsigned char) BOUND_PTR_INDIR(ub, unsigned char)
BOUND_PTR_INDIR(w, short) BOUND_PTR_INDIR(w, short)
@ -179,7 +209,7 @@ static BoundEntry *__bound_new_page(void)
BoundEntry *page; BoundEntry *page;
int i; int i;
page = malloc(sizeof(BoundEntry) * BOUND_T2_SIZE); page = libc_malloc(sizeof(BoundEntry) * BOUND_T2_SIZE);
if (!page) if (!page)
bound_alloc_error(); bound_alloc_error();
for(i=0;i<BOUND_T2_SIZE;i++) { for(i=0;i<BOUND_T2_SIZE;i++) {
@ -196,13 +226,13 @@ static BoundEntry *__bound_new_page(void)
static BoundEntry *bound_new_entry(void) static BoundEntry *bound_new_entry(void)
{ {
BoundEntry *e; BoundEntry *e;
e = malloc(sizeof(BoundEntry)); e = libc_malloc(sizeof(BoundEntry));
return e; return e;
} }
static void bound_free_entry(BoundEntry *e) static void bound_free_entry(BoundEntry *e)
{ {
free(e); libc_free(e);
} }
static inline BoundEntry *get_page(int index) static inline BoundEntry *get_page(int index)
@ -233,7 +263,9 @@ static void mark_invalid(unsigned long addr, unsigned long size)
else else
t2_end = 1 << (BOUND_T1_BITS + BOUND_T2_BITS); t2_end = 1 << (BOUND_T1_BITS + BOUND_T2_BITS);
#if 0
printf("mark_invalid: start = %x %x\n", t2_start, t2_end); printf("mark_invalid: start = %x %x\n", t2_start, t2_end);
#endif
/* first we handle full pages */ /* first we handle full pages */
t1_start = (t2_start + BOUND_T2_SIZE - 1) >> BOUND_T2_BITS; t1_start = (t2_start + BOUND_T2_SIZE - 1) >> BOUND_T2_BITS;
@ -275,8 +307,11 @@ void __bound_init(void)
BoundEntry *page; BoundEntry *page;
unsigned long start, size; unsigned long start, size;
/* save malloc hooks and install bound check hooks */
install_malloc_hooks();
#ifndef BOUND_STATIC #ifndef BOUND_STATIC
__bound_t1 = malloc(BOUND_T1_SIZE * sizeof(BoundEntry *)); __bound_t1 = libc_malloc(BOUND_T1_SIZE * sizeof(BoundEntry *));
if (!__bound_t1) if (!__bound_t1)
bound_alloc_error(); bound_alloc_error();
#endif #endif
@ -300,10 +335,12 @@ void __bound_init(void)
size = BOUND_T23_SIZE; size = BOUND_T23_SIZE;
mark_invalid(start, size); mark_invalid(start, size);
#if !defined(__TINYC__)
/* malloc zone is also marked invalid */ /* malloc zone is also marked invalid */
start = (unsigned long)&_end; start = (unsigned long)&_end;
size = 128 * 0x100000; size = 128 * 0x100000;
mark_invalid(start, size); mark_invalid(start, size);
#endif
} }
static inline void add_region(BoundEntry *e, static inline void add_region(BoundEntry *e,
@ -453,7 +490,7 @@ void __bound_delete_region(void *p)
e = __bound_find_region(e, p); e = __bound_find_region(e, p);
/* test if invalid region */ /* test if invalid region */
if (e->size == EMPTY_SIZE || (unsigned long)p != e->start) if (e->size == EMPTY_SIZE || (unsigned long)p != e->start)
bound_error("deleting invalid region"); bound_error("freeing invalid region");
/* compute the size we put in invalid regions */ /* compute the size we put in invalid regions */
if (e->is_invalid) if (e->is_invalid)
empty_size = INVALID_SIZE; empty_size = INVALID_SIZE;
@ -529,62 +566,109 @@ static unsigned long get_region_size(void *p)
/* patched memory functions */ /* patched memory functions */
static void install_malloc_hooks(void)
{
saved_malloc_hook = __malloc_hook;
saved_free_hook = __free_hook;
saved_realloc_hook = __realloc_hook;
saved_memalign_hook = __memalign_hook;
__malloc_hook = __bound_malloc;
__free_hook = __bound_free;
__realloc_hook = __bound_realloc;
__memalign_hook = __bound_memalign;
}
static void restore_malloc_hooks(void)
{
__malloc_hook = saved_malloc_hook;
__free_hook = saved_free_hook;
__realloc_hook = saved_realloc_hook;
__memalign_hook = saved_memalign_hook;
}
static void *libc_malloc(size_t size)
{
void *ptr;
restore_malloc_hooks();
ptr = malloc(size);
install_malloc_hooks();
return ptr;
}
static void libc_free(void *ptr)
{
restore_malloc_hooks();
free(ptr);
install_malloc_hooks();
}
/* XXX: we should use a malloc which ensure that it is unlikely that /* XXX: we should use a malloc which ensure that it is unlikely that
two malloc'ed data have the same address if 'free' are made in two malloc'ed data have the same address if 'free' are made in
between. */ between. */
void *__bound_malloc(size_t size) void *__bound_malloc(size_t size, const void *caller)
{ {
void *ptr; void *ptr;
/* we allocate one more byte to ensure the regions will be /* we allocate one more byte to ensure the regions will be
separated by at least one byte. With the glibc malloc, it may separated by at least one byte. With the glibc malloc, it may
be in fact not necessary */ be in fact not necessary */
ptr = malloc(size + 1); ptr = libc_malloc(size + 1);
if (!ptr) if (!ptr)
return NULL; return NULL;
__bound_new_region(ptr, size); __bound_new_region(ptr, size);
return ptr; return ptr;
} }
void __bound_free(void *ptr) void *__bound_memalign(size_t size, size_t align, const void *caller)
{
void *ptr;
restore_malloc_hooks();
/* we allocate one more byte to ensure the regions will be
separated by at least one byte. With the glibc malloc, it may
be in fact not necessary */
ptr = memalign(size + 1, align);
install_malloc_hooks();
if (!ptr)
return NULL;
__bound_new_region(ptr, size);
return ptr;
}
void __bound_free(void *ptr, const void *caller)
{ {
if (ptr == NULL) if (ptr == NULL)
return; return;
__bound_delete_region(ptr); __bound_delete_region(ptr);
free(ptr);
libc_free(ptr);
} }
void *__bound_realloc(void *ptr, size_t size) void *__bound_realloc(void *ptr, size_t size, const void *caller)
{ {
void *ptr1; void *ptr1;
int old_size; int old_size;
if (size == 0) { if (size == 0) {
__bound_free(ptr); __bound_free(ptr, caller);
return NULL; return NULL;
} else { } else {
ptr1 = __bound_malloc(size); ptr1 = __bound_malloc(size, caller);
if (ptr == NULL || ptr1 == NULL) if (ptr == NULL || ptr1 == NULL)
return ptr1; return ptr1;
old_size = get_region_size(ptr); old_size = get_region_size(ptr);
if (old_size == EMPTY_SIZE) if (old_size == EMPTY_SIZE)
bound_error("realloc'ing invalid pointer"); bound_error("realloc'ing invalid pointer");
memcpy(ptr1, ptr, old_size); memcpy(ptr1, ptr, old_size);
__bound_free(ptr); __bound_free(ptr, caller);
return ptr1; return ptr1;
} }
} }
void *__bound_calloc(size_t nmemb, size_t size)
{
void *ptr;
size = size * nmemb;
ptr = __bound_malloc(size);
if (!ptr)
return NULL;
memset(ptr, 0, size);
return ptr;
}
#if 0 #if 0
static void bound_dump(void) static void bound_dump(void)
{ {
@ -611,3 +695,29 @@ static void bound_dump(void)
} }
} }
#endif #endif
#if 0
/* resolve check check syms */
typedef struct BCSyms {
char *str;
void *ptr;
} BCSyms;
static BCSyms bcheck_syms[] = {
{ NULL, NULL },
};
#endif
static void *bound_resolve_sym(const char *sym)
{
#if 0
BCSyms *p;
p = bcheck_syms;
while (p->str != NULL) {
if (!strcmp(p->str, sym))
return p->ptr;
p++;
}
#endif
return NULL;
}