Navigation Menu

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

signal handler can clobber $! #7235

Closed
p5pRT opened this issue Apr 15, 2004 · 14 comments
Closed

signal handler can clobber $! #7235

p5pRT opened this issue Apr 15, 2004 · 14 comments

Comments

@p5pRT
Copy link

p5pRT commented Apr 15, 2004

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

Searchable as RT28824$

@p5pRT
Copy link
Author

p5pRT commented Apr 15, 2004

From zefram@fysh.org

Created by zefram@fysh.org

If a signal is caught, and interrupts a system call, and the Perl signal
handler modifies $!, then this replaces the EINTR from the system call.
Simple test case​:

BEGIN t0<<<
#!/usr/bin/perl

use warnings;
use strict;

$SIG{TSTP} = sub { print "caught SIGTSTP\n"; $! = 0; };

my $a;
my $n = sysread(STDIN, $a, 1);
print "sysread returned ", defined($n) ? $n : "undef",
  "; errno = ", 0+$!, " (", $!, ")\n";
exit 0;

END t0<<<

The program attempts to read one character, and just displays what it
gets back from sysread. To perform the test, run the program from a
terminal and ^Z while it's waiting for input. I get this behaviour​:

$ ./t0
caught SIGTSTP
sysread returned undef; errno = 0 ()
$

This is pretty surprising behaviour to the code that was calling sysread;
returning undef with $! == 0 should be impossible.

The behaviour is perfectly understandable, and probably someone is going
to argue that it's correct. But it's inconsistent with the behaviour
one gets in C. Here's the equivalent C program​:

BEGIN t1.c<<<
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>

void sigtstp(int signum)
{
  printf("caught SIGTSTP\n");
  errno = 0;
}

int main(void)
{
  struct sigaction act;
  char c;
  int n;
  act.sa_handler = sigtstp;
  sigemptyset(&act.sa_mask);
  act.sa_flags = 0;
  if(sigaction(SIGTSTP, &act, NULL)) {
  perror("sigaction");
  exit(1);
  }
  n = read(0, &c, 1);
  printf("read returned %d; errno = %d (%s)\n", n,
  errno, strerror(errno));
  exit(0);
}

END t1.c<<<

$ ./t1
caught SIGTSTP
read returned -1; errno = 4 (Interrupted system call)
$

Obviously the difference is just a question of where errno/$! is set.
In C, read() sets errno just before it returns, whereas in Perl sysread()
has errno set internally and then does other things, such as invoking the
signal handler, before returning. I argue that $! should be saved and
restored in this case, so that $! *at the time that sysread() returns*
accurately reflects the result of the system call.

Code such as I showed above still needs to save and restore
errno/$! manually in the signal handler in order to cover all cases​: being
suspended immediately after [sys]read() returns and before errno/$! has
been read is a possibility. However, there are other situations where
the order of events can be guaranteed, and in such cases I think Perl
should match the C semantics that it appears to offer.

Perl Info

Flags:
    category=core
    severity=medium

Site configuration information for perl v5.8.3:

Configured by Debian Project at Sat Mar 27 17:07:14 EST 2004.

Summary of my perl5 (revision 5.0 version 8 subversion 3) configuration:
  Platform:
    osname=linux, osvers=2.4.25-ti1211, archname=i386-linux-thread-multi
    uname='linux kosh 2.4.25-ti1211 #1 thu feb 19 18:20:12 est 2004 i686 gnulinux '
    config_args='-Dusethreads -Duselargefiles -Dccflags=-DDEBIAN -Dcccdlflags=-fPIC -Darchname=i386-linux -Dprefix=/usr -Dprivlib=/usr/share/perl/5.8 -Darchlib=/usr/lib/perl/5.8 -Dvendorprefix=/usr -Dvendorlib=/usr/share/perl5 -Dvendorarch=/usr/lib/perl5 -Dsiteprefix=/usr/local -Dsitelib=/usr/local/share/perl/5.8.3 -Dsitearch=/usr/local/lib/perl/5.8.3 -Dman1dir=/usr/share/man/man1 -Dman3dir=/usr/share/man/man3 -Dsiteman1dir=/usr/local/man/man1 -Dsiteman3dir=/usr/local/man/man3 -Dman1ext=1 -Dman3ext=3perl -Dpager=/usr/bin/sensible-pager -Uafs -Ud_csh -Uusesfio -Uusenm -Duseshrplib -Dlibperl=libperl.so.5.8.3 -Dd_dosuid -des'
    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 -DTHREADS_HAVE_PIDS -DDEBIAN -fno-strict-aliasing -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64',
    optimize='-O3',
    cppflags='-D_REENTRANT -D_GNU_SOURCE -DTHREADS_HAVE_PIDS -DDEBIAN -fno-strict-aliasing -I/usr/local/include'
    ccversion='', gccversion='3.3.3 (Debian 20040314)', 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=-lgdbm -lgdbm_compat -ldb -ldl -lm -lpthread -lc -lcrypt
    perllibs=-ldl -lm -lpthread -lc -lcrypt
    libc=/lib/libc-2.3.2.so, so=so, useshrplib=true, libperl=libperl.so.5.8.3
    gnulibc_version='2.3.2'
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-rdynamic'
    cccdlflags='-fPIC', lddlflags='-shared -L/usr/local/lib'

