Merge branch 'ab/leak-check'

Extend SANITIZE=leak checking and declare more tests "currently leak-free".

* ab/leak-check:
  CI: use "GIT_TEST_SANITIZE_LEAK_LOG=true" in linux-leaks
  upload-pack: fix a memory leak in create_pack_file()
  leak tests: mark passing SANITIZE=leak tests as leak-free
  leak tests: don't skip some tests under SANITIZE=leak
  test-lib: have the "check" mode for SANITIZE=leak consider leak logs
  test-lib: add a GIT_TEST_PASSING_SANITIZE_LEAK=check mode
  test-lib: simplify by removing test_external
  tests: move copy/pasted PERL + Test::More checks to a lib-perl.sh
  t/Makefile: don't remove test-results in "clean-except-prove-cache"
  test-lib: add a SANITIZE=leak logging mode
  t/README: reword the "GIT_TEST_PASSING_SANITIZE_LEAK" description
  test-lib: add a --invert-exit-code switch
  test-lib: fix GIT_EXIT_OK logic errors, use BAIL_OUT
  test-lib: don't set GIT_EXIT_OK before calling test_atexit_handler
  test-lib: use $1, not $@ in test_known_broken_{ok,failure}_
This commit is contained in:
Junio C Hamano 2022-08-12 13:19:08 -07:00
commit 657c7403a3
57 changed files with 408 additions and 230 deletions

View File

@ -276,6 +276,7 @@ linux-musl)
linux-leaks)
export SANITIZE=leak
export GIT_TEST_PASSING_SANITIZE_LEAK=true
export GIT_TEST_SANITIZE_LEAK_LOG=true
;;
esac

View File

@ -3,16 +3,9 @@
cd ../../../t
test_description='git-credential-netrc'
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-perl.sh
if ! test_have_prereq PERL; then
skip_all='skipping perl interface tests, perl not available'
test_done
fi
perl -MTest::More -e 0 2>/dev/null || {
skip_all="Perl Test::More unavailable, skipping test"
test_done
}
skip_all_if_no_Test_More
# set up test repository
@ -20,13 +13,10 @@
'set up test repository' \
'git config --add gpg.program test.git-config-gpg'
# The external test will outputs its own plan
test_external_has_tap=1
export PERL5LIB="$GITPERLLIB"
test_external \
'git-credential-netrc' \
test_expect_success 'git-credential-netrc' '
perl "$GIT_BUILD_DIR"/contrib/credential/netrc/test.pl
'
test_done
)

View File

@ -42,7 +42,7 @@ $(T):
@echo "*** $@ ***"; GIT_CONFIG=.git/config '$(SHELL_PATH_SQ)' $@ $(GIT_TEST_OPTS)
clean-except-prove-cache:
$(RM) -r 'trash directory'.* '$(TEST_RESULTS_DIRECTORY_SQ)'
$(RM) -r 'trash directory'.*
$(RM) -r valgrind/bin
clean: clean-except-prove-cache

View File

@ -47,7 +47,7 @@ pre-clean:
$(RM) -r '$(TEST_RESULTS_DIRECTORY_SQ)'
clean-except-prove-cache:
$(RM) -r 'trash directory'.* '$(TEST_RESULTS_DIRECTORY_SQ)'
$(RM) -r 'trash directory'.*
$(RM) -r valgrind/bin
clean: clean-except-prove-cache

View File

@ -62,7 +62,7 @@ pre-clean:
$(RM) -r '$(TEST_RESULTS_DIRECTORY_SQ)'
clean-except-prove-cache: clean-chainlint
$(RM) -r 'trash directory'.* '$(TEST_RESULTS_DIRECTORY_SQ)'
$(RM) -r 'trash directory'.*
$(RM) -r valgrind/bin
clean: clean-except-prove-cache

View File

@ -366,12 +366,47 @@ excluded as so much relies on it, but this might change in the future.
GIT_TEST_SPLIT_INDEX=<boolean> forces split-index mode on the whole
test suite. Accept any boolean values that are accepted by git-config.
GIT_TEST_PASSING_SANITIZE_LEAK=<boolean> when compiled with
SANITIZE=leak will run only those tests that have whitelisted
themselves as passing with no memory leaks. Tests can be whitelisted
by setting "TEST_PASSES_SANITIZE_LEAK=true" before sourcing
"test-lib.sh" itself at the top of the test script. This test mode is
used by the "linux-leaks" CI target.
GIT_TEST_PASSING_SANITIZE_LEAK=true skips those tests that haven't
declared themselves as leak-free by setting
"TEST_PASSES_SANITIZE_LEAK=true" before sourcing "test-lib.sh". This
test mode is used by the "linux-leaks" CI target.
GIT_TEST_PASSING_SANITIZE_LEAK=check checks that our
"TEST_PASSES_SANITIZE_LEAK=true" markings are current. Rather than
skipping those tests that haven't set "TEST_PASSES_SANITIZE_LEAK=true"
before sourcing "test-lib.sh" this mode runs them with
"--invert-exit-code". This is used to check that there's a one-to-one
mapping between "TEST_PASSES_SANITIZE_LEAK=true" and those tests that
pass under "SANITIZE=leak". This is especially useful when testing a
series that fixes various memory leaks with "git rebase -x".
GIT_TEST_SANITIZE_LEAK_LOG=true will log memory leaks to
"test-results/$TEST_NAME.leak/trace.*" files. The logs include a
"dedup_token" (see +"ASAN_OPTIONS=help=1 ./git") and other options to
make logs +machine-readable.
With GIT_TEST_SANITIZE_LEAK_LOG=true we'll look at the leak logs
before exiting and exit on failure if the logs showed that we had a
memory leak, even if the test itself would have otherwise passed. This
allows us to catch e.g. missing &&-chaining. This is especially useful
when combined with "GIT_TEST_PASSING_SANITIZE_LEAK", see below.
GIT_TEST_PASSING_SANITIZE_LEAK=check when combined with "--immediate"
will run to completion faster, and result in the same failing
tests. The only practical reason to run
GIT_TEST_PASSING_SANITIZE_LEAK=check without "--immediate" is to
combine it with "GIT_TEST_SANITIZE_LEAK_LOG=true". If we stop at the
first failing test case our leak logs won't show subsequent leaks we
might have run into.
GIT_TEST_PASSING_SANITIZE_LEAK=(true|check) will not catch all memory
leaks unless combined with GIT_TEST_SANITIZE_LEAK_LOG=true. Some tests
run "git" (or "test-tool" etc.) without properly checking the exit
code, or git will invoke itself and fail to ferry the abort() exit
code to the original caller. When the two modes are combined we'll
look at the "test-results/$TEST_NAME.leak/trace.*" files at the end of
the test run to see if had memory leaks which the test itself didn't
catch.
GIT_TEST_PROTOCOL_VERSION=<n>, when set, makes 'protocol.version'
default to n.
@ -935,32 +970,6 @@ see test-lib-functions.sh for the full list and their options.
test_done
fi
- test_external [<prereq>] <message> <external> <script>
Execute a <script> with an <external> interpreter (like perl). This
was added for tests like t9700-perl-git.sh which do most of their
work in an external test script.
test_external \
'GitwebCache::*FileCache*' \
perl "$TEST_DIRECTORY"/t9503/test_cache_interface.pl
If the test is outputting its own TAP you should set the
test_external_has_tap variable somewhere before calling the first
test_external* function. See t9700-perl-git.sh for an example.
# The external test will outputs its own plan
test_external_has_tap=1
- test_external_without_stderr [<prereq>] <message> <external> <script>
Like test_external but fail if there's any output on stderr,
instead of checking the exit code.
test_external_without_stderr \
'Perl API' \
perl "$TEST_DIRECTORY"/t9700/test.pl
- test_expect_code <exit-code> <command>
Run a command and ensure that it exits with the given exit code.

19
t/lib-perl.sh Normal file
View File

@ -0,0 +1,19 @@
# Copyright (c) 2022 Ævar Arnfjörð Bjarmason
test_lazy_prereq PERL_TEST_MORE '
perl -MTest::More -e 0
'
skip_all_if_no_Test_More () {
if ! test_have_prereq PERL
then
skip_all='skipping perl interface tests, perl not available'
test_done
fi
if ! test_have_prereq PERL_TEST_MORE
then
skip_all="Perl Test::More unavailable, skipping test"
test_done
fi
}

View File

