Module Name:    src
Committed By:   martin
Date:           Fri Aug 23 16:59:53 UTC 2024

Modified Files:
        src/distrib/sets/lists/debug [netbsd-9]: mi
        src/distrib/sets/lists/tests [netbsd-9]: mi
        src/lib/libc/arch/arm/gen [netbsd-9]: setjmp.S
        src/lib/libc/arch/i386/gen [netbsd-9]: setjmp.S sigsetjmp.S
        src/lib/libc/arch/sh3/gen [netbsd-9]: setjmp.S sigsetjmp.S
        src/lib/libc/arch/x86_64/gen [netbsd-9]: __setjmp14.S __sigsetjmp14.S
        src/tests/lib/libc/setjmp [netbsd-9]: Makefile
Added Files:
        src/tests/lib/libc/setjmp [netbsd-9]: t_sigstack.c

Log Message:
Pull up following revision(s) (requested by riastradh in ticket #795):

        tests/lib/libc/setjmp/Makefile: revision 1.3
        distrib/sets/lists/debug/mi: revision 1.425
        lib/libc/arch/sh3/gen/setjmp.S: revision 1.12
        lib/libc/arch/i386/gen/sigsetjmp.S: revision 1.19
        lib/libc/arch/x86_64/gen/__setjmp14.S: revision 1.4
        tests/lib/libc/setjmp/t_sigstack.c: revision 1.10
        tests/lib/libc/setjmp/t_sigstack.c: revision 1.11
        tests/lib/libc/setjmp/t_sigstack.c: revision 1.12
        tests/lib/libc/setjmp/t_sigstack.c: revision 1.1
        lib/libc/arch/sh3/gen/sigsetjmp.S: revision 1.11
        tests/lib/libc/setjmp/t_sigstack.c: revision 1.2
        tests/lib/libc/setjmp/t_sigstack.c: revision 1.3
        tests/lib/libc/setjmp/t_sigstack.c: revision 1.4
        tests/lib/libc/setjmp/t_sigstack.c: revision 1.5
        tests/lib/libc/setjmp/t_sigstack.c: revision 1.6
        lib/libc/arch/arm/gen/setjmp.S: revision 1.19
        tests/lib/libc/setjmp/t_sigstack.c: revision 1.7
        tests/lib/libc/setjmp/t_sigstack.c: revision 1.8
        tests/lib/libc/setjmp/t_sigstack.c: revision 1.9
        lib/libc/arch/i386/gen/setjmp.S: revision 1.18
        lib/libc/arch/x86_64/gen/__sigsetjmp14.S: revision 1.4
        distrib/sets/lists/tests/mi: revision 1.1306 (patch)

longjmp(3): Add test for PR lib/57946.

longjmp(3): Paranoia: more error checking in PR lib/57946 test.

longjmp(3): Test signal mask vs stack restore with siglongjmp too.
PR lib/57946

longjmp(3) t_sigstack: Print which entry failed.
PR lib/57946

longjmp(3) t_sigstack: Note aarch64 seems to DTRT.
But only by code inspection; it appears to have another problem: on
re-entry, the signal handler is called on the normal stack, not on
the alternate signal stack.
PR lib/57946

longjmp(3) t_sigstack: Use a sigaltstack per handler entry.
longjmp evidently doesn't reset the state of whether the process is
executing on the alternate signal stack.  So when we re-enter the
signal handler, the alternate stack appears to be still in use, and
the system chooses the original stack for the second call to the
signal handler -- which trips our assertion asking to verify that the
signal handler is always using an alternate stack.

Not strictly necessary for the signal handler to use an alternate
stack on re-entry, but this makes it clearer that the signal handler
itself is always using the alternate stack so we can verify that the
interrupted code is _not_ in the signal handler.
With this change, the test now passes on aarch64.
PR lib/57946

longjmp(3) t_sigstack: Fix fencepost error.
Extremely unlikely to cause trouble, but let's just turn that into
`never' to keep it easier for readers.
PR lib/57946

amd64 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 `xorl %eXX,%eXX' instead of `xorq %rXX,%rXX'.
  => Same effect, one byte shorter, breaks dep chain on more uarches.
- Use forward branches for statically predicted not-taken.
  => val==0 is unlikely in longjmp
PR lib/57946

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

arm 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:
- Move the botched sp and lr tests earlier.
PR lib/57946
arm has been fixed

tests/lib/libc/setjmp/t_sigstack: Add missing comment for 1.10.
PR lib/57946

sh3: siglongjmp - restore register context first (PR lib/57946)


To generate a diff of this commit:
cvs rdiff -u -r1.285.2.7 -r1.285.2.8 src/distrib/sets/lists/debug/mi
cvs rdiff -u -r1.818.2.5 -r1.818.2.6 src/distrib/sets/lists/tests/mi
cvs rdiff -u -r1.17 -r1.17.28.1 src/lib/libc/arch/arm/gen/setjmp.S
cvs rdiff -u -r1.17 -r1.17.26.1 src/lib/libc/arch/i386/gen/setjmp.S
cvs rdiff -u -r1.18 -r1.18.26.1 src/lib/libc/arch/i386/gen/sigsetjmp.S
cvs rdiff -u -r1.10 -r1.10.88.1 src/lib/libc/arch/sh3/gen/setjmp.S
cvs rdiff -u -r1.9 -r1.9.88.1 src/lib/libc/arch/sh3/gen/sigsetjmp.S
cvs rdiff -u -r1.3 -r1.3.26.1 src/lib/libc/arch/x86_64/gen/__setjmp14.S \
    src/lib/libc/arch/x86_64/gen/__sigsetjmp14.S
cvs rdiff -u -r1.2 -r1.2.46.1 src/tests/lib/libc/setjmp/Makefile
cvs rdiff -u -r0 -r1.12.4.2 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/distrib/sets/lists/debug/mi
diff -u src/distrib/sets/lists/debug/mi:1.285.2.7 src/distrib/sets/lists/debug/mi:1.285.2.8
--- src/distrib/sets/lists/debug/mi:1.285.2.7	Mon Mar 25 14:26:15 2024
+++ src/distrib/sets/lists/debug/mi	Fri Aug 23 16:59:52 2024
@@ -1,4 +1,4 @@
-# $NetBSD: mi,v 1.285.2.7 2024/03/25 14:26:15 martin Exp $
+# $NetBSD: mi,v 1.285.2.8 2024/08/23 16:59:52 martin Exp $
 ./etc/mtree/set.debug                           comp-sys-root
 ./usr/lib					comp-sys-usr		compatdir
 ./usr/lib/i18n/libBIG5_g.a			comp-c-debuglib		debuglib,compatfile
@@ -2025,6 +2025,7 @@
 ./usr/libdata/debug/usr/tests/lib/libc/rpc/t_rpc.debug			tests-lib-debug		debug,atf,compattestfile
 ./usr/libdata/debug/usr/tests/lib/libc/rpc/t_xdr.debug			tests-lib-debug		debug,atf,compattestfile
 ./usr/libdata/debug/usr/tests/lib/libc/setjmp/t_setjmp.debug		tests-lib-debug		debug,atf,compattestfile
+./usr/libdata/debug/usr/tests/lib/libc/setjmp/t_sigstack.debug		tests-lib-debug		debug,atf,compattestfile
 ./usr/libdata/debug/usr/tests/lib/libc/setjmp/t_threadjmp.debug		tests-lib-debug		debug,atf,compattestfile
 ./usr/libdata/debug/usr/tests/lib/libc/ssp/h_fgets.debug		tests-lib-debug		debug,atf,ssp,compattestfile
 ./usr/libdata/debug/usr/tests/lib/libc/ssp/h_getcwd.debug		tests-lib-debug		debug,atf,ssp,compattestfile

Index: src/distrib/sets/lists/tests/mi
diff -u src/distrib/sets/lists/tests/mi:1.818.2.5 src/distrib/sets/lists/tests/mi:1.818.2.6
--- src/distrib/sets/lists/tests/mi:1.818.2.5	Mon Mar 25 14:26:15 2024
+++ src/distrib/sets/lists/tests/mi	Fri Aug 23 16:59:53 2024
@@ -1,4 +1,4 @@
-# $NetBSD: mi,v 1.818.2.5 2024/03/25 14:26:15 martin Exp $
+# $NetBSD: mi,v 1.818.2.6 2024/08/23 16:59:53 martin Exp $
 #
 # Note: don't delete entries from here - mark them as "obsolete" instead.
 #
@@ -2701,6 +2701,7 @@
 ./usr/tests/lib/libc/setjmp/Atffile		tests-lib-tests		compattestfile,atf
 ./usr/tests/lib/libc/setjmp/Kyuafile		tests-lib-tests		compattestfile,atf,kyua
 ./usr/tests/lib/libc/setjmp/t_setjmp		tests-lib-tests		compattestfile,atf
+./usr/tests/lib/libc/setjmp/t_sigstack		tests-lib-tests		compattestfile,atf
 ./usr/tests/lib/libc/setjmp/t_threadjmp		tests-lib-tests		compattestfile,atf
 ./usr/tests/lib/libc/ssp			tests-lib-tests	compattestfile,atf
 ./usr/tests/lib/libc/ssp/Atffile		tests-lib-tests		compattestfile,atf,ssp

Index: src/lib/libc/arch/arm/gen/setjmp.S
diff -u src/lib/libc/arch/arm/gen/setjmp.S:1.17 src/lib/libc/arch/arm/gen/setjmp.S:1.17.28.1
--- src/lib/libc/arch/arm/gen/setjmp.S:1.17	Sat Nov 30 20:20:42 2013
+++ src/lib/libc/arch/arm/gen/setjmp.S	Fri Aug 23 16:59:52 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: setjmp.S,v 1.17 2013/11/30 20:20:42 joerg Exp $	*/
+/*	$NetBSD: setjmp.S,v 1.17.28.1 2024/08/23 16:59:52 martin Exp $	*/
 
 /*
  * Copyright (c) 1997 Mark Brinicombe
@@ -142,6 +142,25 @@ ENTRY(__longjmp14)
 	cmp	r3, ip
 	bne	.Lbotch
 
+	/* Validate sp and lr */
+	ldr	r2, [r0, #(_JB_REG_R13 * 4)]
+#if defined(__thumb__) && defined(_ARM_ARCH_T2)
+	cbz	r2, .Lbotch
+#else
+	cmp	r2, #0
+	beq	.Lbotch
+#endif
+
+	ldr	r3, [r0, #(_JB_REG_R14 * 4)]
+#if defined(__thumb__) && defined(_ARM_ARCH_T2)
+	cbz	r3, .Lbotch
+#else
+	cmp	r3, #0
+	beq	.Lbotch
+#endif
+	mov	sp, r2
+	mov	lr, r3
+
 	/* Restore the signal mask. */
 	push	{r0-r2, lr}
 	movs	r2, #0
@@ -186,25 +205,6 @@ ENTRY(__longjmp14)
 	adds	r0, r0, #4	/* skip ip(r12) */
 #endif
 
-	ldmia	r0!, {r2-r3}
-
-	/* Validate sp and lr */
-#if defined(__thumb__) && defined(_ARM_ARCH_T2)
-	cbz	r2, .Lbotch
-#else
-	cmp	r2, #0
-	beq	.Lbotch
-#endif
-	mov	sp, r2
-
-#if defined(__thumb__) && defined(_ARM_ARCH_T2)
-	cbz	r3, .Lbotch
-#else
-	cmp	r3, #0
-	beq	.Lbotch
-#endif
-	mov	lr, r3
-
 	/* Set return value */
 	movs	r0, r1
 #if !defined(__thumb__)

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.17.26.1
--- 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	Fri Aug 23 16:59:52 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: setjmp.S,v 1.17 2014/05/23 03:05:56 uebayasi Exp $	*/
+/*	$NetBSD: setjmp.S,v 1.17.26.1 2024/08/23 16:59:52 martin 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.17.26.1 2024/08/23 16:59:52 martin 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.18.26.1
--- 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	Fri Aug 23 16:59:52 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: sigsetjmp.S,v 1.18 2014/05/23 02:34:19 uebayasi Exp $	*/
+/*	$NetBSD: sigsetjmp.S,v 1.18.26.1 2024/08/23 16:59:52 martin 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.18.26.1 2024/08/23 16:59:52 martin 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/lib/libc/arch/sh3/gen/setjmp.S
diff -u src/lib/libc/arch/sh3/gen/setjmp.S:1.10 src/lib/libc/arch/sh3/gen/setjmp.S:1.10.88.1
--- src/lib/libc/arch/sh3/gen/setjmp.S:1.10	Thu Jan  5 19:21:37 2006
+++ src/lib/libc/arch/sh3/gen/setjmp.S	Fri Aug 23 16:59:52 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: setjmp.S,v 1.10 2006/01/05 19:21:37 uwe Exp $	*/
+/*	$NetBSD: setjmp.S,v 1.10.88.1 2024/08/23 16:59:52 martin Exp $	*/
 
 /*-
  * Copyright (c) 1990 The Regents of the University of California.
@@ -38,7 +38,7 @@
 #include <machine/setjmp.h>
 
 #if defined(LIBC_SCCS)
-	RCSID("$NetBSD: setjmp.S,v 1.10 2006/01/05 19:21:37 uwe Exp $")
+	RCSID("$NetBSD: setjmp.S,v 1.10.88.1 2024/08/23 16:59:52 martin Exp $")
 #endif
 
 /*
@@ -90,39 +90,40 @@ ENTRY(__setjmp14)
 
 
 ENTRY(__longjmp14)
-	/* we won't return here, so we don't need to save pr and r12 */
-	PIC_PROLOGUE_NOSAVE(.L_got_2)
-	mov.l	r5, @-sp
-	mov.l	r4, @-sp
+	// return value can't be zero, adjust to 1 if it is
+	tst	r5, r5
+	bf/s	0f
+	 mov.l	@(_JB_REG_PR * 4, r4), r0
+	mov	#1, r5
+0:
+	// restore context first (callee-saved regs)
+	mov.l	@(_JB_REG_R8  * 4, r4), r8
+	mov.l	@(_JB_REG_R9  * 4, r4), r9
+	mov.l	@(_JB_REG_R10 * 4, r4), r10
+	mov.l	@(_JB_REG_R11 * 4, r4), r11
+	mov.l	@(_JB_REG_R12 * 4, r4), r12
+	mov.l	@(_JB_REG_R13 * 4, r4), r13
+	mov.l	@(_JB_REG_R14 * 4, r4), r14
+	mov.l	@(_JB_REG_R15 * 4, r4), r15
+
+	// create a frame
+	mov.l	r5, @-sp	// future return value (pre-adjusted)
+	mov.l	r0, @-sp	// caller's PR from the jumpbuf
+	PIC_PROLOGUE(.L_got_2)
 
-	mov.l	.L___sigprocmask14_2, r0
+	// restore signal mask from &a[_JB_SIGMASK]
+	mov	#0, r6			// oset = NULL
 	mov	r4, r5
-	mov	#3, r4			/* how = SIG_SETMASK */
-	add	#(_JB_SIGMASK * 4), r5	/* new = &sigmask */
+	mov.l	.L___sigprocmask14_2, r0
+	add	#(_JB_SIGMASK * 4), r5	// set = &a[_JB_SIGMASK]
 1:	CALL	r0
-	 mov	#0, r6			/* old = NULL */
+	 mov	#3, r4			// how = SIG_SETMASK
 
-	mov.l	@sp+, r4
-	mov.l	@sp+, r5
-
-	/* identical to _longjmp */
-	lds.l	@r4+, pr
-	mov.l	@r4+, r8
-	mov.l	@r4+, r9
-	mov.l	@r4+, r10
-	mov.l	@r4+, r11
-	mov.l	@r4+, r12
-	mov.l	@r4+, r13
-	mov.l	@r4+, r14
-	mov.l	@r4+, r15
-
-	mov	r5, r0
-	tst	r0, r0	/* make sure return value is non-zero */
-	bf	.L0
-	add	#1, r0
-.L0:
+	// return "from" setjmp
+	PIC_EPILOGUE
+	lds.l	@sp+, pr
 	rts
-	 nop
+	 mov.l	@sp+, r0
 
 	.align	2
 .L_got_2:		PIC_GOT_DATUM

Index: src/lib/libc/arch/sh3/gen/sigsetjmp.S
diff -u src/lib/libc/arch/sh3/gen/sigsetjmp.S:1.9 src/lib/libc/arch/sh3/gen/sigsetjmp.S:1.9.88.1
--- src/lib/libc/arch/sh3/gen/sigsetjmp.S:1.9	Thu Jan  5 19:21:37 2006
+++ src/lib/libc/arch/sh3/gen/sigsetjmp.S	Fri Aug 23 16:59:52 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: sigsetjmp.S,v 1.9 2006/01/05 19:21:37 uwe Exp $	*/
+/*	$NetBSD: sigsetjmp.S,v 1.9.88.1 2024/08/23 16:59:52 martin Exp $	*/
 
 /*-
  * Copyright (c) 1990 The Regents of the University of California.
@@ -38,7 +38,7 @@
 #include <machine/setjmp.h>
 
 #if defined(LIBC_SCCS)
-	RCSID("$NetBSD: sigsetjmp.S,v 1.9 2006/01/05 19:21:37 uwe Exp $")
+	RCSID("$NetBSD: sigsetjmp.S,v 1.9.88.1 2024/08/23 16:59:52 martin Exp $")
 #endif
 
 ENTRY(__sigsetjmp14)
@@ -85,44 +85,49 @@ ENTRY(__sigsetjmp14)
 
 
 ENTRY(__siglongjmp14)
-	mov.l	@(_JB_HAS_MASK * 4, r4), r0
-	tst	r0, r0
-	bt	2f			/* if no mask */
-
-	/* identical to longjmp */
-	/* we won't return here, so we don't need to save pr and r12 */
-	PIC_PROLOGUE_NOSAVE(.L_got_2)
-	mov.l	r5, @-sp
-	mov.l	r4, @-sp
+	// return value can't be zero, adjust to 1 if it is
+	tst	r5, r5
+	bf/s	0f
+	 mov.l	@(_JB_REG_PR * 4, r4), r0
+	mov	#1, r5
+0:
+	// restore context first (callee-saved regs)
+	mov.l	@(_JB_REG_R8  * 4, r4), r8
+	mov.l	@(_JB_REG_R9  * 4, r4), r9
+	mov.l	@(_JB_REG_R10 * 4, r4), r10
+	mov.l	@(_JB_REG_R11 * 4, r4), r11
+	mov.l	@(_JB_REG_R12 * 4, r4), r12
+	mov.l	@(_JB_REG_R13 * 4, r4), r13
+	mov.l	@(_JB_REG_R14 * 4, r4), r14
+	mov.l	@(_JB_REG_R15 * 4, r4), r15
+
+	// do we need to restore signal mask?
+	mov.l	@(_JB_HAS_MASK * 4, r4), r7
+	tst	r7, r7
+	bf/s	0f
+	 mov	#0, r6		// sigprocmask: oset = NULL
+	// ... no, just the registers
+	lds	r0, pr
+	rts
+	 mov	r5, r0
+0:
+	// create a frame
+	mov.l	r5, @-sp	// future return value (pre-adjusted)
+	mov.l	r0, @-sp	// caller's PR from the jumpbuf
+	PIC_PROLOGUE(.L_got_2)
 
-	mov.l	.L___sigprocmask14_2, r0
+	// restore signal mask from &a[_JB_SIGMASK]
 	mov	r4, r5
-	mov	#3, r4			/* how = SIG_SETMASK */
-	add	#(_JB_SIGMASK * 4), r5	/* new = &sigmask */
+	mov.l	.L___sigprocmask14_2, r0
+	add	#(_JB_SIGMASK * 4), r5	// set = &a[_JB_SIGMASK]
 1:	CALL	r0
-	 mov	#0, r6			/* old = NULL */
+	 mov	#3, r4			// how = SIG_SETMASK
 
-	mov.l	@sp+, r4
-	mov.l	@sp+, r5
-
-2:	/* identical to _longjmp */
-	lds.l	@r4+, pr
-	mov.l	@r4+, r8
-	mov.l	@r4+, r9
-	mov.l	@r4+, r10
-	mov.l	@r4+, r11
-	mov.l	@r4+, r12
-	mov.l	@r4+, r13
-	mov.l	@r4+, r14
-	mov.l	@r4+, r15
-
-	mov	r5, r0
-	tst	r0, r0	/* make sure return value is non-zero */
-	bf	.L0
-	add	#1, r0
-.L0:
+	// return "from" setjmp
+	PIC_EPILOGUE
+	lds.l	@sp+, pr
 	rts
-	 nop
+	 mov.l	@sp+, r0
 
 	.align	2
 .L_got_2:		PIC_GOT_DATUM

Index: src/lib/libc/arch/x86_64/gen/__setjmp14.S
diff -u src/lib/libc/arch/x86_64/gen/__setjmp14.S:1.3 src/lib/libc/arch/x86_64/gen/__setjmp14.S:1.3.26.1
--- src/lib/libc/arch/x86_64/gen/__setjmp14.S:1.3	Thu May 22 15:01:56 2014
+++ src/lib/libc/arch/x86_64/gen/__setjmp14.S	Fri Aug 23 16:59:52 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: __setjmp14.S,v 1.3 2014/05/22 15:01:56 uebayasi Exp $	*/
+/*	$NetBSD: __setjmp14.S,v 1.3.26.1 2024/08/23 16:59:52 martin Exp $	*/
 
 /*
  * Copyright (c) 2001 Wasabi Systems, Inc.
@@ -40,7 +40,7 @@
 #include <machine/setjmp.h>
 
 #if defined(LIBC_SCCS)
-	RCSID("$NetBSD: __setjmp14.S,v 1.3 2014/05/22 15:01:56 uebayasi Exp $")
+	RCSID("$NetBSD: __setjmp14.S,v 1.3.26.1 2024/08/23 16:59:52 martin Exp $")
 #endif
 
 /*
@@ -53,7 +53,19 @@
  * The previous signal state is restored.
  */
 
+/*
+ * setjmp(jmp_buf env@rdi)
+ *
+ * ELF symbol: __setjmp14, because the size of jmp_buf changed on some
+ * platforms in 1.4.
+ */
 ENTRY(__setjmp14)
+	/*
+	 * Save the callee-saves registers: %rbx, %rbp, %r12-r15,
+	 * plus %rsp and the return address on the stack since it
+	 * will be overwritten if the caller makes any subroutine
+	 * calls before longjmp.
+	 */
 	movq	(%rsp),%r11
 	movq	%rbx,(_JB_RBX * 8)(%rdi)
 	movq	%rbp,(_JB_RBP * 8)(%rdi)
@@ -64,47 +76,62 @@ ENTRY(__setjmp14)
 	movq	%rsp,(_JB_RSP * 8)(%rdi)
 	movq	%r11,(_JB_PC  * 8)(%rdi)
 
-	leaq	(_JB_SIGMASK * 8)(%rdi),%rdx
-	xorl	%edi,%edi
-	xorq	%rsi,%rsi
+	leaq	(_JB_SIGMASK * 8)(%rdi),%rdx	/* oset@rdx */
+	xorl	%edi,%edi		/* how@edi := 0 (ignored) */
+	xorl	%esi,%esi		/* set@rsi := NULL */
 
 #ifdef __PIC__
 	call	PIC_PLT(_C_LABEL(__sigprocmask14))
 #else
 	call	_C_LABEL(__sigprocmask14)
 #endif
-2:	xorl	%eax,%eax
+	xorl	%eax,%eax
 	ret
 END(__setjmp14)
 
+/*
+ * longjmp(jmp_buf env@rdi, int val@esi)
+ *
+ * ELF symbol: __longjmp14, because the size of jmp_buf changed on some
+ * platforms in 1.4
+ */
 ENTRY(__longjmp14)
-	movq	%rdi,%r12
-	movl	%esi,%r8d
-
-	leaq	(_JB_SIGMASK * 8)(%rdi),%rsi
-	movl	$3,%edi		/* SIG_SETMASK */
-	xorq	%rdx,%rdx
+	/*
+	 * Restore the callee-saves registers: %rbx, %rbp, %r12-r15,
+	 * plus %rsp and the return address on the stack.
+	 */
+	movq	(_JB_RBX * 8)(%rdi),%rbx
+	movq	(_JB_RBP * 8)(%rdi),%rbp
+	movq	(_JB_R12 * 8)(%rdi),%r12
+	movq	(_JB_R13 * 8)(%rdi),%r13
+	movq	(_JB_R14 * 8)(%rdi),%r14
+	movq	(_JB_R15 * 8)(%rdi),%r15
+	movq	(_JB_RSP * 8)(%rdi),%rsp
+	movq	(_JB_PC  * 8)(%rdi),%r11
+	movq	%r11,0(%rsp)
+
+	/*
+	 * Use  pushq %rsi  instead of  pushl %esi  in order to keep
+	 * 16-byte stack alignment, even though we only care about the
+	 * 32-bit int in esi.
+	 */
+	pushq	%rsi		/* save val@esi */
+
+	leaq	(_JB_SIGMASK * 8)(%rdi),%rsi	/* set@rsi */
+	movl	$3,%edi		/* how@edi := SIG_SETMASK */
+	xorl	%edx,%edx	/* oset@rdx := NULL */
 
-	pushq	%r8
 #ifdef __PIC__
 	call	PIC_PLT(_C_LABEL(__sigprocmask14))
 #else
 	call	_C_LABEL(__sigprocmask14)
 #endif
-	popq	%r8
-	movq	(_JB_RBX * 8)(%r12),%rbx
-	movq	(_JB_RBP * 8)(%r12),%rbp
-	movq	(_JB_R13 * 8)(%r12),%r13
-	movq	(_JB_R14 * 8)(%r12),%r14
-	movq	(_JB_R15 * 8)(%r12),%r15
-	movq	(_JB_RSP * 8)(%r12),%rsp
-	movq	(_JB_PC  * 8)(%r12),%r11
-	movq	(_JB_R12 * 8)(%r12),%r12
-
-	movl	%r8d,%eax
-	testl	%eax,%eax
-	jnz	1f
-	incl	%eax
-1:	movq	%r11,0(%rsp)
-	ret
+
+	popq	%rax		/* restore val@eax */
+
+	testl	%eax,%eax	/* val@eax == 0? */
+	jz	1f		/* jump if val@eax == 0 */
+	ret			/* return val@eax */
+1:	incl	%eax		/* val@eax := 1 */
+	ret			/* return val@eax */
 END(__longjmp14)
Index: src/lib/libc/arch/x86_64/gen/__sigsetjmp14.S
diff -u src/lib/libc/arch/x86_64/gen/__sigsetjmp14.S:1.3 src/lib/libc/arch/x86_64/gen/__sigsetjmp14.S:1.3.26.1
--- src/lib/libc/arch/x86_64/gen/__sigsetjmp14.S:1.3	Thu May 22 15:01:56 2014
+++ src/lib/libc/arch/x86_64/gen/__sigsetjmp14.S	Fri Aug 23 16:59:52 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: __sigsetjmp14.S,v 1.3 2014/05/22 15:01:56 uebayasi Exp $	*/
+/*	$NetBSD: __sigsetjmp14.S,v 1.3.26.1 2024/08/23 16:59:52 martin Exp $	*/
 
 /*
  * Copyright (c) 2001 Wasabi Systems, Inc.
@@ -40,7 +40,7 @@
 #include <machine/setjmp.h>
 
 #if defined(LIBC_SCCS)
-	RCSID("$NetBSD: __sigsetjmp14.S,v 1.3 2014/05/22 15:01:56 uebayasi Exp $")
+	RCSID("$NetBSD: __sigsetjmp14.S,v 1.3.26.1 2024/08/23 16:59:52 martin Exp $")
 #endif
 
 /*
@@ -53,7 +53,19 @@
  * The previous signal state is restored.
  */
 
+/*
+ * sigsetjmp(sigjmp_buf env@rdi, int savemask@esi)
+ *
+ * ELF symbol: __sigsetjmp14, because the size of sigjmp_buf changed on
+ * some platforms in 1.4.
+ */
 ENTRY(__sigsetjmp14)
+	/*
+	 * Save the callee-saves registers: %rbx, %rbp, %r12-r15,
+	 * plus %rsp and the return address on the stack since it
+	 * will be overwritten if the caller makes any subroutine
+	 * calls before siglongjmp.
+	 */
 	movq	(%rsp),%r11
 	movq	%rbx,(_JB_RBX * 8)(%rdi)
 	movq	%rbp,(_JB_RBP * 8)(%rdi)
@@ -64,51 +76,69 @@ ENTRY(__sigsetjmp14)
 	movq	%rsp,(_JB_RSP * 8)(%rdi)
 	movq	%r11,(_JB_PC  * 8)(%rdi)
 
-	movq	%rsi,(_JB_SIGFLAG  * 8)(%rdi)
-	testl	%esi,%esi
-	jz	2f
-
-	leaq	(_JB_SIGMASK * 8)(%rdi),%rdx
-	xorl	%edi,%edi
-	xorq	%rsi,%rsi
+	movq	%rsi,(_JB_SIGFLAG  * 8)(%rdi)	/* store savemask */
+	testl	%esi,%esi		/* savemask == 0? */
+	jz	2f			/* jump if savemask == 0 */
+
+	leaq	(_JB_SIGMASK * 8)(%rdi),%rdx	/* oset@rdx */
+	xorl	%edi,%edi		/* how@edi := 0 (ignored) */
+	xorl	%esi,%esi		/* set@rsi := NULL */
 
 #ifdef __PIC__
 	call	PIC_PLT(_C_LABEL(__sigprocmask14))
 #else
 	call	_C_LABEL(__sigprocmask14)
 #endif
-2:	xorl	%eax,%eax
+2:	xorl	%eax,%eax		/* return 0 first time around */
 	ret
 END(__sigsetjmp14)
 
+/*
+ * siglongjmp(sigjmp_buf env@rdi, int val@esi)
+ *
+ * ELF symbol: __siglongjmp14, because the size of sigjmp_buf changed
+ * on some platforms in 1.4.
+ */
 ENTRY(__siglongjmp14)
-	movq	%rdi,%r12
-	pushq	%rsi
-	cmpl	$0, (_JB_SIGFLAG * 8)(%rdi)
-
-	jz	2f
-	leaq	(_JB_SIGMASK * 8)(%rdi),%rsi
-	movl	$3,%edi		/* SIG_SETMASK */
-	xorq	%rdx,%rdx
+	/*
+	 * Restore the callee-saves registers: %rbx, %rbp, %r12-r15,
+	 * plus %rsp and the return address on the stack.
+	 */
+	movq	(_JB_RBX * 8)(%rdi),%rbx
+	movq	(_JB_RBP * 8)(%rdi),%rbp
+	movq	(_JB_R12 * 8)(%rdi),%r12
+	movq	(_JB_R13 * 8)(%rdi),%r13
+	movq	(_JB_R14 * 8)(%rdi),%r14
+	movq	(_JB_R15 * 8)(%rdi),%r15
+	movq	(_JB_RSP * 8)(%rdi),%rsp
+	movq	(_JB_PC  * 8)(%rdi),%r11
+	movq	%r11,0(%rsp)
+
+	/*
+	 * Use  pushq %rsi  instead of  pushl %esi  in order to keep
+	 * 16-byte stack alignment, even though we only care about the
+	 * 32-bit int in esi.
+	 */
+	pushq	%rsi		/* save val@esi */
+
+	cmpl	$0, (_JB_SIGFLAG * 8)(%rdi)	/* test savemask == 0? */
+	jz	2f		/* jump if savemask == 0 */
+
+	leaq	(_JB_SIGMASK * 8)(%rdi),%rsi	/* set@rsi */
+	movl	$3,%edi		/* how@edi := SIG_SETMASK */
+	xorl	%edx,%edx	/* oset@rdx := NULL */
 
 #ifdef __PIC__
 	call	PIC_PLT(_C_LABEL(__sigprocmask14))
 #else
 	call	_C_LABEL(__sigprocmask14)
 #endif
-2:	popq	%rax
-	movq	(_JB_RBX * 8)(%r12),%rbx
-	movq	(_JB_RBP * 8)(%r12),%rbp
-	movq	(_JB_R13 * 8)(%r12),%r13
-	movq	(_JB_R14 * 8)(%r12),%r14
-	movq	(_JB_R15 * 8)(%r12),%r15
-	movq	(_JB_RSP * 8)(%r12),%rsp
-	movq	(_JB_PC  * 8)(%r12),%r11
-	movq	(_JB_R12 * 8)(%r12),%r12
-
-	testl	%eax,%eax
-	jnz	1f
-	incl	%eax
-1:	movq	%r11,0(%rsp)
-	ret
+
+2:	popq	%rax		/* restore val@eax */
+
+	testl	%eax,%eax	/* val@eax == 0? */
+	jz	1f		/* jump if val@eax == 0 */
+	ret			/* return val@eax */
+1:	incl	%eax		/* val@eax := 1 */
+	ret			/* return val@eax */
 END(__siglongjmp14)

Index: src/tests/lib/libc/setjmp/Makefile
diff -u src/tests/lib/libc/setjmp/Makefile:1.2 src/tests/lib/libc/setjmp/Makefile:1.2.46.1
--- src/tests/lib/libc/setjmp/Makefile:1.2	Thu Apr 21 18:58:20 2011
+++ src/tests/lib/libc/setjmp/Makefile	Fri Aug 23 16:59:51 2024
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile,v 1.2 2011/04/21 18:58:20 martin Exp $
+# $NetBSD: Makefile,v 1.2.46.1 2024/08/23 16:59:51 martin Exp $
 
 NOMAN=		# defined
 
@@ -9,6 +9,7 @@ WARNS=	4
 TESTSDIR=	${TESTSBASE}/lib/libc/setjmp
 
 TESTS_C+=	t_setjmp
+TESTS_C+=	t_sigstack
 TESTS_C+=	t_threadjmp
 
 LDFLAGS.t_threadjmp+= -pthread

Added files:

Index: src/tests/lib/libc/setjmp/t_sigstack.c
diff -u /dev/null src/tests/lib/libc/setjmp/t_sigstack.c:1.12.4.2
--- /dev/null	Fri Aug 23 16:59:53 2024
+++ src/tests/lib/libc/setjmp/t_sigstack.c	Fri Aug 23 16:59:52 2024
@@ -0,0 +1,262 @@
+/*	$NetBSD: t_sigstack.c,v 1.12.4.2 2024/08/23 16:59:52 martin Exp $	*/
+
+/*-
+ * Copyright (c) 2024 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: t_sigstack.c,v 1.12.4.2 2024/08/23 16:59:52 martin Exp $");
+
+#include <setjmp.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <ucontext.h>
+
+#include "h_macros.h"
+
+struct sigaltstack ss[3];
+jmp_buf jmp;
+sigjmp_buf sigjmp;
+unsigned nentries;
+const char *bailname;
+void (*bailfn)(void) __dead;
+
+static void
+on_sigusr1(int signo, siginfo_t *si, void *ctx)
+{
+	ucontext_t *uc = ctx;
+	void *sp = (void *)(uintptr_t)_UC_MACHINE_SP(uc);
+	void *fp = __builtin_frame_address(0);
+	struct sigaltstack *ssp;
+
+	/*
+	 * Ensure we haven't re-entered the signal handler too many
+	 * times.  We should enter only twice.
+	 */
+	ATF_REQUIRE_MSG(nentries < 2,
+	    "%u recursive signal handler entries is too many in this test",
+	    nentries + 1);
+
+	/*
+	 * Ensure that the signal handler was called in the alternate
+	 * signal stack.
+	 */
+	ssp = &ss[nentries];
+	ATF_REQUIRE_MSG((fp >= ssp->ss_sp &&
+		fp < (void *)((char *)ssp->ss_sp + ssp->ss_size)),
+	    "sigaltstack failed to take effect on entry %u --"
+	    " signal handler's frame pointer %p doesn't lie in sigaltstack"
+	    " [%p, %p), size 0x%zx",
+	    nentries,
+	    fp, ssp->ss_sp, (char *)ssp->ss_sp + ssp->ss_size, ssp->ss_size);
+
+	/*
+	 * Ensure that if we enter the signal handler, we are entering
+	 * it from the original stack, not from any of the alternate
+	 * signal stacks.
+	 *
+	 * On some architectures, this is broken.  Those that appear to
+	 * get this right are:
+	 *
+	 *	aarch64
+	 *	alpha
+	 *	arm
+	 *	i386
+	 *	m68k
+	 *	or1k
+	 *	powerpc
+	 *	powerpc64
+	 *	riscv
+	 *	vax
+	 *	x86_64
+	 */
+#if defined __hppa__ || \
+    defined __ia64__ || defined __mips__ || \
+    defined __sparc__ || defined __sparc64__
+	if (nentries > 0)
+		atf_tc_expect_fail("PR lib/57946");
+#endif
+	for (ssp = &ss[0]; ssp < &ss[__arraycount(ss)]; ssp++) {
+		ATF_REQUIRE_MSG((sp < ssp->ss_sp ||
+			sp >= (void *)((char *)ssp->ss_sp + ssp->ss_size)),
+		    "%s failed to restore stack"
+		    " before allowing signal on entry %u --"
+		    " interrupted stack pointer %p lies in sigaltstack %zd"
+		    " [%p, %p), size 0x%zx",
+		    bailname,
+		    nentries,
+		    sp, ssp - ss,
+		    ssp->ss_sp, (char *)ssp->ss_sp + ssp->ss_size,
+		    ssp->ss_size);
+	}
+
+	/*
+	 * First time through, we want to test whether longjmp restores
+	 * the signal mask first, or restores the stack pointer first.
+	 * The signal should be blocked at this point, so we re-raise
+	 * the signal to queue it up for delivery as soon as it is
+	 * unmasked -- which should wait until the stack pointer has
+	 * been restored in longjmp.
+	 */
+	if (nentries++ == 0)
+		RL(raise(SIGUSR1));
+
+	/*
+	 * Set up the next sigaltstack.  We can't reuse the current one
+	 * for the next signal handler re-entry until the system clears
+	 * the SS_ONSTACK process state -- which normal return from
+	 * signal handler does, but which longjmp does not.  So to keep
+	 * it simple (ha), we just use another sigaltstack.
+	 */
+	RL(sigaltstack(&ss[nentries], NULL));
+
+	/*
+	 * Jump back to the original context.
+	 */
+	(*bailfn)();
+}
+
+static void
+go(const char *name, void (*fn)(void) __dead)
+{
+	struct sigaction sa;
+	unsigned i;
+
+	bailname = name;
+	bailfn = fn;
+
+	/*
+	 * Allocate a stack for the signal handler to run in, and
+	 * configure the system to use the first one.
+	 *
+	 * XXX Should maybe use a guard page but this is simpler.
+	 */
+	for (i = 0; i < __arraycount(ss); i++) {
+		ss[i].ss_size = SIGSTKSZ;
+		REQUIRE_LIBC(ss[i].ss_sp = malloc(ss[i].ss_size), NULL);
+	}
+	RL(sigaltstack(&ss[0], NULL));
+
+	/*
+	 * Set up a test signal handler for SIGUSR1.  Allow all
+	 * signals, except SIGUSR1 (which is masked by default) -- that
+	 * way we don't inadvertently obscure weird crashes in the
+	 * signal handler.
+	 *
+	 * Set SA_SIGINFO so the system will pass siginfo -- and, more
+	 * to the point, ucontext, so the signal handler can determine
+	 * the stack pointer of the logic it interrupted.
+	 *
+	 * Set SA_ONSTACK so the system will use the alternate signal
+	 * stack to call the signal handler -- that way, it can tell
+	 * whether the stack was restored before the second time
+	 * around.
+	 */
+	memset(&sa, 0, sizeof(sa));
+	sa.sa_sigaction = &on_sigusr1;
+	RL(sigemptyset(&sa.sa_mask));
+	sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
+	RL(sigaction(SIGUSR1, &sa, NULL));
+
+	/*
+	 * Raise the signal to enter the signal handler the first time.
+	 */
+	RL(raise(SIGUSR1));
+
+	/*
+	 * If we ever reach this point, something went seriously wrong.
+	 */
+	atf_tc_fail("unreachable");
+}
+
+static void __dead
+bail_longjmp(void)
+{
+
+	longjmp(jmp, 1);
+}
+
+ATF_TC(setjmp);
+ATF_TC_HEAD(setjmp, tc)
+{
+	atf_tc_set_md_var(tc, "descr",
+	    "Test longjmp restores stack first, then signal mask");
+}
+ATF_TC_BODY(setjmp, tc)
+{
+
+	/*
+	 * Set up a return point for the signal handler: when the
+	 * signal handler does longjmp(jmp, 1), it comes flying out of
+	 * here.
+	 */
+	if (setjmp(jmp) == 1)
+		return;
+
+	/*
+	 * Run the test with longjmp.
+	 */
+	go("longjmp", &bail_longjmp);
+}
+
+static void __dead
+bail_siglongjmp(void)
+{
+
+	siglongjmp(sigjmp, 1);
+}
+
+ATF_TC(sigsetjmp);
+ATF_TC_HEAD(sigsetjmp, tc)
+{
+	atf_tc_set_md_var(tc, "descr",
+	    "Test siglongjmp restores stack first, then signal mask");
+}
+ATF_TC_BODY(sigsetjmp, tc)
+{
+
+	/*
+	 * Set up a return point for the signal handler: when the
+	 * signal handler does siglongjmp(sigjmp, 1), it comes flying
+	 * out of here.
+	 */
+	if (sigsetjmp(sigjmp, /*savesigmask*/1) == 1)
+		return;
+
+	/*
+	 * Run the test with siglongjmp.
+	 */
+	go("siglongjmp", &bail_siglongjmp);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+	ATF_TP_ADD_TC(tp, setjmp);
+	ATF_TP_ADD_TC(tp, sigsetjmp);
+
+	return atf_no_error();
+}

Reply via email to