perl - 如何确定 Perl 警告的位置 - 插入后在哈希上使用each()

标签 perl

我有一个相当大的 Perl 程序,用 PAR::Packer 打包成可执行文件。它使用了相当多的模块。

通常,当 perl 给我一个警告时,比如使用未定义的值,它会打印错误的位置,然后很容易深入并调试它。

但是,我现在面临一个错误(我认为是在 5.22 中引入的),当发生这种情况时,我无法获取位置:

插入后在哈希上使用each()而不重置哈希迭代器会导致未定义的行为,Perl解释器:0xa94010

我尝试设置use warnings FATAL=>'all';,但没有任何变化,程序不会终止。

也许它来自一个模块?我还能如何确定警告的位置?

最佳答案

warnings pragma 从一组给定类别中发出针对法律代码的警告。虽然 FATAL 将它们更改为 fatal error ,但它不会改变 warn 的工作方式。由于不知道这是如何发出的,因此重写 __WARN__ 钩子(Hook)很有可能会有所帮助

local $SIG{__WARN__} = \&Carp::confess;   # or just die

或者您也可以仅删除本地这一次。

要尝试的另一件事是覆盖 CORE::GLOBAL::warn

BEGIN { *CORE::GLOBAL::warn = sub { die } }  # before use Module;

这也会影响模块,如果在模块之前的 BEGIN 中设置 __WARN__ 信号也会影响模块。

请注意Carp::Always实现这一点,甚至更多。此外,它通常只需在运行程序时使用 -MCarp::Always 即可激活。感谢ikegami进行澄清。

参见warn%SIG hash in perlvar ,还有这个Effective Perler article .

最后,您对每个有多少次调用?检查全部。


注释中解释说,打印来自 XS,是通过调试器找到的,但仍不清楚是什么代码触发了这一点。然后尝试将流tie-ing到一个类,在相关文本上触发跟踪。一个最小的例子

TraceError.pm

package TraceError;
use warnings;
use strict;
use Carp qw(longmess confess);

sub TIEHANDLE { bless {} }

sub PRINT {
    my $self = shift;
    my $prn = join '', @_;

    # print "STDERR: $prn";   # TEST
    print @_;                 # or   print STDERR @_;

    # if ($prn =~ /\QUse of each() on hash after insertion/)  # in your code
    if ($prn =~ /TRACE/) {                                    # test
        print longmess(@_);
    }
}

1;

更改为注释掉的 if 行,以便扫描打印件以查找错误消息的文本。下面的其余部分只是对此的测试。在代码中,您需要 main.pl 中的前两行来 use 这个类并将流(文件句柄)绑定(bind)到它,然后所有打印(到 STDERR)都通过上面的 PRINT 进行。

ma​​in.pl

use TraceError;
tie *STDERR,'TraceError';

use warnings;
use strict;
use Pack qw(issue_warn);

call_for_err(Pack->new);

sub call_for_err {
    my ($pck) = @_; 
    $pck->issue_warn("TRACE call_for_err()");  # should catch this print
    $pck->issue_warn("from call_for_err()");   # but not this
};

Pack.pm

package Pack;
use warnings;
use strict;

use Exporter qw(import);
our @EXPORT_OK = qw(issue_warn);

sub new { bless {}, $_[0] }

sub issue_warn { 
    my $self = shift;
    warn "In ", __PACKAGE__, ", issue_warn(@_).";
}

1;

输出

In Pack, issue_warn(TRACE, call_for_err()). at Pack.pm line 12.
 at Pack.pm line 12.
    Pack::issue_warn('Pack=HASH(0x7016e8)', 'TRACE call_for_err()') called at main.pl line 12
    main::call_for_err('Pack=HASH(0x7016e8)') called at main.pl line 8

tie-ing 类应该写得更好,首先要接受参数(要搜索的文本、要打印的流或句柄)。请参阅perltieTie::Handle ,关于perlmonks的讨论,在 SO 上发布帖子,例如 this one ,尤其是 Camel(第 3 版)中的“绑定(bind)文件句柄”一章。

关于perl - 如何确定 Perl 警告的位置 - 插入后在哈希上使用each(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43059012/

相关文章:

Perl 处理格式错误的字符

regex - Perl,动态生成的带有反斜杠元字符的正则表达式字符串奇怪的行为

linux - 没有可用于基本错误的 Presto 元数据下载包 :

perl 在 HTTP::Request 中支持 IPv6 地址格式 [::1]

java - 优化 CSV 处理脚本 - Python、Perl 和 Java

regex - 在 Perl 中使用正则表达式替换整个字符串

perl - 如何使用 Perl::Mechanize 的解析器迭代 300 页?

Perl - 简单的 if 语句不起作用

arrays - Perl 将哈希值数组输出为表

perl - 为什么 perl 找不到我安装的 SSH2 模块?