This is the mail archive of the
libc-ports@sources.redhat.com
mailing list for the libc-ports project.
MIPS ____longjmp_chk update
- From: "Joseph S. Myers" <joseph at codesourcery dot com>
- To: libc-ports at sourceware dot org
- Date: Wed, 5 Aug 2009 21:16:03 +0000 (UTC)
- Subject: MIPS ____longjmp_chk update
I've applied this patch to update MIPS ____longjmp_chk in line with the
changes to some libc versions for alternate signal stack support, so that
debug/tst-longjmp_chk2 now passes for all three ABIs where it previously
failed.
I hope that the C code here may make it clearer for port maintainers just
what the logic (taken from x86 and x86_64) is that the various
target-specific ____longjmp_chk implementations need for signal stacks. I
plan to update ARM, but not other ports (e.g. m68k, alpha, hppa, none of
which have ____longjmp_chk at present so all of which should currently
fail to build). If the initial stack pointer check fails - if it appears
that longjmp would return to a stack frame that has been left - then there
is a further check to avoid false positives in the case of jumping from a
frame on the alternate signal stack to one on the normal stack. If the
sigaltstack syscall fails, things are treated as OK as we cannot tell
whether an alternate signal stack is involved or not. Otherwise, to be OK
we must be on the alternate stack (ss.ss_flags & SS_ONSTACK) and the stack
pointer saved in the jmp_buf must be outside it. The logic for being
outside it - at least for stacks growing down - seems to be that ss_sp +
ss_size counts as inside and ss_sp counts as outside, so you are outside
(OK) if ss_sp + ss_size - (saved sp) >= ss_size as an *unsigned*
comparison.
diff --git a/ChangeLog.mips b/ChangeLog.mips
index 9afd961..5ba4297 100644
--- a/ChangeLog.mips
+++ b/ChangeLog.mips
@@ -1,3 +1,11 @@
+2009-08-05 Joseph Myers <joseph@codesourcery.com>
+
+ * sysdeps/mips/____longjmp_chk.c: Remove. Replaced by....
+ * sysdeps/unix/sysv/linux/mips/____longjmp_chk.c: This. New file.
+ * sysdeps/mips/__longjmp.c (__longjmp): Use explicit register
+ variable for env. Use expansion of CHECK_SP macro for check.
+ * sysdeps/mips/mips64/__longjmp.c (__Longjmp): Likewise.
+
2009-08-03 Joseph Myers <joseph@codesourcery.com>
* sysdeps/unix/sysv/linux/mips/mips32/accept4.c,
diff --git a/sysdeps/mips/____longjmp_chk.c b/sysdeps/mips/____longjmp_chk.c
deleted file mode 100644
index a46ed15..0000000
--- a/sysdeps/mips/____longjmp_chk.c
+++ /dev/null
@@ -1,22 +0,0 @@
-/* Copyright (C) 2009 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, write to the Free
- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- 02111-1307 USA. */
-
-#include <stdio.h>
-#define __longjmp ____longjmp_chk
-#define CHECK_SP
-#include <__longjmp.c>
diff --git a/sysdeps/mips/__longjmp.c b/sysdeps/mips/__longjmp.c
index 340485d..2a91771 100644
--- a/sysdeps/mips/__longjmp.c
+++ b/sysdeps/mips/__longjmp.c
@@ -25,19 +25,19 @@
#endif
void
-__longjmp (env, val_arg)
- __jmp_buf env;
+__longjmp (env_arg, val_arg)
+ __jmp_buf env_arg;
int val_arg;
{
/* gcc 1.39.19 miscompiled the longjmp routine (as it did setjmp before
the hack around it); force it to use $a1 for the longjmp value.
Without this it saves $a1 in a register which gets clobbered
along the way. */
+ register struct __jmp_buf_internal_tag *env asm ("a0");
register int val asm ("a1");
#ifdef CHECK_SP
register long sp asm ("$29");
- if ((long) (env[0].__sp) < sp)
- __fortify_fail ("longjmp causes uninitialized stack frame");
+ CHECK_SP (env[0].__sp, sp, long);
#endif
#ifdef __mips_hard_float
diff --git a/sysdeps/mips/mips64/__longjmp.c b/sysdeps/mips/mips64/__longjmp.c
index d7e36ff..99aac01 100644
--- a/sysdeps/mips/mips64/__longjmp.c
+++ b/sysdeps/mips/mips64/__longjmp.c
@@ -27,19 +27,19 @@
#endif
void
-__longjmp (env, val_arg)
- __jmp_buf env;
+__longjmp (env_arg, val_arg)
+ __jmp_buf env_arg;
int val_arg;
{
/* gcc 1.39.19 miscompiled the longjmp routine (as it did setjmp before
the hack around it); force it to use $a1 for the longjmp value.
Without this it saves $a1 in a register which gets clobbered
along the way. */
+ register struct __jmp_buf_internal_tag *env asm ("a0");
register int val asm ("a1");
#ifdef CHECK_SP
register long long sp asm ("$29");
- if ((long long) (env[0].__sp) < sp)
- __fortify_fail ("longjmp causes uninitialized stack frame");
+ CHECK_SP (env[0].__sp, sp, long long);
#endif
#ifdef __mips_hard_float
diff --git a/sysdeps/unix/sysv/linux/mips/____longjmp_chk.c b/sysdeps/unix/sysv/linux/mips/____longjmp_chk.c
new file mode 100644
index 0000000..9db339c
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/mips/____longjmp_chk.c
@@ -0,0 +1,42 @@
+/* Copyright (C) 2009 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <signal.h>
+#include <stdio.h>
+#define __longjmp ____longjmp_chk
+#define CHECK_SP(saved_sp, cur_sp, sp_type) \
+ do { \
+ sp_type sp_saved = (sp_type) (saved_sp); \
+ if (sp_saved < (cur_sp)) \
+ { \
+ struct __jmp_buf_internal_tag *env_save = env_arg; \
+ int val_save = val_arg; \
+ stack_t ss; \
+ int ret = __sigaltstack (NULL, &ss); \
+ if (ret == 0 \
+ && (!(ss.ss_flags & SS_ONSTACK) \
+ || ((unsigned sp_type) ((sp_type) ss.ss_sp \
+ + (sp_type) ss.ss_size \
+ - sp_saved) \
+ < ss.ss_size))) \
+ __fortify_fail ("longjmp causes uninitialized stack frame"); \
+ asm volatile ("move %0, %1" : "=r" (env) : "r" (env_save)); \
+ asm volatile ("move %0, %1" : "=r" (val) : "r" (val_save)); \
+ } \
+ } while (0)
+#include <__longjmp.c>
--
Joseph S. Myers
joseph@codesourcery.com