aboutsummaryrefslogtreecommitdiff
path: root/gcc/fold-const.c
diff options
context:
space:
mode:
authorMartin Sebor <msebor@redhat.com>2018-07-09 20:33:48 +0000
committerMartin Sebor <msebor@gcc.gnu.org>2018-07-09 14:33:48 -0600
commit35b4d3a644222b7bd69b3a1e9c00e78f3dbf3eba (patch)
treea540d226c0eeee38bd5ea06483ae688c1e0c070e /gcc/fold-const.c
parentaad2444d346d4ae504a938de8708341dd1889aed (diff)
downloadgcc-35b4d3a644222b7bd69b3a1e9c00e78f3dbf3eba.zip
gcc-35b4d3a644222b7bd69b3a1e9c00e78f3dbf3eba.tar.gz
gcc-35b4d3a644222b7bd69b3a1e9c00e78f3dbf3eba.tar.bz2
PR middle-end/77357 - strlen of constant strings not folded
gcc/ChangeLog: PR middle-end/77357 PR middle-end/86428 * builtins.c (c_strlen): Avoid out-of-bounds warnings when accessing implicitly initialized array elements. * expr.c (string_constant): Handle string initializers of character arrays within aggregates. * gimple-fold.c (fold_array_ctor_reference): Add argument. Store element offset. As a special case, handle zero size. (fold_nonarray_ctor_reference): Same. (fold_ctor_reference): Add argument. Store subobject offset. * gimple-fold.h (fold_ctor_reference): Add argument. gcc/testsuite/ChangeLog: PR middle-end/77357 * gcc.dg/strlenopt-49.c: New test. * gcc.dg/strlenopt-50.c: New test. * gcc.dg/strlenopt-51.c: New test. * gcc.dg/strlenopt-52.c: New test. From-SVN: r262522
Diffstat (limited to 'gcc/fold-const.c')
-rw-r--r--gcc/fold-const.c58
1 files changed, 46 insertions, 12 deletions
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 5b94c70..97c435f 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -14546,14 +14546,19 @@ fold_build_pointer_plus_hwi_loc (location_t loc, tree ptr, HOST_WIDE_INT off)
ptr, size_int (off));
}
-/* Return a char pointer for a C string if it is a string constant
- or sum of string constant and integer constant. We only support
- string constants properly terminated with '\0' character.
- If STRLEN is a valid pointer, length (including terminating character)
- of returned string is stored to the argument. */
+/* Return a pointer P to a NUL-terminated string representing the sequence
+ of constant characters referred to by SRC (or a subsequence of such
+ characters within it if SRC is a reference to a string plus some
+ constant offset). If STRLEN is non-null, store stgrlen(P) in *STRLEN.
+ If STRSIZE is non-null, store in *STRSIZE the size of the array
+ the string is stored in; in that case, even though P points to a NUL
+ terminated string, SRC need not refer to one. This can happen when
+ SRC refers to a constant character array initialized to all non-NUL
+ values, as in the C declaration: char a[4] = "1234"; */
const char *
-c_getstr (tree src, unsigned HOST_WIDE_INT *strlen)
+c_getstr (tree src, unsigned HOST_WIDE_INT *strlen /* = NULL */,
+ unsigned HOST_WIDE_INT *strsize /* = NULL */)
{
tree offset_node;
@@ -14573,18 +14578,47 @@ c_getstr (tree src, unsigned HOST_WIDE_INT *strlen)
offset = tree_to_uhwi (offset_node);
}
+ /* STRING_LENGTH is the size of the string literal, including any
+ embedded NULs. STRING_SIZE is the size of the array the string
+ literal is stored in. */
unsigned HOST_WIDE_INT string_length = TREE_STRING_LENGTH (src);
+ unsigned HOST_WIDE_INT string_size = string_length;
+ tree type = TREE_TYPE (src);
+ if (tree size = TYPE_SIZE_UNIT (type))
+ if (tree_fits_shwi_p (size))
+ string_size = tree_to_uhwi (size);
+
+ if (strlen)
+ {
+ /* Compute and store the length of the substring at OFFSET.
+ All offsets past the initial length refer to null strings. */
+ if (offset <= string_length)
+ *strlen = string_length - offset;
+ else
+ *strlen = 0;
+ }
+
const char *string = TREE_STRING_POINTER (src);
- /* Support only properly null-terminated strings. */
if (string_length == 0
- || string[string_length - 1] != '\0'
- || offset >= string_length)
+ || offset >= string_size)
return NULL;
- if (strlen)
- *strlen = string_length - offset;
- return string + offset;
+ if (strsize)
+ {
+ /* Support even constant character arrays that aren't proper
+ NUL-terminated strings. */
+ *strsize = string_size;
+ }
+ else if (string[string_length - 1] != '\0')
+ {
+ /* Support only properly NUL-terminated strings but handle
+ consecutive strings within the same array, such as the six
+ substrings in "1\0002\0003". */
+ return NULL;
+ }
+
+ return offset <= string_length ? string + offset : "";
}
/* Given a tree T, compute which bits in T may be nonzero. */