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]

[PATCH] Handle read-only vars initialized to string literals in c_strlen (take 2)


On Mon, Sep 13, 2004 at 11:50:15AM -0700, Richard Henderson wrote:
> You probably need additional tests to notice that
> 
> 	const char var[5] = "hello";
> 
> has no null terminator.  You should use binds_local_p.
> 
> Rather than duplicating these tests for ARRAY_REF and PLUS_EXPR,
> you might break this out into a new function, or recurse.
> 
> > --- gcc/testsuite/gcc.c-torture/execute/builtins/strlen.c
> 
> Please create a new test instead.

Like this?
Bootstrapped/regtested on i386-redhat-linux.

2004-09-14  Jakub Jelinek  <jakub@redhat.com>

	* expr.c (string_constant): Handle also read-only variables
	initialized to string literals.

	* gcc.c-torture/execute/builtins/strlen-3.c: New test.
	* gcc.c-torture/execute/builtins/strlen-3-lib.c: New.

--- gcc/expr.c.jj	2004-09-11 20:34:54.000000000 +0200
+++ gcc/expr.c	2004-09-14 14:56:46.517320327 +0200
@@ -8299,20 +8299,31 @@ is_aligning_offset (tree offset, tree ex
 tree
 string_constant (tree arg, tree *ptr_offset)
 {
+  tree array, offset;
   STRIP_NOPS (arg);
 
-  if (TREE_CODE (arg) == ADDR_EXPR
-      && TREE_CODE (TREE_OPERAND (arg, 0)) == STRING_CST)
+  if (TREE_CODE (arg) == ADDR_EXPR)
     {
-      *ptr_offset = size_zero_node;
-      return TREE_OPERAND (arg, 0);
-    }
-  if (TREE_CODE (arg) == ADDR_EXPR
-      && TREE_CODE (TREE_OPERAND (arg, 0)) == ARRAY_REF
-      && TREE_CODE (TREE_OPERAND (TREE_OPERAND (arg, 0), 0)) == STRING_CST)
-    {
-      *ptr_offset = convert (sizetype, TREE_OPERAND (TREE_OPERAND (arg, 0), 1));
-      return TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
+      if (TREE_CODE (TREE_OPERAND (arg, 0)) == STRING_CST)
+	{
+	  *ptr_offset = size_zero_node;
+	  return TREE_OPERAND (arg, 0);
+	}
+      else if (TREE_CODE (TREE_OPERAND (arg, 0)) == VAR_DECL)
+	{
+	  array = TREE_OPERAND (arg, 0);
+	  offset = size_zero_node;
+	}
+      else if (TREE_CODE (TREE_OPERAND (arg, 0)) == ARRAY_REF)
+	{
+	  array = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
+	  offset = TREE_OPERAND (TREE_OPERAND (arg, 0), 1);
+	  if (TREE_CODE (array) != STRING_CST
+	      && TREE_CODE (array) != VAR_DECL)
+	    return 0;
+	}
+      else
+	return 0;
     }
   else if (TREE_CODE (arg) == PLUS_EXPR)
     {
@@ -8323,17 +8334,62 @@ string_constant (tree arg, tree *ptr_off
       STRIP_NOPS (arg1);
 
       if (TREE_CODE (arg0) == ADDR_EXPR
-	  && TREE_CODE (TREE_OPERAND (arg0, 0)) == STRING_CST)
+	  && (TREE_CODE (TREE_OPERAND (arg0, 0)) == STRING_CST
+	      || TREE_CODE (TREE_OPERAND (arg0, 0)) == VAR_DECL))
 	{
-	  *ptr_offset = convert (sizetype, arg1);
-	  return TREE_OPERAND (arg0, 0);
+	  array = TREE_OPERAND (arg0, 0);
+	  offset = arg1;
 	}
       else if (TREE_CODE (arg1) == ADDR_EXPR
-	       && TREE_CODE (TREE_OPERAND (arg1, 0)) == STRING_CST)
+	       && (TREE_CODE (TREE_OPERAND (arg1, 0)) == STRING_CST
+		   || TREE_CODE (TREE_OPERAND (arg1, 0)) == VAR_DECL))
 	{
-	  *ptr_offset = convert (sizetype, arg0);
-	  return TREE_OPERAND (arg1, 0);
+	  array = TREE_OPERAND (arg1, 0);
+	  offset = arg0;
 	}
+      else
+	return 0;
+    }
+  else
+    return 0;
+
+  if (TREE_CODE (array) == STRING_CST)
+    {
+      *ptr_offset = convert (sizetype, offset);
+      return array;
+    }
+  else if (TREE_CODE (array) == VAR_DECL)
+    {
+      int length;
+
+      /* Variables initialized to string literals can be handled too.  */
+      if (DECL_INITIAL (array) == NULL_TREE
+	  || TREE_CODE (DECL_INITIAL (array)) != STRING_CST)
+	return 0;
+
+      /* If they are read-only, non-volatile and bind locally.  */
+      if (! TREE_READONLY (array)
+	  || TREE_SIDE_EFFECTS (array)
+	  || ! targetm.binds_local_p (array))
+	return 0;
+
+      /* Avoid const char foo[4] = "abcde";  */
+      if (DECL_SIZE_UNIT (array) == NULL_TREE
+	  || TREE_CODE (DECL_SIZE_UNIT (array)) != INTEGER_CST
+	  || (length = TREE_STRING_LENGTH (DECL_INITIAL (array))) <= 0
+	  || compare_tree_int (DECL_SIZE_UNIT (array), length) < 0)
+	return 0;
+
+      /* If variable is bigger than the string literal, OFFSET must be constant
+	 and inside of the bounds of the string literal.  */
+      offset = convert (sizetype, offset);
+      if (compare_tree_int (DECL_SIZE_UNIT (array), length) > 0
+	  && (! host_integerp (offset, 1)
+	      || compare_tree_int (offset, length) >= 0))
+	return 0;
+
+      *ptr_offset = offset;
+      return DECL_INITIAL (array);
     }
 
   return 0;
--- gcc/testsuite/gcc.c-torture/execute/builtins/strlen-3.c.jj	2004-09-14 11:17:28.150355605 +0200
+++ gcc/testsuite/gcc.c-torture/execute/builtins/strlen-3.c	2004-09-14 15:23:44.181478207 +0200
@@ -0,0 +1,68 @@
+/* Copyright (C) 2004  Free Software Foundation.
+
+   Test strlen on const variables initialized to string literals.
+
+   Written by Jakub Jelinek, 9/14/2004.  */
+
+extern void abort (void);
+extern __SIZE_TYPE__ strlen (const char *);
+extern char *strcpy (char *, const char *);
+const char bar[] = "Hello, World!";
+const char baz[] = "hello, world?";
+const char larger[20] = "short string";
+extern volatile int inside_main;
+
+int l1 = 1;
+int x = 6;
+
+void
+main_test(void)
+{
+  const char *foo;
+  int i;
+
+  if (strlen (bar) != 13)
+    abort ();
+
+  if (strlen (bar + 3) != 10)
+    abort ();
+
+  if (strlen (&bar[6]) != 7)
+    abort ();
+
+  if (strlen (bar + (x++ & 7)) != 7)
+    abort ();
+  if (x != 7)
+    abort ();
+
+#ifdef __OPTIMIZE__
+  foo = bar;
+  for (i = 0; i < 4; ++i)
+    {
+      if (i == l1 - 1)
+	foo = "HELLO, WORLD!";
+      else if (i == l1)
+	foo = bar;
+      else if (i == l1 + 1)
+	foo = "hello, world!";
+      else
+	foo = baz;
+    }
+  if (strlen (foo) != 13)
+    abort ();
+#endif
+
+  if (strlen (larger) != 12)
+    abort ();
+  if (strlen (&larger[10]) != 2)
+    abort ();
+
+  inside_main = 0;
+  /* This will result in strlen call, because larger
+     array is bigger than its initializer.  */
+  if (strlen (larger + (x++ & 7)) != 5)
+    abort ();
+  if (x != 8)
+    abort ();
+  inside_main = 1;
+}
--- gcc/testsuite/gcc.c-torture/execute/builtins/strlen-3-lib.c.jj	2004-09-14 11:17:24.316030839 +0200
+++ gcc/testsuite/gcc.c-torture/execute/builtins/strlen-3-lib.c	2004-07-03 04:16:50.000000000 +0200
@@ -0,0 +1 @@
+#include "lib/strlen.c"


	Jakub


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