Commit c42d0aa0 by Martin Sebor Committed by Martin Sebor

PR tree-optimization/83671 - Fix for false positive reported by…

PR tree-optimization/83671 - Fix for false positive reported by -Wstringop-overflow does not work with inlining

gcc/testsuite/ChangeLog:

	PR tree-optimization/83671
	* gcc.dg/strlenopt-40.c: New test.
	* gcc.dg/strlenopt-41.c: New test.

gcc/ChangeLog:

	PR tree-optimization/83671
	* builtins.c (c_strlen): Unconditionally return zero for the empty
	string.
	Use -Warray-bounds for warnings.
	* gimple-fold.c (get_range_strlen): Handle non-constant lengths
	for non-constant array indices with COMPONENT_REF, arrays of
	arrays, and pointers to arrays.
	(gimple_fold_builtin_strlen): Determine and set length range for
	non-constant character arrays.

From-SVN: r256457
parent e7c6abad
2018-01-10 Martin Sebor <msebor@redhat.com>
PR tree-optimization/83671
* builtins.c (c_strlen): Unconditionally return zero for the empty
string.
Use -Warray-bounds for warnings.
* gimple-fold.c (get_range_strlen): Handle non-constant lengths
for non-constant array indices with COMPONENT_REF, arrays of
arrays, and pointers to arrays.
(gimple_fold_builtin_strlen): Determine and set length range for
non-constant character arrays.
2018-01-10 Aldy Hernandez <aldyh@redhat.com>
PR middle-end/81897
......
......@@ -621,6 +621,9 @@ c_strlen (tree src, int only_value)
return NULL_TREE;
}
if (!maxelts)
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
......@@ -651,7 +654,8 @@ c_strlen (tree src, int only_value)
if (only_value != 2
&& !TREE_NO_WARNING (src))
{
warning_at (loc, 0, "offset %qwi outside bounds of constant string",
warning_at (loc, OPT_Warray_bounds,
"offset %qwi outside bounds of constant string",
eltoff);
TREE_NO_WARNING (src) = 1;
}
......
......@@ -1299,7 +1299,7 @@ static bool
get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
bool fuzzy, bool *flexp)
{
tree var, val;
tree var, val = NULL_TREE;
gimple *def_stmt;
/* The minimum and maximum length. The MAXLEN pointer stays unchanged
......@@ -1311,15 +1311,34 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
{
/* We can end up with &(*iftmp_1)[0] here as well, so handle it. */
if (TREE_CODE (arg) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (arg, 0)) == ARRAY_REF
&& integer_zerop (TREE_OPERAND (TREE_OPERAND (arg, 0), 1)))
&& TREE_CODE (TREE_OPERAND (arg, 0)) == ARRAY_REF)
{
tree aop0 = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
tree op = TREE_OPERAND (arg, 0);
if (integer_zerop (TREE_OPERAND (op, 1)))
{
tree aop0 = TREE_OPERAND (op, 0);
if (TREE_CODE (aop0) == INDIRECT_REF
&& TREE_CODE (TREE_OPERAND (aop0, 0)) == SSA_NAME)
return get_range_strlen (TREE_OPERAND (aop0, 0),
length, visited, type, fuzzy, flexp);
}
else if (TREE_CODE (TREE_OPERAND (op, 0)) == COMPONENT_REF && fuzzy)
{
/* Fail if an array is the last member of a struct object
since it could be treated as a (fake) flexible array
member. */
tree idx = TREE_OPERAND (op, 1);
arg = TREE_OPERAND (op, 0);
tree optype = TREE_TYPE (arg);
if (tree dom = TYPE_DOMAIN (optype))
if (tree bound = TYPE_MAX_VALUE (dom))
if (TREE_CODE (bound) == INTEGER_CST
&& TREE_CODE (idx) == INTEGER_CST
&& tree_int_cst_lt (bound, idx))
return false;
}
}
if (type == 2)
{
......@@ -1337,21 +1356,48 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
return get_range_strlen (TREE_OPERAND (arg, 0), length,
visited, type, fuzzy, flexp);
if (TREE_CODE (arg) == COMPONENT_REF
if (TREE_CODE (arg) == ARRAY_REF)
{
tree type = TREE_TYPE (TREE_OPERAND (arg, 0));
while (TREE_CODE (type) == ARRAY_TYPE
&& TREE_CODE (TREE_TYPE (type)) == ARRAY_TYPE)
type = TREE_TYPE (type);
val = TYPE_SIZE_UNIT (type);
if (!val || integer_zerop (val))
return false;
val = fold_build2 (MINUS_EXPR, TREE_TYPE (val), val,
integer_one_node);
/* Set the minimum size to zero since the string in
the array could have zero length. */
*minlen = ssize_int (0);
}
else if (TREE_CODE (arg) == COMPONENT_REF
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (arg, 1))) == ARRAY_TYPE)
{
/* Use the type of the member array to determine the upper
bound on the length of the array. This may be overly
optimistic if the array itself isn't NUL-terminated and
the caller relies on the subsequent member to contain
the NUL.
the NUL but that would only be considered valid if
the array were the last member of a struct.
Set *FLEXP to true if the array whose bound is being
used is at the end of a struct. */
if (array_at_struct_end_p (arg))
*flexp = true;
arg = TREE_OPERAND (arg, 1);
val = TYPE_SIZE_UNIT (TREE_TYPE (arg));
tree type = TREE_TYPE (arg);
while (TREE_CODE (type) == ARRAY_TYPE
&& TREE_CODE (TREE_TYPE (type)) == ARRAY_TYPE)
type = TREE_TYPE (type);
/* Fail when the array bound is unknown or zero. */
val = TYPE_SIZE_UNIT (type);
if (!val || integer_zerop (val))
return false;
val = fold_build2 (MINUS_EXPR, TREE_TYPE (val), val,
......@@ -1361,11 +1407,18 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
*minlen = ssize_int (0);
}
if (VAR_P (arg)
&& TREE_CODE (TREE_TYPE (arg)) == ARRAY_TYPE)
if (VAR_P (arg))
{
val = TYPE_SIZE_UNIT (TREE_TYPE (arg));
if (!val || TREE_CODE (val) != INTEGER_CST || integer_zerop (val))
tree type = TREE_TYPE (arg);
if (POINTER_TYPE_P (type))
type = TREE_TYPE (type);
if (TREE_CODE (type) == ARRAY_TYPE)
{
val = TYPE_SIZE_UNIT (type);
if (!val
|| TREE_CODE (val) != INTEGER_CST
|| integer_zerop (val))
return false;
val = wide_int_to_tree (TREE_TYPE (val),
wi::sub(wi::to_wide (val), 1));
......@@ -1374,6 +1427,7 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
*minlen = ssize_int (0);
}
}
}
if (!val)
return false;
......@@ -3462,12 +3516,44 @@ static bool
gimple_fold_builtin_strlen (gimple_stmt_iterator *gsi)
{
gimple *stmt = gsi_stmt (*gsi);
tree len = get_maxval_strlen (gimple_call_arg (stmt, 0), 0);
if (!len)
return false;
len = force_gimple_operand_gsi (gsi, len, true, NULL, true, GSI_SAME_STMT);
replace_call_with_value (gsi, len);
wide_int minlen;
wide_int maxlen;
tree lenrange[2];
if (!get_range_strlen (gimple_call_arg (stmt, 0), lenrange)
&& lenrange[0] && TREE_CODE (lenrange[0]) == INTEGER_CST
&& lenrange[1] && TREE_CODE (lenrange[1]) == INTEGER_CST)
{
/* The range of lengths refers to either a single constant
string or to the longest and shortest constant string
referenced by the argument of the strlen() call, or to
the strings that can possibly be stored in the arrays
the argument refers to. */
minlen = wi::to_wide (lenrange[0]);
maxlen = wi::to_wide (lenrange[1]);
}
else
{
unsigned prec = TYPE_PRECISION (sizetype);
minlen = wi::shwi (0, prec);
maxlen = wi::to_wide (max_object_size (), prec) - 2;
}
if (minlen == maxlen)
{
lenrange[0] = force_gimple_operand_gsi (gsi, lenrange[0], true, NULL,
true, GSI_SAME_STMT);
replace_call_with_value (gsi, lenrange[0]);
return true;
}
tree lhs = gimple_call_lhs (stmt);
if (lhs && TREE_CODE (lhs) == SSA_NAME)
set_range_info (lhs, VR_RANGE, minlen, maxlen);
return false;
}
/* Fold a call to __builtin_acc_on_device. */
......
2018-01-10 Martin Sebor <msebor@redhat.com>
PR tree-optimization/83671
* gcc.dg/strlenopt-40.c: New test.
* gcc.dg/strlenopt-41.c: New test.
2018-01-10 Steven G. Kargl <kargl@gcc.gnu.org>
PR fortran/83093
......
// PR c++/35652
// { dg-options "-O" }
// { dg-options "-O -Wall" }
#include <string>
int test() {
......
/* PR tree-optimization/83671 - fix for false positive reported by
-Wstringop-overflow does not work with inlining
Verify that the length the empty string is folded to zero even at -O1
regardless of offset into it.
Also verify that the length of a non-empty string isn't folded given
a variable offset.
{ dg-do compile }
{ dg-options "-O1 -fdump-tree-optimized" } */
#include "strlenopt.h"
inline unsigned length (const char *s)
{
return __builtin_strlen (s);
}
void check_length_cst (int i)
{
unsigned len = length (&""[i]);
if (len)
__builtin_abort ();
}
void check_length_var (int i)
{
unsigned len = length (&"1"[i]);
if (len != 1)
__builtin_abort ();
}
/* { dg-final { scan-tree-dump-times "abort" 1 "optimized" } }
{ dg-final { scan-tree-dump-times "strlen" 1 "optimized" } } */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment