Подтвердить что ты не робот

Почему этот блок 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([email protected])
  {
    die "Really die"  unless([email protected]>isa('MyEx'));
  }
}

print "OK\n";

Если вы поместите это в somefile.pl и запустите его, он напечатает "ОК", как ожидалось. Если вы запустите его в отладчике с perl -d somefile.pl, он умрет с этой ошибкой:

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

Результатом является то, что [email protected] не является объектом, когда код работает под отладчиком. Вместо этого он представляет собой непревзойденный скаляр, содержащий эту строку:

" 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.)

4b9b3361

Ответ 1

Это проблема с 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 dieLevel. В конце этой подпрограммы есть:

# perl5db.pl dieLevel, around line 7777 
       elsif ($prevdie) {
            $SIG{__DIE__} = $prevdie;
            print $OUT "Default die handler restored.\n";
        }

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

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

Ответ 2

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

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

Ответ 3

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