diff --git a/src/thread.c b/src/thread.c index 5eb68e33a..eeb0e04f4 100644 --- a/src/thread.c +++ b/src/thread.c @@ -189,6 +189,27 @@ static int thread_cpus_enabled() return ret; } +/* Depending on the platform and how libpthread was built, pthread_exit() may + * involve some code in libgcc_s that would be loaded on exit for the first + * time, causing aborts if the process is chrooted. It's harmless bit very + * dirty. There isn't much we can do to make sure libgcc_s is loaded only if + * needed, so what we do here is that during early boot we create a dummy + * thread that immediately exits. This will lead to libgcc_s being loaded + * during boot on the platforms where it's required. + */ +static void *dummy_thread_function(void *data) +{ + pthread_exit(NULL); + return NULL; +} + +static inline void preload_libgcc_s(void) +{ + pthread_t dummy_thread; + pthread_create(&dummy_thread, NULL, dummy_thread_function, NULL); + pthread_join(dummy_thread, NULL); +} + __attribute__((constructor)) static void __thread_init(void) { @@ -201,17 +222,7 @@ static void __thread_init(void) exit(1); } -#if defined(__GNUC__) && (__GNUC__ >= 3) && defined(__GNU_LIBRARY__) && !defined(__clang__) - /* make sure libgcc_s is already loaded, because pthread_exit() may - * may need it on exit after the chroot! _Unwind_Find_FDE() is defined - * there since gcc 3.0, has no side effect, doesn't take any argument - * and seems to be present on all supported platforms. - */ - { - extern void _Unwind_Find_FDE(void); - _Unwind_Find_FDE(); - } -#endif + preload_libgcc_s(); thread_cpus_enabled_at_boot = thread_cpus_enabled();