Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

[WORKAROUND] Re^4: Setting signal handlers considered unsafe?

by gnosek (Sexton)
on Nov 07, 2008 at 17:53 UTC ( [id://722263]=note: print w/replies, xml ) Need Help??


in reply to Re^3: Setting signal handlers considered unsafe?
in thread Setting signal handlers considered unsafe?

eventually Perl left eval state, with the die handler still set.

Isn't that a rather serious bug in perl (famous last words)? Looking at the code there is no place where a handler capable of dying is possibly called outside eval.

Could a signal get caught while perl was inside the eval block, a Perl-level handler stored somewhere and its execution resumed after the current opcode "exit eval block" finished? But at the ending brace of the eval block the handler should have already been reset. So (blissfully ignorant of perlguts) I'd guess that signals may be delivered to Perl more than one opcode after delivery to perl (yay, I used them both in a single sentence). If the two opcodes interact with the signal delivery process, Bad Things (tm) happen.

Newsflash! Adding a sleep $anything_above_1us (and use Time::HiRes qw( sleep ) of course) between resetting the handlers and the closing brace makes the test pass quite repeatably, at least for me. Sleeping for 1e-6 seconds does not do anything, sleeping for 1.00001e-6 passes the test. Probably has something to do with populating a struct timeval with 1us resolution somewhere.

The difference between two calls clearly shows that Time::HiRes::sleep rounds its argument to microsecond precision and any non-zero value prevents the bug from appearing.

$ strace -e nanosleep perl -MTime::HiRes=sleep -le 'sleep 1.e-6' nanosleep({0, 0}, NULL) = 0 Process 12719 detached $ strace -e nanosleep perl -MTime::HiRes=sleep -le 'sleep 1.01e-6' nanosleep({0, 1000}, NULL) = 0 Process 12721 detached

Replies are listed 'Best First'.
Re: [WORKAROUND] Re^4: Setting signal handlers considered unsafe?
by gone2015 (Deacon) on Nov 07, 2008 at 21:47 UTC

    Isn't that a rather serious bug in perl (famous last words)? Looking at the code there is no place where a handler capable of dying is possibly called outside eval.

    Could a signal get caught while perl was inside the eval block, a Perl-level handler stored somewhere and its execution resumed after the current opcode "exit eval block" finished? But at the ending brace of the eval block the handler should have already been reset.

    The problem is that "at the ending brace of the eval block" the handler is not reset.

    For that to be the case, it would be necessary to localise the $SIG{ALRM}. But as has been discovered, the serious bug is that the localisation temporarily sets the DEFAULT -- which is horrible.

    Anyway, reverting to the empirical approach: to show that the handler set in the eval block remains set after the handler dies and terminates the eval, I modified your test as shown below. The results I got are:

    +++ parent entering wrap_sigs loop
    $SIG{ALRM}=outr_alrm enter wrap_alrm
    $SIG{ALRM}=outr_alrm exit  wrap_alrm (0) $outr=0; $rcvd=0; $dies=0; $wrap=0
    $SIG{ALRM}=outr_alrm after sleep         $outr=0; $rcvd=0; $dies=0; $wrap=0
    $SIG{ALRM}=outr_alrm enter wrap_alrm
    $SIG{ALRM}=outr_alrm exit  wrap_alrm (0) $outr=0; $rcvd=0; $dies=0; $wrap=0
    $SIG{ALRM}=outr_alrm after sleep         $outr=0; $rcvd=0; $dies=0; $wrap=0
    $SIG{ALRM}=outr_alrm enter wrap_alrm
    $SIG{ALRM}=outr_alrm exit  wrap_alrm (0) $outr=0; $rcvd=0; $dies=0; $wrap=0
    +++ child starting signal storm
    $SIG{ALRM}=outr_alrm after sleep         $outr=1; $rcvd=0; $dies=0; $wrap=0
    $SIG{ALRM}=outr_alrm enter wrap_alrm
    $SIG{ALRM}=wrap_alrm exit  wrap_alrm (1) $outr=1; $rcvd=1; $dies=1; $wrap=0
    $SIG{ALRM}=wrap_alrm after sleep         $outr=1; $rcvd=2; $dies=1; $wrap=1
    $SIG{ALRM}=wrap_alrm enter wrap_alrm
    $SIG{ALRM}=wrap_alrm exit  wrap_alrm (1) $outr=1; $rcvd=3; $dies=2; $wrap=1
    $SIG{ALRM}=wrap_alrm after sleep         $outr=1; $rcvd=4; $dies=2; $wrap=2
    $SIG{ALRM}=wrap_alrm enter wrap_alrm
    $SIG{ALRM}=wrap_alrm exit  wrap_alrm (1) $outr=1; $rcvd=5; $dies=3; $wrap=2
    $SIG{ALRM}=wrap_alrm after sleep         $outr=1; $rcvd=6; $dies=3; $wrap=3
    $SIG{ALRM}=wrap_alrm enter wrap_alrm
    $SIG{ALRM}=wrap_alrm exit  wrap_alrm (1) $outr=1; $rcvd=7; $dies=4; $wrap=3
    $SIG{ALRM}=wrap_alrm after sleep         $outr=1; $rcvd=8; $dies=4; $wrap=4
    
    this shows:
    • to start with the ALRM is set to the "outr_alrm" subroutine, which simply counts up the $outr counter.
    • before the child process starts sending ALRMs the eval in the "wrap_alrm" subroutine sets it's own ALRM signal handler, sleeps for a bit, and the restores the "outr_alrm" handler. The output above shows that before and after the call to "wrap_alrm", $SIG{ALRM} is set to the "outr_alrm".
    • when the child process starts sendin ALRMs it first catches the parent sleeping outside the "wrap_alrm" subroutine -- so we see the $outr signal counter steps by one.
    • then the parent process loops round and enters "wrap alrm", and in the eval sets its own handler. This promptly collects a signal, which counts up $rcvd and since it is in the eval, counts up $dies and dies. This terminates the eval, which skips the restoration of the "outr_alrm" handler.
    • so, on exit from "wrap_alrm" when its handler has died, we can see that its handler is still in place.
    • so, the sleep that follows is interrupted by a further ALRM, which while outside the eval counts up $wrap (and does not die).
    • and the process continues, with the "wrap_alrm" handler in place...
    I hope this is reasonably clear !

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://722263]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having a coffee break in the Monastery: (4)
As of 2024-04-25 07:54 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found