]> git.vpit.fr Git - perl/modules/Test-Valgrind.git/blob - lib/Test/Valgrind.pm
Add 'regen_def_supp', an option to regenerate the suppressions
[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.14
13
14 =cut
15
16 our $VERSION = '1.14';
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<12>.
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<< extra_supps => \@files >>
128
129 Also use suppressions from C<@files> besides C<perl>'s.
130
131 Defaults to empty.
132
133 =back
134
135 =cut
136
137 sub analyse {
138  shift;
139
140  my %args = @_;
141
142  my $instanceof = sub {
143   require Scalar::Util;
144   Scalar::Util::blessed($_[0]) && $_[0]->isa($_[1]);
145  };
146
147  my $cmd = delete $args{command};
148  unless ($cmd->$instanceof('Test::Valgrind::Command')) {
149   require Test::Valgrind::Command;
150   $cmd = Test::Valgrind::Command->new(
151    command => $cmd || 'PerlScript',
152    file    => delete $args{file},
153    args    => [ '-MTest::Valgrind=run,1' ],
154   );
155  }
156
157  my $tool = delete $args{tool};
158  unless ($tool->$instanceof('Test::Valgrind::Tool')) {
159   require Test::Valgrind::Tool;
160   $tool = Test::Valgrind::Tool->new(
161    tool     => $tool || 'memcheck',
162    callers  => delete $args{callers},
163   );
164  }
165
166  my $action = delete $args{action};
167  unless ($action->$instanceof('Test::Valgrind::Action')) {
168   require Test::Valgrind::Action;
169   $action = Test::Valgrind::Action->new(
170    action => $action || 'Test',
171    diag   => delete $args{diag},
172   );
173  }
174
175  require Test::Valgrind::Session;
176  my $sess = eval {
177   Test::Valgrind::Session->new(
178    min_version => $tool->requires_version,
179    map { $_ => delete $args{$_} } qw<regen_def_supp no_def_supp extra_supps>
180   );
181  };
182  unless ($sess) {
183   my $err = $@;
184   $err =~ s/^(Empty valgrind candidates list|No appropriate valgrind executable could be found)\s+at.*/$1/;
185   $action->abort($sess, $err);
186   return $action->status($sess);
187  }
188
189  eval {
190   $sess->run(
191    command => $cmd,
192    tool    => $tool,
193    action  => $action,
194   );
195  };
196  if ($@) {
197   require Test::Valgrind::Report;
198   $action->report($sess, Test::Valgrind::Report->new_diag($@));
199  }
200
201  my $status = $sess->status;
202  $status = 255 unless defined $status;
203
204  return $status;
205 }
206
207 =head2 C<import>
208
209     use Test::Valgrind %options;
210
211 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.
212 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).
213
214 In the child process, it just C<return>s so that the calling code is actually run under C<valgrind>, albeit two side-effects :
215
216 =over 4
217
218 =item *
219
220 L<Perl::Destruct::Level> is loaded and the destruction level is set to C<3>.
221
222 =item *
223
224 Autoflush on C<STDOUT> is turned on.
225
226 =back
227
228 =cut
229
230 # We use as little modules as possible in run mode so that they don't pollute
231 # the analysis. Hence all the requires.
232
233 my $run;
234
235 sub import {
236  my $class = shift;
237  $class = ref($class) || $class;
238
239  if (@_ % 2) {
240   require Carp;
241   Carp::croak('Optional arguments must be passed as key => value pairs');
242  }
243  my %args = @_;
244
245  if (defined delete $args{run} or $run) {
246   require Perl::Destruct::Level;
247   Perl::Destruct::Level::set_destruct_level(3);
248   {
249    my $oldfh = select STDOUT;
250    $|++;
251    select $oldfh;
252   }
253   $run = 1;
254   return;
255  }
256
257  my $file = delete $args{file};
258  unless (defined $file) {
259   my ($next, $last_pm);
260   for (my $l = 0; 1; ++$l) {
261    $next = (caller $l)[1];
262    last unless defined $next;
263    next if $next =~ /^\s*\(\s*eval\s*\d*\s*\)\s*$/;
264    if ($next =~ /\.pmc?$/) {
265     $last_pm = $next;
266    } else {
267     $file = $next;
268     last;
269    }
270   }
271   $file = $last_pm unless defined $file;
272  }
273
274  unless (defined $file) {
275   require Test::Builder;
276   Test::Builder->new->diag('Couldn\'t find a valid source file');
277   return;
278  }
279
280  if ($file ne '-e') {
281   exit $class->analyse(
282    file => $file,
283    %args,
284   );
285  }
286
287  require File::Temp;
288  my $tmp = File::Temp->new;
289
290  require Filter::Util::Call;
291  Filter::Util::Call::filter_add(sub {
292   my $status = Filter::Util::Call::filter_read();
293   if ($status > 0) {
294    print $tmp $_;
295   } elsif ($status == 0) {
296    close $tmp;
297    my $code = $class->analyse(
298     file => $tmp->filename,
299     %args,
300    );
301    exit $code;
302   }
303   $status;
304  });
305 }
306
307 =head1 VARIABLES
308
309 =head2 C<$dl_unload>
310
311 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>.
312
313 Since this obfuscates error stack traces, it's disabled by default.
314
315 =cut
316
317 our $dl_unload;
318
319 END {
320  if ($dl_unload and $run and eval { require DynaLoader; 1 }) {
321   my @rest;
322   DynaLoader::dl_unload_file($_) or push @rest, $_ for @DynaLoader::dl_librefs;
323   @DynaLoader::dl_librefs = @rest;
324  }
325 }
326
327 =head1 CAVEATS
328
329 Perl 5.8 is notorious for leaking like there's no tomorrow, so the suppressions are very likely not to be complete on it.
330 You also have a better chance to get more accurate results if your perl is built with debugging enabled.
331 Using the latest C<valgrind> available will also help.
332
333 This module is not really secure.
334 It's definitely not taint safe.
335 That shouldn't be a problem for test files.
336
337 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.
338
339 =head1 DEPENDENCIES
340
341 L<XML::Twig>, L<version>, L<File::HomeDir>, L<Env::Sanctify>, L<Perl::Destruct::Level>.
342
343 =head1 SEE ALSO
344
345 All the C<Test::Valgrind::*> API, including L<Test::Valgrind::Command>, L<Test::Valgrind::Tool>, L<Test::Valgrind::Action> and L<Test::Valgrind::Session>.
346
347 The C<valgrind(1)> man page.
348
349 L<Test::LeakTrace>.
350
351 L<Devel::Leak>, L<Devel::LeakTrace>, L<Devel::LeakTrace::Fast>.
352
353 =head1 AUTHOR
354
355 Vincent Pit, C<< <perl at profvince.com> >>, L<http://www.profvince.com>.
356
357 You can contact me by mail or on C<irc.perl.org> (vincent).
358
359 =head1 BUGS
360
361 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>.
362 I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
363
364 =head1 SUPPORT
365
366 You can find documentation for this module with the perldoc command.
367
368     perldoc Test::Valgrind
369
370 =head1 ACKNOWLEDGEMENTS
371
372 RafaE<euml>l Garcia-Suarez, for writing and instructing me about the existence of L<Perl::Destruct::Level> (Elizabeth Mattijsen is a close second).
373
374 H.Merijn Brand, for daring to test this thing.
375
376 David Cantrell, for providing shell access to one of his smokers where the tests were failing.
377
378 The Debian-perl team, for offering all the feedback they could regarding the build issues they met.
379
380 All you people that showed interest in this module, which motivated me into completely rewriting it.
381
382 =head1 COPYRIGHT & LICENSE
383
384 Copyright 2008,2009,2010,2011,2013 Vincent Pit, all rights reserved.
385
386 This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
387
388 =cut
389
390 1; # End of Test::Valgrind