diff options
author | Jakub Jelinek <jakub@redhat.com> | 2020-12-19 22:24:10 +0100 |
---|---|---|
committer | Jakub Jelinek <jakub@redhat.com> | 2020-12-19 22:24:10 +0100 |
commit | 69165332a914f1167c3077fa1f57afc64fd8a667 (patch) | |
tree | 39b48d9a3a3ecc7f8913d238dd513dbdbc3a6d1f /gcc/fold-const.c | |
parent | e9e4ddfc5abbf9ee5e657d626264cef89f10b4c3 (diff) | |
download | gcc-69165332a914f1167c3077fa1f57afc64fd8a667.zip gcc-69165332a914f1167c3077fa1f57afc64fd8a667.tar.gz gcc-69165332a914f1167c3077fa1f57afc64fd8a667.tar.bz2 |
expr: Fix up constant_byte_string bitfield handling [PR98366]
constant_byte_string now uses a convert_to_bytes function, which doesn't
handle bitfields at all (don't punt on them, just puts them into wrong bits
or bytes). Furthermore, I don't see a reason why that function should exist
at all, it duplicates native_encode_initializer functionality.
Except that native_encode_initializer punted on flexible array members and 2
tests in the testsuite relied on constant_byte_string handling those.
So, this patch throws away convert_to_bytes, uses native_encode_initializer
instead, but teaches it to handle flexible array members (only in the
non-mask mode with off == -1 for now), furthermore, it adds various corner
case checks that the old implementation was missing (like that STRING_CSTs
use int as length and therefore we shouldn't try to build larger than that
strings, or that native_encode*/native_interpret* APIs require sane
host and target bytes (8-bit on both).
2020-12-19 Jakub Jelinek <jakub@redhat.com>
PR middle-end/98366
* fold-const.c (native_encode_initializer): Don't try to
memset more than total_bytes with off == -1 even if len is large.
Handle flexible array member initializers if off == -1 and mask is
NULL.
* expr.c (convert_to_bytes): Remove.
(constant_byte_string): Use native_encode_initializer instead of
convert_to_bytes. Remove extraneous semicolon. Punt on various
corner-cases the APIs don't handle, like sizes > INT_MAX,
BITS_PER_UNIT != 8, CHAR_BIT != 8.
* gcc.c-torture/execute/pr98366.c: New test.
Diffstat (limited to 'gcc/fold-const.c')
-rw-r--r-- | gcc/fold-const.c | 63 |
1 files changed, 52 insertions, 11 deletions
diff --git a/gcc/fold-const.c b/gcc/fold-const.c index b78f3ab..1694ba4 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -8197,7 +8197,7 @@ native_encode_initializer (tree init, unsigned char *ptr, int len, gcc_assert (TREE_CODE (type) == RECORD_TYPE || mask == NULL); if (ptr != NULL) - memset (ptr, '\0', MIN (total_bytes - off, len)); + memset (ptr, '\0', MIN (total_bytes - o, len)); for (cnt = 0; ; cnt++) { tree val = NULL_TREE, field = NULL_TREE; @@ -8266,11 +8266,33 @@ native_encode_initializer (tree init, unsigned char *ptr, int len, if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE && TYPE_DOMAIN (TREE_TYPE (field)) && ! TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (field)))) - return 0; - if (DECL_SIZE_UNIT (field) == NULL_TREE - || !tree_fits_shwi_p (DECL_SIZE_UNIT (field))) - return 0; - fieldsize = tree_to_shwi (DECL_SIZE_UNIT (field)); + { + if (mask || off != -1) + return 0; + if (val == NULL_TREE) + continue; + if (TREE_CODE (TREE_TYPE (val)) != ARRAY_TYPE) + return 0; + fieldsize = int_size_in_bytes (TREE_TYPE (val)); + if (fieldsize < 0 + || (int) fieldsize != fieldsize + || (pos + fieldsize) > INT_MAX) + return 0; + if (pos + fieldsize > total_bytes) + { + if (ptr != NULL && total_bytes - o < len) + memset (ptr + (total_bytes - o), + '\0', MIN (pos + fieldsize - o, len)); + total_bytes = pos + fieldsize; + } + } + else + { + if (DECL_SIZE_UNIT (field) == NULL_TREE + || !tree_fits_shwi_p (DECL_SIZE_UNIT (field))) + return 0; + fieldsize = tree_to_shwi (DECL_SIZE_UNIT (field)); + } if (fieldsize == 0) continue; @@ -8439,12 +8461,31 @@ native_encode_initializer (tree init, unsigned char *ptr, int len, || (pos >= off && (pos + fieldsize <= (HOST_WIDE_INT) off + len))) { - if (!native_encode_initializer (val, ptr ? ptr + pos - o - : NULL, - fieldsize, - off == -1 ? -1 : 0, - mask ? mask + pos : NULL)) + int fldsize = fieldsize; + if (off == -1) + { + tree fld = DECL_CHAIN (field); + while (fld) + { + if (TREE_CODE (fld) == FIELD_DECL) + break; + fld = DECL_CHAIN (fld); + } + if (fld == NULL_TREE) + fldsize = len - pos; + } + r = native_encode_initializer (val, ptr ? ptr + pos - o + : NULL, + fldsize, + off == -1 ? -1 : 0, + mask ? mask + pos : NULL); + if (!r) return 0; + if (off == -1 + && fldsize != fieldsize + && r > fieldsize + && pos + r > total_bytes) + total_bytes = pos + r; } else { |