Module Name:    src
Committed By:   riastradh
Date:           Thu Apr  4 00:46:42 UTC 2024

Modified Files:
        src/lib/libc/arch/i386/gen: setjmp.S sigsetjmp.S
        src/tests/lib/libc/setjmp: t_sigstack.c

Log Message:
i386 longjmp: Restore stack first, then signal mask.

Otherwise, a pending signal may be delivered on the wrong stack when
we restore the signal mask.

While here:

- Tidy the code a little bit.
- Sprinkle comments to explain what's going on.
- Use forward branches for statically predicted not-taken.
  => val==0 is unlikely in longjmp

PR lib/57946


To generate a diff of this commit:
cvs rdiff -u -r1.17 -r1.18 src/lib/libc/arch/i386/gen/setjmp.S
cvs rdiff -u -r1.18 -r1.19 src/lib/libc/arch/i386/gen/sigsetjmp.S
cvs rdiff -u -r1.8 -r1.9 src/tests/lib/libc/setjmp/t_sigstack.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/lib/libc/arch/i386/gen/setjmp.S
diff -u src/lib/libc/arch/i386/gen/setjmp.S:1.17 src/lib/libc/arch/i386/gen/setjmp.S:1.18
--- src/lib/libc/arch/i386/gen/setjmp.S:1.17	Fri May 23 03:05:56 2014
+++ src/lib/libc/arch/i386/gen/setjmp.S	Thu Apr  4 00:46:41 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: setjmp.S,v 1.17 2014/05/23 03:05:56 uebayasi Exp $	*/
+/*	$NetBSD: setjmp.S,v 1.18 2024/04/04 00:46:41 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 1990 The Regents of the University of California.
@@ -36,7 +36,7 @@
 
 #include <machine/asm.h>
 #if defined(LIBC_SCCS)
-	RCSID("$NetBSD: setjmp.S,v 1.17 2014/05/23 03:05:56 uebayasi Exp $")
+	RCSID("$NetBSD: setjmp.S,v 1.18 2024/04/04 00:46:41 riastradh Exp $")
 #endif
 
 /*
@@ -49,12 +49,24 @@
  * The previous signal state is restored.
  */
 
+/*
+ * setjmp(jmp_buf env@esp[4,8))
+ *
+ * ELF symbol: __setjmp14, because the size of jmp_buf changed on some
+ * platforms in 1.4.
+ */
 ENTRY(__setjmp14)
-	movl	4(%esp),%ecx
-	movl	0(%esp),%edx
-	movl	%edx, 0(%ecx)
-	movl	%ebx, 4(%ecx)
-	movl	%esp, 8(%ecx)
+	/*
+	 * Save the callee-saves registers: %ebp, %ebx, %edi, %esi,
+	 * plus %esp and the return address on the stack since it
+	 * will be overwritten if the caller makes any subroutine
+	 * calls before longjmp.
+	 */
+	movl	4(%esp),%ecx		/* ecx := env */
+	movl	0(%esp),%edx		/* edx := return address */
+	movl	%edx,0(%ecx)
+	movl	%ebx,4(%ecx)
+	movl	%esp,8(%ecx)
 	movl	%ebp,12(%ecx)
 	movl	%esi,16(%ecx)
 	movl	%edi,20(%ecx)
@@ -63,49 +75,65 @@ ENTRY(__setjmp14)
 	leal	24(%ecx),%edx
 
 	PIC_PROLOGUE
-	pushl	%edx
-	pushl	$0
-	pushl	$0
+	pushl	%edx			/* oset (signal mask saved to) */
+	pushl	$0			/* set := NULL */
+	pushl	$0			/* how := 0 (ignored) */
 #ifdef __PIC__
 	call	PIC_PLT(_C_LABEL(__sigprocmask14))
 #else
 	call	_C_LABEL(__sigprocmask14)
 #endif
-	addl	$12,%esp
+	addl	$12,%esp		/* pop sigprocmask args */
 	PIC_EPILOGUE
 
-	xorl	%eax,%eax
+	xorl	%eax,%eax		/* return 0 first time around */
 	ret
 END(__setjmp14)
 
+/*
+ * longjmp(jmp_buf env@esp[4,8), int val@[8,12))
+ *
+ * ELF symbol: __longjmp14, because the size of jmp_buf changed on some
+ * platforms in 1.4.
+ */
 ENTRY(__longjmp14)
+	/*
+	 * Restore the callee-saves registers: %ebp, %ebx, %edi, %esi,
+	 * plus %esp and the return address on the stack.
+	 */
+	movl	4(%esp),%edx		/* edx := env */
+	movl	8(%esp),%eax		/* eax := val */
+	movl	0(%edx),%ecx		/* ecx := return address */
+	movl	4(%edx),%ebx
+	movl	8(%edx),%esp
+	movl	12(%edx),%ebp
+	movl	16(%edx),%esi
+	movl	20(%edx),%edi
+	movl	%ecx,0(%esp)		/* restore return address */
+
 	/* Restore the signal mask. */
