This is a bug report for perl from jto...@bierce.john-edwin-tobey.org,
generated with the help of perlbug 1.36 running under perl 5.10.0.
-----------------------------------------------------------------
Signal handlers affect the value of $@ even when they don't use eval/die.
The following program prints "Signal clobbers $@!" I believe it should
print "OK".
$SIG{'INT'} = sub {
$during = $@;
};
$@ = 'hello';
$before = $@;
kill('INT', $$);
$after = $@;
if ($before ne $after) {
print("Signal clobbers \$\@!\n");
}
elsif ($before ne $during) {
print("Signal hides \$\@\n");
}
else {
print("OK\n");
}
-----------------------------------------------------------------
---
Flags:
category=core
severity=low
---
Site configuration information for perl 5.10.0:
Configured by jtobey at Wed Nov 28 13:39:07 EST 2007.
Summary of my perl5 (revision 5 version 10 subversion 0) configuration:
Platform:
osname=linux, osvers=2.6.18-5-686, archname=i686-linux
uname='linux bierce 2.6.18-5-686 #1 smp wed oct 3 00:12:50 utc 2007 i686 gnulinux '
config_args='-des -Dprefix=/home/jtobey/perl-5.10.0-RC2'
hint=recommended, useposix=true, d_sigaction=define
useithreads=undef, usemultiplicity=undef
useperlio=define, d_sfio=undef, uselargefiles=define, usesocks=undef
use64bitint=undef, use64bitall=undef, uselongdouble=undef
usemymalloc=n, bincompat5005=undef
Compiler:
cc='cc', ccflags ='-fno-strict-aliasing -pipe -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64',
optimize='-O2',
cppflags='-fno-strict-aliasing -pipe -I/usr/local/include'
ccversion='', gccversion='4.1.2 20061115 (prerelease) (Debian 4.1.1-21)', 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 /usr/lib64
libs=-lnsl -ldl -lm -lcrypt -lutil -lc
perllibs=-lnsl -ldl -lm -lcrypt -lutil -lc
libc=/lib/libc-2.3.6.so, so=so, useshrplib=false, libperl=libperl.a
gnulibc_version='2.3.6'
Dynamic Linking:
dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E'
cccdlflags='-fPIC', lddlflags='-shared -O2 -L/usr/local/lib'
Locally applied patches:
RC2
---
@INC for perl 5.10.0:
/home/jtobey/perl-5.10.0-RC2/lib/5.10.0/i686-linux
/home/jtobey/perl-5.10.0-RC2/lib/5.10.0
/home/jtobey/perl-5.10.0-RC2/lib/site_perl/5.10.0/i686-linux
/home/jtobey/perl-5.10.0-RC2/lib/site_perl/5.10.0
.
---
Environment for perl 5.10.0:
HOME=/home/jtobey
LANG=C
LANGUAGE (unset)
LC_ALL=C
LD_LIBRARY_PATH (unset)
LOGDIR (unset)
PATH=/home/jtobey/bin:/jtobey/local/bin:/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/usr/local/sbin:/usr/sbin:/sbin
PERL_BADLANG (unset)
SHELL=bash
Severity: High
Perl Version: 5.8.0, 5.8.4, 5.8.8, 5.10.0-RC2 & probably all in between.
Operating System: Linux, Solaris, & probably all unixish and more.
This bug will spookily generate false positive eval results in any
program that uses eval and handles async signals (returns from handlers).
To fix this bug and restore the pre-5.8 behaviour, make
Perl_sighandler() enter scope and localise ERRSV before call_sv(), leave
scope and copy ERRSV thereafter. Then, after the special processing
that motivated the use of G_EVAL, it should test and (if true) die with
the copy, rather than ERRSV.
In other words, Perl_sighandler() needs to do the C equivalent of:
my $err;
{ local $@;
eval ...;
$err = $@; }
...
die($err) if $err;
instead of the current:
eval ...;
die($@) if $@;
By the way, unfriendly RT rejects my edits:
* Could not add new custom field value: Permission Denied
* Could not add new custom field value: Permission Denied
* Could not add new custom field value: Permission Denied
* Could not add new custom field value: Permission Denied
* Could not add new custom field value: Permission Denied
* Could not add new custom field value: Permission Denied
* Permission Denied
Two things. I see nothing wrong with my results of running your
program and you aren't supposed to use $@ as a boolean. If you do, you
risk getting false positives and negatives. $@ cannot be used a
boolean in Perl 5 and it's a bug in your code if you use it that way.
$@=
$before=hello
$during=
$after=
$@ can be false after error because an eval{} happened during a ->DESTROY.
$@ can be true after *NO* error because an a die happened during a
->DESTROY. The eval will still succeed though.
$@ could be tied and act arbitrarily.
The value $@ in could be an overloaded object. If coded poorly,
examining the value clobbers $@. In fact, at work $@ usually is a
stringification overloaded object. An earlier iteration computed "$@"
improperly and would clobber $@ during the compute.
In general you must always examine the result of eval{} to see if the
block succeeded. For the rare case where the eval block succeeds, one
->DESTROY fails and another ->DESTROY suceeds, the failing code can
only be detected by having a $SIG{__DIE__} handler. I hope Perl 6
fixes this mess.
Josh
> Two things. I see nothing wrong with my results of running your
> program and you aren't supposed to use $@ as a boolean. If you do, you
> risk getting false positives and negatives. $@ cannot be used a
> boolean in Perl 5 and it's a bug in your code if you use it that way.
Please refer to the example in the original bug report, not the
pseudocode illustrating Perl_sighandler:
http://rt.perl.org/rt3/Ticket/Display.html?id=47928
You have to meditate a little to appreciate the bug. If your program
uses asynchronous signals, then $@ may be cleared at any time. In
particular, it is cleared if a signal is received between an eval
statement and subsequent examination of $@.
Example:
$SIG{ALRM} = sub { $got_ALRM = 1; };
alarm(1);
unless (eval sub { anything(); 1 }) {
### ALRM SIGNAL HERE CLEARS $@
print("error:$@");
}
The fix is simple but requires changes to Perl_sighandler() in mg.c.
By the way, though it's irrelevant to the bug, several places in the
official documentation use $@ as a boolean. Several places in the
interpreter do the same as SvTRUE(ERRSV).
Regards,
John
Until proven otherwise, all those places are bugs. It's true that in
general $@ works fine as a boolean but perl isn't so straightforward
that you can /always/ use it.
Josh