Skip to content

Commit 94dbf19

Browse files
committed
test(e2e): 166 asserted the mechanism, not the capability
166 exists for mcpp#291 and had two halves. The negative half — a plain binary must not be handed the private glibc — is still exactly right and is unchanged. The positive half required the opposite in the presence of a dlopen-reachable dependency: the payload dir HAD to be on LD_LIBRARY_PATH, "because dlopen'd libraries do not consult the executable's RUNPATH". The guard was right to exist. It stopped anyone from "fixing" #291 by deleting the entry and quietly breaking dlopen. But it pinned the mechanism rather than the capability, and the mechanism's premise was false: a dlopen() performed by the executable does consult the executable's DT_RUNPATH, and the link model already puts the payload glibc there — the artifact's RUNPATH is byte-identical with and without the environment entry. So the entry bought nothing while reaching every descendant process, which is how it became mcpp#401. The capability it was protecting now lives in 208, which asserts the dlopen actually resolves. 166 keeps the rule it is named for and now applies it to both shapes, plus one new assertion: the project's own [runtime] library_dirs entry must still be there. Only the private libc is binary-scoped; dropping ordinary runtime dirs too would be a different regression that the negative assertion alone would not catch. Full local Linux e2e on this HEAD: 202 passed, 0 failed, 8 skipped.
1 parent 19e6c85 commit 94dbf19

1 file changed

Lines changed: 38 additions & 9 deletions

File tree

tests/e2e/166_run_env_no_private_glibc.sh

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,29 @@ if printf '%s' "$line" | grep -q 'xim-x-glibc'; then
6161
exit 1
6262
fi
6363

64-
# ── The other half: when a dlopen-reachable dependency library DOES exist,
65-
# the payload dir must still be there. Without this, a later change could drop
66-
# the entry entirely and the negative assertion above would happily pass.
64+
# ── The other half. This test used to require the OPPOSITE here: with a
65+
# dlopen-reachable dependency library present, the payload dir had to BE on
66+
# LD_LIBRARY_PATH, "because dlopen'd libraries do not consult the executable's
67+
# RUNPATH". The guard was right to exist — it stopped anyone from "fixing"
68+
# mcpp#291 by deleting the entry and quietly breaking dlopen — but it asserted
69+
# the MECHANISM instead of the capability, and the mechanism was wrong:
70+
#
71+
# * a dlopen() performed by the executable DOES consult the executable's
72+
# DT_RUNPATH, and the link model already puts the payload glibc there
73+
# (measured: the artifact's RUNPATH is byte-identical with and without the
74+
# environment entry);
75+
# * so the entry bought nothing, while reaching every descendant process —
76+
# and on a payload whose GLIBC_PRIVATE needs match its own loader, that
77+
# kills /bin/sh outright (mcpp#401, glibc 2.44).
78+
#
79+
# The capability it was really protecting now lives in
80+
# 208_private_libc_stays_in_the_binary.sh, which asserts the dlopen actually
81+
# resolves and that the directory is in the artifact RUNPATH. What belongs
82+
# here is the rule this test is named for, applied to BOTH shapes: the private
83+
# libc is never handed to the process environment.
6784
GLIBC_STORE=$(ls -d "$HOME"/.mcpp/registry/data/xpkgs/xim-x-glibc/*/ 2>/dev/null | head -1)
6885
if [ -z "$GLIBC_STORE" ]; then
69-
echo "SKIP (positive half): no private glibc payload installed"
86+
echo "SKIP (second half): no private glibc payload installed"
7087
echo OK
7188
exit 0
7289
fi
@@ -85,14 +102,26 @@ library_dirs = ["runtime"]
85102
EOF
86103
cp ../pkg/src/main.cpp src/main.cpp
87104

88-
out2=$("$MCPP" run 2>&1) || { echo "FAIL: mcpp run failed (positive half)"; echo "$out2"; exit 1; }
105+
out2=$("$MCPP" run 2>&1) || { echo "FAIL: mcpp run failed (second half)"; echo "$out2"; exit 1; }
89106
line2=$(printf '%s\n' "$out2" | grep -oE 'LDLP=\[[^]]*\]' | head -1)
90107
echo "observed (with [runtime] library_dirs): $line2"
91108

92-
printf '%s' "$line2" | grep -q 'xim-x-glibc' || {
93-
echo "FAIL: a build WITH a dlopen-reachable dependency library dir lost the"
94-
echo " private glibc payload from LD_LIBRARY_PATH. dlopen'd libraries do"
95-
echo " not consult the executable's RUNPATH, so they need it here."
109+
if printf '%s' "$line2" | grep -q 'xim-x-glibc'; then
110+
echo "FAIL: a build WITH a dlopen-reachable dependency library dir still put"
111+
echo " the private glibc payload on LD_LIBRARY_PATH. That variable"
112+
echo " reaches every descendant process, including host shells the host"
113+
echo " loader loads — see mcpp#401."
114+
echo " $line2"
115+
exit 1
116+
fi
117+
118+
# The project's own runtime dir is a plain shared-library directory with no
119+
# loader coupling, so it keeps its environment scope. Losing it here would mean
120+
# the entry was dropped wholesale rather than narrowed to the private libc.
121+
printf '%s' "$line2" | grep -q 'runtime' || {
122+
echo "FAIL: the project's own [runtime] library_dirs entry disappeared too."
123+
echo " Only the private libc is binary-scoped; ordinary dependency"
124+
echo " runtime dirs still belong in the environment."
96125
echo " $line2"
97126
exit 1; }
98127

0 commit comments

Comments
 (0)