diff options
author | Martin Sebor <msebor@redhat.com> | 2018-07-25 02:11:31 +0000 |
---|---|---|
committer | Martin Sebor <msebor@gcc.gnu.org> | 2018-07-24 20:11:31 -0600 |
commit | bfb9bd47b2daac0a01c561effac1d8244ddd99f6 (patch) | |
tree | bf72d7afae065152f74b4f862adffad1c954d61e /gcc/builtins.c | |
parent | ae752f020fd86b2d34a1556124dc4e5f01a8dcce (diff) | |
download | gcc-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/builtins.c')
-rw-r--r-- | gcc/builtins.c | 58 |
1 files changed, 36 insertions, 22 deletions
diff --git a/gcc/builtins.c b/gcc/builtins.c index 539a6d1..aa3e0d8 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -517,11 +517,11 @@ get_pointer_alignment (tree exp) return align; } -/* Return the number of non-zero elements in the sequence +/* Return the number of leading non-zero elements in the sequence [ PTR, PTR + MAXELTS ) where each element's size is ELTSIZE bytes. ELTSIZE must be a power of 2 less than 8. Used by c_strlen. */ -static unsigned +unsigned string_length (const void *ptr, unsigned eltsize, unsigned maxelts) { gcc_checking_assert (eltsize == 1 || eltsize == 2 || eltsize == 4); @@ -605,14 +605,21 @@ c_strlen (tree src, int only_value) /* Set MAXELTS to sizeof (SRC) / sizeof (*SRC) - 1, the maximum possible length of SRC. Prefer TYPE_SIZE() to TREE_STRING_LENGTH() if possible - in case the latter is less than the size of the array. */ - HOST_WIDE_INT maxelts = TREE_STRING_LENGTH (src); + in case the latter is less than the size of the array, such as when + SRC refers to a short string literal used to initialize a large array. + In that case, the elements of the array after the terminating NUL are + all NUL. */ + HOST_WIDE_INT strelts = TREE_STRING_LENGTH (src); + strelts = strelts / eltsize - 1; + + HOST_WIDE_INT maxelts = strelts; tree type = TREE_TYPE (src); if (tree size = TYPE_SIZE_UNIT (type)) if (tree_fits_shwi_p (size)) - maxelts = tree_to_uhwi (size); - - maxelts = maxelts / eltsize - 1; + { + maxelts = tree_to_uhwi (size); + maxelts = maxelts / eltsize - 1; + } /* PTR can point to the byte representation of any string type, including char* and wchar_t*. */ @@ -620,10 +627,12 @@ c_strlen (tree src, int only_value) if (byteoff && TREE_CODE (byteoff) != INTEGER_CST) { - /* If the string has an internal zero byte (e.g., "foo\0bar"), we can't - compute the offset to the following null if we don't know where to + /* If the string has an internal NUL character followed by any + non-NUL characters (e.g., "foo\0bar"), we can't compute + the offset to the following NUL if we don't know where to start searching for it. */ - if (string_length (ptr, eltsize, maxelts) < maxelts) + unsigned len = string_length (ptr, eltsize, strelts); + if (len < strelts) { /* Return when an embedded null character is found. */ return NULL_TREE; @@ -633,12 +642,17 @@ c_strlen (tree src, int only_value) return ssize_int (0); /* We don't know the starting offset, but we do know that the string - has no internal zero bytes. We can assume that the offset falls - within the bounds of the string; otherwise, the programmer deserves - what he gets. Subtract the offset from the length of the string, - and return that. This would perhaps not be valid if we were dealing - with named arrays in addition to literal string constants. */ - return size_diffop_loc (loc, size_int (maxelts * eltsize), byteoff); + has no internal zero bytes. If the offset falls within the bounds + of the string subtract the offset from the length of the string, + and return that. Otherwise the length is zero. Take care to + use SAVE_EXPR in case the OFFSET has side-effects. */ + tree offsave = TREE_SIDE_EFFECTS (byteoff) ? save_expr (byteoff) : byteoff; + offsave = fold_convert (ssizetype, offsave); + tree condexp = fold_build2_loc (loc, LE_EXPR, boolean_type_node, offsave, + build_int_cst (ssizetype, len * eltsize)); + tree lenexp = size_diffop_loc (loc, ssize_int (strelts * eltsize), offsave); + return fold_build3_loc (loc, COND_EXPR, ssizetype, condexp, lenexp, + build_zero_cst (ssizetype)); } /* Offset from the beginning of the string in elements. */ @@ -3192,15 +3206,13 @@ check_access (tree exp, tree, tree, tree dstwrite, if (dstwrite) get_size_range (dstwrite, range); - /* This can happen at -O0. */ - if (range[0] && TREE_CODE (range[0]) != INTEGER_CST) - return false; - tree func = get_callee_fndecl (exp); /* First check the number of bytes to be written against the maximum object size. */ - if (range[0] && tree_int_cst_lt (maxobjsize, range[0])) + if (range[0] + && TREE_CODE (range[0]) == INTEGER_CST + && tree_int_cst_lt (maxobjsize, range[0])) { if (TREE_NO_WARNING (exp)) return false; @@ -3235,9 +3247,11 @@ check_access (tree exp, tree, tree, tree dstwrite, if (range[0] || !exactwrite || integer_all_onesp (dstwrite)) { if (range[0] + && TREE_CODE (range[0]) == INTEGER_CST && ((tree_fits_uhwi_p (dstsize) && tree_int_cst_lt (dstsize, range[0])) - || (tree_fits_uhwi_p (dstwrite) + || (dstwrite + && tree_fits_uhwi_p (dstwrite) && tree_int_cst_lt (dstwrite, range[0])))) { if (TREE_NO_WARNING (exp)) |