PR3609

Mark Mitchell mark@codesourcery.com
Thu Aug 9 10:24:00 GMT 2001


Franz --

  Here is a patch that disables the strlen over-optimization.  I've
tested it in the usual ways, but I'd like to have you verify that it
fixes your kernel bug before I check it in.  Would you let me know 
ASAP?

  Thanks,

--
Mark Mitchell                   mark@codesourcery.com
CodeSourcery, LLC               http://www.codesourcery.com

2001-08-09  Mark Mitchell  <mark@codesourcery.com>

	* builtins.c (c_strlen): Do not try to optimize the case where
	we are taking the length of a string formed by adding a
	non-constant value to a string constant.

Index: builtins.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/builtins.c,v
retrieving revision 1.94.2.5
diff -c -p -r1.94.2.5 builtins.c
*** builtins.c	2001/08/04 00:24:13	1.94.2.5
--- builtins.c	2001/08/09 17:18:37
*************** c_strlen (src)
*** 240,265 ****
    max = TREE_STRING_LENGTH (src) - 1;
    ptr = TREE_STRING_POINTER (src);
  
!   if (offset_node && TREE_CODE (offset_node) != INTEGER_CST)
!     {
!       /* If the string has an internal zero byte (e.g., "foo\0bar"), we can't
! 	 compute the offset to the following null if we don't know where to
! 	 start searching for it.  */
!       int i;
! 
!       for (i = 0; i < max; i++)
! 	if (ptr[i] == 0)
! 	  return 0;
  
!       /* We don't know the starting offset, but we do know that the string
! 	 has no internal zero bytes.  We can assume that the offset falls
! 	 within the bounds of the string; otherwise, the programmer deserves
! 	 what he gets.  Subtract the offset from the length of the string,
! 	 and return that.  This would perhaps not be valid if we were dealing
! 	 with named arrays in addition to literal string constants.  */
  
!       return size_diffop (size_int (max), offset_node);
!     }
  
    /* We have a known offset into the string.  Start searching there for
       a null character.  */
--- 240,258 ----
    max = TREE_STRING_LENGTH (src) - 1;
    ptr = TREE_STRING_POINTER (src);
  
!   /* If we don't know what the OFFSET is, we can't figure out the
!      length.  It's tempting to say that it must be the length of the
!      string, less the offset, if there are no embedded NULs in SRC --
!      but that's not safe.  In particular, the OFFSET might point past
!      SRC into another string; consider something like:
  
!        strlen((char*) ((size_t)("abc") + 47));
  
!      This kind of code appears in the Linux kernel.  There's nothing
!      about this that is invalid, although it clearly depends on
!      knowledge of where the compiler will put the string "abc".  */
!   if (offset_node && TREE_CODE (offset_node) != INTEGER_CST)
!     return NULL_TREE;
  
    /* We have a known offset into the string.  Start searching there for
       a null character.  */
Index: testsuite/gcc.c-torture/execute/string-opt-3.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/gcc.c-torture/execute/string-opt-3.c,v
retrieving revision 1.5
diff -c -p -r1.5 string-opt-3.c
*** string-opt-3.c	2000/12/27 15:29:52	1.5
--- string-opt-3.c	2001/08/09 17:18:49
***************
*** 1,4 ****
! /* Copyright (C) 2000  Free Software Foundation.
  
     Ensure all expected transformations of builtin strlen, strcmp,
     strrchr and rindex occur and perform correctly.
--- 1,4 ----
! /* Copyright (C) 2000, 2001  Free Software Foundation.
  
     Ensure all expected transformations of builtin strlen, strcmp,
     strrchr and rindex occur and perform correctly.
*************** int main()
*** 22,29 ****
--- 22,35 ----
      abort ();
    if (strlen (foo + 4) != 7)
      abort ();
+ #ifndef __OPTIMIZE__
+   /* We intentionally do not try to optimize this to a builtin, so we
+      cannot do this test when optimizing.  */
    if (strlen (foo + (x++ & 7)) != 5)
      abort ();
+ #else
+   x++;
+ #endif
    if (x != 7)
      abort ();
    if (strcmp (foo, "hello") <= 0)
Index: testsuite/gcc.c-torture/execute/string-opt-8.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/gcc.c-torture/execute/string-opt-8.c,v
retrieving revision 1.5
diff -c -p -r1.5 string-opt-8.c
*** string-opt-8.c	2001/01/03 16:54:46	1.5
--- string-opt-8.c	2001/08/09 17:18:49
*************** extern void abort (void);
*** 9,14 ****
--- 9,16 ----
  typedef __SIZE_TYPE__ size_t;
  extern int strncmp (const char *, const char *, size_t);
  
+ int ok_to_call_strncmp;
+ 
  int main ()
  {
    const char *const s1 = "hello world";
*************** int main ()
*** 42,47 ****
--- 44,52 ----
    if (strncmp ("aaaaa", "hello", 1) >= 0)
      abort();
  
+   /* From here on, we will call strncmp, but that's what we expect.  */
+   ok_to_call_strncmp = 1;
+ 
    s2 = s1; s3 = s1+4;
    if (strncmp (++s2, ++s3, 0) != 0 || s2 != s1+1 || s3 != s1+5)
      abort();
*************** int main ()
*** 228,239 ****
  }
  
  #ifdef __OPTIMIZE__
! /* When optimizing, all the above cases should be transformed into
     something else.  So any remaining calls to the original function
     should abort.  */
! static char *
  strncmp(const char *s1, const char *s2, size_t n)
  {
!   abort();
  }
  #endif
--- 233,257 ----
  }
  
  #ifdef __OPTIMIZE__
! /* When optimizing, some of the above cases should be transformed into
     something else.  So any remaining calls to the original function
     should abort.  */
! static int
  strncmp(const char *s1, const char *s2, size_t n)
  {
!   size_t i;
! 
!   if (!ok_to_call_strncmp)
!     abort();
! 
!   for (i = 0; i < n; ++i) 
!     {
!       if (s1[i] < s2[i])
! 	return -1;
!       else if (s2[i] < s1[i])
! 	return 1;
!     }
! 
!   return 0;
  }
  #endif



More information about the Gcc-patches mailing list