Subject: lib/34210: bus error in getdents() on 4.0_BETA with 3.0 binary
To: None <,,>
From: None <>
List: netbsd-bugs
Date: 08/16/2006 02:55:00
>Number:         34210
>Category:       lib
>Synopsis:       bus error in getdents() on 4.0_BETA with 3.0 binary
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    lib-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Wed Aug 16 02:55:00 +0000 2006
>Originator:     Takeshi Nakayama
>Release:        NetBSD 4.0_BETA
System: NetBSD eos 4.0_BETA NetBSD 4.0_BETA (EOS) #0: Tue Aug 15 08:35:41 JST 2006 takeshi@eos:/work/netbsd-4/src/sys/arch/sparc64/compile/EOS sparc64
Architecture: sparc64
Machine: sparc64

	Running 3.0 binary on 4.0_BETA (or -current) causes bus error as

% uname -r
% file /usr/pkg/bin/zsh
/usr/pkg/bin/zsh: ELF 64-bit MSB executable, SPARC V9, version 1 (SYSV), for NetBSD 3.0, dynamically linked (uses shared libs), for NetBSD 3.0, stripped
% /usr/pkg/bin/zsh
(do command completion or filename expansion on directory which has many files)
Bus error  /usr/pkg/bin/zsh

	Debugger traces are here. It seems that the cause is 64-bit load on
	non 8-bytes aligned address.

(gdb) run
Starting program: /usr/pkg/bin/zsh 
Program received signal SIGBUS, Bus error.
0x00000000404dbef0 in getdents () from /lib/
(gdb) where
#0  0x00000000404dbef0 in getdents () from /lib/
#1  0x00000000404dcb90 in __opendir2 () from /lib/
#2  0x000000004160a610 in getcpat () from /usr/pkg/lib/zsh/4.2.6/zsh/
#3  0x000000004160dfd0 in getcpat () from /usr/pkg/lib/zsh/4.2.6/zsh/
(gdb) disassemble 0x404dbee8 0x404dbef8
Dump of assembler code from 0x404dbee8 to 0x404dbef8:
0x404dbee8 <getdents+72>:       lduh  [ %g4 + 0xa ], %g1
0x404dbeec <getdents+76>:       cmp  %g3, 0x100
0x404dbef0 <getdents+80>:       ldx  [ %g4 ], %g2
0x404dbef4 <getdents+84>:       movcc  %icc, %l1, %g1
End of assembler dump.
(gdb) print/x $g4
$1 = 0x24178c

	Run binaries which contain opendir()/getdents() and compiled on 3.0
	on 4.0_BETA/sparc64.

	A quick and dirty fix is the following. This patch avoid 64-bit load.

	Another candidate is that return value of getdents() always align to
	8-bytes to avoid an unaligned buffer address in the next call.

Index: compat_getdents.c
RCS file: /cvsroot/src/lib/libc/compat/sys/compat_getdents.c,v
retrieving revision 1.1
diff -u -d -r1.1 compat_getdents.c
--- compat_getdents.c	13 Sep 2005 01:44:09 -0000	1.1
+++ compat_getdents.c	15 Aug 2006 05:45:49 -0000
@@ -73,7 +73,7 @@
 	for (; ndp < endp; ndp = nndp) {
 		nndp = _DIRENT_NEXT(ndp);
-		odp->d_ino = (u_int32_t)ndp->d_ino;
+		odp->d_ino = ((u_int32_t *)(void *)&ndp->d_ino)[_QUAD_LOWWORD];
 		if (ndp->d_namlen >= sizeof(odp->d_name))
 			odp->d_namlen = sizeof(odp->d_name) - 1;