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]
Other format: [Raw text]

[patch] Update SJLJ buffer after dynamic stack allocation


Hi,

the SJLJ EH schemes manipulate a buffer that contains a few pointers and, in 
particular, the stack pointer.  Therefore, when dynamic stack allocation is 
also used, you need to update its value in the buffer, otherwise Bad Things 
will happen if you resume execution where the stack is shifted.

GNAT uses a manual SJLJ EH scheme that is piggybacked on the __builtin_setjmp 
__builtin_longjmp machinery and has this block in gcc-interface/decl.c:

	/* If we are defining an object with variable size or an object with
	   fixed size that will be dynamically allocated, and we are using the
	   setjmp/longjmp exception mechanism, update the setjmp buffer.  */
	if (definition
	    && Exception_Mechanism == Setjmp_Longjmp
	    && get_block_jmpbuf_decl ()
	    && DECL_SIZE_UNIT (gnu_decl)
	    && (TREE_CODE (DECL_SIZE_UNIT (gnu_decl)) != INTEGER_CST
		|| (flag_stack_check == GENERIC_STACK_CHECK
		    && compare_tree_int (DECL_SIZE_UNIT (gnu_decl),
					 STACK_CHECK_MAX_VAR_SIZE) > 0)))
	  add_stmt_with_node (build_call_n_expr
			      (update_setjmp_buf_decl, 1,
			       build_unary_op (ADDR_EXPR, NULL_TREE,
					       get_block_jmpbuf_decl ())),
			      gnat_entity);

It is necessary if you want to pass the ACATS testsuite.

But the regular SJLJ scheme (--enable-sjlj-exceptions) doesn't do this update 
and, therefore, doesn't play nice with dynamic stack allocation.  It's a long-
standing issue and you can find messages about it in the archives.  On the 
other hand, this update has always been done for non-local gotos (they also 
use a buffer, the non-local goto save area).

The attached patch implements this update for the regular SJLJ scheme and 
yields a clean ACATS testsuite.  Tested on x86_64-suse-linux with --enable-
sjlj-exceptions, OK for the mainline?


2015-05-13  Eric Botcazou  <ebotcazou@adacore.com>
            Tristan Gingold  <gingold@adacore.com>

	* insn-notes.def (UPDATE_SJLJ_CONTEXT): New note.
	* builtins.c (expand_builtin_update_setjmp_buf): Make global.
	(expand_stack_restore): Call record_new_stack_level.
	(expand_stack_save): Do not call do_pending_stack_adjust.
	* builtins.h (expand_builtin_update_setjmp_buf): Declare.
	* calls.c (expand_call): Call record_new_stack_level for alloca.
	* except.c (sjlj_mark_call_sites): Expand builtin_update_setjmp_buf
	wherever a NOTE_INSN_UPDATE_SJLJ_CONTEXT note is present.
	(update_sjlj_context): New global function.
	* except.h (update_sjlj_context): Declare.
	* explow.c (record_new_stack_level): New global function.
	(allocate_dynamic_stack_space): Call record_new_stack_level.
	* explow.h (record_new_stack_level): Declare.
	* final.c (final_scan_insn): Deal with NOTE_INSN_UPDATE_SJLJ_CONTEXT.
	* cfgrtl.c (duplicate_insn_chain): Likewise.


-- 
Eric Botcazou
Index: builtins.c
===================================================================
--- builtins.c	(revision 222673)
+++ builtins.c	(working copy)
@@ -120,7 +120,6 @@ static int apply_result_size (void);
 #if defined (HAVE_untyped_call) || defined (HAVE_untyped_return)
 static rtx result_vector (int, rtx);
 #endif
-static void expand_builtin_update_setjmp_buf (rtx);
 static void expand_builtin_prefetch (tree);
 static rtx expand_builtin_apply_args (void);
 static rtx expand_builtin_apply_args_1 (void);
@@ -1213,10 +1212,10 @@ expand_builtin_nonlocal_goto (tree exp)
 
 /* __builtin_update_setjmp_buf is passed a pointer to an array of five words
    (not all will be used on all machines) that was passed to __builtin_setjmp.
-   It updates the stack pointer in that block to correspond to the current
-   stack pointer.  */
+   It updates the stack pointer in that block to the current value.  This is
+   also called directly by the SJLJ exception handling code.  */
 
