Почему этот блок 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 но, очевидно, когда он установлен на значение больше нуля, он может вызвать раскручивание стека и "имеет тенденцию безнадежно уничтожать любую программу, которая серьезно относится к обработке исключений". ( Цитата отсюда).

Другие вопросы по тегам