develooper Front page | perl.perl5.porters | Postings from March 2008

[perl #52000] Warn/abort on attempted perl exit

John Gardiner Myers
March 21, 2008 18:49
[perl #52000] Warn/abort on attempted perl exit
Message ID:
# New Ticket Created by  John Gardiner Myers 
# Please include the string:  [perl #52000]
# 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.35 running under perl v5.8.8.

[Please enter your report here]

I have a multithreaded C++ server which embeds Perl and has a handful
of PerlInterpreter objects.  One of the problems is that occasionally
Perl or some CPAN module will attempt to exit.  In a multithreaded
process, calling exit() results in bad behavior--the thread will run
all of the static destructors and atexit handlers and then terminate,
leaving the remaining threads running, using the already-destructed
and/or freed static data.  The process will usually dump core some
time later, possibly after having corrupted persistent data.

Clearing the PERL_EXIT_EXPECTED bit doesn't quite work right, for
reasons which I'll mention in a separate bug.  One of the main
problems with it is that perl unwinds the stack a bit before even
testing for PERL_EXIT_EXPECTED, so there is no way I can find out
where in all that perl code the exit came from.

Below is a patch that adds a PERL_EXIT_WARN feature for embedders.
This allows one to obtain, through a __WARN__ handler, a perl stack
trace pointing to the code that attempted to exit.

Also is a PERL_EXIT_ABORT feature primarily intended to prevent
infinite recursion through the PERL_EXIT_WARN feature.  It is also
useful separately to allow a clean abort of the process instead of
attempting to unwind the stack.

diff -u perl-5.8.8-1utf8valid/perl.c perl-5.8.8-2xexitwarn/perl.c
--- perl-5.8.8-1utf8valid/perl.c        2007-06-20 09:46:57.000000000 -0700
+++ perl-5.8.8-2xexitwarn/perl.c        2008-03-21 14:32:10.000000000 -0700
@@ -5206,6 +5206,15 @@
     DEBUG_S(PerlIO_printf(Perl_debug_log, "my_exit: thread %p, status 
                          thr, (unsigned long) status));
+    if (PL_exit_flags & PERL_EXIT_WARN) {
+       U8 orig_exit_flags = PL_exit_flags;
+       PL_exit_flags = (PL_exit_flags | PERL_EXIT_ABORT) & 
~PERL_EXIT_WARN; /* Protect against reentrant calls */
+       Perl_warn(aTHX_ "Unexpected exit %u", status);
+       PL_exit_flags = orig_exit_flags;
+    }
+    if (PL_exit_flags & PERL_EXIT_ABORT) {
+       abort();
+    }
     switch (status) {
     case 0:
@@ -5246,6 +5255,15 @@
+    if (PL_exit_flags & PERL_EXIT_WARN) {
+       U8 orig_exit_flags = PL_exit_flags;
+       PL_exit_flags = (PL_exit_flags | PERL_EXIT_ABORT) & 
~PERL_EXIT_WARN; /* Protect against reentrant calls */
+       Perl_warn(aTHX_ "Unexpected exit failure %u", PL_statusvalue);
+       PL_exit_flags = orig_exit_flags;
+    }
+    if (PL_exit_flags & PERL_EXIT_ABORT) {
+       abort();
+    }

diff -u perl-5.8.8-1utf8valid/perl.h perl-5.8.8-2xexitwarn/perl.h
--- perl-5.8.8-1utf8valid/perl.h        2007-06-20 09:46:51.000000000 -0700
+++ perl-5.8.8-2xexitwarn/perl.h        2008-03-21 14:06:48.000000000 -0700
@@ -2491,6 +2491,8 @@
 /* flags in PL_exit_flags for nature of exit() */
 #define PERL_EXIT_EXPECTED     0x01
 #define PERL_EXIT_DESTRUCT_END  0x02  /* Run END in perl_destruct */
+#define PERL_EXIT_WARN         0x04
+#define PERL_EXIT_ABORT                0x08

 #  define MEMBER_TO_FPTR(name)         name

[Please do not change anything below this line]
This perlbug was built using Perl v5.8.8 - Fri Mar 21 14:19:48 PDT 2008
It is being executed now by  Perl v5.8.8 - Tue Feb 13 10:14:49 PST 2007.

Site configuration information for perl v5.8.8:

Configured by jgmyers at Tue Feb 13 10:14:49 PST 2007.

Summary of my perl5 (revision 5 version 8 subversion 8) configuration:
    osname=linux, osvers=2.6.9-42.0.8.elsmp, 
    uname='linux pong 2.6.9-42.0.8.elsmp #1 smp tue jan 30 12:33:47 est 
2007 i686 i686 i386 gnulinux '
    hint=recommended, useposix=true, d_sigaction=define
    usethreads=define use5005threads=undef useithreads=define 
    useperlio=define d_sfio=undef uselargefiles=define usesocks=undef
    use64bitint=undef use64bitall=undef uselongdouble=undef
    usemymalloc=n, bincompat5005=undef
    cc='gcc-4.1', ccflags ='-D_REENTRANT -D_GNU_SOURCE 
-DTHREADS_HAVE_PIDS -DDEBUGGING -fno-strict-aliasing -pipe 
-Wdeclaration-after-statement -I/usr/local/include -D_LARGEFILE_SOURCE 
-D_FILE_OFFSET_BITS=64 -I/usr/include/gdbm',
-fno-strict-aliasing -pipe -Wdeclaration-after-statement 
-I/usr/local/include -I/usr/include/gdbm'
    ccversion='', gccversion='4.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', 
    alignbytes=4, prototype=define
  Linker and Libraries:
    ld='gcc-4.1', 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/, so=so, useshrplib=false, libperl=libperl.a
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E'
    cccdlflags='-fpic', lddlflags='-shared -L/usr/local/lib'

Locally applied patches:

@INC for perl v5.8.8:

Environment for perl v5.8.8:
    LANGUAGE (unset)
    LD_LIBRARY_PATH (unset)
    LOGDIR (unset)
    PERL_BADLANG (unset)
    SHELL=/bin/bash Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at | Group listing | About