This is the mail archive of the egcs-bugs@egcs.cygnus.com mailing list for the EGCS project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

vfork/SPARC problem.


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)"

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]