develooper Front page | perl.perl5.porters | Postings from December 2003

[perl #24699] Locally defined signal handlers executed outside scope of eval block

December 19, 2003 20:15
[perl #24699] Locally defined signal handlers executed outside scope of eval block
Message ID:
# New Ticket Created by 
# Please include the string:  [perl #24699]
# in the subject line of all future correspondence about this issue. 
# <URL: >

This is a bug report for perl from
generated with the help of perlbug 1.34 running under perl v5.8.2.

I have uncovered the following 'issue' (I feel it is a bug) with
Perl: Namely,
it is possible for a signal handler defined locally inside an eval
block to be
executed outside the scope of that eval block.

There appears to be a 'gap' between the end of an eval block and the
restoration of the %SIG hash to remove any signal handlers defined
inside the eval block.

>From perl581delta.pod: Perl no longer handles signals immediately but
"between opcodes" when it is safe to do so.

However, if one or more opcodes mark the end of the eval block, and
opcodes follow to restoring the %SIG hash, but a signal occurs in
between them,
then the (now defunct) signal handler defined inside the eval block
will get
executed outside of the eval block.  This appears to be what is

It is not enough to suppress signal handling between opcodes.  Perl
needs to go
further and ensure safe signal handling when the %SIG hash is
modified inside
an eval block.

In one system I have developed, I have encounted this bug in two very
scenarios.  Further, I have been able to create a Perl script that
this bug (below).

In my system, I can workaround this bug by nesting the eval block that
contains the locally defined signal handlers inside another eval
    eval {
        eval {
            local $SIG{'CHLD'} = sub { die("SIGCHLD\n"); };

            # Do work
However, this may not be a suitable for every situation.

The following code reproduces the bug:


# Test program to reproduce the following Perl bug:
#    It is possible for a signal handler defined locally inside an
#    eval blocks to be executed outside the scope of the eval block.
# Just execute this Perl script.
# It will eventually (after a few minutes) exit when the bug occurs.

use strict;
use warnings;

use Time::HiRes qw( usleep );

my $CHILD_MAX   = 25;  # Max number of children to run
my $child_count = 0;   # Count of children currently running
my $child_done  = 0;   # Flag that a child has terminated
my %child_pids;        # Holds child processes' PIDs

# Set the flag that a child has terminated
$SIG{'CHLD'} = sub { $child_done = 1; };

# Loop until the bug occurs
do {
    # Cleanup any terminated children
    if ($child_done) {
        $child_done = 0;

        # Check all child processes using non-blocking waitpid() call
        foreach my $pid (keys(%child_pids)) {
            if (waitpid($pid, 1) == $pid) {   # 1 = POSIX::WNOHANG

    # Start more children
    while ($child_count < $CHILD_MAX) {
        my $pid;
        if (($pid = fork()) == 0) {
            # Child sleeps for a random amount of time and then exits
            my $usec = 950000 + int(rand(100000));

        # Parent remembers the child's PID for later cleanup
        $child_pids{$pid} = undef;

    # Try to recreate the bug
    eval {
        eval {
            # Local signal handler to 'kill' the sleep() call below
            local $SIG{'CHLD'} = sub { die("SIGCHLD\n"); };

            sleep(1);   # Hang around a bit

        # Set the flag for cleaning up terminated child processes
        if ($@ && ($@ =~ /CHLD/)) {
            $child_done = 1;

    # Keep looping until the bug occurs
} while (! $@);

# When we get here, it shows that the signal handler
# defined inside the inner eval block above was
# executed OUTSIDE the scope of the inner eval block.

print("Bug detected: $@");


Site configuration information for perl v5.8.2:

Configured by Gerrit at Fri Nov  7 12:03:56     2003.

Summary of my perl5 (revision 5.0 version 8 subversion 2)
    osname=cygwin, osvers=1.5.5(0.9432),
    uname='cygwin_nt-5.0 troubardix 1.5.5(0.9432) 2003-09-20 16:31
i686 unknown unknown cygwin '
    config_args='-de -Dmksymlinks -Duse64bitint -Dusethreads
-Doptimize=-O2 -Dman3ext=3pm'
    hint=recommended, useposix=true, d_sigaction=define
    usethreads=define use5005threads=undef useithreads=define
    useperlio=define d_sfio=undef uselargefiles=define usesocks=undef
    use64bitint=define use64bitall=undef uselongdouble=undef
    usemymalloc=y, bincompat5005=undef
    cc='gcc', ccflags ='-DPERL_USE_SAFE_PUTENV -fno-strict-aliasing',
    cppflags='-DPERL_USE_SAFE_PUTENV -fno-strict-aliasing'
    ccversion='', gccversion='3.3.1 (cygming special)',
    intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=12345678
    d_longlong=define, longlongsize=8, d_longdbl=define,
    ivtype='long long', ivsize=8, nvtype='double', nvsize=8,
Off_t='off_t', lseeksize=8
    alignbytes=8, prototype=define
  Linker and Libraries:
    ld='ld2', ldflags =' -s -L/usr/local/lib'
    libpth=/usr/local/lib /usr/lib /lib
    libs=-lgdbm -ldb -lcrypt -lgdbm_compat
    perllibs=-lcrypt -lgdbm_compat
    libc=/usr/lib/libc.a, so=dll, useshrplib=true, libperl=libperl.a
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=dll, d_dlsymun=undef, ccdlflags=' -s'
    cccdlflags=' ', lddlflags=' -s -L/usr/local/lib'

Locally applied patches:

@INC for perl v5.8.2:

Environment for perl v5.8.2:
    LD_LIBRARY_PATH (unset)
    LOGDIR (unset)
m Files/Hummingbird/Connectivity/7.10/Accessories/:.
    PERL_BADLANG (unset)
    SHELL (unset) Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at | Group listing | About