aboutsummaryrefslogtreecommitdiff
path: root/gcc/expr.c
diff options
context:
space:
mode:
authorMartin Sebor <msebor@redhat.com>2018-07-25 02:11:31 +0000
committerMartin Sebor <msebor@gcc.gnu.org>2018-07-24 20:11:31 -0600
commitbfb9bd47b2daac0a01c561effac1d8244ddd99f6 (patch)
treebf72d7afae065152f74b4f862adffad1c954d61e /gcc/expr.c
parentae752f020fd86b2d34a1556124dc4e5f01a8dcce (diff)
downloadgcc-bfb9bd47b2daac0a01c561effac1d8244ddd99f6.zip
gcc-bfb9bd47b2daac0a01c561effac1d8244ddd99f6.tar.gz
gcc-bfb9bd47b2daac0a01c561effac1d8244ddd99f6.tar.bz2
PR tree-optimization/86622 - incorrect strlen of array of array plus variable offset
PR tree-optimization/86622 - incorrect strlen of array of array plus variable offset PR tree-optimization/86532 - Wrong code due to a wrong strlen folding starting with r262522 gcc/ChangeLog: PR tree-optimization/86622 PR tree-optimization/86532 * builtins.h (string_length): Declare. * builtins.c (c_strlen): Correct handling of non-constant offsets. (check_access): Be prepared for non-constant length ranges. (string_length): Make extern. * expr.c (string_constant): Only handle the minor non-constant array index. Use string_constant to compute the length of a generic string constant. gcc/testsuite/ChangeLog: PR tree-optimization/86622 PR tree-optimization/86532 * gcc.c-torture/execute/strlen-2.c: New test. * gcc.c-torture/execute/strlen-3.c: New test. * gcc.c-torture/execute/strlen-4.c: New test. From-SVN: r262958
Diffstat (limited to 'gcc/expr.c')
-rw-r--r--gcc/expr.c62
1 files changed, 37 insertions, 25 deletions
diff --git a/gcc/expr.c b/gcc/expr.c
index f665e18..de6709d 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -11294,12 +11294,15 @@ string_constant (tree arg, tree *ptr_offset)
tree idx = TREE_OPERAND (arg, 1);
if (TREE_CODE (idx) != INTEGER_CST)
{
- /* Extract the variable index to prevent
- get_addr_base_and_unit_offset() from failing due to
- it. Use it later to compute the non-constant offset
+ /* From a pointer (but not array) argument extract the variable
+ index to prevent get_addr_base_and_unit_offset() from failing
+ due to it. Use it later to compute the non-constant offset
into the string and return it to the caller. */
varidx = idx;
ref = TREE_OPERAND (arg, 0);
+
+ if (TREE_CODE (TREE_TYPE (arg)) == ARRAY_TYPE)
+ return NULL_TREE;
}
}
array = get_addr_base_and_unit_offset (ref, &base_off);
@@ -11327,6 +11330,12 @@ string_constant (tree arg, tree *ptr_offset)
tree offset;
if (tree str = string_constant (arg0, &offset))
{
+ /* Avoid pointers to arrays (see bug 86622). */
+ if (POINTER_TYPE_P (TREE_TYPE (arg))
+ && TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) == ARRAY_TYPE
+ && TREE_CODE (TREE_OPERAND (arg0, 0)) == ARRAY_REF)
+ return NULL_TREE;
+
tree type = TREE_TYPE (arg1);
*ptr_offset = fold_build2 (PLUS_EXPR, type, offset, arg1);
return str;
@@ -11343,16 +11352,17 @@ string_constant (tree arg, tree *ptr_offset)
{
if (TREE_CODE (TREE_TYPE (array)) != ARRAY_TYPE)
return NULL_TREE;
- if (tree eltsize = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (array))))
- {
- /* Add the scaled variable index to the constant offset. */
- tree eltoff = fold_build2 (MULT_EXPR, TREE_TYPE (offset),
- fold_convert (sizetype, varidx),
- eltsize);
- offset = fold_build2 (PLUS_EXPR, TREE_TYPE (offset), offset, eltoff);
- }
- else
- return NULL_TREE;
+
+ gcc_assert (TREE_CODE (arg) == ARRAY_REF);
+ tree chartype = TREE_TYPE (TREE_TYPE (TREE_OPERAND (arg, 0)));
+ if (TREE_CODE (chartype) != INTEGER_TYPE)
+ return NULL;
+
+ tree charsize = array_ref_element_size (arg);
+ /* Set the non-constant offset to the non-constant index scaled
+ by the size of the character type. */
+ offset = fold_build2 (MULT_EXPR, TREE_TYPE (offset),
+ fold_convert (sizetype, varidx), charsize);
}
if (TREE_CODE (array) == STRING_CST)
@@ -11371,11 +11381,6 @@ string_constant (tree arg, tree *ptr_offset)
return NULL_TREE;
if (TREE_CODE (init) == CONSTRUCTOR)
{
- if (TREE_CODE (arg) != ARRAY_REF
- && TREE_CODE (arg) == COMPONENT_REF
- && TREE_CODE (arg) == MEM_REF)
- return NULL_TREE;
-
/* Convert the 64-bit constant offset to a wider type to avoid
overflow. */
offset_int wioff;
@@ -11391,11 +11396,15 @@ string_constant (tree arg, tree *ptr_offset)
init = fold_ctor_reference (NULL_TREE, init, base_off, 0, array,
&fieldoff);
HOST_WIDE_INT cstoff;
- if (init && base_off.is_constant (&cstoff))
- {
- cstoff = (cstoff - fieldoff) / BITS_PER_UNIT;
- offset = build_int_cst (sizetype, cstoff);
- }
+ if (!base_off.is_constant (&cstoff))
+ return NULL_TREE;
+
+ cstoff = (cstoff - fieldoff) / BITS_PER_UNIT;
+ tree off = build_int_cst (sizetype, cstoff);
+ if (varidx)
+ offset = fold_build2 (PLUS_EXPR, TREE_TYPE (offset), offset, off);
+ else
+ offset = off;
}
if (!init || TREE_CODE (init) != STRING_CST)
@@ -11413,8 +11422,11 @@ string_constant (tree arg, tree *ptr_offset)
const char a[4] = "abc\000\000";
The excess elements contribute to TREE_STRING_LENGTH()
but not to strlen(). */
- unsigned HOST_WIDE_INT length
- = strnlen (TREE_STRING_POINTER (init), TREE_STRING_LENGTH (init));
+ unsigned HOST_WIDE_INT charsize
+ = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (init))));
+ unsigned HOST_WIDE_INT length = TREE_STRING_LENGTH (init);
+ length = string_length (TREE_STRING_POINTER (init), charsize,
+ length / charsize);
if (compare_tree_int (array_size, length + 1) < 0)
return NULL_TREE;