Просмотр исходного кода

sparc: end the clone child with the exit syscall, not exit()

tst-getpid2 kills its child with SIGSEGV on sparc:

  in f
  pid = 57
  Didn't expect signal from child: got `Segmentation fault'

The test is tst-getpid1.c with TEST_CLONE_FLAGS set to CLONE_VM, and
tst-getpid1 and tst-getpid3 pass -- so it is the shared address space
that matters.  The child prints its pid and returns from the function;
it dies afterwards, in the exit path:

  __thread_start:
	mov	%g0, %fp	/* terminate backtrace */
	call	%g2
	 mov	%g3,%o0
	call	exit,0

That is the C library exit(): atexit handlers, destructors, stdio
flush.  In a CLONE_VM child those touch the parent's FILE structures,
on a stack that is an array inside the parent's frame, right after %fp
was zeroed.

The rest of uClibc-ng does not do this.  i386, m68k, riscv64 and hppa
issue the raw exit syscall; arm, powerpc, sh, alpha and mips call
_exit; sparc is the only one calling exit.  It is not inherited from
glibc either -- glibc had "call HIDDEN_JUMPTARGET(_exit),0" here and
still has _exit in our own sparc64 copy of the file.  The underscore
was lost when the file was adopted, in 843d561eb ("sparc specific bits
needed for nptl", 2009).

Use the raw syscall, which is what glibc settled on in 3f823e87ccb
("Call exit directly in clone (BZ #21512)"): _exit lands in exit_group
and tears down the whole thread group, so a thread created with
CLONE_THREAD through clone() takes everything else with it.  The
syscall exits just the caller.

Verified A/B under qemu-system-sparc, same kernel and rootfs, only
libuClibc swapped: before 4 passed / 2 failed with both tst-getpid2
variants segfaulting, after 6 passed / 0 failed, and tst-getpid1 and
tst-getpid3 green in both.

Signed-off-by: Ramin Moussavi <lordrasmus@gmail.com>
ramin 1 неделя назад
Родитель
Сommit
67ae1abdc0
1 измененных файлов с 2 добавлено и 1 удалено
  1. 2 1
      libc/sysdeps/linux/sparc/clone.S

+ 2 - 1
libc/sysdeps/linux/sparc/clone.S

@@ -78,7 +78,8 @@ __thread_start:
 	mov	%g0, %fp	/* terminate backtrace */
 	call	%g2
 	 mov	%g3,%o0
-	call	exit,0
+	set	__NR_exit, %g1
+	ta	0x10
 	 nop
 
 	.size	__thread_start, .-__thread_start