Re: PR lib/59751: dlclose is not MT-safe depending on the libraries unloaded

Taylor R Campbell <[email protected]>
Newsgroups gmane.os.netbsd.bugs
Message-ID <[email protected]>
> Date: Wed, 15 Jul 2026 23:54:56 +0200
> From: Anthony Mallet <[email protected]>
> 
> I was actually trying to debug dlclose(3) issues in a complex C++
> program (not related to this PR at all). Then I found this report and
> the associated recent commits, so I gave it a try as it looked
> promising for my case too.
> 
> Now, (with -current and ld.elf_so from today) it seems that
> _recursive_ dlclose() calls blocks infinitely. I can try to provide
> a minimal reproducer, but I wanted to let you know first, in case you can
> quickly spot or figure out the issue.

Darnit!  That's probably much worse than requiring the caller to
serialize dlopen/dlclose, which was an effective workaround for the
original problem this PR was about...

> Note that the recursive dlclose, as weird as it looks, is expected to
> happen given the way the code is written. The two dlclose are not
> targetting the same libraries, although both libraries have many
> dependencies in common. I'm not sure if recursive dlclose is not
> undefined behaviour though.

I don't know if it's really defined by a standard but it's a
reasonable thing to do.

Can you try the attached patch and see if it works in your complex
application?

I haven't really thought through the implications but it makes a
simple test pass.
pr59751-recursivedlopendlclose.patch (text/plain, 2.6 KB)
# HG changeset patch
# User Taylor R Campbell <[email protected]>
# Date 1784160130 0
#      Thu Jul 16 00:02:10 2026 +0000
# Branch trunk
# Node ID cd0994f0feb0884c98f4ab9523142cd99fabde47
# Parent  05f0f4cd0342e5f669a0e3bfdb589842a248e4a4
# EXP-Topic riastradh-pr59751-recursivedlopendlclose
WIP: dlfcn(3): Allow recursive dlopen/dclose again through init/fini.

PR lib/59751: dlclose is not MT-safe depending on the libraries
unloaded

diff -r 05f0f4cd0342 -r cd0994f0feb0 libexec/ld.elf_so/rtld.c
--- a/libexec/ld.elf_so/rtld.c	Wed Jul 15 23:56:27 2026 +0000
+++ b/libexec/ld.elf_so/rtld.c	Thu Jul 16 00:02:10 2026 +0000
@@ -529,6 +529,8 @@ restart:
 			if (obj->refcount > 0 && !force) {
 				continue;
 			}
+			if (obj->initfinilock == _lwp_self())
+				continue;
 			if (!_rtld_initfini_enter(&obj, mask)) {
 				_rtld_objlist_clear(&finilist);
 				goto restart;
@@ -549,6 +551,8 @@ restart:
 		if (obj->refcount > 0 && !force) {
 			continue;
 		}
+		if (obj->initfinilock == _lwp_self())
+			continue;
 		if (!_rtld_initfini_enter(&obj, mask)) {
 			_rtld_objlist_clear(&finilist);
 			goto restart;
@@ -600,6 +604,8 @@ static void
 static bool
 _rtld_call_ifunc_functions(sigset_t *mask, Obj_Entry *obj, u_int cur_objgen)
 {
+	if (obj->initfinilock == _lwp_self())
+		return false;
 	if (!_rtld_initfini_enter(&obj, mask))
 		return true;
 	if (obj->ifunc_remaining
@@ -683,6 +689,8 @@ restart:
 			goto restart;
 		}
 		if (obj->z_initfirst) {
+			if (obj->initfinilock == _lwp_self())
+				continue;
 			if (!_rtld_initfini_enter(&obj, mask)) {
 				_rtld_objlist_clear(&initlist);
 				goto restart;
@@ -704,6 +712,8 @@ restart:
 			_rtld_objlist_clear(&initlist);
 			goto restart;
 		}
+		if (obj->initfinilock == _lwp_self())
+			continue;
 		if (!_rtld_initfini_enter(&obj, mask)) {
 			_rtld_objlist_clear(&initlist);
 			goto restart;
diff -r 05f0f4cd0342 -r cd0994f0feb0 tests/libexec/ld.elf_so/t_dlclose_thread.c
--- a/tests/libexec/ld.elf_so/t_dlclose_thread.c	Wed Jul 15 23:56:27 2026 +0000
+++ b/tests/libexec/ld.elf_so/t_dlclose_thread.c	Thu Jul 16 00:02:10 2026 +0000
@@ -116,13 +116,6 @@ ATF_TC_BODY(dlclose_recursive, tc)
 	RL(timer_create(CLOCK_MONOTONIC, &sigev, &t));
 	RL(timer_settime(t, TIMER_RELTIME, &it, NULL));
 
-	/*
-	 * Really, the issue is the followup to the fix for the PR
-	 * which is that I broke recursive dlopen/dlclose!
-	 */
-	atf_tc_expect_signal(SIGABRT, "PR lib/59751: dlclose is not MT-safe"
-	    " depending on the libraries unloaded");
-
 	handle = dlopen("libh_helper_recurdso.so", RTLD_LAZY | RTLD_LOCAL);
 	ATF_REQUIRE_MSG(handle != NULL, "%s", dlerror());
 	ATF_REQUIRE_MSG((error = dlclose(handle)) == 0,
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.