author | Alberto Bertogli
<albertito@blitiri.com.ar> 2012-08-26 20:56:52 UTC |
committer | Alberto Bertogli
<albertito@blitiri.com.ar> 2012-08-26 21:46:15 UTC |
parent | 2dafdf78fa23c4244def42f28d5bfd78d3a27841 |
preload/posix/Makefile | +4 | -0 |
preload/posix/codegen.c | +19 | -20 |
preload/posix/codegen.h | +19 | -10 |
preload/posix/function_list.in | +0 | -2 |
preload/posix/generate | +2 | -2 |
preload/posix/modules/libc.mm.custom.c | +0 | -113 |
preload/posix/modules/libc.mm.mod | +21 | -0 |
preload/posix/modules/posix.custom.c | +18 | -6 |
diff --git a/preload/posix/Makefile b/preload/posix/Makefile index b2afa58..b269781 100644 --- a/preload/posix/Makefile +++ b/preload/posix/Makefile @@ -60,6 +60,10 @@ $(OBJS): build-flags .c.o: $(NICE_CC) $(ALL_CFLAGS) -c $< -o $@ +# We define _GNU_SOURCE to get RTLD_NEXT if available; on non-GNU +# platforms it should be harmless. +codegen.o: codegen.c + $(NICE_CC) $(ALL_CFLAGS) -D_GNU_SOURCE -c $< -o $@ # some platforms do not have libdl, we only use it if available build-needlibdl: diff --git a/preload/posix/codegen.c b/preload/posix/codegen.c index 177fdcd..691d6f0 100644 --- a/preload/posix/codegen.c +++ b/preload/posix/codegen.c @@ -6,9 +6,6 @@ #include "codegen.h" #include "build-env.h" -/* Dynamically load libc */ -void *_fiu_libc; - /* Recursion counter, per-thread */ int __thread _fiu_called = 0; @@ -18,30 +15,32 @@ int __thread _fiu_called = 0; #warning "Building without using constructor priorities" #endif -void constructor_attr(200) _fiu_init(void) +/* Get a symbol from libc. + * This function is a wrapper around dlsym(libc, ...), that we use to abstract + * away how we get the libc wrapper, because on some platforms there are + * better shortcuts. */ +void *libc_symbol(const char *symbol) { - static int initialized = 0; - - /* When built without constructor priorities, we could be called more - * than once during the initialization phase: one because we're marked - * as a constructor, and another when one of the other constructors - * sees that it doesn't have _fiu_libc set. */ - - printd("_fiu_init() start (%d)\n", initialized); - if (initialized) - goto exit; +#ifdef RTLD_NEXT + return dlsym(RTLD_NEXT, symbol); +#else + /* We don't want to get this over and over again, so we set it once + * and reuse it afterwards. */ + static void *_fiu_libc = NULL; - _fiu_libc = dlopen(LIBC_SONAME, RTLD_NOW); if (_fiu_libc == NULL) { - fprintf(stderr, "Error loading libc: %s\n", dlerror()); - exit(1); + _fiu_libc = dlopen(LIBC_SONAME, RTLD_NOW); + if (_fiu_libc == NULL) { + fprintf(stderr, "Error loading libc: %s\n", dlerror()); + exit(1); + } } - initialized = 1; -exit: - printd("_fiu_init() done\n"); + return dlsym(_fiu_libc, symbol); +#endif } + /* this runs after all function-specific constructors */ static void constructor_attr(250) _fiu_init_final(void) { diff --git a/preload/posix/codegen.h b/preload/posix/codegen.h index 80b3344..efee7bc 100644 --- a/preload/posix/codegen.h +++ b/preload/posix/codegen.h @@ -2,17 +2,15 @@ #ifndef _FIU_CODEGEN #define _FIU_CODEGEN -#include <dlfcn.h> /* dlsym() */ #include <fiu.h> /* fiu_* */ #include <stdlib.h> /* NULL, random() */ -/* Pointer to the dynamically loaded library */ -extern void *_fiu_libc; -void _fiu_init(void); - /* Recursion counter, per-thread */ extern int __thread _fiu_called; +/* Get a symbol from libc */ +void *libc_symbol(const char *symbol); + /* Some compilers support constructor priorities. Since we don't rely on them, * but use them for clarity purposes, use a macro so libfiu builds on systems * where they're not supported. @@ -76,18 +74,20 @@ extern int __thread _fiu_called; */ /* Generates the common top of the wrapped function */ -#define mkwrap_top(RTYPE, NAME, PARAMS, PARAMSN, PARAMST) \ +#define mkwrap_top(RTYPE, NAME, PARAMS, PARAMSN, PARAMST, ON_ERR) \ static RTYPE (*_fiu_orig_##NAME) PARAMS = NULL; \ \ + static int _fiu_in_init_##NAME = 0; \ + \ static void constructor_attr(201) _fiu_init_##NAME(void) \ { \ rec_inc(); \ - \ - if (_fiu_libc == NULL) \ - _fiu_init(); \ + _fiu_in_init_##NAME++; \ \ _fiu_orig_##NAME = (RTYPE (*) PARAMST) \ - dlsym(_fiu_libc, #NAME); \ + libc_symbol(#NAME); \ + \ + _fiu_in_init_##NAME--; \ rec_dec(); \ } \ \ @@ -97,6 +97,15 @@ extern int __thread _fiu_called; int fstatus; \ \ if (_fiu_called) { \ + if (_fiu_orig_##NAME == NULL) { \ + if (_fiu_in_init_##NAME) { \ + printd("fail on init\n"); \ + return ON_ERR; \ + } else { \ + printd("get orig\n"); \ + _fiu_init_##NAME(); \ + } \ + } \ printd("orig\n"); \ return (*_fiu_orig_##NAME) PARAMSN; \ } \ diff --git a/preload/posix/function_list.in b/preload/posix/function_list.in index d82bf59..94e71d5 100644 --- a/preload/posix/function_list.in +++ b/preload/posix/function_list.in @@ -8,8 +8,6 @@ It is not set in stone, although it shouldn't change frequently. Manually written ---------------- -malloc libc/mm/malloc -realloc libc/mm/realloc open posix/io/oc/open diff --git a/preload/posix/generate b/preload/posix/generate index e7aac43..9c93ef6 100755 --- a/preload/posix/generate +++ b/preload/posix/generate @@ -100,9 +100,9 @@ class Function: paramst = ', '.join([i[0] for i in self.params_info]) paramsn = ', '.join([i[1] for i in self.params_info]) - f.write('mkwrap_top(%s, %s, (%s), (%s), (%s))\n' % \ + f.write('mkwrap_top(%s, %s, (%s), (%s), (%s), (%s))\n' % \ (self.ret_type, self.name, self.params, - paramsn, paramst) ) + paramsn, paramst, self.on_error) ) if self.reduce: f.write('mkwrap_body_reduce("%s/reduce", %s)\n' % \ diff --git a/preload/posix/modules/libc.mm.custom.c b/preload/posix/modules/libc.mm.custom.c deleted file mode 100644 index e94dec3..0000000 --- a/preload/posix/modules/libc.mm.custom.c +++ /dev/null @@ -1,113 +0,0 @@ - -/* - * Custom-made wrappers for malloc() and realloc(). - * - * They can't be made generic because, at least on glibc, they're used before - * constructors are called. - * - * We use __malloc_hook, the glibc-specific interface, so this is glibc-only. - */ - -/* We need to include features.h, which in turns defines __GLIBC__. However, - * features.h is glibc-specific and does not exist on other platforms, so we - * can't include it directly or the file won't build. - * Instead, we have to resort to this ugly trick of including limits.h, which - * is standard and we know glibc's implementation includes features.h. - */ -#include <limits.h> - -#ifndef __GLIBC__ - #warning "Not using glibc, so no malloc() wrappers will be available" -#else - -#include "codegen.h" - -#include <malloc.h> - - -/* Original glibc's hooks, saved in our init function */ -static void *(*old_malloc_hook)(size_t, const void *); -static void *(*old_realloc_hook)(void *ptr, size_t size, const void *caller); - -/* Our own hooks, that will replace glibc's */ -static void *fiu_malloc_hook(size_t size, const void *caller); -static void *fiu_realloc_hook(void *ptr, size_t size, const void *caller); - - -/* We are not going to use __malloc_initialize_hook because it would be called - * before our library initialization functions, which include fiu_init(). - * Instead, we will use a constructor just like the other wrappers, but it - * will run after them just to make things tidier (NOT because it is - * necessary). */ - -static void constructor_attr(202) fiu_init_malloc(void) -{ - /* Save original hooks, used in ours to prevent unwanted recursion */ - old_malloc_hook = __malloc_hook; - old_realloc_hook = __realloc_hook; - - __malloc_hook = fiu_malloc_hook; - __realloc_hook = fiu_realloc_hook; -} - - -static void *fiu_malloc_hook(size_t size, const void *caller) -{ - void *r; - int fstatus; - - /* fiu_fail() may call anything */ - rec_inc(); - - /* See __malloc_hook(3) for details */ - __malloc_hook = old_malloc_hook; - - fstatus = fiu_fail("libc/mm/malloc"); - if (fstatus != 0) { - r = NULL; - goto exit; - } - - printd("calling orig\n"); - r = malloc(size); - -exit: - old_malloc_hook = __malloc_hook; - __malloc_hook = fiu_malloc_hook; - - rec_dec(); - return r; -} - - -static void *fiu_realloc_hook(void *ptr, size_t size, const void *caller) -{ - void *r; - int fstatus; - - /* fiu_fail() may call anything */ - rec_inc(); - - /* See __malloc_hook(3) for details */ - __realloc_hook = old_realloc_hook; - - fstatus = fiu_fail("libc/mm/realloc"); - if (fstatus != 0) { - r = NULL; - goto exit; - } - - printd("calling orig\n"); - r = realloc(ptr, size); - -exit: - old_realloc_hook = __realloc_hook; - __realloc_hook = fiu_realloc_hook; - - rec_dec(); - return r; -} - - -#endif // defined __GLIBC__ - diff --git a/preload/posix/modules/libc.mm.mod b/preload/posix/modules/libc.mm.mod new file mode 100644 index 0000000..20f9f04 --- /dev/null +++ b/preload/posix/modules/libc.mm.mod @@ -0,0 +1,21 @@ + +include: <errno.h> +include: <stdlib.h> + +fiu name base: libc/mm/ + + +void *malloc(size_t size); + on error: NULL + valid errnos: ENOMEM + +void *calloc(size_t nmemb, size_t size); + on error: NULL + valid errnos: ENOMEM + +void *realloc(void *ptr, size_t size); + on error: NULL + valid errnos: ENOMEM + +# Note we don't wrap free() as it does not return anything. + diff --git a/preload/posix/modules/posix.custom.c b/preload/posix/modules/posix.custom.c index 1c709cd..959c58b 100644 --- a/preload/posix/modules/posix.custom.c +++ b/preload/posix/modules/posix.custom.c @@ -18,15 +18,17 @@ * of arguments */ static int (*_fiu_orig_open) (const char *pathname, int flags, ...) = NULL; +static int _fiu_in_init_open = 0; + static void constructor_attr(201) _fiu_init_open(void) { rec_inc(); - - if (_fiu_libc == NULL) - _fiu_init(); + _fiu_in_init_open++; _fiu_orig_open = (int (*) (const char *, int, ...)) - dlsym(_fiu_libc, "open"); + libc_symbol("open"); + + _fiu_in_init_open--; rec_dec(); } @@ -56,13 +58,23 @@ int open(const char *pathname, int flags, ...) mode = 0; } + /* Differences from the generated code end here */ + if (_fiu_called) { + if (_fiu_orig_open == NULL) { + if (_fiu_in_init_open) { + printd("fail on init\n"); + return -1; + } else { + printd("get orig\n"); + _fiu_init_open(); + } + } + printd("orig\n"); return (*_fiu_orig_open) (pathname, flags, mode); } - /* Differences from the generated code end here */ - printd("fiu\n"); /* fiu_fail() may call anything */