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



我有一个相当大的perl程序,将PAR::P acker打包到可执行文件中。它使用了很多模块。

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

但是,我现在面临一个错误(我认为是在 5.22 中引入的),当这种情况发生时,我没有得到任何位置:

Use of each() on hash after insertion without resetting hash iterator results in undefined behaviour, Perl interpreter: 0xa94010

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

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

警告杂注从一组给定类别发出法律代码警告。虽然FATAL将它们更改为致命错误,但它不会改变warn的工作方式。 由于不知道这是如何发出的,因此覆盖__WARN__钩子可能会有所帮助

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

或者你不妨只local这一次。

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

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

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

请注意,Carp::总是完成此操作,甚至更多。 此外,它通常仅在运行程序时激活,-MCarp::Always.感谢池上澄清。

请参阅 perlvar 中的 warn 和 %SIG 哈希,以及这篇 Effective Perler 文章。

最后,你有多少个电话给each? 全部检查。


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

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这个类并将流(文件句柄)tie到它,然后所有打印(到STDERR)都通过上面的PRINT

main.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;

输出

在 Pack 中,issue_warn(TRACE, call_for_err()). 在第 12 行 Pack.pm。  在第 12 Pack.pm 行。 Pack::issue_warn('Pack=HASH(0x7016e8)', 'TRACE call_for_err()') 在第 12 行 main.pl 调用 main::call_for_err('Pack=HASH(0x7016e8)') 在第 8 行调用 main.pl

tie-ing 类应该写得更好,首先是获取参数(要搜索的文本、流或要打印到的句柄)。 参见perltie和Tie::Handle,关于perlmonks的讨论,关于SO的帖子,例如这个,最重要的是Camel(第3版)中的">捆绑文件句柄"一章。

use strict;
use warnings;
sub g {
my %h = ( a => 4, b => 5 );
my $done = 0;
while (my ($k, $v) = each(%h)) {
print("$kn");
$h{c} = 6 if !$done++;
}
}
sub f {
g();
}
f();

你应该得到一个行号!

>perl a.pl
a
Use of each() on hash after insertion without resetting hash iterator results in undefined behavior, Perl interpreter: 0xe688d8 at a.pl line 8.
b
c

Carp::always会将其扩展到堆栈跟踪中。

>perl -MCarp::Always a.pl
a
Use of each() on hash after insertion without resetting hash iterator results in undefined behavior, Perl interpreter: 0x1e88d8 at a.pl line 8.
main::g() called at a.pl line 15
main::f() called at a.pl line 18
c
b

我认为您可以使用诊断或解释。我使用了诊断程序,如果我们无法跟踪生成警告的位置,它会有所帮助。

您只需要在代码中放入行use diagnostics;即可。你可以从Perl Maven网站 - 链接中找到对此的详细说明。

谢谢。

最新更新