Locally applied patches:
    


@INC for perl v5.8.3:
    /etc/perl
    /usr/local/lib/perl/5.8.3
    /usr/local/share/perl/5.8.3
    /usr/lib/perl5
    /usr/share/perl5
    /usr/lib/perl/5.8
    /usr/share/perl/5.8
    /usr/local/lib/site_perl
    .


Environment for perl v5.8.3:
    HOME=/home/zefram
    LANG (unset)
    LANGUAGE (unset)
    LD_LIBRARY_PATH (unset)
    LOGDIR (unset)
    PATH=/home/zefram/pub/i686-pc-linux-gnu/bin:/home/zefram/pub/common/bin:/usr/bin:/usr/X11R6/bin:/bin:/usr/local/bin:/usr/games:/opt/libunsn/bin
    PERL_BADLANG (unset)
    SHELL=/usr/bin/zsh

@p5pRT
Copy link
Author

p5pRT commented Jul 24, 2007

From @smpeters

On Thu Apr 15 06​:25​:56 2004, zefram <!-- x --> at fysh.org wrote​:

This is a bug report for perl from zefram <!-- x --> at fysh.org,
generated with the help of perlbug 1.34 running under perl v5.8.3.

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

If a signal is caught, and interrupts a system call, and the Perl
signal
handler modifies $!, then this replaces the EINTR from the system
call.
Simple test case​:

BEGIN t0<<<
#!/usr/bin/perl

use warnings;
use strict;

$SIG{TSTP} = sub { print "caught SIGTSTP\n"; $! = 0; };

my $a;
my $n = sysread(STDIN, $a, 1);
print "sysread returned ", defined($n) ? $n : "undef",
"; errno = ", 0+$!, " (", $!, ")\n";
exit 0;

END t0<<<

The program attempts to read one character, and just displays what it
gets back from sysread. To perform the test, run the program from a
terminal and ^Z while it's waiting for input. I get this behaviour​:

$ ./t0
caught SIGTSTP
sysread returned undef; errno = 0 ()
$

This is pretty surprising behaviour to the code that was calling
sysread;
returning undef with $! == 0 should be impossible.

The behaviour is perfectly understandable, and probably someone is
going
to argue that it's correct. But it's inconsistent with the behaviour
one gets in C. Here's the equivalent C program​:

The problem is that by the time $! is displayed at the end, several
other operations have occurred. $! has to be checked as soon as
possible or you risk having it cleared out. Looking at this, I'm
thinking that this isn't a bug. Any other opinions?

@p5pRT
Copy link
Author

p5pRT commented Jul 24, 2007

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

@p5pRT
Copy link
Author

p5pRT commented Jul 24, 2007

From nospam-abuse@bloodgate.com

-----BEGIN PGP SIGNED MESSAGE-----
Hash​: SHA1

Moin,

On Tuesday 24 July 2007 23​:23​:29 Steve Peters via RT wrote​:

On Thu Apr 15 06​:25​:56 2004, zefram <!-- x --> at fysh.org wrote​:

This is a bug report for perl from zefram <!-- x --> at fysh.org,
generated with the help of perlbug 1.34 running under perl v5.8.3.

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

If a signal is caught, and interrupts a system call, and the Perl
signal
handler modifies $!, then this replaces the EINTR from the system
call.

Simple test case​:

BEGIN t0<<<

#!/usr/bin/perl

