Summary
On a Linux host with /etc/ld.so.preload, the managed GCC 16.1.0 toolchain can fail before compilation starts. mcpp build fails while probing g++ --version with exit status 127.
The private glibc 2.44 loader cache contains absolute paths from the package build machine rather than the installed mcpp home. A preloaded host library whose indirect dependency is not covered by the executable's DT_RUNPATH therefore cannot locate libdl.so.2.
Environment
- mcpp:
2026.8.21.3
- managed compiler:
gcc@16.1.0
- private libc:
xim-x-glibc@2.44
- host has
/etc/ld.so.preload containing /lib/x86_64-linux-gnu/libonion.so
libonion.so has DT_NEEDED: libdl.so.2 and no RPATH/RUNPATH
Reproduction
MCPP_HOME=${MCPP_HOME:-$HOME/.mcpp}
GCC=$MCPP_HOME/registry/data/xpkgs/xim-x-gcc/16.1.0
GCC_RT=$MCPP_HOME/registry/data/xpkgs/xim-x-gcc-runtime/15.1.0
env -i PATH=/usr/bin:/bin LD_LIBRARY_PATH="$GCC_RT/lib64" \
"$GCC/bin/g++" --version
Actual result:
.../bin/g++: error while loading shared libraries: libdl.so.2: cannot open shared object file: No such file or directory
mcpp build -v then reports the probe command as exited with status 127, before build.mcpp or any project source is compiled.
The failure is independent of inherited LD_LIBRARY_PATH and LD_PRELOAD: it still reproduces with env -i. /etc/ld.so.preload is processed by the private loader.
Evidence
The installed private cache is stale:
strings "$MCPP_HOME/registry/data/xpkgs/xim-x-glibc/2.44/etc/ld.so.cache" | grep libdl.so.2
# /home/xlings/.xlings_data/xim/xpkgs/fromsource-x-glibc/2.44/lib/libdl.so.2
The file actually exists at:
$MCPP_HOME/registry/data/xpkgs/xim-x-glibc/2.44/lib/libdl.so.2
LD_DEBUG=libs,files identifies the complete failing edge:
file=libonion.so [0]; needed by .../xim-x-gcc/16.1.0/bin/g++ [0]
file=libdl.so.2 [0]; needed by /lib/x86_64-linux-gnu/libonion.so [0]
... search path=$GCC_RT/lib64 (LD_LIBRARY_PATH)
... search cache=$MCPP_HOME/registry/data/xpkgs/xim-x-glibc/2.44/etc/ld.so.cache
... trying file=/home/xlings/.xlings_data/.../lib/libdl.so.2
The GCC executable itself has a correct DT_RUNPATH for the current private glibc directory, but it is DT_RUNPATH, so it is not transitive to the preloaded library's dependency.
As a confirmation, explicitly including the private glibc directory makes the exact command succeed:
GLIBC=$MCPP_HOME/registry/data/xpkgs/xim-x-glibc/2.44
env -i PATH=/usr/bin:/bin LD_LIBRARY_PATH="$GLIBC/lib:$GCC_RT/lib64" \
"$GCC/bin/g++" --version
# g++ (xlings-fromsource) 16.1.0
Expected behavior
A managed GCC toolchain should remain executable on a host that uses /etc/ld.so.preload; at minimum, mcpp should fail with a diagnostic identifying the broken private glibc cache rather than a generic compiler exit status.
Possible fixes
- Package/install fix: regenerate or relocate the private glibc
etc/ld.so.cache after installation, or avoid shipping a cache with build-machine absolute paths.
- Probe hardening: derive the compiler's bound glibc library directory and include it in the compiler child environment, rather than injecting only
gcc-runtime.
- Add a regression fixture using a preloaded library with an indirect dependency outside the compiler executable's direct dependency closure.
The immediate local workaround is rebuilding the private cache with its bundled ldconfig, but this should not be necessary for a managed toolchain.
Summary
On a Linux host with
/etc/ld.so.preload, the managed GCC 16.1.0 toolchain can fail before compilation starts.mcpp buildfails while probingg++ --versionwith exit status 127.The private glibc 2.44 loader cache contains absolute paths from the package build machine rather than the installed mcpp home. A preloaded host library whose indirect dependency is not covered by the executable's
DT_RUNPATHtherefore cannot locatelibdl.so.2.Environment
2026.8.21.3gcc@16.1.0xim-x-glibc@2.44/etc/ld.so.preloadcontaining/lib/x86_64-linux-gnu/libonion.solibonion.sohasDT_NEEDED: libdl.so.2and noRPATH/RUNPATHReproduction
Actual result:
mcpp build -vthen reports the probe command as exited with status 127, beforebuild.mcppor any project source is compiled.The failure is independent of inherited
LD_LIBRARY_PATHandLD_PRELOAD: it still reproduces withenv -i./etc/ld.so.preloadis processed by the private loader.Evidence
The installed private cache is stale:
The file actually exists at:
LD_DEBUG=libs,filesidentifies the complete failing edge:The GCC executable itself has a correct
DT_RUNPATHfor the current private glibc directory, but it isDT_RUNPATH, so it is not transitive to the preloaded library's dependency.As a confirmation, explicitly including the private glibc directory makes the exact command succeed:
Expected behavior
A managed GCC toolchain should remain executable on a host that uses
/etc/ld.so.preload; at minimum, mcpp should fail with a diagnostic identifying the broken private glibc cache rather than a generic compiler exit status.Possible fixes
etc/ld.so.cacheafter installation, or avoid shipping a cache with build-machine absolute paths.gcc-runtime.The immediate local workaround is rebuilding the private cache with its bundled
ldconfig, but this should not be necessary for a managed toolchain.