perl - 从Perl脚本创建/引发SIGINT(Ctrl-C)-并导致从模具处理程序进入调试器进入步骤模式?

标签 perl debugging error-handling event-handling sigint

我在尝试调试的Perl(在Linux下)中的一个相当复杂的程序遇到问题。我可以使用以下简单代码段(test.pl)模拟问题:

use warnings;
use strict;
use feature qw/say/;

my @testa = ();
my $numelems = 10000;

# populate array/list of arrays
for (my $ix = 0; $ix < $numelems; $ix++) {
  my @miniarr = ($ix, 1);
  push(@testa, \@miniarr);
}

say "Array is now " . scalar(@testa) . " elements long";

my $BADnumelems = $numelems + 2;
my $sum = 0;

# loop through array/list of arrays
for (my $ix = 0; $ix < $BADnumelems; $ix++) {
  my @minientry = @{$testa[$ix]};
  $sum += $minientry[0];
}

say "Sum of elements is $sum";

运行该程序将退出:
$ perl test.pl 
Array is now 10000 elements long
Can't use an undefined value as an ARRAY reference at test.pl line 22.

所以,现在我想调试它-但该错误导致程序死亡,并退出调试器:
$ perl -d test.pl 

Loading DB routines from perl5db.pl version 1.32
Editor support available.

Enter h or `h h' for help, or `man perldebug' for more help.

main::(test.pl:6):  my @testa = ();
  DB<1> c
Array is now 10000 elements long
Can't use an undefined value as an ARRAY reference at test.pl line 22.
 at test.pl line 22
Debugged program terminated.  Use q to quit or R to restart,
  use o inhibit_exit to avoid stopping after program termination,
  h q, h R or h o to get additional info.  
  DB<1> p $sum

  DB<2> exit
$ 

然后,我发现break on warning in debugger (PerlMonks);所以我尝试添加以下内容:
...
use feature qw/say/;

$SIG{__DIE__} = sub { my($signal) = @_; say "DIEhandler: $signal"; $DB::single = 1; };
$SIG{__WARN__} = sub { my($signal) = @_; say "WARNhandler: $signal"; $DB::single = 1; };

my @testa = ();
...

...但是这也会杀死调试器:
$ perl -d test.pl 

Loading DB routines from perl5db.pl version 1.32
Editor support available.

Enter h or `h h' for help, or `man perldebug' for more help.

main::(test.pl:6):  $SIG{__DIE__} = sub { my($signal) = @_; say "DIEhandler: $signal"; $DB::single = 1; };
  DB<1> c
Array is now 10000 elements long
DIEhandler: Can't use an undefined value as an ARRAY reference at test.pl line 25.

Can't use an undefined value as an ARRAY reference at test.pl line 25.
Debugged program terminated.  Use q to quit or R to restart,
  use o inhibit_exit to avoid stopping after program termination,
  h q, h R or h o to get additional info.  

现在,我知道如果我用Ctrl-C中断程序-通常会导致调试器进入步进模式;否则,调试器将进入 Debug模式。例如,您可以设置my $numelems = 100000000;,并在其循环时按Ctrl-C-并可以调试:
$ perl -d test.pl 

Loading DB routines from perl5db.pl version 1.32
Editor support available.

Enter h or `h h' for help, or `man perldebug' for more help.

main::(test.pl:6):  $SIG{__DIE__} = sub { my($signal) = @_; say "DIEhandler: $signal"; $DB::single = 1; };
  DB<1> c
^Cmain::(test.pl:14):     my @miniarr = ($ix, 1);
  DB<1> p $ix
148607
  DB<2> q

