http://www.perlmonks.org?node_id=1155447

Darkwing has asked for the wisdom of the Perl Monks concerning the following question:

Hi, i had the problem that the contents of $@ produced by a failed eval{...} looked wired. It turned out that this was caused by a module that set the $SIG{__DIE__} handler. I then tried this:

use strict; use warnings; # Just to demonstrate the problem: $SIG{__DIE__} = sub {die "[Unwanted stuff] @_"}; eval { local %SIG; die("Something is wrong!\n"); }; print "Got: $@\n";

But i got: Got: [Unwanted stuff]  Something is wrong!. Obviously, the handler is still active inside the eval{...}. Looking at perlmonks i found this http://www.perlmonks.org/?node_id=51097 and changed my code to:

use strict; use warnings; # Just to demonstrate the problem: $SIG{__DIE__} = sub {die "[Unwanted stuff] @_"}; eval { local $SIG{__DIE__}; # No sigdie handler die("Something is wrong!\n"); }; print "Got: $@\n";

Now the output is Got: Something is wrong!, meaning that the handler is switched off, which is the desired result.

But i still do not understand why my fist approach didn't work. Why does local %SIG; not turn off the handler? I expected this to just turn off all handlers. Why do i need to write local $SIG{__DIE__};? Can anybody explain this?

Replies are listed 'Best First'.
Re: Localizing %SIG
by shmem (Chancellor) on Feb 17, 2016 at 12:33 UTC
    I expected this to just turn off all handlers. Why do i need to write local $SIG{__DIE__};? Can anybody explain this?

    Localizing a hash just creates an empty alias, with no key whatsoever. With local $SIG{__DIE__} you explicitly set the __DIE__ handler to undef, so for this context, you get back the default behavior of die, and die is done, signal processed. If you just localize %SIG, the __DIE__ handler of the surrounding context is still in place, since the __DIE__ signal isn't handled by the current localized %SIG (there is no __DIE__ key in %SIG) - so it is passed up and hits the handler installed before the localization. Does that make sense to you?

    Update: the question from the previous paragraph just indicates that the explanation is poor, i.e. uncomplete. Further then:

    Localizing a hash just creates an empty alias, with no key whatsoever. The processing of a signal via a custom handler is dependent on the presence of the signal name as key in the hash %SIG.

    If you say local $SIG{__DIE__}, you just alias the value of the slot __DIE__ of the %SIG currently in place. If you localize the entire %SIG without further ado, this has no effect whatsoever, since it has no keys. Aliasing doesn't create keys! So, if you write something like

    $SIG{__DIE__}= sub {print "fubar!\n"}; eval { local %SIG; local $SIG{__DIE__}; $a/$b }; print $@;

    you will see

    fubar! Illegal division by zero at - line 5.

    since the subsequent aliasing of an undefined value in the already localized hash %SIG doesn't create the key __DIE__ in %SIG.

    perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'

      That makes perfect sense - but where is that behavior documented? It doesn't seem to be mentioned in %SIG or the Camel at least...

        "... where is that behavior documented?"

        The "Illegal division by zero" example is documented in eval. This has additional information about $SIG{__DIE__}.

        die also has information about $SIG{__DIE__}.

        More general information related to this topic can be found in local, perlsub, perlipc and, as already noted, perlvar.

        — Ken

Re: Localizing %SIG
by LanX (Saint) on Feb 17, 2016 at 14:14 UTC
    I'd recommend to treat %SIG as magic and not to expect local %SIG to have useful effects

    perlvar says

    > Due to an implementation glitch, the $SIG{__DIE__} hook is called even inside an "eval()".

    this is a strong hint that the implementation doesn't always resolve %SIG like with normal variables ( well, that's why it's called a "special variable" anyway)

    local %SIG looks wrong anyway since you are disabling all default settings of a running system

    DB<100> \%SIG => do { my $a = { __DIE__ => sub { ... }, __WARN__ => sub { ... }, ABRT => undef, ALRM => undef, BUS => sub { ... }, CHLD => undef, CLD => undef, CONT => undef, FPE => "IGNORE", HUP => undef, ILL => undef, INT => sub { ... }, IO => undef, IOT => undef, KILL => undef, NUM32 => undef, NUM33 => undef, NUM35 => undef, NUM36 => undef, NUM37 => undef, NUM38 => undef, NUM39 => undef, NUM40 => undef, NUM41 => undef, NUM42 => undef, NUM43 => undef, NUM44 => undef, NUM45 => undef, NUM46 => undef, NUM47 => undef, NUM48 => undef, NUM49 => undef, NUM50 => undef, NUM51 => undef, NUM52 => undef, NUM53 => undef, NUM54 => undef, NUM55 => undef, NUM56 => undef, NUM57 => undef, NUM58 => undef, NUM59 => undef, NUM60 => undef, NUM61 => undef, NUM62 => undef, NUM63 => undef, PIPE => undef, POLL => undef, PROF => undef, PWR => undef, QUIT => undef, RTMAX => undef, RTMIN => undef, SEGV => 'fix', STKFLT => undef, STOP => undef, SYS => undef, TERM => undef, TRAP => undef, TSTP => undef, TTIN => undef, TTOU => undef, UNUSED => undef, URG => undef, USR1 => undef, USR2 => undef, VTALRM => undef, WINCH => undef, XCPU => undef, XFSZ => undef, }; $a->{SEGV} = $a->{BUS}; $a; }

    Cheers Rolf
    (addicted to the Perl Programming Language and ☆☆☆☆ :)
    Je suis Charlie!

Re: Localizing %SIG
by Anonymous Monk on Feb 17, 2016 at 12:24 UTC