3 # Copyright (c) 2002 Slaven Rezic
5 # You may redistribute only under the same terms as Perl 5, as specified
6 # in the README file that comes with the distribution.
12 @INC = ('.', '../lib');
16 require Config; import Config;
17 if ($ENV{PERL_CORE} and $Config{'extensions'} !~ /\bStorable\b/) {
18 print "1..0 # Skip: Storable was not built\n";
31 print "1..0 # skip: tests only work with B::Deparse 0.61 and at least perl 5.6.0\n";
35 if ($File::Spec::VERSION < 0.8) {
36 print "1..0 # Skip: newer File::Spec needed\n";
41 BEGIN { plan tests => 59 }
43 use Storable qw(retrieve store nstore freeze nfreeze thaw dclone);
46 #$Storable::DEBUGME = 1;
48 use vars qw($freezed $thawed @obj @res $blessed_code);
50 $blessed_code = bless sub { "blessed" }, "Some::Package";
51 { package Another::Package; sub foo { __PACKAGE__ } }
54 no strict; # to make the life for Safe->reval easier
61 ([\&code, # code reference
63 $blessed_code, # blessed code reference
64 \&Another::Package::foo, # code in another package
65 sub ($$;$) { 0 }, # prototypes
66 sub { print "test\n" },
67 \&Test::ok, # large scalar
70 {"a" => sub { "srt" }, "b" => \&code},
72 sub { ord("a")-ord("7") },
76 \&dclone, # XS function
78 sub { open FOO, "/" },
81 $Storable::Deparse = 1;
84 ######################################################################
87 $freezed = freeze $obj[0];
88 $thawed = thaw $freezed;
90 ok($thawed->[0]->(), "JAPH");
91 ok($thawed->[1]->(), 42);
92 ok($thawed->[2]->(), "blessed");
93 ok($thawed->[3]->(), "Another::Package");
94 ok(prototype($thawed->[4]), prototype($obj[0]->[4]));
96 ######################################################################
98 $freezed = freeze $obj[1];
99 $thawed = thaw $freezed;
101 ok($thawed->{"a"}->(), "srt");
102 ok($thawed->{"b"}->(), "JAPH");
104 ######################################################################
106 $freezed = freeze $obj[2];
107 $thawed = thaw $freezed;
111 ######################################################################
113 $freezed = freeze $obj[3];
114 $thawed = thaw $freezed;
116 ok($thawed->(), "JAPH");
118 ######################################################################
120 eval { $freezed = freeze $obj[4] };
121 ok($@, qr/The result of B::Deparse::coderef2text was empty/);
123 ######################################################################
126 my $new_sub = dclone($obj[2]);
127 ok($new_sub->(), $obj[2]->());
129 ######################################################################
130 # Test retrieve & store
132 store $obj[0], 'store';
133 $thawed = retrieve 'store';
135 ok($thawed->[0]->(), "JAPH");
136 ok($thawed->[1]->(), 42);
137 ok($thawed->[2]->(), "blessed");
138 ok($thawed->[3]->(), "Another::Package");
139 ok(prototype($thawed->[4]), prototype($obj[0]->[4]));
141 ######################################################################
143 nstore $obj[0], 'store';
144 $thawed = retrieve 'store';
147 ok($thawed->[0]->(), "JAPH");
148 ok($thawed->[1]->(), 42);
149 ok($thawed->[2]->(), "blessed");
150 ok($thawed->[3]->(), "Another::Package");
151 ok(prototype($thawed->[4]), prototype($obj[0]->[4]));
153 ######################################################################
159 local $Storable::Eval = 0;
162 $freezed = freeze $obj[$i];
164 eval { $thawed = thaw $freezed };
165 ok($@, qr/Can\'t eval/);
171 local $Storable::Deparse = 0;
174 eval { $freezed = freeze $obj[$i] };
175 ok($@, qr/Can\'t store CODE items/);
180 local $Storable::Eval = 0;
181 local $Storable::forgive_me = 1;
183 $freezed = freeze $obj[0]->[$i];
185 eval { $thawed = thaw $freezed };
187 ok($$thawed, qr/^sub/);
192 local $Storable::Deparse = 0;
193 local $Storable::forgive_me = 1;
195 my $devnull = File::Spec->devnull;
197 open(SAVEERR, ">&STDERR");
198 open(STDERR, ">$devnull") or
199 ( print SAVEERR "Unable to redirect STDERR: $!\n" and exit(1) );
201 eval { $freezed = freeze $obj[0]->[0] };
203 open(STDERR, ">&SAVEERR");
211 local $Storable::Eval = sub { $safe->reval(shift) };
213 $freezed = freeze $obj[0]->[0];
215 eval { $thawed = thaw $freezed };
217 ok($thawed->(), "JAPH");
219 $freezed = freeze $obj[0]->[6];
220 eval { $thawed = thaw $freezed };
221 # The "Code sub ..." error message only appears if Log::Agent is installed
222 ok($@, qr/(trapped|Code sub)/);
225 # Disable or fix this test if the internal representation of Storable
227 skip("no malicious storable file check", 1);
229 # Construct malicious storable code
230 $freezed = nfreeze $obj[0]->[0];
231 my $bad_code = ';open FOO, "/badfile"';
232 # 5th byte is (short) length of scalar
233 my $len = ord(substr($freezed, 4, 1));
234 substr($freezed, 4, 1, chr($len+length($bad_code)));
235 substr($freezed, -1, 0, $bad_code);
237 eval { $thawed = thaw $freezed };
238 ok($@, qr/(trapped|Code sub)/);
244 # because of opcodes used in "use strict":
245 $safe->permit(qw(:default require));
246 local $Storable::Eval = sub { $safe->reval(shift) };
248 $freezed = freeze $obj[0]->[1];
250 eval { $thawed = thaw $freezed };
258 sub new { bless {}, shift }
261 # Here you can apply some nifty regexpes to ensure the
262 # safeness of the source code.
263 my $coderef = eval $source;
268 my $safe = new MySafe;
269 local $Storable::Eval = sub { $safe->reval($_[0]) };
271 $freezed = freeze $obj[0];
272 eval { $thawed = thaw $freezed };
278 ok($thawed->[0]->(), "JAPH");
279 ok($thawed->[1]->(), 42);
280 ok($thawed->[2]->(), "blessed");
281 ok($thawed->[3]->(), "Another::Package");
282 ok(prototype($thawed->[4]), prototype($obj[0]->[4]));
287 # Check internal "seen" code
288 my $short_sub = sub { "short sub" }; # for SX_SCALAR
290 my $long_sub_code = 'sub { "' . "x"x255 . '" }';
291 my $long_sub = eval $long_sub_code; die $@ if $@;
294 local $Storable::Deparse = 1;
295 local $Storable::Eval = 1;
297 for my $sub ($short_sub, $long_sub) {
300 $res = thaw freeze [$sub, $sub];
301 ok(int($res->[0]), int($res->[1]));
303 $res = thaw freeze [$sclr, $sub, $sub, $sclr];
304 ok(int($res->[0]), int($res->[3]));
305 ok(int($res->[1]), int($res->[2]));
307 $res = thaw freeze [$sub, $sub, $sclr, $sclr];
308 ok(int($res->[0]), int($res->[1]));
309 ok(int($res->[2]), int($res->[3]));