From eaa94147a822f9c56d5842d6ff601aa39cf05a63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Wed, 2 Sep 2015 15:21:41 +0200 Subject: [PATCH] ralloc: Use __attribute__((destructor)) instead of atexit(3) ... to free the ralloc context at program exit. On Linux, atexit(3) handlers are called when the program exits but also when a library is unloaded. The latter behavior is a Glibc extension. On systems where this extension is not supported, this causes an application to crash when, for instance, a library using ralloc is dlclosed: at program exit, the registered function is no longer in memory. For example, this happens with OpenCL applications using an ICD loader on FreeBSD. __attribute__((destructor)) fixes the problem because such handlers are called when a library is unloaded and when the program exits. --- configure.ac | 1 + src/util/macros.h | 6 ++++++ src/util/ralloc.c | 5 +++-- src/util/ralloc.h | 9 ++++++--- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index 90ba4fe..f4ab843 100644 --- a/configure.ac +++ b/configure.ac @@ -209,6 +209,7 @@ AX_GCC_BUILTIN([__builtin_popcountll]) AX_GCC_BUILTIN([__builtin_unreachable]) AX_GCC_FUNC_ATTRIBUTE([const]) +AX_GCC_FUNC_ATTRIBUTE([destructor]) AX_GCC_FUNC_ATTRIBUTE([flatten]) AX_GCC_FUNC_ATTRIBUTE([format]) AX_GCC_FUNC_ATTRIBUTE([malloc]) diff --git a/src/util/macros.h b/src/util/macros.h index 84e4f18..539aba4 100644 --- a/src/util/macros.h +++ b/src/util/macros.h @@ -114,6 +114,12 @@ do { \ #define ATTRIBUTE_CONST #endif +#ifdef HAVE_FUNC_ATTRIBUTE_DESTRUCTOR +#define DESTRUCTOR __attribute__((destructor)) +#else +#define DESTRUCTOR +#endif + #ifdef HAVE_FUNC_ATTRIBUTE_FLATTEN #define FLATTEN __attribute__((__flatten__)) #else diff --git a/src/util/ralloc.c b/src/util/ralloc.c index 01719c8..09b9524 100644 --- a/src/util/ralloc.c +++ b/src/util/ralloc.c @@ -311,7 +311,7 @@ ralloc_parent(const void *ptr) static void *autofree_context = NULL; -static void +static DESTRUCTOR void autofree(void) { ralloc_free(autofree_context); @@ -322,7 +322,8 @@ ralloc_autofree_context(void) { if (unlikely(autofree_context == NULL)) { autofree_context = ralloc_context(NULL); - atexit(autofree); + /* autofree_context is freed at program exit or library unload in + * autofree() above. */ } return autofree_context; } diff --git a/src/util/ralloc.h b/src/util/ralloc.h index 7587e11..d8c6cc0 100644 --- a/src/util/ralloc.h +++ b/src/util/ralloc.h @@ -249,9 +249,12 @@ void *ralloc_parent(const void *ptr); /** * Return a context whose memory will be automatically freed at program exit. * - * The first call to this function creates a context and registers a handler - * to free it using \c atexit. This may cause trouble if used in a library - * loaded with \c dlopen. + * The first call to this function creates a context. + * + * The context is freed in a function registered with + * \c __attribute__((destructor)). \c atexit is not used for this + * purpose as it would crash when used in a library loaded with + * \c dlopen. */ void *ralloc_autofree_context(void); -- 2.4.6