Front page | perl.perl5.porters |
Postings from November 2008
[perl #60574] sv_upgrade() loses 64-bit alignment, causing SIGBUS on sparc
Thread Next
From:
Niko Tyni
Date:
November 16, 2008 07:46
Subject:
[perl #60574] sv_upgrade() loses 64-bit alignment, causing SIGBUS on sparc
Message ID:
rt-3.6.HEAD-10965-1226837774-412.60574-75-0@perl.org
# New Ticket Created by Niko Tyni
# Please include the string: [perl #60574]
# in the subject line of all future correspondence about this issue.
# <URL: http://rt.perl.org/rt3/Ticket/Display.html?id=60574 >
This is a bug report for perl from Niko Tyni <ntyni@debian.org>
generated with the help of perlbug 1.39 running under perl 5.11.0.
-----------------------------------------------------------------
As seen in <http://bugs.debian.org/505415>, calling sv_chop() or otherwise
upgrading an SV can result in an unaligned 64-bit access on the sparc
architecture.
This was uncovered by the JSON-XS-2.23 test suite failing for us on
sparc with Perl 5.10.0. The failure is a SIGBUS that only occurs with
gcc optimization level -O2 or higher.
On 5.10.0, calling sv_chop() will upgrade the SV into an SVt_PVIV due
to the 'OOK hack'. The upgrade will allocate a new memory area for
sv->sv_any, possibly losing the 64-bit alignment in the process.
Calling the SvGROW() macro afterwards will cast sv->sv_any to an XPV
pointer, which should be 64-bit aligned according to __alignof__().
With -O2, gcc will compile the code using a doubleword load instruction
(ldd) that fails with a SIGBUS if the 64-bit alignment has been lost.
I'm attaching a test program that mimics what JSON-XS does when compiled
with -DUSE_CHOP. The test program compiled at -O2 dies with a SIGBUS
for me on the second doit() call.
This particular failure mode has been fixed in bleadperl with change
32836, which reimplements the 'OOK hack' in a different way so that the
SV isn't upgraded anymore. The failure is still present in maint-5.10,
as of change 34715.
However, it seems to me that this is a more general problem that should
be fixed by making sv_upgrade() somehow retain the alignment of the
existing SV.
The same test program, when compiled with -O2 but without -DUSE_CHOP
(making it explicitly call SvUPGRADE() instead), dies here on current
bleadperl (change 34714) with a SIGBUS on the second doit() call.
Note that using a debugging perl build (-DDEBUGGING) seems to defeat the crash.
Details for the bleadperl SIGBUS:
Program received signal SIGBUS, Bus error.
[Switching to Thread 0xf7aca6b0 (LWP 32099)]
0x0001070c in doit () at crash.c:15
15 SvGROW (sv, SvCUR (sv) + 1);
(gdb) bt
#0 0x0001070c in doit () at crash.c:15
#1 0x00010774 in main (argc=<value optimized out>, argv=0xff995984, env=0xff995990) at crash.c:25
(gdb) print *sv
$1 = {sv_any = 0x2569c, sv_refcnt = 1, sv_flags = 17413, sv_u = {svu_iv = 157328, svu_uv = 157328,
svu_rv = 0x26690, svu_pv = 0x26690 "foo", svu_array = 0x26690, svu_hash = 0x26690, svu_gp = 0x26690}}
The preprocessor output for the above SvGROW() invocation is
(((XPV*) (sv)->sv_any)->xpv_len < (((XPV*) (sv)->sv_any)->xpv_cur + 1) ? Perl_sv_grow(my_perl, sv,((XPV*) (sv)->sv_any)->xpv_cur + 1) : ((sv)->sv_u.svu_pv));
The instruction that causes the bus error is a double-word load (ldd)
during the first comparison. The compiler (gcc -O2) is using the
double-word instruction to load both xpv_cur and xpv_len in one go.
0x00010708 <doit+56>: ld [ %i1 ], %g1
0x0001070c <doit+60>: ldd [ %g1 + 8 ], %g2
0x00010710 <doit+64>: add %g2, 1, %i2
0x00010714 <doit+68>: cmp %g3, %i2
Quoting Julien Cristau in the Debian bug:
> __alignof__(XPV) is 8, so gcc is allowed to assume that any XPV is
> 64-bit aligned, as far as I can tell. xpv_cur's offset is 8, so it
> should also be 64-bit aligned.
-----------------------------------------------------------------
---
Flags:
category=core
severity=medium
---
Site configuration information for perl 5.11.0:
Configured by niko at Sat Nov 15 18:40:57 UTC 2008.
Summary of my perl5 (revision 5 version 11 subversion 0) configuration:
Platform:
osname=linux, osvers=2.6.24-etchnhalf.1-sparc64-smp, archname=sparc-linux-gnu-thread-multi
uname='linux raakel 2.6.24-etchnhalf.1-sparc64-smp #1 smp tue oct 14 04:04:33 utc 2008 sparc64 gnulinux '
config_args='-Dusethreads -Duselargefiles -Dcccdlflags=-fPIC -Darchname=sparc-linux-gnu -Uafs -Ud_csh -Ud_ualarm -Uusesfio -Uusenm -DDEBUGGING=-g -Dprefix=/home/niko/bleadperl -Dusedevel -Doptimize=-O2 -Duseshrplib -Dlibperl=libperl.so.5.11.0 -des'
hint=recommended, useposix=true, d_sigaction=define
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 -pipe -fstack-protector -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64',
optimize='-O2 -g',
cppflags='-D_REENTRANT -D_GNU_SOURCE -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include'
ccversion='', gccversion='4.3.2', gccosandvers=''
intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=4321
d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16
ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
alignbytes=8, prototype=define
Linker and Libraries:
ld='cc', ldflags =' -fstack-protector -L/usr/local/lib'
libpth=/usr/local/lib /lib /usr/lib /lib64 /usr/lib64
libs=-lnsl -lgdbm -ldb -ldl -lm -lcrypt -lutil -lpthread -lc -lgdbm_compat
perllibs=-lnsl -ldl -lm -lcrypt -lutil -lpthread -lc
libc=/lib/libc-2.7.so, so=so, useshrplib=true, libperl=libperl.so.5.11.0
gnulibc_version='2.7'
Dynamic Linking:
dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E -Wl,-rpath,/home/niko/bleadperl/lib/5.11.0/sparc-linux-gnu-thread-multi/CORE'
cccdlflags='-fPIC', lddlflags='-shared -O2 -g -L/usr/local/lib -fstack-protector'
Locally applied patches:
DEVEL
---
@INC for perl 5.11.0:
/home/niko/bleadperl/lib/5.11.0/sparc-linux-gnu-thread-multi
/home/niko/bleadperl/lib/5.11.0
/home/niko/bleadperl/lib/site_perl/5.11.0/sparc-linux-gnu-thread-multi
/home/niko/bleadperl/lib/site_perl/5.11.0
.
---
Environment for perl 5.11.0:
HOME=/home/niko
LANG (unset)
LANGUAGE (unset)
LD_LIBRARY_PATH (unset)
LOGDIR (unset)
PATH=/usr/local/bin:/usr/bin:/bin:/usr/games
PERL_BADLANG (unset)
SHELL=/bin/sh
Thread Next
-
[perl #60574] sv_upgrade() loses 64-bit alignment, causing SIGBUS on sparc
by Niko Tyni