We currently read and write beyond the builtin jmpbuf on ILP32 targets
where Pmode == DImode and ptr_mode == SImode.  Since the builtin jmpbuf
is an array of 5 pointers, ptr_mode should be used to save and restore
frame and program pointers.  Since x86 only saves stack pointer in
stack save area, STACK_SAVEAREA_MODE should be ptr_mode, not Pmode.

Note: If ptr_mode != Pmode, builtin setjmp/longjmp tests may fail.  When
it happens, please check if there are correct save_stack_nonlocal and
restore_stack_nonlocal expand patterns.

Tested on i686 and x86-64.  OK for trunk?

H.J.
----
gcc/

        PR middle-end/84150
        * builtins.c (expand_builtin_setjmp_setup): Use ptr_mode to
        save frame and program pointers.
        (expand_builtin_longjmp): Use ptr_mode to restore frame and
        program pointers.
        * config/i386/i386.md (save_stack_nonlocal): New expand pattern.
        (restore_stack_nonlocal): Likewise.
        * config/i386/i386.h (STACK_SAVEAREA_MODE): New.

gcc/testsuite/

        PR middle-end/84150
        * gcc.dg/pr84150.c: New test.
        * gcc.target/i386/pr84150.c: Likewisde.
---
 gcc/builtins.c                          | 36 +++++++++++++++++---------
 gcc/config/i386/i386.h                  |  4 +++
 gcc/config/i386/i386.md                 | 36 ++++++++++++++++++++++++++
 gcc/testsuite/gcc.dg/pr84150.c          | 45 +++++++++++++++++++++++++++++++++
 gcc/testsuite/gcc.target/i386/pr84150.c | 44 ++++++++++++++++++++++++++++++++
 5 files changed, 153 insertions(+), 12 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/pr84150.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr84150.c

diff --git a/gcc/builtins.c b/gcc/builtins.c
index 683c6ec6e5b..c3d45d5e3fa 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -840,6 +840,7 @@ expand_builtin_setjmp_setup (rtx buf_addr, rtx 
receiver_label)
   machine_mode sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
   rtx stack_save;
   rtx mem;
+  rtx tmp;
 
   if (setjmp_alias_set == -1)
     setjmp_alias_set = new_alias_set ();
@@ -852,20 +853,25 @@ expand_builtin_setjmp_setup (rtx buf_addr, rtx 
receiver_label)
      the buffer and use the rest of it for the stack save area, which
      is machine-dependent.  */
 
-  mem = gen_rtx_MEM (Pmode, buf_addr);
+  mem = gen_rtx_MEM (ptr_mode, buf_addr);
   set_mem_alias_set (mem, setjmp_alias_set);
-  emit_move_insn (mem, targetm.builtin_setjmp_frame_value ());
+  tmp = targetm.builtin_setjmp_frame_value ();
+  if (GET_MODE (tmp) != ptr_mode)
+    tmp = gen_lowpart (ptr_mode, tmp);
+  emit_move_insn (mem, tmp);
 
-  mem = gen_rtx_MEM (Pmode, plus_constant (Pmode, buf_addr,
-                                          GET_MODE_SIZE (Pmode))),
+  mem = gen_rtx_MEM (ptr_mode, plus_constant (Pmode, buf_addr,
+                                             GET_MODE_SIZE (ptr_mode))),
   set_mem_alias_set (mem, setjmp_alias_set);
 
-  emit_move_insn (validize_mem (mem),
-                 force_reg (Pmode, gen_rtx_LABEL_REF (Pmode, receiver_label)));
+  tmp = force_reg (Pmode, gen_rtx_LABEL_REF (Pmode, receiver_label));
+  if (Pmode != ptr_mode)
+    tmp = gen_lowpart (ptr_mode, tmp);
+  emit_move_insn (validize_mem (mem), tmp);
 
   stack_save = gen_rtx_MEM (sa_mode,
                            plus_constant (Pmode, buf_addr,
-                                          2 * GET_MODE_SIZE (Pmode)));
+                                          2 * GET_MODE_SIZE (ptr_mode)));
   set_mem_alias_set (stack_save, setjmp_alias_set);
   emit_stack_save (SAVE_NONLOCAL, &stack_save);
 
@@ -991,12 +997,14 @@ expand_builtin_longjmp (rtx buf_addr, rtx value)
     emit_insn (targetm.gen_builtin_longjmp (buf_addr));
   else
     {
-      fp = gen_rtx_MEM (Pmode, buf_addr);
-      lab = gen_rtx_MEM (Pmode, plus_constant (Pmode, buf_addr,
-                                              GET_MODE_SIZE (Pmode)));
+      fp = gen_rtx_MEM (ptr_mode, buf_addr);
+      lab = gen_rtx_MEM (ptr_mode,
+                        plus_constant (Pmode, buf_addr,
+                                       GET_MODE_SIZE (ptr_mode)));
 
-      stack = gen_rtx_MEM (sa_mode, plus_constant (Pmode, buf_addr,
-                                                  2 * GET_MODE_SIZE (Pmode)));
+      stack = gen_rtx_MEM (sa_mode,
+                          plus_constant (Pmode, buf_addr,
+                                         2 * GET_MODE_SIZE (ptr_mode)));
       set_mem_alias_set (fp, setjmp_alias_set);
       set_mem_alias_set (lab, setjmp_alias_set);
       set_mem_alias_set (stack, setjmp_alias_set);
@@ -1015,6 +1023,10 @@ expand_builtin_longjmp (rtx buf_addr, rtx value)
          emit_clobber (gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode)));
          emit_clobber (gen_rtx_MEM (BLKmode, hard_frame_pointer_rtx));
 
