Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

system/fork in DESTROY overrides exit code of parent program #7371

Closed
p5pRT opened this issue Jun 17, 2004 · 8 comments
Closed

system/fork in DESTROY overrides exit code of parent program #7371

p5pRT opened this issue Jun 17, 2004 · 8 comments

Comments

@p5pRT
Copy link

p5pRT commented Jun 17, 2004

Migrated from rt.perl.org#30331 (status was 'resolved')

Searchable as RT30331$

@p5pRT
Copy link
Author

p5pRT commented Jun 17, 2004

From xiaoke@cup.hp.com

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

@p5pRT
Copy link
Author

p5pRT commented Jun 17, 2004

From @iabyn

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
  }

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

@p5pRT
Copy link
Author

p5pRT commented Jun 17, 2004

The RT System itself - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Jun 18, 2004

From @ysth

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&#8203;:

END \{
    $? = 1 if $? == 255;  \# die would make it 255
\} 

How does this look? (No, I haven't actually verified that local $? helps.)

Inline Patch
--- 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.

@p5pRT
Copy link
Author

p5pRT commented Jun 18, 2004

From xiaoke@cup.hp.com

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​:

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&#8203;:

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.

@p5pRT
Copy link
Author

p5pRT commented Jun 18, 2004

From perl5-porters@ton.iguana.be

In article <20040618172727.GB3864@​e_n.org>,
  Yitzchak Scott-Thoennes <sthoenna@​efn.org> writes​:

+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.

@p5pRT
Copy link
Author

p5pRT commented Jun 19, 2004

From @hvds

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

@p5pRT
Copy link
Author

p5pRT commented Jun 30, 2004

@iabyn - Status changed from 'open' to 'resolved'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant