]> git.vpit.fr Git - perl/modules/Test-Valgrind.git/blob - lib/Test/Valgrind.pm
d2bbb25ea1bb88a2f8176e1d77390a18ed86d796
[perl/modules/Test-Valgrind.git] / lib / Test / Valgrind.pm
1 package Test::Valgrind;
2
3 use strict;
4 use warnings;
5
6 =head1 NAME
7
8 Test::Valgrind - Generate suppressions, analyse and test any command with valgrind.
9
10 =head1 VERSION
11
12 Version 1.16
13
14 =cut
15
16 our $VERSION = '1.16';
17
18 =head1 SYNOPSIS
19
20     # From the command-line
21     perl -MTest::Valgrind leaky.pl
22
23     # From the command-line, snippet style
24     perl -MTest::Valgrind -e 'leaky()'
25
26     # In a test file
27     use Test::More;
28     eval 'use Test::Valgrind';
29     plan skip_all => 'Test::Valgrind is required to test your distribution with valgrind' if $@;
30     leaky();
31
32     # In all the test files of a directory
33     prove --exec 'perl -Iblib/lib -Iblib/arch -MTest::Valgrind' t/*.t
34
35 =head1 DESCRIPTION
36
37 This module is a front-end to the C<Test::Valgrind::*> API that lets you run Perl code through the C<memcheck> tool of the C<valgrind> memory debugger, to test for memory errors and leaks.
38 If they aren't available yet, it will first generate suppressions for the current C<perl> interpreter and store them in the portable flavour of F<~/.perl/Test-Valgrind/suppressions/$VERSION>.
39 The actual run will then take place, and tests will be passed or failed according to the result of the analysis.
40
41 The complete API is much more versatile than this.
42 By declaring an appropriate L<Test::Valgrind::Command> class, you can run any executable (that is, not only Perl scripts) under valgrind, generate the corresponding suppressions on-the-fly and convert the analysis result to TAP output so that it can be incorporated into your project's testsuite.
43 If you're not interested in producing TAP, you can output the results in whatever format you like (for example HTML pages) by defining your own L<Test::Valgrind::Action> class.
44
45 Due to the nature of perl's memory allocator, this module can't track leaks of Perl objects.
46 This includes non-mortalized scalars and memory cycles.
47 However, it can track leaks of chunks of memory allocated in XS extensions with C<Newx> and friends or C<malloc>.
48 As such, it's complementary to the other very good leak detectors listed in the L</SEE ALSO> section.
49
50 =head1 METHODS
51
52 =head2 C<analyse>
53
54     Test::Valgrind->analyse(%options);
55
56 Run a C<valgrind> analysis configured by C<%options> :
57
58 =over 4
59
60 =item *
61
62 C<< command => $command >>
63
64 The L<Test::Valgrind::Command> object (or class name) to use.
65
66 Defaults to L<Test::Valgrind::Command::PerlScript>.
67
68 =item *
69
70 C<< tool => $tool >>
71
72 The L<Test::Valgrind::Tool> object (or class name) to use.
73
74 Defaults to L<Test::Valgrind::Tool::memcheck>.
75
76 =item *
77
78 C<< action => $action >>
79
80 The L<Test::Valgrind::Action> object (or class name) to use.
81
82 Defaults to L<Test::Valgrind::Action::Test>.
83
84 =item *
85
86 C<< file => $file >>
87
88 The file name of the script to analyse.
89
90 Ignored if you supply your own custom C<command>, but mandatory otherwise.
91
92 =item *
93
94 C<< callers => $number >>
95
96 Specify the maximum stack depth studied when valgrind encounters an error.
97 Raising this number improves granularity.
98
99 Ignored if you supply your own custom C<tool>, otherwise defaults to C<50>.
100
101 =item *
102
103 C<< diag => $bool >>
104
105 If true, print the output of the test script as diagnostics.
106
107 Ignored if you supply your own custom C<action>, otherwise defaults to false.
108
109 =item *
110
111 C<< regen_def_supp => $bool >>
112
113 If true, forcefully regenerate the default suppression file.
114
115 Defaults to false.
116
117 =item *
118
119 C<< no_def_supp => $bool >>
120
121 If true, do not use the default suppression file.
122
123 Defaults to false.
124
125 =item *
126
127 C<< allow_no_supp => $bool >>
128
129 If true, force running the analysis even if the suppression files do not refer to any C<perl>-related symbol.
130
131 Defaults to false.
132
133 =item *
134
135 C<< extra_supps => \@files >>
136
137 Also use suppressions from C<@files> besides C<perl>'s.
138
139 Defaults to empty.
140
141 =back
142
143 =cut
144
145 sub _croak {
146  require Carp;
147  Carp::croak(@_);
148 }
149
150 my %skippable_errors = (
151  session => [
152   'Empty valgrind candidates list',
153   'No appropriate valgrind executable could be found',
154  ],
155  action  => [ ],
156  tool    => [ ],
157  command => [ ],
158  run     => [
159   'No compatible suppressions available',
160  ],
161 );
162
163 my %filter_errors;
164
165 for my $obj (keys %skippable_errors) {
166  my @errors = @{$skippable_errors{$obj} || []};
167  if (@errors) {
168   my $rxp   = join '|', @errors;
169   $rxp      = qr/($rxp)\s+at.*/;
170   $filter_errors{$obj} = sub {
171    my ($err) = @_;
172    if ($err =~ /$rxp/) {
173     return ($1, 1);
174    } else {
175     return ($err, 0);
176    }
177   };
178  } else {
179   $filter_errors{$obj} = sub {
180    return ($_[0], 0);
181   };
182  }
183 }
184
185 sub _default_abort {
186  my ($err) = @_;
187
188  require Test::Builder;
189  my $tb   = Test::Builder->new;
190  my $plan = $tb->has_plan;
191  if (defined $plan) {
192   $tb->BAIL_OUT($err);
193   return 255;
194  } else {
195   $tb->skip_all($err);
196   return 0;
197  }
198 }
199
200 sub analyse {
201  shift;
202
203  my %args = @_;
204
205  my $instanceof = sub {
206   require Scalar::Util;
207   Scalar::Util::blessed($_[0]) && $_[0]->isa($_[1]);
208  };
209
210  my $tool = delete $args{tool};
211  unless ($tool->$instanceof('Test::Valgrind::Tool')) {
212   require Test::Valgrind::Tool;
213   local $@;
214   $tool = eval {
215    Test::Valgrind::Tool->new(
216     tool     => $tool || 'memcheck',
217     callers  => delete $args{callers},
218    );
219   };
220   unless ($tool) {
221    my ($err, $skippable) = $filter_errors{tool}->($@);
222    _croak($err) unless $skippable;
223    return _default_abort($err);
224   }
225  }
226
227  require Test::Valgrind::Session;
228  my $sess = eval {
229   Test::Valgrind::Session->new(
230    min_version => $tool->requires_version,
231    map { $_ => delete $args{$_} } qw<
232     regen_def_supp
233     no_def_supp
234     allow_no_supp
235     extra_supps
236    >
237   );
238  };
239  unless ($sess) {
240   my ($err, $skippable) = $filter_errors{session}->($@);
241   _croak($err) unless $skippable;
242   return _default_abort($err);
243  }
244
245  my $action = delete $args{action};
246  unless ($action->$instanceof('Test::Valgrind::Action')) {
247   require Test::Valgrind::Action;
248   local $@;
249   $action = eval {
250    Test::Valgrind::Action->new(
251     action => $action || 'Test',
252     diag   => delete $args{diag},
253    );
254   };
255   unless ($action) {
256    my ($err, $skippable) = $filter_errors{action}->($@);
257    _croak($err) unless $skippable;
258    return _default_abort($err);
259   }
260  }
261
262  my $cmd = delete $args{command};
263  unless ($cmd->$instanceof('Test::Valgrind::Command')) {
264   require Test::Valgrind::Command;
265   local $@;
266   $cmd = eval {
267    Test::Valgrind::Command->new(
268     command => $cmd || 'PerlScript',
269     file    => delete $args{file},
270     args    => [ '-MTest::Valgrind=run,1' ],
271    );
272   };
273   unless ($cmd) {
274    my ($err, $skippable) = $filter_errors{command}->($@);
275    _croak($err) unless $skippable;
276    $action->abort($sess, $err);
277    return $action->status($sess);
278   }
279  }
280
281  {
282   local $@;
283   eval {
284    $sess->run(
285     command => $cmd,
286     tool    => $tool,
287     action  => $action,
288    );
289    1
290   } or do {
291    my ($err, $skippable) = $filter_errors{run}->($@);
292    if ($skippable) {
293     $action->abort($sess, $err);
294     return $action->status($sess);
295    } else {
296     require Test::Valgrind::Report;
297     $action->report($sess, Test::Valgrind::Report->new_diag($@));
298    }
299   }
300  }
301
302  my $status = $sess->status;
303  $status = 255 unless defined $status;
304
305  return $status;
306 }
307
308 =head2 C<import>
309
310     use Test::Valgrind %options;
311
312 In the parent process, L</import> calls L</analyse> with the arguments it received itself - except that if no C<file> option was supplied, it tries to pick the first caller context that looks like a script.
313 When the analysis ends, it exits with the status returned by the action (for the default TAP-generator action, it's the number of failed tests).
314
315 In the child process, it just C<return>s so that the calling code is actually run under C<valgrind>, albeit two side-effects :
316
317 =over 4
318
319 =item *
320
321 L<Perl::Destruct::Level> is loaded and the destruction level is set to C<3>.
322
323 =item *
324
325 Autoflush on C<STDOUT> is turned on.
326
327 =back
328
329 =cut
330
331 # We use as little modules as possible in run mode so that they don't pollute
332 # the analysis. Hence all the requires.
333
334 my $run;
335
336 sub import {
337  my $class = shift;
338  $class = ref($class) || $class;
339
340  _croak('Optional arguments must be passed as key => value pairs') if @_ % 2;
341  my %args = @_;
342
343  if (defined delete $args{run} or $run) {
344   require Perl::Destruct::Level;
345   Perl::Destruct::Level::set_destruct_level(3);
346   {
347    my $oldfh = select STDOUT;
348    $|++;
349    select $oldfh;
350   }
351   $run = 1;
352   return;
353  }
354
355  my $file = delete $args{file};
356  unless (defined $file) {
357   my ($next, $last_pm);
358   for (my $l = 0; 1; ++$l) {
359    $next = (caller $l)[1];
360    last unless defined $next;
361    next if $next =~ /^\s*\(\s*eval\s*\d*\s*\)\s*$/;
362    if ($next =~ /\.pmc?$/) {
363     $last_pm = $next;
364    } else {
365     $file = $next;
366     last;
367    }
368   }
369   $file = $last_pm unless defined $file;
370  }
371
372  unless (defined $file) {
373   require Test::Builder;
374   Test::Builder->new->diag('Couldn\'t find a valid source file');
375   return;
376  }
377
378  if ($file ne '-e') {
379   exit $class->analyse(
380    file => $file,
381    %args,
382   );
383  }
384
385  require File::Temp;
386  my $tmp = File::Temp->new;
387
388  require Filter::Util::Call;
389  Filter::Util::Call::filter_add(sub {
390   my $status = Filter::Util::Call::filter_read();
391   if ($status > 0) {
392    print $tmp $_;
393   } elsif ($status == 0) {
394    close $tmp;
395    my $code = $class->analyse(
396     file => $tmp->filename,
397     %args,
398    );
399    exit $code;
400   }
401   $status;
402  });
403 }
404
405 =head1 VARIABLES
406
407 =head2 C<$dl_unload>
408
409 When set to true, all dynamic extensions that were loaded during the analysis will be unloaded at C<END> time by L<DynaLoader/dl_unload_file>.
410
411 Since this obfuscates error stack traces, it's disabled by default.
412
413 =cut
414
415 our $dl_unload;
416
417 END {
418  if ($dl_unload and $run and eval { require DynaLoader; 1 }) {
419   my @rest;
420   DynaLoader::dl_unload_file($_) or push @rest, $_ for @DynaLoader::dl_librefs;
421   @DynaLoader::dl_librefs = @rest;
422  }
423 }
424
425 =head1 CAVEATS
426
427 Perl 5.8 is notorious for leaking like there's no tomorrow, so the suppressions are very likely not to be complete on it.
428 You also have a better chance to get more accurate results if your perl is built with debugging enabled.
429 Using the latest C<valgrind> available will also help.
430
431 This module is not really secure.
432 It's definitely not taint safe.
433 That shouldn't be a problem for test files.
434
435 What your tests output to C<STDOUT> and C<STDERR> is eaten unless you pass the C<diag> option, in which case it will be reprinted as diagnostics.
436
437 =head1 DEPENDENCIES
438
439 L<XML::Twig>, L<version>, L<File::HomeDir>, L<Env::Sanctify>, L<Perl::Destruct::Level>.
440
441 =head1 SEE ALSO
442
443 All the C<Test::Valgrind::*> API, including L<Test::Valgrind::Command>, L<Test::Valgrind::Tool>, L<Test::Valgrind::Action> and L<Test::Valgrind::Session>.
444
445 The C<valgrind(1)> man page.
446
447 L<Test::LeakTrace>.
448
449 L<Devel::Leak>, L<Devel::LeakTrace>, L<Devel::LeakTrace::Fast>.
450
451 =head1 AUTHOR
452
453 Vincent Pit, C<< <perl at profvince.com> >>, L<http://www.profvince.com>.
454
455 You can contact me by mail or on C<irc.perl.org> (vincent).
456
457 =head1 BUGS
458
459 Please report any bugs or feature requests to C<bug-test-valgrind at rt.cpan.org>, or through the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Test-Valgrind>.
460 I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
461
462 =head1 SUPPORT
463
464 You can find documentation for this module with the perldoc command.
465
466     perldoc Test::Valgrind
467
468 =head1 ACKNOWLEDGEMENTS
469
470 RafaE<euml>l Garcia-Suarez, for writing and instructing me about the existence of L<Perl::Destruct::Level> (Elizabeth Mattijsen is a close second).
471
472 H.Merijn Brand, for daring to test this thing.
473
474 David Cantrell, for providing shell access to one of his smokers where the tests were failing.
475
476 The Debian-perl team, for offering all the feedback they could regarding the build issues they met.
477
478 All you people that showed interest in this module, which motivated me into completely rewriting it.
479
480 =head1 COPYRIGHT & LICENSE
481
482 Copyright 2008,2009,2010,2011,2013,2015 Vincent Pit, all rights reserved.
483
484 This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
485
486 =cut
487
488 1; # End of Test::Valgrind