-	movl	4(%esp),%ecx
-	leal	24(%ecx),%edx
+	leal	24(%edx),%edx
+
+	pushl	%eax			/* save val@eax */
 
 	PIC_PROLOGUE
-	pushl	$0
-	pushl	%edx
-	pushl	$3			/* SIG_SETMASK */
+	pushl	$0			/* oset := NULL */
+	pushl	%edx			/* set (signal mask restored from) */
+	pushl	$3			/* how := SIG_SETMASK */
 #ifdef __PIC__
 	call	PIC_PLT(_C_LABEL(__sigprocmask14))
 #else
 	call	_C_LABEL(__sigprocmask14)
 #endif
-	addl	$12,%esp
+	addl	$12,%esp		/* pop sigprocmask args */
 	PIC_EPILOGUE
 
-	movl	4(%esp),%edx
-	movl	8(%esp),%eax
-	movl	0(%edx),%ecx
-	movl	4(%edx),%ebx
-	movl	8(%edx),%esp
-	movl	12(%edx),%ebp
-	movl	16(%edx),%esi
-	movl	20(%edx),%edi
-	testl	%eax,%eax
-	jnz	1f
-	incl	%eax
-1:	movl	%ecx,0(%esp)
-	ret
+	popl	%eax			/* restore val@eax */
+
+	testl	%eax,%eax		/* val == 0? */
+	jz	3f			/* jump if val == 0 */
+	ret				/* return val@eax */
+
+3:	incl	%eax			/* val@eax := 1 */
+	ret				/* return val@eax */
 END(__longjmp14)

Index: src/lib/libc/arch/i386/gen/sigsetjmp.S
diff -u src/lib/libc/arch/i386/gen/sigsetjmp.S:1.18 src/lib/libc/arch/i386/gen/sigsetjmp.S:1.19
--- src/lib/libc/arch/i386/gen/sigsetjmp.S:1.18	Fri May 23 02:34:19 2014
+++ src/lib/libc/arch/i386/gen/sigsetjmp.S	Thu Apr  4 00:46:41 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: sigsetjmp.S,v 1.18 2014/05/23 02:34:19 uebayasi Exp $	*/
+/*	$NetBSD: sigsetjmp.S,v 1.19 2024/04/04 00:46:41 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 1990 The Regents of the University of California.
@@ -36,76 +36,104 @@
 
 #include <machine/asm.h>
 #if defined(LIBC_SCCS)
-	RCSID("$NetBSD: sigsetjmp.S,v 1.18 2014/05/23 02:34:19 uebayasi Exp $")
+	RCSID("$NetBSD: sigsetjmp.S,v 1.19 2024/04/04 00:46:41 riastradh Exp $")
 #endif
 
+/*
+ * sigsetjmp(sigjmp_buf env@esp[4,8), savemask@esp[8,12))
+ *
+ * ELF symbol: __sigsetjmp14, because the size of sigjmp_buf changed on
+ * some platforms in 1.4.
+ */
 ENTRY(__sigsetjmp14)
-	movl	4(%esp),%ecx
-	movl	0(%esp),%edx
-	movl	%edx, 0(%ecx)
-	movl	%ebx, 4(%ecx)
-	movl	%esp, 8(%ecx)
+	/*
+	 * Save the callee-saves registers: %ebp, %ebx, %edi, %esi,
+	 * plus %esp and the return address on the stack since it
+	 * will be overwritten if the caller makes any subroutine
+	 * calls before siglongjmp.
+	 */
+	movl	4(%esp),%ecx		/* ecx := env */
+	movl	0(%esp),%edx		/* edx := return address */
+	movl	%edx,0(%ecx)
+	movl	%ebx,4(%ecx)
+	movl	%esp,8(%ecx)
 	movl	%ebp,12(%ecx)
 	movl	%esi,16(%ecx)
 	movl	%edi,20(%ecx)
 
 	/* Check if we should save the signal mask, and remember it. */
-	movl	8(%esp),%eax
+	movl	8(%esp),%eax		/* eax := savemask */
 	movl	%eax,40(%ecx)
-	testl	%eax,%eax
-	jz	2f			/* no, skip */
+	testl	%eax,%eax		/* savemask == 0? */
+	jz	2f			/* jump if savemask == 0 */
 
 	/* Get the signal mask. */
 	leal	24(%ecx),%edx
 
 	PIC_PROLOGUE
-	pushl	%edx
-	pushl	$0
-	pushl	$0
+	pushl	%edx			/* oset (signal mask saved to) */
+	pushl	$0			/* set := NULL */
+	pushl	$0			/* how := 0 (ignored) */
 #ifdef __PIC__
 	call	PIC_PLT(_C_LABEL(__sigprocmask14))
 #else
 	call	_C_LABEL(__sigprocmask14)
 #endif
