我有一个相当大的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网站 - 链接中找到对此的详细说明。
谢谢。