FAQ
# New Ticket Created by "Mao Morimoto"
# Please include the string: [perl #29012]
# in the subject line of all future correspondence about this issue.
# <URL: http://rt.perl.org:80/rt3/Ticket/Display.html?id=29012 >


This is a bug report for perl from morimoto@interlink.ad.jp,
generated with the help of perlbug 1.26 running under perl 5.008003.


-----------------------------------------------------------------
[Please enter your report here]

Manipulating hash in signal handler (SIGCHLD) causes "Segmentation fault".
Run following script some times. "Segmentation fault" may happen at "POINT1"
or "POINT2".

$speed = 0.001 ; # more fast more error

$SIG{CHLD} = sub {
while ( (my $pid = waitpid( -1, WNOHANG )) > 0 ) {
if ( exists $children{$pid} ) {
delete $children{$pid} ;
} else {
print "no such pid in the hash! ($pid)\n" ;
}
}
} ;

for ( my $i = 0 ; $i < 1000 ; $i++ ) {
my $pid = fork ;
if ( !defined $pid ) {
print "fork : error\n" ;
} elsif ( $pid ) {
$children{$pid} = time ;
} else {
my $delay = rand( $speed ) ;
select undef, undef, undef, $delay ;
exit 0 ;
}
while ( keys %children > 20 ) { ### SEGV here??
sleep 1 ;
}
}

1 while wait > 0 ;
foreach my $pid ( keys %children ) {
print "still living?? ($pid)\n" ;
}

[Please do not change anything below this line]
-----------------------------------------------------------------

---
This perlbug was built using Perl 5.00503 - Sun Mar 5 13:39:27 SAST 2000
It is being executed now by Perl 5.008003 - Tue Apr 6 15:46:58 JST 2004.

Site configuration information for perl 5.008003:

Configured by yneko at Tue Apr 6 15:46:58 JST 2004.

Summary of my perl5 (revision 5.0 version 8 subversion 3) configuration:
Platform:
osname=freebsd, osvers=4.9-release, archname=i386-freebsd
uname='freebsd lime.interlink.or.jp 4.9-release freebsd 4.9-release #0:
mon oct 27 17:51:09 gmt 2003
root@freebsd-stable.sentex.ca:usrobjusrsrcsysgeneric i386 '
config_args='-de'
hint=recommended, useposix=true, d_sigaction=define
usethreads=undef use5005threads=undef useithreads=undef
usemultiplicity=undef
useperlio=define d_sfio=undef uselargefiles=define usesocks=undef
use64bitint=undef use64bitall=undef uselongdouble=undef
usemymalloc=n, bincompat5005=undef
Compiler:
cc='cc', ccflags
='-DHAS_FPSETMASK -DHAS_FLOATINGPOINT_H -fno-strict-aliasing',
optimize='-O',
cppflags='-DHAS_FPSETMASK -DHAS_FLOATINGPOINT_H -fno-strict-aliasing'
ccversion='', gccversion='2.95.4 20020320 [FreeBSD]', gccosandvers=''
intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234
d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=12
ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='off_t',
lseeksize=8
alignbytes=4, prototype=define
Linker and Libraries:
ld='cc', ldflags ='-Wl,-E '
libpth=/usr/lib
libs=-lm -lcrypt -lutil -lc
perllibs=-lm -lcrypt -lutil -lc
libc=, so=so, useshrplib=false, libperl=libperl.a
gnulibc_version=''
Dynamic Linking:
dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags=' '
cccdlflags='-DPIC -fPIC', lddlflags='-shared '

Locally applied patches:


---
@INC for perl 5.008003:
/usr/local/lib/perl5/5.8.3/i386-freebsd
/usr/local/lib/perl5/5.8.3
/usr/local/lib/perl5/site_perl/5.8.3/i386-freebsd
/usr/local/lib/perl5/site_perl/5.8.3
/usr/local/lib/perl5/site_perl
.

