Почему этот блок Perl BEGIN действует в отладчике по-другому? - PullRequest
12 голосов
/ 27 ноября 2008

У меня есть некоторый Perl-код, который отлично работает вне отладчика:

% perl somefile.pl

но когда я запускаю его внутри отладчика:

% perl -d somefile.pl

ведет себя по-разному.

Указанные файлы (их несколько) являются частью набора тестов для большого модуля Perl (~ 20 тыс. Строк кода). Тесты выполняют большую часть настройки во время компиляции и используют блоки 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? Каков наилучший способ решить эту проблему? (Я знаю, что это несколько вопросов, но все они связаны.)

Я использую 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 ]

14 голосов
/ 27 ноября 2008

Это проблема с perl5db.pl, создающим __DIE__ обработчики. Если я локализую $SIG{__DIE__} в вашем eval, все будет работать так, как вы ожидаете.

 eval { 
    local $SIG{__DIE__};
    die MyEx->new 
    };

Если вы этого не сделаете, вы получите обработчик из 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, around line 7777 
       elsif ($prevdie) {
            $SIG{__DIE__} = $prevdie;
            print $OUT "Default die handler restored.\n";
        }

Но обратите внимание, что после восстановления $SIG{__DIE__} оно сохраняет предыдущее значение в $prevdie, что означает, что все, что там, просачивается на другой вызов. Когда я запускаю эту командную строку, перед его обработкой PERLDB_OPT происходит два вызова dieLevel, поэтому $prevdie, вероятно, грязный.

Итак, это все, что я получил до того, как больше не хотел думать о perl5db.pl.

5 голосов
/ 27 ноября 2008

Я считаю это ошибкой, когда любой код в отладчике ведет себя по-разному.

Ваша проблема может быть связана с этим: Отладчик портит обработку таблицы символов . По сути, отладчик, похоже, играет некоторые хитрости с local - предположительно, как часть «песочницы» для обеспечения интерактивности. Очевидно, что связывание с таблицей символов может иметь неожиданные побочные эффекты. Я предполагаю, что отладчик локализует $@ и таким образом скрывает ваш объект. Я не могу придумать обходного пути.

3 голосов
/ 27 ноября 2008

Возможно, у вас есть файл RC или переменная среды (PERLDB_OPTS), которая изменяет параметр dieLevel отладчика? Лично я не использовал dieLevel, но, очевидно, когда он установлен на значение больше нуля, это может привести к разматыванию стека и «имеет тенденцию безнадежно уничтожать любую программу, которая серьезно относится к обработке исключений». ( Цитата отсюда ).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...