-	addl	$12,%esp
+	addl	$12,%esp		/* pop sigprocmask args */
 	PIC_EPILOGUE
 
-2:	xorl	%eax,%eax
+2:	xorl	%eax,%eax		/* return 0 first time around */
 	ret
 END(__sigsetjmp14)
 
+/*
+ * siglongjmp(sigjmp_buf env@esp[4,8), int val@[8,12))
+ *
+ * ELF symbol: __siglongjmp14, because the size of sigjmp_buf changed
+ * on some platforms in 1.4.
+ */
 ENTRY(__siglongjmp14)
+	/*
+	 * Restore the callee-saves registers: %ebp, %ebx, %edi, %esi,
+	 * plus %esp and the return address on the stack.
+	 */
+	movl	4(%esp),%edx		/* edx := env */
+	movl	8(%esp),%eax		/* eax := val */
+	movl	0(%edx),%ecx		/* ecx := return address */
+	movl	4(%edx),%ebx
+	movl	8(%edx),%esp
+	movl	12(%edx),%ebp
+	movl	16(%edx),%esi
+	movl	20(%edx),%edi
+	movl	%ecx,0(%esp)		/* restore return address */
+
 	/* Check to see if we need to restore the signal mask. */
-	movl	4(%esp),%ecx
-	cmpl	$0,40(%ecx)
-	jz	2f			/* no, skip */
+	cmpl	$0,40(%edx)		/* savemask == 0 */
+	jz	2f			/* jump if savemask == 0 */
 
 	/* Restore the signal mask. */
-	leal	24(%ecx),%edx
+	leal	24(%edx),%edx
+
+	pushl	%eax			/* save val@eax */
 
 	PIC_PROLOGUE
-	pushl	$0
-	pushl	%edx
-	pushl	$3			/* SIG_SETMASK */
+	pushl	$0			/* oset := NULL */
+	pushl	%edx			/* set (signal mask restored from) */
+	pushl	$3			/* how := SIG_SETMASK */
 #ifdef __PIC__
 	call	PIC_PLT(_C_LABEL(__sigprocmask14))
 #else
 	call	_C_LABEL(__sigprocmask14)
 #endif
-	addl	$12,%esp
+	addl	$12,%esp		/* pop sigprocmask args */
 	PIC_EPILOGUE
 
-2:	movl	4(%esp),%edx
-	movl	8(%esp),%eax
-	movl	0(%edx),%ecx
-	movl	4(%edx),%ebx
-	movl	8(%edx),%esp
-	movl	12(%edx),%ebp
-	movl	16(%edx),%esi
-	movl	20(%edx),%edi
-	testl	%eax,%eax
-	jnz	3f
-	incl	%eax
-3:	movl	%ecx,0(%esp)
-	ret
+	popl	%eax			/* restore val@eax */
+
+2:	testl	%eax,%eax		/* val == 0? */
+	jz	3f			/* jump if val == 0 */
+	ret				/* return val@eax */
+
+3:	incl	%eax			/* val@eax := 1 */
+	ret				/* return val@eax */
 END(__siglongjmp14)

Index: src/tests/lib/libc/setjmp/t_sigstack.c
diff -u src/tests/lib/libc/setjmp/t_sigstack.c:1.8 src/tests/lib/libc/setjmp/t_sigstack.c:1.9
--- src/tests/lib/libc/setjmp/t_sigstack.c:1.8	Thu Apr  4 00:46:30 2024
+++ src/tests/lib/libc/setjmp/t_sigstack.c	Thu Apr  4 00:46:42 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: t_sigstack.c,v 1.8 2024/04/04 00:46:30 riastradh Exp $	*/
+/*	$NetBSD: t_sigstack.c,v 1.9 2024/04/04 00:46:42 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 2024 The NetBSD Foundation, Inc.
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: t_sigstack.c,v 1.8 2024/04/04 00:46:30 riastradh Exp $");
+__RCSID("$NetBSD: t_sigstack.c,v 1.9 2024/04/04 00:46:42 riastradh Exp $");
 
 #include <setjmp.h>
 #include <signal.h>
@@ -81,10 +81,18 @@ on_sigusr1(int signo, siginfo_t *si, voi
 	 * On some architectures, this is broken.  Those that appear to
 	 * get this right are:
 	 *
-	 *	aarch64, alpha, m68k, or1k, powerpc, powerpc64, riscv,
-	 *	vax, x86_64
+	 *	aarch64
+	 *	alpha
+	 *	i386
+	 *	m68k
+	 *	or1k
+	 *	powerpc
+	 *	powerpc64
+	 *	riscv
+	 *	vax
+	 *	x86_64
 	 */
-#if defined __arm__ || defined __hppa__ || defined __i386__ || \
+#if defined __arm__ || defined __hppa__ || \
     defined __ia64__ || defined __mips__ || defined __sh3__ || \
     defined __sparc__ || defined __sparc64__
 	if (nentries > 0)

Reply via email to