Skip Menu |
 
Report information
Id: 30331
Status: resolved
Priority: 0/
Queue: perl5

Owner: Nobody
Requestors: xiaoke [at] cup.hp.com
Cc:
AdminCc:

Operating System: (no value)
PatchStatus: (no value)
Severity: low
Type: notabug
Perl Version: (no value)
Fixed In: (no value)



Subject: system/fork in DESTROY overrides exit code of parent program
Date: Thu, 17 Jun 2004 00:16:23 -0700 (PDT)
To: perlbug [...] perl.org
From: Xiaoke Zhang <xiaoke [...] cup.hp.com>
Download (untitled) / with headers
text/plain 3.9k
This is a bug report for perl from xiaoke@cup.hp.com, generated with the help of perlbug 1.34 running under perl v5.8.0. ----------------------------------------------------------------- Hi, It seems there is a problem with exit codes and DESTORY method of an object. I ran into a problem where a script loads a perl object and then exits 1. But $? on the command line shows the program exited with status 0. After tinkering around with this. It seems if the DESTROY method in an object uses a system or fork call, the exit code from the forked process overrides the exit code of the parent process. Here is an example: #!/usr/bin/perl -w package T; use strict; sub new { my $pkg=shift; my $self = {}; bless $self, $pkg; return $self; } sub DESTROY { my $self = shift; print "Destroying....\n"; system("date"); } 1; print "Bluh bluh bluh\n"; my $ty = T->new(); exit 3; ----- It doesn't matter what exit code is at the bottom, the script always exits with 0 according to $? # ./test.pl ; echo $? Bluh bluh bluh Destroying.... Wed Jun 16 23:59:59 PDT 2004 0 As if the exit code 0 from system("date") is overriding the "exit 3" in the main script. I don't know if this is a feature or a bug, please advise. Thanks. xiaoke(at)cup(dot)hp(dot)com ----------------------------------------------------------------- --- Flags: category=core severity=high --- This perlbug was built using Perl v5.8.0 - Wed Apr 2 21:15:30 UTC 2003 It is being executed now by Perl v5.8.0 - Wed Apr 2 21:06:22 UTC 2003. Site configuration information for perl v5.8.0: Configured by root at Wed Apr 2 21:06:22 UTC 2003. Summary of my perl5 (revision 5.0 version 8 subversion 0) configuration: Platform: osname=linux, osvers=2.4.19, archname=i586-linux-thread-multi uname='linux brooks 2.4.19 #1 thu nov 14 12:14:04 utc 2002 i686 unknown ' config_args='-ds -e -Dprefix=/usr -Dusethreads -Di_db -Di_dbm -Di_ndbm -Di_gdbm -Duseshrplib=true' hint=recommended, useposix=true, d_sigaction=define usethreads=define use5005threads=undef 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 -fno-strict-aliasing -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64', optimize='-O3 --pipe', cppflags='-D_REENTRANT -D_GNU_SOURCE -fno-strict-aliasing' ccversion='', gccversion='3.2.2', 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 ='' libpth=/lib /usr/lib /usr/local/lib libs=-lnsl -ldl -lm -lpthread -lc -lcrypt -lutil perllibs=-lnsl -ldl -lm -lpthread -lc -lcrypt -lutil libc=, so=so, useshrplib=true, libperl=libperl.so gnulibc_version='2.2.5' Dynamic Linking: dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-rdynamic -Wl,-rpath,/usr/lib/perl5/5.8.0/i586-linux-thread-multi/CORE' cccdlflags='-fPIC', lddlflags='-shared' Locally applied patches: --- @INC for perl v5.8.0: /usr/lib/perl5/5.8.0/i586-linux-thread-multi /usr/lib/perl5/5.8.0 /usr/lib/perl5/site_perl/5.8.0/i586-linux-thread-multi /usr/lib/perl5/site_perl/5.8.0 /usr/lib/perl5/site_perl . --- Environment for perl v5.8.0: HOME=/root LANG (unset) LANGUAGE (unset) LC_CTYPE=en_US LD_LIBRARY_PATH (unset) LOGDIR (unset) PATH=/usr/java/j2re1.4.1_03/bin:/opt/sgtest/bin:/opt/cmcluster/bin:/usr/local/sbin:/usr/sbin:/sbin:/sbin:/usr/sbin:/usr/local/sbin:/root/bin:/usr/local/bin:/usr/bin:/usr/X11R6/bin:/bin:/usr/games:/opt/gnome2/bin:/opt/gnome/bin:/opt/kde3/bin:/usr/lib/java/bin:/opt/gnome/bin:/root/bin:/usr/local/cmcluster/bin PERL_BADLANG (unset) SHELL=/bin/bash
Subject: Re: [perl #30331] system/fork in DESTROY overrides exit code of parent program
Date: Thu, 17 Jun 2004 23:38:26 +0100
To: perl5-porters [...] perl.org
From: Dave Mitchell <davem [...] iabyn.com>
Download (untitled) / with headers
text/plain 924b
On Thu, Jun 17, 2004 at 07:16:52AM -0000, Xiaoke Zhang wrote: Show quoted text
> After tinkering around with this. It seems if the DESTROY method in an > object uses a system or fork call, the exit code from the forked process > overrides the exit code of the parent process.
[snip] Show quoted text
> I don't know if this is a feature or a bug, please advise. Thanks.
It's (mostly) a feature. From 'man perlvar': Inside an C<END> subroutine C<$?> contains the value that is going to be given to C<exit()>. You can modify C<$?> in an C<END> subroutine to change the exit status of your program. For example: END { $? = 1 if $? == 255; # die would make it 255 } Admittedly you're setting $? inside a destructor called at the end of the program rather than explicitly in an END block, but the effect is the same. Dave. -- Red sky at night - gerroff my land! Red sky at morning - gerroff my land! -- old farmers' sayings #14
CC: perl5-porters [...] perl.org
Subject: Re: [perl #30331] system/fork in DESTROY overrides exit code of parent program
Date: Fri, 18 Jun 2004 10:27:27 -0700
To: Dave Mitchell <davem [...] iabyn.com>
From: Yitzchak Scott-Thoennes <sthoenna [...] efn.org>
Download (untitled) / with headers
text/plain 1.9k
On Thu, Jun 17, 2004 at 11:38:26PM +0100, Dave Mitchell <davem@iabyn.com> wrote: Show quoted text
> On Thu, Jun 17, 2004 at 07:16:52AM -0000, Xiaoke Zhang wrote:
> > After tinkering around with this. It seems if the DESTROY method in an > > object uses a system or fork call, the exit code from the forked process > > overrides the exit code of the parent process.
> [snip]
> > I don't know if this is a feature or a bug, please advise. Thanks.
> > It's (mostly) a feature. From 'man perlvar': > > Inside an C<END> subroutine C<$?> contains the value that is going to be > given to C<exit()>. You can modify C<$?> in an C<END> subroutine to > change the exit status of your program. For example: > > END { > $? = 1 if $? == 255; # die would make it 255 > }
How does this look? (No, I haven't actually verified that local $? helps.) --- perl/pod/perlvar.pod.orig 2004-02-03 12:00:30.000000000 -0800 +++ perl/pod/perlvar.pod 2004-06-17 17:31:10.930244800 -0700 @@ -629,14 +629,18 @@ is returned via $? if any C<gethost*()> If you have installed a signal handler for C<SIGCHLD>, the value of C<$?> will usually be wrong outside that handler. -Inside an C<END> subroutine C<$?> contains the value that is going to be -given to C<exit()>. You can modify C<$?> in an C<END> subroutine to -change the exit status of your program. For example: +Inside an C<END> subroutine, or a C<DESTROY> method called while +exiting, C<$?> contains the value that is going to be given to +C<exit()>. You can modify C<$?> in an C<END> subroutine to change the +exit status of your program. For example: END { $? = 1 if $? == 255; # die would make it 255 } +Even indirect setting of $? (e.g. by calling C<system> or C<fork>) +will have this effect. If this is not intended, localize $?. + Under VMS, the pragma C<use vmsish 'status'> makes C<$?> reflect the actual VMS exit status, instead of the default emulation of POSIX status; see L<perlvms/$?> for details. End of Patch.
Subject: Re: [perl #30331] system/fork in DESTROY overrides exit code of parent program
Date: Fri, 18 Jun 2004 10:36:00 -0700 (PDT)
To: Yitzchak Scott-Thoennes via RT <perlbug-followup [...] perl.org>
From: Xiaoke Zhang <xiaoke [...] cup.hp.com>
Download (untitled) / with headers
text/plain 2.2k
Thanks for your help. I am going to get the $? in the begining of DESTORY and restore it at the end after the destructor. I verified and it seems to work. Thanks for prompt response. xz On Fri, 18 Jun 2004, Yitzchak Scott-Thoennes via RT wrote: Show quoted text
> On Thu, Jun 17, 2004 at 11:38:26PM +0100, Dave Mitchell <davem@iabyn.com> wrote:
> > On Thu, Jun 17, 2004 at 07:16:52AM -0000, Xiaoke Zhang wrote:
> > > After tinkering around with this. It seems if the DESTROY method in an > > > object uses a system or fork call, the exit code from the forked process > > > overrides the exit code of the parent process.
> > [snip]
> > > I don't know if this is a feature or a bug, please advise. Thanks.
> > > > It's (mostly) a feature. From 'man perlvar': > > > > Inside an C<END> subroutine C<$?> contains the value that is going to be > > given to C<exit()>. You can modify C<$?> in an C<END> subroutine to > > change the exit status of your program. For example: > > > > END { > > $? = 1 if $? == 255; # die would make it 255 > > }
> > How does this look? (No, I haven't actually verified that local $? helps.) > > --- perl/pod/perlvar.pod.orig 2004-02-03 12:00:30.000000000 -0800 > +++ perl/pod/perlvar.pod 2004-06-17 17:31:10.930244800 -0700 > @@ -629,14 +629,18 @@ is returned via $? if any C<gethost*()> > If you have installed a signal handler for C<SIGCHLD>, the > value of C<$?> will usually be wrong outside that handler. > > -Inside an C<END> subroutine C<$?> contains the value that is going to be > -given to C<exit()>. You can modify C<$?> in an C<END> subroutine to > -change the exit status of your program. For example: > +Inside an C<END> subroutine, or a C<DESTROY> method called while > +exiting, C<$?> contains the value that is going to be given to > +C<exit()>. You can modify C<$?> in an C<END> subroutine to change the > +exit status of your program. For example: > > END { > $? = 1 if $? == 255; # die would make it 255 > } > > +Even indirect setting of $? (e.g. by calling C<system> or C<fork>) > +will have this effect. If this is not intended, localize $?. > + > Under VMS, the pragma C<use vmsish 'status'> makes C<$?> reflect the > actual VMS exit status, instead of the default emulation of POSIX > status; see L<perlvms/$?> for details. > End of Patch. > > >
Subject: Re: [perl #30331] system/fork in DESTROY overrides exit code of parent program
Date: Fri, 18 Jun 2004 19:26:10 +0000 (UTC)
To: perl5-porters [...] perl.org
From: perl5-porters [...] ton.iguana.be (Ton Hospel)
Download (untitled) / with headers
text/plain 1.3k
In article <20040618172727.GB3864@e_n.org>, Yitzchak Scott-Thoennes <sthoenna@efn.org> writes: Show quoted text
> +Inside an C<END> subroutine, or a C<DESTROY> method called while > +exiting, C<$?> contains the value that is going to be given to > +C<exit()>. You can modify C<$?> in an C<END> subroutine to change the > +exit status of your program. For example: > > END { > $? = 1 if $? == 255; # die would make it 255 > } > > +Even indirect setting of $? (e.g. by calling C<system> or C<fork>) > +will have this effect. If this is not intended, localize $?. > +
I'd rather see it fixed than documented. Conceptually you don't think of things running after the last END. Being sure that all DESTROYS during global destruction don't change $? puts a bigger burden of understanding the exact lifetimes of his objects (of which he maybe isn't the author) on the user than is reasonable. Also think of module authors that now have to be very careful in their DESTROYs, because they can't know how long the user will keep their objects alive. Isn't it possible to find a place between END block processing and global cleanup to store the presumably wanted exit code and then exit with that saved value after global cleanup ? Even if not, documenting it would make it official, and I really can't see this as a feature you'd realistically want.
CC: perl5-porters [...] perl.org
Subject: Re: [perl #30331] system/fork in DESTROY overrides exit code of parent program
Date: Sat, 19 Jun 2004 15:21:56 +0100
To: perl5-porters [...] ton.iguana.be (Ton Hospel)
From: hv [...] crypt.org
perl5-porters@ton.iguana.be (Ton Hospel) wrote: :I'd rather see it fixed than documented. Conceptually you don't :think of things running after the last END. Then you should read the documentation, and adjust your concepts - things _do_ run after the last END. :Being sure that all :DESTROYS during global destruction don't change $? puts a bigger :burden of understanding the exact lifetimes of his objects (of which :he maybe isn't the author) on the user than is reasonable. Also :think of module authors that now have to be very careful in their :DESTROYs, because they can't know how long the user will keep their :objects alive. It is rare that a DESTROY method does anything that might affect $?. I think it is important to retain the ability to modify $?, and the existing mechanism seems the simplest way to do that, and also allows the simplest workaround should you need it: { local $?; system(...) }} It therefore seems perfectly reasonable to me to document this behaviour; the only modification I'd suggest to ysth's patch is to give an actual example of the use of local() to protect $?. Hugo


This service is sponsored and maintained by Best Practical Solutions and runs on Perl.org infrastructure.

For issues related to this RT instance (aka "perlbug"), please contact perlbug-admin at perl.org