use warnings;
use strict;

$SIG{TSTP} = sub { print "caught SIGTSTP\n"; $! = 0; };

my $a;
my $n = sysread(STDIN, $a, 1);
print "sysread returned ", defined($n) ? $n : "undef",
"; errno = ", 0+$!, " (", $!, ")\n";
exit 0;

END t0<<<

The program attempts to read one character, and just displays what it
gets back from sysread. To perform the test, run the program from a
terminal and ^Z while it's waiting for input. I get this behaviour​:

$ ./t0
caught SIGTSTP
sysread returned undef; errno = 0 ()
$

This is pretty surprising behaviour to the code that was calling
sysread;
returning undef with $! == 0 should be impossible.

The behaviour is perfectly understandable, and probably someone is
going
to argue that it's correct. But it's inconsistent with the behaviour
one gets in C. Here's the equivalent C program​:

The problem is that by the time $! is displayed at the end, several
other operations have occurred.

I am not sure what other operations you mean. This modified program​:

  #!/usr/bin/perl
 
  use warnings;
  use strict;
 
  $SIG{TSTP} = sub { print "caught SIGTSTP\n"; $! = 0; };
 
  my $a;
  my $n = sysread(STDIN, $a, 1); my $b = $! + 0; my $c = "$!";
  print "\$!​: " . $b . "$c\n";
  print "sysread returned ", defined($n) ? $n : "undef",
  "; errno = ", 0+$!, " (", $!, ")\n";
  exit 0;

prints on Linux, Perl v5.8.8​:

  linux​:/home/te # perl t.pl
  caught SIGTSTP
  $!​: 0
  sysread returned undef; errno = 0 ()

I can't think of a way to check $! earlier.

All the best,

Tels

- --
Signed on Tue Jul 24 23​:35​:01 2007 with key 0x93B84C15.
View my photo gallery​: http​://bloodgate.com/photos
PGP key on http​://bloodgate.com/tels.asc or per email.

"It is true that some lawyers are dishonest, arrogant, greedy, venal,
amoral, ruthless buckets of slime. On the other hand, it is unfair to
judge the entire profession by a few hundred-thousand bad apples."

  -- The Washington Post
-----BEGIN PGP SIGNATURE-----
Version​: GnuPG v1.4.2 (GNU/Linux)

iQEVAwUBRqZxJncLPEOTuEwVAQKn8gf6A0I1wQtR6M9lGSyRjsaL7VtO4hDBeOv9
icbS5jBPcyWSFkovlJK6r2T95vKbwAY9Hxd5eqz1yZvplM3TrRUXZ8IVk0oYGvc3
zOEbNs3Walco1hOP+RgqZLuSgv9fXUgfaIzArc2NQ6T39c8vyZIs1mDtx/UkbqBJ
ePPk77OtGx/2Xg+s82IH1xd6jxlYTnt19yDgpoA8npbr380X4tWCmiqEKPcQUvus
7zdeMdNI6tm61flh2OAOFWmSiRyobliOvzRKawHJXw2QAbq2TPONkp1dZxEyWajl
sV6RyGKafO9jF/JH0ady7YtEN0lxGSw+Tku1Ij6pQTytZ3SkKfkU3Q==
=Lkt2
-----END PGP SIGNATURE-----

@p5pRT
Copy link
Author

p5pRT commented Jul 25, 2007

From mark@mark.mielke.cc

Tels wrote​:

-----BEGIN PGP SIGNED MESSAGE-----
Hash​: SHA1

Moin,

On Tuesday 24 July 2007 23​:23​:29 Steve Peters via RT wrote​:

On Thu Apr 15 06​:25​:56 2004, zefram <!-- x --> at fysh.org wrote​:

$SIG{TSTP} = sub { print "caught SIGTSTP\n"; $! = 0; };
my $a;
my $n = sysread(STDIN, $a, 1);
print "sysread returned ", defined($n) ? $n : "undef",
"; errno = ", 0+$!, " (", $!, ")\n";
exit 0;

The problem is that by the time $! is displayed at the end, several
other operations have occurred.

I believe the correct behaviour would be for sysread() to return EINTR.
Although it is true that he over-writes errno twice in the signal
handler (both the print which turns into a successful write() and the
explicit overwrite of $!), this occurs in a separate signal call stack
on UNIX. The sysread() itself is interrupted when the signal returns. I
tested removing the explicit assignment and found​:

