base (< 2.14) が $SIG{__DIE__} を破壊するのではまった
たとえば,
#!/usr/bin/perl use strict; use warnings; local $SIG{__DIE__} = sub { warn "signal handled"; die $_[0]; }; require Foo; die "foo";
こんなスクリプトがあったとして,実行すると,
signal handled at test.pl line 7. foo at test.pl line 12.
みたいになる(それなりの package Foo があったとして)。
ところが,その package Foo の中身が
package Foo; use strict; use warnings; use base qw( URI ); # なんでもよい
のようになっていた場合。つまり,(パッケージ指定の)use base
を使っているときに,実行すると,
foo at test.pl line 12.
みたくなって,__DIE__
シグナルハンドラが呼ばれない。
なんでーと思ったら,RT にも登録されてた。1年も前だけど。⇒ Bug #30375 for base: base.pm doesn't honor already installed $SIG{__DIE__} handlers
これ,base
(ただし 2.14 未満)のコードが下記のようになってるからっぽい。
my $sigdie; { local $SIG{__DIE__}; eval "require $base"; # Only ignore "Can't locate" errors from our eval require. # Other fatal errors (syntax etc) must be reported. die if $@ && $@ !~ /^Can't locate .*? at \(eval /; # ...... snip snip snip ...... $sigdie = $SIG{__DIE__}; } # Make sure a global $SIG{__DIE__} makes it out of the localization. $SIG{__DIE__} = $sigdie if defined $sigdie;
素人目には,スコープくぎって $SIG{__DIE__}
を localization してるから,わざわざ設定しなおす必要ないじゃんとか思うんだけど,それなりに理由があるのかな?
んで,どうも Perl 5.10 未満だと,local $SIG{__DIE__};
で(値を設定せずに) localization しても $SIG{__DIE__}
は defined となってしまうみたい。普通の local
なら,ちゃんと undef になるんですけどね。
さっき 2.14 未満だと,って書いたとおり,実は base 2.14 で fixed されてる。(Perl 5.10 だと露呈しなかったのかな?)
2.14 - fix problem with SIGDIE on perls < 5.10http://search.cpan.org/src/RGARCIA/base-2.14/Changes
該当部分が下記のように修正されてる。
$sigdie = $SIG{__DIE__} || undef;
ここだけ違う。それでも Perl のスコープ& local
による localization に頼らないのは,やっぱりなんらかの理由があるんでしょうね。
以下おまけ。
当初 base-2.14 に気づいてなかったので,それを fix するモジュールを書いてた。
package base::fix; use strict; use warnings; use base; BEGIN { my $original = \&{'base::import'}; my $sub = sub { { local $SIG{__DIE__} = $SIG{__DIE__} if defined $SIG{__DIE__}; local $Carp::CarpLevel = $Carp::CarpLevel + 1; return &$original(@_); } }; no strict 'refs'; no warnings 'redefine'; *{'base::import'} = $sub; } 1;
ほんとは goto
で飛ばせればもっとスマートに書けるんだけど,goto
使うと local
による localization が働かなくなるんですね。うーむ。
あとこんなパッチあてしなくても,parent 使えばいいのかな?このモジュールの立ち位置がよくわからんです。