Почему этот блок Perl BEGIN действует в отладчике по-другому?
У меня есть некоторый 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
и запустить его, он печатает "ОК", как и ожидалось. Если вы запустите его в отладчике с 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? Каков наилучший способ решить эту проблему? (Я знаю, что это несколько вопросов, но они все связаны.)
Я использую Perl 5.10.0 на Mac OS X 10.5.5.
Предложенная Адамом Беллэром вещь dieLevel выглядела многообещающе, и действительно что-то (не могу выяснить, что) устанавливает для меня 1. Но я установил его на 0, используя ~/.perldb
файл и проблема сохраняется. На самом деле я установил все три соответствующих параметра на 0. Мой ~/.perldb
файл:
parse_options('dieLevel=0 warnLevel=0 signalLevel=0');
Я подтвердил, что настройки действуют, запустив o
Команда в отладчике. Я вижу, что все они установлены в 0, когда я бегу perl -de 0
а также при запуске фактического somefile.pl
файл.
Спасибо, Брайан. я использовал perlbug
подать ошибку ( RT 60890), и я начал окропить local $SIG{'__DIE__'}
во всех соответствующих местах в моем коде. (Я также отметил в ошибке, что perldoc perldebug
по-прежнему подразумевает, что по умолчанию dieLevel
это 0.)
3 ответа
Это проблема с созданием perl5db.pl __DIE__
обработчики. Если я локализую $SIG{__DIE__}
в вашем eval
все работает так, как вы ожидаете.
eval { местный $SIG{__DIE__}; умри MyEx-> новый };
Если вы этого не сделаете, вы получите обработчик из DB::dbdie, который использует Carp::longmess. Этого не должно быть, если dieLevel равен 0, но по умолчанию он равен 1, и ему присваивается значение 1, если он не определен. Это был патч для perl5db.pl еще в 2001 году, и ранее по умолчанию было 0.
Вы должны отключить это с:
PERLDB_OPT="dieLevel=0" perl5.10.0 -d program
Но есть еще ссылка на код в $SIG{__DIE__}
после этого, и это ссылка на dbdie. Я думаю, что это ошибка в обработке глобальной переменной $prevdie
в perl5db.pl's dieLevel
, В конце этой подпрограммы есть:
# perl5db.pl dieLevel, около строки 7777 elsif ($prevdie) { $SIG{__DIE__} = $prevdie; print $OUT "Обработчик штампа по умолчанию восстановлен.\n"; }
Но обратите внимание, что после восстановления $SIG{__DIE__}
, он сохраняет предыдущее значение в $prevdie
Это означает, что все, что есть, просачивается на другой вызов. Когда я запускаю эту командную строку, перед ее обработкой происходит два вызова dieLevel PERLDB_OPT
, так $prevdie
вероятно грязный
Итак, это то, что я получил до того, как больше не хотел думать о perl5db.pl.
Я считаю это ошибкой, так как любой код времени ведет себя по-разному в отладчике.
Ваша проблема может быть связана с этим: отладчик портит таблицу символов. По сути, отладчик играет некоторые хитрости с local
- предположительно как часть вещей для песочницы, чтобы обеспечить интерактивность. Очевидно, что связывание с таблицей символов может иметь неожиданные побочные эффекты. Я предполагаю, что отладчик локализует $@
и, таким образом, скрывая свой объект. Я не могу думать об обходном пути.
Возможно, у вас есть файл RC или переменная среды (PERLDB_OPTS
), который модифицирует dieLevel
вариант отладчика? Я лично не использовал dieLevel
но, очевидно, когда он установлен на значение больше нуля, он может вызвать раскручивание стека и "имеет тенденцию безнадежно уничтожать любую программу, которая серьезно относится к обработке исключений". ( Цитата отсюда).