-static void
+void
 expand_builtin_update_setjmp_buf (rtx buf_addr)
 {
   machine_mode sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
@@ -5891,10 +5890,12 @@ expand_stack_restore (tree var)
 
   prev = get_last_insn ();
   emit_stack_restore (SAVE_BLOCK, sa);
+
+  record_new_stack_level ();
+
   fixup_args_size_notes (prev, get_last_insn (), 0);
 }
 
-
 /* Emit code to save the current value of stack.  */
 
 static rtx
@@ -5902,7 +5903,6 @@ expand_stack_save (void)
 {
   rtx ret = NULL_RTX;
 
-  do_pending_stack_adjust ();
   emit_stack_save (SAVE_BLOCK, &ret);
   return ret;
 }
Index: final.c
===================================================================
--- final.c	(revision 222673)
+++ final.c	(working copy)
@@ -2215,6 +2215,7 @@ final_scan_insn (rtx_insn *insn, FILE *f
       switch (NOTE_KIND (insn))
 	{
 	case NOTE_INSN_DELETED:
+	case NOTE_INSN_UPDATE_SJLJ_CONTEXT:
 	  break;
 
 	case NOTE_INSN_SWITCH_TEXT_SECTIONS:
Index: builtins.h
===================================================================
--- builtins.h	(revision 222673)
+++ builtins.h	(working copy)
@@ -59,6 +59,7 @@ extern unsigned int get_pointer_alignmen
 extern tree c_strlen (tree, int);
 extern void expand_builtin_setjmp_setup (rtx, rtx);
 extern void expand_builtin_setjmp_receiver (rtx);
+extern void expand_builtin_update_setjmp_buf (rtx);
 extern tree mathfn_built_in (tree, enum built_in_function fn);
 extern rtx builtin_strncpy_read_str (void *, HOST_WIDE_INT, machine_mode);
 extern rtx builtin_memset_read_str (void *, HOST_WIDE_INT, machine_mode);
Index: insn-notes.def
===================================================================
--- insn-notes.def	(revision 222673)
+++ insn-notes.def	(working copy)
@@ -87,4 +87,8 @@ INSN_NOTE (CFI)
    label that should be emitted.  */
 INSN_NOTE (CFI_LABEL)
 
+/* This note indicates that the function context must be updated if
+   the Setjmp/Longjmp exception mechanism is used.  */
+INSN_NOTE (UPDATE_SJLJ_CONTEXT)
+
 #undef INSN_NOTE
Index: calls.c
===================================================================
--- calls.c	(revision 222673)
+++ calls.c	(working copy)
@@ -3632,12 +3632,9 @@ expand_call (tree exp, rtx target, int i
 	  stack_usage_map = initial_stack_usage_map;
 	}
 
-      /* If this was alloca, record the new stack level for nonlocal gotos.
-	 Check for the handler slots since we might not have a save area
-	 for non-local gotos.  */
-
-      if ((flags & ECF_MAY_BE_ALLOCA) && cfun->nonlocal_goto_save_area != 0)
-	update_nonlocal_goto_save_area ();
+      /* If this was alloca, record the new stack level.  */
+      if (flags & ECF_MAY_BE_ALLOCA)
+	record_new_stack_level ();
 
       /* Free up storage we no longer need.  */
       for (i = 0; i < num_actuals; ++i)
Index: except.c
===================================================================
--- except.c	(revision 222673)
+++ except.c	(working copy)
@@ -1126,6 +1126,21 @@ sjlj_mark_call_sites (void)
       if (LABEL_P (insn))
 	last_call_site = -2;
 
+      /* If the function allocates dynamic stack space, the context must
+	 be updated after every allocation/deallocation accordingly.  */
+      if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_UPDATE_SJLJ_CONTEXT)
+	{
+	  rtx buf_addr;
+
+	  start_sequence ();
+	  buf_addr = plus_constant (Pmode, XEXP (crtl->eh.sjlj_fc, 0),
+				    sjlj_fc_jbuf_ofs);
+	  expand_builtin_update_setjmp_buf (buf_addr);
+	  p = get_insns ();
+	  end_sequence ();
+	  emit_insn_before (p, insn);
+	}
+
       if (! INSN_P (insn))
 	continue;
 
@@ -1495,6 +1510,18 @@ sjlj_build_landing_pads (void)
   sjlj_lp_call_site_index.release ();
 }
 
