Skip to content

Commit dea28af

Browse files
lthjtolmer
authored andcommitted
Add valgrind error check for mysqltest client
Summary: Currently, mysql-test-run.pl does not check mysqltest.log for valgrind errors. This fixes that by adding mysqltest.log to the list of files to check for valgrind errors. The current valgrind_exit_reports will only check the summary lines for leaks after server shutdown. This is okay for the mysqld processes, since we check at the end of every test case for valgrind errors. For mysqltest, we need report all valgrind errors that have occurred since no check is done. This also fixes the way valgrind errors are outputted. Unlike usual tests, the error output for valgrind_report failures occurs before test case line. This is because mysql-test-run will output valgrind errors to stdout as they are encountered. This is especially problematic in parallel runs, as multiple children processes are sharing the same stdout descriptor which means that some of the valgrind output may get interleaved. The fix here is instead of printing directly to stdout, we save the output to a .valgrind file. Then, the parent process will check and print these files at the end of the test run. That way, the valgrind output occurs after the test case line is printed, and since we're only outputting from a single process, we should get no interleaving output. Test Plan: Added a my_malloc (without corresponding my_free) to mysqltest.cc. Test fails with with --valgrind and --valgrind-mysqltest. Test passes with --valgrind-mysqld. arc diff --big-test-queue Reviewers: jtolmer Reviewed By: jtolmer Subscribers: webscalesql-eng Differential Revision: https://reviews.facebook.net/D49779
1 parent 5cbfab0 commit dea28af

File tree

2 files changed

+86
-21
lines changed

2 files changed

+86
-21
lines changed

Diff for: client/mysqltest.cc

+28-7
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ static char line_buffer[MAX_DELIMITER_LENGTH], *line_buffer_pos= line_buffer;
133133
static const char *opt_server_public_key= 0;
134134
#endif
135135
static my_bool can_handle_expired_passwords= TRUE;
136+
static char closed_connection[]= "-closed_connection-";
136137

137138
/* Info on properties that can be set with --enable_X and --disable_X */
138139

@@ -1665,7 +1666,8 @@ void close_connections()
16651666
mysql_close(&next_con->mysql);
16661667
if (next_con->util_mysql)
16671668
mysql_close(next_con->util_mysql);
1668-
my_free(next_con->name);
1669+
if (strcmp(next_con->name, closed_connection))
1670+
my_free(next_con->name);
16691671
}
16701672
my_free(connections);
16711673
DBUG_VOID_RETURN;
@@ -2438,6 +2440,7 @@ void check_require(DYNAMIC_STRING* ds, const char *fname)
24382440
{
24392441
char reason[FN_REFLEN];
24402442
fn_format(reason, fname, "", "", MY_REPLACE_EXT | MY_REPLACE_DIR);
2443+
dynstr_free(ds);
24412444
abort_not_supported_test("Test requires: '%s'", reason);
24422445
}
24432446
DBUG_VOID_RETURN;
@@ -3082,6 +3085,7 @@ void var_set_query_get_value(struct st_command *command, VAR *var)
30823085
mysql_sqlstate(mysql), &ds_res);
30833086
/* If error was acceptable, return empty string */
30843087
dynstr_free(&ds_query);
3088+
dynstr_free(&ds_col);
30853089
eval_expr(var, "", 0);
30863090
DBUG_VOID_RETURN;
30873091
}
@@ -5311,8 +5315,7 @@ void do_get_errcodes(struct st_command *command)
53115315
/* code to handle variables passed to mysqltest */
53125316
if( *p == '$')
53135317
{
5314-
const char* fin;
5315-
VAR *var = var_get(p,&fin,0,0);
5318+
VAR *var = var_get(p,NULL,0,0);
53165319
p=var->str_val;
53175320
end=p+var->str_val_len;
53185321
}
@@ -5591,6 +5594,8 @@ void do_close_connection(struct st_command *command)
55915594
{
55925595
vio_delete(con->mysql.net.vio);
55935596
con->mysql.net.vio = 0;
5597+
net_end(&con->mysql.net);
5598+
free_old_query(&con->mysql);
55945599
}
55955600
}
55965601
#else
@@ -5618,8 +5623,8 @@ void do_close_connection(struct st_command *command)
56185623
When the connection is closed set name to "-closed_connection-"
56195624
to make it possible to reuse the connection name.
56205625
*/
5621-
if (!(con->name = my_strdup("-closed_connection-", MYF(MY_WME))))
5622-
die("Out of memory");
5626+
con->name= closed_connection;
5627+
con->name_len= strlen(closed_connection);
56235628

