⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 safe.pm

📁 UNIX下perl实现代码
💻 PM
📖 第 1 页 / 共 2 页
字号:
package Safe;use 5.003_11;use strict;our $VERSION = "2.06";use Carp;use Opcode 1.01, qw(    opset opset_to_ops opmask_add    empty_opset full_opset invert_opset verify_opset    opdesc opcodes opmask define_optag opset_to_hex);*ops_to_opset = \&opset;   # Temporary alias for old Penguinsmy $default_root  = 0;my $default_share = ['*_']; #, '*main::'];sub new {    my($class, $root, $mask) = @_;    my $obj = {};    bless $obj, $class;    if (defined($root)) {	croak "Can't use \"$root\" as root name"	    if $root =~ /^main\b/ or $root !~ /^\w[:\w]*$/;	$obj->{Root}  = $root;	$obj->{Erase} = 0;    }    else {	$obj->{Root}  = "Safe::Root".$default_root++;	$obj->{Erase} = 1;    }    # use permit/deny methods instead till interface issues resolved    # XXX perhaps new Safe 'Root', mask => $mask, foo => bar, ...;    croak "Mask parameter to new no longer supported" if defined $mask;    $obj->permit_only(':default');    # We must share $_ and @_ with the compartment or else ops such    # as split, length and so on won't default to $_ properly, nor    # will passing argument to subroutines work (via @_). In fact,    # for reasons I don't completely understand, we need to share    # the whole glob *_ rather than $_ and @_ separately, otherwise    # @_ in non default packages within the compartment don't work.    $obj->share_from('main', $default_share);    return $obj;}sub DESTROY {    my $obj = shift;    $obj->erase('DESTROY') if $obj->{Erase};}sub erase {    my ($obj, $action) = @_;    my $pkg = $obj->root();    my ($stem, $leaf);    no strict 'refs';    $pkg = "main::$pkg\::";	# expand to full symbol table name    ($stem, $leaf) = $pkg =~ m/(.*::)(\w+::)$/;    # The 'my $foo' is needed! Without it you get an    # 'Attempt to free unreferenced scalar' warning!    my $stem_symtab = *{$stem}{HASH};    #warn "erase($pkg) stem=$stem, leaf=$leaf";    #warn " stem_symtab hash ".scalar(%$stem_symtab)."\n";	# ", join(', ', %$stem_symtab),"\n";#    delete $stem_symtab->{$leaf};    my $leaf_glob   = $stem_symtab->{$leaf};    my $leaf_symtab = *{$leaf_glob}{HASH};#    warn " leaf_symtab ", join(', ', %$leaf_symtab),"\n";    %$leaf_symtab = ();    #delete $leaf_symtab->{'__ANON__'};    #delete $leaf_symtab->{'foo'};    #delete $leaf_symtab->{'main::'};#    my $foo = undef ${"$stem\::"}{"$leaf\::"};    if ($action and $action eq 'DESTROY') {        delete $stem_symtab->{$leaf};    } else {        $obj->share_from('main', $default_share);    }    1;}sub reinit {    my $obj= shift;    $obj->erase;    $obj->share_redo;}sub root {    my $obj = shift;    croak("Safe root method now read-only") if @_;    return $obj->{Root};}sub mask {    my $obj = shift;    return $obj->{Mask} unless @_;    $obj->deny_only(@_);}# v1 compatibility methodssub trap   { shift->deny(@_)   }sub untrap { shift->permit(@_) }sub deny {    my $obj = shift;    $obj->{Mask} |= opset(@_);}sub deny_only {    my $obj = shift;    $obj->{Mask} = opset(@_);}sub permit {    my $obj = shift;    # XXX needs testing    $obj->{Mask} &= invert_opset opset(@_);}sub permit_only {    my $obj = shift;    $obj->{Mask} = invert_opset opset(@_);}sub dump_mask {    my $obj = shift;    print opset_to_hex($obj->{Mask}),"\n";}sub share {    my($obj, @vars) = @_;    $obj->share_from(scalar(caller), \@vars);}sub share_from {    my $obj = shift;    my $pkg = shift;    my $vars = shift;    my $no_record = shift || 0;    my $root = $obj->root();    croak("vars not an array ref") unless ref $vars eq 'ARRAY';	no strict 'refs';    # Check that 'from' package actually exists    croak("Package \"$pkg\" does not exist")	unless keys %{"$pkg\::"};    my $arg;    foreach $arg (@$vars) {	# catch some $safe->share($var) errors:	croak("'$arg' not a valid symbol table name")	    unless $arg =~ /^[\$\@%*&]?\w[\w:]*$/	    	or $arg =~ /^\$\W$/;	my ($var, $type);	$type = $1 if ($var = $arg) =~ s/^(\W)//;	# warn "share_from $pkg $type $var";	*{$root."::$var"} = (!$type)       ? \&{$pkg."::$var"}			  : ($type eq '&') ? \&{$pkg."::$var"}			  : ($type eq '$') ? \${$pkg."::$var"}			  : ($type eq '@') ? \@{$pkg."::$var"}			  : ($type eq '%') ? \%{$pkg."::$var"}			  : ($type eq '*') ?  *{$pkg."::$var"}			  : croak(qq(Can't share "$type$var" of unknown type));    }    $obj->share_record($pkg, $vars) unless $no_record or !$vars;}sub share_record {    my $obj = shift;    my $pkg = shift;    my $vars = shift;    my $shares = \%{$obj->{Shares} ||= {}};    # Record shares using keys of $obj->{Shares}. See reinit.    @{$shares}{@$vars} = ($pkg) x @$vars if @$vars;}sub share_redo {    my $obj = shift;    my $shares = \%{$obj->{Shares} ||= {}};	my($var, $pkg);    while(($var, $pkg) = each %$shares) {	# warn "share_redo $pkg\:: $var";	$obj->share_from($pkg,  [ $var ], 1);    }}sub share_forget {    delete shift->{Shares};}sub varglob {    my ($obj, $var) = @_;    no strict 'refs';    return *{$obj->root()."::$var"};}sub reval {    my ($obj, $expr, $strict) = @_;    my $root = $obj->{Root};    # Create anon sub ref in root of compartment.    # Uses a closure (on $expr) to pass in the code to be executed.    # (eval on one line to keep line numbers as expected by caller)	my $evalcode = sprintf('package %s; sub { eval $expr; }', $root);    my $evalsub;	if ($strict) { use strict; $evalsub = eval $evalcode; }	else         {  no strict; $evalsub = eval $evalcode; }    return Opcode::_safe_call_sv($root, $obj->{Mask}, $evalsub);}sub rdo {    my ($obj, $file) = @_;    my $root = $obj->{Root};    my $evalsub = eval	    sprintf('package %s; sub { do $file }', $root);    return Opcode::_safe_call_sv($root, $obj->{Mask}, $evalsub);}1;__END__=head1 NAMESafe - Compile and execute code in restricted compartments=head1 SYNOPSIS  use Safe;  $compartment = new Safe;  $compartment->permit(qw(time sort :browse));  $result = $compartment->reval($unsafe_code);=head1 DESCRIPTIONThe Safe extension module allows the creation of compartmentsin which perl code can be evaluated. Each compartment has=over 8=item a new namespaceThe "root" of the namespace (i.e. "main::") is changed to adifferent package and code evaluated in the compartment cannotrefer to variables outside this namespace, even with run-timeglob lookups and other tricks.Code which is compiled outside the compartment can choose to placevariables into (or I<share> variables with) the compartment's namespaceand only that data will be visible to code evaluated in thecompartment.By default, the only variables shared with compartments are the"underscore" variables $_ and @_ (and, technically, the less frequentlyused %_, the _ filehandle and so on). This is because otherwise perloperators which default to $_ will not work and neither will theassignment of arguments to @_ on subroutine entry.=item an operator maskEach compartment has an associated "operator mask". Recall that

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -