2008-11-26 58 views
12

我有一個運行良好的調試器外部的一些Perl代碼:爲什麼Perl BEGIN塊在調試器中的行爲不同?

% 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並運行它,它打印「OK」預期。如果您在調試器與perl -d somefile.pl運行它,它死與此錯誤:

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

其結果是,[email protected]不是一個對象時,該代碼的調試器下運行。相反,它是含有該字符串的unblessed標:

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

(內部換行符和間距保持那是文字文本,連「......」 S。)

我需要這樣的代碼運行在調試器中。在測試套件中使用調試器是我工作流程的重要部分。該模塊使用異常對象,並在編譯時做了很多工作,並期望在被捕獲時拋出一個對象作爲對象。

我的問題(最終)是這樣的:我怎樣才能得到這個工作?有沒有解決方法?這是perl調試器模塊中的一個錯誤嗎?解決這個問題最好的方法是什麼? (我知道這是幾個問題,但它們都是相關的。)

我在Mac OS X 10.5.5上使用perl 5.10.0。


由亞當百利建議的dieLevel事情看起來有希望的,確實的東西(無法找出什麼)是它設置爲1我。但我使用~/.perldb文件將其設置爲0,問題依然存在。事實上,我設置了全部三個的相關設置爲0。我~/.perldb文件:

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

我證實,該設置生效通過在調試器中運行的o命令。當我運行perl -de 0時以及運行實際的somefile.pl文件時,我發現它們都設置爲0。


謝謝你,布萊恩。我用perlbug來提交一個bug(RT 60890),並且我已經開始在我的代碼中的所有合適的地方使用local $SIG{'__DIE__'}

回答

14

這是perl5db.pl創建__DIE__處理程序的問題。如果我在您的eval中本地化$SIG{__DIE__},事情就像您期望的那樣工作。

 
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的引用。我認爲這是處理perl5db.pl的dieLevel中的全局變量$prevdie的一個錯誤。在該子程序結束,有:

 
# 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了。

3

(我也是在perldoc perldebug仍然似乎在暗示,默認dieLevel爲0的錯誤說明)是否有可能你有一個RC文件或正在修改調試器的dieLevel選擇環境變量(PERLDB_OPTS)?我個人並沒有使用dieLevel,但顯然當它被設置爲大於零的值時,它可以強制堆棧展開,並且「傾向於無可救藥地銷燬任何認真對待異常處理的程序」。 (Quote from here)。

+0

沒有設置PERL的env變量,但是看起來我的dieLevel確實設置爲1!有什麼可以做到這一點? – 2008-11-26 21:42:25

+0

嗯,rc文件位於Unix系統的./.perldb或〜/ .perldb中,我認爲OS X可能會使用同一個文件。據文件說,如果選項不在命令行或env中,則必須在該選項中設置該選項。也許你可以嘗試明確地設置dieLevel爲零? – 2008-11-27 02:01:12

5

我認爲它是一個錯誤,任何時間代碼在調試器中的行爲都不相同。

您的問題可能與此相關:Debugger corrupts symbol table munging。實質上,調試器似乎扮演了一些技巧local - 大概是作爲沙箱的一部分提供交互性。顯然,符號表的混亂可能會產生意想不到的副作用。我猜測調試器本地化[email protected],從而模糊你的對象。我想不出一種解決辦法。

+0

你是說你認爲它是調試器中的一個錯誤? – 2008-11-27 13:58:03

相關問題