+/* Update the sjlj function context.  This function should be called
+   whenever we allocate or deallocate dynamic stack space.  */
+
+void
+update_sjlj_context (void)
+{
+  if (!flag_exceptions)
+    return;
+
+  emit_note (NOTE_INSN_UPDATE_SJLJ_CONTEXT);
+}
+
 /* After initial rtl generation, call back to finish generating
    exception support code.  */
 
Index: except.h
===================================================================
--- except.h	(revision 222673)
+++ except.h	(working copy)
@@ -252,6 +252,7 @@ extern hash_map<void *, void *> *duplica
   (struct function *, eh_region, int, duplicate_eh_regions_map, void *);
 
 extern void sjlj_emit_function_exit_after (rtx_insn *);
+extern void update_sjlj_context (void);
 
 extern eh_region gen_eh_region_cleanup (eh_region);
 extern eh_region gen_eh_region_try (eh_region);
Index: explow.c
===================================================================
--- explow.c	(revision 222673)
+++ explow.c	(working copy)
@@ -1096,8 +1096,8 @@ emit_stack_restore (enum save_level save
 }
 
 /* Invoke emit_stack_save on the nonlocal_goto_save_area for the current
-   function.  This function should be called whenever we allocate or
-   deallocate dynamic stack space.  */
+   function.  This should be called whenever we allocate or deallocate
+   dynamic stack space.  */
 
 void
 update_nonlocal_goto_save_area (void)
@@ -1117,6 +1117,21 @@ update_nonlocal_goto_save_area (void)
 
   emit_stack_save (SAVE_NONLOCAL, &r_save);
 }
+
+/* Record a new stack level for the current function.  This should be called
+   whenever we allocate or deallocate dynamic stack space.  */
+
+void
+record_new_stack_level (void)
+{
+  /* Record the new stack level for nonlocal gotos.  */
+  if (cfun->nonlocal_goto_save_area)
+    update_nonlocal_goto_save_area ();
+ 
+  /* Record the new stack level for SJLJ exceptions.  */
+  if (targetm_common.except_unwind_info (&global_options) == UI_SJLJ)
+    update_sjlj_context ();
+}
 
 /* Return an rtx representing the address of an area of memory dynamically
    pushed on the stack.
@@ -1479,9 +1494,8 @@ allocate_dynamic_stack_space (rtx size,
   /* Now that we've committed to a return value, mark its alignment.  */
   mark_reg_pointer (target, required_align);
 
-  /* Record the new stack level for nonlocal gotos.  */
-  if (cfun->nonlocal_goto_save_area != 0)
-    update_nonlocal_goto_save_area ();
+  /* Record the new stack level.  */
+  record_new_stack_level ();
 
   return target;
 }
Index: explow.h
===================================================================
--- explow.h	(revision 222673)
+++ explow.h	(working copy)
@@ -78,6 +78,9 @@ extern void emit_stack_restore (enum sav
 /* Invoke emit_stack_save for the nonlocal_goto_save_area.  */
 extern void update_nonlocal_goto_save_area (void);
 
+/* Record a new stack level.  */
+extern void record_new_stack_level (void);
+
 /* Allocate some space on the stack dynamically and return its address.  */
 extern rtx allocate_dynamic_stack_space (rtx, unsigned, unsigned, bool);
 
Index: cfgrtl.c
===================================================================
--- cfgrtl.c	(revision 222673)
+++ cfgrtl.c	(working copy)
@@ -4209,6 +4209,7 @@ duplicate_insn_chain (rtx_insn *from, rt
 	      break;
 
 	    case NOTE_INSN_EPILOGUE_BEG:
+	    case NOTE_INSN_UPDATE_SJLJ_CONTEXT:
 	      emit_note_copy (as_a <rtx_note *> (insn));
 	      break;
 

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