This is the mail archive of the
egcs-bugs@egcs.cygnus.com
mailing list for the EGCS project.
vfork/SPARC problem.
- To: egcs-bugs@egcs.cygnus.com
- Subject: vfork/SPARC problem.
- From: Casper Dik <casper@holland.sun.com>
- Date: Thu, 15 Jul 1999 11:14:54 +0200
I noticed in egcs 2.95 (and as early as I have them, really), that
the 'working vfork" tests fails when you pass "CFLAGS=-O2".
$ gcc -O vfork.c
$ ./a.out
$ gcc -O2 vfork.c
$ ./a.out
Segmentation fault
$ gcc -v
Reading specs from /usr/local/gnu/lib/gcc-lib/sparc-sun-solaris2/2.95/specs
gcc version 2.95 19990712 (prerelease)
This works for gcc 2.8.1
Attached are: vfork.c (a test programma from configure modified to
compile w/o confdefs.
vfork-O1.s: working vfork
vfork-O2.s: failing vfork.
Diffs show:
nop
call vfork, 0
! nop
! sethi %hi(child.3), %o1
cmp %o0, 0
----
nop
call vfork, 0
! sethi %hi(child.3), %l0
cmp %o0, 0
bge .LL4
So the broken code drops the nop in the delay slot
and that causes the %l0 register to be clobbered in the
child and %hi(child.3) to be lost when the parent resumes.
/* Thanks to Paul Eggert for this test. */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#ifdef HAVE_VFORK_H
#include <vfork.h>
#endif
/* On some sparc systems, changes by the child to local and incoming
argument registers are propagated back to the parent.
The compiler is told about this with #include <vfork.h>,
but some compilers (e.g. gcc -O) don't grok <vfork.h>.
Test for this by using a static variable whose address
is put into a register that is clobbered by the vfork. */
static
#ifdef __cplusplus
sparc_address_test (int arg)
#else
sparc_address_test (arg) int arg;
#endif
{
static pid_t child;
if (!child) {
child = vfork ();
if (child < 0) {
perror ("vfork");
_exit(2);
}
if (!child) {
arg = getpid();
write(-1, "", 0);
_exit (arg);
}
}
}
main() {
pid_t parent = getpid ();
pid_t child;
sparc_address_test ();
child = vfork ();
if (child == 0) {
/* Here is another test for sparc vfork register problems.
This test uses lots of local variables, at least
as many local variables as main has allocated so far
including compiler temporaries. 4 locals are enough for
gcc 1.40.3 on a Solaris 4.1.3 sparc, but we use 8 to be safe.
A buggy compiler should reuse the register of parent
for one of the local variables, since it will think that
parent can't possibly be used any more in this routine.
Assigning to the local variable will thus munge parent
in the parent process. */
pid_t
p = getpid(), p1 = getpid(), p2 = getpid(), p3 = getpid(),
p4 = getpid(), p5 = getpid(), p6 = getpid(), p7 = getpid();
/* Convince the compiler that p..p7 are live; otherwise, it might
use the same hardware register for all 8 local variables. */
if (p != p1 || p != p2 || p != p3 || p != p4
|| p != p5 || p != p6 || p != p7)
_exit(1);
/* On some systems (e.g. IRIX 3.3),
vfork doesn't separate parent from child file descriptors.
If the child closes a descriptor before it execs or exits,
this munges the parent's descriptor as well.
Test for this by closing stdout in the child. */
_exit(close(fileno(stdout)) != 0);
} else {
int status;
struct stat st;
while (wait(&status) != child)
;
exit(
/* Was there some problem with vforking? */
child < 0
/* Did the child fail? (This shouldn't happen.) */
|| status
/* Did the vfork/compiler bug occur? */
|| parent != getpid()
/* Did the file descriptor bug occur? */
|| fstat(fileno(stdout), &st) != 0
);
}
}
.file "foo.c"
gcc2_compiled.:
.local child.3
.common child.3,4,4
.section ".rodata"
.align 8
.LLC0:
.asciz "vfork"
.align 8
.LLC1:
.asciz ""
.section ".text"
.align 4
.type sparc_address_test,#function
.proc 04
sparc_address_test:
!#PROLOGUE# 0
save %sp, -112, %sp
!#PROLOGUE# 1
sethi %hi(child.3), %o0
ld [%o0+%lo(child.3)], %o0
cmp %o0, 0
bne .LL3
nop
call vfork, 0
nop
sethi %hi(child.3), %o1
cmp %o0, 0
bge .LL4
st %o0, [%o1+%lo(child.3)]
sethi %hi(.LLC0), %o0
call perror, 0
or %o0, %lo(.LLC0), %o0
call _exit, 0
mov 2, %o0
.LL4:
sethi %hi(child.3), %o0
ld [%o0+%lo(child.3)], %o0
cmp %o0, 0
bne .LL3
nop
call getpid, 0
nop
mov %o0, %l0
mov -1, %o0
sethi %hi(.LLC1), %o1
or %o1, %lo(.LLC1), %o1
call write, 0
mov 0, %o2
call _exit, 0
mov %l0, %o0
.LL3:
ret
restore
.LLfe1:
.size sparc_address_test,.LLfe1-sparc_address_test
.align 4
.global main
.type main,#function
.proc 04
main:
!#PROLOGUE# 0
save %sp, -312, %sp
!#PROLOGUE# 1
call getpid, 0
nop
call sparc_address_test, 0
st %o0, [%fp-216]
call vfork, 0
nop
orcc %o0, 0, %l0
bne .LL13
nop
call getpid, 0
nop
call getpid, 0
mov %o0, %l1
call getpid, 0
mov %o0, %l0
call getpid, 0
mov %o0, %l2
call getpid, 0
mov %o0, %l3
call getpid, 0
mov %o0, %l4
call getpid, 0
mov %o0, %l5
call getpid, 0
mov %o0, %l6
cmp %l1, %l0
bne .LL9
cmp %l1, %l2
bne .LL9
cmp %l1, %l3
bne .LL9
cmp %l1, %l4
bne .LL9
cmp %l1, %l5
bne .LL9
cmp %l1, %l6
bne .LL9
cmp %l1, %o0
be .LL16
sethi %hi(__iob+16), %o0
.LL9:
call _exit, 0
mov 1, %o0
sethi %hi(__iob+16), %o0
.LL16:
call fileno, 0
or %o0, %lo(__iob+16), %o0
call close, 0
nop
subcc %g0, %o0, %g0
call _exit, 0
addx %g0, 0, %o0
b,a .LL10
.LL13:
call wait, 0
add %fp, -212, %o0
cmp %o0, %l0
bne .LL13
cmp %l0, 0
bl .LL15
mov 0, %l1
ld [%fp-212], %o0
cmp %o0, 0
bne,a .LL17
mov 1, %l1
call getpid, 0
nop
ld [%fp-216], %o1
cmp %o1, %o0
bne,a .LL17
mov 1, %l1
sethi %hi(__iob+16), %o0
call fileno, 0
or %o0, %lo(__iob+16), %o0
call fstat, 0
add %fp, -208, %o1
cmp %o0, 0
be .LL17
nop
.LL15:
mov 1, %l1
.LL17:
call exit, 0
mov %l1, %o0
.LL10:
ret
restore
.LLfe2:
.size main,.LLfe2-main
.ident "GCC: (GNU) 2.95 19990712 (prerelease)"
.file "foo.c"
gcc2_compiled.:
.local child.3
.common child.3,4,4
.section ".rodata"
.align 8
.LLC0:
.asciz "vfork"
.align 8
.LLC1:
.asciz ""
.section ".text"
.align 4
.type sparc_address_test,#function
.proc 04
sparc_address_test:
!#PROLOGUE# 0
save %sp, -112, %sp
!#PROLOGUE# 1
sethi %hi(child.3), %o0
ld [%o0+%lo(child.3)], %o1
cmp %o1, 0
bne .LL3
nop
call vfork, 0
sethi %hi(child.3), %l0
cmp %o0, 0
bge .LL4
st %o0, [%l0+%lo(child.3)]
sethi %hi(.LLC0), %o0
call perror, 0
or %o0, %lo(.LLC0), %o0
call _exit, 0
mov 2, %o0
.LL4:
ld [%l0+%lo(child.3)], %o0
cmp %o0, 0
bne .LL3
nop
call getpid, 0
nop
mov %o0, %l0
sethi %hi(.LLC1), %o1
mov 0, %o2
or %o1, %lo(.LLC1), %o1
call write, 0
mov -1, %o0
call _exit, 0
mov %l0, %o0
.LL3:
ret
restore
.LLfe1:
.size sparc_address_test,.LLfe1-sparc_address_test
.align 4
.global main
.type main,#function
.proc 04
main:
!#PROLOGUE# 0
save %sp, -312, %sp
!#PROLOGUE# 1
call getpid, 0
nop
call sparc_address_test, 0
st %o0, [%fp-216]
call vfork, 0
nop
orcc %o0, 0, %l0
bne .LL13
nop
call getpid, 0
nop
call getpid, 0
mov %o0, %l1
call getpid, 0
mov %o0, %l0
call getpid, 0
mov %o0, %l2
call getpid, 0
mov %o0, %l3
call getpid, 0
mov %o0, %l4
call getpid, 0
mov %o0, %l5
call getpid, 0
mov %o0, %l6
cmp %l1, %l0
bne .LL9
cmp %l1, %l2
bne .LL9
cmp %l1, %l3
bne .LL9
cmp %l1, %l4
bne .LL9
cmp %l1, %l5
bne .LL9
cmp %l1, %l6
bne .LL9
cmp %l1, %o0
be .LL16
sethi %hi(__iob+16), %o0
.LL9:
call _exit, 0
mov 1, %o0
sethi %hi(__iob+16), %o0
.LL16:
call fileno, 0
or %o0, %lo(__iob+16), %o0
call close, 0
nop
subcc %g0, %o0, %g0
call _exit, 0
addx %g0, 0, %o0
b,a .LL10
.LL13:
call wait, 0
add %fp, -212, %o0
cmp %o0, %l0
bne .LL13
cmp %l0, 0
bl .LL15
mov 0, %l0
ld [%fp-212], %o0
cmp %o0, 0
bne,a .LL17
mov 1, %l0
call getpid, 0
nop
ld [%fp-216], %o1
cmp %o1, %o0
bne,a .LL17
mov 1, %l0
sethi %hi(__iob+16), %o0
call fileno, 0
or %o0, %lo(__iob+16), %o0
call fstat, 0
add %fp, -208, %o1
cmp %o0, 0
be .LL17
nop
.LL15:
mov 1, %l0
.LL17:
call exit, 0
mov %l0, %o0
.LL10:
ret
restore
.LLfe2:
.size main,.LLfe2-main
.ident "GCC: (GNU) 2.95 19990712 (prerelease)"