11#! /usr/bin/env bash
22# Automated diagnostic for the stack-overflow detection miscompilation.
33# Runs in CI on failure; everything is printed to the job log.
4- # Compiletest deletes the run-pass exe, so we compile our own repro (which
5- # matches the failing tests) and trace it.
64set +e
75
86SYSROOT=" $PWD /build/build_sysroot/sysroot"
@@ -17,60 +15,25 @@ uname -a
1715ldd --version 2> /dev/null | head -1
1816LIB=$( ls " $STDLIB " /libstd* .so 2> /dev/null | head -1)
1917echo " libstd.so: $LIB size=$( stat -c%s " $LIB " 2> /dev/null) "
20- echo " backend: $BACKEND "
21- echo " rustc: $RUSTC "
2218
23- echo " ===================== BUILD REPRO ====================="
24- D=$( mktemp -d)
25- cat > " $D /repro.rs" << 'RS '
26- use std::hint::black_box;
27- use std::mem::MaybeUninit;
28- use std::thread;
29- use std::env;
30- #[allow(unconditional_recursion)]
31- fn recurse(a: &MaybeUninit<[u64; 1024]>) {
32- black_box(a.as_ptr() as u64);
33- let l: MaybeUninit<[u64; 1024]> = MaybeUninit::uninit();
34- recurse(&l);
35- }
36- fn overflow_recurse() { recurse(&MaybeUninit::uninit()); }
37- fn overflow_frame() {
38- const S: usize = 512 * 1024;
39- thread::Builder::new().stack_size(S).spawn(|| {
40- let l: MaybeUninit<[u8; 2 * S]> = MaybeUninit::uninit();
41- black_box(l.as_ptr() as u64);
42- }).unwrap().join().unwrap();
43- }
44- fn silent() { let b = [0u8; 1000]; black_box(b); silent(); }
45- fn main() {
46- match env::args().nth(1).as_deref() {
47- Some("child-recurse") => { thread::spawn(overflow_recurse).join().unwrap(); }
48- Some("child-frame") => overflow_frame(),
49- Some("silent-thread") => { thread::Builder::new().name("ferris".into())
50- .spawn(silent).unwrap().join().ok(); }
51- _ => panic!("need arg"),
52- }
53- }
54- RS
55- " $RUSTC " -Zcodegen-backend=" $BACKEND " --sysroot " $SYSROOT " -Cprefer-dynamic -g -o " $D /a" " $D /repro.rs"
56- echo " compiled repro: $( ls -l " $D /a" 2> /dev/null) "
57-
58- debug_one () {
59- local ARG=" $1 "
19+ # $1 = binary path, $2 = arg (the subprocess mode that overflows)
20+ debug_bin () {
21+ local BIN=" $1 " ARG=" $2 "
22+ [ -z " $BIN " ] || [ ! -x " $BIN " ] && { echo " SKIP (no binary): $BIN " ; return ; }
6023 echo " "
6124 echo " ############################################################"
62- echo " # DEBUG repro $ARG "
25+ echo " # DEBUG $BIN $ARG "
6326 echo " ############################################################"
6427
6528 echo " ----- reproduce (139=SIGSEGV/undetected-BUG, 134=SIGABRT/detected-ok) -----"
66- " $D /a " " $ARG " ; echo " exit=$? "
29+ " $BIN " " $ARG " ; echo " exit=$? "
6730
6831 echo " ----- strace: clone + sigaltstack per thread (does the SPAWNED thread set up its altstack?) -----"
69- strace -f -e trace=clone,clone3,sigaltstack,rt_sigaction " $D /a " " $ARG " 2> " $D / strace.txt"
70- grep -nE " clone|sigaltstack|rt_sigaction\((SIGSEGV|SIGBUS)" " $D / strace.txt"
71- echo " sigaltstack total: $( grep -c ' sigaltstack(' " $D / strace.txt" ) clone total: $( grep -cE ' clone[3]?\(' " $D / strace.txt" ) "
32+ strace -f -e trace=clone,clone3,sigaltstack,rt_sigaction " $BIN " " $ARG " 2> /tmp/ strace.txt
33+ grep -nE " clone|sigaltstack|rt_sigaction\((SIGSEGV|SIGBUS)" /tmp/ strace.txt
34+ echo " sigaltstack total: $( grep -c ' sigaltstack(' /tmp/ strace.txt) clone total: $( grep -cE ' clone[3]?\(' /tmp/ strace.txt) "
7235
73- echo " ----- gdb: is make_handler / set_current_info reached by the SPAWNED thread? + NEED_ALTSTACK -----"
36+ echo " ----- gdb: is make_handler / set_current_info reached by the SPAWNED thread? -----"
7437 gdb -q -batch -nx \
7538 -ex ' set pagination off' -ex ' set confirm off' \
7639 -ex ' rbreak stack_overflow.*imp.*make_handler' \
@@ -82,13 +45,30 @@ debug_one() {
8245 -ex ' printf "== HIT#4 thread=%d ==\n", $_thread' -ex ' bt 3' -ex ' continue' \
8346 -ex ' printf "== HIT#5 thread=%d ==\n", $_thread' -ex ' bt 3' -ex ' continue' \
8447 -ex ' printf "== end ==\n"' -ex ' info program' \
85- --args " $D /a " " $ARG " 2>&1 \
86- | grep -vE " Missing separate|Download failed|Reading symbols|warning: File" | head -150
48+ --args " $BIN " " $ARG " 2>&1 \
49+ | grep -vE " Missing separate|Download failed|Reading symbols|warning: File" | head -140
8750}
8851
89- debug_one " silent-thread"
90- debug_one " child-recurse"
91- debug_one " child-frame"
52+ echo " ===================== REAL COMPILETEST BINARIES ====================="
53+ OO=$( find build/rust -type f -path ' *out-of-stack/a' 2> /dev/null | head -1)
54+ SP=$( find build/rust -type f -path ' *stack-probes*/a' 2> /dev/null | head -1)
55+ echo " out-of-stack: ${OO:- <none>} "
56+ echo " stack-probes: ${SP:- <none>} "
57+ debug_bin " $OO " " silent-thread"
58+ debug_bin " $SP " " child-recurse"
59+ debug_bin " $SP " " child-frame"
60+
61+ echo " "
62+ echo " ===================== COMPARISON: freshly-built minimal repro ====================="
63+ D=$( mktemp -d)
64+ cat > " $D /repro.rs" << 'RS '
65+ use std::hint::black_box;
66+ use std::thread::Builder;
67+ fn silent() { let b = [0u8; 1000]; black_box(b); silent(); }
68+ fn main() { Builder::new().name("ferris".into()).spawn(silent).unwrap().join().ok(); }
69+ RS
70+ " $RUSTC " -Zcodegen-backend=" $BACKEND " --sysroot " $SYSROOT " -Cprefer-dynamic -o " $D /a" " $D /repro.rs" 2> /dev/null
71+ debug_bin " $D /a" " "
9272
9373echo " "
9474echo " ===================== OBJDUMP make_handler ====================="
0 commit comments