$ perl -e '
  $SIG{"TSTP"} = sub { print "caught SIGTSTP\n"; };
  my $a;
  my $n = sysread(STDIN, $a, 1);
  print "sysread return ", defined($n) ? $n : "undef",
  "; errno = ", 0+$!, " (", $!, ")\n";
'
caught SIGTSTP
sysread return undef; errno = 4 (Interrupted system call)

This leads me to believe that it is the explicit assignment to the Perl
$! that is causing a problem. To be sure​:

$ perl -e '
  $SIG{"TSTP"} = sub { $! = 0 };
  my $a; my $n = sysread(STDIN, $a, 1);
  print "sysread() == ", defined($n) ? $n : "undef",
  "; errno = ", 0+$!, " (", $!, ")\n";
'
sysread() == undef; errno = 0 ()

And to be sure this has to do with signals and assignment to $!​:
$ perl -e '
  $! = 0; $SIG{"TSTP"} = sub {};
  my $a; my $n = sysread(STDIN, $a, 1);
  print "sysread() == ", defined($n) ? $n : "undef",
  "; errno = ", 0+$!, " (", $!, ")\n";
'
sysread() == undef; errno = 4 (Interrupted system call)

So - on the surface, it does look like there is some sort of bug.
Perhaps $! has the wrong reference count, or the errno magic is disabled
in some way?

However!

I do not believe C promises you the ability to set the value of errno.
The expectation that you can set errno, or specifically, set errno in a
signal handler, and be certain that it will have no effect on the caller
that may or may not currently be in a system call, is wrong. What are
you trying to do? Why do you expect assignment of errno in a signal
handler to be ignored in this case?

Cheers,
mark

--
Mark Mielke <mark@​mielke.cc>

@p5pRT
Copy link
Author

p5pRT commented Jul 25, 2007

From @gbarr

On Jul 24, 2007, at 9​:06 PM, Mark Mielke wrote​:

Tels wrote​:

-----BEGIN PGP SIGNED MESSAGE-----
Hash​: SHA1

Moin,

On Tuesday 24 July 2007 23​:23​:29 Steve Peters via RT wrote​:

On Thu Apr 15 06​:25​:56 2004, zefram <!-- x --> at fysh.org wrote​:

$SIG{TSTP} = sub { print "caught SIGTSTP\n"; $! = 0; };
my $a;
my $n = sysread(STDIN, $a, 1);
print "sysread returned ", defined($n) ? $n : "undef",
"; errno = ", 0+$!, " (", $!, ")\n";
exit 0;

The problem is that by the time $! is displayed at the end, several
other operations have occurred.

I believe the correct behaviour would be for sysread() to return
EINTR.

Yes

Although it is true that he over-writes errno twice in the signal
handler (both the print which turns into a successful write() and
the explicit overwrite of $!), this occurs in a separate signal
call stack on UNIX. The sysread() itself is interrupted when the
signal returns. I tested removing the explicit assignment and found​:

UNIX signal handlers are run on a separate stack and are called
before sysread sets errno. But signal handlers in perl are not called
from the C signal handler. We used to do it that way, but that causes
all sorts of stability problems because it is run in a separate
stack. So instead the C signal handler remembers it saw a signal and
the perl signal handler is run after the OP has completed (search
archives for "safe signals"). So sysread has returned and errno is
set before the perl handler is run.

To fix this despatch_signals in mg.c would need to save and restore
errno.

I do not believe C promises you the ability to set the value of
errno. The expectation that you can set errno, or specifically, set
errno in a signal handler, and be certain that it will have no
effect on the caller that may or may not currently be in a system
call, is wrong.

You can always write to errno, you just cannot be sure when it will
get overwritten. And in the case of a signal
handler, the system call that got interrupted will probably overwrite
it after the handler returns.

Graham.

@p5pRT
Copy link
Author

p5pRT commented Apr 1, 2009

From perlbug@plan9.de

Created by perlbug@plan9.de

Hi!

Today, I wondered whether I should localise $! in my signal handler in perl.

I looked through 5.10 sources, and think that perl simply destroys errno
in many occasions, and should probably save and restore errno.

Please note that I have not *verified* anything of this :)

For example, the Perl_csighandler calls "rsignal" which might destroy
errno, and croak, which might do the same.

