test-lib: avoid accidental globbing in match_pattern_list()

We have a custom match_pattern_list() function which we use for matching
test names (like "t1234") against glob-like patterns (like "t1???") for
$GIT_SKIP_TESTS, --verbose-only, etc.

Those patterns may have multiple whitespace-separated elements (e.g.,
"t0* t1234 t5?78"). The callers of match_pattern_list thus pass the
strings unquoted, so that the shell does the usual field-splitting into
separate arguments.

But this also means the shell will do the usual globbing for each
argument, which can result in us seeing an expansion based on what's in
the filesystem, rather than the real pattern. For example, if I have the
path "t5000" in the filesystem, and you feed the pattern "t?000", that
_should_ match the string "t0000", but it won't after the shell has
expanded it to "t5000".

This has been a bug ever since that function was introduced. But it
didn't usually trigger since we typically use the function inside the
trash directory, which has a very limited set of files that are unlikely
to match. It became a lot easier to trigger after edc23840b0 (test-lib:
bring $remove_trash out of retirement, 2021-05-10), because now we match
$GIT_SKIP_TESTS before even entering the trash directory. So the t5000
example above can be seen with:

  GIT_SKIP_TESTS=t?000 ./t0000-basic.sh

which should skip all tests but doesn't.

We can fix this by using "set -f" to ask the shell not to glob (which is
in POSIX, so should hopefully be portable enough). We only want to do
this in a subshell (to avoid polluting the rest of the script), which
means we need to get the whole string intact into the match_pattern_list
function by quoting it. Arguably this is a good idea anyway, since it
makes it much more obvious that we intend to split, and it's not simply
sloppy scripting.

Diagnosed-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Jeff King 2021-06-16 06:23:07 -04:00 committed by Junio C Hamano
parent 670b81a890
commit 560bf51892

View file

@ -732,14 +732,24 @@ match_pattern_list () {
arg="$1"
shift
test -z "$*" && return 1
for pattern_
do
case "$arg" in
$pattern_)
return 0
esac
done
return 1
# We need to use "$*" to get field-splitting, but we want to
# disable globbing, since we are matching against an arbitrary
# $arg, not what's in the filesystem. Using "set -f" accomplishes
# that, but we must do it in a subshell to avoid impacting the
# rest of the script. The exit value of the subshell becomes
# the function's return value.
(
set -f
for pattern_ in $*
do
case "$arg" in
$pattern_)
exit 0
;;
esac
done
exit 1
)
}
match_test_selector_list () {
@ -848,7 +858,7 @@ maybe_teardown_verbose () {
last_verbose=t
maybe_setup_verbose () {
test -z "$verbose_only" && return
if match_pattern_list $test_count $verbose_only
if match_pattern_list $test_count "$verbose_only"
then
exec 4>&2 3>&1
# Emit a delimiting blank line when going from
@ -878,7 +888,7 @@ maybe_setup_valgrind () {
return
fi
GIT_VALGRIND_ENABLED=
if match_pattern_list $test_count $valgrind_only
if match_pattern_list $test_count "$valgrind_only"
then
GIT_VALGRIND_ENABLED=t
fi
@ -1006,7 +1016,7 @@ test_finish_ () {
test_skip () {
to_skip=
skipped_reason=
if match_pattern_list $this_test.$test_count $GIT_SKIP_TESTS
if match_pattern_list $this_test.$test_count "$GIT_SKIP_TESTS"
then
to_skip=t
skipped_reason="GIT_SKIP_TESTS"
@ -1346,7 +1356,7 @@ fi
remove_trash=
this_test=${0##*/}
this_test=${this_test%%-*}
if match_pattern_list "$this_test" $GIT_SKIP_TESTS
if match_pattern_list "$this_test" "$GIT_SKIP_TESTS"
then
say_color info >&3 "skipping test $this_test altogether"
skip_all="skip all tests in $this_test"