Fix crash in __longjmp on hppa architecture (BZ #21049)

Message ID 20170115123629.GA12030@ls3530
State New, archived
Headers

Commit Message

Helge Deller Jan. 15, 2017, 12:36 p.m. UTC
  This fixes a crash in __longjmp on the hppa architecture which happens if the
new sigaltstack is above the current stack. In that case CHECK_SP() does an
INTERNAL_SYSCALL which clobbers %r26. Fix this issue by calling CHECK_SP before
assigning the local register variables r26 and r25.

The bug exists in all glibc versions and is triggered by running the GNU forth
compiler.

I don't have write access, so somebody should commit this for me. Thanks.

ChangeLog:

2017-01-15  Helge Deller  <deller@gmx.de>

	[BZ #21049]
	* sysdeps/hppa/__longjmp.c (__longjmp): Move call to CHECK_SP up
	to avoid clobbering r26.
  

Comments

John David Anglin March 25, 2017, 11:13 p.m. UTC | #1
Ping.

This bug also breaks libsigsegv build.

Dave

On 2017-01-15, at 7:36 AM, Helge Deller wrote:

> This fixes a crash in __longjmp on the hppa architecture which happens if the
> new sigaltstack is above the current stack. In that case CHECK_SP() does an
> INTERNAL_SYSCALL which clobbers %r26. Fix this issue by calling CHECK_SP before
> assigning the local register variables r26 and r25.
> 
> The bug exists in all glibc versions and is triggered by running the GNU forth
> compiler.
> 
> I don't have write access, so somebody should commit this for me. Thanks.
> 
> ChangeLog:
> 
> 2017-01-15  Helge Deller  <deller@gmx.de>
> 
> 	[BZ #21049]
> 	* sysdeps/hppa/__longjmp.c (__longjmp): Move call to CHECK_SP up
> 	to avoid clobbering r26.
> 
> 
> diff -up ./sysdeps/hppa/__longjmp.c.org ./sysdeps/hppa/__longjmp.c
> --- ./sysdeps/hppa/__longjmp.c.org	2017-01-13 10:45:24.180424626 +0100
> +++ ./sysdeps/hppa/__longjmp.c	2017-01-13 10:47:41.720409134 +0100
> @@ -24,15 +24,16 @@
> void
> __longjmp (__jmp_buf env, int val)
> {
> +#ifdef CHECK_SP
> +  CHECK_SP (env[0].__jmp_buf.__sp);
> +#endif
> +
> +  {
>   /* We must use one of the non-callee saves registers
>      for env.  */
>   register unsigned long r26 asm ("r26") = (unsigned long)&env[0];
>   register unsigned long r25 asm ("r25") = (unsigned long)(val == 0 ? 1 : val);
> 
> -#ifdef CHECK_SP
> -  CHECK_SP (env[0].__jmp_buf.__sp);
> -#endif
> -
>   asm volatile(
> 	/* Set return value.  */
> 	"copy	%0, %%r28\n\t"
> @@ -79,6 +80,8 @@ __longjmp (__jmp_buf env, int val)
> 	: /* No outputs.  */
> 	: "r" (r25), "r" (r26)
> 	: /* No point in clobbers.  */ );
> +  }
> +
>   /* Avoid `volatile function does return' warnings.  */
>   for (;;);
> }

--
John David Anglin	dave.anglin@bell.net
  
Florian Weimer March 26, 2017, 7:50 a.m. UTC | #2
* Helge Deller:

> This fixes a crash in __longjmp on the hppa architecture which
> happens if the new sigaltstack is above the current stack. In that
> case CHECK_SP() does an INTERNAL_SYSCALL which clobbers %r26. Fix
> this issue by calling CHECK_SP before assigning the local register
> variables r26 and r25.

I agree this is the right thing to do because of INTERNAL_SYSCALL uses
%r26 as an input operand, so GCC is not required to preserve the %r26
contents there.  I think the assumption on the GCC side is that if the
programmer requires explicit registers, they know what they are doing.
(Otherwise, GCC is expected to avoid registers assigned to register
variables.)
  

Patch

diff -up ./sysdeps/hppa/__longjmp.c.org ./sysdeps/hppa/__longjmp.c
--- ./sysdeps/hppa/__longjmp.c.org	2017-01-13 10:45:24.180424626 +0100
+++ ./sysdeps/hppa/__longjmp.c	2017-01-13 10:47:41.720409134 +0100
@@ -24,15 +24,16 @@ 
 void
 __longjmp (__jmp_buf env, int val)
 {
+#ifdef CHECK_SP
+  CHECK_SP (env[0].__jmp_buf.__sp);
+#endif
+
+  {
   /* We must use one of the non-callee saves registers
      for env.  */
   register unsigned long r26 asm ("r26") = (unsigned long)&env[0];
   register unsigned long r25 asm ("r25") = (unsigned long)(val == 0 ? 1 : val);
 
-#ifdef CHECK_SP
-  CHECK_SP (env[0].__jmp_buf.__sp);
-#endif
-
   asm volatile(
 	/* Set return value.  */
 	"copy	%0, %%r28\n\t"
@@ -79,6 +80,8 @@  __longjmp (__jmp_buf env, int val)
 	: /* No outputs.  */
 	: "r" (r25), "r" (r26)
 	: /* No point in clobbers.  */ );
+  }
+
   /* Avoid `volatile function does return' warnings.  */
   for (;;);
 }