This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] Make strlen range computations more conservative


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.

Attachment: changelog-range-strlen-v3.txt
Description: changelog-range-strlen-v3.txt

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)

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]