The Perl_sighandler might do I/O (for warn), again destroying errno.

While this is probably not a big deal in most cases, in some cases, this
cna lead to hard to debug problems, I think. Also, most perl signal
handlers do not seem to care about $!, so saving/restoring errno (which is
standard practise otherwise if you do syscalls) might be a good thing in both
Perl_sighandler and Perl_csighandler.

Just my 0.02€

Perl Info

Flags:
    category=core
    severity=wishlist

Site configuration information for perl 5.10.0:

Configured by Marc Lehmann at Sat Feb 21 02:30:27 CET 2009.

Summary of my perl5 (revision 5 version 10 subversion 0) configuration:
  Platform:
    osname=linux, osvers=2.6.24-etchnhalf.1-amd64, archname=amd64-linux
    uname='linux cerebro 2.6.24-etchnhalf.1-amd64 #1 smp mon jul 21 10:36:02 utc 2008 x86_64 gnulinux '
    config_args='-Duselargefiles -Dxxxxuse64bitint -Uuse64bitall -Dusemymalloc=n -Dcc=gcc -Dccflags=-ggdb -gdwarf-2 -g3 -Dcppflags=-DPERL_ARENA_SIZE=16368 -D_GNU_SOURCE -I/opt/include -Doptimize=-O6 -msse2 -funroll-loops -fno-strict-aliasing -Dcccdlflags=-fPIC -Dldflags=-L/opt/perl/lib -L/opt/lib -Dlibs=-ldl -lm -lcrypt -Darchname=amd64-linux -Dprefix=/opt/perl -Dprivlib=/opt/perl/lib/perl5 -Darchlib=/opt/perl/lib/perl5 -Dvendorprefix=/opt/perl -Dvendorlib=/opt/perl/lib/perl5 -Dvendorarch=/opt/perl/lib/perl5 -Dsiteprefix=/opt/perl -Dsitelib=/opt/perl/lib/perl5 -Dsitearch=/opt/perl/lib/perl5 -Dsitebin=/opt/perl/bin -Dman1dir=/opt/perl/man/man1 -Dman3dir=/opt/perl/man/man3 -Dsiteman1dir=/opt/perl/man/man1 -Dsiteman3dir=/opt/perl/man/man3 -Dman1ext=1 -Dman3ext=3 -Dpager=/usr/bin/less -Uafs -Uusesfio -Uusenm -Uuseshrplib -Dd_dosuid -Dusethreads=undef -Duse5005threads=undef -Duseithreads=undef -Dusemultiplicity=undef -Demail=perl-binary@plan9.de -Dcf_email=perl-binary@plan9.de -Dcf_by=Marc Lehmann -Dlocincpth=/opt/perl/include /opt/include -Dmyhostname=localhost -Dmultiarch=undef -Dbin=/opt/perl/bin -Dxxxusedevel -DxxxDEBUGGING -Dxxxuse_debugging_perl -Dxxxuse_debugmalloc -des'
    hint=recommended, useposix=true, d_sigaction=define
    useithreads=undef, usemultiplicity=undef
    useperlio=define, d_sfio=undef, uselargefiles=define, usesocks=undef
    use64bitint=define, use64bitall=undef, uselongdouble=undef
    usemymalloc=n, bincompat5005=undef
  Compiler:
    cc='gcc', ccflags ='-ggdb -gdwarf-2 -g3 -fno-strict-aliasing -pipe -I/opt/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64',
    optimize='-O6 -msse2 -funroll-loops -fno-strict-aliasing',
    cppflags='-DPERL_ARENA_SIZE=16368 -D_GNU_SOURCE -I/opt/include -ggdb -gdwarf-2 -g3 -fno-strict-aliasing -pipe -I/opt/include'
    ccversion='', gccversion='4.3.2', gccosandvers=''
    intsize=4, longsize=8, ptrsize=8, doublesize=8, byteorder=12345678
    d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16
    ivtype='long', ivsize=8, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
    alignbytes=8, prototype=define
  Linker and Libraries:
    ld='gcc', ldflags ='-L/opt/perl/lib -L/opt/lib -L/usr/local/lib'
    libpth=/usr/local/lib /lib /usr/lib /lib64 /usr/lib64
    libs=-ldl -lm -lcrypt
    perllibs=-ldl -lm -lcrypt
    libc=/lib/libc-2.7.so, so=so, useshrplib=false, libperl=libperl.a
    gnulibc_version='2.7'
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E'
    cccdlflags='-fPIC', lddlflags='-shared -O6 -msse2 -funroll-loops -fno-strict-aliasing -L/opt/perl/lib -L/opt/lib -L/usr/local/lib'

