BUILD: threads: better workaround for late loading of libgcc_s
Commit 77b98220e ("BUG/MINOR: threads: work around a libgcc_s issue with
chrooting") tried to address an issue with libgcc_s being loaded too late.
But it turns out that the symbol used there isn't present on armhf, thus
it breaks the build.
Given that the issue manifests itself during pthread_exit(), the safest
and most portable way to test this is to call pthread_exit(). For this
we create a dummy thread which exits, during the early boot. This results
in the relevant library to be loaded if needed, making sure that a later
call to pthread_exit() will still work. It was tested to work fine under
linux on the following platforms:
glibc:
- armhf
- aarch64
- x86_64
- sparc64
- ppc64le
musl:
- mipsel
Just running the code under strace easily shows the call in the dummy
thread, for example here on armhf:
$ strace -fe trace=file ./haproxy -v 2>&1 | grep gcc_s
[pid 23055] open("/lib/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = 3
The code was isolated so that it's easy to #ifdef it out if needed.
This should be backported where the patch above is backported (likely
2.0).
(cherry picked from commit f734ebfac4c406f245347527bd0e5831a251cc61)
Signed-off-by: Willy Tarreau <w@1wt.eu>
(cherry picked from commit 10c627ab2ebeb0a38ae8df477a5f2d870ad77f7c)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
(cherry picked from commit 73f2a3f2783ed740ee29ef2ed0220ddecd50652f)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
diff --git a/src/hathreads.c b/src/hathreads.c
index 4c9e5dc..72754b6 100644
--- a/src/hathreads.c
+++ b/src/hathreads.c
@@ -189,6 +189,27 @@
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 __hathreads_init(void)
{
@@ -201,17 +222,7 @@
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();