diff mbox

RFA: Fix calculation of size of builtin setjmp buffer

Message ID 87wqdzjccp.fsf@redhat.com
State New
Headers show

Commit Message

Nick Clifton May 6, 2014, 12:55 p.m. UTC
Hi Guys,

  There is a small bug in the computation for the size of the builtin
  setjmp buffer.  The size is based upon BITS_PER_WORD / POINTER_SIZE
  which for most targets equates to 1.  But for targets where pointers
  are larger than a word, it equates to zero.  This leads to stack
  corruption and all kinds of fun things.

  The patch is obvious - see below - but since it affects generic code
  and might have consequences which I have not foreseen, I thought it
  best to ask for approval first.

  No regressions with an x86_64-pc-linux toolchain, and quite a few G++
  testsuite fixes for an rl78-elf toolchain.

  OK to apply ?

Cheers
  Nick

2014-05-06  Nick Clifton  <nickc@redhat.com>

	* except.c (init_eh): Fix computation of builtin setjmp buffer
	size.

Comments

Jakub Jelinek May 6, 2014, 1:15 p.m. UTC | #1
On Tue, May 06, 2014 at 01:55:18PM +0100, Nick Clifton wrote:
> 2014-05-06  Nick Clifton  <nickc@redhat.com>
> 
> 	* except.c (init_eh): Fix computation of builtin setjmp buffer
> 	size.
> 
> Index: gcc/except.c
> ===================================================================
> --- gcc/except.c	(revision 210096)
> +++ gcc/except.c	(working copy)
> @@ -287,7 +287,7 @@
>  #endif
>  #else
>        /* builtin_setjmp takes a pointer to 5 words.  */
> -      tmp = size_int (5 * BITS_PER_WORD / POINTER_SIZE - 1);
> +      tmp = size_int (5 * POINTER_SIZE / BITS_PER_WORD - 1);
>  #endif
>        tmp = build_index_type (tmp);
>        tmp = build_array_type (ptr_type_node, tmp);

That doesn't look correct to me.  If the code wants to create 5 words long
array, but with pointer elements (instead of word sized elements), then
5 * BITS_PER_WORD is the desired size in bits of the buffer, POINTER_SIZE
is how many bits each void *array[...] element occupies and thus
5 * BITS_PER_WORD / POINTER_SIZE - 1 is the right last element, so I'd
say the previous expression is the right one.  Perhaps you want to round up
rather than down, but certainly not swap the division operands.

Now, if the code actually expects 5 pointers, rather than 5 words, or
something else, then you'd at least need to also fix the comment.

	Jakub
Eric Botcazou May 14, 2014, 8:16 a.m. UTC | #2
> 2014-05-06  Nick Clifton  <nickc@redhat.com>
> 
> 	* except.c (init_eh): Fix computation of builtin setjmp buffer
> 	size.

That's the same patch as
  https://gcc.gnu.org/ml/gcc-patches/2011-11/msg00272.html
and is still incorrect.
Nick Clifton May 14, 2014, 1:32 p.m. UTC | #3
Hi Eric,

>> 2014-05-06  Nick Clifton  <nickc@redhat.com>
>>
>> 	* except.c (init_eh): Fix computation of builtin setjmp buffer
>> 	size.
>
> That's the same patch as
>    https://gcc.gnu.org/ml/gcc-patches/2011-11/msg00272.html
> and is still incorrect.

Ah - you are worried about the case where STACK_SAVEAREA_MODE() is 
smaller than Pmode, yes ?

OK then, how about this revised version of the patch where the size 
computation is now:

      tmp = size_int (MAX (GET_MODE_SIZE (STACK_SAVEAREA_MODE 
(SAVE_NONLOCAL))
			   / GET_MODE_SIZE (Pmode), 1)
		      + 2 /* Stack pointer and frame pointer.  */
		      + 1 /* Slop for mips.  */
		      - 1);

OK to apply ?

Cheers
   Nick
Eric Botcazou May 15, 2014, 7:55 a.m. UTC | #4
> Ah - you are worried about the case where STACK_SAVEAREA_MODE() is
> smaller than Pmode, yes ?

No, simply that the modified formula is plain wrong.  The code does:

  tmp = size_int (5 * BITS_PER_WORD / POINTER_SIZE - 1);
  tmp = build_index_type (tmp);
  tmp = build_array_type (ptr_type_node, tmp);

so, in the end, the size of the buffer is:

  [(5 * BITS_PER_WORD / POINTER_SIZE - 1) + 1] * POINTER_SIZE

which boilds down to:

  5 * BITS_PER_WORD

provided that POINTER_SIZE <= BITS_PER_WORD.


So we have a problem if POINTER_SIZE > BITS_PER_WORD, in which case it's 
sufficient to use 5 * POINTER_SIZE instead.

> OK then, how about this revised version of the patch where the size
> computation is now:
> 
>       tmp = size_int (MAX (GET_MODE_SIZE (STACK_SAVEAREA_MODE
> (SAVE_NONLOCAL))
> 			   / GET_MODE_SIZE (Pmode), 1)
> 		      + 2 /* Stack pointer and frame pointer.  */
> 		      + 1 /* Slop for mips.  */
> 		      - 1);
> 
> OK to apply ?

No, that's too complicated and risky, just do the following:

      /* builtin_setjmp takes a pointer to 5 words or pointers.  */
      if (POINTER_SIZE > BITS_PER_WORD)
	tmp = size_int (4);
      else
	tmp = size_int (5 * BITS_PER_WORD / POINTER_SIZE - 1);

which is simple and safe.
Mike Stump May 15, 2014, 2:49 p.m. UTC | #5
On May 15, 2014, at 12:55 AM, Eric Botcazou <ebotcazou@adacore.com> wrote:
> No, that's too complicated and risky, just do the following:
> 
>      /* builtin_setjmp takes a pointer to 5 words or pointers.  */
>      if (POINTER_SIZE > BITS_PER_WORD)
> 	tmp = size_int (4);
>      else
> 	tmp = size_int (5 * BITS_PER_WORD / POINTER_SIZE - 1);
> 
> which is simple and safe.

But, fails whenever the size of the mode of the save area is bigger than a certain amount…  On my port, the size taken up by the  save area is large enough to cause this to fail.  :-(  The correct bug fix would have my port not fail.
Eric Botcazou May 16, 2014, 4:55 p.m. UTC | #6
> But, fails whenever the size of the mode of the save area is bigger than a
> certain amount…  On my port, the size taken up by the  save area is large
> enough to cause this to fail.  :-(

That's a bit unexpected, why do you need so big a save area exactly?  The only 
architecture for which this doesn't work is the IA-64, which is a very special 
beast...  In this case, the way out is to define DONT_USE_BUILTIN_SETJMP and 
JMP_BUF_SIZE to the needed size.
diff mbox

Patch

Index: gcc/except.c
===================================================================
--- gcc/except.c	(revision 210096)
+++ gcc/except.c	(working copy)
@@ -287,7 +287,7 @@ 
 #endif
 #else
       /* builtin_setjmp takes a pointer to 5 words.  */
-      tmp = size_int (5 * BITS_PER_WORD / POINTER_SIZE - 1);
+      tmp = size_int (5 * POINTER_SIZE / BITS_PER_WORD - 1);
 #endif
       tmp = build_index_type (tmp);
       tmp = build_array_type (ptr_type_node, tmp);