Locally applied patches:
    http://public.activestate.com/cgi-bin/perlbrowse/p/34209
    http://public.activestate.com/cgi-bin/perlbrowse/p/34507
    http://www.gossamer-threads.com/lists/perl/porters/232549
    embed.fnc:Perl_vcroak NULLOK


@INC for perl 5.10.0:
    /root/src/sex
    /opt/perl/lib/perl5
    /opt/perl/lib/perl5
    /opt/perl/lib/perl5
    /opt/perl/lib/perl5
    /opt/perl/lib/perl5
    .


Environment for perl 5.10.0:
    HOME=/root
    LANG (unset)
    LANGUAGE (unset)
    LC_CTYPE=en_US.UTF-8
    LD_LIBRARY_PATH (unset)
    LOGDIR (unset)
    PATH=/root/s2:/root/s:/opt/bin:/opt/sbin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/X11/bin:/usr/games:/usr/local/bin:/usr/local/sbin:/root/pserv:.
    PERL5LIB=/root/src/sex
    PERL5_CPANPLUS_CONFIG=/root/.cpanplus/config
    PERLDB_OPTS=ornaments=0
    PERL_ANYEVENT_EDNS0=1
    PERL_ANYEVENT_NET_TESTS=1
    PERL_ANYEVENT_PROTOCOLS=ipv4,ipv6
    PERL_ANYEVENT_STRICT=1
    PERL_BADLANG (unset)
    PERL_UNICODE=0
    SHELL=/bin/bash

@p5pRT
Copy link
Author

p5pRT commented Feb 4, 2010

From lubo.rintel@gooddata.com

This is probably the same issue as this patch deals with​:

http​://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2010-02/msg00060.html

@p5pRT
Copy link
Author

p5pRT commented Feb 4, 2010

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

@p5pRT
Copy link
Author

p5pRT commented Feb 4, 2010

From schmorp@schmorp.de

On Thu, Feb 04, 2010 at 04​:58​:19AM -0800, Lubomir Rintel via RT <perlbug-followup@​perl.org> wrote​:

This is probably the same issue as this patch deals with​:

http​://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2010-02/msg00060.html

nope, but similar. localising $! is not enough, as the (C) signal handler
itself can change errno.

(and the dSAVE_ERRNO should be done outside the loop, anyways)

