diff -r 03d10f218fce UPDATING --- a/UPDATING Sun Oct 19 18:56:19 2025 +0000 +++ b/UPDATING Sat Nov 22 16:57:48 2025 +0000 @@ -19,6 +19,10 @@ See also: BUILDING, build.sh, Makefile. Recent changes: ^^^^^^^^^^^^^^^ +20251122: + Changes to libpthread for PR 59784 require you to make clean in + lib/libpthread so it is rebuilt with updated ld flags. + 20250721: GCC 12.5 was imported and there may be weird build issues. Clean any GCC build dirs if you encounter weird things. diff -r 03d10f218fce lib/libpthread/Makefile --- a/lib/libpthread/Makefile Sun Oct 19 18:56:19 2025 +0000 +++ b/lib/libpthread/Makefile Sat Nov 22 16:57:48 2025 +0000 @@ -65,6 +65,22 @@ CPPFLAGS+=-I${NETBSDSRCDIR}/sys -I${.CUR # set by the rumprun software stacks (see https://github.com/rumpkernel/rumprun ) PTHREAD_MAKELWP?= pthread_makelwp_netbsd.c +# Prevent unloading libpthread. +# +# libpthread provides strong definitions of some symbols defined weakly +# by libc, such as pthread_mutex_lock (actually __libc_mutex_lock under +# the hood), which are used in libraries that take locks for +# thread-safety -- this way, in non-threaded applications, +# pthread_mutex_lock is a cheap noop libc stub, while in threaded +# applications, it's a real libpthread operation. If libpthread is +# dlopened, the symbol might be lazily resolved _after_ it is dlopened +# to point at libpthread; then it cannot be safely unloaded, because +# there's no way to roll back symbol resolution. +# +# PR lib/59784: dlopening and dlclosing libpthread is broken +# +LDADD+= -Wl,-z,nodelete + # # NOTE: When you create a new file for libpthread, make sure that pthread.c # gets a reference to a symbol in that file. Otherwise, Unix's stupid static diff -r 03d10f218fce tests/lib/libpthread/dlopen/t_dlopen.c --- a/tests/lib/libpthread/dlopen/t_dlopen.c Sun Oct 19 18:56:19 2025 +0000 +++ b/tests/lib/libpthread/dlopen/t_dlopen.c Sat Nov 22 16:57:48 2025 +0000 @@ -37,23 +37,17 @@ __RCSID("$NetBSD: t_dlopen.c,v 1.1 2013/ #include #include #include +#include #include -ATF_TC(dlopen); - -ATF_TC_HEAD(dlopen, tc) -{ - atf_tc_set_md_var(tc, "descr", - "Test if dlopen can load -lpthread DSO"); -} - #define DSO TESTDIR "/h_pthread_dlopen.so" -ATF_TC_BODY(dlopen, tc) +static void +test_dlopen(int flags) { void *handle; int (*testf_dso_null)(void); - handle = dlopen(DSO, RTLD_NOW | RTLD_LOCAL); + handle = dlopen(DSO, flags); ATF_REQUIRE_MSG(handle != NULL, "dlopen fails: %s", dlerror()); testf_dso_null = dlsym(handle, "testf_dso_null"); @@ -64,15 +58,30 @@ ATF_TC_BODY(dlopen, tc) ATF_REQUIRE(dlclose(handle) == 0); } -ATF_TC(dlopen_mutex); - -ATF_TC_HEAD(dlopen_mutex, tc) +ATF_TC(dlopen); +ATF_TC_HEAD(dlopen, tc) { atf_tc_set_md_var(tc, "descr", - "Test if dlopen can load -lpthread DSO without breaking mutex"); + "Test if dlopen can load -lpthread DSO"); +} +ATF_TC_BODY(dlopen, tc) +{ + test_dlopen(RTLD_NOW | RTLD_LOCAL); } -ATF_TC_BODY(dlopen_mutex, tc) +ATF_TC(dlopen_lazyglobal); +ATF_TC_HEAD(dlopen_lazyglobal, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test if dlopen can load -lpthread DSO"); +} +ATF_TC_BODY(dlopen_lazyglobal, tc) +{ + test_dlopen(RTLD_LAZY | RTLD_GLOBAL); +} + +static void +test_dlopen_mutex(int flags) { pthread_mutex_t mtx; void *handle; @@ -81,7 +90,7 @@ ATF_TC_BODY(dlopen_mutex, tc) ATF_REQUIRE(pthread_mutex_init(&mtx, NULL) == 0); ATF_REQUIRE(pthread_mutex_lock(&mtx) == 0); - handle = dlopen(DSO, RTLD_NOW | RTLD_LOCAL); + handle = dlopen(DSO, flags); ATF_REQUIRE_MSG(handle != NULL, "dlopen fails: %s", dlerror()); testf_dso_null = dlsym(handle, "testf_dso_null"); @@ -93,18 +102,36 @@ ATF_TC_BODY(dlopen_mutex, tc) ATF_REQUIRE(dlclose(handle) == 0); + ATF_REQUIRE(pthread_mutex_lock(&mtx) == 0); + ATF_REQUIRE(pthread_mutex_unlock(&mtx) == 0); + pthread_mutex_destroy(&mtx); } -ATF_TC(dlopen_mutex_libc); - -ATF_TC_HEAD(dlopen_mutex_libc, tc) +ATF_TC(dlopen_mutex); +ATF_TC_HEAD(dlopen_mutex, tc) { atf_tc_set_md_var(tc, "descr", - "Test if dlopen can load -lpthread DSO and use libc locked mutex"); + "Test if dlopen can load -lpthread DSO without breaking mutex"); +} +ATF_TC_BODY(dlopen_mutex, tc) +{ + test_dlopen_mutex(RTLD_NOW | RTLD_LOCAL); } -ATF_TC_BODY(dlopen_mutex_libc, tc) +ATF_TC(dlopen_mutex_lazyglobal); +ATF_TC_HEAD(dlopen_mutex_lazyglobal, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test if dlopen can load -lpthread DSO without breaking mutex"); +} +ATF_TC_BODY(dlopen_mutex_lazyglobal, tc) +{ + test_dlopen_mutex(RTLD_LAZY | RTLD_GLOBAL); +} + +static void +test_dlopen_mutex_libc(int flags) { pthread_mutex_t mtx; void *handle; @@ -113,7 +140,7 @@ ATF_TC_BODY(dlopen_mutex_libc, tc) ATF_REQUIRE(pthread_mutex_init(&mtx, NULL) == 0); ATF_REQUIRE(pthread_mutex_lock(&mtx) == 0); - handle = dlopen(DSO, RTLD_NOW | RTLD_LOCAL); + handle = dlopen(DSO, flags); ATF_REQUIRE_MSG(handle != NULL, "dlopen fails: %s", dlerror()); testf_dso_mutex_unlock = dlsym(handle, "testf_dso_mutex_unlock"); @@ -124,19 +151,36 @@ ATF_TC_BODY(dlopen_mutex_libc, tc) dlclose(handle); + ATF_REQUIRE(pthread_mutex_lock(&mtx) == 0); + ATF_REQUIRE(pthread_mutex_unlock(&mtx) == 0); + pthread_mutex_destroy(&mtx); } -ATF_TC(dlopen_mutex_libpthread); - -ATF_TC_HEAD(dlopen_mutex_libpthread, tc) +ATF_TC(dlopen_mutex_libc); +ATF_TC_HEAD(dlopen_mutex_libc, tc) { atf_tc_set_md_var(tc, "descr", - "Test if dlopen can load -lpthread DSO and use " - "libpthread locked mutex"); + "Test if dlopen can load -lpthread DSO and use libc locked mutex"); +} +ATF_TC_BODY(dlopen_mutex_libc, tc) +{ + test_dlopen_mutex_libc(RTLD_NOW | RTLD_LOCAL); } -ATF_TC_BODY(dlopen_mutex_libpthread, tc) +ATF_TC(dlopen_mutex_libc_lazyglobal); +ATF_TC_HEAD(dlopen_mutex_libc_lazyglobal, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test if dlopen can load -lpthread DSO and use libc locked mutex"); +} +ATF_TC_BODY(dlopen_mutex_libc_lazyglobal, tc) +{ + test_dlopen_mutex_libc(RTLD_LAZY | RTLD_GLOBAL); +} + +static void +test_dlopen_mutex_libpthread(int flags) { pthread_mutex_t mtx; void *handle; @@ -144,7 +188,7 @@ ATF_TC_BODY(dlopen_mutex_libpthread, tc) ATF_REQUIRE(pthread_mutex_init(&mtx, NULL) == 0); - handle = dlopen(DSO, RTLD_NOW | RTLD_LOCAL); + handle = dlopen(DSO, flags); ATF_REQUIRE_MSG(handle != NULL, "dlopen fails: %s", dlerror()); testf_dso_mutex_lock = dlsym(handle, "testf_dso_mutex_lock"); @@ -157,15 +201,48 @@ ATF_TC_BODY(dlopen_mutex_libpthread, tc) dlclose(handle); + ATF_REQUIRE(pthread_mutex_lock(&mtx) == 0); + ATF_REQUIRE(pthread_mutex_unlock(&mtx) == 0); + pthread_mutex_destroy(&mtx); } +ATF_TC(dlopen_mutex_libpthread); +ATF_TC_HEAD(dlopen_mutex_libpthread, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test if dlopen can load -lpthread DSO and use " + "libpthread locked mutex"); +} +ATF_TC_BODY(dlopen_mutex_libpthread, tc) +{ + test_dlopen_mutex_libpthread(RTLD_NOW | RTLD_LOCAL); +} + +ATF_TC(dlopen_mutex_libpthread_lazyglobal); +ATF_TC_HEAD(dlopen_mutex_libpthread_lazyglobal, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test if dlopen can load -lpthread DSO and use " + "libpthread locked mutex"); +} +ATF_TC_BODY(dlopen_mutex_libpthread_lazyglobal, tc) +{ + test_dlopen_mutex_libpthread(RTLD_LAZY | RTLD_GLOBAL); +} + ATF_TP_ADD_TCS(tp) { + ATF_TP_ADD_TC(tp, dlopen); ATF_TP_ADD_TC(tp, dlopen_mutex); ATF_TP_ADD_TC(tp, dlopen_mutex_libc); ATF_TP_ADD_TC(tp, dlopen_mutex_libpthread); + ATF_TP_ADD_TC(tp, dlopen_lazyglobal); + ATF_TP_ADD_TC(tp, dlopen_mutex_lazyglobal); + ATF_TP_ADD_TC(tp, dlopen_mutex_libc_lazyglobal); + ATF_TP_ADD_TC(tp, dlopen_mutex_libpthread_lazyglobal); + return atf_no_error(); } diff -r 03d10f218fce tests/lib/libpthread/dlopen/t_dso_pthread_create.c --- a/tests/lib/libpthread/dlopen/t_dso_pthread_create.c Sun Oct 19 18:56:19 2025 +0000 +++ b/tests/lib/libpthread/dlopen/t_dso_pthread_create.c Sat Nov 22 16:57:48 2025 +0000 @@ -34,12 +34,15 @@ #include __RCSID("$NetBSD: t_dso_pthread_create.c,v 1.1 2013/03/21 16:50:21 christos Exp $"); -#include #include #include #include +#include +#include #include +#include "../../../h_macros.h" + #define DSO TESTDIR "/h_pthread_dlopen.so" void * @@ -49,6 +52,17 @@ routine(void *arg) return NULL; } +static jmp_buf abort_aborting; + +static void +handle_sigabrt(int signo) +{ + + ATF_REQUIRE_EQ_MSG(signo, SIGABRT, "signo=%d (%s)", signo, + strsignal(signo)); + longjmp(abort_aborting, 1); +} + ATF_TC(dso_pthread_create_dso); ATF_TC_HEAD(dso_pthread_create_dso, tc) @@ -64,25 +78,24 @@ ATF_TC_BODY(dso_pthread_create_dso, tc) pthread_t thread; void *arg = (void *)0xcafe; void *handle; - int (*testf_dso_pthread_create)(pthread_t *, pthread_attr_t *, + int (*testf_dso_pthread_create)(pthread_t *, pthread_attr_t *, void *(*)(void *), void *); - struct rlimit rl; - - atf_tc_expect_signal(6, - "calling pthread_create() requires -lpthread main"); - - rl.rlim_max = rl.rlim_cur = 0; - ATF_REQUIRE_EQ(setrlimit(RLIMIT_CORE, &rl), 0); + void (*sighandler)(int); handle = dlopen(DSO, RTLD_NOW | RTLD_LOCAL); ATF_REQUIRE_MSG(handle != NULL, "dlopen fails: %s", dlerror()); testf_dso_pthread_create = dlsym(handle, "testf_dso_pthread_create"); - ATF_REQUIRE_MSG(testf_dso_pthread_create != NULL, + ATF_REQUIRE_MSG(testf_dso_pthread_create != NULL, "dlsym fails: %s", dlerror()); - ret = testf_dso_pthread_create(&thread, NULL, routine, arg); - ATF_REQUIRE(ret == 0); + REQUIRE_LIBC((sighandler = signal(SIGABRT, &handle_sigabrt)), SIG_ERR); + if (setjmp(abort_aborting) == 0) { + ret = testf_dso_pthread_create(&thread, NULL, routine, arg); + ATF_REQUIRE_MSG(ret != 0, + "pthread_create unexpectedly succeeded"); + } + REQUIRE_LIBC(signal(SIGABRT, sighandler), SIG_ERR); ATF_REQUIRE(dlclose(handle) == 0);