From c42d0aa0893cab444366c80fdd5b23bb45de6276 Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Wed, 10 Jan 2018 21:40:14 +0000 Subject: [PATCH] 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 --- gcc/ChangeLog | 12 + gcc/builtins.c | 6 +- gcc/gimple-fold.c | 140 ++++++++-- gcc/testsuite/ChangeLog | 6 + gcc/testsuite/g++.dg/warn/string1.C | 2 +- gcc/testsuite/gcc.dg/strlenopt-40.c | 393 ++++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/strlenopt-41.c | 34 +++ 7 files changed, 564 insertions(+), 29 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/strlenopt-40.c create mode 100644 gcc/testsuite/gcc.dg/strlenopt-41.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ba1a8447517..081c04aa8a7 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,15 @@ +2018-01-10 Martin Sebor + + 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 PR middle-end/81897 diff --git a/gcc/builtins.c b/gcc/builtins.c index 1d6e69d30ce..a0d0a10d38f 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -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; } diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c index 7e4cb74d7cc..504a85d1441 100644 --- a/gcc/gimple-fold.c +++ b/gcc/gimple-fold.c @@ -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. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 825224d8e58..10273a9d8a6 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2018-01-10 Martin Sebor + + PR tree-optimization/83671 + * gcc.dg/strlenopt-40.c: New test. + * gcc.dg/strlenopt-41.c: New test. + 2018-01-10 Steven G. Kargl PR fortran/83093 diff --git a/gcc/testsuite/g++.dg/warn/string1.C b/gcc/testsuite/g++.dg/warn/string1.C index 8f24a78f709..a0b0d47de1b 100644 --- a/gcc/testsuite/g++.dg/warn/string1.C +++ b/gcc/testsuite/g++.dg/warn/string1.C @@ -1,5 +1,5 @@ // PR c++/35652 -// { dg-options "-O" } +// { dg-options "-O -Wall" } #include int test() { diff --git a/gcc/testsuite/gcc.dg/strlenopt-40.c b/gcc/testsuite/gcc.dg/strlenopt-40.c new file mode 100644 index 00000000000..f4577d69e1a --- /dev/null +++ b/gcc/testsuite/gcc.dg/strlenopt-40.c @@ -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" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-41.c b/gcc/testsuite/gcc.dg/strlenopt-41.c new file mode 100644 index 00000000000..c5e8eb6d8df --- /dev/null +++ b/gcc/testsuite/gcc.dg/strlenopt-41.c @@ -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" } } */ -- 2.30.2