develooper Front page | perl.perl5.porters | Postings from September 2006

[perl #40390] [SEGFAULT] %SIG isn't cleared during perl_shutdown()

From:
gozer @ activestate . com
Date:
September 22, 2006 01:48
Subject:
[perl #40390] [SEGFAULT] %SIG isn't cleared during perl_shutdown()
Message ID:
rt-3.5.HEAD-31251-1158872397-1848.40390-75-0@perl.org
# New Ticket Created by  gozer@activestate.com 
# Please include the string:  [perl #40390]
# in the subject line of all future correspondence about this issue. 
# <URL: http://rt.perl.org/rt3/Ticket/Display.html?id=40390 >



This is a bug report for perl from gozer@activestate.com,
generated with the help of perlbug 1.35 running under perl 5.9.4.


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

During perl_shutdown, Perl signal handlers are still registered, and are not
correctly unset. This can lead to a segfault if a signal is recieved during
perl_shutdown() and after PL_psig_pend has been freed.

The way I assume this should work is that during perl_destruct():

- PL_defstash is destroyed
  - %SIG (in PL_defstash) is found and cleared
    - Eash entry in %SIG unsets the underlying sig handler when destroyed

And this would be correct. However, PL_defstash isn't currently correctly
refcounted and ends up never being destroyed (see my previous bug #40389).

Even then, if %SIG was cleared, the hash would be itself destroyed, but the
various entries it contains are not directly cleared, even though they have
magic associated with them. This means that Perl_magic_clearsig isn't being
called on the various enabled %SIG handlers, leaving them enabled during
perl_shutdown() leading to the segfault below.

I've patched perl.c with this simple patch to make the time window bigger
and ease reproductibility:

--- current/perl.c      2006-07-13 07:06:23.000000000 -0700
+++ current/perl.c.mine 2006-09-21 11:25:45.000000000 -0700
@@ -1256,6 +1256,9 @@
     PL_bitcount = NULL;
     Safefree(PL_psig_pend);
     PL_psig_pend = (int*)NULL;
+
+    if (getenv("PSIG_PEND_SLEEP")) { sleep(10); }
+
     PL_formfeed = NULL;
     nuke_stacks();
     PL_tainting = FALSE;

$> cat test.pl
#!/usr/bin/env perl

$SIG{CHLD} = sub { warn "[$$] SIG CHLD recieved\n"  };

my $a = a->new;

package a;

sub new {
  my $class = shift;
  my $self = bless { id => $$ }, $class;
  foreach my $i (1..5) {
      if (my $pid = fork()) {
           $self->{chld}{$i} = $pid;
      }
      else {
          sleep(1);
          exit;
      }
  }
  return $self;
}

sub DESTROY {
   my $self = shift;
   if ($self->{id} == $$) {
     foreach my $pid (values %{$self->{chld}}) {
         kill TERM => $pid;
     }
   }
}
     
$> perl test.pl

#0  0x003f9474 in S_raise_signal (my_perl=0x8254008, sig=17) at mg.c:1283
1283        PL_psig_pend[sig]++;
(gdb) bt
#0  0x003f9474 in S_raise_signal (my_perl=0x8254008, sig=17) at mg.c:1283
#1  0x003f94f6 in Perl_csighandler (sig=17) at mg.c:1327
#2  <signal handler called>
#3  0x003e620d in Perl_safesysfree (where=0x82651b8) at util.c:242
#4  0x004067a1 in Perl_reentrant_free (my_perl=0x8254008) at reentr.c:281
#5  0x0041a0a0 in perl_destruct (my_perl=0x8254008) at perl.c:1269
#6  0x08048ba0 in main (argc=2, argv=0xbfdf78e4, env=0xbfdf78f0) at perlmain.c:115

Of course, this is can be avoided if the Perl code in DESTROY either cleared $SIG{CHLD}
or used waitpid() to wait for it's children, but it illustrates the bug in a fairly 
reproductible way.

I've managed to plug this problem by modifying perl_destruct to retrieve %SIG from PL_defstash,
iterate over the keys, and hv_delete() them manually early on. It does fix the problem, but I
still believe the correct fix is to make sure %SIG is correctly destroyed early in the perl_destruct()
code.

[Please do not change anything below this line]
-----------------------------------------------------------------
---
Flags:
    category=core
    severity=high
---
Site configuration information for perl 5.9.4:

Configured by gozer at Thu Sep 21 13:27:41 PDT 2006.

Summary of my perl5 (revision 5 version 9 subversion 4 patch 28880) configuration:
  Platform:
    osname=linux, osvers=2.6.17-1.2174_fc5smp, archname=i686-linux-thread-multi
    uname='linux coupler.activestate.com 2.6.17-1.2174_fc5smp #1 smp tue aug 8 16:00:39 edt 2006 i686 i686 i386 gnulinux '
    config_args='-des -Dusedevel -Duseshrplib -Dusethreads -Duseithreads -Doptimize=-g -Dprefix=/home/gozer/opt/perl/i386-linux/current/debug/28880'
    hint=recommended, useposix=true, d_sigaction=define
    useithreads=define, usemultiplicity=define
    useperlio=define, d_sfio=undef, uselargefiles=define, usesocks=undef
    use64bitint=undef, use64bitall=undef, uselongdouble=undef
    usemymalloc=n, bincompat5005=undef
  Compiler:
    cc='cc', ccflags ='-D_REENTRANT -D_GNU_SOURCE -DTHREADS_HAVE_PIDS -DDEBUGGING -fno-strict-aliasing -pipe -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I/usr/include/gdbm',
    optimize='-g',
    cppflags='-D_REENTRANT -D_GNU_SOURCE -DTHREADS_HAVE_PIDS -DDEBUGGING -fno-strict-aliasing -pipe -I/usr/local/include -I/usr/include/gdbm'
    ccversion='', gccversion='4.1.1 20060525 (Red Hat 4.1.1-1)', 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 =' -L/usr/local/lib'
    libpth=/usr/local/lib /lib /usr/lib
    libs=-lnsl -lgdbm -ldb -ldl -lm -lcrypt -lutil -lpthread -lc
    perllibs=-lnsl -ldl -lm -lcrypt -lutil -lpthread -lc
    libc=/lib/libc-2.4.so, so=so, useshrplib=true, libperl=libperl.so
    gnulibc_version='2.4'
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E -Wl,-rpath,/home/gozer/opt/perl/i386-linux/current/debug/28880/lib/5.9.4/i686-linux-thread-multi/CORE'
    cccdlflags='-fpic', lddlflags='-shared -L/usr/local/lib'

Locally applied patches:
    

---
@INC for perl 5.9.4:
    /home/gozer/opt/lib/perl5
    /home/gozer/opt/lib/perl5/site_perl
    /home/gozer/opt/perl_lib/lib
    /home/gozer/opt/perl/i386-linux/current/debug/28880/lib/5.9.4/i686-linux-thread-multi
    /home/gozer/opt/perl/i386-linux/current/debug/28880/lib/5.9.4
    /home/gozer/opt/perl/i386-linux/current/debug/28880/lib/site_perl/5.9.4/i686-linux-thread-multi
    /home/gozer/opt/perl/i386-linux/current/debug/28880/lib/site_perl/5.9.4
    .

---
Environment for perl 5.9.4:
    HOME=/home/gozer
    LANG=en_US.UTF-8
    LANGUAGE (unset)
    LD_LIBRARY_PATH=/home/gozer/opt/lib
    LOGDIR (unset)
    PATH=/home/gozer/bin:/home/gozer/opt/bin:/home/gozer/bin:/home/gozer/opt/bin:/usr/lib/qt-3.3/bin:/usr/kerberos/bin:/usr/lib/ccache:/usr/local/bin:/usr/bin:/bin:/usr/X11R6/bin:/usr/lib/jre/bin:/home/gozer/bin:/home/gozer/opt/activestate.com/komodo/current/bin:/usr/lib/jre/bin:/home/gozer/bin:/home/gozer/opt/activestate.com/komodo/current/bin
    PERL5LIB=/home/gozer/opt/lib/perl5:/home/gozer/opt/lib/perl5/site_perl:/home/gozer/opt/perl_lib/lib
    PERL5_CPANPLUS_CONFIG=/home/gozer/.cpanplus/config
    PERL_BADLANG (unset)
    SHELL=/bin/bash




nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About