On 07/24/18 16:50, Richard Biener wrote: > On Tue, 24 Jul 2018, Bernd Edlinger wrote: > >> Hi! >> >> This patch makes strlen range computations more conservative. >> >> Firstly if there is a visible type cast from type A to B before passing >> then value to strlen, don't expect the type layout of B to restrict the >> possible return value range of strlen. >> >> Furthermore use the outermost enclosing array instead of the >> innermost one, because too aggressive optimization will likely >> convert harmless errors into security-relevant errors, because >> as the existing test cases demonstrate, this optimization is actively >> attacking string length checks in user code, while and not giving >> any warnings. >> >> >> >> Bootstrapped and reg-tested on x86_64-pc-linux-gnu. >> Is it OK for trunk? > > I'd like us to be explicit in what we support, not what we do not > support, thus > > + /* Avoid arrays of pointers. */ > + if (TREE_CODE (TREE_TYPE (arg)) == POINTER_TYPE) > + return false; > > should become > > /* We handle arrays of integer types. */ > if (TREE_CODE (TRE_TYPE (arg)) != INTEGER_TYPE) > return false; >
Yes. I think I can also check the TYPE_MODE/PRECISION. > + tree base = arg; > + while (TREE_CODE (base) == ARRAY_REF > + || TREE_CODE (base) == ARRAY_RANGE_REF > + || TREE_CODE (base) == COMPONENT_REF) > + base = TREE_OPERAND (base, 0); > + > + /* If this looks like a type cast don't assume anything. */ > + if ((TREE_CODE (base) == MEM_REF > + && (! integer_zerop (TREE_OPERAND (base, 1)) > + || TREE_TYPE (TREE_TYPE (TREE_OPERAND (base, 0))) > + != TREE_TYPE (base))) > + || TREE_CODE (base) == VIEW_CONVERT_EXPR) > return false; > > likewise - you miss to handle BIT_FIELD_REF. So, instead > I did not expect to see BIT_FIELD_REF in the inner tree elements, but you never know. The new version handles them, and bails out if they happen to be there. Is this handling now how you wanted it to be? > if (!(DECL_P (base) > || TREE_CODE (base) == STRING_CST > || (TREE_CODE (base) == MEM_REF > && ...> > you should look at comparing TYPE_MAIN_VARIANT in your type > check, aligned/unaligned or const/non-const accesses shouldn't > be considered a "type cast". Maybe even use Good point. TYPE_MAIN_VARIANT is my friend. > types_compatible_p. Not sure why you enforce zero-offset MEMs? > Do we in the end only handle &decl bases of MEMs? Given you > strip arbitrary COMPONENT_REFs the offset in a MEM isn't > so much different? > something like: ma0[1].a5_7[0] gets transformed into: (const char *) &(ma0 + 64)->a5_7[0] ma0 + 64 is a MEM_REF[&ma0, 64] I don't really think that happens too often, but I think other weirdo-type casts can look quite similar. But that happens very rarely. > It looks like the component-ref stripping plus type-check part > could be factored out into sth like get_base_address? I don't > have a good name or suggested semantics for it though. > Yes, done. While playing with the now more rigorous type checking I noticed something that is most likely a pre-existent programming error: @@ -1310,8 +1350,8 @@ get_range_strlen (tree arg, tree length[2], bitmap member. */ tree idx = TREE_OPERAND (op, 1); - arg = TREE_OPERAND (op, 0); - tree optype = TREE_TYPE (arg); + op = TREE_OPERAND (op, 0); + tree optype = TREE_TYPE (op); if (tree dom = TYPE_DOMAIN (optype)) if (tree bound = TYPE_MAX_VALUE (dom)) if (TREE_CODE (bound) == INTEGER_CST I believe this was not meant to change "arg". This is in a block that is guarded by: /* 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) so this is entered with arg = &ma0_3_5_7[0][0][0].a5_7[4] op = ma0_3_5_7[0][0][0].a5_7[4] at this point, then arg is accidentally set to TREE_OPERAND (op, 0) which now makes arg = ma0_3_5_7[0][0][0].a5_7 this did not pass the type check in get_inner_char_array_unless_typecast, but more importantly this is passed to val = c_strlen (arg, 1), which will likely return the first array initializer instead of the fifth. I have also added an else here: @@ -1400,8 +1432,7 @@ get_range_strlen (tree arg, tree length[2], bitmap the array could have zero length. */ *minlen = ssize_int (0); } - - if (VAR_P (arg)) + else if (VAR_P (arg)) { tree type = TREE_TYPE (arg); if (POINTER_TYPE_P (type)) because I noticed that the control flow can reach this if from the previous if statement, but the range info has already been set at that point. Bootstrapped and reg-tested on x86_64-pc-linux-gnu. Not asking for OK right now, since Jeff asked me to hold this patch for the moment, but I just wanted to keep you informed, where I am right now. Thanks Bernd.
gcc: 2018-07-24 Bernd Edlinger <bernd.edlin...@hotmail.de> * gimple-fold.c (get_inner_char_array_unless_typecast): Helper function for strlen range estimations. (get_range_strlen): Use get_inner_char_array_unless_typecast. * tree-ssa-strlen.c (maybe_set_strlen_range): Likewise. * gimple-fold.h (get_inner_char_array_unless_typecast): Declare. testsuite: 2018-07-24 Bernd Edlinger <bernd.edlin...@hotmail.de> * gcc.dg/strlenopt-40.c: Adjust test expectations. * gcc.dg/strlenopt-45.c: Likewise. * gcc.dg/strlenopt-48.c: Likewise. * gcc.dg/strlenopt-51.c: Likewise. * gcc.dg/strlenopt-54.c: New test.
Index: gcc/gimple-fold.c =================================================================== --- gcc/gimple-fold.c (revision 262933) +++ gcc/gimple-fold.c (working copy) @@ -1257,7 +1257,47 @@ gimple_fold_builtin_memset (gimple_stmt_iterator * return true; } +/* Obtain the inner char array for strlen range estimations. + Return NULL if ARG is not a char array, or if the inner reference + chain goes through a type cast. */ +tree +get_inner_char_array_unless_typecast (tree arg) +{ + /* We handle arrays of integer types. */ + if (TREE_CODE (TREE_TYPE (arg)) != ARRAY_TYPE + || TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) != INTEGER_TYPE + || TYPE_MODE (TREE_TYPE (TREE_TYPE (arg))) != TYPE_MODE (char_type_node) + || TYPE_PRECISION (TREE_TYPE (TREE_TYPE (arg))) + != TYPE_PRECISION (char_type_node)) + return NULL_TREE; + + /* Look for the innermost enclosing array. */ + while (TREE_CODE (arg) == ARRAY_REF + && TREE_CODE (TREE_TYPE (TREE_OPERAND (arg, 0))) == ARRAY_TYPE) + arg = TREE_OPERAND (arg, 0); + + tree base = arg; + while (TREE_CODE (base) == ARRAY_REF + || TREE_CODE (base) == ARRAY_RANGE_REF + || TREE_CODE (base) == COMPONENT_REF) + base = TREE_OPERAND (base, 0); + + /* If this looks like a type cast don't assume anything. */ + if ((TREE_CODE (base) == MEM_REF + && (! integer_zerop (TREE_OPERAND (base, 1)) + || TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (TREE_OPERAND (base, 0)))) + != TYPE_MAIN_VARIANT (TREE_TYPE (base)))) + || TREE_CODE (base) == VIEW_CONVERT_EXPR + /* Or other stuff that would be handled by get_inner_reference. */ + || TREE_CODE (base) == BIT_FIELD_REF + || TREE_CODE (base) == REALPART_EXPR + || TREE_CODE (base) == IMAGPART_EXPR) + return NULL_TREE; + + return arg; +} + /* Obtain the minimum and maximum string length or minimum and maximum value of ARG in LENGTH[0] and LENGTH[1], respectively. If ARG is an SSA name variable, follow its use-def chains. When @@ -1310,8 +1350,8 @@ get_range_strlen (tree arg, tree length[2], bitmap member. */ tree idx = TREE_OPERAND (op, 1); - arg = TREE_OPERAND (op, 0); - tree optype = TREE_TYPE (arg); + op = TREE_OPERAND (op, 0); + tree optype = TREE_TYPE (op); if (tree dom = TYPE_DOMAIN (optype)) if (tree bound = TYPE_MAX_VALUE (dom)) if (TREE_CODE (bound) == INTEGER_CST @@ -1339,19 +1379,13 @@ get_range_strlen (tree arg, tree length[2], bitmap if (TREE_CODE (arg) == ARRAY_REF) { - tree type = TREE_TYPE (TREE_OPERAND (arg, 0)); + arg = get_inner_char_array_unless_typecast (arg); + if (!arg) + return false; - /* Determine the "innermost" array type. */ - while (TREE_CODE (type) == ARRAY_TYPE - && TREE_CODE (TREE_TYPE (type)) == ARRAY_TYPE) - type = TREE_TYPE (type); + tree type = TREE_TYPE (arg); - /* Avoid arrays of pointers. */ - tree eltype = TREE_TYPE (type); - if (TREE_CODE (type) != ARRAY_TYPE - || !INTEGRAL_TYPE_P (eltype)) - return false; - + /* Fail when the array bound is unknown or zero. */ val = TYPE_SIZE_UNIT (type); if (!val || integer_zerop (val)) return false; @@ -1362,15 +1396,17 @@ get_range_strlen (tree arg, tree length[2], bitmap the array could have zero length. */ *minlen = ssize_int (0); - if (TREE_CODE (TREE_OPERAND (arg, 0)) == COMPONENT_REF - && type == TREE_TYPE (TREE_OPERAND (arg, 0)) - && array_at_struct_end_p (TREE_OPERAND (arg, 0))) + if (TREE_CODE (arg) == COMPONENT_REF + && type == TREE_TYPE (arg) + && array_at_struct_end_p (arg)) *flexp = true; } - else if (TREE_CODE (arg) == COMPONENT_REF - && (TREE_CODE (TREE_TYPE (TREE_OPERAND (arg, 1))) - == ARRAY_TYPE)) + else if (TREE_CODE (arg) == COMPONENT_REF) { + arg = get_inner_char_array_unless_typecast (arg); + if (!arg) + return false; + /* 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 @@ -1386,10 +1422,6 @@ get_range_strlen (tree arg, tree length[2], bitmap 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)) @@ -1400,8 +1432,7 @@ get_range_strlen (tree arg, tree length[2], bitmap the array could have zero length. */ *minlen = ssize_int (0); } - - if (VAR_P (arg)) + else if (VAR_P (arg)) { tree type = TREE_TYPE (arg); if (POINTER_TYPE_P (type)) @@ -1409,13 +1440,16 @@ get_range_strlen (tree arg, tree length[2], bitmap if (TREE_CODE (type) == ARRAY_TYPE) { + /* We handle arrays of integer types. */ + if (TREE_CODE (TREE_TYPE (type)) != INTEGER_TYPE) + return false; + + /* Fail when the array bound is unknown or zero. */ val = TYPE_SIZE_UNIT (type); - if (!val - || TREE_CODE (val) != INTEGER_CST - || integer_zerop (val)) + if (!val || integer_zerop (val)) return false; - val = wide_int_to_tree (TREE_TYPE (val), - wi::sub (wi::to_wide (val), 1)); + 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); Index: gcc/gimple-fold.h =================================================================== --- gcc/gimple-fold.h (revision 262933) +++ gcc/gimple-fold.h (working copy) @@ -61,6 +61,7 @@ extern bool gimple_fold_builtin_snprintf (gimple_s extern bool arith_code_with_undefined_signed_overflow (tree_code); extern gimple_seq rewrite_to_defined_overflow (gimple *); extern void replace_call_with_value (gimple_stmt_iterator *, tree); +extern tree get_inner_char_array_unless_typecast (tree); /* gimple_build, functionally matching fold_buildN, outputs stmts int the provided sequence, matching and simplifying them on-the-fly. Index: gcc/tree-ssa-strlen.c =================================================================== --- gcc/tree-ssa-strlen.c (revision 262933) +++ gcc/tree-ssa-strlen.c (working copy) @@ -1149,11 +1149,15 @@ maybe_set_strlen_range (tree lhs, tree src, tree b if (TREE_CODE (src) == ADDR_EXPR) { + src = TREE_OPERAND (src, 0); + + src = get_inner_char_array_unless_typecast (src); + + if (!src) + ; /* The last array member of a struct can be bigger than its size suggests if it's treated as a poor-man's flexible array member. */ - src = TREE_OPERAND (src, 0); - bool src_is_array = TREE_CODE (TREE_TYPE (src)) == ARRAY_TYPE; - if (src_is_array && !array_at_struct_end_p (src)) + else if (!array_at_struct_end_p (src)) { tree type = TREE_TYPE (src); if (tree size = TYPE_SIZE_UNIT (type)) @@ -1170,8 +1174,6 @@ maybe_set_strlen_range (tree lhs, tree src, tree b } else { - if (TREE_CODE (src) == COMPONENT_REF && !src_is_array) - src = TREE_OPERAND (src, 1); if (DECL_P (src)) { /* Handle the unlikely case of strlen (&c) where c is some Index: gcc/testsuite/gcc.dg/strlenopt-40.c =================================================================== --- gcc/testsuite/gcc.dg/strlenopt-40.c (revision 262933) +++ gcc/testsuite/gcc.dg/strlenopt-40.c (working copy) @@ -105,20 +105,20 @@ 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 (a7_3[0]) < sizeof a7_3); + ELIM_TRUE (strlen (a7_3[1]) < sizeof a7_3); + ELIM_TRUE (strlen (a7_3[6]) < sizeof a7_3); + ELIM_TRUE (strlen (a7_3[i]) < sizeof a7_3); - 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 (a5_7[0]) < sizeof a5_7); + ELIM_TRUE (strlen (a5_7[1]) < sizeof a5_7); + ELIM_TRUE (strlen (a5_7[4]) < sizeof a5_7); + ELIM_TRUE (strlen (a5_7[i]) < sizeof a5_7); - 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 (ax_3[0]) < DIFF_MAX - 1); + ELIM_TRUE (strlen (ax_3[1]) < DIFF_MAX - 1); + ELIM_TRUE (strlen (ax_3[9]) < DIFF_MAX - 1); + ELIM_TRUE (strlen (ax_3[i]) < DIFF_MAX - 1); ELIM_TRUE (strlen (a3) < sizeof a3); ELIM_TRUE (strlen (a7) < sizeof a7); @@ -134,17 +134,17 @@ void elim_pointer_to_arrays (void) 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 ((*pa7_3)[0]) < 21); + ELIM_TRUE (strlen ((*pa7_3)[1]) < 21); + ELIM_TRUE (strlen ((*pa7_3)[6]) < 21); - ELIM_TRUE (strlen ((*pax_3)[0]) < 3); - ELIM_TRUE (strlen ((*pax_3)[1]) < 3); - ELIM_TRUE (strlen ((*pax_3)[9]) < 3); + ELIM_TRUE (strlen ((*pax_3)[0]) < DIFF_MAX - 1); + ELIM_TRUE (strlen ((*pax_3)[1]) < DIFF_MAX - 1); + ELIM_TRUE (strlen ((*pax_3)[9]) < DIFF_MAX - 1); - ELIM_TRUE (strlen ((*pa5_7)[0]) < 7); - ELIM_TRUE (strlen ((*pa5_7)[1]) < 7); - ELIM_TRUE (strlen ((*pa5_7)[4]) < 7); + ELIM_TRUE (strlen ((*pa5_7)[0]) < 35); + ELIM_TRUE (strlen ((*pa5_7)[1]) < 35); + ELIM_TRUE (strlen ((*pa5_7)[4]) < 35); } void elim_global_arrays_and_strings (int i) @@ -198,11 +198,11 @@ void elim_member_arrays_obj (int i) 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].a7_3[0]) < 21); + ELIM_TRUE (strlen (ma0_3_5_7[2][4][6].a7_3[2]) < 21); - 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); + ELIM_TRUE (strlen (ma0_3_5_7[0][0][0].a5_7[0]) < 35); + ELIM_TRUE (strlen (ma0_3_5_7[2][4][6].a5_7[4]) < 35); } void elim_member_arrays_ptr (struct MemArrays0 *ma0, @@ -210,19 +210,23 @@ void elim_member_arrays_ptr (struct MemArrays0 *ma 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->a7_3[0]) < 21); + ELIM_TRUE (strlen (ma0->a7_3[1]) < 21); + ELIM_TRUE (strlen (ma0->a7_3[6]) < 21); + ELIM_TRUE (strlen (ma0->a7_3[6]) < 21); + ELIM_TRUE (strlen (ma0->a7_3[i]) < 21); + ELIM_TRUE (strlen (ma0->a7_3[i]) < 21); - 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->a5_7[0]) < 35); + ELIM_TRUE (strlen (ma0[0].a5_7[0]) < 35); +#if 0 + /* This is tranformed into strlen ((const char *) &(ma0 + 64)->a5_7[0]) + which looks like a type cast and fails the check in get_range_strlen. */ + ELIM_TRUE (strlen (ma0[1].a5_7[0]) < 35); + ELIM_TRUE (strlen (ma0[1].a5_7[4]) < 35); + ELIM_TRUE (strlen (ma0[9].a5_7[0]) < 35); + ELIM_TRUE (strlen (ma0[9].a5_7[4]) < 35); +#endif ELIM_TRUE (strlen (ma0->a3) < sizeof ma0->a3); ELIM_TRUE (strlen (ma0->a5) < sizeof ma0->a5); Index: gcc/testsuite/gcc.dg/strlenopt-45.c =================================================================== --- gcc/testsuite/gcc.dg/strlenopt-45.c (revision 262933) +++ gcc/testsuite/gcc.dg/strlenopt-45.c (working copy) @@ -43,7 +43,6 @@ extern size_t strnlen (const char *, size_t); else \ FAIL (made_in_false_branch) -extern char c; extern char a1[1]; extern char a3[3]; extern char a5[5]; @@ -52,18 +51,6 @@ extern char ax[]; void elim_strnlen_arr_cst (void) { - /* The length of a string stored in a one-element array must be zero. - The result reported by strnlen() for such an array can be non-zero - only when the bound is equal to 1 (in which case the result must - be one). */ - ELIM (strnlen (&c, 0) == 0); - ELIM (strnlen (&c, 1) < 2); - ELIM (strnlen (&c, 2) == 0); - ELIM (strnlen (&c, 9) == 0); - ELIM (strnlen (&c, PTRDIFF_MAX) == 0); - ELIM (strnlen (&c, SIZE_MAX) == 0); - ELIM (strnlen (&c, -1) == 0); - ELIM (strnlen (a1, 0) == 0); ELIM (strnlen (a1, 1) < 2); ELIM (strnlen (a1, 2) == 0); @@ -85,31 +72,31 @@ void elim_strnlen_arr_cst (void) ELIM (strnlen (a3_7[0], 1) < 2); ELIM (strnlen (a3_7[0], 2) < 3); ELIM (strnlen (a3_7[0], 3) < 4); - ELIM (strnlen (a3_7[0], 9) < 8); - ELIM (strnlen (a3_7[0], PTRDIFF_MAX) < 8); - ELIM (strnlen (a3_7[0], SIZE_MAX) < 8); - ELIM (strnlen (a3_7[0], -1) < 8); + ELIM (strnlen (a3_7[0], 9) < 10); + ELIM (strnlen (a3_7[0], PTRDIFF_MAX) < 21); + ELIM (strnlen (a3_7[0], SIZE_MAX) < 21); + ELIM (strnlen (a3_7[0], -1) < 21); ELIM (strnlen (a3_7[2], 0) == 0); ELIM (strnlen (a3_7[2], 1) < 2); ELIM (strnlen (a3_7[2], 2) < 3); ELIM (strnlen (a3_7[2], 3) < 4); - ELIM (strnlen (a3_7[2], 9) < 8); - ELIM (strnlen (a3_7[2], PTRDIFF_MAX) < 8); - ELIM (strnlen (a3_7[2], SIZE_MAX) < 8); - ELIM (strnlen (a3_7[2], -1) < 8); + ELIM (strnlen (a3_7[2], 9) < 10); + ELIM (strnlen (a3_7[2], PTRDIFF_MAX) < 21); + ELIM (strnlen (a3_7[2], SIZE_MAX) < 21); + ELIM (strnlen (a3_7[2], -1) < 21); - ELIM (strnlen ((char*)a3_7, 0) == 0); - ELIM (strnlen ((char*)a3_7, 1) < 2); - ELIM (strnlen ((char*)a3_7, 2) < 3); - ELIM (strnlen ((char*)a3_7, 3) < 4); - ELIM (strnlen ((char*)a3_7, 9) < 10); - ELIM (strnlen ((char*)a3_7, 19) < 20); - ELIM (strnlen ((char*)a3_7, 21) < 22); - ELIM (strnlen ((char*)a3_7, 23) < 22); - ELIM (strnlen ((char*)a3_7, PTRDIFF_MAX) < 22); - ELIM (strnlen ((char*)a3_7, SIZE_MAX) < 22); - ELIM (strnlen ((char*)a3_7, -1) < 22); + ELIM (strnlen ((char*)a3_7[0], 0) == 0); + ELIM (strnlen ((char*)a3_7[0], 1) < 2); + ELIM (strnlen ((char*)a3_7[0], 2) < 3); + ELIM (strnlen ((char*)a3_7[0], 3) < 4); + ELIM (strnlen ((char*)a3_7[0], 9) < 10); + ELIM (strnlen ((char*)a3_7[0], 19) < 20); + ELIM (strnlen ((char*)a3_7[0], 21) < 22); + ELIM (strnlen ((char*)a3_7[0], 23) < 21); + ELIM (strnlen ((char*)a3_7[0], PTRDIFF_MAX) < 21); + ELIM (strnlen ((char*)a3_7[0], SIZE_MAX) < 21); + ELIM (strnlen ((char*)a3_7[0], -1) < 21); ELIM (strnlen (ax, 0) == 0); ELIM (strnlen (ax, 1) < 2); @@ -122,7 +109,6 @@ void elim_strnlen_arr_cst (void) struct MemArrays { - char c; char a0[0]; char a1[1]; char a3[3]; @@ -133,13 +119,6 @@ struct MemArrays void elim_strnlen_memarr_cst (struct MemArrays *p, int i) { - ELIM (strnlen (&p->c, 0) == 0); - ELIM (strnlen (&p->c, 1) < 2); - ELIM (strnlen (&p->c, 9) == 0); - ELIM (strnlen (&p->c, PTRDIFF_MAX) == 0); - ELIM (strnlen (&p->c, SIZE_MAX) == 0); - ELIM (strnlen (&p->c, -1) == 0); - /* Other accesses to internal zero-length arrays are undefined. */ ELIM (strnlen (p->a0, 0) == 0); @@ -154,37 +133,39 @@ void elim_strnlen_memarr_cst (struct MemArrays *p, ELIM (strnlen (p->a3, 1) < 2); ELIM (strnlen (p->a3, 2) < 3); ELIM (strnlen (p->a3, 3) < 4); - ELIM (strnlen (p->a3, 9) < 4); - ELIM (strnlen (p->a3, PTRDIFF_MAX) < 4); - ELIM (strnlen (p->a3, SIZE_MAX) < 4); - ELIM (strnlen (p->a3, -1) < 4); + ELIM (strnlen (p->a3, 9) < 3); + ELIM (strnlen (p->a3, PTRDIFF_MAX) < 3); + ELIM (strnlen (p->a3, SIZE_MAX) < 3); + ELIM (strnlen (p->a3, -1) < 3); ELIM (strnlen (p[i].a3, 0) == 0); ELIM (strnlen (p[i].a3, 1) < 2); ELIM (strnlen (p[i].a3, 2) < 3); ELIM (strnlen (p[i].a3, 3) < 4); - ELIM (strnlen (p[i].a3, 9) < 4); - ELIM (strnlen (p[i].a3, PTRDIFF_MAX) < 4); - ELIM (strnlen (p[i].a3, SIZE_MAX) < 4); - ELIM (strnlen (p[i].a3, -1) < 4); + ELIM (strnlen (p[i].a3, 9) < 3); + ELIM (strnlen (p[i].a3, PTRDIFF_MAX) < 3); + ELIM (strnlen (p[i].a3, SIZE_MAX) < 3); + ELIM (strnlen (p[i].a3, -1) < 3); ELIM (strnlen (p->a3_7[0], 0) == 0); ELIM (strnlen (p->a3_7[0], 1) < 2); ELIM (strnlen (p->a3_7[0], 2) < 3); ELIM (strnlen (p->a3_7[0], 3) < 4); - ELIM (strnlen (p->a3_7[0], 9) < 8); - ELIM (strnlen (p->a3_7[0], PTRDIFF_MAX) < 8); - ELIM (strnlen (p->a3_7[0], SIZE_MAX) < 8); - ELIM (strnlen (p->a3_7[0], -1) < 8); + ELIM (strnlen (p->a3_7[0], 9) < 10); + ELIM (strnlen (p->a3_7[0], 21) < 22); + ELIM (strnlen (p->a3_7[0], PTRDIFF_MAX) < 21); + ELIM (strnlen (p->a3_7[0], SIZE_MAX) < 21); + ELIM (strnlen (p->a3_7[0], -1) < 21); ELIM (strnlen (p->a3_7[2], 0) == 0); ELIM (strnlen (p->a3_7[2], 1) < 2); ELIM (strnlen (p->a3_7[2], 2) < 3); ELIM (strnlen (p->a3_7[2], 3) < 4); - ELIM (strnlen (p->a3_7[2], 9) < 8); - ELIM (strnlen (p->a3_7[2], PTRDIFF_MAX) < 8); - ELIM (strnlen (p->a3_7[2], SIZE_MAX) < 8); - ELIM (strnlen (p->a3_7[2], -1) < 8); + ELIM (strnlen (p->a3_7[2], 9) < 10); + ELIM (strnlen (p->a3_7[2], 21) < 22); + ELIM (strnlen (p->a3_7[2], PTRDIFF_MAX) < 21); + ELIM (strnlen (p->a3_7[2], SIZE_MAX) < 21); + ELIM (strnlen (p->a3_7[2], -1) < 21); ELIM (strnlen (p->a3_7[i], 0) == 0); ELIM (strnlen (p->a3_7[i], 1) < 2); @@ -203,17 +184,17 @@ void elim_strnlen_memarr_cst (struct MemArrays *p, ELIM (strnlen (p->a3_7[i], 19) < 20); #endif - ELIM (strnlen ((char*)p->a3_7, 0) == 0); - ELIM (strnlen ((char*)p->a3_7, 1) < 2); - ELIM (strnlen ((char*)p->a3_7, 2) < 3); - ELIM (strnlen ((char*)p->a3_7, 3) < 4); - ELIM (strnlen ((char*)p->a3_7, 9) < 10); - ELIM (strnlen ((char*)p->a3_7, 19) < 20); - ELIM (strnlen ((char*)p->a3_7, 21) < 22); - ELIM (strnlen ((char*)p->a3_7, 23) < 22); - ELIM (strnlen ((char*)p->a3_7, PTRDIFF_MAX) < 22); - ELIM (strnlen ((char*)p->a3_7, SIZE_MAX) < 22); - ELIM (strnlen ((char*)p->a3_7, -1) < 22); + ELIM (strnlen ((char*)p->a3_7[0], 0) == 0); + ELIM (strnlen ((char*)p->a3_7[0], 1) < 2); + ELIM (strnlen ((char*)p->a3_7[0], 2) < 3); + ELIM (strnlen ((char*)p->a3_7[0], 3) < 4); + ELIM (strnlen ((char*)p->a3_7[0], 9) < 10); + ELIM (strnlen ((char*)p->a3_7[0], 19) < 20); + ELIM (strnlen ((char*)p->a3_7[0], 21) < 22); + ELIM (strnlen ((char*)p->a3_7[0], 23) < 22); + ELIM (strnlen ((char*)p->a3_7[0], PTRDIFF_MAX) < 22); + ELIM (strnlen ((char*)p->a3_7[0], SIZE_MAX) < 22); + ELIM (strnlen ((char*)p->a3_7[0], -1) < 22); ELIM (strnlen (p->ax, 0) == 0); ELIM (strnlen (p->ax, 1) < 2); @@ -290,9 +271,6 @@ void elim_strnlen_range (char *s) void keep_strnlen_arr_cst (void) { - KEEP (strnlen (&c, 1) == 0); - KEEP (strnlen (&c, 1) == 1); - KEEP (strnlen (a1, 1) == 0); KEEP (strnlen (a1, 1) == 1); @@ -301,7 +279,6 @@ void keep_strnlen_arr_cst (void) struct FlexArrays { - char c; char a0[0]; /* Access to internal zero-length arrays are undefined. */ char a1[1]; }; @@ -308,9 +285,6 @@ struct FlexArrays void keep_strnlen_memarr_cst (struct FlexArrays *p) { - KEEP (strnlen (&p->c, 1) == 0); - KEEP (strnlen (&p->c, 1) == 1); - #if 0 /* Accesses to internal zero-length arrays are undefined so avoid exercising them. */ @@ -331,5 +305,5 @@ void keep_strnlen_memarr_cst (struct FlexArrays *p /* { dg-final { scan-tree-dump-times "call_in_true_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\]" 13 "optimized" } } - { dg-final { scan-tree-dump-times "call_made_in_false_branch_on_line_1\[0-9\]\[0-9\]\[0-9\]" 13 "optimized" } } */ + { dg-final { scan-tree-dump-times "call_made_in_true_branch_on_line_1\[0-9\]\[0-9\]\[0-9\]" 9 "optimized" } } + { dg-final { scan-tree-dump-times "call_made_in_false_branch_on_line_1\[0-9\]\[0-9\]\[0-9\]" 9 "optimized" } } */ Index: gcc/testsuite/gcc.dg/strlenopt-48.c =================================================================== --- gcc/testsuite/gcc.dg/strlenopt-48.c (revision 262933) +++ gcc/testsuite/gcc.dg/strlenopt-48.c (working copy) @@ -9,8 +9,8 @@ void f (void) { - extern char a[2][1]; - int n = strlen (a[1]); + extern char a[1][1]; + int n = strlen (a[0]); if (n) abort(); } @@ -17,8 +17,8 @@ void f (void) void g (void) { - extern char b[3][2][1]; - int n = strlen (b[2][1]); + extern char b[1][1][1]; + int n = strlen (b[0][0]); if (n) abort(); } @@ -25,8 +25,8 @@ void g (void) void h (void) { - extern char c[4][3][2][1]; - int n = strlen (c[3][2][1]); + extern char c[1][1][1][1]; + int n = strlen (c[0][0][0]); if (n) abort(); } Index: gcc/testsuite/gcc.dg/strlenopt-51.c =================================================================== --- gcc/testsuite/gcc.dg/strlenopt-51.c (revision 262933) +++ gcc/testsuite/gcc.dg/strlenopt-51.c (working copy) @@ -101,7 +101,7 @@ void test_keep_a9_9 (int i) { #undef T #define T(I) \ - KEEP (strlen (&a9_9[i][I][0]) > (1 + I) % 9); \ + KEEP (strlen (&a9_9[i][I][0]) > (0 + I) % 9); \ KEEP (strlen (&a9_9[i][I][1]) > (1 + I) % 9); \ KEEP (strlen (&a9_9[i][I][2]) > (2 + I) % 9); \ KEEP (strlen (&a9_9[i][I][3]) > (3 + I) % 9); \ @@ -115,7 +115,7 @@ void test_keep_a9_9 (int i) } /* { dg-final { scan-tree-dump-times "strlen" 72 "gimple" } } - { dg-final { scan-tree-dump-times "strlen" 63 "optimized" } } + { dg-final { scan-tree-dump-times "strlen" 72 "optimized" } } - { dg-final { scan-tree-dump-times "call_made_in_true_branch_on_line_1\[0-9\]\[0-9\]\[0-9\]" 72 "optimized" } } + { dg-final { scan-tree-dump-times "call_made_in_true_branch_on_line_1\[0-9\]\[0-9\]\[0-9\]" 81 "optimized" } } { dg-final { scan-tree-dump-times "call_made_in_false_branch_on_line_1\[0-9\]\[0-9\]\[0-9\]" 81 "optimized" } } */ Index: gcc/testsuite/gcc.dg/strlenopt-54.c =================================================================== --- gcc/testsuite/gcc.dg/strlenopt-54.c (revision 0) +++ gcc/testsuite/gcc.dg/strlenopt-54.c (working copy) @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fdump-tree-optimized" } */ + +typedef char A[6]; +typedef char B[2][3]; + +A a; + +void test (void) +{ + B* b = (B*) a; + if (__builtin_strlen ((*b)[0]) > 2) + __builtin_abort (); +} + +/* { dg-final { scan-tree-dump-times "__builtin_strlen" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "__builtin_abort" 1 "optimized" } } */