Skip to content

Linux: private glibc ld.so.cache is not relocated, so gcc probe fails with /etc/ld.so.preload #484

Description

@ZheFeng7110

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

  1. 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.
  2. Probe hardening: derive the compiler's bound glibc library directory and include it in the compiler child environment, rather than injecting only gcc-runtime.
  3. 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.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions