From 4e1be63c3b05fd379b51b611b7e869ff6977d8ab Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 4 Feb 2009 00:25:59 +0100 Subject: Add valgrind support in test scripts This patch adds the ability to use valgrind's memcheck tool to diagnose memory problems in Git while running the test scripts. It requires valgrind 3.4.0 or newer. It works by creating symlinks to a valgrind script, which have the same name as our Git binaries, and then putting that directory in front of the test script's PATH as well as set GIT_EXEC_PATH to that directory. Git scripts are symlinked from that directory directly. That way, Git binaries called by Git scripts are valgrinded, too. Valgrind can be used by specifying "GIT_TEST_OPTS=--valgrind" in the make invocation. Any invocation of git that finds any errors under valgrind will exit with failure code 126. Any valgrind output will go to the usual stderr channel for tests (i.e., /dev/null, unless -v has been specified). If you need to pass options to valgrind -- you might want to run another tool than memcheck, for example -- you can set the environment variable GIT_VALGRIND_OPTIONS. A few default suppressions are included, since libz seems to trigger quite a few false positives. We'll assume that libz works and that we can ignore any errors which are reported there. Note: it is safe to run the valgrind tests in parallel, as the links in t/valgrind/bin/ are created using proper locking. Initial patch and all the hard work by Jeff King. Signed-off-by: Johannes Schindelin Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- t/valgrind/.gitignore | 2 ++ t/valgrind/default.supp | 21 +++++++++++++++++++++ t/valgrind/valgrind.sh | 13 +++++++++++++ 3 files changed, 36 insertions(+) create mode 100644 t/valgrind/.gitignore create mode 100644 t/valgrind/default.supp create mode 100755 t/valgrind/valgrind.sh (limited to 't/valgrind') diff --git a/t/valgrind/.gitignore b/t/valgrind/.gitignore new file mode 100644 index 0000000000..d4ae6676d1 --- /dev/null +++ b/t/valgrind/.gitignore @@ -0,0 +1,2 @@ +/bin/ +/templates diff --git a/t/valgrind/default.supp b/t/valgrind/default.supp new file mode 100644 index 0000000000..2482b3b06a --- /dev/null +++ b/t/valgrind/default.supp @@ -0,0 +1,21 @@ +{ + ignore-zlib-errors-cond + Memcheck:Cond + obj:*libz.so* +} + +{ + ignore-zlib-errors-value4 + Memcheck:Value4 + obj:*libz.so* +} + +{ + writing-data-from-zlib-triggers-errors + Memcheck:Param + write(buf) + obj:/lib/ld-*.so + fun:write_in_full + fun:write_buffer + fun:write_loose_object +} diff --git a/t/valgrind/valgrind.sh b/t/valgrind/valgrind.sh new file mode 100755 index 0000000000..dc9261265b --- /dev/null +++ b/t/valgrind/valgrind.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +base=$(basename "$0") + +exec valgrind -q --error-exitcode=126 \ + --leak-check=no \ + --suppressions="$GIT_VALGRIND/default.supp" \ + --gen-suppressions=all \ + --track-origins=yes \ + --log-fd=4 \ + --input-fd=4 \ + $GIT_VALGRIND_OPTIONS \ + "$GIT_VALGRIND"/../../"$base" "$@" -- cgit v1.2.3 From 6a7e37c99f733821bd3a17432fa6e4591b63866c Mon Sep 17 00:00:00 2001 From: Jeff King Date: Wed, 4 Feb 2009 00:26:03 +0100 Subject: valgrind: ignore ldso and more libz errors On some Linux systems, we get a host of Cond and Addr errors from calls to dlopen that are caused by nss modules. We should be able to safely ignore anything happening in ld-*.so as "not our problem." [Johannes: I added some more... unfortunately using valgrind 3.4.0 syntax] Signed-off-by: Jeff King Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- t/valgrind/default.supp | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) (limited to 't/valgrind') diff --git a/t/valgrind/default.supp b/t/valgrind/default.supp index 2482b3b06a..5f341b8598 100644 --- a/t/valgrind/default.supp +++ b/t/valgrind/default.supp @@ -4,6 +4,12 @@ obj:*libz.so* } +{ + ignore-zlib-errors-value8 + Memcheck:Value8 + obj:*libz.so* +} + { ignore-zlib-errors-value4 Memcheck:Value4 @@ -11,11 +17,27 @@ } { - writing-data-from-zlib-triggers-errors + ignore-ldso-cond + Memcheck:Cond + obj:*ld-*.so +} + +{ + ignore-ldso-addr8 + Memcheck:Addr8 + obj:*ld-*.so +} + +{ + ignore-ldso-addr4 + Memcheck:Addr4 + obj:*ld-*.so +} + +{ + writing-data-from-zlib-triggers-even-more-errors Memcheck:Param write(buf) - obj:/lib/ld-*.so - fun:write_in_full - fun:write_buffer + ... fun:write_loose_object } -- cgit v1.2.3 From 268fac6919ef673094e50e2d944d09f017f5ad33 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 4 Feb 2009 00:26:22 +0100 Subject: Add a script to coalesce the valgrind outputs After running the valgrind tests with GIT_TEST_TREE=t, the test output is in the test-results/$TEST.out files. Call ./valgrind/analyze.sh in $GIT_ROOT/t/ to group the valgrind errors by backtrace. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- t/valgrind/analyze.sh | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100755 t/valgrind/analyze.sh (limited to 't/valgrind') diff --git a/t/valgrind/analyze.sh b/t/valgrind/analyze.sh new file mode 100755 index 0000000000..d8105d9fab --- /dev/null +++ b/t/valgrind/analyze.sh @@ -0,0 +1,123 @@ +#!/bin/sh + +out_prefix=$(dirname "$0")/../test-results/valgrind.out +output= +count=0 +total_count=0 +missing_message= +new_line=' +' + +# start outputting the current valgrind error in $out_prefix.++$count, +# and the test case which failed in the corresponding .message file +start_output () { + test -z "$output" || return + + # progress + total_count=$(($total_count+1)) + test -t 2 && printf "\rFound %d errors" $total_count >&2 + + count=$(($count+1)) + output=$out_prefix.$count + : > $output + + echo "*** $1 ***" > $output.message +} + +finish_output () { + test ! -z "$output" || return + output= + + # if a test case has more than one valgrind error, we need to + # copy the last .message file to the previous errors + test -z "$missing_message" || { + while test $missing_message -lt $count + do + cp $out_prefix.$count.message \ + $out_prefix.$missing_message.message + missing_message=$(($missing_message+1)) + done + missing_message= + } +} + +# group the valgrind errors by backtrace +output_all () { + last_line= + j=0 + i=1 + while test $i -le $count + do + # output + echo "$i $(tr '\n' ' ' < $out_prefix.$i)" + i=$(($i+1)) + done | + sort -t ' ' -k 2 | # order by + while read number line + do + # find duplicates, do not output backtrace twice + if test "$line" != "$last_line" + then + last_line=$line + j=$(($j+1)) + printf "\nValgrind error $j:\n\n" + cat $out_prefix.$number + printf "\nfound in:\n" + fi + # print the test case where this came from + printf "\n" + cat $out_prefix.$number.message + done +} + +handle_one () { + OLDIFS=$IFS + IFS="$new_line" + while read line + do + case "$line" in + # backtrace, possibly a new one + ==[0-9]*) + + # Does the current valgrind error have a message yet? + case "$output" in + *.message) + test -z "$missing_message" && + missing_message=$count + output= + esac + + start_output $(basename $1) + echo "$line" | + sed 's/==[0-9]*==/==valgrind==/' >> $output + ;; + # end of backtrace + '}') + test -z "$output" || { + echo "$line" >> $output + test $output = ${output%.message} && + output=$output.message + } + ;; + # end of test case + '') + finish_output + ;; + # normal line; if $output is set, print the line + *) + test -z "$output" || echo "$line" >> $output + ;; + esac + done < $1 + IFS=$OLDIFS + + # just to be safe + finish_output +} + +for test_script in "$(dirname "$0")"/../test-results/*.out +do + handle_one $test_script +done + +output_all -- cgit v1.2.3 From 5caa81d1b4f1b0b9ed73605ab1e4d91ba31a56b4 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 5 Feb 2009 22:03:00 +0100 Subject: valgrind: do not require valgrind 3.4.0 or newer Valgrind 3.4.0 is pretty new, and even if --track-origins is a nice feature, it is not the end of the world if that is not available. So play nice and use that option only when only an older version of valgrind is available. In the same spirit, refrain from the use of '...' in suppression files, which is also a feature only valgrind 3.4 and newer understand. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- t/valgrind/default.supp | 4 +++- t/valgrind/valgrind.sh | 11 ++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) (limited to 't/valgrind') diff --git a/t/valgrind/default.supp b/t/valgrind/default.supp index 5f341b8598..9e013fa3b2 100644 --- a/t/valgrind/default.supp +++ b/t/valgrind/default.supp @@ -38,6 +38,8 @@ writing-data-from-zlib-triggers-even-more-errors Memcheck:Param write(buf) - ... + obj:/lib/ld-*.so + fun:write_in_full + fun:write_buffer fun:write_loose_object } diff --git a/t/valgrind/valgrind.sh b/t/valgrind/valgrind.sh index dc9261265b..582b4dca94 100755 --- a/t/valgrind/valgrind.sh +++ b/t/valgrind/valgrind.sh @@ -2,11 +2,20 @@ base=$(basename "$0") +TRACK_ORIGINS= + +VALGRIND_VERSION=$(valgrind --version) +VALGRIND_MAJOR=$(expr "$VALGRIND_VERSION" : '[^0-9]*\([0-9]*\)') +VALGRIND_MINOR=$(expr "$VALGRIND_VERSION" : '[^0-9]*[0-9]*\.\([0-9]*\)') +test 3 -gt "$VALGRIND_MAJOR" || +test 3 -eq "$VALGRIND_MAJOR" -a 4 -gt "$VALGRIND_MINOR" || +TRACK_ORIGINS=--track-origins=yes + exec valgrind -q --error-exitcode=126 \ --leak-check=no \ --suppressions="$GIT_VALGRIND/default.supp" \ --gen-suppressions=all \ - --track-origins=yes \ + $TRACK_ORIGINS \ --log-fd=4 \ --input-fd=4 \ $GIT_VALGRIND_OPTIONS \ -- cgit v1.2.3