---
Environment for perl 5.008003:
HOME=/root
LANG (unset)
LANGUAGE (unset)
LD_LIBRARY_PATH (unset)
LOGDIR (unset)

PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/games:/usr/local/sbin:/usr/local/bin
:/usr/X11R6/bin:/root/bin
PERL_BADLANG (unset)
SHELL=/bin/csh

Search Discussions

  • Dave Mitchell at May 3, 2004 at 11:24 pm

    On Wed, Apr 21, 2004 at 01:25:17AM -0000, Mao Morimoto wrote:
    Manipulating hash in signal handler (SIGCHLD) causes "Segmentation fault".
    Run following script some times. "Segmentation fault" may happen at "POINT1"
    or "POINT2".

    $speed = 0.001 ; # more fast more error

    $SIG{CHLD} = sub {
    while ( (my $pid = waitpid( -1, WNOHANG )) > 0 ) {
    if ( exists $children{$pid} ) {
    delete $children{$pid} ;
    } else {
    print "no such pid in the hash! ($pid)\n" ;
    }
    }
    } ;

    for ( my $i = 0 ; $i < 1000 ; $i++ ) {
    my $pid = fork ;
    if ( !defined $pid ) {
    print "fork : error\n" ;
    } elsif ( $pid ) {
    $children{$pid} = time ;
    } else {
    my $delay = rand( $speed ) ;
    select undef, undef, undef, $delay ;
    exit 0 ;
    }
    while ( keys %children > 20 ) { ### SEGV here??
    sleep 1 ;
    }
    }

    1 while wait > 0 ;
    foreach my $pid ( keys %children ) {
    print "still living?? ($pid)\n" ;
    }
    Thanks for the report. The problem boils down to the following:
    The code
    $children{$pid} = time ;

    gets interrupted by the signal after $children{$pid} has been pushed on
    the stack (helem has executed), but before the assignment. Then in the
    signal handler, this value is freed by the delete. On return from the
    signal handler, the assignment is done to a freed value, and badness
    follows.

    Yet another side-effect of stuff on the stack not being ref-counted.
    I can't see a way of making this safe.

    --
    "You're so sadly neglected, and often ignored.
    A poor second to Belgium, When going abroad."
    -- Monty Python - "Finland"
  • Ton Hospel at May 5, 2004 at 1:32 pm
    In article <20040503232914.GL1895@iabyn.com>,
    Dave Mitchell <davem@iabyn.com> writes:
    On Wed, Apr 21, 2004 at 01:25:17AM -0000, Mao Morimoto wrote:
    Manipulating hash in signal handler (SIGCHLD) causes "Segmentation fault".
    Thanks for the report. The problem boils down to the following:
    The code
    $children{$pid} = time ;

    gets interrupted by the signal after $children{$pid} has been pushed on
    the stack (helem has executed), but before the assignment. Then in the
    signal handler, this value is freed by the delete. On return from the
    signal handler, the assignment is done to a freed value, and badness
    follows.

    Yet another side-effect of stuff on the stack not being ref-counted.
    I can't see a way of making this safe.
    Since this is a case of "don't do that then", you can however
    work around this by detecting your child exits synchronously. This
    you can often do by leaving an open write side of a pipe in each of
    your children (one pipe per child) (see $^F if your children use exec()).
    Then in the parent use EOF on the read side as an indication of process
    death. And these you can multiplex on using poll/select. Since quite
    often you leave a communication channel to your children anyways,
    you probably can use that instead of an extra pipe.
  • Mao Morimoto at May 5, 2004 at 2:04 pm
    Thank you for your advice.
    I could correct the problem by processing child exits without using the
    signals.
    But I hope, please make signals more safe. It is really useful mechanism.

    thank you!
    - Mao Morimoto

    ----- Original Message -----
    From: "(Ton Hospel) via RT" <perlbug-followup@perl.org>
    To: <morimoto@interlink.ad.jp>
    Sent: Wednesday, May 05, 2004 10:32 PM
    Subject: Re: [perl #29012] Manipulating hash in SIGCHLD handler causes
    "Segmentation fault"

    In article <20040503232914.GL1895@iabyn.com>,
    Dave Mitchell <davem@iabyn.com> writes:
    On Wed, Apr 21, 2004 at 01:25:17AM -0000, Mao Morimoto wrote:
    Manipulating hash in signal handler (SIGCHLD) causes "Segmentation
    fault".
    Thanks for the report. The problem boils down to the following:
    The code
    $children{$pid} = time ;

    gets interrupted by the signal after $children{$pid} has been pushed on
    the stack (helem has executed), but before the assignment. Then in the
    signal handler, this value is freed by the delete. On return from the
    signal handler, the assignment is done to a freed value, and badness
    follows.

    Yet another side-effect of stuff on the stack not being ref-counted.
    I can't see a way of making this safe.
    Since this is a case of "don't do that then", you can however
    work around this by detecting your child exits synchronously. This
    you can often do by leaving an open write side of a pipe in each of
    your children (one pipe per child) (see $^F if your children use exec()).
    Then in the parent use EOF on the read side as an indication of process
    death. And these you can multiplex on using poll/select. Since quite
    often you leave a communication channel to your children anyways,
    you probably can use that instead of an extra pipe.

  • Dave Mitchell at May 5, 2004 at 8:51 pm

    On Wed, May 05, 2004 at 11:03:41PM +0900, Mao Morimoto wrote:
    Thank you for your advice.
    I could correct the problem by processing child exits without using the
    signals.
    But I hope, please make signals more safe. It is really useful mechanism.
    Well, the main difficulty here is that if the child exits quickly,
    the signal handler is trying to delete the entry in the hash before the
    main process has finished inserting that entry into the hash! It is the
    fault of perl that this causes a crash (and is hard to fix), but even
    if we fixed it, your code would still be logically wrong. What you could
    do, both to make your code 'correct' and to avoid triggering a perl crash,
    is delay the delivery of signals while the pid is being added to the
    hash. This can be done via the POSIX module (see page 418 of "Programming
    Perl" 3rd edition for more info).


    Here's a modified version of your code which does jjust that.
    Dave.


    $speed = 0.001 ; # more fast more error

    $SIG{CHLD} = sub {
    while ( (my $pid = waitpid( -1, WNOHANG )) > 0 ) {
    if ( exists $children{$pid} ) {
    delete $children{$pid} ;
    } else {
    print "no such pid in the hash! ($pid)\n" ;
    }
    }
    } ;

    {
    use POSIX qw(:signal_h);
    my $sigset = POSIX::SigSet->new;
    my $blockset = POSIX::SigSet->new(SIGCHLD);
    sub block { sigprocmask(SIG_BLOCK, $blockset, $sigset) }
    sub unblock { sigprocmask(SIG_SETMASK, $sigset) }
    }


    for ( my $i = 0 ; $i < 1000 ; $i++ ) {
    block;
    my $pid = fork ;
    if ( !defined $pid ) {
    unblock;
    print "fork : error\n" ;
    } elsif ( $pid ) {
    $children{$pid} = time ;
    unblock;
    } else {
    unblock;
    my $delay = rand( $speed ) ;
    select undef, undef, undef, $delay ;
    exit 0 ;
    }
    while ( keys %children > 20 ) { ### SEGV here??
    sleep 1 ;
    }
    }

    1 while wait > 0 ;
    foreach my $pid ( keys %children ) {
    print "still living?? ($pid)\n" ;
    }

    --
    "There's something wrong with our bloody ships today, Chatfield."
    -- Admiral Beatty at the Battle of Jutland, 31st May 1916.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupperl5-porters @
categoriesperl
postedApr 28, '04 at 11:53a
activeMay 5, '04 at 8:51p
posts5
users4
websiteperl.org

People

Translate

site design / logo © 2022 Grokbase