Closed p5pRT closed 11 years ago
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.
%lu\n", 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: STATUS_ALL_SUCCESS; @@ -5246\,6 +5255\,15 @@ STATUS_POSIX_SET(255); } #endif + 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(); + } my_exit_jump(); }
On Fri Mar 21 15:51:56 2008\, jgmyers@proofpoint.com wrote:
This is a bug report for perl from jgmyers@pong.us.proofpoint.com\, 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.
Hello\,
Did you also try with overriding the built-in exit function?
#!/usr/bin/perl -l BEGIN { *CORE::GLOBAL::exit = sub { my $i=0; while (my @z = caller($i++)) { print "$i: @z"; } CORE::exit(@_); } }
sub s1 { s2(); } sub s2 { s3(); }; sub s3 { exit(); }
s1(); __END__ 1: main /tmp/52000.pl 13 main::__ANON__ 1 0 2: main /tmp/52000.pl 12 main::s3 1 0 3: main /tmp/52000.pl 11 main::s2 1 0 4: main /tmp/52000.pl 15 main::s1 1 0
This (of course) won't stop someone from exiting by calling CORE::exit.
Kind regards\,
Bram
The RT System itself - Status changed from 'new' to 'open'
Did you also try with overriding the built-in exit function?
I had not tried that. Most exit calls I'm seeing\, however\, are malloc failures and I doubt overriding CORE::GLOBAL::exit will help with that.
On Sat Apr 26 09:34:32 2008\, jgmyers@proofpoint.com wrote:
Did you also try with overriding the built-in exit function?
I had not tried that. Most exit calls I'm seeing\, however\, are malloc failures and I doubt overriding CORE::GLOBAL::exit will help with that.
Have you had any success with the problems described in the original post to this ticket?
Thank you very much. Jim Keenan
On 3/30/2012 4:52 PM\, James E Keenan via RT wrote:
Have you had any success with the problems described in the original post to this ticket?
I don't understand the question. The patch I submitted\, plus a fix to the PERL_EXIT_EXPECTED semantics\, are what I use to cause our server to report and fail safe upon a Perl exit().
On Fri Mar 21 15:51:56 2008\, jgmyers wrote:
This is a bug report for perl from jgmyers@pong.us.proofpoint.com\, generated with the help of perlbug 1.35 running under perl v5.8.8.
----------------------------------------------------------------- [Please enter your report here]
Can someone who understands the exit flags comment on this patch?
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 %lu\n"\, 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: STATUS_ALL_SUCCESS; @@ -5246\,6 +5255\,15 @@ STATUS_POSIX_SET(255); } #endif + 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(); + } my_exit_jump(); }
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
#ifndef MEMBER_TO_FPTR # define MEMBER_TO_FPTR(name) name
--
Father Chrysostomos
On Fri Mar 21 15:51:56 2008\, jgmyers wrote:
This is a bug report for perl from jgmyers@pong.us.proofpoint.com\, generated with the help of perlbug 1.35 running under perl v5.8.8.
----------------------------------------------------------------- [Please enter your report here]
Can someone who understands the exit flags comment on this patch?
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 %lu\n"\, 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: STATUS_ALL_SUCCESS; @@ -5246\,6 +5255\,15 @@ STATUS_POSIX_SET(255); } #endif + 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(); + } my_exit_jump(); }
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
#ifndef MEMBER_TO_FPTR # define MEMBER_TO_FPTR(name) name
--
Father Chrysostomos
On Wed May 23 14:46:19 2012\, sprout wrote:
On Fri Mar 21 15:51:56 2008\, jgmyers wrote:
This is a bug report for perl from jgmyers@pong.us.proofpoint.com\, generated with the help of perlbug 1.35 running under perl v5.8.8.
----------------------------------------------------------------- [Please enter your report here]
Can someone who understands the exit flags comment on this patch?
I think I understand the purpose of the patch\, and the use of PL_exit_flags fits with it's name at least.
The OP mentioned another ticket about PERL_EXIT_UNEXPECTED but I don't see another ticket by the same email that appears to concern that.
Unfortunately perl has changed enough that the patch no longer applies.
At this point I'm inclined to close the ticket\, if a new patch is supplied with the same purpose\, and preferably with some documentation and tests\, I may apply a bit more promptly than this ticket was responded to.
Tony
On Sun Jun 30 22:32:48 2013\, tonyc wrote:
Unfortunately perl has changed enough that the patch no longer applies.
It hasn't changed that much in this area. It was trivial to update the patch\, which is attached.
I've added comments and a test case per request.
On Sun Jun 30 22:32:48 2013\, tonyc wrote:
The OP mentioned another ticket about PERL_EXIT_UNEXPECTED but I don't see another ticket by the same email that appears to concern that.
I was waiting for this ticket to be acted on before spending the effort reporting the bug that is PERL_EXIT_UNEXPECTED. A wise conservation of my time that turns out to have been.
On Mon Jul 15 13:34:01 2013\, jgmyers wrote:
On Sun Jun 30 22:32:48 2013\, tonyc wrote:
Unfortunately perl has changed enough that the patch no longer applies.
It hasn't changed that much in this area. It was trivial to update the patch\, which is attached.
I've added comments and a test case per request.
Thanks\, applied as 6136213b81ecb05d74939be5083ddfdc96aef566.
I've also added the warnings to pod/perldiag.pod.
Tony
@tonycoz - Status changed from 'open' to 'resolved'
Migrated from rt.perl.org#52000 (status was 'resolved')
Searchable as RT52000$