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

时间:2017-03-28 01:16:02

标签: perl

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

通常,当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';,但没有任何变化,程序也不会死。

也许它来自一个模块?我怎样才能确定警告的位置?

3 个答案:

答案 0 :(得分:2)

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

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

或者您也可以这一次放弃local

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

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

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

请注意Carp::Always完成此操作,等等。此外,它通常仅在运行程序时使用BEGIN激活。感谢ikegami澄清。

请参阅warn%SIG hash in perlvar以及此Effective Perler article

最后,您有多少次拨打-MCarp::Always?检查一下。

在评论中解释说,打印来自XS,通过调试器找到,但仍然不知道是什么代码触发了这个。然后尝试each - 将流转换为类,其中在相关文本上触发跟踪。最小的例子

<强> TraceError.pm

tie

更改为已注释的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; 行,以便扫描错误消息文本的打印件。下面的其余部分只是对此的测试。在您的代码中,您需要前两行ifmain.pl此类和use流(文件句柄)到它,然后所有打印(到tie)去通过上面的STDERR

<强> main.pl

PRINT

<强> Pack.pm

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
};

输出

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

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; - ing类应该写得更好,首先要采用参数(文本搜索,流或句柄打印到)。请参阅perltieTie::Handle,关于perlmonks的讨论,关于SO的帖子,例如this one,以及最重要的章节&#34; 绑定文件句柄 &#34;在Camel(第3版)。

答案 1 :(得分:1)

use strict;
use warnings;

sub g {
   my %h = ( a => 4, b => 5 );

   my $done = 0;
   while (my ($k, $v) = each(%h)) {
      print("$k\n");
      $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

答案 2 :(得分:-1)

我认为你可以使用诊断或splain。我已经使用了诊断功能,如果我们无法跟踪生成警告的位置,它会有所帮助。

您只需将代码行use diagnostics;放在代码中即可。您可以在Perl Maven网站上找到详细的解释 - Link

感谢。