Files
httrack/tests/151_bash-shell-validate.test
Xavier Roche a3e1d3dd40 3.49.16-1 fails to build on four Debian architectures (#1017)
* Fix the four 3.49.16-1 Debian buildd failures

armhf and loong64 cannot unwind out of the frame that faulted on the guard
page, so 180_crash-stack-overflow saw no repeated address and read that as
"never recursed". Judge the recursion only where the report is deeper than
the ordinary-fault control, which keeps the mutant that stopped recursing
failing on x86-64.

hppa needs ~150s per configure run, so 151_bash-shell-validate and
196_install-rpath-gates blew the 600s per-test budget meant to catch a
wedge. They now pace themselves against that budget and skip out rather
than take the build down with them.

hurd-i386 has a network, so the online crawl probe said yes and the crawls
then failed on DNS. Debian Policy 4.9 forbids network access during a build
anyway, so stop asking for it. While there, install crawl-test.sh's traps
one at a time: SIGSTKFLT is Linux-only and its absence made the whole trap
command complain on every Hurd run.

Signed-off-by: Xavier Roche <xroche@gmail.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>

* Close two vacuity holes the review found in the new gates

Test 180 compared the stack trace against the segv control's depth, but the
two call chains differ by a frame that only -O2 tail-calls away: at -O0, -O1
and -Og the control is 12 frames and a crash_stack that faults in its own
body is 11, so that mutant slipped through the gate. Use an absolute floor
instead. The handler contributes 3 frames and any non-recursing crash_stack
still unwinds 11, so 6 sits clear of both.

skip_if_out_of_budget projected the step that just ran across every step
left. Test 196 shares one config.cache, so its first step costs several
times the rest and the projection over-estimated by ~2.5x, skipping runs
that fit -- including the hppa case this is for. Look one step ahead
instead, at 1.5x the last step's cost.

Both gates now have coverage in 105_suite-timeout.test: dropping the export
or the skip fails it.

Signed-off-by: Xavier Roche <xroche@gmail.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>

---------

Signed-off-by: Xavier Roche <xroche@gmail.com>
Signed-off-by: Xavier Roche <roche@httrack.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 07:19:09 +00:00

177 lines
6.2 KiB
Bash

#!/bin/bash
#
# An absolute BASH_SHELL is taken verbatim by AC_PATH_PROGS and a relative one is dropped
# for the search result, so configure has to check what it ends up with: BASH_SHELL=/bin/sh
# otherwise puts #895 back and only shows up at "make check" or "make deb" (#908).
set -euo pipefail
testdir=$(cd "$(dirname "$0")" && pwd)
# shellcheck source=tests/testlib.sh
. "${testdir}/testlib.sh"
sh=${BASH_SHELL:-}
test -n "$sh" || {
echo "BASH_SHELL is empty; tests/Makefile.am must export the configured value" >&2
exit 1
}
configure="${abs_top_srcdir:-}/configure"
test -r "$configure" || {
echo "no configure script at $configure; tests/Makefile.am must export abs_top_srcdir" >&2
exit 1
}
tmp=$(mktemp -d)
cleanup() {
# O_RDWR never blocks, and it releases whatever is left stuck opening the FIFO for read.
exec 9<>"$tmp/fifo" && exec 9>&-
rm -rf "$tmp"
}
trap 'set +e; cleanup' EXIT
trap 'set +e; cleanup; exit 1' HUP INT TERM
# Symlink farm, not the real srcdir: an in-tree config.status makes autoconf refuse it.
mkdir "$tmp/src"
for f in "$abs_top_srcdir"/*; do
case "${f##*/}" in
config.status | config.log | config.h | stamp-h1 | Makefile) continue ;;
esac
ln -s "$f" "$tmp/src/"
done
mkdir "$tmp/notexec" "$tmp/with space" "$tmp/fakebin"
: >"$tmp/notexec/bash"
chmod 644 "$tmp/notexec/bash"
ln -s "$sh" "$tmp/mybash"
ln -s "$sh" "$tmp/with space/bash"
ln -s "$sh" "$tmp/sh" # bash invoked as "sh" enters POSIX mode
# A "bash" the PATH search will find first, and that answers -c like any other shell.
printf '#!/bin/sh\nexec /bin/sh "$@"\n' >"$tmp/fakebin/bash"
chmod 755 "$tmp/fakebin/bash"
# Executable to "test -x", but bash blocks in open() on one it failed to exec.
mkfifo "$tmp/fifo"
chmod 755 "$tmp/fifo"
n=0
cases=16 # reject/accept calls below; pinned again once they have all run
status=0
log=
rundir=
run() { # run <label> <env argument>...
local label=$1 began=$SECONDS
shift
n=$((n + 1))
rundir="$tmp/run$n"
mkdir "$rundir"
status=0
# Capped: configure executes the candidate, and a hang wedges "make check" with no output
# at all. Polled, not a backgrounded "sleep" watchdog, which outlives the run it guards.
(cd "$rundir" && env "$@" bash "$tmp/src/configure" --disable-https) \
>"$rundir/log" 2>&1 &
local pid=$! waited=0
while test "$waited" -lt 300 && kill -0 "$pid" 2>/dev/null; do
sleep 1
waited=$((waited + 1))
done
if kill -0 "$pid" 2>/dev/null; then
kill -9 "$pid" 2>/dev/null
echo "configure did not return within ${waited}s for $label" >&2
tail -5 "$rundir/log" >&2
exit 1
fi
wait "$pid" || status=$?
log=$(cat "$rundir/log")
echo "run $n ($label): exit $status"
skip_if_out_of_budget "$((cases - n))" "$((SECONDS - began))"
}
reject() { # reject <label> <expected message> <env argument>...
local label=$1 want=$2
shift 2
run "$label" "$@"
test "$status" -ne 0 || {
echo "configure accepted $label" >&2
exit 1
}
grep -q "$want" <<<"$log" || {
echo "$label rejected without '$want':" >&2
tail -5 <<<"$log" >&2
exit 1
}
}
# accept <label> <expected $(BASH_SHELL), "" for any> <expected message, "" for none> <env argument>...
accept() {
local label=$1 path=$2 want=$3
shift 3
run "$label" "$@"
test "$status" -eq 0 || {
echo "configure rejected $label (exit $status):" >&2
tail -10 <<<"$log" >&2
exit 1
}
got=$(sed -n 's/^BASH_SHELL = //p' "$rundir/Makefile")
test -n "$got" || {
echo "$label configured, but the Makefile carries no BASH_SHELL" >&2
exit 1
}
if test -n "$path" && test "$got" != "$path"; then
echo "$label reached the Makefile as $got" >&2
exit 1
fi
if test -n "$want"; then
grep -q "$want" <<<"$log" || {
echo "$label configured without '$want':" >&2
tail -5 <<<"$log" >&2
exit 1
}
fi
}
reject relative 'BASH_SHELL must be an absolute path' BASH_SHELL=relbash
notreg='is not an executable regular file'
reject missing "$notreg" "BASH_SHELL=$tmp/missing/bash"
reject non-executable "$notreg" "BASH_SHELL=$tmp/notexec/bash"
# "test -x" passes a FIFO, and configure then hangs forever instead of rejecting it (#922).
reject fifo "$notreg" "BASH_SHELL=$tmp/fifo"
reject sh-mode 'is a bash in POSIX sh-mode' "BASH_SHELL=$tmp/sh"
# The #908 case: dash on Linux, bash in sh-mode on macOS, unusable either way. The spoofed
# BASH_VERSION is what an ordinary shell echoes straight back, so it cannot be the probe.
reject /bin/sh 'BASH_SHELL=/bin/sh is ' BASH_SHELL=/bin/sh BASH_VERSION=9.9
# make splits the value on whitespace, cuts it at a '#' and expands a '$', and no Makefile
# quotes $(BASH_SHELL).
meta='must not contain shell or make metacharacters'
reject space "$meta" "BASH_SHELL=$tmp/with space/bash"
reject semicolon "$meta" 'BASH_SHELL=/opt/a;b/bash'
# shellcheck disable=SC2016 # the '$' has to reach configure unexpanded
reject dollar "$meta" 'BASH_SHELL=/opt/a$b/bash'
reject hash "$meta" 'BASH_SHELL=/opt/a#b/bash'
# An environment in POSIX mode leaves no path that could pass, so the message must blame it
# and not the shell.
reject posix-env 'POSIXLY_CORRECT or SHELLOPTS' "BASH_SHELL=$sh" POSIXLY_CORRECT=1
# Both at once: clearing the variable would still leave a bash invoked as sh, so the second
# probe has to decide which one to blame instead of reading the environment.
reject sh-mode-in-posix-env "BASH_SHELL=$tmp/sh is a bash in POSIX sh-mode" \
"BASH_SHELL=$tmp/sh" POSIXLY_CORRECT=1
if grep -q 'POSIXLY_CORRECT or SHELLOPTS' <<<"$log"; then
echo "a bash invoked as sh was blamed on the environment:" >&2
tail -5 <<<"$log" >&2
exit 1
fi
accept override "$tmp/mybash" '' "BASH_SHELL=$tmp/mybash"
accept empty '' '' BASH_SHELL=
# No override: an unusable bash is a warning, so a box that has none still builds.
accept searched "$tmp/fakebin/bash" 'no usable bash found' -u BASH_SHELL "PATH=$tmp/fakebin:$PATH"
accept searched-posix-env '' 'POSIXLY_CORRECT or SHELLOPTS' -u BASH_SHELL POSIXLY_CORRECT=1
test "$n" -eq "$cases" || {
echo "ran $n cases, not the $cases the budget is paced against" >&2
exit 1
}
echo "configure validated $n BASH_SHELL values"