From: Willy Tarreau Date: Mon, 18 Jul 2022 11:58:17 +0000 (+0200) Subject: BUG/MEDIUM: tools: avoid calling dlsym() in static builds (try 2) X-Git-Tag: v2.7-dev3~87 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5b3cd9561bdbf7bac7db04bafead76125f1458ae;p=thirdparty%2Fhaproxy.git BUG/MEDIUM: tools: avoid calling dlsym() in static builds (try 2) The first approach in commit 288dc1d8e ("BUG/MEDIUM: tools: avoid calling dlsym() in static builds") relied on dlopen() but on certain configs (at least gcc-4.8+ld-2.27+glibc-2.17) it used to catch situations where it ought not fail. Let's have a second try on this using dladdr() instead. The variable was renamed "build_is_static" as it's exactly what's being detected there. We could even take it for reporting in -vv though that doesn't seem very useful. At least the variable was made global to ease inspection via the debugger, or in case it's useful later. Now it properly detects a static build even with gcc-4.4+glibc-2.11.1 and doesn't crash anymore. --- diff --git a/include/haproxy/tools.h b/include/haproxy/tools.h index 6e3848f499..90d46a60d1 100644 --- a/include/haproxy/tools.h +++ b/include/haproxy/tools.h @@ -70,6 +70,7 @@ extern int strlcpy2(char *dst, const char *src, int size); */ extern THREAD_LOCAL int itoa_idx; /* index of next itoa_str to use */ extern THREAD_LOCAL char itoa_str[][171]; +extern int build_is_static; extern char *ultoa_r(unsigned long n, char *buffer, int size); extern char *lltoa_r(long long int n, char *buffer, int size); extern char *sltoa_r(long n, char *buffer, int size); diff --git a/src/tools.c b/src/tools.c index 44424176cc..36db6a48a8 100644 --- a/src/tools.c +++ b/src/tools.c @@ -98,6 +98,9 @@ THREAD_LOCAL int quoted_idx = 0; */ THREAD_LOCAL unsigned int statistical_prng_state = 2463534242U; +/* set to true if this is a static build */ +int build_is_static = 0; + /* * unsigned long long ASCII representation * @@ -4920,22 +4923,25 @@ static int dladdr_and_size(const void *addr, Dl_info *dli, size_t *size) return ret; } -/* dlopen() support: 0=no/not yet checked, 1=ok */ -static int dlopen_usable = 0; - -/* Sets dlopen_usable to true if dlopen() works and is usable. We verify if - * we're in a static build because some old glibcs used to crash in dlsym() - * in this case. +/* Sets build_is_static to true if we detect a static build. Some older glibcs + * tend to crash inside dlsym() in static builds, but tests show that at least + * dladdr() still works (and will fail to resolve anything of course). Thus we + * try to determine if we're on a static build to avoid calling dlsym() in this + * case. */ -void check_if_dlopen_usable() +void check_if_static_build() { - /* dlopen(NULL) returns a handle to the main program or NULL - * on static builds. - */ - dlopen_usable = dlopen(NULL, RTLD_LAZY) ? 1 : 0; + Dl_info dli = { }; + size_t size = 0; + + /* Now let's try to be smarter */ + if (!dladdr_and_size(&main, &dli, &size)) + build_is_static = 1; + else + build_is_static = 0; } -INITCALL0(STG_PREPARE, check_if_dlopen_usable); +INITCALL0(STG_PREPARE, check_if_static_build); /* Tries to retrieve the address of the first occurrence symbol . * Note that NULL in return is not always an error as a symbol may have that @@ -4946,7 +4952,7 @@ void *get_sym_curr_addr(const char *name) void *ptr = NULL; #ifdef RTLD_DEFAULT - if (dlopen_usable) + if (!build_is_static) ptr = dlsym(RTLD_DEFAULT, name); #endif return ptr; @@ -4962,7 +4968,7 @@ void *get_sym_next_addr(const char *name) void *ptr = NULL; #ifdef RTLD_NEXT - if (dlopen_usable) + if (!build_is_static) ptr = dlsym(RTLD_NEXT, name); #endif return ptr;