perl - Perl 的 Safe 是否了解新功能?

标签 perl opcode

我在玩Safe包含在 Mastering Perl 中的模块. v5.16 之前的版本(支持的最早版本)似乎不理解新关键字。我错过了什么吗?

说适用于 v5.16 及更高版本

use v5.10;

use Safe;

say "Running $0 under $^V with Safe ", Safe->VERSION;

my $compartment = Safe->new;
$compartment->permit( ':base_io', ':load' );

my $code =<<"CODE";
use v5.10;
say "Hello Safe!";
CODE

$compartment->reval( $code ) or do {
        my $error = $@;
        warn "Safe compartment error! $@";
        };

此代码在 v5.18 和 v5.16 下按我预期运行,这两个 officially supported versions of Perl :
% perl5.18.0 safe.pl
Running safe.pl under v5.18.0 with Safe 2.35
Hello Safe!

% perl5.16.3 safe.pl
Running safe.pl under v5.16.3 with Safe 2.35
Hello Safe!

它在 v5.16 之前不起作用,因为它不认为 say关键字有效:
% perl5.14.4 safe.pl
Running safe.pl under v5.14.4 with Safe 2.35
String found where operator expected at (eval 5) line 2, near "say "Hello Safe!""
    (Do you need to predeclare say?)
Safe compartment error! syntax error at (eval 5) line 2, near "say "Hello Safe!""

% perl5.12.3 safe.pl
Running safe.pl under v5.12.3 with Safe 2.35
String found where operator expected at (eval 5) line 2, near "say "Hello Safe!""
    (Do you need to predeclare say?)
Safe compartment error! syntax error at (eval 5) line 2, near "say "Hello Safe!""

% perl5.10.1 safe.pl
Running safe.pl under v5.10.1 with Safe 2.35
String found where operator expected at (eval 5) line 2, near "say "Hello Safe!""
    (Do you need to predeclare say?)
Safe compartment error! syntax error at (eval 5) line 2, near "say "Hello Safe!""

状态不起作用,但中断方式不同

state这是不同的。
use v5.10;

use Safe;

say "Running $0 under $^V with Safe ", Safe->VERSION;

my $compartment = Safe->new;
$compartment->permit( ':base_io', ':load' );

my $code =<<'CODE';
use v5.10;
print "Hello Safe!\n";
foo();
sub foo {
    state $n = 0;
    print "n is $n\n";
    }
CODE

$compartment->reval( $code ) or do {
        my $error = $@;
        warn "Safe compartment error! $@";
        };

v5.18 和 v5.16 认为 state是语法错误:
% perl5.18.0 safe.pl
Running safe.pl under v5.18.0 with Safe 2.35
Hello Safe!
n is 0

% perl5.16.3 safe.pl
Running safe.pl under v5.16.3 with Safe 2.35
Hello Safe!
n is 0

在那些版本之前,我认为它正在处理 state作为间接方法:
% perl5.14.4 safe.pl
Running safe.pl under v5.14.4 with Safe 2.35
Hello Safe!
Safe compartment error! Can't call method "state" on an undefined value at (eval 5) line 5.

给定
given有同样的问题:
use v5.10;

use Safe;

say "Running $0 under $^V with Safe ", Safe->VERSION;

my $compartment = Safe->new;
$compartment->permit( ':base_io', ':load' );

my $code =<<'CODE';
use v5.10;
print "Hello Safe!\n";
my $foo = 'Buster Bean';
given( $foo ) {
    when( /Buster/ ) { print "Buster\n" }
    }
CODE

$compartment->reval( $code ) or do {
        my $error = $@;
        warn "Safe compartment error! $@";
        };

它在 v5.16 和 v5.18 中运行良好:
% perl5.18.0 safe.pl
Running safe.pl under v5.18.0 with Safe 2.35
given is experimental at (eval 5) line 4.
when is experimental at (eval 5) line 5.
Hello Safe!
Buster

但在早期版本中中断:
% perl5.14.4 safe.pl
Running safe.pl under v5.14.4 with Safe 2.35
Safe compartment error! syntax error at (eval 5) line 4, near ") {"

最佳答案

可以使用二等分工具来检查某些代码何时开始工作。如果您克隆整个 Perl 存储库,则包括一个。这允许检查它何时开始工作。

~/perl> Porting/bisect.pl --expect-fail --start=v5.14.0 --end=v5.16.3 -e '
        use v5.10;

        use Safe;

        say "Running $0 under $^V with Safe ", Safe->VERSION;

        my $compartment = Safe->new;
        $compartment->permit( ":base_io", ":load" );

        my $code =<<"CODE";
        use v5.10;
        say "Hello Safe!";
        CODE

        $compartment->reval( $code ) or do {
                my $error = $@;
                warn "Safe compartment error! $@";
                exit 1;
                };
        '