+#ifdef POINTERS_EXTEND_UNSIGNED
+         if (GET_MODE (fp) != Pmode)
+           fp = convert_to_mode (Pmode, fp, POINTERS_EXTEND_UNSIGNED);
+#endif
          emit_move_insn (hard_frame_pointer_rtx, fp);
          emit_stack_restore (SAVE_NONLOCAL, stack);
 
diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
index 59522ccba02..16aace86e48 100644
--- a/gcc/config/i386/i386.h
+++ b/gcc/config/i386/i386.h
@@ -1937,6 +1937,10 @@ do {                                                     
\
    between pointers and any other objects of this machine mode.  */
 #define Pmode (ix86_pmode == PMODE_DI ? DImode : SImode)
 
+/* Supply a definition of STACK_SAVEAREA_MODE for emit_stack_save.  We
+   only need save and restore stack pointer in ptr_mode.  */
+#define STACK_SAVEAREA_MODE(LEVEL) ptr_mode
+
 /* Specify the machine mode that bounds have.  */
 #define BNDmode (ix86_pmode == PMODE_DI ? BND64mode : BND32mode)
 
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index c08e4f55cff..c563a26cd60 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -18375,6 +18375,42 @@
   "* return output_probe_stack_range (operands[0], operands[2]);"
   [(set_attr "type" "multi")])
 
+;; Non-local goto support.
+
+(define_expand "save_stack_nonlocal"
+  [(use (match_operand 0 "memory_operand" ""))
+   (use (match_operand 1 "register_operand" ""))]
+  ""
+{
+  /* Stack is saved in ptr_mode and stack register is in Pmode.  */
+  if (GET_MODE (operands[0]) != GET_MODE (operands[1]))
+    {
+      if (GET_MODE (operands[0]) != ptr_mode
+         || GET_MODE (operands[1]) != Pmode)
+       gcc_unreachable ();
+      operands[1] = gen_rtx_SUBREG (ptr_mode, operands[1], 0);
+    }
+  emit_move_insn (operands[0], operands[1]);
+  DONE;
+})
+
+(define_expand "restore_stack_nonlocal"
+  [(use (match_operand 0 "register_operand" ""))
+   (use (match_operand 1 "memory_operand" ""))]
+  ""
+{
+  /* Stack is saved in ptr_mode and stack register is in Pmode.  */
+  if (GET_MODE (operands[0]) != GET_MODE (operands[1]))
+    {
+      if (GET_MODE (operands[0]) != Pmode
+         || GET_MODE (operands[1]) != ptr_mode)
+       gcc_unreachable ();
+      operands[1] = gen_rtx_ZERO_EXTEND (Pmode, operands[1]);
+    }
+  emit_move_insn (operands[0], operands[1]);
+  DONE;
+})
+
 /* Additional processing for builtin_setjmp.  Store the shadow stack pointer
    as a forth element in jmpbuf.  */
 (define_expand "builtin_setjmp_setup"
diff --git a/gcc/testsuite/gcc.dg/pr84150.c b/gcc/testsuite/gcc.dg/pr84150.c
new file mode 100644
index 00000000000..1e7a04c1e9c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr84150.c
@@ -0,0 +1,45 @@
+/* { dg-do run } */
+/* { dg-options "-O" } */
+/* { dg-require-effective-target indirect_jumps } */
+
+void *buf[6] = {
+  (void *) -1,
+  (void *) -1,
+  (void *) -1,
+  (void *) -1,
+  (void *) -1,
+  (void *) -1
+};
+
+void raise0(void)
+{
+  __builtin_longjmp (buf, 1);
+}
+
+int execute(int cmd)
+{
+  int last = 0;
+
+  if (__builtin_setjmp (buf) == 0)
+    while (1)
+      {
+        last = 1;
+        raise0 ();
+      }
+
+  if (last == 0)
+    return 0;
+  else
+    return cmd;
+}
+
+int main(void)
+{
+  if (execute (1) == 0)
+    __builtin_abort ();
+
+  if (buf[5] != (void *) -1)
+    __builtin_abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr84150.c 
b/gcc/testsuite/gcc.target/i386/pr84150.c
new file mode 100644
index 00000000000..11d3d361487
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr84150.c
@@ -0,0 +1,44 @@
+/* { dg-do run { target x32 } } */
+/* { dg-options "-O -maddress-mode=long" } */
+
+void *buf[6] = {
+  (void *) -1,
+  (void *) -1,
+  (void *) -1,
+  (void *) -1,
+  (void *) -1,
+  (void *) -1
+};
+
+void raise0(void)
+{
+  __builtin_longjmp (buf, 1);
+}
+
+int execute(int cmd)
+{
+  int last = 0;
+
+  if (__builtin_setjmp (buf) == 0)
+    while (1)
+      {
+        last = 1;
+        raise0 ();
+      }
+
+  if (last == 0)
+    return 0;
+  else
+    return cmd;
+}
+
+int main(void)
+{
+  if (execute (1) == 0)
+    __builtin_abort ();
+
+  if (buf[5] != (void *) -1)
+    __builtin_abort ();
+
+  return 0;
+}
-- 
2.14.3

Reply via email to