[PATCH v7 0/4] elf: Release dl_load_lock around ELF constructors and destructors + LD_DEBUG=loadlock observability (BZ 15686)
[email protected] Mon, 3 Aug 2026 23:03:22 +0300
| Newsgroups | gmane.comp.lib.glibc.alpha |
|---|---|
| Message-ID | <[email protected]> |
From: Artem Proskurnev <[email protected]> This v6 series implements the three concrete asks from Carlos's 2026-07-21 review of v3 ("Re: [PATCH v3] elf: Release dl_load_lock before running dlopen constructors (BZ 15686)"): (a) Keep the glibc.rtld.strict_init_order tunable, document it, and flag it for eventual removal once the ecosystem has been shown to work with the new default. Carlos on (3) in that message: "I think it's OK to keep the tunable ... The documentation should clearly state we intend to remove this when the ecosystem has been shown to work with the new implementation." (b) Extend the same dl_load_lock release to ELF destructors so the dlclose path mirrors the dlopen path. Carlos on (4): "I'm also concerned about destructors since both see this kind of problem. What prevents us from providing the same invariant in destructors?" (c) Add an LD_DEBUG option that logs every dl_load_lock acquisition and release site with a raw-address backtrace, so residual deadlocks of this shape can be localised without a debugger. Carlos on tooling: "I think we should add this as a 2/2 patch, which improves the observability." Then in reply to my question about how admins know to flip the tunable: "How does a system admin, or developer know to flip the tunable?" -- the LD_DEBUG=loadlock trace is the answer. Patch layout: 0001 - Release dl_load_lock before running dlopen constructors (BZ 15686). Constructor side. Adds the glibc.rtld.strict_init_order tunable (documented in manual/tunables.texi, marked for eventual removal), the l_init_once / l_init_owner / l_init_pending fields on struct link_map, and tst-create2..6 covering the ctor deadlock and concurrent-dlopen races. tst-create4 was reworked in v7: the old test (flaky probabilistic interleave check, marked XFAIL) is replaced by a deterministic barrier-based test that verifies a long-running constructor does not block concurrent dlopen of an unrelated library -- the core invariant the BZ 15686 fix provides. 0002 - Release dl_load_lock before running dlclose destructors (BZ 15686). Destructor side; same tunable, same caveat. Mirrors the _dl_fini behaviour on the _dl_close_worker path. Adds tst-create7..10 covering the symmetric dtor scenarios. 0003 - Add LD_DEBUG=loadlock to trace dl_load_lock acquisitions (BZ 15686). Instruments the dlopen constructor path. The backtrace is a manual frame-pointer walk -- deliberately lock-free, allocation-free and syscall-free, so the trace can be emitted while dl_load_lock is held without re-entering the loader. Raw addresses are resolved offline with addr2line(1). 0004 - Add LD_DEBUG=loadlock tracing for the dlclose destructor path (BZ 15686). Extends 0003 coverage to _dl_close and _dl_close_worker, including the BZ 15686 release site around _dl_call_fini. The scope claim made in v3 (originally independent threads can run independent dlopens concurrently; a constructor or destructor may call any libc / dynamic-loader function safe to call from a regular non-signal-handler thread) now applies symmetrically to constructors and destructors. Synchronous loader-internal reentrancy (e.g. a malloc interposer that itself calls dlopen, routing through the loader's own malloc during dlopen processing outside the ctor/dtor window) remains out of scope, as in v3. Testing: x86_64 make check across five trees (unpatched, +0001, +0001+0002, +0001..+0003, +0001..+0004) with the same tst-create1..10 regression suite forward-ported onto each tree. Each functional patch converts exactly one tst-create* timeout-on-deadlock into a PASS with no other transitions; 0003 and 0004 each add one PASS (elf/tst-debug-loadlock) for the LD_DEBUG=loadlock test and are otherwise pure diagnostics with no behavioural diff. tst-create4 (barrier-based deterministic test) passes on all five trees confirming the lock release is effective; no XFAIL marker needed. The tunable is expected to remain in tree for roughly four release cycles, per Carlos's guidance, and is removed once the ecosystem has been shown to adapt. Artem Proskurnev (4): elf: Release dl_load_lock before running dlopen constructors (BZ 15686) elf: Release dl_load_lock before running dlclose destructors (BZ 15686) elf: Add LD_DEBUG=loadlock to trace dl_load_lock acquisitions (BZ 15686) elf: Add LD_DEBUG=loadlock tracing for the dlclose destructor path (BZ 15686) elf/Makefile | 5 + elf/dl-close.c | 87 ++++++++++++++-- elf/dl-debug.c | 42 ++++++++ elf/dl-init.c | 99 +++++++++++++++++- elf/dl-open.c | 161 ++++++++++++++++++++++++++++- elf/dl-tunables.list | 6 ++ elf/rtld.c | 2 + elf/tst-debug-loadlock-mod.c | 4 + elf/tst-debug-loadlock.c | 131 +++++++++++++++++++++++ elf/tst-rtld-list-tunables.exp | 1 + include/link.h | 22 ++++ manual/dynlink.texi | 12 +++ manual/tunables.texi | 46 +++++++++ sysdeps/generic/ldsodefs.h | 12 +++ sysdeps/pthread/Makefile | 104 +++++++++++++++++++ sysdeps/pthread/tst-create10.c | 119 +++++++++++++++++++++ sysdeps/pthread/tst-create10mod.c | 59 +++++++++++ sysdeps/pthread/tst-create2.c | 67 ++++++++++++ sysdeps/pthread/tst-create2mod.c | 74 +++++++++++++ sysdeps/pthread/tst-create3.c | 112 ++++++++++++++++++++ sysdeps/pthread/tst-create3.h | 27 +++++ sysdeps/pthread/tst-create3mod.c | 68 ++++++++++++ sysdeps/pthread/tst-create4.c | 100 ++++++++++++++++++ sysdeps/pthread/tst-create4.h | 37 +++++++ sysdeps/pthread/tst-create4mod-a.c | 30 ++++++ sysdeps/pthread/tst-create4mod-b.c | 22 ++++ sysdeps/pthread/tst-create5.c | 63 +++++++++++ sysdeps/pthread/tst-create6.c | 111 ++++++++++++++++++++ sysdeps/pthread/tst-create6.h | 26 +++++ sysdeps/pthread/tst-create6mod.c | 72 +++++++++++++ sysdeps/pthread/tst-create7.c | 129 +++++++++++++++++++++++ sysdeps/pthread/tst-create7mod-a.c | 46 +++++++++ sysdeps/pthread/tst-create7mod-b.c | 26 +++++ sysdeps/pthread/tst-create8.c | 97 +++++++++++++++++ sysdeps/pthread/tst-create8mod-a.c | 55 ++++++++++ sysdeps/pthread/tst-create8mod-b.c | 27 +++++ sysdeps/pthread/tst-create9.c | 113 ++++++++++++++++++++ sysdeps/pthread/tst-create9mod.c | 37 +++++++ 38 files changed, 2239 insertions(+), 12 deletions(-) create mode 100644 elf/tst-debug-loadlock-mod.c create mode 100644 elf/tst-debug-loadlock.c create mode 100644 sysdeps/pthread/tst-create10.c create mode 100644 sysdeps/pthread/tst-create10mod.c create mode 100644 sysdeps/pthread/tst-create2.c create mode 100644 sysdeps/pthread/tst-create2mod.c create mode 100644 sysdeps/pthread/tst-create3.c create mode 100644 sysdeps/pthread/tst-create3.h create mode 100644 sysdeps/pthread/tst-create3mod.c create mode 100644 sysdeps/pthread/tst-create4.c create mode 100644 sysdeps/pthread/tst-create4.h create mode 100644 sysdeps/pthread/tst-create4mod-a.c create mode 100644 sysdeps/pthread/tst-create4mod-b.c create mode 100644 sysdeps/pthread/tst-create5.c create mode 100644 sysdeps/pthread/tst-create6.c create mode 100644 sysdeps/pthread/tst-create6.h create mode 100644 sysdeps/pthread/tst-create6mod.c create mode 100644 sysdeps/pthread/tst-create7.c create mode 100644 sysdeps/pthread/tst-create7mod-a.c create mode 100644 sysdeps/pthread/tst-create7mod-b.c create mode 100644 sysdeps/pthread/tst-create8.c create mode 100644 sysdeps/pthread/tst-create8mod-a.c create mode 100644 sysdeps/pthread/tst-create8mod-b.c create mode 100644 sysdeps/pthread/tst-create9.c create mode 100644 sysdeps/pthread/tst-create9mod.c -- 2.51.0