56245629
if (con == cur_con)
56255630
{
@@ -5828,6 +5833,7 @@ int connect_n_handle_errors(struct st_command *command,
58285833
var_set_errno(mysql_errno(con));
58295834
handle_error(command, mysql_errno(con), mysql_error(con),
58305835
mysql_sqlstate(con), ds);
5836+
mysql_close(con);
58315837
return 0; /* Not connected */
58325838
}
58335839

@@ -5988,7 +5994,7 @@ void do_connect(struct st_command *command)
59885994
con_slot= next_con;
59895995
else
59905996
{
5991-
if (!(con_slot= find_connection_by_name("-closed_connection-")))
5997+
if (!(con_slot= find_connection_by_name(closed_connection)))
59925998
die("Connection limit exhausted, you can have max %d connections",
59935999
opt_max_connections);
59946000
}
@@ -7852,10 +7858,12 @@ void run_query_normal(struct st_connection *cn, struct st_command *command,
78527858

78537859
handle_error(command, mysql_errno(mysql), mysql_error(mysql),
78547860
mysql_sqlstate(mysql), ds);
7861+
dynstr_free(&temp);
78557862
goto end;
78567863
}
78577864
}
78587865
dynstr_append_mem(ds, temp.str, temp.length);
7866+
dynstr_free(&temp);
78597867
}
78607868
else
78617869
{
@@ -7912,6 +7920,11 @@ void run_query_normal(struct st_connection *cn, struct st_command *command,
79127920
revert_properties();
79137921

79147922
end:
7923+
if (res)
7924+
{
7925+
mysql_free_result_wrapper(res);
7926+
res= 0;
7927+
}
79157928

79167929
cn->pending= FALSE;
79177930
/*
@@ -8584,14 +8597,22 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags)
85848597
if (sp_created)
85858598
{
85868599
if (util_query(mysql, "DROP PROCEDURE mysqltest_tmp_sp "))
8600+
{
8601+
if (ds == &ds_result)
8602+
dynstr_free(&ds_result);
85878603
die("Failed to drop sp: %d: %s", mysql_errno(mysql), mysql_error(mysql));
8604+
}
85888605
}
85898606

85908607
if (view_created)
85918608
{
85928609
if (util_query(mysql, "DROP VIEW mysqltest_tmp_v "))
8610+
{
8611+
if (ds == &ds_result)
8612+
dynstr_free(&ds_result);
85938613
die("Failed to drop view: %d: %s",
8594-
mysql_errno(mysql), mysql_error(mysql));
8614+
mysql_errno(mysql), mysql_error(mysql));
8615+
}
85958616
}
85968617

85978618
if (command->require_file[0])

Diff for: mysql-test/mysql-test-run.pl

+58-14
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,7 @@ sub main {
459459

460460
# Create child processes
461461
my %children;
462+
my %children_logdir;
462463
for my $child_num (1..$opt_parallel){
463464
my $child_pid= My::SafeProcess::Base::_safe_fork();
464465
if ($child_pid == 0){
@@ -476,6 +477,12 @@ sub main {
476477
exit(1);
477478
}
478479

480+
if ($opt_parallel > 1) {
481+
$children_logdir{"$opt_vardir/$child_num/log/"}= 1;
482+
}
483+
else {
484+
$children_logdir{"$opt_vardir/log/"}= 1;
485+
}
479486
$children{$child_pid}= 1;
480487
}
481488
#######################################################################
@@ -540,12 +547,30 @@ sub main {
540547
$tinfo->{worker} = 0 if $opt_parallel > 1;
541548
if ($valgrind_reports) {
542549
$tinfo->{result}= 'MTR_RES_FAILED';
543-
$tinfo->{comment}= "Valgrind reported failures at shutdown, see above";
550+
$tinfo->{comment}= "Valgrind reported failures at shutdown";
544551
$tinfo->{failures}= 1;
552+
mtr_report_test($tinfo);
553+
554+
foreach my $logdir (keys %children_logdir) {
555+
opendir(LOGDIR, $logdir)
556+
or mtr_error("Can't open log directory: $logdir");
557+
558+
while (my $file = readdir(LOGDIR)) {
559+
next unless ($file =~ m/\.valgrind$/);
560+
561+
open(FILE, "< $logdir/$file" ) or mtr_error("Can't open file: $file");
562+
while(<FILE>) {
563+
print;
564+
}
565+
close FILE;
566+
}
567+
568+
closedir(LOGDIR);
569+
}
545570
} else {
546571
$tinfo->{result}= 'MTR_RES_PASSED';
572+
mtr_report_test($tinfo);
547573
}
548-
mtr_report_test($tinfo);
549574
push @$completed, $tinfo;
550575
}
551576

@@ -5399,7 +5424,7 @@ ($$)
53995424

54005425
my $output= $mysqld->value('#log-error');
54015426
# Remember this log file for valgrind error report search
5402-
$mysqld_logs{$output}= 1 if $opt_valgrind;
5427+
$mysqld_logs{$output}= 1 if $opt_valgrind_mysqld;
54035428
# Remember data dir for gmon.out files if using gprof
54045429
$gprof_dirs{$mysqld->value('datadir')}= 1 if $opt_gprof;
54055430

@@ -6080,6 +6105,8 @@ ($)
60806105
mtr_init_args(\$args);
60816106
valgrind_arguments($args, \$exe);
60826107
mtr_add_arg($args, "%s", $_) for @args_saved;
6108+
# Remember this log file for valgrind error report search
6109+
$mysqld_logs{$path_testlog} = 1
60836110
}
60846111

60856112
mtr_add_arg($args, "--test-file=%s", $tinfo->{'path'});
@@ -6427,10 +6454,14 @@ ()
64276454
my $found_report= 0;
64286455
my $err_in_report= 0;
64296456
my $ignore_report= 0;
6457+
my $valgrind_out= "$log_file.valgrind";
64306458

64316459
my $LOGF = IO::File->new($log_file)
64326460
or mtr_error("Could not open file '$log_file' for reading: $!");
64336461

6462+
my $OUTF = IO::File->new($valgrind_out, 'w')
6463+
or mtr_error("Could not open file '$valgrind_out' for writing$!");
6464+
64346465
while ( my $line = <$LOGF> )
64356466
{
64366467
if ($line =~ /^CURRENT_TEST: (.+)$/)
@@ -6441,10 +6472,10 @@ ()
64416472
{
64426473
if ($err_in_report)
64436474
{
6444-
mtr_print ("Valgrind report from $log_file after tests:\n",
6445-
@culprits);
6446-
mtr_print_line();
6447-
print ("$valgrind_rep\n");
6475+
print $OUTF "Valgrind report from $log_file after tests:\n";
6476+
print $OUTF join("\n", @culprits);
6477+
print $OUTF "\n\n";
6478+
print $OUTF "$valgrind_rep\n";
64486479
$found_err= 1;
64496480
$err_in_report= 0;
64506481
}
@@ -6456,10 +6487,20 @@ ()
64566487
push (@culprits, $testname);
64576488
next;
64586489
}
6459-
# This line marks a report to be ignored
6460-
$ignore_report=1 if $line =~ /VALGRIND_DO_QUICK_LEAK_CHECK/;
6461-
# This line marks the start of a valgrind report
6462-
$found_report= 1 if $line =~ /^==\d+== .* SUMMARY:/;
6490+
6491+
# The mysqltest log is handled differently from the mysqld logs because
6492+
# we check the mysqld logs for valgrind errors after every run. This is
6493+
# why we only look at the summary for mysqld. For mysqltest, we need to
6494+
# look at all valgrind errors that may have occurred.
6495+
if ($log_file eq $path_testlog) {
6496+
$found_report= 1 if $line =~ /^==\d+==/;
6497+
}
6498+
else {
6499+
# This line marks a report to be ignored
6500+
$ignore_report=1 if $line =~ /VALGRIND_DO_QUICK_LEAK_CHECK/;
6501+
# This line marks the start of a valgrind report
6502+
$found_report= 1 if $line =~ /^==\d+== .* SUMMARY:/;
6503+
}
64636504

64646505
if ($ignore_report && $found_report) {
64656506
$ignore_report= 0;
@@ -6479,11 +6520,14 @@ ()
64796520
$LOGF= undef;
64806521

64816522
if ($err_in_report) {
6482-
mtr_print ("Valgrind report from $log_file after tests:\n", @culprits);
6483-
mtr_print_line();
6484-
print ("$valgrind_rep\n");
6523+
print $OUTF "Valgrind report from $log_file after tests:\n";
6524+
print $OUTF join("\n", @culprits);
6525+
print $OUTF "\n\n";
6526+
print $OUTF "$valgrind_rep\n";
64856527
$found_err= 1;
64866528
}
6529+
6530+
$OUTF= undef;
64876531
}
64886532

64896533
return $found_err;

0 commit comments

Comments
 (0)