我正在尝试将 Perl 从版本 5.16 升级到 5.26,现在哈希值的随机化方式有所不同。有没有办法恢复到 5.16 的旧行为?我对新行为有疑问,因为现有代码和测试依赖于旧的可预测哈希顺序。
zdi*_*dim 12
哈希值的实现在 5.18 中进行了重大修改,请参阅perl5180delta。
(问题的原始形式)中没有说明大规模检修的哪一部分是问题所在,但 PERL_PERTURB_KEYS环境变量似乎可以提供帮助
环境
PERL_PERTURB_KEYS变量允许控制应用于 和 朋友的随机化级别keys。当
PERL_PERTURB_KEYS为 0 时,perl 根本不会随机化键顺序。由于插入而发生变化的机会keys与之前的 perls 中相同,基本上仅当存储桶大小发生变化时。
...
更全面的讨论可以在 perlrun 中找到,例如PERL_HASH_SEED
...
如果提供了该选项,但未PERL_PERTURB_KEYS设置,则值“0”意味着PERL_PERTURB_KEYS=0/PERL_PERTURB_KEYS=NO,任何其他值意味着PERL_PERTURB_KEYS=2/PERL_PERTURB_KEYS=DETERMINISTIC。PERL_PERTURB_KEYS有关该模式的重要注意事项,请参阅文档DETERMINISTIC。
...
以及紧随其后的PERL_PERTURB_KEYS(我的重点)
...
(自 Perl 5.18.0 起)设置为“0”或“NO”,则对于相同的运行,遍历键将可以在运行之间重复PERL_HASH_SEED。插入散列不会改变顺序,除非在散列中提供更多空间。 与设置结合使用时,PERL_HASH_SEED此模式尽可能接近 5.18 之前的行为。
...
因此,请设置这些环境变量,或者设置PERL_HASH_SEED并相应地设置另一个环境变量,以便重复运行程序以具有相同的顺序等。(请注意,如果将键添加到哈希中,则它可能会在 5.18 之前的代码中随机化同样,在这种情况下,在 5.18+ 中设置这些变量也无济于事。更安全的方法是始终对键进行排序。)
我理解恢复旧行为的论点,但我必须建议阅读完整的文档并考虑安全影响。
另请参阅perlsec 中的算法复杂性攻击。
为此需要在 shell 中设置环境变量,例如在 bash 中设置为
export PERL_HASH_SEED=0
Run Code Online (Sandbox Code Playgroud)
这可以在运行程序的终端中完成,也可以在其中完成,这样.bashrc您就不必每次打开终端时都执行此操作。(但是它会影响从该 shell 运行的所有脚本。)或者,可以在启动程序的同一命令行上执行此操作
$ PERL_HASH_SEED=0 program.pl arguments
Run Code Online (Sandbox Code Playgroud)
如果程序是由另一个程序启动的(不是直接在 shell 中),那么您也可以通过父进程中的%ENV哈希来设置它,因为环境是由子进程继承的。然后,组织所有这些的一种独立方法是添加一个简短的包装脚本,其中
$ENV{PERL_HASH_SEED} = 0;
my @cmd = ...
system( @cmd ) == 0 or ...
Run Code Online (Sandbox Code Playgroud)
当然,除了system之外,还有很多方法可以从 Perl 程序中运行命令,从内置qx(“反引号”的运算符形式)和pipeline-open (也可以在 perlipc 中查看)开始,它们允许对命令的输出。或者,更好的是,使用像IPC::System::Simple, Capture::Tiny, IPC::Run(从更简单到更强大)这样的库。
哈希随机化更改的文档位于此处
以下设置将使您获得一致的订单
设置 PERL_HASH_SEED=0(恰好是一个 0)意味着 PERL_PERTURB_KEYS=0(禁用哈希密钥随机化)
您可以按照一致的顺序返回钥匙,我怀疑这不足以满足您的目的。
无论如何,我们用一个小脚本来测试一下
# create a hash
my %hash = map { $_ => $_ } 'a' .. 'e';
printHashKeys(\%hash);
printHashKeys(\%hash);
printHashKeys(\%hash);
printHashKeys(\%hash);
sub printHashKeys
{
my $h = shift ;
my %hash = %$h;
for my $key (keys %hash)
{
print "$key " ;
}
print "\n";
}
Run Code Online (Sandbox Code Playgroud)
使用 Perl 5.30.2 运行,我得到这个 - 键顺序每次都不同。
$ perl try.pl
c a e b d
a c e b d
d b e a c
a c e b d
Run Code Online (Sandbox Code Playgroud)
现在PERL_HASH_SEED设置为 0。这次它们的密钥以一致的顺序出现
$ PERL_HASH_SEED=0 perl try.pl
b c d e a
b c d e a
b c d e a
b c d e a
Run Code Online (Sandbox Code Playgroud)