it surely helps in general, of course, but the issue the patch works
around can be fixed from perl (it's a faster local $!), while the thing
I reported cannot (Perl_csighandler is called asynchronously and does not
call perl).

--
  The choice of a Deliantra, the free code+content MORPG
  -----==- _GNU_ http​://www.deliantra.net
  ----==-- _ generation
  ---==---(_)__ __ ____ __ Marc Lehmann
  --==---/ / _ \/ // /\ \/ / schmorp@​schmorp.de
  -=====/_/_//_/\_,_/ /_/\_\

@p5pRT
Copy link
Author

p5pRT commented Dec 11, 2011

From @Leont

On Thu Apr 15 06​:25​:56 2004, zefram@​fysh.org wrote​:

If a signal is caught, and interrupts a system call, and the Perl
signal
handler modifies $!, then this replaces the EINTR from the system
call.
Simple test case​:

BEGIN t0<<<
#!/usr/bin/perl

use warnings;
use strict;

$SIG{TSTP} = sub { print "caught SIGTSTP\n"; $! = 0; };

my $a;
my $n = sysread(STDIN, $a, 1);
print "sysread returned ", defined($n) ? $n : "undef",
"; errno = ", 0+$!, " (", $!, ")\n";
exit 0;

END t0<<<

The program attempts to read one character, and just displays what it
gets back from sysread. To perform the test, run the program from a
terminal and ^Z while it's waiting for input. I get this behaviour​:

$ ./t0
caught SIGTSTP
sysread returned undef; errno = 0 ()
$

This is pretty surprising behaviour to the code that was calling
sysread;
returning undef with $! == 0 should be impossible.

The behaviour is perfectly understandable, and probably someone is
going
to argue that it's correct. But it's inconsistent with the behaviour
one gets in C. Here's the equivalent C program​:

BEGIN t1.c<<<
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>

void sigtstp(int signum)
{
printf("caught SIGTSTP\n");
errno = 0;
}

int main(void)
{
struct sigaction act;
char c;
int n;
act.sa_handler = sigtstp;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
if(sigaction(SIGTSTP, &act, NULL)) {
perror("sigaction");
exit(1);
}
n = read(0, &c, 1);
printf("read returned %d; errno = %d (%s)\n", n,
errno, strerror(errno));
exit(0);
}

END t1.c<<<

$ ./t1
caught SIGTSTP
read returned -1; errno = 4 (Interrupted system call)
$

Obviously the difference is just a question of where errno/$! is set.
In C, read() sets errno just before it returns, whereas in Perl
sysread()
has errno set internally and then does other things, such as invoking
the
signal handler, before returning. I argue that $! should be saved and
restored in this case, so that $! *at the time that sysread() returns*
accurately reflects the result of the system call.

Code such as I showed above still needs to save and restore
errno/$! manually in the signal handler in order to cover all cases​:
being
suspended immediately after [sys]read() returns and before errno/$!
has
been read is a possibility. However, there are other situations where
the order of events can be guaranteed, and in such cases I think Perl
should match the C semantics that it appears to offer.

This bug seems to be fixed in blead, probably by d016601.

Leon

@p5pRT
Copy link
Author

p5pRT commented Dec 11, 2011

From @Leont

On Wed Apr 01 08​:55​:28 2009, perlbug@​plan9.de wrote​:

This is a bug report for perl from perlbug@​plan9.de,
generated with the help of perlbug 1.36 running under perl 5.10.0.

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

Hi!

Today, I wondered whether I should localise $! in my signal handler in
perl.

I looked through 5.10 sources, and think that perl simply destroys
errno
in many occasions, and should probably save and restore errno.

Please note that I have not *verified* anything of this :)

For example, the Perl_csighandler calls "rsignal" which might destroy
errno, and croak, which might do the same.

The Perl_sighandler might do I/O (for warn), again destroying errno.

While this is probably not a big deal in most cases, in some cases,
this
cna lead to hard to debug problems, I think. Also, most perl signal
handlers do not seem to care about $!, so saving/restoring errno
(which is
standard practise otherwise if you do syscalls) might be a good thing
in both
Perl_sighandler and Perl_csighandler.

Just my 0.02€

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

Configured by Marc Lehmann at Sat Feb 21 02​:30​:27 CET 2009.

