Skip to content

Commit abc4fec

Browse files
committed
Capture an lld --reproduce tar and environment discriminators on crash
Identical inputs pass locally and on most VMs but crash 100% consistently on affected VMs, so the trigger is environmental (mmap_rnd_bits=28 on all VMs, green and crashing, so ASLR config is ruled out too). Settle it with lld's built-in reproducer: --reproduce streams every input it opens into a tar that survives the crash; replaying that tar locally either gives a local repro or proves the environment dependency. Also try the replay under env -i and taskset -c 0 to rule environment variables and thread scheduling in or out, and hash all link inputs on every run (including green ones) so cross-run input identity is measured, not assumed.
1 parent 2bccd85 commit abc4fec

1 file changed

Lines changed: 41 additions & 4 deletions

File tree

.github/workflows/debug-zig-crash.yml

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,15 @@ jobs:
8787
ulimit -c unlimited
8888
bin/spp build --phpv=8.5 --type=deb --packages=cli
8989
90+
- name: Hash link inputs
91+
if: ${{ always() && steps.build.outcome != 'cancelled' }}
92+
shell: bash
93+
run: |
94+
mkdir -p diag
95+
find source/php-src -name '*.o' -type f 2>/dev/null | sort | xargs -r sha256sum > diag/object-hashes.txt || true
96+
sha256sum buildroot/lib/*.a >> diag/object-hashes.txt 2>/dev/null || true
97+
wc -l diag/object-hashes.txt
98+
9099
- name: Re-run failing make with diagnostics
91100
if: ${{ steps.build.outcome == 'failure' }}
92101
shell: bash
@@ -145,11 +154,31 @@ jobs:
145154
gdb -q -batch -ex 'set pagination off' -ex run -ex 'info registers' -ex 'x/8i $rip' \
146155
-ex bt -ex 'thread apply all bt' --args "${LLD[@]}" > ../../diag/gdb-live.txt 2>&1 || true
147156
tail -40 ../../diag/gdb-live.txt || true
148-
# 2) which LLVM pass dies: opt-bisect logs every pass to stderr until the crash
157+
# 2) pack a byte-exact reproducer: lld streams every input it opens into the
158+
# tar, so it survives the crash; replaying it locally settles whether the
159+
# trigger is in the inputs or in the runner environment
160+
rm -f sapi/cli/php
161+
"${LLD[@]}" --reproduce=../../lld-repro.tar > /dev/null 2>&1 || true
162+
ls -la ../../lld-repro.tar || true
163+
zstd -T0 --rm ../../lld-repro.tar -o ../../lld-repro.tar.zst || true
164+
# 3) environment discriminators on the affected VM
165+
rm -f sapi/cli/php
166+
if env -i PATH=/usr/bin:/bin HOME=/tmp "${LLD[@]}" > /dev/null 2>&1 && [ -f sapi/cli/php ]; then
167+
echo "ENV-I REPLAY OK (crash depends on environment variables)" | tee -a ../../diag/mitigations.txt
168+
else
169+
echo "ENV-I REPLAY FAIL (environment variables ruled out)" | tee -a ../../diag/mitigations.txt
170+
fi
171+
rm -f sapi/cli/php
172+
if taskset -c 0 "${LLD[@]}" > /dev/null 2>&1 && [ -f sapi/cli/php ]; then
173+
echo "TASKSET-1CPU REPLAY OK (crash depends on thread scheduling)" | tee -a ../../diag/mitigations.txt
174+
else
175+
echo "TASKSET-1CPU REPLAY FAIL (single-cpu still crashes)" | tee -a ../../diag/mitigations.txt
176+
fi
177+
# 4) which LLVM pass dies: opt-bisect logs every pass to stderr until the crash
149178
rm -f sapi/cli/php
150179
"${LLD[@]}" -mllvm -opt-bisect-limit=2147483647 2>&1 >/dev/null | tail -n 500 > ../../diag/bisect-tail.txt || true
151180
tail -3 ../../diag/bisect-tail.txt || true
152-
# 3) lld-level mitigations (for --lto-O*/--threads the last occurrence wins)
181+
# 5) lld-level mitigations (for --lto-O*/--threads the last occurrence wins)
153182
for extra in '--lto-O2' '--lto-O1' '--lto-O0' '--threads=1'; do
154183
rm -f sapi/cli/php
155184
if "${LLD[@]}" $extra > /dev/null 2>&1 && [ -f sapi/cli/php ]; then
@@ -158,7 +187,7 @@ jobs:
158187
echo "LLD MITIGATION FAIL: $extra" | tee -a ../../diag/mitigations.txt
159188
fi
160189
done
161-
# 4) production-path candidate: -O0 on the link line only; zig cc maps the link-time
190+
# 6) production-path candidate: -O0 on the link line only; zig cc maps the link-time
162191
# -O level to lld's --lto-O, and EXTRA_LDFLAGS_PROGRAM lands after EXTRA_CFLAGS' -O3
163192
MAKE_O0=$(printf '%s' "$MAKE_CMD" | sed "s|EXTRA_LDFLAGS_PROGRAM='\([^']*\)'|EXTRA_LDFLAGS_PROGRAM='\1 -O0'|")
164193
rm -f sapi/cli/php
@@ -167,7 +196,7 @@ jobs:
167196
else
168197
echo "MAKE MITIGATION FAIL: EXTRA_LDFLAGS_PROGRAM += -O0" | tee -a ../../diag/mitigations.txt
169198
fi
170-
# 5) the mixed-LTO hypothesis: buildroot libs are ThinLTO bitcode (-flto=thin) but
199+
# 7) the mixed-LTO hypothesis: buildroot libs are ThinLTO bitcode (-flto=thin) but
171200
# the trailing -flto makes PHP objects full-LTO bitcode; the crash sits in LLVM's
172201
# prevailing-symbol resolution that reconciles the two. Rebuild PHP thin-only.
173202
MAKE_THIN=$(printf '%s' "$MAKE_CMD" | sed "s/ -flto\([ ']\)/\1/g")
@@ -189,6 +218,14 @@ jobs:
189218
diag
190219
log
191220
221+
- name: Upload lld reproducer
222+
if: ${{ always() }}
223+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
224+
with:
225+
name: lld-repro
226+
path: lld-repro.tar.zst
227+
if-no-files-found: ignore
228+
192229
- name: Report result
193230
if: ${{ always() }}
194231
run: |

0 commit comments

Comments
 (0)