Понимает ли сейф Perl новые функции?
Я играю с модулем Safe для включения в освоение Perl. Версии до версии v5. 16 (самая ранняя поддерживаемая версия), похоже, не понимают новых ключевых слов. Я что-то упустил?
Say работает с 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, двумя официально поддерживаемыми версиями 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, так как он не думает, что говорит ключевое слово допустимо:
% 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!""
Государство не работает, но ломается по-разному
С состоянием все по-другому.
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 $nn";
}
CODE
$compartment->reval( $code ) or do {
my $error = $@;
warn "Safe compartment error! $@";
};
V5. 18 и v5. 16 считают состояние синтаксической ошибкой:
% 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 "Bustern" }
}
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 ") {"
1 ответ:
Можно использовать инструмент деления на части, чтобы проверить, когда определенный фрагмент кода начал работать. Один включен, если вы клонируете весь репозиторий 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; }; 'Проблема в том, что это была случайно исправленная ошибка. Если вы посмотрите на diff для toke.c , Вы можете заметить, что старая версия взяла функции из7d69d4a61be1619f90910462eac42234c874712e is the first bad commit commit 7d69d4a61be1619f90910462eac42234c874712e Author: Father Chrysostomos <[email protected]> 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 secondsPL_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из него). Тем не менее, это ужасный Хак ...
Comments