Blame t/code.t

Packit 14c646
#!./perl
Packit 14c646
#
Packit 14c646
#  Copyright (c) 2002 Slaven Rezic
Packit 14c646
#
Packit 14c646
#  You may redistribute only under the same terms as Perl 5, as specified
Packit 14c646
#  in the README file that comes with the distribution.
Packit 14c646
#
Packit 14c646
Packit 14c646
sub BEGIN {
Packit 14c646
    unshift @INC, 't';
Packit 14c646
    unshift @INC, 't/compat' if $] < 5.006002;
Packit 14c646
    require Config; import Config;
Packit 14c646
    if ($ENV{PERL_CORE} and $Config{'extensions'} !~ /\bStorable\b/) {
Packit 14c646
        print "1..0 # Skip: Storable was not built\n";
Packit 14c646
        exit 0;
Packit 14c646
    }
Packit 14c646
}
Packit 14c646
Packit 14c646
use strict;
Packit 14c646
BEGIN {
Packit 14c646
    if (!eval q{
Packit 14c646
	use Test::More;
Packit 14c646
	use B::Deparse 0.61;
Packit 14c646
	use 5.006;
Packit 14c646
	1;
Packit 14c646
    }) {
Packit 14c646
	print "1..0 # skip: tests only work with B::Deparse 0.61 and at least perl 5.6.0\n";
Packit 14c646
	exit;
Packit 14c646
    }
Packit 14c646
    require File::Spec;
Packit 14c646
    if ($File::Spec::VERSION < 0.8) {
Packit 14c646
	print "1..0 # Skip: newer File::Spec needed\n";
Packit 14c646
	exit 0;
Packit 14c646
    }
Packit 14c646
}
Packit 14c646
Packit 14c646
BEGIN { plan tests => 63 }
Packit 14c646
Packit 14c646
use Storable qw(retrieve store nstore freeze nfreeze thaw dclone);
Packit 14c646
use Safe;
Packit 14c646
Packit 14c646
#$Storable::DEBUGME = 1;
Packit 14c646
Packit 14c646
our ($freezed, $thawed, @obj, @res, $blessed_code);
Packit 14c646
Packit 14c646
$blessed_code = bless sub { "blessed" }, "Some::Package";
Packit 14c646
{ package Another::Package; sub foo { __PACKAGE__ } }
Packit 14c646
Packit 14c646
{
Packit 14c646
    no strict; # to make the life for Safe->reval easier
Packit 14c646
    sub code { "JAPH" }
Packit 14c646
}
Packit 14c646
Packit 14c646
local *FOO;
Packit 14c646
Packit 14c646
@obj =
Packit 14c646
    ([\&code,                   # code reference
Packit 14c646
      sub { 6*7 },
Packit 14c646
      $blessed_code,            # blessed code reference
Packit 14c646
      \&Another::Package::foo,  # code in another package
Packit 14c646
      sub ($$;$) { 0 },         # prototypes
Packit 14c646
      sub { print "test\n" },
Packit 14c646
      \&Storable::_store,       # large scalar
Packit 14c646
     ],
Packit 14c646
Packit 14c646
     {"a" => sub { "srt" }, "b" => \&code},
Packit 14c646
Packit 14c646
     sub { ord("a")-ord("7") },
Packit 14c646
Packit 14c646
     \&code,
Packit 14c646
Packit 14c646
     \&dclone,                 # XS function
Packit 14c646
Packit 14c646
     sub { open FOO, '<', "/" },
Packit 14c646
    );