这样做之后,你就会得到结果。
7d69d4a61be1619f90910462eac42234c874712e is the first bad commit
commit 7d69d4a61be1619f90910462eac42234c874712e
Author: Father Chrysostomos <sprout@cpan.org>
Date:   Thu Dec 15 16:26:16 2011 -0800

    Disable $[ under 5.16

    This adds the array_base feature to feature.pm

    Perl_feature_is_enabled has been modified to use PL_curcop, rather
    than PL_hintgv, so it can work with run-time hints as well.
    (PL_curcop holds the current state op at run time, and &PL_compiling
    at compile time, so it works for both.)  The hints in $^H are not
    stored in the same place at compile time and run time, so the FEATURE_IS_ENABLED macro has been modified to check first whether
    PL_curop == &PL_compiling.

    Since array_base is on by default with no hint for it in %^H, it is
    a ‘negative’ feature, whose entry in %^H turns it off.  feature.pm
    has been modified to support such negative features.  The new FEATURE_IS_ENABLED_d can check whether such default features
    are enabled.

    This does make things less efficient, as every version declaration
    now loads feature.pm to disable all features (including turning off
    array_base, which entails adding an entry to %^H) before loading the
    new bundle.  I have plans to make this more efficient.

:100644 100644 e96e6608641a33838158a54cb0ac2402c716e848 3b81d3fc286480be3512864b43f3c9230fd1c376 M      embed.fnc
:040000 040000 7f9483dd9d2f290810866ad40810461398385515 e1d43bd8aa24bec1d6b5f80a1f36f6787fb70d32 M      ext
:100644 100644 2af41a87c417a2afded5c9f55bd0a69bcf71db80 37a1bd9510eb5064d052fb00b68a0e7eec3df716 M      gv.c
:040000 040000 9d82bf63a49734aec1e01c5da6362c3dec7e1a22 2b12bd8c206ae14fc819fbb781cdb2b09c1a9c95 M      lib
:100644 100644 c55ca63a5819c32c747279ddcc698653dc8eca6f 3432dfe5c4c7b568712a9f0f31177695528892e4 M      mg.c
:100644 100644 313087d34a4135e1854b4f00ab58b71d687a32e1 812ece2bb1757489865e36dec0ceeaa8d6c86168 M      op.c
:100644 100644 e203dfe1941e7c3e13cdf6b68e509339258229bf ef3d4efec6604738d6beded3ff16d9a1ab73c465 M      perl.h
:100644 100644 92befdac8afebe578740e84ca24ca46a091b072e eec052f413638d1efba00c81f423a68d1a4f984e M      proto.h
:040000 040000 9deb7ece55f230bcf0e0bb83a5e1646e05770db2 d425283f05fb825181a2b3836ff3ce2570821500 M      t
:100644 100644 2c29c582e2a1c2ba6aeefe56368a383785b27830 2f395d458da5941b49552d85bbf52b1070b5b32e M      toke.c
bisect run success
That took 1921 seconds

问题是它是一个意外修复的错误。如果你看看diff for toke.c ,您会注意到旧版本从 PL_hintgv 中获取了功能。 ,但新版本使用PL_curcop .它们之间的区别在于 PL_hintgv包含编译时间单位设置。 PL_curcop但是,包含当前设置。在Safe , use feature保存到错误的地方。

问题是 PL_hintgv检查当前编译单元。与Safe打交道时,它是无意义的空哈希,因为模块确实可以工作。 PL_curcop但是检查当前范围 - 所以它适用于 Safe .

现在寻找解决方法。存在一个,但它涉及使用 eval 指定设置.如eval设置编译单元,您可以使用它来指定您想要的设置。它不会让用户更改设置,但会为您提供一些评估代码的设置。

例如,如果您更改 $compartment->reval( $code )eval '$compartment->reval( $code )'在您的代码中,它将开始工作,如 eval做了一个新的编译单元,你的代码有use v5.10;在标题中(eval 从中复制 use v5.10)。尽管如此,这是一个可怕的黑客......

关于perl - Perl 的 Safe 是否了解新功能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17131094/

相关文章:

xml - 无法定位对象方法 setData - 将值保存在 XML 文件中

php - 用于添加出现在搜索引擎结果中的评级/星级的脚本

java - 使用 Java 访问内存

mips - 为什么 'opcode' 字段和 'funct' 字段在 MIPS 中是分开的?

java - 为什么 JSR/RET 不推荐使用 Java 字节码?

perl - 如何从数组元素中删除前导和尾随空格?

perl - 为什么第 4 章中来自 'Learning Perl 6th edition' 的示例无法运行?

regex - bash - 如何从 bash 脚本中将换行符传递给 perl?

php - 类扩展或接口(interface)如何工作?

assembly - 'call dword ptr [mem32]' 问题的操作码和 ModRM?