=head1 VERSION
-Version 1.14
+Version 1.15
=cut
-our $VERSION = '1.14';
+our $VERSION = '1.15';
=head1 DESCRIPTION
min_version => $min_version,
regen_def_supp => $regen_def_supp,
no_def_supp => $no_def_supp,
+ allow_no_supp => $allow_no_supp,
extra_supps => \@extra_supps,
);
=item *
+If C<$allow_no_supp> is true, the command will always be run into C<valgrind> even if no appropriate suppression file is available.
+
+Defaults to false.
+
+=item *
+
C<$extra_supps> is a reference to an array of optional suppression files that will be passed to C<valgrind>.
Defaults to none.
version => $version,
regen_def_supp => delete($args{regen_def_supp}),
no_def_supp => delete($args{no_def_supp}),
+ allow_no_supp => delete($args{allow_no_supp}),
extra_supps => $extra_supps,
}, $class;
}
Read-only accessor for the C<no_def_supp> option.
+=head2 C<allow_no_supp>
+
+ my $allow_no_supp = $tvs->allow_no_supp;
+
+Read-only accessor for the C<allow_no_supp> option.
+
=cut
-eval "sub $_ { \$_[0]->{$_} }" for qw<valgrind regen_def_supp no_def_supp>;
+eval "sub $_ { \$_[0]->{$_} }" for qw<
+ valgrind
+ regen_def_supp
+ no_def_supp
+ allow_no_supp
+>;
=head2 C<extra_supps>
=cut
sub run {
- my $self = shift;
-
- my %args = @_;
-
- $self->start(%args);
- my $guard = Test::Valgrind::Session::Guard->new(sub { $self->finish });
-
- $self->_run($args{command});
-}
+ my ($self, %args) = @_;
-sub _run {
- my ($self, $cmd) = @_;
+ for (qw<action tool command>) {
+ my $base = 'Test::Valgrind::' . ucfirst;
+ my $value = $args{$_};
+ $self->_croak("Invalid $_") unless Scalar::Util::blessed($value)
+ and $value->isa($base);
+ $self->$_($args{$_})
+ }
+ my $cmd = $self->command;
if ($cmd->isa('Test::Valgrind::Command::Aggregate')) {
- $self->_run($_) for $cmd->commands;
+ for my $subcmd ($cmd->commands) {
+ $args{command} = $subcmd;
+ $self->run(%args);
+ }
return;
}
- $self->command($cmd);
-
$self->report($self->report_class->new_diag(
'Using valgrind ' . $self->version . ' located at ' . $self->valgrind
));
my @supp_args;
if ($self->do_suppressions) {
push @supp_args, '--gen-suppressions=all';
- } elsif (not $self->no_def_supp) {
- my $def_supp = $self->def_supp_file;
- my $forced;
- if ($self->regen_def_supp and -e $def_supp) {
- 1 while unlink $def_supp;
- $forced = 1;
+ } else {
+ if (!$self->no_def_supp) {
+ my $def_supp = $self->def_supp_file;
+ my $forced;
+ if ($self->regen_def_supp and -e $def_supp) {
+ 1 while unlink $def_supp;
+ $forced = 1;
+ }
+ if (defined $def_supp and not -e $def_supp) {
+ $self->report($self->report_class->new_diag(
+ 'Generating suppressions' . ($forced ? ' (forced)' : '') . '...'
+ ));
+ require Test::Valgrind::Suppressions;
+ Test::Valgrind::Suppressions->generate(
+ tool => $self->tool,
+ command => $self->command,
+ target => $def_supp,
+ );
+ $self->_croak('Couldn\'t generate suppressions') unless -e $def_supp;
+ $self->report($self->report_class->new_diag(
+ "Suppressions for this perl stored in $def_supp"
+ ));
+ }
}
- if (defined $def_supp and not -e $def_supp) {
+ my @supp_files = grep {
+ -e $_ and $self->command->check_suppressions_file($_)
+ } $self->suppressions;
+ if (@supp_files > 1) {
+ my $files_list = join "\n", map " $_", @supp_files;
$self->report($self->report_class->new_diag(
- 'Generating suppressions' . ($forced ? ' (forced)' : '') . '...'
+ "Using suppressions from:\n$files_list"
));
- require Test::Valgrind::Suppressions;
- Test::Valgrind::Suppressions->generate(
- tool => $self->tool,
- command => $self->command,
- target => $def_supp,
- );
- $self->_croak('Couldn\'t generate suppressions') unless -e $def_supp;
+ } elsif (@supp_files) {
$self->report($self->report_class->new_diag(
- "Suppressions for this perl stored in $def_supp"
+ "Using suppressions from $supp_files[0]"
));
+ } elsif ($self->allow_no_supp) {
+ $self->report($self->report_class->new_diag("No suppressions used"));
+ } else {
+ $self->_croak("No compatible suppressions available");
}
- for ($self->suppressions) {
- next unless -e $_;
- $self->report($self->report_class->new_diag("Using suppression file $_"));
- push @supp_args, "--suppressions=$_";
- }
+ @supp_args = map "--suppressions=$_", @supp_files;
}
+ my $guard = Test::Valgrind::Session::Guard->new(sub { $self->finish });
+ $self->start;
+
pipe my $vrdr, my $vwtr or $self->_croak("pipe(\$vrdr, \$vwtr): $!");
{
my $oldfh = select $vrdr;
$self->_croak("fork(): $!") unless defined $pid;
if ($pid == 0) {
- eval 'setpgrp 0, 0';
+ {
+ local $@;
+ eval { setpgrp(0, 0) };
+ }
close $vrdr or $self->_croak("close(\$vrdr): $!");
fcntl $vwtr, Fcntl::F_SETFD(), 0
or $self->_croak("fcntl(\$vwtr, F_SETFD, 0): $!");
local $SIG{INT} = sub {
kill -(POSIX::SIGKILL()) => $pid;
waitpid $pid, 0;
- die 'interrupted';
+ die 'valgrind analysis was interrupted';
};
close $vwtr or $self->_croak("close(\$vwtr): $!");
- $self->parser->parse($self, $vrdr);
+ my $aborted = $self->parser->parse($self, $vrdr);
+
+ kill -(POSIX::SIGKILL()) => $pid if $aborted;
$self->{exit_code} = (waitpid($pid, 0) == $pid) ? $? >> 8 : 255;
=head2 C<start>
- $tvs->start(
- action => $action,
- tool => $tool,
- command => $command,
- );
+ $tvs->start;
Starts the action and tool associated to the current run.
It's automatically called at the beginning of L</run>.
sub start {
my $self = shift;
- my %args = @_;
-
- for (qw<action tool command>) {
- my $base = 'Test::Valgrind::' . ucfirst;
- my $value = $args{$_};
- $self->_croak("Invalid $_") unless Scalar::Util::blessed($value)
- and $value->isa($base);
- $self->$_($args{$_})
- }
-
delete @{$self}{qw<last_status exit_code>};
$self->tool->start($self);
=head1 COPYRIGHT & LICENSE
-Copyright 2009,2010,2011,2013 Vincent Pit, all rights reserved.
+Copyright 2009,2010,2011,2013,2015 Vincent Pit, all rights reserved.
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.