_testmark_call: run library code under set -u, restoring the caller's setting.
commit ecf703ab46c10f0577ad289dea5626afe49009de · parent 1fcf6f35d8
· browse this tree
Ximianth, 2026-10-23 23:31:57 UTC
A library bug that reads an unset variable now exits the script loudly, whatever the caller's own setting. `local -` (bash 4.4+) restores the caller's set options when the wrapper returns. The suite already ran every library call under the caller's set -u, and a scratch run of the parse, API, and testdata scripts with the caller's set -u off passes too, so nothing in the library trips it.
diff --git a/lib/testmark.bash b/lib/testmark.bash index 5e80e44..f5789b5 100644 --- a/lib/testmark.bash +++ b/lib/testmark.bash @@ -18,10 +18,12 @@ source "${BASH_SOURCE[0]%/*}/testmark/document.bash" ## Runs an implementation function in a known environment, whatever the caller's settings. ## ## - `LC_ALL=C`: string operations work on bytes, and `[[:space:]]` is exactly ASCII whitespace. +## - `set -u`: a library bug that reads an unset variable exits the script loudly. `local -` restores the caller's setting. ## - `nocasematch` off: pattern matches are exact. It's restored afterwards, since `local -` doesn't cover shopts. ## - The `||` list: inside it, the caller's `set -e` and ERR trap can't fire on the implementation's ordinary nonzero statuses. _testmark_call() { - local LC_ALL=C _testmark_st=0 _testmark_nocase= + local - LC_ALL=C _testmark_st=0 _testmark_nocase= + set -u case ":$BASHOPTS:" in *:nocasematch:*) _testmark_nocase=1 && shopt -u nocasematch ;; esac "$@" || _testmark_st=$? [[ -z $_testmark_nocase ]] || shopt -s nocasematch diff --git a/tests/test-caller-env.sh b/tests/test-caller-env.sh index 1d6e317..d69f237 100755 --- a/tests/test-caller-env.sh +++ b/tests/test-caller-env.sh @@ -28,4 +28,11 @@ testmark_body doc nope 2>/dev/null || rc=$? expect_eq "errexit: an error returns, to a caller that checks" "$rc" 1 expect_eq "the ERR trap never fired" "$err_trap_fired" 0 +# The library turns on set -u for its own code only. +set +u +before=$- +testmark_body doc x >/dev/null +expect_eq "set -u: a caller without it still lacks it after a call" "$-" "$before" +set -u + exit "$RESULT"