[PATCH] Fix buffer overflow in simplify_immed_subreg

Jakub Jelinek jakub@redhat.com
Sat Aug 20 20:41:00 GMT 2005


Hi!

The following testcase causes
*** stack smashing detected ***: /usr/libexec/gcc/i386-redhat-linux/4.0.1/cc1 terminated
when gcc is built with -fstack-protector.
The problematic simplify_immed_subreg call is:
simplify_immed_subreg (outermode=V16QImode, op, innermode=V2DImode, byte=0)
where op is
(const_vector:V2DI [
        (const_double 168430090 [0xa0a0a0a] 168430090 [0xa0a0a0a] 0 [0x0] 0
[0x0] 0 [0x0] 0 [0x0])
        (const_double 168430090 [0xa0a0a0a] 168430090 [0xa0a0a0a] 0 [0x0] 0
[0x0] 0 [0x0] 0 [0x0])
    ])
CONST_VECTOR has 2 elements, both VOIDmode CONST_DOUBLEs.
value is a 64 byte long array (max_bitsize / value_bit).
When handling the first CONST_DOUBLE, vp will be set to &value[0] before getting
into the
case CONST_DOUBLE:
so clearing bits up to max_bitsize causes no overflow.
But for the second CONST_DOUBLE, vp will be &value[8] (the first CONST_DOUBLE
covered 64 bits), and so we clear 8 bytes after the value array, which can be stack
canary, return address or whatever else.
When handling CONST_INTs or MODE_FLOAT CONST_DOUBLEs, simplify_immed_subreg just
clears (or sign extends) bits up to elem_bitsize, which makes sense:
          /* CONST_INTs are always logically sign-extended.  */
          for (; i < elem_bitsize; i += value_bit)
            *vp++ = INTVAL (el) < 0 ? -1 : 0;
resp.
              /* It shouldn't matter what's done here, so fill it with
                 zero.  */
              for (; i < elem_bitsize; i += value_bit)
                *vp++ = 0;
Only VOIDmode CONST_DOUBLEs do the surprising:
              /* It shouldn't matter what's done here, so fill it with
                 zero.  */
              for (; i < max_bitsize; i += value_bit)
                *vp++ = 0;
which really can't work.  Really sounds like a typo to me.
The bug has been introduced in 3.4.
Ok to commit to 3.4/4.0/HEAD?

2005-08-20  Jakub Jelinek  <jakub@redhat.com>

	* simplify-rtx.c (simplify_immed_subreg) <case CONST_DOUBLE>: Only clear
	up to elem_bitsize bits, not max_bitsize.

	* gcc.target/i386/sse-4.c: New test.

--- gcc/simplify-rtx.c.jj	2005-08-20 04:24:41.000000000 -0400
+++ gcc/simplify-rtx.c	2005-08-20 16:02:21.613690586 -0400
@@ -3605,7 +3605,7 @@ simplify_immed_subreg (enum machine_mode
 		}
 	      /* It shouldn't matter what's done here, so fill it with
 		 zero.  */
-	      for (; i < max_bitsize; i += value_bit)
+	      for (; i < elem_bitsize; i += value_bit)
 		*vp++ = 0;
 	    }
 	  else
--- gcc/testsuite/gcc.target/i386/sse-4.c.jj	2005-08-20 16:04:34.754403712 -0400
+++ gcc/testsuite/gcc.target/i386/sse-4.c	2005-08-20 16:06:58.996092357 -0400
@@ -0,0 +1,10 @@
+/* This testcase caused a buffer overflow in simplify_immed_subreg.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -msse2" } */
+
+#include <emmintrin.h>
+
+__m128i foo (__m128i x)
+{
+  return _mm_min_epu8 (x, _mm_set1_epi8 (10));
+}

	Jakub



More information about the Gcc-patches mailing list