From 802157210e8999693f40de6aeb6ce23fb1069826 Mon Sep 17 00:00:00 2001 From: Stephan Bauroth Date: Thu, 12 Nov 2026 12:43:24 +0100 Subject: [PATCH] build-bench-env.sh: fix guarder's thread function lookup Guarder resolves the real pthread_create with dlopen("libpthread.so.0", RTLD_NOLOAD). Since glibc 2.34 that library is an empty compatibility stub that nothing loads, so the handle comes back NULL and dlsym(NULL, name) searches the global scope from the front - which finds guarder's own interposer. Every pthread_create then recursed into itself until the 128-entry thread table was full and guarder aborted with "maximum concurrent thread limit reached (128)"; an interposer mounted in front of libguarder.so counts 128 creations and no joins for "./mstress 4 50 25". That is the mstressN and rptestN failure in the gd jobs on ubuntu and fedora, and with the fallback both return to exit 0. RTLD_NEXT starts the search after libguarder.so, at the real libc; the same file already resolves malloc and free that way. larsonN-sized still fails, for a reason unrelated to the lookup. --- build-bench-env.sh | 3 +++ patches/gd.patch | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 patches/gd.patch diff --git a/build-bench-env.sh b/build-bench-env.sh index 9b98cc4..3701b7c 100755 --- a/build-bench-env.sh +++ b/build-bench-env.sh @@ -517,6 +517,9 @@ fi if test "$setup_gd" = "1"; then checkout gd $version_gd https://github.com/UTSASRG/Guarder + set +e + patch -p1 -N -r- < ../../patches/gd.patch + set -e make -j $procs popd fi diff --git a/patches/gd.patch b/patches/gd.patch new file mode 100644 index 0000000..93322ba --- /dev/null +++ b/patches/gd.patch @@ -0,0 +1,19 @@ +--- a/real.cpp ++++ b/real.cpp +@@ -43,8 +43,15 @@ + INIT_WRAPPER(malloc, RTLD_NEXT); + // INIT_WRAPPER(realloc, RTLD_NEXT); + +- // FIXME about the flags ++ // glibc >= 2.34 moved pthread into libc; libpthread.so.0 is an empty ++ // compatibility stub that nothing loads any more, so this dlopen returns ++ // NULL. dlsym(NULL, name) is dlsym(RTLD_DEFAULT, name), which searches the ++ // preloaded libraries first and would hand us back our own interposers ++ // below, making every thread creation recurse into itself. RTLD_NEXT ++ // starts the search after libguarder, i.e. at the real libc. + void *pthread_handle = dlopen("libpthread.so.0", RTLD_NOW | RTLD_GLOBAL | RTLD_NOLOAD); ++ if (pthread_handle == NULL) ++ pthread_handle = RTLD_NEXT; + INIT_WRAPPER(pthread_create, pthread_handle); + INIT_WRAPPER(pthread_join, pthread_handle); + INIT_WRAPPER(pthread_kill, pthread_handle);