Summary of my perl5 (revision 5 version 10 subversion 0)
configuration​:
Platform​:
osname=linux, osvers=2.6.24-etchnhalf.1-amd64, archname=amd64-
linux
uname='linux cerebro 2.6.24-etchnhalf.1-amd64 #1 smp mon jul 21
10​:36​:02 utc 2008 x86_64 gnulinux '
config_args='-Duselargefiles -Dxxxxuse64bitint -Uuse64bitall
-Dusemymalloc=n -Dcc=gcc -Dccflags=-ggdb -gdwarf-2 -g3
-Dcppflags=-DPERL_ARENA_SIZE=16368 -D_GNU_SOURCE -I/opt/include
-Doptimize=-O6 -msse2 -funroll-loops -fno-strict-aliasing
-Dcccdlflags=-fPIC -Dldflags=-L/opt/perl/lib -L/opt/lib -Dlibs=-ldl
-lm -lcrypt -Darchname=amd64-linux -Dprefix=/opt/perl
-Dprivlib=/opt/perl/lib/perl5 -Darchlib=/opt/perl/lib/perl5
-Dvendorprefix=/opt/perl -Dvendorlib=/opt/perl/lib/perl5
-Dvendorarch=/opt/perl/lib/perl5 -Dsiteprefix=/opt/perl
-Dsitelib=/opt/perl/lib/perl5 -Dsitearch=/opt/perl/lib/perl5
-Dsitebin=/opt/perl/bin -Dman1dir=/opt/perl/man/man1
-Dman3dir=/opt/perl/man/man3 -Dsiteman1dir=/opt/perl/man/man1
-Dsiteman3dir=/opt/perl/man/man3 -Dman1ext=1 -Dman3ext=3
-Dpager=/usr/bin/less -Uafs -Uusesfio -Uusenm -Uuseshrplib
-Dd_dosuid -Dusethreads=undef -Duse5005threads=undef
-Duseithreads=undef -Dusemultiplicity=undef
-Demail=perl-binary@​plan9.de -Dcf_email=perl-binary@​plan9.de
-Dcf_by=Marc Lehmann -Dlocincpth=/opt/perl/include /opt/include
-Dmyhostname=localhost -Dmultiarch=undef -Dbin=/opt/perl/bin
-Dxxxusedevel -DxxxDEBUGGING -Dxxxuse_debugging_perl
-Dxxxuse_debugmalloc -des'
hint=recommended, useposix=true, d_sigaction=define
useithreads=undef, usemultiplicity=undef
useperlio=define, d_sfio=undef, uselargefiles=define,
usesocks=undef
use64bitint=define, use64bitall=undef, uselongdouble=undef
usemymalloc=n, bincompat5005=undef
Compiler​:
cc='gcc', ccflags ='-ggdb -gdwarf-2 -g3 -fno-strict-aliasing -pipe
-I/opt/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64',
optimize='-O6 -msse2 -funroll-loops -fno-strict-aliasing',
cppflags='-DPERL_ARENA_SIZE=16368 -D_GNU_SOURCE -I/opt/include
-ggdb -gdwarf-2 -g3 -fno-strict-aliasing -pipe -I/opt/include'
ccversion='', gccversion='4.3.2', gccosandvers=''
intsize=4, longsize=8, ptrsize=8, doublesize=8, byteorder=12345678
d_longlong=define, longlongsize=8, d_longdbl=define,
longdblsize=16
ivtype='long', ivsize=8, nvtype='double', nvsize=8, Off_t='off_t',
lseeksize=8
alignbytes=8, prototype=define
Linker and Libraries​:
ld='gcc', ldflags ='-L/opt/perl/lib -L/opt/lib -L/usr/local/lib'
libpth=/usr/local/lib /lib /usr/lib /lib64 /usr/lib64
libs=-ldl -lm -lcrypt
perllibs=-ldl -lm -lcrypt
libc=/lib/libc-2.7.so, so=so, useshrplib=false, libperl=libperl.a
gnulibc_version='2.7'
Dynamic Linking​:
dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E'
cccdlflags='-fPIC', lddlflags='-shared -O6 -msse2 -funroll-loops
-fno-strict-aliasing -L/opt/perl/lib -L/opt/lib -L/usr/local/lib'

Locally applied patches​:
http​://public.activestate.com/cgi-bin/perlbrowse/p/34209
http​://public.activestate.com/cgi-bin/perlbrowse/p/34507
http​://www.gossamer-threads.com/lists/perl/porters/232549
embed.fnc​:Perl_vcroak NULLOK

---
@​INC for perl 5.10.0​:
/root/src/sex
/opt/perl/lib/perl5
/opt/perl/lib/perl5
/opt/perl/lib/perl5
/opt/perl/lib/perl5
/opt/perl/lib/perl5
.

---
Environment for perl 5.10.0​:
HOME=/root
LANG (unset)
LANGUAGE (unset)
LC_CTYPE=en_US.UTF-8
LD_LIBRARY_PATH (unset)
LOGDIR (unset)

PATH=/root/s2​:/root/s​:/opt/bin​:/opt/sbin​:/bin​:/sbin​:/usr/bin​:/usr/sbin​:/usr/X11/bin​:/usr/games​:/usr/local/bin​:/usr/local/sbin​:/root/pserv​:.

PERL5LIB=/root/src/sex
PERL5\_CPANPLUS\_CONFIG=/root/\.cpanplus/config
PERLDB\_OPTS=ornaments=0
PERL\_ANYEVENT\_EDNS0=1
PERL\_ANYEVENT\_NET\_TESTS=1
PERL\_ANYEVENT\_PROTOCOLS=ipv4\,ipv6
PERL\_ANYEVENT\_STRICT=1
PERL\_BADLANG \(unset\)
PERL\_UNICODE=0
SHELL=/bin/bash

This bug is a duplicate of #28824. It seems to have been fixed in commit
d016601.

Leon

@p5pRT
Copy link
Author

p5pRT commented Dec 11, 2011

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

@p5pRT p5pRT closed this as completed Dec 11, 2011
@p5pRT
Copy link
Author

p5pRT commented Dec 11, 2011

@cpansprout - 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