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
This commit is contained in:
Martin Sebor 2018-01-10 21:40:14 +00:00 committed by Martin Sebor
parent e7c6abad7f
commit c42d0aa089
7 changed files with 564 additions and 29 deletions

View File

@ -1,3 +1,15 @@
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

View File

@ -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;
}

View File

@ -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,14 +1311,33 @@ 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);
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);
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,17 +1407,25 @@ 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))
return false;
val = wide_int_to_tree (TREE_TYPE (val),
wi::sub(wi::to_wide (val), 1));
/* Set the minimum size to zero since the string in
the array could have zero length. */
*minlen = ssize_int (0);
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));
/* Set the minimum size to zero since the string in
the array could have zero length. */
*minlen = ssize_int (0);
}
}
}
@ -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);
return true;
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. */

View File

@ -1,3 +1,9 @@
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

View File

@ -1,5 +1,5 @@
// PR c++/35652
// { dg-options "-O" }
// { dg-options "-O -Wall" }
#include <string>
int test() {

View File

@ -0,0 +1,393 @@
/* PR tree-optimization/83671 - fix for false positive reported by
-Wstringop-overflow does not work with inlining
{ dg-do compile }
{ dg-options "-O1 -fdump-tree-optimized" } */
#include "strlenopt.h"
#define DIFF_MAX __PTRDIFF_MAX__
#define CAT(x, y) x ## y
#define CONCAT(x, y) CAT (x, y)
#define FAILNAME(name) CONCAT (call_ ## name ##_on_line_, __LINE__)
#define FAIL(name) do { \
extern void FAILNAME (name) (void); \
FAILNAME (name)(); \
} while (0)
/* Macros to emit a call to funcation named
call_in_{true,false}_branch_not_eliminated_on_line_NNN()
for each call that's expected to be eliminated. The dg-final
scan-tree-dump-time directive at the bottom of the test verifies
that no such call appears in output. */
#define ELIM_TRUE(expr) \
if (!(expr)) FAIL (in_true_branch_not_eliminated); else (void)0
#define ELIM_FALSE(expr) \
if (!!(expr)) FAIL (in_false_branch_not_eliminated); else (void)0
/* Macro to emit a call to a function named
call_made_in_{true,false}_branch_on_line_NNN()
for each call that's expected to be retained. The dg-final
scan-tree-dump-time directive at the bottom of the test verifies
that the expected number of both kinds of calls appears in output
(a pair for each line with the invocation of the KEEP() macro. */
#define KEEP(expr) \
if (expr) \
FAIL (made_in_true_branch); \
else \
FAIL (made_in_false_branch)
typedef char A3[3], A5[5], A7[7], AX[];
typedef A3 A7_3[7];
typedef A3 AX_3[];
typedef A5 A7_5[7];
typedef A7 A5_7[5];
extern A7_3 a7_3;
extern A5_7 a5_7;
extern AX_3 ax_3;
extern A3 a3;
extern A7 a5;
extern A7 a7;
extern AX ax;
extern A3 *pa3;
extern A5 *pa5;
extern A7 *pa7;
extern A7_3 *pa7_3;
extern AX_3 *pax_3;
extern A5_7 *pa5_7;
extern A7_5 *pa7_5;
extern char *ptr;
struct MemArrays0 {
A7_3 a7_3;
A5_7 a5_7;
char a3[3], a5[5], a0[0];
};
struct MemArraysX { char a3[3], a5[5], ax[]; };
struct MemArrays7 { char a3[3], a5[5], a7[7]; };
struct MemArrays0 ma0_3_5_7[3][5][7];
void elim_strings (int i)
{
ELIM_TRUE (strlen (i < 0 ? "123" : "321") == 3);
ELIM_FALSE (strlen (i < 0 ? "123" : "321") > 3);
ELIM_FALSE (strlen (i < 0 ? "123" : "321") < 3);
ELIM_TRUE (strlen (i < 0 ? "123" : "4321") >= 3);
ELIM_FALSE (strlen (i < 0 ? "123" : "4321") > 4);
ELIM_FALSE (strlen (i < 0 ? "123" : "4321") < 3);
ELIM_TRUE (strlen (i < 0 ? "1234" : "321") >= 3);
ELIM_FALSE (strlen (i < 0 ? "1234" : "321") < 3);
ELIM_FALSE (strlen (i < 0 ? "1234" : "321") > 4);
ELIM_TRUE (strlen (i < 0 ? "123" : "4321") <= 4);
ELIM_TRUE (strlen (i < 0 ? "1234" : "321") <= 4);
ELIM_TRUE (strlen (i < 0 ? "1" : "123456789") <= 9);
ELIM_TRUE (strlen (i < 0 ? "1" : "123456789") >= 1);
}
/* Verify that strlen calls involving uninitialized global arrays
of known size are eliminated when they appear in expressions
that test for results that must be true. */
void elim_global_arrays (int i)
{
/* Verify that the expression involving the strlen call as well
as whatever depends on it is eliminated from the test output.
All these expressions must be trivially true. */
ELIM_TRUE (strlen (a7_3[0]) < sizeof a7_3[0]);
ELIM_TRUE (strlen (a7_3[1]) < sizeof a7_3[1]);
ELIM_TRUE (strlen (a7_3[6]) < sizeof a7_3[6]);
ELIM_TRUE (strlen (a7_3[i]) < sizeof a7_3[i]);
ELIM_TRUE (strlen (a5_7[0]) < sizeof a5_7[0]);
ELIM_TRUE (strlen (a5_7[1]) < sizeof a5_7[1]);
ELIM_TRUE (strlen (a5_7[4]) < sizeof a5_7[4]);
ELIM_TRUE (strlen (a5_7[i]) < sizeof a5_7[0]);
ELIM_TRUE (strlen (ax_3[0]) < sizeof ax_3[0]);
ELIM_TRUE (strlen (ax_3[1]) < sizeof ax_3[1]);
ELIM_TRUE (strlen (ax_3[9]) < sizeof ax_3[9]);
ELIM_TRUE (strlen (ax_3[i]) < sizeof ax_3[i]);
ELIM_TRUE (strlen (a3) < sizeof a3);
ELIM_TRUE (strlen (a7) < sizeof a7);
ELIM_TRUE (strlen (ax) != DIFF_MAX);
ELIM_TRUE (strlen (ax) != DIFF_MAX - 1);
ELIM_TRUE (strlen (ax) < DIFF_MAX - 1);
}
void elim_pointer_to_arrays (void)
{
ELIM_TRUE (strlen (*pa7) < 7);
ELIM_TRUE (strlen (*pa5) < 5);
ELIM_TRUE (strlen (*pa3) < 3);
ELIM_TRUE (strlen ((*pa7_3)[0]) < 3);
ELIM_TRUE (strlen ((*pa7_3)[1]) < 3);
ELIM_TRUE (strlen ((*pa7_3)[6]) < 3);
ELIM_TRUE (strlen ((*pax_3)[0]) < 3);
ELIM_TRUE (strlen ((*pax_3)[1]) < 3);
ELIM_TRUE (strlen ((*pax_3)[9]) < 3);
ELIM_TRUE (strlen ((*pa5_7)[0]) < 7);
ELIM_TRUE (strlen ((*pa5_7)[1]) < 7);
ELIM_TRUE (strlen ((*pa5_7)[4]) < 7);
}
void elim_global_arrays_and_strings (int i)
{
ELIM_TRUE (strlen (i < 0 ? a3 : "") < 3);
ELIM_TRUE (strlen (i < 0 ? a3 : "1") < 3);
ELIM_TRUE (strlen (i < 0 ? a3 : "12") < 3);
ELIM_TRUE (strlen (i < 0 ? a3 : "123") < 4);
ELIM_FALSE (strlen (i < 0 ? a3 : "") > 3);
ELIM_FALSE (strlen (i < 0 ? a3 : "1") > 3);
ELIM_FALSE (strlen (i < 0 ? a3 : "12") > 3);
ELIM_FALSE (strlen (i < 0 ? a3 : "123") > 4);
ELIM_TRUE (strlen (i < 0 ? a7 : "") < 7);
ELIM_TRUE (strlen (i < 0 ? a7 : "1") < 7);
ELIM_TRUE (strlen (i < 0 ? a7 : "12") < 7);
ELIM_TRUE (strlen (i < 0 ? a7 : "123") < 7);
ELIM_TRUE (strlen (i < 0 ? a7 : "123456") < 7);
ELIM_TRUE (strlen (i < 0 ? a7 : "1234567") < 8);
ELIM_FALSE (strlen (i < 0 ? a7 : "") > 6);
ELIM_FALSE (strlen (i < 0 ? a7 : "1") > 6);
ELIM_FALSE (strlen (i < 0 ? a7 : "12") > 6);
ELIM_FALSE (strlen (i < 0 ? a7 : "123") > 6);
ELIM_FALSE (strlen (i < 0 ? a7 : "123456") > 7);
ELIM_FALSE (strlen (i < 0 ? a7 : "1234567") > 8);
}
void elim_member_arrays_obj (int i)
{
ELIM_TRUE (strlen (ma0_3_5_7[0][0][0].a3) < 3);
ELIM_TRUE (strlen (ma0_3_5_7[0][0][1].a3) < 3);
ELIM_TRUE (strlen (ma0_3_5_7[0][0][2].a3) < 3);
ELIM_TRUE (strlen (ma0_3_5_7[0][0][6].a3) < 3);
ELIM_TRUE (strlen (ma0_3_5_7[1][0][0].a3) < 3);
ELIM_TRUE (strlen (ma0_3_5_7[2][0][1].a3) < 3);
ELIM_TRUE (strlen (ma0_3_5_7[1][1][0].a3) < 3);
ELIM_TRUE (strlen (ma0_3_5_7[2][4][6].a3) < 3);
ELIM_TRUE (strlen (ma0_3_5_7[0][0][0].a5) < 5);
ELIM_TRUE (strlen (ma0_3_5_7[0][0][1].a5) < 5);
ELIM_TRUE (strlen (ma0_3_5_7[0][0][2].a5) < 5);
ELIM_TRUE (strlen (ma0_3_5_7[0][0][6].a5) < 5);
ELIM_TRUE (strlen (ma0_3_5_7[1][0][0].a5) < 5);
ELIM_TRUE (strlen (ma0_3_5_7[2][0][1].a5) < 5);
ELIM_TRUE (strlen (ma0_3_5_7[1][1][0].a5) < 5);
ELIM_TRUE (strlen (ma0_3_5_7[2][4][6].a5) < 5);
ELIM_TRUE (strlen (ma0_3_5_7[0][0][0].a7_3[0]) < 3);
ELIM_TRUE (strlen (ma0_3_5_7[2][4][6].a7_3[2]) < 3);
ELIM_TRUE (strlen (ma0_3_5_7[0][0][0].a5_7[0]) < 7);
ELIM_TRUE (strlen (ma0_3_5_7[2][4][6].a5_7[4]) < 7);
}
void elim_member_arrays_ptr (struct MemArrays0 *ma0,
struct MemArraysX *max,
struct MemArrays7 *ma7,
int i)
{
ELIM_TRUE (strlen (ma0->a7_3[0]) < 3);
ELIM_TRUE (strlen (ma0->a7_3[1]) < 3);
ELIM_TRUE (strlen (ma0->a7_3[6]) < 3);
ELIM_TRUE (strlen (ma0->a7_3[6]) < 3);
ELIM_TRUE (strlen (ma0->a7_3[i]) < 3);
ELIM_TRUE (strlen (ma0->a7_3[i]) < 3);
ELIM_TRUE (strlen (ma0->a5_7[0]) < 7);
ELIM_TRUE (strlen (ma0[0].a5_7[0]) < 7);
ELIM_TRUE (strlen (ma0[1].a5_7[0]) < 7);
ELIM_TRUE (strlen (ma0[1].a5_7[4]) < 7);
ELIM_TRUE (strlen (ma0[9].a5_7[0]) < 7);
ELIM_TRUE (strlen (ma0[9].a5_7[4]) < 7);
ELIM_TRUE (strlen (ma0->a3) < sizeof ma0->a3);
ELIM_TRUE (strlen (ma0->a5) < sizeof ma0->a5);
ELIM_TRUE (strlen (ma0->a0) < DIFF_MAX - 1);
ELIM_TRUE (strlen (max->a3) < sizeof max->a3);
ELIM_TRUE (strlen (max->a5) < sizeof max->a5);
ELIM_TRUE (strlen (max->ax) < DIFF_MAX - 1);
ELIM_TRUE (strlen (ma7->a3) < sizeof max->a3);
ELIM_TRUE (strlen (ma7->a5) < sizeof max->a5);
ELIM_TRUE (strlen (ma7->a7) < DIFF_MAX - 1);
}
#line 1000
/* Verify that strlen calls involving uninitialized global arrays
of unknown size are not eliminated when they appear in expressions
that test for results that need not be true. */
void keep_global_arrays (int i)
{
KEEP (strlen (a7_3[0]) < 2);
KEEP (strlen (a7_3[1]) < 2);
KEEP (strlen (a7_3[6]) < 2);
KEEP (strlen (a7_3[i]) < 2);
KEEP (strlen (a5_7[0]) < 6);
KEEP (strlen (a5_7[1]) < 6);
KEEP (strlen (a5_7[4]) < 6);
KEEP (strlen (a5_7[i]) < 6);
KEEP (strlen (ax_3[0]) < 2);
KEEP (strlen (ax_3[1]) < 2);
KEEP (strlen (ax_3[2]) < 2);
KEEP (strlen (ax_3[i]) < 2);
KEEP (strlen (a3) < 2);
KEEP (strlen (a7) < 6);
KEEP (strlen (a3 + i) < 2);
KEEP (strlen (a7 + i) < 2);
/* The length of an array of unknown size may be as large as
DIFF_MAX - 2. */
KEEP (strlen (ax) != DIFF_MAX - 2);
KEEP (strlen (ax) < DIFF_MAX - 2);
KEEP (strlen (ax) < 999);
KEEP (strlen (ax) < 1);
}
void keep_pointer_to_arrays (void)
{
KEEP (strlen (*pa7) < 6);
KEEP (strlen (*pa5) < 4);
KEEP (strlen (*pa3) < 2);
KEEP (strlen ((*pa7_3)[0]) < 2);
KEEP (strlen ((*pa7_3)[1]) < 2);
KEEP (strlen ((*pa7_3)[6]) < 2);
KEEP (strlen ((*pax_3)[0]) < 2);
KEEP (strlen ((*pax_3)[1]) < 2);
KEEP (strlen ((*pax_3)[9]) < 2);
KEEP (strlen ((*pa5_7)[0]) < 6);
KEEP (strlen ((*pa5_7)[1]) < 6);
KEEP (strlen ((*pa5_7)[4]) < 6);
}
void keep_global_arrays_and_strings (int i)
{
KEEP (strlen (i < 0 ? a3 : "") < 2);
KEEP (strlen (i < 0 ? a3 : "1") < 2);
KEEP (strlen (i < 0 ? a3 : "12") < 2);
KEEP (strlen (i < 0 ? a3 : "123") < 3);
KEEP (strlen (i < 0 ? a7 : "") < 5);
KEEP (strlen (i < 0 ? a7 : "1") < 5);
KEEP (strlen (i < 0 ? a7 : "12") < 5);
KEEP (strlen (i < 0 ? a7 : "123") < 5);
KEEP (strlen (i < 0 ? a7 : "123456") < 6);
KEEP (strlen (i < 0 ? a7 : "1234567") < 6);
}
void keep_member_arrays_obj (int i)
{
KEEP (strlen (ma0_3_5_7[0][0][0].a3) < 2);
KEEP (strlen (ma0_3_5_7[0][0][1].a3) < 2);
KEEP (strlen (ma0_3_5_7[0][0][2].a3) < 2);
KEEP (strlen (ma0_3_5_7[0][0][6].a3) < 2);
KEEP (strlen (ma0_3_5_7[1][0][0].a3) < 2);
KEEP (strlen (ma0_3_5_7[2][0][1].a3) < 2);
KEEP (strlen (ma0_3_5_7[1][1][0].a3) < 2);
KEEP (strlen (ma0_3_5_7[2][4][6].a3) < 2);
KEEP (strlen (ma0_3_5_7[0][0][0].a5) < 4);
KEEP (strlen (ma0_3_5_7[0][0][1].a5) < 4);
KEEP (strlen (ma0_3_5_7[0][0][2].a5) < 4);
KEEP (strlen (ma0_3_5_7[0][0][6].a5) < 4);
KEEP (strlen (ma0_3_5_7[1][0][0].a5) < 4);
KEEP (strlen (ma0_3_5_7[2][0][1].a5) < 4);
KEEP (strlen (ma0_3_5_7[1][1][0].a5) < 4);
KEEP (strlen (ma0_3_5_7[2][4][6].a5) < 4);
KEEP (strlen (ma0_3_5_7[0][0][0].a7_3[0]) < 2);
KEEP (strlen (ma0_3_5_7[2][4][6].a7_3[2]) < 2);
KEEP (strlen (ma0_3_5_7[0][0][0].a5_7[0]) < 6);
KEEP (strlen (ma0_3_5_7[2][4][6].a5_7[4]) < 6);
}
void keep_member_arrays_ptr (struct MemArrays0 *ma0,
struct MemArraysX *max,
struct MemArrays7 *ma7,
int i)
{
KEEP (strlen (ma0->a7_3[0]) > 0);
KEEP (strlen (ma0->a7_3[0]) < 2);
KEEP (strlen (ma0->a7_3[1]) < 2);
KEEP (strlen (ma0->a7_3[6]) < 2);
KEEP (strlen (ma0->a7_3[6]) < 2);
KEEP (strlen (ma0->a7_3[i]) > 0);
KEEP (strlen (ma0->a7_3[i]) < 2);
KEEP (strlen (ma0->a7_3[i]) < 2);
KEEP (strlen (ma0->a5_7[0]) < 5);
KEEP (strlen (ma0[0].a5_7[0]) < 5);
KEEP (strlen (ma0[1].a5_7[0]) < 5);
KEEP (strlen (ma0[9].a5_7[0]) < 5);
KEEP (strlen (ma0[9].a5_7[4]) < 5);
KEEP (strlen (ma0[i].a5_7[4]) < 5);
KEEP (strlen (ma0[i].a5_7[i]) < 5);
KEEP (strlen (ma0->a0) < DIFF_MAX - 2);
KEEP (strlen (ma0->a0) < 999);
KEEP (strlen (ma0->a0) < 1);
KEEP (strlen (max->ax) < DIFF_MAX - 2);
KEEP (strlen (max->ax) < 999);
KEEP (strlen (max->ax) < 1);
KEEP (strlen (ma7->a7) < DIFF_MAX - 2);
KEEP (strlen (ma7->a7) < 999);
KEEP (strlen (ma7->a7) < 1);
}
void keep_pointers (const char *s)
{
KEEP (strlen (ptr) < DIFF_MAX - 2);
KEEP (strlen (ptr) < 999);
KEEP (strlen (ptr) < 1);
KEEP (strlen (s) < DIFF_MAX - 2);
KEEP (strlen (s) < 999);
KEEP (strlen (s) < 1);
}
/* { dg-final { scan-tree-dump-times "call_in_true_branch_not_eliminated_" 0 "optimized" } }
{ dg-final { scan-tree-dump-times "call_in_false_branch_not_eliminated_" 0 "optimized" } }
{ dg-final { scan-tree-dump-times "call_made_in_true_branch_on_line_1\[0-9\]\[0-9\]\[0-9\]" 92 "optimized" } }
{ dg-final { scan-tree-dump-times "call_made_in_false_branch_on_line_1\[0-9\]\[0-9\]\[0-9\]" 92 "optimized" } } */

View File

@ -0,0 +1,34 @@
/* 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" } } */