现在,我可以insert break point into source perl program:
...
for (my $ix = 0; $ix < $BADnumelems; $ix++) {
  $DB::single = 1;               ### <=== BREAK HERE
  my @minientry = @{$testa[$ix]};
...

但它在$ix = 0时进入循环:
$ perl -d test.pl 

Loading DB routines from perl5db.pl version 1.32
Editor support available.

Enter h or `h h' for help, or `man perldebug' for more help.

main::(test.pl:6):  $SIG{__DIE__} = sub { my($signal) = @_; say "DIEhandler: $signal"; $DB::single = 1; };
  DB<1> c
Array is now 10000 elements long
main::(test.pl:26):   my @minientry = @{$testa[$ix]};
  DB<1> p $ix
0
  DB<2> q

...并且我不想单步执行10000个元素来了解有问题的部分:)
因此,我认为以下内容-如果有一种方法可以从Perl脚本本身中引发/生成/创建SIGINT(Ctrl-C),那么我将能够从die处理程序中引发它,并希望在此过程中有所作为。进程终止之前的调试器。因此,我的问题是:
  • 是否有可能从Perl脚本中引发SIGINT,该脚本会自行中断-如果是这样,怎么办?
  • 如果以前的版本可行,是否可以在进程终止之前使用die handler中的Ctrl-C进入调试器步进模式?
  • 如果以前的版本不可能-我必须在哪种可能性下进入die程序所在的调试器步进模式?
  • 最佳答案

    有了这些(尽管不确定我是否正确理解了:)的所有内容),这要归功于这些:

  • Perl's Warn and Die Signals (PerlMonks)
  • How can I get around a 'die' call in a Perl library I can't modify?

  • 只需使用eval包装和warn修改代码,如下所示:
    ...
    # loop through array/list of arrays
    for (my $ix = 0; $ix < $BADnumelems; $ix++) {
      eval {
        my @minientry;
        @minientry = @{$testa[$ix]};
        $sum += $minientry[0];
      }; # just this causes step into debugger at $ix = 10001
      warn $@ if $@; # this causes step into debugger at $ix=10000 (OK)
    }
    ...
    

    ...然后调试器的工作方式如下:
    $ perl -d test.pl 
    
    Loading DB routines from perl5db.pl version 1.32
    Editor support available.
    
    Enter h or `h h' for help, or `man perldebug' for more help.
    
    main::(test.pl:6):  $SIG{__DIE__} = sub { my($signal) = @_; say "DIEhandler: $signal"; @_ = (); $DB::single = 1; };
      DB<1> c
    Array is now 10000 elements long
    DIEhandler: Can't use an undefined value as an ARRAY reference at test.pl line 27.
    
    main::(test.pl:30):   warn $@ if $@; # this causes step into debugger at $ix=10000 (OK)
      DB<1> p $ix
    10000
      DB<2> p @{$testa[$ix]}
    
      DB<3> p @{$testa[$ix-1]}
    99991
      DB<4> p join("--", @{$testa[$ix]})
    
      DB<5> p join("--", @{$testa[$ix-1]})
    9999--1
      DB<6> q
    

    ...就是直接进入有问题的行,这就是我想要的。

    好吧,希望这对某人有帮助,
    干杯!

    编辑:也可能相关:Why do I need to localize $@ before using eval?

    关于perl - 从Perl脚本创建/引发SIGINT(Ctrl-C)-并导致从模具处理程序进入调试器进入步骤模式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14755634/

    相关文章:

    perl - 在 Perl 中如何按二级哈希值排序?

    json - 有没有办法在 JSON 1.x Perl 模块中强制引用数字?

    c# - 如何在 Resharper 中评估表达式,如 IntellijIdea(Alt+F8)

    c# - 在 Visual Studio 2019 调试器中运行时,为什么控制台应用程序在最后一条语句后不退出?

    asp.net-mvc - asp.mvc View 在发布配置中进入#IF DEBUG

    c# - ASP.NET WEB API 2 : Exception Handler and Logger not handling all errors

    ruby-on-rails - 更优雅地处理项目中的 Redis 需求?

    perl - 在 mod_perl2 下 fork 是个坏主意吗?

    asp.net - 经典的ASP错误捕获-可以直接使用ASP.Net页面完成吗?

    regex - 反转正则表达式