在作用域 `no autodie` 之后,程序在 `*STDOUT` 结束

After scoped `no autodie` the program dies at `*STDOUT`

这个节目

use warnings;
use strict;
use feature qw(say);

{
    #use autodie;   # all good when this is uncommented
    no autodie;
}

open my $OLDSTD, '>&', *STDOUT;        #--> line 10 (program fails)
open *STDOUT, '>', 'stdout.out';

say "$$ done";

中止

Undefined subroutine called at problem_no_autodie.pl line 10.

重申代码中的注释:如果首先有一个 use autodie; 语句,那么一切都很好。 (只有 use autodie; 也很好。)奇怪的是,在与 no autodie 语句相同的范围内,我也没有看到这样的问题;只有超出其范围的代码才会失败!有点反作用域,嗯?

如果这个作用域 no autodie 在 使用 *STDOUT 之后 出现,那么一切都很好。在(作用域)no autodie 之后进一步使用 *STDOUT,程序失败。

文档中提到的 Gotcha 涉及裸词(我不完全理解),并且该程序确实因 STDOUT 而失败 - 但我将其作为 *STDOUT.

所以 *STDOUT 似乎被视为用户的 sub,但我不明白 autodie 的范围是如何被击败的。 (范围泄漏在某些版本中被称为错误,但以一种看似无关的方式。)这有一个实际问题。

我没有在我的代码中使用 autodie。但是考虑一下我确实使用的这个潜艇

sub isatty {
    no autodie;
    state $isatty = open(my $tty, '+<', '/dev/tty');
    return $isatty;
}

open 失败是合法的,因此我们必须在该范围内禁用 autodie,以防子用户启用它。那么所描述的行为会造成伤害吗?在什么情况下?

我对 no autodie 的这种影响及其超出其范围的泄漏以及它们所有奇怪的细节感到困惑。但真正令人担忧的是,我不确定如何保护使用上述库的代码免受这种行为的影响,因为我不了解它。有什么想法吗?

我在 CentOS 7.8 的 5.16.3(系统)、5.26.2 和 5.30.0(perlbrew)下看到了这个

没有在 5.32.0 上看到这种行为;那里没有失败。


... or die $!open 的检查没有任何区别,因此为简单起见未显示。

This bug 在 autodie 2.24 中引入并在 autodie 2.30 中修复。

$ ( cd ./autodie-2.23; perl Makefile.PL >&3; make >&3; perl -Mblib ../a.pl && echo ok ) 3>/dev/null
ok

$ ( cd ./autodie-2.24; perl Makefile.PL >&3; make >&3; perl -Mblib ../a.pl && echo ok ) 3>/dev/null
Undefined subroutine called at ../a.pl line 10.

$ ( cd ./autodie-2.29; perl Makefile.PL >&3; make >&3; perl -Mblib ../a.pl && echo ok ) 3>/dev/null
Undefined subroutine called at ../a.pl line 10.

$ ( cd ./autodie-2.30; perl Makefile.PL >&3; make >&3; perl -Mblib ../a.pl && echo ok ) 3>/dev/null
ok

$ ( cd ./autodie-2.31; perl Makefile.PL >&3; make >&3; perl -Mblib ../a.pl && echo ok ) 3>/dev/null
ok

(在 CPAN 上找不到 2.30。)

为防止出现此问题,请添加对 autodie 2.30 或更高版本的依赖。