This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

[PATCH] Bug in setjmp/longjmp on Sparc


On Sun, Dec 21, 2036 at 04:46:12PM -0500, Richard Kenner wrote:
> Try running the following test case:
> 
> int buf[20];
> 
> void
> main ()
> {
>   char *p = (char *) alloca (20);
> 
>   strcpy (p, "test\n");
> 
>   if (__builtin_setjmp (buf))
>     {
>       printf (p);
>       exit (0);
>     }
> 
>   {
>     int *q = (int *) alloca (p[2] * sizeof (int));
>     int i;
>     
>     for (i = 0; i < p[2]; i++)
>       q[i] = 0;
> 
>     while (1)
>       sub2 ();
>   }
> }
> 
> sub2 ()
> {
>   __builtin_longjmp (buf, 1);
> }
> 
> 
> This will dump core on Solaris.  The reason is that the SP saved in the setjmp
> buffer is expected to be the location where the registers will be saved, but
> instead they are saved at the value of SP at the call.
> 
> Does anybody who knows the Sparc better than I do have any suggestions
> as to how to fix this?

This patch seems to fix this, ok to commit?
There were two issues: expand_builtin_setjmp was not setting
current_function_calls_setjmp, which is used by optimize_save_area_alloca
and so the alloca was done without the regwindow save area subtraction.
The second issue is that if we call setjmp and then do alloca in the same
function, we need to flush register windows, so that the register windows
make it to the address recorded in the setjmp buffer (otherwise they can be
well saved after the second alloca to a different place and longjmp reloads
garbage). This is correctly handled in glibc setjmp, I think Solaris does
not handle this correctly (if only the builtins.c part of the patch is
applied, it died on bus error unless run in the debugger where the register
window is saved during stepping through the function).
Can you install the testcase?

2000-11-14  Jakub Jelinek  <jakub@redhat.com>

	* builtins.c (expand_builtin_setjmp): Set
	current_function_calls_setjmp.
	(expand_builtin_longjmp): Set current_function_calls_longjmp.

	* config/sparc/sparc.md (builtin_setjmp_setup): New expand.
	(do_builtin_setjmp_setup): New insn.

--- gcc/config/sparc/sparc.md.jj	Mon Nov  6 11:44:02 2000
+++ gcc/config/sparc/sparc.md	Tue Nov 14 18:37:56 2000
@@ -50,6 +50,7 @@
 ;;			2	goto_handler_and_restore
 ;;			3	goto_handler_and_restore_v9*
 ;;			4	flush
+;;			5	do_builtin_setjmp_setup
 ;;
 
 ;; The upper 32 fp regs on the v9 can't hold SFmode values.  To deal with this
@@ -9013,6 +9014,32 @@
 ;;   sethi\\t%%hi(%2), %1\\n\\treturn\\t%0+0\\n\\tor\\t%Y1, %%lo(%2), %Y1"
 ;;  [(set_attr "type" "misc")
 ;;   (set_attr "length" "2,3")])
+
+;; For __builtin_setjmp we need to flush register windows iff the function
+;; calls alloca as well, because otherwise the register window might be
+;; saved after %sp adjustement and thus setjmp would crash
+(define_expand "builtin_setjmp_setup"
+  [(match_operand 0 "register_operand" "r")]
+  ""
+  "
+{
+  emit_insn (gen_do_builtin_setjmp_setup ());
+  DONE;
+}")
+
+(define_insn "do_builtin_setjmp_setup"
+  [(unspec_volatile [(const_int 0)] 5)]
+  ""
+  "*
+{
+  if (!current_function_calls_alloca)
+    return \"\";
+  if (TARGET_V9)
+    return \"flushw\";
+  return \"ta\\t3\";
+}"
+  [(set_attr "type" "misc")
+   (set_attr "length" "1")])
 
 ;; Pattern for use after a setjmp to store FP and the return register
 ;; into the stack area.
--- gcc/builtins.c.jj	Tue Nov 14 11:16:50 2000
+++ gcc/builtins.c	Tue Nov 14 17:51:55 2000
@@ -446,6 +446,7 @@ expand_builtin_setjmp (buf_addr, target,
      calls may traverse the arc back to this label.  */
 
   current_function_has_nonlocal_label = 1;
+  current_function_calls_setjmp = 1;
   nonlocal_goto_handler_labels
     = gen_rtx_EXPR_LIST (VOIDmode, lab1, nonlocal_goto_handler_labels);
 
@@ -546,6 +547,8 @@ expand_builtin_longjmp (buf_addr, value)
      longer copying around a value that we don't care about.  */
   if (value != const1_rtx)
     abort ();
+
+  current_function_calls_longjmp = 1;
 
 #ifdef HAVE_builtin_longjmp
   if (HAVE_builtin_longjmp)


	Jakub

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]