@ -578,6 +578,78 @@ test_expect_success 'subtest: --run invalid range end' '
EOF_ERR
'
test_expect_success 'subtest: --invert-exit-code without --immediate' '
run_sub_test_lib_test_err full-pass \
--invert-exit-code &&
check_sub_test_lib_test_err full-pass \
<<-\EOF_OUT 3<<-EOF_ERR
ok 1 - passing test #1
ok 2 - passing test #2
ok 3 - passing test #3
# passed all 3 test(s)
1..3
# faking up non-zero exit with --invert-exit-code
EOF_OUT
EOF_ERR
'
test_expect_success 'subtest: --invert-exit-code with --immediate: all passed' '
run_sub_test_lib_test_err full-pass \
--invert-exit-code --immediate &&
check_sub_test_lib_test_err full-pass \
<<-\EOF_OUT 3<<-EOF_ERR
ok 1 - passing test #1
ok 2 - passing test #2
ok 3 - passing test #3
# passed all 3 test(s)
1..3
# faking up non-zero exit with --invert-exit-code
EOF_OUT
EOF_ERR
'
test_expect_success 'subtest: --invert-exit-code without --immediate: partial pass' '
run_sub_test_lib_test partial-pass \
--invert-exit-code &&
check_sub_test_lib_test partial-pass <<-\EOF
ok 1 - passing test #1
not ok 2 - # TODO induced breakage (--invert-exit-code): failing test #2
# false
ok 3 - passing test #3
# failed 1 among 3 test(s)
1..3
# faked up failures as TODO & now exiting with 0 due to --invert-exit-code
EOF
'
test_expect_success 'subtest: --invert-exit-code with --immediate: partial pass' '
run_sub_test_lib_test partial-pass \
--invert-exit-code --immediate &&
check_sub_test_lib_test partial-pass \
<<-\EOF_OUT 3<<-EOF_ERR
ok 1 - passing test #1
not ok 2 - # TODO induced breakage (--invert-exit-code): failing test #2
# false
1..2
# faked up failures as TODO & now exiting with 0 due to --invert-exit-code
EOF_OUT
EOF_ERR
'
test_expect_success 'subtest: --invert-exit-code --immediate: got a failure' '
run_sub_test_lib_test partial-pass \
--invert-exit-code --immediate &&
check_sub_test_lib_test_err partial-pass \
<<-\EOF_OUT 3<<-EOF_ERR
ok 1 - passing test #1
not ok 2 - # TODO induced breakage (--invert-exit-code): failing test #2
# false
1..2
# faked up failures as TODO & now exiting with 0 due to --invert-exit-code
EOF_OUT
EOF_ERR
'
test_expect_success 'subtest: tests respect prerequisites' '
write_and_run_sub_test_lib_test prereqs <<-\EOF &&

View File

@ -65,7 +65,7 @@ test_expect_success 'check commit-tree' '
test_path_is_file "$REAL/objects/$(objpath $SHA)"
'
test_expect_success !SANITIZE_LEAK 'check rev-list' '
test_expect_success 'check rev-list' '
git update-ref "HEAD" "$SHA" &&
git rev-list HEAD >actual &&
echo $SHA >expected &&

View File

@ -31,7 +31,7 @@ test_expect_success WRITE_TREE_OUT 'write-tree output on unwritable repository'
test_cmp expect out.write-tree
'
test_expect_success POSIXPERM,SANITY,!SANITIZE_LEAK 'commit should notice unwritable repository' '
test_expect_success POSIXPERM,SANITY 'commit should notice unwritable repository' '
test_when_finished "chmod 775 .git/objects .git/objects/??" &&
chmod a-w .git/objects .git/objects/?? &&
test_must_fail git commit -m second 2>out.commit

View File