Packit 14c646
Packit 14c646
$Storable::Deparse = 1;
Packit 14c646
$Storable::Eval    = 1;
Packit 14c646
Packit 14c646
######################################################################
Packit 14c646
# Test freeze & thaw
Packit 14c646
Packit 14c646
$freezed = freeze $obj[0];
Packit 14c646
$thawed  = thaw $freezed;
Packit 14c646
Packit 14c646
is($thawed->[0]->(), "JAPH");
Packit 14c646
is($thawed->[1]->(), 42);
Packit 14c646
is($thawed->[2]->(), "blessed");
Packit 14c646
is($thawed->[3]->(), "Another::Package");
Packit 14c646
is(prototype($thawed->[4]), prototype($obj[0]->[4]));
Packit 14c646
Packit 14c646
######################################################################
Packit 14c646
Packit 14c646
$freezed = freeze $obj[1];
Packit 14c646
$thawed  = thaw $freezed;
Packit 14c646
Packit 14c646
is($thawed->{"a"}->(), "srt");
Packit 14c646
is($thawed->{"b"}->(), "JAPH");
Packit 14c646
Packit 14c646
######################################################################
Packit 14c646
Packit 14c646
$freezed = freeze $obj[2];
Packit 14c646
$thawed  = thaw $freezed;
Packit 14c646
Packit 14c646
is($thawed->(), (ord "A") == 193 ? -118 : 42);
Packit 14c646
Packit 14c646
######################################################################
Packit 14c646
Packit 14c646
$freezed = freeze $obj[3];
Packit 14c646
$thawed  = thaw $freezed;
Packit 14c646
Packit 14c646
is($thawed->(), "JAPH");
Packit 14c646
Packit 14c646
######################################################################
Packit 14c646
Packit 14c646
eval { $freezed = freeze $obj[4] };
Packit 14c646
like($@, qr/The result of B::Deparse::coderef2text was empty/);
Packit 14c646
Packit 14c646
######################################################################
Packit 14c646
# Test dclone
Packit 14c646
Packit 14c646
my $new_sub = dclone($obj[2]);
Packit 14c646
is($new_sub->(), $obj[2]->());
Packit 14c646
Packit 14c646
######################################################################
Packit 14c646
# Test retrieve & store
Packit 14c646
Packit 14c646
store $obj[0], "store$$";
Packit 14c646
# $Storable::DEBUGME = 1;
Packit 14c646
$thawed = retrieve "store$$";
Packit 14c646
Packit 14c646
is($thawed->[0]->(), "JAPH");
Packit 14c646
is($thawed->[1]->(), 42);
Packit 14c646
is($thawed->[2]->(), "blessed");
Packit 14c646
is($thawed->[3]->(), "Another::Package");
Packit 14c646
is(prototype($thawed->[4]), prototype($obj[0]->[4]));
Packit 14c646
Packit 14c646
######################################################################
Packit 14c646
Packit 14c646
nstore $obj[0], "store$$";
Packit 14c646
$thawed = retrieve "store$$";
Packit 14c646
unlink "store$$";
Packit 14c646
Packit 14c646
is($thawed->[0]->(), "JAPH");
Packit 14c646
is($thawed->[1]->(), 42);
Packit 14c646
is($thawed->[2]->(), "blessed");
Packit 14c646
is($thawed->[3]->(), "Another::Package");
Packit 14c646
is(prototype($thawed->[4]), prototype($obj[0]->[4]));
Packit 14c646
Packit 14c646
######################################################################
Packit 14c646
# Security with
Packit 14c646
#   $Storable::Eval
Packit 14c646
#   $Storable::Deparse
Packit 14c646
Packit 14c646
{
Packit 14c646
    local $Storable::Eval = 0;
Packit 14c646
Packit 14c646
    for my $i (0 .. 1) {
Packit 14c646
	$freezed = freeze $obj[$i];
Packit 14c646
	$@ = "";
Packit 14c646
	eval { $thawed  = thaw $freezed };
Packit 14c646
	like($@, qr/Can\'t eval/);
Packit 14c646
    }
Packit 14c646
}
Packit 14c646
Packit 14c646
{
Packit 14c646
Packit 14c646
    local $Storable::Deparse = 0;
Packit 14c646
    for my $i (0 .. 1) {
Packit 14c646
	$@ = "";
Packit 14c646
	eval { $freezed = freeze $obj[$i] };
Packit 14c646
	like($@, qr/Can\'t store CODE items/);
Packit 14c646
    }
Packit 14c646
}
Packit 14c646
Packit 14c646
{
Packit 14c646
    local $Storable::Eval = 0;
Packit 14c646
    local $Storable::forgive_me = 1;
Packit 14c646
    for my $i (0 .. 4) {
Packit 14c646
	$freezed = freeze $obj[0]->[$i];
Packit 14c646
	$@ = "";
Packit 14c646
	eval { $thawed  = thaw $freezed };
Packit 14c646
	is($@, "");
Packit 14c646
	like($$thawed, qr/^sub/);
Packit 14c646
    }
Packit 14c646
}
Packit 14c646
Packit 14c646
{
Packit 14c646
    local $Storable::Deparse = 0;
Packit 14c646
    local $Storable::forgive_me = 1;
Packit 14c646
Packit 14c646
    my $devnull = File::Spec->devnull;
Packit 14c646
Packit 14c646
    open(SAVEERR, ">&STDERR");
Packit 14c646
    open(STDERR, '>', $devnull) or
Packit 14c646
	( print SAVEERR "Unable to redirect STDERR: $!\n" and exit(1) );
Packit 14c646
Packit 14c646
    eval { $freezed = freeze $obj[0]->[0] };
Packit 14c646
Packit 14c646
    open(STDERR, ">&SAVEERR");
Packit 14c646
Packit 14c646
    is($@, "");
Packit 14c646
    isnt($freezed, '');
Packit 14c646
}
Packit 14c646
Packit 14c646
{
Packit 14c646
    my $safe = new Safe;
Packit 14c646
    local $Storable::Eval = sub { $safe->reval(shift) };
Packit 14c646
Packit 14c646
    $freezed = freeze $obj[0]->[0];
Packit 14c646
    $@ = "";
Packit 14c646
    eval { $thawed = thaw $freezed };
Packit 14c646
    is($@, "");
Packit 14c646
    is($thawed->(), "JAPH");
Packit 14c646
Packit 14c646
    $freezed = freeze $obj[0]->[6];
Packit 14c646
    eval { $thawed = thaw $freezed };
Packit 14c646
    # The "Code sub ..." error message only appears if Log::Agent is installed
Packit 14c646
    like($@, qr/(trapped|Code sub)/);
Packit 14c646
Packit 14c646
    if (0) {
Packit 14c646
	# Disable or fix this test if the internal representation of Storable
Packit 14c646
	# changes.
Packit 14c646
	skip("no malicious storable file check", 1);
Packit 14c646
    } else {
Packit 14c646
	# Construct malicious storable code
Packit 14c646
	$freezed = nfreeze $obj[0]->[0];
Packit 14c646
	my $bad_code = ';open FOO, "/badfile"';
Packit 14c646
	# 5th byte is (short) length of scalar
Packit 14c646
	my $len = ord(substr($freezed, 4, 1));
Packit 14c646
	substr($freezed, 4, 1, chr($len+length($bad_code)));
Packit 14c646
	substr($freezed, -1, 0, $bad_code);
Packit 14c646
	$@ = "";
Packit 14c646
	eval { $thawed = thaw $freezed };
Packit 14c646
	like($@, qr/(trapped|Code sub)/);
Packit 14c646
    }
Packit 14c646
}
Packit 14c646
Packit 14c646
{
Packit 14c646
    my $safe = new Safe;
Packit 14c646
    # because of opcodes used in "use strict":
Packit 14c646
    $safe->permit(qw(:default require caller));
Packit 14c646
    local $Storable::Eval = sub { $safe->reval(shift) };
Packit 14c646
Packit 14c646
    $freezed = freeze $obj[0]->[1];
Packit 14c646
    $@ = "";
Packit 14c646
    eval { $thawed = thaw $freezed };
Packit 14c646
    is($@, "");
Packit 14c646
    is($thawed->(), 42);
Packit 14c646
}
Packit 14c646
Packit 14c646
{
Packit 14c646
    {
Packit 14c646
	package MySafe;
Packit 14c646
	sub new { bless {}, shift }
Packit 14c646
	sub reval {
Packit 14c646
	    my $source = $_[1];
Packit 14c646
	    # Here you can apply some nifty regexpes to ensure the
Packit 14c646
	    # safeness of the source code.
Packit 14c646
	    my $coderef = eval $source;
Packit 14c646
	    $coderef;
Packit 14c646
	}
Packit 14c646
    }
Packit 14c646
Packit 14c646
    my $safe = new MySafe;
Packit 14c646
    local $Storable::Eval = sub { $safe->reval($_[0]) };
Packit 14c646
Packit 14c646
    $freezed = freeze $obj[0];
Packit 14c646
    eval { $thawed  = thaw $freezed };
Packit 14c646
    is($@, "");
Packit 14c646
Packit 14c646
    if ($@ ne "") {
Packit 14c646
        fail() for (1..5);
Packit 14c646
    } else {
Packit 14c646
	is($thawed->[0]->(), "JAPH");
Packit 14c646
	is($thawed->[1]->(), 42);
Packit 14c646
	is($thawed->[2]->(), "blessed");
Packit 14c646
	is($thawed->[3]->(), "Another::Package");
Packit 14c646
	is(prototype($thawed->[4]), prototype($obj[0]->[4]));
Packit 14c646
    }
Packit 14c646
}
Packit 14c646
Packit 14c646
{
Packit 14c646
    # Check internal "seen" code
Packit 14c646
    my $short_sub = sub { "short sub" }; # for SX_SCALAR
Packit 14c646
    # for SX_LSCALAR
Packit 14c646
    my $long_sub_code = 'sub { "' . "x"x255 . '" }';
Packit 14c646
    my $long_sub = eval $long_sub_code; die $@ if $@;
Packit 14c646
    my $sclr = \1;
Packit 14c646
Packit 14c646
    local $Storable::Deparse = 1;
Packit 14c646
    local $Storable::Eval    = 1;
Packit 14c646
Packit 14c646
    for my $sub ($short_sub, $long_sub) {
Packit 14c646
	my $res;
Packit 14c646
Packit 14c646
	$res = thaw freeze [$sub, $sub];
Packit 14c646
	is(int($res->[0]), int($res->[1]));
Packit 14c646
Packit 14c646
	$res = thaw freeze [$sclr, $sub, $sub, $sclr];
Packit 14c646
	is(int($res->[0]), int($res->[3]));
Packit 14c646
	is(int($res->[1]), int($res->[2]));
Packit 14c646
Packit 14c646
	$res = thaw freeze [$sub, $sub, $sclr, $sclr];
Packit 14c646
	is(int($res->[0]), int($res->[1]));
Packit 14c646
	is(int($res->[2]), int($res->[3]));
Packit 14c646
    }
Packit 14c646
Packit 14c646
}
Packit 14c646
Packit 14c646
{
Packit 14c646
    my @text = ("hello", "\x{a3}", "\x{a3} \x{2234}", "\x{2234}\x{2234}");
Packit 14c646
Packit 14c646
    for my $text(@text) {
Packit 14c646
        my $res = (thaw freeze eval "sub {'" . $text . "'}")->();
Packit 14c646
        ok($res eq $text);
Packit 14c646
    }
Packit 14c646
}
Packit 14c646