Hi, this is an update of the patch to prevent unsafe optimizations due to strlen range assuming always zero-terminated char arrays.
Since the previous version I do no longer try to locate the outermost char array, but just bail out if there is a typecast, that means, supposed we have a 2-dimensional array, char a[x][y], strlen (s.a[x]) may assume a[x] is zero-terminated, if the optimization is enabled. strlen ((char*)s.a) involves a type cast and should assume nothing. Additionally due to the discussion, I came to the conclusion that this strlen range optimization should only be used when enabled with -fassume-zero-terminated-char-arrays or -Ofast. Note that I included the test case with the removed assertion as gcc/testsuite/gcc.dg/strlenopt-57.c Initially it would only miscompile with -Ofast, but with r263018 aka PR tree-optimization/86043, PR tree-optimization/86042 it was miscompiled with -O3 as well. I located the reason in gcc/tree-ssa-strlen.c (get_min_string_length) which did not check if the string constant is in fact zero terminated: @@ -3192,7 +3194,9 @@ get_min_string_length (tree rhs, bool *full_string && TREE_READONLY (rhs)) rhs = DECL_INITIAL (rhs); - if (rhs && TREE_CODE (rhs) == STRING_CST) + if (rhs && TREE_CODE (rhs) == STRING_CST + && compare_tree_int (TYPE_SIZE_UNIT (TREE_TYPE (rhs)), + TREE_STRING_LENGTH (rhs)) >= 0) { *full_string_p = true; return strlen (TREE_STRING_POINTER (rhs)); Fortunately this also shows a way how to narrow strlen return value expectations when we are able to positively prove that a string must be zero terminated. Bootstrapped and reg-tested on x86_64-pc-linux-gnu. Is it OK for trunk? Thanks Bernd.
gcc: 2018-08-01 Bernd Edlinger <bernd.edlin...@hotmail.de> * common.opt: Add new optimization option -fassume-zero-terminated-char-arrays. * opts.c (default_options): Enable -fassume-zero-terminated-char-arrays with -Ofast. * 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. * gimple-fold.h (get_inner_char_array_unless_typecast): Declare. * tree-ssa-strlen.c (maybe_set_strlen_range): Likewise. (get_min_string_length): Avoid not NUL terminated string literals. * doc/invoke.texi: Document -fassume-zero-terminated-char-arrays. testsuite: 2018-08-01 Bernd Edlinger <bernd.edlin...@hotmail.de> * gcc.dg/tree-ssa/builtin-snprintf-warn-1.c: Add -fassume-zero-terminated-char-arrays. * gcc.dg/tree-ssa/builtin-snprintf-warn-2.c: Likewise * gcc.dg/tree-ssa/builtin-snprintf-warn-3.c: Likewise * gcc.dg/tree-ssa/builtin-sprintf-warn-14.c: Likewise * gcc.dg/tree-ssa/builtin-sprintf-warn-2.c: Likewise * gcc.dg/tree-ssa/pr79376.c: Likewise * gcc.dg/Wstringop-overflow-5.c: Likewise. * gcc.dg/Wstringop-truncation-3.c: Likewise. * gcc.dg/Wstringop-truncation.c: Likewise. * gcc.dg/pr79538.c: Likewise. * gcc.dg/pr83373.c: Likewise. * gcc.dg/strlenopt-36.c: Likewise. * 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-55.c: New test. * gcc.dg/strlenopt-56.c: New test. * gcc.dg/strlenopt-57.c: New test.
Index: gcc/common.opt =================================================================== --- gcc/common.opt (revision 263029) +++ gcc/common.opt (working copy) @@ -1025,6 +1025,10 @@ fsanitize-undefined-trap-on-error Common Driver Report Var(flag_sanitize_undefined_trap_on_error) Init(0) Use trap instead of a library function for undefined behavior sanitization. +fassume-zero-terminated-char-arrays +Common Var(flag_assume_zero_terminated_char_arrays) Optimization Init(0) +Optimize under the assumption that char arrays must always be zero terminated. + fasynchronous-unwind-tables Common Report Var(flag_asynchronous_unwind_tables) Optimization Generate unwind tables that are exact at each instruction boundary. Index: gcc/gimple-fold.c =================================================================== --- gcc/gimple-fold.c (revision 263029) +++ gcc/gimple-fold.c (working copy) @@ -1257,7 +1257,45 @@ 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) +{ + if (!flag_assume_zero_terminated_char_arrays) + return NULL_TREE; + + /* 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; + + 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 +1348,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 +1377,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 +1394,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 +1420,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 +1430,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) && flag_assume_zero_terminated_char_arrays) { tree type = TREE_TYPE (arg); if (POINTER_TYPE_P (type)) @@ -1409,13 +1438,20 @@ 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 + || TYPE_MODE (TREE_TYPE (type)) + != TYPE_MODE (char_type_node) + || TYPE_PRECISION (TREE_TYPE (type)) + != TYPE_PRECISION (char_type_node)) + 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 263029) +++ 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/opts.c =================================================================== --- gcc/opts.c (revision 263029) +++ gcc/opts.c (working copy) @@ -547,6 +547,7 @@ static const struct default_options default_option /* -Ofast adds optimizations to -O3. */ { OPT_LEVELS_FAST, OPT_ffast_math, NULL, 1 }, + { OPT_LEVELS_FAST, OPT_fassume_zero_terminated_char_arrays, NULL, 1 }, { OPT_LEVELS_NONE, 0, NULL, 0 } }; Index: gcc/tree-ssa-strlen.c =================================================================== --- gcc/tree-ssa-strlen.c (revision 263029) +++ 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 @@ -3192,7 +3194,9 @@ get_min_string_length (tree rhs, bool *full_string && TREE_READONLY (rhs)) rhs = DECL_INITIAL (rhs); - if (rhs && TREE_CODE (rhs) == STRING_CST) + if (rhs && TREE_CODE (rhs) == STRING_CST + && compare_tree_int (TYPE_SIZE_UNIT (TREE_TYPE (rhs)), + TREE_STRING_LENGTH (rhs)) >= 0) { *full_string_p = true; return strlen (TREE_STRING_POINTER (rhs)); Index: gcc/doc/invoke.texi =================================================================== --- gcc/doc/invoke.texi (revision 263045) +++ gcc/doc/invoke.texi (working copy) @@ -387,7 +387,8 @@ Objective-C and Objective-C++ Dialects}. -falign-jumps[=@var{n}[:@var{m}:[@var{n2}[:@var{m2}]]]] @gol -falign-labels[=@var{n}[:@var{m}:[@var{n2}[:@var{m2}]]]] @gol -falign-loops[=@var{n}[:@var{m}:[@var{n2}[:@var{m2}]]]] @gol --fassociative-math -fauto-profile -fauto-profile[=@var{path}] @gol +-fassociative-math -fassume-zero-terminated-char-arrays @gol +-fauto-profile -fauto-profile[=@var{path}] @gol -fauto-inc-dec -fbranch-probabilities @gol -fbranch-target-load-optimize -fbranch-target-load-optimize2 @gol -fbtr-bb-exclusive -fcaller-saves @gol @@ -9938,6 +9939,17 @@ is automatically enabled when both @option{-fno-si The default is @option{-fno-associative-math}. +@item -fassume-zero-terminated-char-arrays +@opindex fassume-zero-terminated-char-arrays + +Optimize under the assumption that char arrays must always be zero +terminated. This may have an effect on code that uses strlen to +check the string length, for instance in assertions. Under certain +conditions such checks can be optimized away. This option is enabled +by default at optimization level @option{-Ofast}. + +The default is @option{-fno-assume-zero-terminated-char-arrays}. + @item -freciprocal-math @opindex freciprocal-math Index: gcc/testsuite/gcc.dg/Wstringop-overflow-5.c =================================================================== --- gcc/testsuite/gcc.dg/Wstringop-overflow-5.c (revision 263029) +++ gcc/testsuite/gcc.dg/Wstringop-overflow-5.c (working copy) @@ -1,6 +1,6 @@ /* PR tree-optimization/85259 - Missing -Wstringop-overflow= since r256683 { dg-do compile } - { dg-options "-O2 -Wstringop-overflow" } */ + { dg-options "-O2 -Wstringop-overflow -fassume-zero-terminated-char-arrays" } */ extern char* strcpy (char*, const char*); extern char* strcat (char*, const char*); Index: gcc/testsuite/gcc.dg/Wstringop-truncation-3.c =================================================================== --- gcc/testsuite/gcc.dg/Wstringop-truncation-3.c (revision 263029) +++ gcc/testsuite/gcc.dg/Wstringop-truncation-3.c (working copy) @@ -1,6 +1,6 @@ /* PR c/85931 - -Wsizeof-pointer-memaccess for strncpy with size of source { dg-do compile } - { dg-options "-O2 -Wall -Wstringop-truncation -ftrack-macro-expansion=0" } */ + { dg-options "-O2 -Wall -Wstringop-truncation -fassume-zero-terminated-char-arrays -ftrack-macro-expansion=0" } */ typedef __SIZE_TYPE__ size_t; Index: gcc/testsuite/gcc.dg/Wstringop-truncation.c =================================================================== --- gcc/testsuite/gcc.dg/Wstringop-truncation.c (revision 263029) +++ gcc/testsuite/gcc.dg/Wstringop-truncation.c (working copy) @@ -1,7 +1,7 @@ /* PR tree-optimization/84468 - Inconsistent -Wstringop-truncation warnings with -O2 { dg-do compile } - { dg-options "-O2 -Wstringop-truncation -ftrack-macro-expansion=0 -g" } */ + { dg-options "-O2 -Wstringop-truncation -fassume-zero-terminated-char-arrays -ftrack-macro-expansion=0 -g" } */ #define strncpy __builtin_strncpy Index: gcc/testsuite/gcc.dg/pr79538.c =================================================================== --- gcc/testsuite/gcc.dg/pr79538.c (revision 263029) +++ gcc/testsuite/gcc.dg/pr79538.c (working copy) @@ -1,6 +1,6 @@ /* PR middle-end/79538 - missing -Wformat-overflow with %s and non-member array arguments { dg-do compile } - { dg-options "-O2 -Wformat-overflow" } */ + { dg-options "-O2 -Wformat-overflow -fassume-zero-terminated-char-arrays" } */ char a3[3]; char a4[4]; Index: gcc/testsuite/gcc.dg/pr83373.c =================================================================== --- gcc/testsuite/gcc.dg/pr83373.c (revision 263029) +++ gcc/testsuite/gcc.dg/pr83373.c (working copy) @@ -1,6 +1,6 @@ /* PR middle-end/83373 - False positive reported by -Wstringop-overflow { dg-do compile } - { dg-options "-O2 -Wstringop-overflow" } */ + { dg-options "-O2 -Wstringop-overflow -fassume-zero-terminated-char-arrays" } */ typedef __SIZE_TYPE__ size_t; Index: gcc/testsuite/gcc.dg/strlenopt-36.c =================================================================== --- gcc/testsuite/gcc.dg/strlenopt-36.c (revision 263029) +++ gcc/testsuite/gcc.dg/strlenopt-36.c (working copy) @@ -1,7 +1,7 @@ /* PR tree-optimization/78450 - strlen(s) return value can be assumed to be less than the size of s { dg-do compile } - { dg-options "-O2 -fdump-tree-optimized" } */ + { dg-options "-O2 -fassume-zero-terminated-char-arrays -fdump-tree-optimized" } */ #include "strlenopt.h" Index: gcc/testsuite/gcc.dg/strlenopt-40.c =================================================================== --- gcc/testsuite/gcc.dg/strlenopt-40.c (revision 263029) +++ gcc/testsuite/gcc.dg/strlenopt-40.c (working copy) @@ -1,7 +1,7 @@ /* 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" } */ + { dg-options "-O1 -fassume-zero-terminated-char-arrays -fdump-tree-optimized" } */ #include "strlenopt.h" @@ -219,10 +219,15 @@ void elim_member_arrays_ptr (struct MemArrays0 *ma ELIM_TRUE (strlen (ma0->a5_7[0]) < 7); ELIM_TRUE (strlen (ma0[0].a5_7[0]) < 7); +#if 0 + /* This is transformed into strlen ((const char *) &(ma0 + 64)->a5_7[0]) + which looks like a type cast and fails the check in + get_inner_char_array_unless_typecast. */ 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); +#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 263029) +++ gcc/testsuite/gcc.dg/strlenopt-45.c (working copy) @@ -2,7 +2,7 @@ Test to verify that strnlen built-in expansion works correctly in the absence of tree strlen optimization. { dg-do compile } - { dg-options "-O2 -Wall -fdump-tree-optimized" } */ + { dg-options "-O2 -Wall -fassume-zero-terminated-char-arrays -fdump-tree-optimized" } */ #include "strlenopt.h" @@ -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); @@ -99,17 +86,18 @@ void elim_strnlen_arr_cst (void) ELIM (strnlen (a3_7[2], SIZE_MAX) < 8); ELIM (strnlen (a3_7[2], -1) < 8); - 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], 7) < 8); + ELIM (strnlen ((char*)a3_7[0], 9) < 7); + ELIM (strnlen ((char*)a3_7[0], 19) < 7); + ELIM (strnlen ((char*)a3_7[0], 21) < 7); + ELIM (strnlen ((char*)a3_7[0], 23) < 7); + ELIM (strnlen ((char*)a3_7[0], PTRDIFF_MAX) < 7); + ELIM (strnlen ((char*)a3_7[0], SIZE_MAX) < 7); + ELIM (strnlen ((char*)a3_7[0], -1) < 7); ELIM (strnlen (ax, 0) == 0); ELIM (strnlen (ax, 1) < 2); @@ -122,7 +110,6 @@ void elim_strnlen_arr_cst (void) struct MemArrays { - char c; char a0[0]; char a1[1]; char a3[3]; @@ -133,13 +120,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,19 +134,19 @@ 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); @@ -203,17 +183,18 @@ 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], 7) < 8); + ELIM (strnlen ((char*)p->a3_7[0], 9) < 7); + ELIM (strnlen ((char*)p->a3_7[0], 19) < 7); + ELIM (strnlen ((char*)p->a3_7[0], 21) < 7); + ELIM (strnlen ((char*)p->a3_7[0], 23) < 7); + ELIM (strnlen ((char*)p->a3_7[0], PTRDIFF_MAX) < 7); + ELIM (strnlen ((char*)p->a3_7[0], SIZE_MAX) < 7); + ELIM (strnlen ((char*)p->a3_7[0], -1) < 7); 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 263029) +++ gcc/testsuite/gcc.dg/strlenopt-48.c (working copy) @@ -3,7 +3,7 @@ Verify that strlen() calls with one-character array elements of multidimensional arrays are still folded. { dg-do compile } - { dg-options "-O2 -Wall -fdump-tree-optimized" } */ + { dg-options "-O2 -Wall -fassume-zero-terminated-char-arrays -fdump-tree-optimized" } */ #include "strlenopt.h" Index: gcc/testsuite/gcc.dg/strlenopt-51.c =================================================================== --- gcc/testsuite/gcc.dg/strlenopt-51.c (revision 263029) +++ 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-55.c =================================================================== --- gcc/testsuite/gcc.dg/strlenopt-55.c (revision 0) +++ gcc/testsuite/gcc.dg/strlenopt-55.c (working copy) @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-Ofast -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" } } */ Index: gcc/testsuite/gcc.dg/strlenopt-56.c =================================================================== --- gcc/testsuite/gcc.dg/strlenopt-56.c (revision 0) +++ gcc/testsuite/gcc.dg/strlenopt-56.c (working copy) @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-Ofast -fdump-tree-optimized" } */ + +typedef char B[2][3]; + +B b; + +void test (void) +{ + if (__builtin_strlen (b[0]) > 2) + __builtin_abort (); +} + +/* { dg-final { scan-tree-dump-not "__builtin_strlen" "optimized" } } */ +/* { dg-final { scan-tree-dump-not "__builtin_abort" "optimized" } } */ Index: gcc/testsuite/gcc.dg/strlenopt-57.c =================================================================== --- gcc/testsuite/gcc.dg/strlenopt-57.c (revision 0) +++ gcc/testsuite/gcc.dg/strlenopt-57.c (working copy) @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fdump-tree-optimized" } */ + +#define assert(x) do { if (!(x)) __builtin_abort (); } while (0) +extern int system (const char *); +static int fun (char *p) +{ + char buf[16]; + + assert (__builtin_strlen (p) < 4); + + __builtin_sprintf (buf, "echo %s - %s", p, p); + return system (buf); +} + +void test (void) +{ + char b[2] = "ab"; + fun (b); +} + +/* { dg-final { scan-tree-dump-times "__builtin_strlen" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "__builtin_abort" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "__builtin_sprintf" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "system" 1 "optimized" } } */ Index: gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-1.c =================================================================== --- gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-1.c (revision 263029) +++ gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-1.c (working copy) @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -Wformat -Wformat-truncation=1 -ftrack-macro-expansion=0" } */ +/* { dg-options "-O2 -Wformat -Wformat-truncation=1 -fassume-zero-terminated-char-arrays -ftrack-macro-expansion=0" } */ typedef struct { Index: gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-2.c =================================================================== --- gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-2.c (revision 263029) +++ gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-2.c (working copy) @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -Wformat -Wformat-truncation=2 -ftrack-macro-expansion=0" } */ +/* { dg-options "-O2 -Wformat -Wformat-truncation=2 -fassume-zero-terminated-char-arrays -ftrack-macro-expansion=0" } */ typedef struct { Index: gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-3.c =================================================================== --- gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-3.c (revision 263029) +++ gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-3.c (working copy) @@ -1,6 +1,6 @@ /* PR middle-end/79448 - unhelpful -Wformat-truncation=2 warning { dg-do compile } - { dg-options "-O2 -Wformat -Wformat-truncation=2 -ftrack-macro-expansion=0" } + { dg-options "-O2 -Wformat -Wformat-truncation=2 -fassume-zero-terminated-char-arrays -ftrack-macro-expansion=0" } { dg-require-effective-target ptr32plus } */ typedef __SIZE_TYPE__ size_t; Index: gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-14.c =================================================================== --- gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-14.c (revision 263029) +++ gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-14.c (working copy) @@ -1,7 +1,7 @@ /* PR middle-end/79376 - wrong lower bound with %s and non-constant strings in -Wformat-overflow { dg-do compile } - { dg-options "-O2 -Wall -Wformat-overflow=1 -ftrack-macro-expansion=0" } */ + { dg-options "-O2 -Wall -Wformat-overflow=1 -fassume-zero-terminated-char-arrays -ftrack-macro-expansion=0" } */ typedef __SIZE_TYPE__ size_t; Index: gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-2.c =================================================================== --- gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-2.c (revision 263029) +++ gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-2.c (working copy) @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-Wformat -Wformat-overflow=2 -ftrack-macro-expansion=0" } */ +/* { dg-options "-Wformat -Wformat-overflow=2 -fassume-zero-terminated-char-arrays -ftrack-macro-expansion=0" } */ /* When debugging, define LINE to the line number of the test case to exercise and avoid exercising any of the others. The buffer and objsize macros Index: gcc/testsuite/gcc.dg/tree-ssa/pr79376.c =================================================================== --- gcc/testsuite/gcc.dg/tree-ssa/pr79376.c (revision 263029) +++ gcc/testsuite/gcc.dg/tree-ssa/pr79376.c (working copy) @@ -1,7 +1,7 @@ /* PR tree-optimization/79376 - wrong lower bound with %s and non-constant strings in -Wformat-overflow { dg-do compile } - { dg-options "-O2 -fdump-tree-optimized" } */ + { dg-options "-O2 -fassume-zero-terminated-char-arrays -fdump-tree-optimized" } */ #define CAT(s, n) s ## n #define FAIL(line) CAT (failure_on_line_, line)