line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Test::Valgrind::Session; |
2
|
|
|
|
|
|
|
|
3
|
8
|
|
|
8
|
|
3109
|
use strict; |
|
8
|
|
|
|
|
14
|
|
|
8
|
|
|
|
|
206
|
|
4
|
8
|
|
|
8
|
|
37
|
use warnings; |
|
8
|
|
|
|
|
16
|
|
|
8
|
|
|
|
|
317
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
=head1 NAME |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
Test::Valgrind::Session - Test::Valgrind session object. |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
=head1 VERSION |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
Version 1.17 |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
=cut |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
our $VERSION = '1.17'; |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
=head1 DESCRIPTION |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
This class supervises the execution of the C process. |
21
|
|
|
|
|
|
|
It also acts as a dispatcher between the different components. |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
=cut |
24
|
|
|
|
|
|
|
|
25
|
8
|
|
|
8
|
|
37
|
use File::Spec (); |
|
8
|
|
|
|
|
14
|
|
|
8
|
|
|
|
|
118
|
|
26
|
8
|
|
|
8
|
|
37
|
use Scalar::Util (); |
|
8
|
|
|
|
|
13
|
|
|
8
|
|
|
|
|
120
|
|
27
|
|
|
|
|
|
|
|
28
|
8
|
|
|
8
|
|
46
|
use Fcntl (); # F_SETFD |
|
8
|
|
|
|
|
12
|
|
|
8
|
|
|
|
|
152
|
|
29
|
8
|
|
|
8
|
|
7630
|
use IO::Select; |
|
8
|
|
|
|
|
15414
|
|
|
8
|
|
|
|
|
465
|
|
30
|
8
|
|
|
8
|
|
7322
|
use POSIX (); # SIGKILL, _exit() |
|
8
|
|
|
|
|
65782
|
|
|
8
|
|
|
|
|
202
|
|
31
|
|
|
|
|
|
|
|
32
|
8
|
|
|
8
|
|
5340
|
use version (); |
|
8
|
|
|
|
|
16833
|
|
|
8
|
|
|
|
|
223
|
|
33
|
|
|
|
|
|
|
|
34
|
8
|
|
|
8
|
|
49
|
use base qw; |
|
8
|
|
|
|
|
20
|
|
|
8
|
|
|
|
|
10925
|
|
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
=head1 METHODS |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
=head2 C |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
my $tvs = Test::Valgrind::Session->new( |
41
|
|
|
|
|
|
|
search_dirs => \@search_dirs, |
42
|
|
|
|
|
|
|
valgrind => $valgrind, # One candidate |
43
|
|
|
|
|
|
|
valgrind => \@valgrind, # Several candidates |
44
|
|
|
|
|
|
|
min_version => $min_version, |
45
|
|
|
|
|
|
|
regen_def_supp => $regen_def_supp, |
46
|
|
|
|
|
|
|
no_def_supp => $no_def_supp, |
47
|
|
|
|
|
|
|
allow_no_supp => $allow_no_supp, |
48
|
|
|
|
|
|
|
extra_supps => \@extra_supps, |
49
|
|
|
|
|
|
|
); |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
The package constructor, which takes several options : |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
=over 4 |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
=item * |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
All the directories from C<@search_dirs> will have F appended to create a list of candidates for the C executable. |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
Defaults to the current C environment variable. |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
=item * |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
If a simple scalar C<$valgrind> is passed as the value to C<'valgrind'>, it will be the only candidate. |
64
|
|
|
|
|
|
|
C<@search_dirs> will then be ignored. |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
If an array refernce C<\@valgrind> is passed, its values will be I to the list of the candidates resulting from C<@search_dirs>. |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
=item * |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
C<$min_version> specifies the minimal C version required. |
71
|
|
|
|
|
|
|
The constructor will croak if it's not able to find an adequate C from the supplied candidates list and search path. |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
Defaults to none. |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
=item * |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
If C<$regen_def_supp> is true, the default suppression file associated with the tool and the command will be forcefully regenerated. |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
Defaults to false. |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
=item * |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
If C<$no_def_supp> is true, C won't read the default suppression file associated with the tool and the command. |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
Defaults to false. |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
=item * |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
If C<$allow_no_supp> is true, the command will always be run into C even if no appropriate suppression file is available. |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
Defaults to false. |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
=item * |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
C<$extra_supps> is a reference to an array of optional suppression files that will be passed to C. |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
Defaults to none. |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
=back |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
=cut |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
sub new { |
104
|
16
|
|
|
16
|
1
|
13458
|
my $class = shift; |
105
|
16
|
|
33
|
|
|
119
|
$class = ref($class) || $class; |
106
|
|
|
|
|
|
|
|
107
|
16
|
|
|
|
|
81
|
my %args = @_; |
108
|
|
|
|
|
|
|
|
109
|
16
|
|
|
|
|
30
|
my @paths; |
110
|
16
|
|
|
|
|
40
|
my $vg = delete $args{valgrind}; |
111
|
16
|
100
|
100
|
|
|
115
|
if (defined $vg and not ref $vg) { |
112
|
9
|
|
|
|
|
27
|
@paths = ($vg); |
113
|
|
|
|
|
|
|
} else { |
114
|
7
|
100
|
66
|
|
|
46
|
push @paths, @$vg if $vg and ref $vg eq 'ARRAY'; |
115
|
7
|
|
|
|
|
15
|
my $dirs = delete $args{search_dirs}; |
116
|
7
|
100
|
|
|
|
161
|
$dirs = [ File::Spec->path ] unless $dirs; |
117
|
7
|
50
|
|
|
|
278
|
push @paths, map File::Spec->catfile($_, 'valgrind'), @$dirs |
118
|
|
|
|
|
|
|
if ref $dirs eq 'ARRAY'; |
119
|
|
|
|
|
|
|
} |
120
|
16
|
100
|
|
|
|
67
|
$class->_croak('Empty valgrind candidates list') unless @paths; |
121
|
|
|
|
|
|
|
|
122
|
15
|
|
|
|
|
41
|
my $min_version = delete $args{min_version}; |
123
|
15
|
|
66
|
|
|
197
|
defined and not ref and $_ = version->new($_) for $min_version; |
|
|
|
66
|
|
|
|
|
124
|
|
|
|
|
|
|
|
125
|
15
|
|
|
|
|
31
|
my ($valgrind, $version); |
126
|
15
|
|
|
|
|
37
|
for (@paths) { |
127
|
46
|
100
|
|
|
|
949
|
next unless -x; |
128
|
10
|
|
|
|
|
69206
|
my $ver = qx/$_ --version/; |
129
|
10
|
50
|
|
|
|
449
|
if ($ver =~ /^valgrind-(\d+(\.\d+)*)/) { |
130
|
10
|
100
|
|
|
|
237
|
if ($min_version) { |
131
|
4
|
|
|
|
|
85
|
$version = version->new($1); |
132
|
4
|
100
|
|
|
|
59
|
next if $version < $min_version; |
133
|
|
|
|
|
|
|
} else { |
134
|
6
|
|
|
|
|
112
|
$version = $1; |
135
|
|
|
|
|
|
|
} |
136
|
8
|
|
|
|
|
53
|
$valgrind = $_; |
137
|
8
|
|
|
|
|
81
|
last; |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
} |
140
|
15
|
100
|
|
|
|
127
|
$class->_croak('No appropriate valgrind executable could be found') |
141
|
|
|
|
|
|
|
unless defined $valgrind; |
142
|
|
|
|
|
|
|
|
143
|
8
|
|
|
|
|
47
|
my $extra_supps = delete $args{extra_supps}; |
144
|
8
|
50
|
33
|
|
|
94
|
$extra_supps = [ ] unless $extra_supps and ref $extra_supps eq 'ARRAY'; |
145
|
8
|
0
|
0
|
|
|
40
|
@$extra_supps = grep { defined && -f $_ && -r _ } @$extra_supps; |
|
0
|
|
|
|
|
0
|
|
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
bless { |
148
|
|
|
|
|
|
|
valgrind => $valgrind, |
149
|
|
|
|
|
|
|
version => $version, |
150
|
|
|
|
|
|
|
regen_def_supp => delete($args{regen_def_supp}), |
151
|
|
|
|
|
|
|
no_def_supp => delete($args{no_def_supp}), |
152
|
8
|
|
|
|
|
484
|
allow_no_supp => delete($args{allow_no_supp}), |
153
|
|
|
|
|
|
|
extra_supps => $extra_supps, |
154
|
|
|
|
|
|
|
}, $class; |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
=head2 C |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
my $valgrind_path = $tvs->valgrind; |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
The path to the selected C executable. |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
=head2 C |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
my $valgrind_version = $tvs->version; |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
The L object associated to the selected C. |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
=cut |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
sub version { |
172
|
8
|
|
|
8
|
1
|
25
|
my ($self) = @_; |
173
|
|
|
|
|
|
|
|
174
|
8
|
|
|
|
|
40
|
my $version = $self->{version}; |
175
|
8
|
100
|
|
|
|
190
|
$self->{version} = $version = version->new($version) unless ref $version; |
176
|
|
|
|
|
|
|
|
177
|
8
|
|
|
|
|
543
|
return $version; |
178
|
|
|
|
|
|
|
} |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
=head2 C |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
my $regen_def_supp = $tvs->regen_def_supp; |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
Read-only accessor for the C option. |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
=cut |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
=head2 C |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
my $no_def_supp = $tvs->no_def_supp; |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
Read-only accessor for the C option. |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
=head2 C |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
my $allow_no_supp = $tvs->allow_no_supp; |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
Read-only accessor for the C option. |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
=cut |
201
|
|
|
|
|
|
|
|
202
|
6
|
|
|
6
|
1
|
50
|
eval "sub $_ { \$_[0]->{$_} }" for qw< |
|
12
|
|
|
12
|
1
|
86
|
|
|
0
|
|
|
0
|
1
|
0
|
|
|
8
|
|
|
8
|
1
|
316
|
|
203
|
|
|
|
|
|
|
valgrind |
204
|
|
|
|
|
|
|
regen_def_supp |
205
|
|
|
|
|
|
|
no_def_supp |
206
|
|
|
|
|
|
|
allow_no_supp |
207
|
|
|
|
|
|
|
>; |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
=head2 C |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
my @extra_supps = $tvs->extra_supps; |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
Read-only accessor for the C option. |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
=cut |
216
|
|
|
|
|
|
|
|
217
|
6
|
50
|
|
6
|
1
|
16
|
sub extra_supps { @{$_[0]->{extra_supps} || []} } |
|
6
|
|
|
|
|
66
|
|
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
=head2 C |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
$tvs->run( |
222
|
|
|
|
|
|
|
action => $action, |
223
|
|
|
|
|
|
|
tool => $tool, |
224
|
|
|
|
|
|
|
command => $command, |
225
|
|
|
|
|
|
|
); |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
Runs the command C<$command> through C with the tool C<$tool>, which will report to the action C<$action>. |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
If the command is a L object, the action and the tool will be initialized once before running all the aggregated commands. |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
=cut |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
sub run { |
234
|
6
|
|
|
6
|
1
|
3504
|
my ($self, %args) = @_; |
235
|
|
|
|
|
|
|
|
236
|
6
|
|
|
|
|
22
|
for (qw) { |
237
|
18
|
|
|
|
|
78
|
my $base = 'Test::Valgrind::' . ucfirst; |
238
|
18
|
|
|
|
|
46
|
my $value = $args{$_}; |
239
|
18
|
50
|
33
|
|
|
464
|
$self->_croak("Invalid $_") unless Scalar::Util::blessed($value) |
240
|
|
|
|
|
|
|
and $value->isa($base); |
241
|
18
|
|
|
|
|
1392
|
$self->$_($args{$_}) |
242
|
|
|
|
|
|
|
} |
243
|
|
|
|
|
|
|
|
244
|
6
|
|
|
|
|
276
|
my $cmd = $self->command; |
245
|
6
|
50
|
|
|
|
106
|
if ($cmd->isa('Test::Valgrind::Command::Aggregate')) { |
246
|
0
|
|
|
|
|
0
|
for my $subcmd ($cmd->commands) { |
247
|
0
|
|
|
|
|
0
|
$args{command} = $subcmd; |
248
|
0
|
|
|
|
|
0
|
$self->run(%args); |
249
|
|
|
|
|
|
|
} |
250
|
0
|
|
|
|
|
0
|
return; |
251
|
|
|
|
|
|
|
} |
252
|
|
|
|
|
|
|
|
253
|
6
|
|
|
|
|
58
|
$self->report($self->report_class->new_diag( |
254
|
|
|
|
|
|
|
'Using valgrind ' . $self->version . ' located at ' . $self->valgrind |
255
|
|
|
|
|
|
|
)); |
256
|
|
|
|
|
|
|
|
257
|
6
|
|
|
|
|
358
|
my $env = $self->command->env($self); |
258
|
|
|
|
|
|
|
|
259
|
6
|
|
|
|
|
558
|
my @supp_args; |
260
|
6
|
50
|
|
|
|
24
|
if ($self->do_suppressions) { |
261
|
0
|
|
|
|
|
0
|
push @supp_args, '--gen-suppressions=all'; |
262
|
|
|
|
|
|
|
} else { |
263
|
6
|
50
|
|
|
|
274
|
if (!$self->no_def_supp) { |
264
|
0
|
|
|
|
|
0
|
my $def_supp = $self->def_supp_file; |
265
|
0
|
|
|
|
|
0
|
my $forced; |
266
|
0
|
0
|
0
|
|
|
0
|
if ($self->regen_def_supp and -e $def_supp) { |
267
|
0
|
|
|
|
|
0
|
1 while unlink $def_supp; |
268
|
0
|
|
|
|
|
0
|
$forced = 1; |
269
|
|
|
|
|
|
|
} |
270
|
0
|
0
|
0
|
|
|
0
|
if (defined $def_supp and not -e $def_supp) { |
271
|
0
|
0
|
|
|
|
0
|
$self->report($self->report_class->new_diag( |
272
|
|
|
|
|
|
|
'Generating suppressions' . ($forced ? ' (forced)' : '') . '...' |
273
|
|
|
|
|
|
|
)); |
274
|
0
|
|
|
|
|
0
|
require Test::Valgrind::Suppressions; |
275
|
0
|
|
|
|
|
0
|
Test::Valgrind::Suppressions->generate( |
276
|
|
|
|
|
|
|
tool => $self->tool, |
277
|
|
|
|
|
|
|
command => $self->command, |
278
|
|
|
|
|
|
|
target => $def_supp, |
279
|
|
|
|
|
|
|
); |
280
|
0
|
0
|
|
|
|
0
|
$self->_croak('Couldn\'t generate suppressions') unless -e $def_supp; |
281
|
0
|
|
|
|
|
0
|
$self->report($self->report_class->new_diag( |
282
|
|
|
|
|
|
|
"Suppressions for this perl stored in $def_supp" |
283
|
|
|
|
|
|
|
)); |
284
|
|
|
|
|
|
|
} |
285
|
|
|
|
|
|
|
} |
286
|
|
|
|
|
|
|
my @supp_files = grep { |
287
|
6
|
0
|
|
|
|
62
|
-e $_ and $self->command->check_suppressions_file($_) |
|
0
|
|
|
|
|
0
|
|
288
|
|
|
|
|
|
|
} $self->suppressions; |
289
|
6
|
50
|
|
|
|
276
|
if (@supp_files > 1) { |
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
290
|
0
|
|
|
|
|
0
|
my $files_list = join "\n", map " $_", @supp_files; |
291
|
0
|
|
|
|
|
0
|
$self->report($self->report_class->new_diag( |
292
|
|
|
|
|
|
|
"Using suppressions from:\n$files_list" |
293
|
|
|
|
|
|
|
)); |
294
|
|
|
|
|
|
|
} elsif (@supp_files) { |
295
|
0
|
|
|
|
|
0
|
$self->report($self->report_class->new_diag( |
296
|
|
|
|
|
|
|
"Using suppressions from $supp_files[0]" |
297
|
|
|
|
|
|
|
)); |
298
|
|
|
|
|
|
|
} elsif ($self->allow_no_supp) { |
299
|
4
|
|
|
|
|
44
|
$self->report($self->report_class->new_diag("No suppressions used")); |
300
|
|
|
|
|
|
|
} else { |
301
|
2
|
|
|
|
|
32
|
$self->_croak("No compatible suppressions available"); |
302
|
|
|
|
|
|
|
} |
303
|
4
|
|
|
|
|
60
|
@supp_args = map "--suppressions=$_", @supp_files; |
304
|
|
|
|
|
|
|
} |
305
|
|
|
|
|
|
|
|
306
|
4
|
|
|
|
|
16
|
my $error; |
307
|
|
|
|
|
|
|
GUARDED: { |
308
|
4
|
|
|
2
|
|
16
|
my $guard = Test::Valgrind::Session::Guard->new(sub { $self->finish }); |
|
4
|
|
|
|
|
118
|
|
|
2
|
|
|
|
|
28
|
|
309
|
4
|
|
|
|
|
28
|
$self->start; |
310
|
|
|
|
|
|
|
|
311
|
4
|
50
|
|
|
|
196
|
pipe my $vrdr, my $vwtr or $self->_croak("pipe(\$vrdr, \$vwtr): $!"); |
312
|
|
|
|
|
|
|
{ |
313
|
4
|
|
|
|
|
10
|
my $oldfh = select $vrdr; |
|
4
|
|
|
|
|
24
|
|
314
|
4
|
|
|
|
|
38
|
$|++; |
315
|
4
|
|
|
|
|
16
|
select $oldfh; |
316
|
|
|
|
|
|
|
} |
317
|
|
|
|
|
|
|
|
318
|
4
|
50
|
|
|
|
128
|
pipe my $erdr, my $ewtr or $self->_croak("pipe(\$erdr, \$ewtr): $!"); |
319
|
|
|
|
|
|
|
{ |
320
|
4
|
|
|
|
|
14
|
my $oldfh = select $erdr; |
|
4
|
|
|
|
|
24
|
|
321
|
4
|
|
|
|
|
20
|
$|++; |
322
|
4
|
|
|
|
|
32
|
select $oldfh; |
323
|
|
|
|
|
|
|
} |
324
|
|
|
|
|
|
|
|
325
|
4
|
|
|
|
|
5563
|
my $pid = fork; |
326
|
4
|
50
|
|
|
|
316
|
$self->_croak("fork(): $!") unless defined $pid; |
327
|
|
|
|
|
|
|
|
328
|
4
|
100
|
|
|
|
85
|
if ($pid == 0) { |
329
|
|
|
|
|
|
|
{ |
330
|
2
|
|
|
|
|
18
|
local $@; |
|
2
|
|
|
|
|
48
|
|
331
|
2
|
|
|
|
|
34
|
eval { setpgrp(0, 0) }; |
|
2
|
|
|
|
|
171
|
|
332
|
|
|
|
|
|
|
} |
333
|
|
|
|
|
|
|
|
334
|
2
|
50
|
|
|
|
136
|
close $erdr or POSIX::_exit(255); |
335
|
|
|
|
|
|
|
|
336
|
2
|
|
|
|
|
18
|
local $@; |
337
|
2
|
|
|
|
|
14
|
eval { |
338
|
2
|
50
|
|
|
|
53
|
close $vrdr or $self->_croak("close(\$vrdr): $!"); |
339
|
|
|
|
|
|
|
|
340
|
2
|
50
|
|
|
|
42
|
fcntl $vwtr, Fcntl::F_SETFD(), 0 |
341
|
|
|
|
|
|
|
or $self->_croak("fcntl(\$vwtr, F_SETFD, 0): $!"); |
342
|
|
|
|
|
|
|
|
343
|
2
|
|
|
|
|
811
|
my @args = ( |
344
|
|
|
|
|
|
|
$self->valgrind, |
345
|
|
|
|
|
|
|
$self->tool->args($self), |
346
|
|
|
|
|
|
|
@supp_args, |
347
|
|
|
|
|
|
|
$self->parser->args($self, $vwtr), |
348
|
|
|
|
|
|
|
$self->command->args($self), |
349
|
|
|
|
|
|
|
); |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
{ |
352
|
8
|
|
|
8
|
|
48
|
no warnings 'exec'; |
|
8
|
|
|
|
|
16
|
|
|
8
|
|
|
|
|
6005
|
|
|
2
|
|
|
|
|
18
|
|
353
|
2
|
|
|
|
|
6
|
exec { $args[0] } @args; |
|
2
|
|
|
|
|
0
|
|
354
|
|
|
|
|
|
|
} |
355
|
0
|
|
|
|
|
0
|
$self->_croak("exec @args: $!"); |
356
|
|
|
|
|
|
|
}; |
357
|
|
|
|
|
|
|
|
358
|
0
|
|
|
|
|
0
|
print $ewtr $@; |
359
|
0
|
|
|
|
|
0
|
close $ewtr; |
360
|
|
|
|
|
|
|
|
361
|
0
|
|
|
|
|
0
|
POSIX::_exit(255); |
362
|
|
|
|
|
|
|
} |
363
|
|
|
|
|
|
|
|
364
|
2
|
|
|
|
|
45
|
local $@; |
365
|
|
|
|
|
|
|
eval { |
366
|
|
|
|
|
|
|
local $SIG{INT} = sub { |
367
|
0
|
|
|
0
|
|
0
|
die 'valgrind analysis was interrupted'; |
368
|
2
|
|
|
|
|
335
|
}; |
369
|
|
|
|
|
|
|
|
370
|
2
|
50
|
|
|
|
88
|
close $vwtr or $self->_croak("close(\$vwtr): $!"); |
371
|
2
|
50
|
|
|
|
84
|
close $ewtr or $self->_croak("close(\$ewtr): $!"); |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
SEL: { |
374
|
2
|
|
|
|
|
27
|
my $sel = IO::Select->new($vrdr, $erdr); |
|
2
|
|
|
|
|
180
|
|
375
|
|
|
|
|
|
|
|
376
|
2
|
|
|
|
|
415
|
my $child_err; |
377
|
2
|
|
|
|
|
36
|
while (my @ready = $sel->can_read) { |
378
|
4
|
100
|
66
|
|
|
1477613
|
last SEL if @ready == 1 and fileno $ready[0] == fileno $vrdr; |
379
|
|
|
|
|
|
|
|
380
|
3
|
|
|
|
|
16
|
my $buf; |
381
|
3
|
|
|
|
|
70
|
my $bytes_read = sysread $erdr, $buf, 4096; |
382
|
3
|
50
|
|
|
|
89
|
if (not defined $bytes_read) { |
|
|
100
|
|
|
|
|
|
383
|
0
|
|
|
|
|
0
|
$self->_croak("sysread(\$erdr): $!"); |
384
|
|
|
|
|
|
|
} elsif ($bytes_read) { |
385
|
1
|
50
|
|
|
|
20
|
$sel->remove($vrdr) unless $child_err; |
386
|
1
|
|
|
|
|
113
|
$child_err .= $buf; |
387
|
|
|
|
|
|
|
} else { |
388
|
2
|
|
|
|
|
21
|
$sel->remove($erdr); |
389
|
2
|
100
|
|
|
|
194
|
die $child_err if $child_err; |
390
|
|
|
|
|
|
|
} |
391
|
|
|
|
|
|
|
} |
392
|
|
|
|
|
|
|
} |
393
|
|
|
|
|
|
|
|
394
|
1
|
|
|
|
|
140
|
my $aborted = $self->parser->parse($self, $vrdr); |
395
|
|
|
|
|
|
|
|
396
|
1
|
50
|
|
|
|
15
|
if ($aborted) { |
397
|
0
|
|
|
|
|
0
|
$self->report($self->report_class->new_diag("valgrind has aborted")); |
398
|
0
|
|
|
|
|
0
|
return 0; |
399
|
|
|
|
|
|
|
} |
400
|
|
|
|
|
|
|
|
401
|
1
|
|
|
|
|
25
|
1; |
402
|
2
|
100
|
|
|
|
68
|
} or do { |
403
|
1
|
|
|
|
|
4
|
$error = $@; |
404
|
1
|
50
|
|
|
|
40
|
kill -(POSIX::SIGKILL()) => $pid if kill 0 => $pid; |
405
|
1
|
|
|
|
|
50
|
close $erdr; |
406
|
1
|
|
|
|
|
9
|
close $vrdr; |
407
|
1
|
|
|
|
|
2429
|
waitpid $pid, 0; |
408
|
|
|
|
|
|
|
# Force the guard destructor to trigger now so that old perls don't lose $@ |
409
|
1
|
|
|
|
|
36
|
last GUARDED; |
410
|
|
|
|
|
|
|
}; |
411
|
|
|
|
|
|
|
|
412
|
1
|
50
|
|
|
|
66
|
$self->{exit_code} = (waitpid($pid, 0) == $pid) ? $? >> 8 : 255; |
413
|
|
|
|
|
|
|
|
414
|
1
|
50
|
|
|
|
20
|
close $erdr or $self->_croak("close(\$erdr): $!"); |
415
|
1
|
50
|
|
|
|
14
|
close $vrdr or $self->_croak("close(\$vrdr): $!"); |
416
|
|
|
|
|
|
|
|
417
|
1
|
|
|
|
|
32
|
return; |
418
|
|
|
|
|
|
|
} |
419
|
|
|
|
|
|
|
|
420
|
1
|
50
|
|
|
|
21
|
die $error if $error; |
421
|
|
|
|
|
|
|
|
422
|
0
|
|
|
|
|
0
|
return; |
423
|
|
|
|
|
|
|
} |
424
|
|
|
|
|
|
|
|
425
|
4
|
|
|
4
|
|
18
|
sub Test::Valgrind::Session::Guard::new { bless \($_[1]), $_[0] } |
426
|
|
|
|
|
|
|
|
427
|
2
|
|
|
2
|
|
6
|
sub Test::Valgrind::Session::Guard::DESTROY { ${$_[0]}->() } |
|
2
|
|
|
|
|
78
|
|
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
=head2 C |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
Read-only accessor for the C associated to the current run. |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
=head2 C |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
Read-only accessor for the C associated to the current run. |
436
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
=head2 C |
438
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
Read-only accessor for the C associated to the current tool. |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
=head2 C |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
Read-only accessor for the C associated to the current run. |
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
=cut |
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
my @members; |
448
|
|
|
|
|
|
|
BEGIN { |
449
|
8
|
|
|
8
|
|
136
|
@members = qw; |
450
|
8
|
|
|
|
|
29
|
for (@members) { |
451
|
32
|
100
|
|
40
|
1
|
2022
|
eval "sub $_ { \@_ <= 1 ? \$_[0]->{$_} : (\$_[0]->{$_} = \$_[1]) }"; |
|
40
|
100
|
|
32
|
1
|
535
|
|
|
32
|
100
|
|
11
|
1
|
482
|
|
|
11
|
100
|
|
40
|
1
|
361
|
|
|
40
|
|
|
|
|
978
|
|
452
|
32
|
50
|
|
|
|
5175
|
die if $@; |
453
|
|
|
|
|
|
|
} |
454
|
|
|
|
|
|
|
} |
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
=head2 C |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
Forwards to C<< ->action->do_suppressions >>. |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
=cut |
461
|
|
|
|
|
|
|
|
462
|
16
|
|
|
16
|
1
|
670
|
sub do_suppressions { $_[0]->action->do_suppressions } |
463
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
=head2 C |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
Calls C<< ->tool->parser_class >> with the current session object as the unique argument. |
467
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
=cut |
469
|
|
|
|
|
|
|
|
470
|
4
|
|
|
4
|
1
|
144
|
sub parser_class { $_[0]->tool->parser_class($_[0]) } |
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
=head2 C |
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
Calls C<< ->tool->report_class >> with the current session object as the unique argument. |
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
=cut |
477
|
|
|
|
|
|
|
|
478
|
10
|
|
|
10
|
1
|
412
|
sub report_class { $_[0]->tool->report_class($_[0]) } |
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
=head2 C |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
Returns an absolute path to the default suppression file associated to the current session. |
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
C will be returned as soon as any of C<< ->command->suppressions_tag >> or C<< ->tool->suppressions_tag >> are also C. |
485
|
|
|
|
|
|
|
Otherwise, the file part of the name is builded by joining those two together, and the directory part is roughly F<< File::HomeDir->my_home / .perl / Test-Valgrind / suppressions / $VERSION >>. |
486
|
|
|
|
|
|
|
|
487
|
|
|
|
|
|
|
=cut |
488
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
sub def_supp_file { |
490
|
0
|
|
|
0
|
1
|
0
|
my ($self) = @_; |
491
|
|
|
|
|
|
|
|
492
|
0
|
|
|
|
|
0
|
my $tool_tag = $self->tool->suppressions_tag($self); |
493
|
0
|
0
|
|
|
|
0
|
return unless defined $tool_tag; |
494
|
|
|
|
|
|
|
|
495
|
0
|
|
|
|
|
0
|
my $cmd_tag = $self->command->suppressions_tag($self); |
496
|
0
|
0
|
|
|
|
0
|
return unless defined $cmd_tag; |
497
|
|
|
|
|
|
|
|
498
|
0
|
|
|
|
|
0
|
require File::HomeDir; # So that it's not needed at configure time. |
499
|
|
|
|
|
|
|
|
500
|
0
|
|
|
|
|
0
|
return File::Spec->catfile( |
501
|
|
|
|
|
|
|
File::HomeDir->my_home, |
502
|
|
|
|
|
|
|
'.perl', |
503
|
|
|
|
|
|
|
'Test-Valgrind', |
504
|
|
|
|
|
|
|
'suppressions', |
505
|
|
|
|
|
|
|
$VERSION, |
506
|
|
|
|
|
|
|
"$tool_tag-$cmd_tag.supp", |
507
|
|
|
|
|
|
|
); |
508
|
|
|
|
|
|
|
} |
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
=head2 C |
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
my @suppressions = $tvs->suppressions; |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
Returns the list of all the suppressions that will be passed to C. |
515
|
|
|
|
|
|
|
Honors L and L. |
516
|
|
|
|
|
|
|
|
517
|
|
|
|
|
|
|
=cut |
518
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
sub suppressions { |
520
|
6
|
|
|
6
|
1
|
18
|
my ($self) = @_; |
521
|
|
|
|
|
|
|
|
522
|
6
|
|
|
|
|
18
|
my @supps; |
523
|
6
|
50
|
|
|
|
242
|
unless ($self->no_def_supp) { |
524
|
0
|
|
|
|
|
0
|
my $def_supp = $self->def_supp_file; |
525
|
0
|
0
|
|
|
|
0
|
push @supps, $def_supp if defined $def_supp; |
526
|
|
|
|
|
|
|
} |
527
|
6
|
|
|
|
|
34
|
push @supps, $self->extra_supps; |
528
|
|
|
|
|
|
|
|
529
|
6
|
|
|
|
|
30
|
return @supps; |
530
|
|
|
|
|
|
|
} |
531
|
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
=head2 C |
533
|
|
|
|
|
|
|
|
534
|
|
|
|
|
|
|
$tvs->start; |
535
|
|
|
|
|
|
|
|
536
|
|
|
|
|
|
|
Starts the action and tool associated to the current run. |
537
|
|
|
|
|
|
|
It's automatically called at the beginning of L. |
538
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
=cut |
540
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
sub start { |
542
|
4
|
|
|
4
|
1
|
12
|
my $self = shift; |
543
|
|
|
|
|
|
|
|
544
|
4
|
|
|
|
|
10
|
delete @{$self}{qw}; |
|
4
|
|
|
|
|
18
|
|
545
|
|
|
|
|
|
|
|
546
|
4
|
|
|
|
|
154
|
$self->tool->start($self); |
547
|
4
|
|
|
|
|
26
|
$self->parser($self->parser_class->new)->start($self); |
548
|
4
|
|
|
|
|
174
|
$self->action->start($self); |
549
|
|
|
|
|
|
|
|
550
|
4
|
|
|
|
|
12
|
return; |
551
|
|
|
|
|
|
|
} |
552
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
=head2 C |
554
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
$tvs->abort($msg); |
556
|
|
|
|
|
|
|
|
557
|
|
|
|
|
|
|
Forwards to C<< ->action->abort >> after unshifting the session object to the argument list. |
558
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
=cut |
560
|
|
|
|
|
|
|
|
561
|
|
|
|
|
|
|
sub abort { |
562
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
563
|
|
|
|
|
|
|
|
564
|
0
|
|
|
|
|
0
|
$self->action->abort($self, @_); |
565
|
|
|
|
|
|
|
} |
566
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
=head2 C |
568
|
|
|
|
|
|
|
|
569
|
|
|
|
|
|
|
$tvs->report($report); |
570
|
|
|
|
|
|
|
|
571
|
|
|
|
|
|
|
Forwards to C<< ->action->report >> after unshifting the session object to the argument list. |
572
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
=cut |
574
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
sub report { |
576
|
10
|
|
|
10
|
1
|
32
|
my ($self, $report) = @_; |
577
|
|
|
|
|
|
|
|
578
|
10
|
50
|
|
|
|
42
|
return unless defined $report; |
579
|
|
|
|
|
|
|
|
580
|
10
|
|
|
|
|
48
|
for my $handler (qw) { |
581
|
20
|
|
|
|
|
826
|
$report = $self->$handler->filter($self, $report); |
582
|
20
|
50
|
|
|
|
88
|
return unless defined $report; |
583
|
|
|
|
|
|
|
} |
584
|
|
|
|
|
|
|
|
585
|
10
|
|
|
|
|
356
|
$self->action->report($self, $report); |
586
|
|
|
|
|
|
|
} |
587
|
|
|
|
|
|
|
|
588
|
|
|
|
|
|
|
=head2 C |
589
|
|
|
|
|
|
|
|
590
|
|
|
|
|
|
|
$tvs->finish; |
591
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
Finishes the action and tool associated to the current run. |
593
|
|
|
|
|
|
|
It's automatically called at the end of L. |
594
|
|
|
|
|
|
|
|
595
|
|
|
|
|
|
|
=cut |
596
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
sub finish { |
598
|
2
|
|
|
2
|
1
|
10
|
my ($self) = @_; |
599
|
|
|
|
|
|
|
|
600
|
2
|
|
|
|
|
143
|
my $action = $self->action; |
601
|
|
|
|
|
|
|
|
602
|
2
|
|
|
|
|
92
|
$action->finish($self); |
603
|
2
|
|
|
|
|
81
|
$self->parser->finish($self); |
604
|
2
|
|
|
|
|
140
|
$self->tool->finish($self); |
605
|
|
|
|
|
|
|
|
606
|
2
|
|
|
|
|
76
|
my $status = $action->status($self); |
607
|
2
|
50
|
|
|
|
19
|
$self->{last_status} = defined $status ? $status : $self->{exit_code}; |
608
|
|
|
|
|
|
|
|
609
|
2
|
|
|
|
|
92
|
$self->$_(undef) for @members; |
610
|
|
|
|
|
|
|
|
611
|
2
|
|
|
|
|
38
|
return; |
612
|
|
|
|
|
|
|
} |
613
|
|
|
|
|
|
|
|
614
|
|
|
|
|
|
|
=head2 C |
615
|
|
|
|
|
|
|
|
616
|
|
|
|
|
|
|
my $status = $tvs->status; |
617
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
Returns the status code of the last run of the session. |
619
|
|
|
|
|
|
|
|
620
|
|
|
|
|
|
|
=cut |
621
|
|
|
|
|
|
|
|
622
|
0
|
|
|
0
|
1
|
|
sub status { $_[0]->{last_status} } |
623
|
|
|
|
|
|
|
|
624
|
|
|
|
|
|
|
=head1 SEE ALSO |
625
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
L, L, L, L, L. |
627
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
L, L. |
629
|
|
|
|
|
|
|
|
630
|
|
|
|
|
|
|
=head1 AUTHOR |
631
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
Vincent Pit, C<< >>, L. |
633
|
|
|
|
|
|
|
|
634
|
|
|
|
|
|
|
You can contact me by mail or on C (vincent). |
635
|
|
|
|
|
|
|
|
636
|
|
|
|
|
|
|
=head1 BUGS |
637
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
Please report any bugs or feature requests to C, or through the web interface at L. |
639
|
|
|
|
|
|
|
I will be notified, and then you'll automatically be notified of progress on your bug as I make changes. |
640
|
|
|
|
|
|
|
|
641
|
|
|
|
|
|
|
=head1 SUPPORT |
642
|
|
|
|
|
|
|
|
643
|
|
|
|
|
|
|
You can find documentation for this module with the perldoc command. |
644
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
perldoc Test::Valgrind::Session |
646
|
|
|
|
|
|
|
|
647
|
|
|
|
|
|
|
=head1 COPYRIGHT & LICENSE |
648
|
|
|
|
|
|
|
|
649
|
|
|
|
|
|
|
Copyright 2009,2010,2011,2013,2015 Vincent Pit, all rights reserved. |
650
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. |
652
|
|
|
|
|
|
|
|
653
|
|
|
|
|
|
|
=cut |
654
|
|
|
|
|
|
|
|
655
|
|
|
|
|
|
|
1; # End of Test::Valgrind::Session |