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