我有一些在调试器外运行良好的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的错误。)
答案 0 :(得分:14)
这是perl5db.pl创建__DIE__
处理程序的问题。如果我在$SIG{__DIE__}
中对eval
进行本地化,则可以按预期进行操作。
eval { local $SIG{__DIE__}; die MyEx->new };
如果你不这样做,你将从DB :: dbdie获得处理程序,它使用Carp :: longmess。如果dieLevel为0,则不会发生这种情况,但默认情况下为1,如果未定义,则设置为1。这是2001年perl5db.pl的补丁,之前的默认值是0。
你应该用以下方式关闭它:
PERLDB_OPT="dieLevel=0" perl5.10.0 -d program
但之后在$SIG{__DIE__}
中仍然存在代码引用,它是对dbdie的引用。我认为这是处理perl5db.pl的$prevdie
中的全局变量dieLevel
时的错误。在该子例程结束时,有:
# perl5db.pl dieLevel, around line 7777 elsif ($prevdie) { $SIG{__DIE__} = $prevdie; print $OUT "Default die handler restored.\n"; }
但请注意,在恢复$SIG{__DIE__}
之后,它会将之前的值保留在$prevdie
中,这意味着其中的任何内容都会泄漏给另一个调用。当我运行该命令行时,在处理PERLDB_OPT
之前有两次对dieLevel的调用,因此$prevdie
可能很脏。
所以,就我所知,我不想再考虑perl5db.pl了。
答案 1 :(得分:5)
我认为任何时候代码在调试器中的行为方式都是错误的。
您的问题可能与此相关:Debugger corrupts symbol table munging。从本质上讲,调试器似乎与local
一起玩一些技巧 - 可能是作为沙盒事物的一部分来提供交互性。显然,弄乱符号表会产生意想不到的副作用。我猜测调试器正在本地化$@
,从而模糊了你的对象。我无法想到一个解决方法。
答案 2 :(得分:3)
是否可能有RC文件或环境变量(PERLDB_OPTS
)正在修改调试器的dieLevel
选项?我个人没有使用dieLevel
,但显然当它被设置为大于零的值时,它可以强制堆栈展开,并且“倾向于无可救药地破坏任何严重处理其异常处理的程序。” (Quote from here)。