[Bug dynamic-link/15686] Shared-object static constructors called with a lock held
temap at mail dot ru via Glibc-bugs <[email protected]> Sun, 12 Jul 2026 12:08:11 +0000
| Newsgroups | gmane.comp.lib.glibc.bugs |
|---|---|
| Message-ID | <[email protected]/bugzilla/> |
https://sourceware.org/bugzilla/show_bug.cgi?id=3D15686 --- Comment #8 from Artem Proskurnev <temap at mail dot ru> --- I received a message from [email protected] and ran all available tests again. -- Method -- Two independent glibc builds from source, identical configuration, differing only in whether the patch is applied. Full make check run on each. Results compared by test name. -- Source revisions -- NEW: 96623a9cf9 =E2=80=9Celf: Release dl_load_lock before running dlopen co= nstructors (BZ 15686)=E2=80=9D patch applied OLD: 5396eb7045 =E2=80=9Clocaledata: Use libc-alpha ML as the canonical con= tact=E2=80=9D (parent of the patch commit) patch not applied The patch commit adds tst-create2 as a regression test. For OLD, the regres= sion test source files (sysdeps/pthread/tst-create2.c and sysdeps/pthread/tst-create2mod.c) and their Makefile entries were forward-ported onto the unpatched base, so that the same test is present in both builds. No other changes were made to the OLD tree; in particular, elf/dl-open.c is unchanged from upstream master and still contains the bug. -- Build configuration -- Both trees configured identically, out-of-tree: ``` ../src/configure \ --prefix=3D/usr \ --disable-werror \ --disable-profile \ --enable-kernel=3D3.2 \ --without-selinux \ --enable-bind-now ``` Toolchain: GCC 14.3.0 (ROSA), binutils from host, x86_64-linux-gnu. Build steps for each side: ``` mkdir build && cd build ../src/configure <flags as above> make -j8 make -j8 check ``` No mocking, no chroots, no container isolation. Both builds ran on the same bare-metal x86_64 host (ROSA Linux, kernel 6.12). -- Results -- Aggregate counts from `tests.sum`: Status | NEW | OLD ------------------------- PASS | 6874 | 6873 FAIL | 7 | 8 XFAIL | 16 | 16 XPASS | 0 | 0 UNSUPPORTED | 476 | 476 ERROR | 0 | 0 -- Per-test diff (the entire behavioral difference) -- Test | NEW | OLD ------------------------------- `nptl/tst-create2` | PASS | **FAIL** (deadlock) This is the only test whose outcome differs between the two runs. On unpatched glibc, `tst-create2` reproduces the deadlock described in BZ 15686: the main thread is in `dlopen()` running a constructor that calls `pthread_join` on a worker thread; the worker thread blocks forever in `__cxa_thread_atexit_impl` trying to acquire `dl_load_lock`, which the main thread still holds. The test times out and is reported as FAIL. With the patch applied, `dlopen()` releases `dl_load_lock` before invoking constructors, the worker thread completes its TLS destructor registration, the constructor returns, and the test exits cleanly. -- FAILs common to both runs (not caused by the patch) -- These 7 FAILs appear identically in NEW and OLD and are unrelated to the patch - they require root, specific hardware, or kernel capabilities that the unprivileged run environment does not provide: ``` FAIL: misc/test-errno-linux FAIL: misc/tst-mlock2 FAIL: misc/tst-ntp_gettime FAIL: misc/tst-ntp_gettimex FAIL: misc/tst-pkey FAIL: misc/tst-process_mrelease FAIL: time/tst-adjtime ``` No regressions were introduced by the patch. -- Conclusion -- - The patch resolves the deadlock class tracked by BZ 15686, demonstrated by `tst-create2` transitioning from FAIL (timeout on deadlock) on unpatched glibc to PASS on patched glibc. - The patch introduces no regressions: across the full `make check` suite (~7400 outcomes), no other test changes state in either direction. -- Cross-check against the Linaro tcwg_glibc_check CI run (aarch64) -- The Linaro CI bot reported https://patchwork.sourceware.org/patch/138954, build `tcwg_glibc_check--master-aarch64-precommit/10384`): > "Produces 1 regression 96 fixes" > regressions.sum: FAIL: posix/tst-affinity-static The CI summary uses "1 regression" to mean "1 stable fail" (a test that consistently failed across multiple CI runs of the patched build). The underlying `notify/results.compare.txt` shows a more detailed picture - 6 actual transitions on the patchwork run vs. the reference `master-aarch64-build/10334` run: Transition | Test --------------------------------------------- PASS -> FAIL | `posix/tst-affinity-static` PASS -> FAIL | `posix/tst-affinity` PASS -> FAIL | `posix/tst-affinity-pid` PASS -> FAIL | `malloc/tst-malloc-tcache-leak` (none) -> XPASS | `elf/tst-protected1a` (none) -> XPASS | `elf/tst-protected1b` All six are listed in the CI's own `sumfiles/xfails.xfail` as known-flaky on aarch64, with explicit expiry dates: ``` flaky,expire=3D20260922 | FAIL: malloc/tst-malloc-tcache-leak flaky,expire=3D20260910 | FAIL: posix/tst-affinity flaky,expire=3D20260910 | FAIL: posix/tst-affinity-pid flaky,expire=3D20260909 | XPASS: elf/tst-protected1a flaky,expire=3D20260909 | XPASS: elf/tst-protected1b ``` `tst-affinity-static` is the only one not yet on the flaky list, but the CI's own `00-sumfiles/tests.log.1` shows it fails for the same reason as the flaky `tst-affinity*` siblings - the aarch64 CI guest sees a 64-CPU topology and the test times out iterating over it: ``` FAIL: posix/tst-affinity-static original exit status 1 info: Detected CPU set size (in bits): 64 info: Maximum test CPU: 63 ``` The same `tests.log.1` records the broken container environment at the top of the run - these explain the bulk of the 96 "fixes" (`fixes.sum` is dominated by `resolv/*`, `nss/*`, `io/tst-fchmod-fuse`, `posix/tst-wordexp-*`, `sunrpc/tst-udp-*` and similar tests that need network, FUSE, or root): ``` error: ../sysdeps/unix/sysv/linux/tst-spawn-cgroup.c:152: can not create a = new cgroupv2 group error: support_fuse.c:425: cannot open /dev/fuse: No such file or directory error: tst-faccessat-setuid.c:90: Test needs to be run as root (UID 0) ``` The reference build (`master-aarch64-build/10334`) ran with the same environmental limitations, so a test that flaked to FAIL there and flaked to PASS on the precommit run shows up as a "fix"; the inverse shows up as a "regression". None of these transitions are behavioral effects of the patch - none of the affected tests exercise the `dl_open_worker` code path that the patch modifies. The x86_64 `make check` run reported in this document, executed under identical conditions for both sides on the same host, shows zero PASS->FAIL transitions attributable to the patch. This is consistent with the CI's own classification of the aarch64 transitions as flaky/environmental. CI artifacts referenced: - `notify/results.compare.txt` - full per-test diff (reference vs. patched) - `notify/regressions.sum` - CI's regression summary (1 stable, 37 flaky) - `notify/fixes.sum` - CI's improvements summary (96 stable fixes) - `sumfiles/xfails.xfail` - known flaky / known failure list - `00-sumfiles/tests.log.1`, `tests.log.0` - per-test output logs All under `http://54.172.246.49:9090/jobs/tcwg_glibc_check--master-aarch64-precommit/= builds/10384/archive/artifacts/artifacts.precommit/`. --=20 You are receiving this mail because: You are on the CC list for the bug.=