]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Fix segfault during encoding of CONSTRUCTORs
authorEric Botcazou <ebotcazou@adacore.com>
Fri, 19 Mar 2021 08:21:11 +0000 (09:21 +0100)
committerEric Botcazou <ebotcazou@adacore.com>
Fri, 19 Mar 2021 09:44:20 +0000 (10:44 +0100)
The segfault occurs in native_encode_initializer when it is encoding the
CONSTRUCTOR for an array whose lower bound is negative (it's OK in Ada).
The computation of the current position is done in HOST_WIDE_INT and this
does not work for arrays whose original range has a negative lower bound
and a positive upper bound; the computation must be done in sizetype
instead so that it may wrap around.

gcc/
PR middle-end/99641
* fold-const.c (native_encode_initializer) <CONSTRUCTOR>: For an
array type, do the computation of the current position in sizetype.

gcc/fold-const.c

index 07ec9ab2dfa472112b28ad33d617153d5dbfd094..f23ccc2992292a2bc6955484ce29a97cdc7e6a93 100644 (file)
@@ -7943,21 +7943,21 @@ native_encode_initializer (tree init, unsigned char *ptr, int len,
       int o = off == -1 ? 0 : off;
       if (TREE_CODE (type) == ARRAY_TYPE)
        {
-         HOST_WIDE_INT min_index;
+         tree min_index;
          unsigned HOST_WIDE_INT cnt;
          HOST_WIDE_INT curpos = 0, fieldsize;
          constructor_elt *ce;
 
-         if (TYPE_DOMAIN (type) == NULL_TREE
-             || !tree_fits_shwi_p (TYPE_MIN_VALUE (TYPE_DOMAIN (type))))
+         if (!TYPE_DOMAIN (type)
+             || TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) != INTEGER_CST)
            return 0;
 
          fieldsize = int_size_in_bytes (TREE_TYPE (type));
          if (fieldsize <= 0)
            return 0;
 
-         min_index = tree_to_shwi (TYPE_MIN_VALUE (TYPE_DOMAIN (type)));
-         if (ptr != NULL)
+         min_index = TYPE_MIN_VALUE (TYPE_DOMAIN (type));
+         if (ptr)
            memset (ptr, '\0', MIN (total_bytes - off, len));
 
          FOR_EACH_VEC_SAFE_ELT (CONSTRUCTOR_ELTS (init), cnt, ce)
@@ -7968,19 +7968,37 @@ native_encode_initializer (tree init, unsigned char *ptr, int len,
              bool full = false;
              if (index && TREE_CODE (index) == RANGE_EXPR)
                {
-                 if (!tree_fits_shwi_p (TREE_OPERAND (index, 0))
-                     || !tree_fits_shwi_p (TREE_OPERAND (index, 1)))
+                 if (TREE_CODE (TREE_OPERAND (index, 0)) != INTEGER_CST
+                     || TREE_CODE (TREE_OPERAND (index, 1)) != INTEGER_CST)
+                   return 0;
+                 offset_int wpos
+                   = wi::sext (wi::to_offset (TREE_OPERAND (index, 0))
+                               - wi::to_offset (min_index),
+                               TYPE_PRECISION (sizetype));
+                 wpos *= fieldsize;
+                 if (!wi::fits_shwi_p (pos))
                    return 0;
-                 pos = (tree_to_shwi (TREE_OPERAND (index, 0)) - min_index)
-                       * fieldsize;
-                 count = (tree_to_shwi (TREE_OPERAND (index, 1))
-                          - tree_to_shwi (TREE_OPERAND (index, 0)));
+                 pos = wpos.to_shwi ();
+                 offset_int wcount
+                   = wi::sext (wi::to_offset (TREE_OPERAND (index, 1))
+                               - wi::to_offset (TREE_OPERAND (index, 0)),
+                               TYPE_PRECISION (sizetype));
+                 if (!wi::fits_shwi_p (wcount))
+                   return 0;
+                 count = wcount.to_shwi ();
                }
              else if (index)
                {
-                 if (!tree_fits_shwi_p (index))
+                 if (TREE_CODE (index) != INTEGER_CST)
+                   return 0;
+                 offset_int wpos
+                   = wi::sext (wi::to_offset (index)
+                               - wi::to_offset (min_index),
+                               TYPE_PRECISION (sizetype));
+                 wpos *= fieldsize;
+                 if (!wi::fits_shwi_p (wpos))
                    return 0;
-                 pos = (tree_to_shwi (index) - min_index) * fieldsize;
+                 pos = wpos.to_shwi ();
                }
 
              curpos = pos;