@ -2,6 +2,7 @@
test_description='CRLF conversion all combinations'
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
compare_files () {

View File

@ -5,6 +5,7 @@
test_description='reftable unittests'
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'unittests' '

View File

@ -2,6 +2,7 @@
test_description='verify safe.directory checks'
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
GIT_TEST_ASSUME_DIFFERENT_OWNER=1

View File

@ -5,6 +5,7 @@ test_description='Various filesystem issues'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
auml=$(printf '\303\244')

View File

@ -1,6 +1,8 @@
#!/bin/sh
test_description='Testing the various Bloom filter computations in bloom.c'
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'compute unseeded murmur3 hash for empty string' '

View File

@ -7,22 +7,12 @@ test_description='Perl gettext interface (Git::I18N)'
TEST_PASSES_SANITIZE_LEAK=true
. ./lib-gettext.sh
. "$TEST_DIRECTORY"/lib-perl.sh
skip_all_if_no_Test_More
if ! test_have_prereq PERL; then
skip_all='skipping perl interface tests, perl not available'
test_done
fi
perl -MTest::More -e 0 2>/dev/null || {
skip_all="Perl Test::More unavailable, skipping test"
test_done
}
# The external test will outputs its own plan
test_external_has_tap=1
test_external_without_stderr \
'Perl Git::I18N API' \
perl "$TEST_DIRECTORY"/t0202/test.pl
test_expect_success 'run t0202/test.pl to test Git::I18N.pm' '
"$PERL_PATH" "$TEST_DIRECTORY"/t0202/test.pl 2>stderr &&
test_must_be_empty stderr
'
test_done

View File

@ -5,6 +5,7 @@ test_description='test main ref store api'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
RUN="test-tool ref-store main"

View File

@ -5,6 +5,7 @@ test_description='test worktree ref store api'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
RWT="test-tool ref-store worktree:wt"

View File

@ -4,6 +4,7 @@ test_description='Test reflog display routines'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '

View File

@ -132,7 +132,7 @@ test_expect_success 'use --default' '
test_must_fail git rev-parse --verify --default bar
'
test_expect_success !SANITIZE_LEAK 'main@{n} for various n' '
test_expect_success 'main@{n} for various n' '
git reflog >out &&
N=$(wc -l <out) &&
Nm1=$(($N-1)) &&

View File

@ -5,6 +5,7 @@
test_description='racy split index'
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '

View File

@ -3,6 +3,7 @@
test_description='basic checkout-index tests
'
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'checkout-index --gobbledegook' '

View File

@ -7,6 +7,7 @@ Ensures that checkout -m on a resolved file restores the conflicted file'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '

View File

@ -17,6 +17,7 @@ outside the repository. Two instances for which this can occur are tested:
repository can be added to the index.
'
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success '1a: setup--config worktree' '

View File

@ -103,7 +103,7 @@ test_expect_success 'git ls-files --others with various exclude options.' '
test_cmp expect output
'
test_expect_success !SANITIZE_LEAK 'restore gitignore' '
test_expect_success 'restore gitignore' '
git checkout --ignore-skip-worktree-bits $allignores &&
rm .git/index
'
@ -126,7 +126,7 @@ cat > expect << EOF
# three/
EOF
test_expect_success !SANITIZE_LEAK 'git status honors core.excludesfile' \
test_expect_success 'git status honors core.excludesfile' \
'test_cmp expect output'
test_expect_success 'trailing slash in exclude allows directory match(1)' '

View File

@ -2,6 +2,7 @@
test_description='git ls-files --deduplicate test'
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '

View File

@ -51,7 +51,7 @@ test_expect_success 'creating many notes with git-notes' '
done
'
test_expect_success !SANITIZE_LEAK 'many notes created correctly with git-notes' '
test_expect_success 'many notes created correctly with git-notes' '
git log >output.raw &&
grep "^ " output.raw >output &&
i=$num_notes &&

View File

@ -5,6 +5,7 @@ test_description='Return value of diffs'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '

View File

@ -33,7 +33,7 @@ test_expect_success 'GIT_EXTERNAL_DIFF environment' '
'
test_expect_success !SANITIZE_LEAK 'GIT_EXTERNAL_DIFF environment should apply only to diff' '
test_expect_success 'GIT_EXTERNAL_DIFF environment should apply only to diff' '
GIT_EXTERNAL_DIFF=echo git log -p -1 HEAD >out &&
grep "^diff --git a/file b/file" out
@ -74,7 +74,7 @@ test_expect_success 'diff.external' '
test_cmp expect actual
'
test_expect_success !SANITIZE_LEAK 'diff.external should apply only to diff' '
test_expect_success 'diff.external should apply only to diff' '
test_config diff.external echo &&
git log -p -1 HEAD >out &&
grep "^diff --git a/file b/file" out

View File

@ -2,6 +2,7 @@
test_description='diff function context'
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
dir="$TEST_DIRECTORY/t4051"

View File

@ -5,6 +5,7 @@ test_description='combined diff show only paths that are different to all parent
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# verify that diffc.expect matches output of

View File

@ -7,6 +7,7 @@ test_description='git apply should not get confused with type changes.
'
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup repository and commits' '

View File

@ -2,6 +2,7 @@
test_description='git merge-tree --write-tree'
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# This test is ort-specific

View File

@ -2,6 +2,7 @@
test_description='pack-object compression configuration'
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '

View File

@ -5,6 +5,7 @@
test_description='git unpack-objects with large objects'
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
prepare_dest () {

View File

@ -7,6 +7,7 @@ test_description='Test the post-merge hook.'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '

View File

@ -5,6 +5,7 @@ test_description='test automatic tag following'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# End state of the repository:

View File

@ -17,7 +17,7 @@ test_expect_success 'setup unexpected non-blob entry' '
broken_tree="$(git hash-object -w --literally -t tree broken-tree)"
'
test_expect_success !SANITIZE_LEAK 'TODO (should fail!): traverse unexpected non-blob entry (lone)' '
test_expect_success 'TODO (should fail!): traverse unexpected non-blob entry (lone)' '
sed "s/Z$//" >expect <<-EOF &&
$broken_tree Z
$tree foo
@ -121,7 +121,7 @@ test_expect_success 'setup unexpected non-blob tag' '
tag=$(git hash-object -w --literally -t tag broken-tag)
'
test_expect_success !SANITIZE_LEAK 'TODO (should fail!): traverse unexpected non-blob tag (lone)' '
test_expect_success 'TODO (should fail!): traverse unexpected non-blob tag (lone)' '
git rev-list --objects $tag
'

View File

@ -4,6 +4,7 @@ test_description='Test merge without common ancestors'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# This scenario is based on a real-world repository of Shawn Pearce.

View File

@ -11,6 +11,7 @@ if core.symlinks is false.'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '

View File

@ -5,7 +5,6 @@ test_description='ask merge-recursive to merge binary files'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '

View File

@ -2,6 +2,7 @@
test_description='merge fast-forward and up to date'
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '

View File

@ -4,6 +4,7 @@ test_description='merge: handle file mode'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'set up mode change in one branch' '

View File

@ -11,6 +11,7 @@ test_description='merge conflict in crlf repo
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '

View File

@ -4,6 +4,7 @@ test_description='Merge-recursive rename/delete conflict message'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'rename/delete' '

View File

@ -2,6 +2,7 @@
test_description='merge-recursive backend test'
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# A <- create some files

View File

@ -5,6 +5,7 @@ test_description='basic work tree status reporting'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '

View File

@ -2,6 +2,7 @@
test_description='git-status with core.ignorecase=true'
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'status with hash collisions' '

View File

@ -5,6 +5,7 @@
test_description='Tests for "git reset" with "--merge" and "--keep" options'
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '

View File

@ -5,6 +5,7 @@
test_description='Tests to check that "reset" options follow a known table'
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh

View File

@ -4,6 +4,7 @@ test_description='git mergetool
Testing basic merge tools options'
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'mergetool --tool=vimdiff creates the expected layout' '

View File

@ -8,7 +8,6 @@ test_description='git svn basic tests'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
TEST_FAILS_SANITIZE_LEAK=true
. ./lib-git-svn.sh
prepare_utf8_locale

View File

@ -4,17 +4,12 @@
#
test_description='perl interface (Git.pm)'
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-perl.sh
if ! test_have_prereq PERL; then
skip_all='skipping perl interface tests, perl not available'
test_done
fi
perl -MTest::More -e 0 2>/dev/null || {
skip_all="Perl Test::More unavailable, skipping test"
test_done
}
skip_all_if_no_Test_More
# set up test repository
@ -50,11 +45,9 @@ test_expect_success \
git config --add test.pathmulti bar
'
# The external test will outputs its own plan
test_external_has_tap=1
test_external_without_stderr \
'Perl API' \
perl "$TEST_DIRECTORY"/t9700/test.pl
test_expect_success 'use t9700/test.pl to test Git.pm' '
"$PERL_PATH" "$TEST_DIRECTORY"/t9700/test.pl 2>stderr &&
test_must_be_empty stderr
'
test_done

View File

@ -5,6 +5,7 @@ test_description='git web--browse basic tests
This test checks that git web--browse can handle various valid URLs.'
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_web_browse () {

View File

@ -633,7 +633,7 @@ test_hook () {
# - Explicitly using test_have_prereq.
#
# - Implicitly by specifying the prerequisite tag in the calls to
# test_expect_{success,failure} and test_external{,_without_stderr}.
# test_expect_{success,failure}
#
# The single parameter is the prerequisite tag (a simple word, in all
# capital letters by convention).
@ -835,93 +835,6 @@ test_expect_success () {
test_finish_
}
# test_external runs external test scripts that provide continuous
# test output about their progress, and succeeds/fails on
# zero/non-zero exit code. It outputs the test output on stdout even
# in non-verbose mode, and announces the external script with "# run
# <n>: ..." before running it. When providing relative paths, keep in
# mind that all scripts run in "trash directory".
# Usage: test_external description command arguments...
# Example: test_external 'Perl API' perl ../path/to/test.pl
test_external () {
test "$#" = 4 && { test_prereq=$1; shift; } || test_prereq=
test "$#" = 3 ||
BUG "not 3 or 4 parameters to test_external"
descr="$1"
shift
test_verify_prereq
export test_prereq
if ! test_skip "$descr" "$@"
then
# Announce the script to reduce confusion about the
# test output that follows.
say_color "" "# run $test_count: $descr ($*)"
# Export TEST_DIRECTORY, TRASH_DIRECTORY and GIT_TEST_LONG
# to be able to use them in script
export TEST_DIRECTORY TRASH_DIRECTORY GIT_TEST_LONG
# Run command; redirect its stderr to &4 as in
# test_run_, but keep its stdout on our stdout even in
# non-verbose mode.
"$@" 2>&4
if test "$?" = 0
then
if test $test_external_has_tap -eq 0; then
test_ok_ "$descr"
else
say_color "" "# test_external test $descr was ok"
test_success=$(($test_success + 1))
fi
else
if test $test_external_has_tap -eq 0; then
test_failure_ "$descr" "$@"
else
say_color error "# test_external test $descr failed: $@"
test_failure=$(($test_failure + 1))
fi
fi
fi
}
# Like test_external, but in addition tests that the command generated
# no output on stderr.
test_external_without_stderr () {
# The temporary file has no (and must have no) security
# implications.
tmp=${TMPDIR:-/tmp}
stderr="$tmp/git-external-stderr.$$.tmp"
test_external "$@" 4> "$stderr"
test -f "$stderr" || error "Internal error: $stderr disappeared."
descr="no stderr: $1"
shift
say >&3 "# expecting no stderr from previous command"
if test ! -s "$stderr"
then
rm "$stderr"
if test $test_external_has_tap -eq 0; then
test_ok_ "$descr"
else
say_color "" "# test_external_without_stderr test $descr was ok"
test_success=$(($test_success + 1))
fi
else
if test "$verbose" = t
then
output=$(echo; echo "# Stderr is:"; cat "$stderr")
else
output=
fi
# rm first in case test_failure exits.
rm "$stderr"
if test $test_external_has_tap -eq 0; then
test_failure_ "$descr" "$@" "$output"
else
say_color error "# test_external_without_stderr test $descr failed: $@: $output"
test_failure=$(($test_failure + 1))
fi
fi
}
# debugging-friendly alternatives to "test [-f|-d|-e]"
# The commands test the existence or non-existence of $1
test_path_is_file () {

View File

@ -238,6 +238,9 @@ parse_option () {
;;
esac
;;
--invert-exit-code)
invert_exit_code=t
;;
*)
echo "error: unknown test option '$opt'" >&2; exit 1 ;;
esac
@ -302,6 +305,11 @@ TEST_NUMBER="${TEST_NAME%%-*}"
TEST_NUMBER="${TEST_NUMBER#t}"
TEST_RESULTS_DIR="$TEST_OUTPUT_DIRECTORY/test-results"
TEST_RESULTS_BASE="$TEST_RESULTS_DIR/$TEST_NAME$TEST_STRESS_JOB_SFX"
TEST_RESULTS_SAN_FILE_PFX=trace
TEST_RESULTS_SAN_DIR_SFX=leak
TEST_RESULTS_SAN_FILE=
TEST_RESULTS_SAN_DIR="$TEST_RESULTS_DIR/$TEST_NAME.$TEST_RESULTS_SAN_DIR_SFX"
TEST_RESULTS_SAN_DIR_NR_LEAKS_STARTUP=
TRASH_DIRECTORY="trash directory.$TEST_NAME$TEST_STRESS_JOB_SFX"
test -n "$root" && TRASH_DIRECTORY="$root/$TRASH_DIRECTORY"
case "$TRASH_DIRECTORY" in
@ -309,6 +317,16 @@ case "$TRASH_DIRECTORY" in
*) TRASH_DIRECTORY="$TEST_OUTPUT_DIRECTORY/$TRASH_DIRECTORY" ;;
esac
# Utility functions using $TEST_RESULTS_* variables
nr_san_dir_leaks_ () {
# stderr piped to /dev/null because the directory may have
# been "rmdir"'d already.
find "$TEST_RESULTS_SAN_DIR" \
-type f \
-name "$TEST_RESULTS_SAN_FILE_PFX.*" 2>/dev/null |
wc -l
}
# If --stress was passed, run this test repeatedly in several parallel loops.
if test "$GIT_TEST_STRESS_STARTED" = "done"
then
@ -788,15 +806,31 @@ test_ok_ () {
finalize_test_case_output ok "$@"
}
_invert_exit_code_failure_end_blurb () {
say_color warn "# faked up failures as TODO & now exiting with 0 due to --invert-exit-code"
}
test_failure_ () {
failure_label=$1
test_failure=$(($test_failure + 1))
say_color error "not ok $test_count - $1"
local pfx=""
if test -n "$invert_exit_code" # && test -n "$HARNESS_ACTIVE"
then
pfx="# TODO induced breakage (--invert-exit-code):"
fi
say_color error "not ok $test_count - ${pfx:+$pfx }$1"
shift
printf '%s\n' "$*" | sed -e 's/^/# /'
if test -n "$immediate"
then
say_color error "1..$test_count"
if test -n "$invert_exit_code"
then
finalize_test_output
_invert_exit_code_failure_end_blurb
GIT_EXIT_OK=t
exit 0
fi
_error_exit
fi
finalize_test_case_output failure "$failure_label" "$@"
@ -804,14 +838,14 @@ test_failure_ () {
test_known_broken_ok_ () {
test_fixed=$(($test_fixed+1))
say_color error "ok $test_count - $@ # TODO known breakage vanished"
finalize_test_case_output fixed "$@"
say_color error "ok $test_count - $1 # TODO known breakage vanished"
finalize_test_case_output fixed "$1"
}
test_known_broken_failure_ () {
test_broken=$(($test_broken+1))
say_color warn "not ok $test_count - $@ # TODO known breakage"
finalize_test_case_output broken "$@"
say_color warn "not ok $test_count - $1 # TODO known breakage"
finalize_test_case_output broken "$1"
}
test_debug () {
@ -1168,9 +1202,67 @@ test_atexit_handler () {
teardown_malloc_check
}
test_done () {
GIT_EXIT_OK=t
sanitize_leak_log_message_ () {
local new="$1" &&
local old="$2" &&
local file="$3" &&
printf "With SANITIZE=leak at exit we have %d leak logs, but started with %d
This means that we have a blindspot where git is leaking but we're
losing the exit code somewhere, or not propagating it appropriately
upwards!
See the logs at \"%s.*\";
those logs are reproduced below." \
"$new" "$old" "$file"
}
check_test_results_san_file_ () {
if test -z "$TEST_RESULTS_SAN_FILE"
then
return
fi &&
local old="$TEST_RESULTS_SAN_DIR_NR_LEAKS_STARTUP" &&
local new="$(nr_san_dir_leaks_)" &&
if test $new -le $old
then
return
fi &&
local out="$(sanitize_leak_log_message_ "$new" "$old" "$TEST_RESULTS_SAN_FILE")" &&
say_color error "$out" &&
if test "$old" != 0
then
echo &&
say_color error "The logs include output from past runs to avoid" &&
say_color error "that remove 'test-results' between runs."
fi &&
say_color error "$(cat "$TEST_RESULTS_SAN_FILE".*)" &&
if test -n "$passes_sanitize_leak" && test "$test_failure" = 0
then
say "As TEST_PASSES_SANITIZE_LEAK=true and our logs show we're leaking, exit non-zero!" &&
invert_exit_code=t
elif test -n "$passes_sanitize_leak"
then
say "As TEST_PASSES_SANITIZE_LEAK=true and our logs show we're leaking, and we're failing for other reasons too..." &&
invert_exit_code=
elif test -n "$sanitize_leak_check" && test "$test_failure" = 0
then
say "As TEST_PASSES_SANITIZE_LEAK=true isn't set the above leak is 'ok' with GIT_TEST_PASSING_SANITIZE_LEAK=check" &&
invert_exit_code=
elif test -n "$sanitize_leak_check"
then
say "As TEST_PASSES_SANITIZE_LEAK=true isn't set the above leak is 'ok' with GIT_TEST_PASSING_SANITIZE_LEAK=check" &&
invert_exit_code=t
else
say "With GIT_TEST_SANITIZE_LEAK_LOG=true our logs revealed a memory leak, exit non-zero!" &&
invert_exit_code=t
fi
}
test_done () {
# Run the atexit commands _before_ the trash directory is
# removed, so the commands can access pidfiles and socket files.
test_atexit_handler
@ -1210,8 +1302,6 @@ test_done () {
fi
case "$test_failure" in
0)
if test $test_external_has_tap -eq 0
then
if test $test_remaining -gt 0
then
say_color pass "# passed all $msg"
@ -1229,9 +1319,15 @@ test_done () {
say "1..$test_count"
;;
esac
fi
if test -z "$debug" && test -n "$remove_trash"
if test -n "$stress" && test -n "$invert_exit_code"
then
# We're about to move our "$TRASH_DIRECTORY"
# to "$TRASH_DIRECTORY.stress-failed" if
# --stress is combined with
# --invert-exit-code.
say "with --stress and --invert-exit-code we're not removing '$TRASH_DIRECTORY'"
elif test -z "$debug" && test -n "$remove_trash"
then
test -d "$TRASH_DIRECTORY" ||
error "Tests passed but trash directory already removed before test cleanup; aborting"
@ -1244,17 +1340,35 @@ test_done () {
} ||
error "Tests passed but test cleanup failed; aborting"
fi
check_test_results_san_file_ "$test_failure"
if test -z "$skip_all" && test -n "$invert_exit_code"
then
say_color warn "# faking up non-zero exit with --invert-exit-code"
GIT_EXIT_OK=t
exit 1
fi
test_at_end_hook_
GIT_EXIT_OK=t
exit 0 ;;
*)
if test $test_external_has_tap -eq 0
then
say_color error "# failed $test_failure among $msg"
say "1..$test_count"
check_test_results_san_file_ "$test_failure"
if test -n "$invert_exit_code"
then
_invert_exit_code_failure_end_blurb
GIT_EXIT_OK=t
exit 0
fi
GIT_EXIT_OK=t
exit 1 ;;
esac
@ -1387,14 +1501,12 @@ fi
GITPERLLIB="$GIT_BUILD_DIR"/perl/build/lib
export GITPERLLIB
test -d "$GIT_BUILD_DIR"/templates/blt || {
error "You haven't built things yet, have you?"
BAIL_OUT "You haven't built things yet, have you?"
}
if ! test -x "$GIT_BUILD_DIR"/t/helper/test-tool$X
then
echo >&2 'You need to build test-tool:'
echo >&2 'Run "make t/helper/test-tool" in the source (toplevel) directory'
exit 1
BAIL_OUT 'You need to build test-tool; Run "make t/helper/test-tool" in the source (toplevel) directory'
fi
# Are we running this test at all?
@ -1408,24 +1520,70 @@ then
test_done
fi
# skip non-whitelisted tests when compiled with SANITIZE=leak
BAIL_OUT_ENV_NEEDS_SANITIZE_LEAK () {
BAIL_OUT "$1 has no effect except when compiled with SANITIZE=leak"
}
if test -n "$SANITIZE_LEAK"
then
if test_bool_env GIT_TEST_PASSING_SANITIZE_LEAK false
then
# We need to see it in "git env--helper" (via
# test_bool_env)
export TEST_PASSES_SANITIZE_LEAK
# Normalize with test_bool_env
passes_sanitize_leak=
if ! test_bool_env TEST_PASSES_SANITIZE_LEAK false
# We need to see TEST_PASSES_SANITIZE_LEAK in "git
# env--helper" (via test_bool_env)
export TEST_PASSES_SANITIZE_LEAK
if test_bool_env TEST_PASSES_SANITIZE_LEAK false
then
passes_sanitize_leak=t
fi
if test "$GIT_TEST_PASSING_SANITIZE_LEAK" = "check"
then
sanitize_leak_check=t
if test -n "$invert_exit_code"
then
BAIL_OUT "cannot use --invert-exit-code under GIT_TEST_PASSING_SANITIZE_LEAK=check"
fi
if test -z "$passes_sanitize_leak"
then
say "in GIT_TEST_PASSING_SANITIZE_LEAK=check mode, setting --invert-exit-code for TEST_PASSES_SANITIZE_LEAK != true"
invert_exit_code=t
fi
elif test -z "$passes_sanitize_leak" &&
test_bool_env GIT_TEST_PASSING_SANITIZE_LEAK false
then
skip_all="skipping $this_test under GIT_TEST_PASSING_SANITIZE_LEAK=true"
test_done
fi
fi
elif test_bool_env GIT_TEST_PASSING_SANITIZE_LEAK false
if test_bool_env GIT_TEST_SANITIZE_LEAK_LOG false
then
BAIL_OUT "GIT_TEST_PASSING_SANITIZE_LEAK=true has no effect except when compiled with SANITIZE=leak"
if ! mkdir -p "$TEST_RESULTS_SAN_DIR"
then
BAIL_OUT "cannot create $TEST_RESULTS_SAN_DIR"
fi &&
TEST_RESULTS_SAN_FILE="$TEST_RESULTS_SAN_DIR/$TEST_RESULTS_SAN_FILE_PFX"
# In case "test-results" is left over from a previous
# run: Only report if new leaks show up.
TEST_RESULTS_SAN_DIR_NR_LEAKS_STARTUP=$(nr_san_dir_leaks_)
# Don't litter *.leak dirs if there was nothing to report
test_atexit "rmdir \"$TEST_RESULTS_SAN_DIR\" 2>/dev/null || :"
prepend_var LSAN_OPTIONS : dedup_token_length=9999
prepend_var LSAN_OPTIONS : log_exe_name=1
prepend_var LSAN_OPTIONS : log_path=\"$TEST_RESULTS_SAN_FILE\"
export LSAN_OPTIONS
fi
elif test "$GIT_TEST_PASSING_SANITIZE_LEAK" = "check" ||
test_bool_env GIT_TEST_PASSING_SANITIZE_LEAK false
then
BAIL_OUT_ENV_NEEDS_SANITIZE_LEAK "GIT_TEST_PASSING_SANITIZE_LEAK=true"
elif test_bool_env GIT_TEST_SANITIZE_LEAK_LOG false
then
BAIL_OUT_ENV_NEEDS_SANITIZE_LEAK "GIT_TEST_SANITIZE_LEAK_LOG=true"
fi
# Last-minute variable setup
@ -1448,9 +1606,7 @@ remove_trash_directory () {
# Test repository
remove_trash_directory "$TRASH_DIRECTORY" || {
GIT_EXIT_OK=t
echo >&5 "FATAL: Cannot prepare test area"
exit 1
BAIL_OUT 'cannot prepare test area'
}
remove_trash=t
@ -1466,7 +1622,7 @@ fi
# Use -P to resolve symlinks in our working directory so that the cwd
# in subprocesses like git equals our $PWD (for pathname comparisons).
cd -P "$TRASH_DIRECTORY" || exit 1
cd -P "$TRASH_DIRECTORY" || BAIL_OUT "cannot cd -P to \"$TRASH_DIRECTORY\""
start_test_output "$0"

View File

@ -455,6 +455,7 @@ static void create_pack_file(struct upload_pack_data *pack_data,
return;
fail:
free(output_state);
send_client_data(3, abort_msg, sizeof(abort_msg),
pack_data->use_sideband);
die("git upload-pack: %s", abort_msg);