12

我有一些在调试器之外运行良好的 Perl 代码:

% perl somefile.pl

但是当我在调试器中运行它时:

% perl -d somefile.pl

它的行为不同。

有问题的文件(有几个)是大型 Perl 模块(约 20K 行代码)的测试套件的一部分。测试在编译时做了很多设置工作并使用 BEGIN 块。这是一些最小的复制代码:

BEGIN
{
  package MyEx;

  sub new { bless {}, shift }

  package main;

  eval { die MyEx->new };

  if($@)
  {
    die "Really die"  unless($@->isa('MyEx'));
  }
}

print "OK\n";

如果你把它放进去somefile.pl并运行它,它会按预期打印“OK”。如果您在调试器中使用 运行它perl -d somefile.pl,它会因以下错误而死:

Can't call method "isa" without a package or object reference ...

结果是$@当代码在调试器下运行时它不是对象。相反,它是一个包含此字符串的无福标量:

" at somefile.pl line 9
    eval {...} called at somefile.pl line 9
    main::BEGIN() called at somefile.pl line 16
    eval {...} called at somefile.pl line 16
"

(保留内部换行符和间距。这是文字,甚至是“...”。)

我需要这样的代码才能在调试器中运行。在测试套件中使用调试器是我工作流程的重要组成部分。该模块使用异常对象并在编译时做了很多事情,并期望抛出的对象在被捕获时成为对象。

我的问题(最后)是这样的:我怎样才能让它工作?有解决方法吗?这是 perl 调试器模块中的错误吗?解决此问题的最佳方法是什么?(我知道这是几个问题,但它们都是相关的。)

我在 Mac OS X 10.5.5 上使用 perl 5.10.0。


Adam Bellaire 建议的 dieLevel 看起来很有希望,而且确实有些东西(无法找出是什么)对我来说将它设置为 1。但是我使用~/.perldb文件将其设置为 0 并且问题仍然存在。事实上,我将所有三个相关设置都设置为 0。我的~/.perldb文件:

parse_options('dieLevel=0 warnLevel=0 signalLevel=0');

o我通过在调试器中运行命令确认设置生效。当我运行perl -de 0时以及运行实际somefile.pl文件时,我看到它们都设置为 0。


谢谢,布赖恩。我曾经perlbug提交过一个错误 ( RT 60890 ),并且我已经开始local $SIG{'__DIE__'}在我的代码中的所有适当位置进行添加。(我还在错误中注意到perldoc perldebug似乎仍然暗示默认dieLevel值为 0。)

4

3 回答 3

14

这是 perl5db.pl 创建__DIE__处理程序的问题。$SIG{__DIE__}如果我在你的本地化eval,事情会如你所愿。

评估{
    本地 $SIG{__DIE__};
    死MyEx->新
    };

如果您不这样做,您将从 DB::dbdie 获取处理程序,该处理程序使用 Carp::longmess。如果 dieLevel 为 0,则不应该发生这种情况,但默认情况下为 1,如果未定义,则将其设置为 1。这是 2001 年对 perl5db.pl 的补丁,之前默认值为 0。

您应该通过以下方式关闭此功能:

PERLDB_OPT="dieLevel=0" perl5.10.0 -d program

但是在那之后还有一个代码引用$SIG{__DIE__},它是对dbdie的引用。我认为这是处理$prevdieperl5db.pl 中的全局变量的错误dieLevel。在该子程序的末尾,有:

# perl5db.pl dieLevel,在第 7777 行附近
       elsif ($prevdie) {
            $SIG{__DIE__} = $prevdie;
            print $OUT "默认模具处理程序已恢复。\n";
        }

但请注意,在 restore 之后$SIG{__DIE__},它将先前的值保留在 中$prevdie,这意味着其中的任何内容都会泄漏给另一个调用。当我运行该命令行时,在 dieLevel 处理之前有两次调用PERLDB_OPT,所以$prevdie可能很脏。

所以,在我不想再考虑 perl5db.pl 之前,这就是我所得到的。

于 2008-11-27T13:36:15.177 回答
5

每当代码在调试器中表现不同时,我都认为这是一个错误。

您的问题可能与此有关:调试器损坏符号表 munging。从本质上讲,调试器似乎在玩一些技巧local——大概是作为沙盒的一部分以提供交互性。显然,弄乱符号表可能会产生意想不到的副作用。我猜调试器正在本地化$@并因此模糊了您的对象。我想不出解决办法。

于 2008-11-26T23:01:19.173 回答
3

您是否可能有一个 RC 文件或环境变量 ( PERLDB_OPTS) 正在修改dieLevel调试器的选项?我个人没有使用过dieLevel,但显然当它设置为大于零的值时,它会强制堆栈展开,并且“倾向于无可救药地破坏任何认真对待其异常处理的程序”。(从这里引用)。

于 2008-11-26T21:25:06.137 回答