| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Safe; |
|
2
|
|
|
|
|
|
|
|
|
3
|
10
|
|
|
10
|
|
229654
|
use 5.003_11; |
|
|
10
|
|
|
|
|
37
|
|
|
|
10
|
|
|
|
|
449
|
|
|
4
|
10
|
|
|
10
|
|
61
|
use Scalar::Util qw(reftype refaddr); |
|
|
10
|
|
|
|
|
18
|
|
|
|
10
|
|
|
|
|
2031
|
|
|
5
|
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
$Safe::VERSION = "2.35"; |
|
7
|
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
# *** Don't declare any lexicals above this point *** |
|
9
|
|
|
|
|
|
|
# |
|
10
|
|
|
|
|
|
|
# This function should return a closure which contains an eval that can't |
|
11
|
|
|
|
|
|
|
# see any lexicals in scope (apart from __ExPr__ which is unavoidable) |
|
12
|
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
sub lexless_anon_sub { |
|
14
|
|
|
|
|
|
|
# $_[0] is package; |
|
15
|
|
|
|
|
|
|
# $_[1] is strict flag; |
|
16
|
42
|
|
|
42
|
0
|
71
|
my $__ExPr__ = $_[2]; # must be a lexical to create the closure that |
|
17
|
|
|
|
|
|
|
# can be used to pass the value into the safe |
|
18
|
|
|
|
|
|
|
# world |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
# Create anon sub ref in root of compartment. |
|
21
|
|
|
|
|
|
|
# Uses a closure (on $__ExPr__) to pass in the code to be executed. |
|
22
|
|
|
|
|
|
|
# (eval on one line to keep line numbers as expected by caller) |
|
23
|
42
|
50
|
|
|
|
4225
|
eval sprintf |
|
24
|
|
|
|
|
|
|
'package %s; %s sub { @_=(); eval q[local *SIG; my $__ExPr__;] . $__ExPr__; }', |
|
25
|
|
|
|
|
|
|
$_[0], $_[1] ? 'use strict;' : ''; |
|
26
|
|
|
|
|
|
|
} |
|
27
|
|
|
|
|
|
|
|
|
28
|
10
|
|
|
10
|
|
51
|
use strict; |
|
|
10
|
|
|
|
|
22
|
|
|
|
10
|
|
|
|
|
317
|
|
|
29
|
10
|
|
|
10
|
|
49
|
use Carp; |
|
|
10
|
|
|
|
|
20
|
|
|
|
10
|
|
|
|
|
727
|
|
|
30
|
10
|
|
|
10
|
|
669
|
BEGIN { eval q{ |
|
|
10
|
|
|
10
|
|
8382
|
|
|
|
10
|
|
|
|
|
1506
|
|
|
|
10
|
|
|
|
|
332
|
|
|
31
|
|
|
|
|
|
|
use Carp::Heavy; |
|
32
|
|
|
|
|
|
|
} } |
|
33
|
|
|
|
|
|
|
|
|
34
|
10
|
|
|
10
|
|
55
|
use B (); |
|
|
10
|
|
|
|
|
17
|
|
|
|
10
|
|
|
|
|
225
|
|
|
35
|
|
|
|
|
|
|
BEGIN { |
|
36
|
10
|
|
|
10
|
|
44
|
no strict 'refs'; |
|
|
10
|
|
|
|
|
16
|
|
|
|
10
|
|
|
|
|
723
|
|
|
37
|
10
|
50
|
|
10
|
|
46
|
if (defined &B::sub_generation) { |
|
38
|
10
|
|
|
|
|
287
|
*sub_generation = \&B::sub_generation; |
|
39
|
|
|
|
|
|
|
} |
|
40
|
|
|
|
|
|
|
else { |
|
41
|
|
|
|
|
|
|
# fake sub generation changing for perls < 5.8.9 |
|
42
|
0
|
|
|
|
|
0
|
my $sg; *sub_generation = sub { ++$sg }; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
43
|
|
|
|
|
|
|
} |
|
44
|
|
|
|
|
|
|
} |
|
45
|
|
|
|
|
|
|
|
|
46
|
10
|
|
|
|
|
7495
|
use Opcode 1.01, qw( |
|
47
|
|
|
|
|
|
|
opset opset_to_ops opmask_add |
|
48
|
|
|
|
|
|
|
empty_opset full_opset invert_opset verify_opset |
|
49
|
|
|
|
|
|
|
opdesc opcodes opmask define_optag opset_to_hex |
|
50
|
10
|
|
|
10
|
|
6826
|
); |
|
|
10
|
|
|
|
|
42463
|
|
|
51
|
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
*ops_to_opset = \&opset; # Temporary alias for old Penguins |
|
53
|
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
# Regular expressions and other unicode-aware code may need to call |
|
55
|
|
|
|
|
|
|
# utf8->SWASHNEW (via perl's utf8.c). That will fail unless we share the |
|
56
|
|
|
|
|
|
|
# SWASHNEW method. |
|
57
|
|
|
|
|
|
|
# Sadly we can't just add utf8::SWASHNEW to $default_share because perl's |
|
58
|
|
|
|
|
|
|
# utf8.c code does a fetchmethod on SWASHNEW to check if utf8.pm is loaded, |
|
59
|
|
|
|
|
|
|
# and sharing makes it look like the method exists. |
|
60
|
|
|
|
|
|
|
# The simplest and most robust fix is to ensure the utf8 module is loaded when |
|
61
|
|
|
|
|
|
|
# Safe is loaded. Then we can add utf8::SWASHNEW to $default_share. |
|
62
|
|
|
|
|
|
|
require utf8; |
|
63
|
|
|
|
|
|
|
# we must ensure that utf8_heavy.pl, where SWASHNEW is defined, is loaded |
|
64
|
|
|
|
|
|
|
# but without depending on too much knowledge of that implementation detail. |
|
65
|
|
|
|
|
|
|
# This code (//i on a unicode string) should ensure utf8 is fully loaded |
|
66
|
|
|
|
|
|
|
# and also loads the ToFold SWASH, unless things change so that these |
|
67
|
|
|
|
|
|
|
# particular code points don't cause it to load. |
|
68
|
|
|
|
|
|
|
# (Swashes are cached internally by perl in PL_utf8_* variables |
|
69
|
|
|
|
|
|
|
# independent of being inside/outside of Safe. So once loaded they can be) |
|
70
|
10
|
|
|
10
|
|
48
|
do { my $a = pack('U',0x100); my $b = chr 0x101; utf8::upgrade $b; $a =~ /$b/i }; |
|
|
10
|
|
|
|
|
17
|
|
|
|
10
|
|
|
|
|
123
|
|
|
71
|
|
|
|
|
|
|
# now we can safely include utf8::SWASHNEW in $default_share defined below. |
|
72
|
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
my $default_root = 0; |
|
74
|
|
|
|
|
|
|
# share *_ and functions defined in universal.c |
|
75
|
|
|
|
|
|
|
# Don't share stuff like *UNIVERSAL:: otherwise code from the |
|
76
|
|
|
|
|
|
|
# compartment can 0wn functions in UNIVERSAL |
|
77
|
|
|
|
|
|
|
my $default_share = [qw[ |
|
78
|
|
|
|
|
|
|
*_ |
|
79
|
|
|
|
|
|
|
&PerlIO::get_layers |
|
80
|
|
|
|
|
|
|
&UNIVERSAL::isa |
|
81
|
|
|
|
|
|
|
&UNIVERSAL::can |
|
82
|
|
|
|
|
|
|
&UNIVERSAL::VERSION |
|
83
|
|
|
|
|
|
|
&utf8::is_utf8 |
|
84
|
|
|
|
|
|
|
&utf8::valid |
|
85
|
|
|
|
|
|
|
&utf8::encode |
|
86
|
|
|
|
|
|
|
&utf8::decode |
|
87
|
|
|
|
|
|
|
&utf8::upgrade |
|
88
|
|
|
|
|
|
|
&utf8::downgrade |
|
89
|
|
|
|
|
|
|
&utf8::native_to_unicode |
|
90
|
|
|
|
|
|
|
&utf8::unicode_to_native |
|
91
|
|
|
|
|
|
|
&utf8::SWASHNEW |
|
92
|
|
|
|
|
|
|
$version::VERSION |
|
93
|
|
|
|
|
|
|
$version::CLASS |
|
94
|
|
|
|
|
|
|
$version::STRICT |
|
95
|
|
|
|
|
|
|
$version::LAX |
|
96
|
|
|
|
|
|
|
@version::ISA |
|
97
|
|
|
|
|
|
|
], ($] < 5.010 && qw[ |
|
98
|
|
|
|
|
|
|
&utf8::SWASHGET |
|
99
|
|
|
|
|
|
|
]), ($] >= 5.008001 && qw[ |
|
100
|
|
|
|
|
|
|
&Regexp::DESTROY |
|
101
|
|
|
|
|
|
|
]), ($] >= 5.010 && qw[ |
|
102
|
|
|
|
|
|
|
&re::is_regexp |
|
103
|
|
|
|
|
|
|
&re::regname |
|
104
|
|
|
|
|
|
|
&re::regnames |
|
105
|
|
|
|
|
|
|
&re::regnames_count |
|
106
|
|
|
|
|
|
|
&UNIVERSAL::DOES |
|
107
|
|
|
|
|
|
|
&version::() |
|
108
|
|
|
|
|
|
|
&version::new |
|
109
|
|
|
|
|
|
|
&version::("" |
|
110
|
|
|
|
|
|
|
&version::stringify |
|
111
|
|
|
|
|
|
|
&version::(0+ |
|
112
|
|
|
|
|
|
|
&version::numify |
|
113
|
|
|
|
|
|
|
&version::normal |
|
114
|
|
|
|
|
|
|
&version::(cmp |
|
115
|
|
|
|
|
|
|
&version::(<=> |
|
116
|
|
|
|
|
|
|
&version::vcmp |
|
117
|
|
|
|
|
|
|
&version::(bool |
|
118
|
|
|
|
|
|
|
&version::boolean |
|
119
|
|
|
|
|
|
|
&version::(nomethod |
|
120
|
|
|
|
|
|
|
&version::noop |
|
121
|
|
|
|
|
|
|
&version::is_alpha |
|
122
|
|
|
|
|
|
|
&version::qv |
|
123
|
|
|
|
|
|
|
&version::vxs::declare |
|
124
|
|
|
|
|
|
|
&version::vxs::qv |
|
125
|
|
|
|
|
|
|
&version::vxs::_VERSION |
|
126
|
|
|
|
|
|
|
&version::vxs::stringify |
|
127
|
|
|
|
|
|
|
&version::vxs::new |
|
128
|
|
|
|
|
|
|
&version::vxs::parse |
|
129
|
|
|
|
|
|
|
&version::vxs::VCMP |
|
130
|
|
|
|
|
|
|
]), ($] >= 5.011 && qw[ |
|
131
|
|
|
|
|
|
|
&re::regexp_pattern |
|
132
|
|
|
|
|
|
|
]), ($] >= 5.010 && $] < 5.014 && qw[ |
|
133
|
|
|
|
|
|
|
&Tie::Hash::NamedCapture::FETCH |
|
134
|
|
|
|
|
|
|
&Tie::Hash::NamedCapture::STORE |
|
135
|
|
|
|
|
|
|
&Tie::Hash::NamedCapture::DELETE |
|
136
|
|
|
|
|
|
|
&Tie::Hash::NamedCapture::CLEAR |
|
137
|
|
|
|
|
|
|
&Tie::Hash::NamedCapture::EXISTS |
|
138
|
|
|
|
|
|
|
&Tie::Hash::NamedCapture::FIRSTKEY |
|
139
|
|
|
|
|
|
|
&Tie::Hash::NamedCapture::NEXTKEY |
|
140
|
|
|
|
|
|
|
&Tie::Hash::NamedCapture::SCALAR |
|
141
|
|
|
|
|
|
|
&Tie::Hash::NamedCapture::flags |
|
142
|
|
|
|
|
|
|
])]; |
|
143
|
|
|
|
|
|
|
if (defined $Devel::Cover::VERSION) { |
|
144
|
|
|
|
|
|
|
push @$default_share, '&Devel::Cover::use_file'; |
|
145
|
|
|
|
|
|
|
} |
|
146
|
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
sub new { |
|
148
|
17
|
|
|
17
|
1
|
5192
|
my($class, $root, $mask) = @_; |
|
149
|
17
|
|
|
|
|
37
|
my $obj = {}; |
|
150
|
17
|
|
|
|
|
42
|
bless $obj, $class; |
|
151
|
|
|
|
|
|
|
|
|
152
|
17
|
100
|
|
|
|
235
|
if (defined($root)) { |
|
153
|
5
|
50
|
33
|
|
|
66
|
croak "Can't use \"$root\" as root name" |
|
154
|
|
|
|
|
|
|
if $root =~ /^main\b/ or $root !~ /^\w[:\w]*$/; |
|
155
|
5
|
|
|
|
|
48
|
$obj->{Root} = $root; |
|
156
|
5
|
|
|
|
|
14
|
$obj->{Erase} = 0; |
|
157
|
|
|
|
|
|
|
} |
|
158
|
|
|
|
|
|
|
else { |
|
159
|
12
|
|
|
|
|
77
|
$obj->{Root} = "Safe::Root".$default_root++; |
|
160
|
12
|
|
|
|
|
31
|
$obj->{Erase} = 1; |
|
161
|
|
|
|
|
|
|
} |
|
162
|
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
# use permit/deny methods instead till interface issues resolved |
|
164
|
|
|
|
|
|
|
# XXX perhaps new Safe 'Root', mask => $mask, foo => bar, ...; |
|
165
|
17
|
50
|
|
|
|
54
|
croak "Mask parameter to new no longer supported" if defined $mask; |
|
166
|
17
|
|
|
|
|
90
|
$obj->permit_only(':default'); |
|
167
|
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
# We must share $_ and @_ with the compartment or else ops such |
|
169
|
|
|
|
|
|
|
# as split, length and so on won't default to $_ properly, nor |
|
170
|
|
|
|
|
|
|
# will passing argument to subroutines work (via @_). In fact, |
|
171
|
|
|
|
|
|
|
# for reasons I don't completely understand, we need to share |
|
172
|
|
|
|
|
|
|
# the whole glob *_ rather than $_ and @_ separately, otherwise |
|
173
|
|
|
|
|
|
|
# @_ in non default packages within the compartment don't work. |
|
174
|
17
|
|
|
|
|
68
|
$obj->share_from('main', $default_share); |
|
175
|
|
|
|
|
|
|
|
|
176
|
17
|
50
|
|
|
|
195
|
Opcode::_safe_pkg_prep($obj->{Root}) if($Opcode::VERSION > 1.04); |
|
177
|
|
|
|
|
|
|
|
|
178
|
17
|
|
|
|
|
50
|
return $obj; |
|
179
|
|
|
|
|
|
|
} |
|
180
|
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
sub DESTROY { |
|
182
|
17
|
|
|
17
|
|
10853
|
my $obj = shift; |
|
183
|
17
|
100
|
|
|
|
640
|
$obj->erase('DESTROY') if $obj->{Erase}; |
|
184
|
|
|
|
|
|
|
} |
|
185
|
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
sub erase { |
|
187
|
15
|
|
|
15
|
0
|
28
|
my ($obj, $action) = @_; |
|
188
|
15
|
|
|
|
|
36
|
my $pkg = $obj->root(); |
|
189
|
15
|
|
|
|
|
21
|
my ($stem, $leaf); |
|
190
|
|
|
|
|
|
|
|
|
191
|
10
|
|
|
10
|
|
171
|
no strict 'refs'; |
|
|
10
|
|
|
|
|
17
|
|
|
|
10
|
|
|
|
|
6151
|
|
|
192
|
15
|
|
|
|
|
42
|
$pkg = "main::$pkg\::"; # expand to full symbol table name |
|
193
|
15
|
|
|
|
|
102
|
($stem, $leaf) = $pkg =~ m/(.*::)(\w+::)$/; |
|
194
|
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
# The 'my $foo' is needed! Without it you get an |
|
196
|
|
|
|
|
|
|
# 'Attempt to free unreferenced scalar' warning! |
|
197
|
15
|
|
|
|
|
28
|
my $stem_symtab = *{$stem}{HASH}; |
|
|
15
|
|
|
|
|
71
|
|
|
198
|
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
#warn "erase($pkg) stem=$stem, leaf=$leaf"; |
|
200
|
|
|
|
|
|
|
#warn " stem_symtab hash ".scalar(%$stem_symtab)."\n"; |
|
201
|
|
|
|
|
|
|
# ", join(', ', %$stem_symtab),"\n"; |
|
202
|
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
# delete $stem_symtab->{$leaf}; |
|
204
|
|
|
|
|
|
|
|
|
205
|
15
|
|
|
|
|
57
|
my $leaf_glob = $stem_symtab->{$leaf}; |
|
206
|
15
|
|
|
|
|
19
|
my $leaf_symtab = *{$leaf_glob}{HASH}; |
|
|
15
|
|
|
|
|
37
|
|
|
207
|
|
|
|
|
|
|
# warn " leaf_symtab ", join(', ', %$leaf_symtab),"\n"; |
|
208
|
15
|
|
|
|
|
590
|
%$leaf_symtab = (); |
|
209
|
|
|
|
|
|
|
#delete $leaf_symtab->{'__ANON__'}; |
|
210
|
|
|
|
|
|
|
#delete $leaf_symtab->{'foo'}; |
|
211
|
|
|
|
|
|
|
#delete $leaf_symtab->{'main::'}; |
|
212
|
|
|
|
|
|
|
# my $foo = undef ${"$stem\::"}{"$leaf\::"}; |
|
213
|
|
|
|
|
|
|
|
|
214
|
15
|
100
|
66
|
|
|
188
|
if ($action and $action eq 'DESTROY') { |
|
215
|
12
|
|
|
|
|
93
|
delete $stem_symtab->{$leaf}; |
|
216
|
|
|
|
|
|
|
} else { |
|
217
|
3
|
|
|
|
|
10
|
$obj->share_from('main', $default_share); |
|
218
|
|
|
|
|
|
|
} |
|
219
|
15
|
|
|
|
|
695
|
1; |
|
220
|
|
|
|
|
|
|
} |
|
221
|
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
sub reinit { |
|
224
|
0
|
|
|
0
|
0
|
0
|
my $obj= shift; |
|
225
|
0
|
|
|
|
|
0
|
$obj->erase; |
|
226
|
0
|
|
|
|
|
0
|
$obj->share_redo; |
|
227
|
|
|
|
|
|
|
} |
|
228
|
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
sub root { |
|
230
|
52
|
|
|
52
|
1
|
68
|
my $obj = shift; |
|
231
|
52
|
50
|
|
|
|
159
|
croak("Safe root method now read-only") if @_; |
|
232
|
52
|
|
|
|
|
173
|
return $obj->{Root}; |
|
233
|
|
|
|
|
|
|
} |
|
234
|
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
sub mask { |
|
237
|
3
|
|
|
3
|
1
|
599
|
my $obj = shift; |
|
238
|
3
|
100
|
|
|
|
15
|
return $obj->{Mask} unless @_; |
|
239
|
1
|
|
|
|
|
4
|
$obj->deny_only(@_); |
|
240
|
|
|
|
|
|
|
} |
|
241
|
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
# v1 compatibility methods |
|
243
|
1
|
|
|
1
|
1
|
9
|
sub trap { shift->deny(@_) } |
|
244
|
0
|
|
|
0
|
1
|
0
|
sub untrap { shift->permit(@_) } |
|
245
|
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
sub deny { |
|
247
|
3
|
|
|
3
|
1
|
13
|
my $obj = shift; |
|
248
|
3
|
|
|
|
|
29
|
$obj->{Mask} |= opset(@_); |
|
249
|
|
|
|
|
|
|
} |
|
250
|
|
|
|
|
|
|
sub deny_only { |
|
251
|
2
|
|
|
2
|
1
|
8
|
my $obj = shift; |
|
252
|
2
|
|
|
|
|
19
|
$obj->{Mask} = opset(@_); |
|
253
|
|
|
|
|
|
|
} |
|
254
|
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
sub permit { |
|
256
|
3
|
|
|
3
|
1
|
16
|
my $obj = shift; |
|
257
|
|
|
|
|
|
|
# XXX needs testing |
|
258
|
3
|
|
|
|
|
37
|
$obj->{Mask} &= invert_opset opset(@_); |
|
259
|
|
|
|
|
|
|
} |
|
260
|
|
|
|
|
|
|
sub permit_only { |
|
261
|
19
|
|
|
19
|
1
|
35
|
my $obj = shift; |
|
262
|
19
|
|
|
|
|
171
|
$obj->{Mask} = invert_opset opset(@_); |
|
263
|
|
|
|
|
|
|
} |
|
264
|
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
sub dump_mask { |
|
267
|
0
|
|
|
0
|
0
|
0
|
my $obj = shift; |
|
268
|
0
|
|
|
|
|
0
|
print opset_to_hex($obj->{Mask}),"\n"; |
|
269
|
|
|
|
|
|
|
} |
|
270
|
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
sub share { |
|
273
|
5
|
|
|
5
|
1
|
565
|
my($obj, @vars) = @_; |
|
274
|
5
|
|
|
|
|
18
|
$obj->share_from(scalar(caller), \@vars); |
|
275
|
|
|
|
|
|
|
} |
|
276
|
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
sub share_from { |
|
279
|
25
|
|
|
25
|
1
|
42
|
my $obj = shift; |
|
280
|
25
|
|
|
|
|
39
|
my $pkg = shift; |
|
281
|
25
|
|
|
|
|
33
|
my $vars = shift; |
|
282
|
25
|
|
50
|
|
|
138
|
my $no_record = shift || 0; |
|
283
|
25
|
|
|
|
|
98
|
my $root = $obj->root(); |
|
284
|
25
|
50
|
|
|
|
94
|
croak("vars not an array ref") unless ref $vars eq 'ARRAY'; |
|
285
|
10
|
|
|
10
|
|
61
|
no strict 'refs'; |
|
|
10
|
|
|
|
|
20
|
|
|
|
10
|
|
|
|
|
5623
|
|
|
286
|
|
|
|
|
|
|
# Check that 'from' package actually exists |
|
287
|
25
|
|
|
|
|
101
|
croak("Package \"$pkg\" does not exist") |
|
288
|
25
|
50
|
|
|
|
32
|
unless keys %{"$pkg\::"}; |
|
289
|
25
|
|
|
|
|
32
|
my $arg; |
|
290
|
25
|
|
|
|
|
67
|
foreach $arg (@$vars) { |
|
291
|
|
|
|
|
|
|
# catch some $safe->share($var) errors: |
|
292
|
1029
|
|
|
|
|
995
|
my ($var, $type); |
|
293
|
1029
|
100
|
|
|
|
4219
|
$type = $1 if ($var = $arg) =~ s/^(\W)//; |
|
294
|
|
|
|
|
|
|
# warn "share_from $pkg $type $var"; |
|
295
|
1029
|
|
|
|
|
1659
|
for (1..2) { # assign twice to avoid any 'used once' warnings |
|
296
|
2058
|
|
|
|
|
8888
|
*{$root."::$var"} = (!$type) ? \&{$pkg."::$var"} |
|
|
82
|
|
|
|
|
179
|
|
|
|
1720
|
|
|
|
|
4439
|
|
|
297
|
170
|
|
|
|
|
495
|
: ($type eq '&') ? \&{$pkg."::$var"} |
|
298
|
42
|
|
|
|
|
147
|
: ($type eq '$') ? \${$pkg."::$var"} |
|
299
|
2
|
|
|
|
|
4
|
: ($type eq '@') ? \@{$pkg."::$var"} |
|
300
|
42
|
|
|
|
|
101
|
: ($type eq '%') ? \%{$pkg."::$var"} |
|
301
|
2058
|
50
|
|
|
|
4220
|
: ($type eq '*') ? *{$pkg."::$var"} |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
: croak(qq(Can't share "$type$var" of unknown type)); |
|
303
|
|
|
|
|
|
|
} |
|
304
|
|
|
|
|
|
|
} |
|
305
|
25
|
50
|
33
|
|
|
206
|
$obj->share_record($pkg, $vars) unless $no_record or !$vars; |
|
306
|
|
|
|
|
|
|
} |
|
307
|
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
sub share_record { |
|
310
|
25
|
|
|
25
|
0
|
42
|
my $obj = shift; |
|
311
|
25
|
|
|
|
|
50
|
my $pkg = shift; |
|
312
|
25
|
|
|
|
|
33
|
my $vars = shift; |
|
313
|
25
|
|
100
|
|
|
35
|
my $shares = \%{$obj->{Shares} ||= {}}; |
|
|
25
|
|
|
|
|
173
|
|
|
314
|
|
|
|
|
|
|
# Record shares using keys of $obj->{Shares}. See reinit. |
|
315
|
25
|
50
|
|
|
|
203
|
@{$shares}{@$vars} = ($pkg) x @$vars if @$vars; |
|
|
25
|
|
|
|
|
761
|
|
|
316
|
|
|
|
|
|
|
} |
|
317
|
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
sub share_redo { |
|
320
|
0
|
|
|
0
|
0
|
0
|
my $obj = shift; |
|
321
|
0
|
|
0
|
|
|
0
|
my $shares = \%{$obj->{Shares} ||= {}}; |
|
|
0
|
|
|
|
|
0
|
|
|
322
|
0
|
|
|
|
|
0
|
my($var, $pkg); |
|
323
|
0
|
|
|
|
|
0
|
while(($var, $pkg) = each %$shares) { |
|
324
|
|
|
|
|
|
|
# warn "share_redo $pkg\:: $var"; |
|
325
|
0
|
|
|
|
|
0
|
$obj->share_from($pkg, [ $var ], 1); |
|
326
|
|
|
|
|
|
|
} |
|
327
|
|
|
|
|
|
|
} |
|
328
|
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
sub share_forget { |
|
331
|
0
|
|
|
0
|
0
|
0
|
delete shift->{Shares}; |
|
332
|
|
|
|
|
|
|
} |
|
333
|
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
sub varglob { |
|
336
|
12
|
|
|
12
|
1
|
3524
|
my ($obj, $var) = @_; |
|
337
|
10
|
|
|
10
|
|
51
|
no strict 'refs'; |
|
|
10
|
|
|
|
|
20
|
|
|
|
10
|
|
|
|
|
749
|
|
|
338
|
12
|
|
|
|
|
14
|
return *{$obj->root()."::$var"}; |
|
|
12
|
|
|
|
|
23
|
|
|
339
|
|
|
|
|
|
|
} |
|
340
|
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
sub _clean_stash { |
|
342
|
446
|
|
|
446
|
|
560
|
my ($root, $saved_refs) = @_; |
|
343
|
446
|
|
100
|
|
|
938
|
$saved_refs ||= []; |
|
344
|
10
|
|
|
10
|
|
49
|
no strict 'refs'; |
|
|
10
|
|
|
|
|
17
|
|
|
|
10
|
|
|
|
|
9696
|
|
|
345
|
446
|
|
|
|
|
2569
|
foreach my $hook (qw(DESTROY AUTOLOAD), grep /^\(/, keys %$root) { |
|
346
|
990
|
|
|
|
|
1055
|
push @$saved_refs, \*{$root.$hook}; |
|
|
990
|
|
|
|
|
3548
|
|
|
347
|
990
|
|
|
|
|
962
|
delete ${$root}{$hook}; |
|
|
990
|
|
|
|
|
2823
|
|
|
348
|
|
|
|
|
|
|
} |
|
349
|
|
|
|
|
|
|
|
|
350
|
446
|
|
|
|
|
3901
|
for (grep /::$/, keys %$root) { |
|
351
|
446
|
100
|
|
|
|
438
|
next if \%{$root.$_} eq \%$root; |
|
|
446
|
|
|
|
|
1880
|
|
|
352
|
401
|
|
|
|
|
874
|
_clean_stash($root.$_, $saved_refs); |
|
353
|
|
|
|
|
|
|
} |
|
354
|
|
|
|
|
|
|
} |
|
355
|
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
sub reval { |
|
357
|
42
|
|
|
42
|
1
|
8940
|
my ($obj, $expr, $strict) = @_; |
|
358
|
42
|
50
|
|
|
|
267
|
die "Bad Safe object" unless $obj->isa('Safe'); |
|
359
|
|
|
|
|
|
|
|
|
360
|
42
|
|
|
|
|
75
|
my $root = $obj->{Root}; |
|
361
|
|
|
|
|
|
|
|
|
362
|
42
|
|
|
|
|
230
|
my $evalsub = lexless_anon_sub($root, $strict, $expr); |
|
363
|
|
|
|
|
|
|
# propagate context |
|
364
|
42
|
|
|
|
|
137
|
my $sg = sub_generation(); |
|
365
|
42
|
100
|
|
|
|
3092
|
my @subret = (wantarray) |
|
366
|
|
|
|
|
|
|
? Opcode::_safe_call_sv($root, $obj->{Mask}, $evalsub) |
|
367
|
|
|
|
|
|
|
: scalar Opcode::_safe_call_sv($root, $obj->{Mask}, $evalsub); |
|
368
|
42
|
50
|
|
|
|
572
|
_clean_stash($root.'::') if $sg != sub_generation(); |
|
369
|
42
|
|
|
|
|
154
|
$obj->wrap_code_refs_within(@subret); |
|
370
|
42
|
100
|
|
|
|
492
|
return (wantarray) ? @subret : $subret[0]; |
|
371
|
|
|
|
|
|
|
} |
|
372
|
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
my %OID; |
|
374
|
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
sub wrap_code_refs_within { |
|
376
|
44
|
|
|
44
|
1
|
1225
|
my $obj = shift; |
|
377
|
|
|
|
|
|
|
|
|
378
|
44
|
|
|
|
|
85
|
%OID = (); |
|
379
|
44
|
|
|
|
|
116
|
$obj->_find_code_refs('wrap_code_ref', @_); |
|
380
|
|
|
|
|
|
|
} |
|
381
|
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
sub _find_code_refs { |
|
384
|
47
|
|
|
47
|
|
57
|
my $obj = shift; |
|
385
|
47
|
|
|
|
|
58
|
my $visitor = shift; |
|
386
|
|
|
|
|
|
|
|
|
387
|
47
|
|
|
|
|
86
|
for my $item (@_) { |
|
388
|
50
|
100
|
100
|
|
|
508
|
my $reftype = $item && reftype $item |
|
389
|
|
|
|
|
|
|
or next; |
|
390
|
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
# skip references already seen |
|
392
|
4
|
50
|
|
|
|
21
|
next if ++$OID{refaddr $item} > 1; |
|
393
|
|
|
|
|
|
|
|
|
394
|
4
|
100
|
|
|
|
14
|
if ($reftype eq 'ARRAY') { |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
395
|
2
|
|
|
|
|
11
|
$obj->_find_code_refs($visitor, @$item); |
|
396
|
|
|
|
|
|
|
} |
|
397
|
|
|
|
|
|
|
elsif ($reftype eq 'HASH') { |
|
398
|
1
|
|
|
|
|
7
|
$obj->_find_code_refs($visitor, values %$item); |
|
399
|
|
|
|
|
|
|
} |
|
400
|
|
|
|
|
|
|
# XXX GLOBs? |
|
401
|
|
|
|
|
|
|
elsif ($reftype eq 'CODE') { |
|
402
|
1
|
|
|
|
|
4
|
$item = $obj->$visitor($item); |
|
403
|
|
|
|
|
|
|
} |
|
404
|
|
|
|
|
|
|
} |
|
405
|
|
|
|
|
|
|
} |
|
406
|
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
sub wrap_code_ref { |
|
409
|
2
|
|
|
2
|
1
|
1168
|
my ($obj, $sub) = @_; |
|
410
|
2
|
50
|
|
|
|
23
|
die "Bad safe object" unless $obj->isa('Safe'); |
|
411
|
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
# wrap code ref $sub with _safe_call_sv so that, when called, the |
|
413
|
|
|
|
|
|
|
# execution will happen with the compartment fully 'in effect'. |
|
414
|
|
|
|
|
|
|
|
|
415
|
2
|
50
|
|
|
|
12
|
croak "Not a CODE reference" |
|
416
|
|
|
|
|
|
|
if reftype $sub ne 'CODE'; |
|
417
|
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
my $ret = sub { |
|
419
|
2
|
|
|
2
|
|
1042
|
my @args = @_; # lexical to close over |
|
420
|
2
|
|
|
|
|
9
|
my $sub_with_args = sub { $sub->(@args) }; |
|
|
2
|
|
|
|
|
7
|
|
|
421
|
|
|
|
|
|
|
|
|
422
|
2
|
|
|
|
|
4
|
my @subret; |
|
423
|
|
|
|
|
|
|
my $error; |
|
424
|
2
|
|
|
|
|
4
|
do { |
|
425
|
2
|
|
|
|
|
3
|
local $@; # needed due to perl_call_sv(sv, G_EVAL|G_KEEPERR) |
|
426
|
2
|
|
|
|
|
8
|
my $sg = sub_generation(); |
|
427
|
2
|
50
|
|
|
|
43
|
@subret = (wantarray) |
|
428
|
|
|
|
|
|
|
? Opcode::_safe_call_sv($obj->{Root}, $obj->{Mask}, $sub_with_args) |
|
429
|
|
|
|
|
|
|
: scalar Opcode::_safe_call_sv($obj->{Root}, $obj->{Mask}, $sub_with_args); |
|
430
|
2
|
|
|
|
|
78
|
$error = $@; |
|
431
|
2
|
50
|
|
|
|
18
|
_clean_stash($obj->{Root}.'::') if $sg != sub_generation(); |
|
432
|
|
|
|
|
|
|
}; |
|
433
|
2
|
50
|
|
|
|
10
|
if ($error) { # rethrow exception |
|
434
|
2
|
|
|
|
|
5
|
$error =~ s/\t\(in cleanup\) //; # prefix added by G_KEEPERR |
|
435
|
2
|
|
|
|
|
20
|
die $error; |
|
436
|
|
|
|
|
|
|
} |
|
437
|
0
|
0
|
|
|
|
0
|
return (wantarray) ? @subret : $subret[0]; |
|
438
|
2
|
|
|
|
|
13
|
}; |
|
439
|
|
|
|
|
|
|
|
|
440
|
2
|
|
|
|
|
10
|
return $ret; |
|
441
|
|
|
|
|
|
|
} |
|
442
|
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
sub rdo { |
|
445
|
1
|
|
|
1
|
1
|
205
|
my ($obj, $file) = @_; |
|
446
|
1
|
50
|
|
|
|
11
|
die "Bad Safe object" unless $obj->isa('Safe'); |
|
447
|
|
|
|
|
|
|
|
|
448
|
1
|
|
|
|
|
3
|
my $root = $obj->{Root}; |
|
449
|
|
|
|
|
|
|
|
|
450
|
1
|
|
|
|
|
6
|
my $sg = sub_generation(); |
|
451
|
1
|
|
|
|
|
110
|
my $evalsub = eval |
|
452
|
|
|
|
|
|
|
sprintf('package %s; sub { @_ = (); do $file }', $root); |
|
453
|
1
|
50
|
|
|
|
417
|
my @subret = (wantarray) |
|
454
|
|
|
|
|
|
|
? Opcode::_safe_call_sv($root, $obj->{Mask}, $evalsub) |
|
455
|
|
|
|
|
|
|
: scalar Opcode::_safe_call_sv($root, $obj->{Mask}, $evalsub); |
|
456
|
1
|
50
|
|
|
|
15
|
_clean_stash($root.'::') if $sg != sub_generation(); |
|
457
|
1
|
|
|
|
|
6
|
$obj->wrap_code_refs_within(@subret); |
|
458
|
1
|
50
|
|
|
|
13
|
return (wantarray) ? @subret : $subret[0]; |
|
459
|
|
|
|
|
|
|
} |
|
460
|
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
1; |
|
463
|
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
__END__ |