2008-11-26 32 views
12

Tôi có một số mã Perl chạy tốt ngoài debugger:Tại sao khối lệnh Perl BEGIN này hoạt động khác trong trình gỡ lỗi?

% perl somefile.pl 

nhưng khi tôi chạy nó bên trong trình gỡ lỗi:

% perl -d somefile.pl 

nó cư xử khác nhau.

Các tệp được đề cập (có một số) là một phần của bộ thử nghiệm cho mô-đun Perl lớn (~ 20K dòng mã). Các bài kiểm tra làm rất nhiều công việc thiết lập tại thời gian biên dịch và sử dụng khối BEGIN. Đây là một số mã sinh sản tối thiểu:

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

Nếu bạn đặt mã đó vào somefile.pl và chạy nó, nó in "OK" như mong đợi. Nếu bạn chạy nó trong trình gỡ lỗi với perl -d somefile.pl, nó chết với lỗi này:

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

Kết quả là [email protected] không phải là một đối tượng khi mã chạy dưới trình gỡ lỗi. Thay vào đó, nó là một đại lượng vô hướng không được ban phước chứa chuỗi này:

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

(dòng mới nội và khoảng cách bảo quản Đó là văn bản theo nghĩa đen, ngay cả những "..." s..)

Tôi cần có mã như thế này để chạy trong trình gỡ rối. Sử dụng trình gỡ rối trong bộ kiểm thử là một phần quan trọng trong quy trình làm việc của tôi. Module sử dụng các đối tượng ngoại lệ và thực hiện rất nhiều thứ tại thời gian biên dịch và hy vọng một đối tượng được ném vào là một đối tượng khi bị bắt.

Câu hỏi của tôi (cuối cùng) là: Làm thế nào tôi có thể làm việc này? Có cách giải quyết nào không? Đây có phải là lỗi trong mô-đun trình gỡ lỗi perl không? Cách tốt nhất để giải quyết vấn đề này là gì? (Tôi biết đó là một số câu hỏi, nhưng tất cả đều có liên quan.)

Tôi đang sử dụng perl 5.10.0 trên Mac OS X 10.5.5.


Điều chết người được đề xuất bởi Adam Bellaire trông đầy hứa hẹn, và thực sự là điều gì đó (không thể tìm ra điều gì) đang đặt nó thành 1 cho tôi. Nhưng tôi đặt nó bằng 0 bằng cách sử dụng tệp ~/.perldb và sự cố vẫn tiếp diễn. Trong thực tế, tôi đặt tất cả ba của các thiết lập liên quan đến 0. ~/.perldb tập tin của tôi:

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

Tôi khẳng định rằng các thiết lập có hiệu lực bằng cách chạy lệnh o trong trình gỡ lỗi. Tôi thấy tất cả chúng được đặt thành 0 khi tôi chạy perl -de 0 và cũng có thể khi chạy tệp somefile.pl thực tế.


Cảm ơn, brian. Tôi đã sử dụng perlbug để gửi lỗi (RT 60890) và tôi đã bắt đầu rắc local $SIG{'__DIE__'} vào tất cả các vị trí thích hợp trong mã của tôi. (Tôi cũng lưu ý trong các lỗi mà perldoc perldebug vẫn dường như ngụ ý rằng mặc định dieLevel là 0.)

Trả lời

14

Đây là một vấn đề với perl5db.pl tạo các trình xử lý __DIE__. Nếu tôi bản địa hóa $SIG{__DIE__} trong số eval của bạn, mọi thứ hoạt động như bạn mong đợi.

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

Nếu bạn không làm điều đó, bạn sẽ nhận được trình xử lý từ DB :: dbdie, sử dụng Carp :: longmess. Điều đó không nên xảy ra nếu dieLevel là 0, nhưng theo mặc định nó là 1, và nó được đặt thành 1 nếu nó không được xác định. Đây là một bản vá để perl5db.pl trở lại vào năm 2001, và trước đó mặc định đã 0.

Bạn đang nghĩ để tắt chức năng này với:

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

Nhưng vẫn có một tài liệu tham khảo mã trong $SIG{__DIE__} sau đó, và nó là một tham chiếu đến dbdie. Tôi nghĩ rằng đây là một lỗi trong việc xử lý các biến toàn cầu $prevdie trong perl5db.pl của dieLevel. Vào cuối chương trình con đó, có:

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

Nhưng chú ý rằng sau khi khôi phục $SIG{__DIE__}, nó giữ giá trị trước đó trong $prevdie, có nghĩa là bất cứ thứ gì trong đó rò rỉ để cuộc gọi khác. Khi tôi chạy dòng lệnh đó, có hai lệnh gọi dieLevel trước khi nó xử lý PERLDB_OPT, vì vậy $prevdie có thể là bẩn.

Vì vậy, đó là như xa như tôi có trước khi tôi không muốn nghĩ về perl5db.pl nữa.

+1

Bạn là một người dũng cảm hơn tôi, brian. Mỗi lần tôi suy nghĩ về poking xung quanh trong perl5db tôi nhận được để các ý kiến ​​về những gì một rối rối nó là như mất động lực của tôi. –

3

Có thể bạn có một tập tin RC hoặc biến môi trường (PERLDB_OPTS) được sửa đổi dieLevel tùy chọn của chương trình gỡ rối?Cá nhân tôi đã không sử dụng dieLevel nhưng dường như khi nó được đặt thành một giá trị lớn hơn không, nó có thể buộc stack unwinding và "có xu hướng vô vọng phá hủy bất kỳ chương trình nào xử lý ngoại lệ nghiêm túc." (Quote from here).

+0

Không có env vars với PERL trong chúng được thiết lập, nhưng có vẻ như dieLevel của tôi thực sự được đặt thành 1! Điều gì có thể làm điều đó? –

+0

Hmm, tệp rc nằm trong ./.perldb hoặc ~/.perldb trên các hệ thống Unix, tôi nghĩ OS X có thể sẽ sử dụng cùng một tệp. Theo như tài liệu nói, tùy chọn phải được đặt ở đó nếu nó không nằm trên dòng lệnh hoặc trong env. Có lẽ bạn có thể thử thiết lập rõ ràng dieLevel về số không? –

5

Tôi coi đó là lỗi bất kỳ mã thời gian nào hoạt động khác nhau trong trình gỡ lỗi.

Sự cố của bạn có thể có liên quan đến điều này: Debugger corrupts symbol table munging. Về cơ bản, trình gỡ lỗi xuất hiện để chơi một số thủ thuật với local - có lẽ là một phần của những thứ sandboxing để cung cấp tương tác. Rõ ràng, rối tung với bảng biểu tượng có thể có những tác dụng phụ không mong muốn. Tôi đoán rằng trình gỡ lỗi đang bản địa hoá [email protected] và do đó làm mờ đối tượng của bạn. Tôi không thể nghĩ về một công việc xung quanh.

+0

Bạn có nghĩa là bạn coi nó là một lỗi trong trình gỡ rối? –

Các vấn đề liên quan