{"thread":{"id":"11404","subject":"[RFC/PATCH] Add a script to run test scripts using valgrind.","startedAt":"2007-12-25T20:29:14Z","lastAt":"2007-12-25T20:29:14Z","messageCount":1,"participants":["Christian Couder"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"64096","messageId":"20071225212914.c4bb3f87.chriscool@tuxfamily.org","threadId":"11404","inReplyTo":null,"subject":"[RFC/PATCH] Add a script to run test scripts using valgrind.","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2007-12-25T20:29:14Z","receivedAt":"2007-12-25T20:29:14Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"This patch adds a Perl script 'run_valgrind.pl' that runs\nthe test scripts passed as arguments using valgrind.\n\nTo use valgrind, we use a shell alias like:\n\nalias git='valgrind <options> git'\n\nand we source a test script in the same system call.\n\nThe valgrind logs are then parsed for errors and the errors\nfound are hashed so that they appear only once at the end.\n\nSigned-off-by: Christian Couder <chriscool@tuxfamily.org>\n---\n t/run_valgrind.pl |  138 +++++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 138 insertions(+), 0 deletions(-)\n create mode 100755 t/run_valgrind.pl\n\ndiff --git a/t/run_valgrind.pl b/t/run_valgrind.pl\nnew file mode 100755\nindex 0000000..cb965c9\n--- /dev/null\n+++ b/t/run_valgrind.pl\n@@ -0,0 +1,138 @@\n+#!/usr/bin/perl\n+\n+use strict;\n+use warnings;\n+\n+# All arguments should be test scripts.\n+my @scripts = @ARGV;\n+\n+my $vg_vers = valgrind_version();\n+\n+print \"Using valgrind version: $vg_vers\\n\";\n+\n+my $log_base = '/tmp/vg_log';\n+my $log_opt = ($vg_vers < '3.3') ? $log_base : \"$log_base.%p\";\n+my $vg_opts = \"--log-file=$log_opt --trace-children=yes\";\n+my $alias = \"alias git='valgrind $vg_opts git'\";\n+\n+# Remove previous log files.\n+system(\"rm -rf $log_base.*\");\n+\n+# Run the scripts using an alias for Git.\n+foreach my $file (@scripts) {\n+\tsystem(\"$alias \\n . ./$file\");\n+}\n+\n+# Error lines from log files.\n+my @log_files = glob(\"$log_base.*\");\n+my @errs = `grep 'ERROR SUMMARY' $log_base.*`;\n+chomp @errs;\n+\n+print \"\\nNumber of log files: \" . scalar(@log_files) . \"\\n\";\n+print \"Number of error lines: \" . scalar(@errs) . \"\\n\";\n+\n+my @logs;\n+for (@errs) {\n+\tif (m/^([^:]+):.*ERROR SUMMARY: (\\d+) errors/) {\n+\t\tpush @logs, $1 if ($2 > 0);\n+\t} else {\n+\t\tprint STDERR \"strange line: $_\\n\";\n+\t}\n+}\n+\n+print \"\\nResulting files with errors:\\n\\n\", join(\"\\n\", @logs), \"\\n\\n\";\n+\n+# Parse error files.\n+my @info = ();\n+for (@logs) {\n+\tmy @new = parse_error_file($_);\n+\tpush @info, @new;\n+}\n+\n+# Get only uniq errors.\n+my @uniq = ();\n+my %stack = ();\n+for (@info) {\n+\tmy $key = stack_info($_, 1);\n+\tif (exists $stack{$key}) {\n+\t\tpush @{$stack{$key}}, $_->{file};\n+\t} else {\n+\t\t$stack{$key} = [ $_->{file} ];\n+\t\t$_->{file} = $stack{$key};\n+\t\tpush @uniq, $_;\n+\t}\n+}\n+\n+# Print uniq errors.\n+print \"Uniq errors:\\n\";\n+for (@uniq) {\n+\tprint \"\\n\" . stack_info($_);\n+\tprint \"Files: \" . join(\", \", @{$_->{file}}) . \"\\n\";\n+}\n+\n+sub valgrind_version {\n+\tsystem(\"which valgrind > /dev/null 2>&1\") == 0\n+\t  or die \"'which valgrind' failed.\";\n+\n+\tmy $version = `valgrind --version`;\n+\tchomp $version;\n+\n+\tif ($version =~ m/(\\d+)\\.(\\d+)\\.(\\d+)/) {\n+\t\treturn \"$1.$2\";\n+\t} else {\n+\t\tdie \"Could not find valgrind version.\";\n+\t}\n+}\n+\n+sub stack_info {\n+\t$_ = shift;\n+\tmy ($key) = @_;\n+\n+\tmy $msg = $_->{msg};\n+\t$msg =~ s/0x[0-9A-F]+// if ($key);\n+\n+\tmy @places = map { $_->[1] } @{$_->{stack}};\n+\treturn \"$msg\\n\" . join(\"\\n\", @places) . \"\\n\";\n+}\n+\n+sub clean_line {\n+\tmy ($line) = @_;\n+\n+\t$line =~ s/^==\\d+==\\s+//;\n+\n+\treturn $line;\n+}\n+\n+sub parse_error_file {\n+\tmy ($file) = @_;\n+\n+\t# Slurp file.\n+\topen(IN, \"< $file\") or die \"Could not open '$file' for reading: $!\";\n+\tmy @content = <IN>;\n+\tchomp @content;\n+\tclose IN;\n+\n+\t# Parse errors in file.\n+\tmy @errs = ();\n+\tmy $stack = 0;\n+\tmy $prev = '';\n+\tmy $cur;\n+\tfor (@content) {\n+\t\tif (not $stack and m/    at 0x([0-9A-F]+): (.*)$/) {\n+\t\t\t$stack = 1;\n+\t\t\t$cur = { msg => $prev,\n+\t\t\t\t file => $file,\n+\t\t\t\t stack => [ [$1, $2] ] };\n+\t\t} elsif ($stack) {\n+\t\t\tif (m/    by 0x([0-9A-F]+): (.*)$/) {\n+\t\t\t\tpush @{$cur->{stack}}, [$1, $2];\n+\t\t\t} else {\n+\t\t\t\tpush @errs, $cur;\n+\t\t\t\t$stack = 0;\n+\t\t\t}\n+\t\t}\n+\t\t$prev = clean_line($_);\n+\t}\n+\n+\treturn @errs;\n+}\n-- \n1.5.3.7.2270.g786cf-dirty\n"}]}