2008-11-26 14 views
12

mam jakiś kod Perl, który działa poprawnie poza debugera:Dlaczego ten blok Perl BEGIN działa inaczej w debugerze?

% perl somefile.pl 

ale gdy uruchamiam go wewnątrz debuggera:

% perl -d somefile.pl 

zachowuje się inaczej.

Pliki, o których mowa (jest ich kilka) są częścią zestawu testów dla dużego modułu Perla (~ 20K wierszy kodu). Testy wykonują wiele prac konfiguracyjnych podczas kompilacji i używają bloków BEGIN. Oto niektóre minimalne Kod reprodukcji:

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"; 

Jeśli umieścisz że w somefile.pl i uruchomić go, drukuje „OK”, jak oczekiwano. Jeśli uruchomić go w debugera z perl -d somefile.pl, umiera z tego błędu:

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

Skutek jest taki, że [email protected] nie jest obiektem, kiedy uruchamia kod pod debugger. Zamiast tego, jest to unblessed skalarne zawierające ten ciąg:

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

(nowe linie wewnętrzne i odstęp zachowany To dosłowny tekst, nawet „...” s.).

muszę kodu tak, aby uruchomić w debugerze. Używanie debuggera w zestawie testów jest ważną częścią mojego przepływu pracy. Moduł używa obiektów wyjątku i wykonuje wiele rzeczy podczas kompilacji i oczekuje, że obiekt zostanie rzucony jako obiekt podczas przechwytywania.

Moje pytanie (w końcu) brzmi: jak mogę to uruchomić? Czy jest w pobliżu praca? Czy jest to błąd w module debuggera perla? Jaki jest najlepszy sposób, aby rozwiązać ten problem? (Wiem, że to kilka pytań, ale wszystkie są powiązane.)

Używam perl 5.10.0 na Mac OS X 10.5.5.


dieLevel rzeczą sugerowane przez Adam Bellaire wyglądał obiecująco i rzeczywiście coś (nie może dowiedzieć się, co) jest ustawienie go na 1 dla mnie. Ale ustawiłem go na 0, używając pliku ~/.perldb, a problem nadal występuje. W rzeczywistości, mogę ustawić wszystkie trzy powiązanych ustawień 0. My ~/.perldb plik:

parse_options('dieLevel=0 warnLevel=0 signalLevel=0'); 

potwierdziłem, że ustawienia są w rzeczywistości, uruchamiając komendę o w debuggera. Widzę je wszystkie ustawione na 0, gdy uruchamiam perl -de 0, a także podczas uruchamiania rzeczywistego pliku somefile.pl.


Dzięki, Brian. Użyłem perlbug do zgłoszenia błędu (RT 60890) i zacząłem kropić local $SIG{'__DIE__'} we wszystkich odpowiednich miejscach w moim kodzie. (I również zauważyć, że w błąd perldoc perldebug wciąż wydaje się sugerować, że domyślna dieLevel 0.)

Odpowiedz

14

To jest problem z perl5db.pl tworzeniem __DIE__ programów obsługi. Jeśli zlokalizuję $SIG{__DIE__} w twoim eval, wszystko będzie działać zgodnie z oczekiwaniami.

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

Jeśli tego nie zrobisz, otrzymujesz handler z DB :: dbdie, który używa Carp :: longmess. To nie powinno się zdarzyć, jeśli dieLevel ma wartość 0, ale domyślnie jest to 1 i zostanie ustawione na 1, jeśli nie jest zdefiniowane. Był to łatka do perl5db.pl z powrotem w 2001 roku, a wcześniej był domyślną 0.

Miałeś to wyłączyć z:

PERLDB_OPT="dieLevel=0" perl5.10.0 -d program 

Ale nadal istnieje odniesienie kod w $SIG{__DIE__} po tym, i jest to odniesienie do dbdie. Myślę, że jest to błąd w obsłudze globalnej zmiennej $prevdie w perl5db.pl na dieLevel. Pod koniec tego podprogramu, to:

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

jednak zauważyć, że po przywróceniu $SIG{__DIE__}, zachowuje poprzednią wartość w $prevdie, czyli co tam jest przecieki do innego połączenia. Kiedy uruchamiam tę linię poleceń, są dwa wywołania funkcji DieLevel, zanim obsłuży ona PERLDB_OPT, więc $prevdie jest prawdopodobnie brudny.

Tak więc, tak daleko, jak to było, nie chciałem już myśleć o perl5db.pl.

+1

Jesteś odważniejszym mężczyzną niż ja, Brian. Za każdym razem, gdy myślę o poklepywaniu w perl5db, dostaję się do komentarzy na temat tego, co jest splątanym bałaganem, ponieważ traci moją motywację. –

3

Czy to możliwe, że masz plik RC lub zmienną środowiskową (PERLDB_OPTS), który modyfikuje opcję debuggera dieLevel?Osobiście nie używałem dieLevel, ale najwyraźniej, gdy jest ustawione na wartość większą od zera, może wymusić rozwijanie stosu i "ma tendencję do beznadziejnego niszczenia dowolnego programu, który poważnie traktuje wyjątki." (Quote from here).

+0

Żaden env vars z PERL w nich nie jest ustawiony, ale wygląda na to, że moja graLevel jest rzeczywiście ustawiona na 1! Co to może zrobić? –

+0

Hmm, plik rc znajduje się w ./.perldb lub ~/.perldb na systemach Unix, myślę, że OS X prawdopodobnie użyłby tego samego pliku. Jeśli chodzi o dokumentację, opcja musi być tam ustawiona, jeśli nie znajduje się ona w wierszu poleceń lub w env. Może możesz spróbować jawnie ustawić dieLevel na zero? –

5

Uważam, że jest to błąd za każdym razem, gdy kod zachowuje się inaczej w debugerze.

Twój problem może być związany z: Debugger corrupts symbol table munging. Zasadniczo debugger wydaje się odgrywać niektóre sztuczki z local - prawdopodobnie jako część piaskownicy rzeczy w celu zapewnienia interaktywności. Oczywiście zakłócanie tablicy symboli może powodować nieoczekiwane efekty uboczne. Domyślam się, że debugger lokalizuje [email protected] i tym samym przesłania obiekt. Nie mogę myśleć o obejściu.

+0

Masz na myśli, że uważasz go za błąd w debugerze? –