]> git.vpit.fr Git - perl/modules/Test-Valgrind.git/blob - lib/Test/Valgrind/Suppressions.pm
This is 1.19
[perl/modules/Test-Valgrind.git] / lib / Test / Valgrind / Suppressions.pm
1 package Test::Valgrind::Suppressions;
2
3 use strict;
4 use warnings;
5
6 =head1 NAME
7
8 Test::Valgrind::Suppressions - Generate suppressions for given tool and command.
9
10 =head1 VERSION
11
12 Version 1.19
13
14 =cut
15
16 our $VERSION = '1.19';
17
18 =head1 DESCRIPTION
19
20 This module is an helper for generating suppressions.
21
22 =cut
23
24 use base qw<Test::Valgrind::Carp>;
25
26 =head1 METHODS
27
28 =head2 C<generate>
29
30     Test::Valgrind::Suppressions->generate(
31      tool    => $tool,
32      command => $command,
33      target  => $target,
34     );
35
36 Generates suppressions for the command C<< $command->new_trainer >> and the tool C<< $tool->new_trainer >>, and writes them in the file specified by C<$target>.
37 The action used behind the scenes is L<Test::Valgrind::Action::Suppressions>.
38
39 Returns the status code.
40
41 =cut
42
43 sub generate {
44  my $self = shift;
45
46  my %args = @_;
47
48  my $cmd = delete $args{command};
49  unless (ref $cmd) {
50   require Test::Valgrind::Command;
51   $cmd = Test::Valgrind::Command->new(
52    command => $cmd,
53    args    => [ ],
54   );
55  }
56  $cmd = $cmd->new_trainer;
57  return unless defined $cmd;
58
59  my $tool = delete $args{tool};
60  unless (ref $tool) {
61   require Test::Valgrind::Tool;
62   $tool = Test::Valgrind::Tool->new(tool => $tool);
63  }
64  $tool = $tool->new_trainer;
65  return unless defined $tool;
66
67  my $target = delete $args{target};
68  $self->_croak('Invalid target') unless $target and not ref $target;
69
70  require Test::Valgrind::Action;
71  my $action = Test::Valgrind::Action->new(
72   action => 'Suppressions',
73   target => $target,
74   name   => 'PerlSuppression',
75  );
76
77  require Test::Valgrind::Session;
78  my $sess = Test::Valgrind::Session->new(
79   min_version => $tool->requires_version,
80  );
81
82  eval {
83   $sess->run(
84    command => $cmd,
85    tool    => $tool,
86    action  => $action,
87   );
88  };
89  $self->_croak($@) if $@;
90
91  my $status = $sess->status;
92  $status = 255 unless defined $status;
93
94  return $status;
95 }
96
97 =head2 C<maybe_generalize>
98
99     my $mangled_suppression = Test::Valgrind::Suppressions->maybe_generalize(
100      $session,
101      $suppression,
102     );
103
104 Removes all wildcard frames at the end of the suppression.
105 It also replaces sequences of wildcard frames by C<'...'> when C<valgrind> C<3.4.0> or higher is used.
106 Returns the mangled suppression.
107
108 =cut
109
110 sub maybe_generalize {
111  shift;
112
113  my ($sess, $supp) = @_;
114
115  1 while $supp =~ s/[^\r\n]*:\s*\*\s*$//;
116
117  # With valgrind 3.4.0, we can replace unknown series of frames by '...'
118  my $can_ellipsis = $sess->version >= '3.4.0';
119
120  my $did_length_check;
121
122  ELLIPSIS: {
123   if ($can_ellipsis) {
124    $supp .= "...\n";
125    $supp =~ s/(?:^\s*(?:\.{3}|\*:\S*|obj:\*)\s*(?:\n|\z))+/...\n/mg;
126   }
127
128   last if $did_length_check++;
129
130   my $frames_count =()= $supp =~ m/^(?:(?:obj|fun|\*):|\.{3}\s*$)/mg;
131   if ($frames_count > 24) {
132    # Keep only 24 frames, and even sacrifice one more if we can do ellipsis.
133    my $last = $can_ellipsis ? 23 : 24;
134    my $len  = length $supp;
135    $supp    =~ m/^(?:(?:obj|fun|\*):\S*|\.{3})\s*\n/mg for 1 .. $last;
136    my $p    = pos $supp;
137    substr $supp, $p, $len - $p, '';
138    redo ELLIPSIS if $can_ellipsis;
139   }
140  }
141
142  $supp;
143 }
144
145 =head2 C<maybe_z_demangle>
146
147     my $demangled_symbol = Test::Valgrind::Suppressions->maybe_z_demangle(
148      $symbol,
149     );
150
151 If C<$symbol> is Z-encoded as described in C<valgrind>'s F<include/pub_tool_redir.h>, extract and decode its function name part.
152 Otherwise, C<$symbol> is returned as is.
153
154 This routine follows C<valgrind>'s F<coregrind/m_demangle/demangle.c:maybe_Z_demangle>.
155
156 =cut
157
158 my %z_escapes = (
159  a => '*',
160  c => ':',
161  d => '.',
162  h => '-',
163  p => '+',
164  s => ' ',
165  u => '_',
166  A => '@',
167  D => '$',
168  L => '(',
169  R => ')',
170  Z => 'Z',
171 );
172
173 sub maybe_z_demangle {
174  my ($self, $sym) = @_;
175
176  $sym =~ s/^_vg[rwn]Z([ZU])_// or return $sym;
177
178  my $fn_is_encoded = $1 eq 'Z';
179
180  $sym =~ /^VG_Z_/ and $self->_croak('Symbol with a "VG_Z_" prefix is invalid');
181  $sym =~ s/^[^_]*_//
182                    or $self->_croak('Symbol doesn\'t contain a function name');
183
184  if ($fn_is_encoded) {
185   $sym =~ s/Z(.)/
186    my $c = $z_escapes{$1};
187    $self->_croak('Invalid escape sequence') unless defined $c;
188    $c;
189   /ge;
190  }
191
192  $self->_croak('Empty symbol') unless length $sym;
193
194  return $sym;
195 }
196
197 =head1 SEE ALSO
198
199 L<Test::Valgrind>, L<Test::Valgrind::Command>, L<Test::Valgrind::Tool>, L<Test::Valgrind::Action::Suppressions>.
200
201 =head1 AUTHOR
202
203 Vincent Pit, C<< <perl at profvince.com> >>, L<http://www.profvince.com>.
204
205 You can contact me by mail or on C<irc.perl.org> (vincent).
206
207 =head1 BUGS
208
209 Please report any bugs or feature requests to C<bug-test-valgrind-suppressions at rt.cpan.org>, or through the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Test-Valgrind>.
210 I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
211
212 =head1 SUPPORT
213
214 You can find documentation for this module with the perldoc command.
215
216     perldoc Test::Valgrind::Suppressions
217
218 =head1 COPYRIGHT & LICENSE
219
220 Copyright 2008,2009,2010,2011,2013,2015,2016 Vincent Pit, all rights reserved.
221
222 This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
223
224 =cut
225
226 1; # End of Test::Valgrind::Suppressions