Module Name:    src
Committed By:   christos
Date:           Sun Oct  4 14:44:48 UTC 2020

Modified Files:
        src/external/gpl3/gcc/dist/gcc: builtins.c fold-const.c tree.c tree.h

Log Message:
Apply by hand a patch to fix http://r6.ca/blog/20200929T023701Z.html
aka "the memcmp bug", from a patch for gcc-10 in
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95189
Tested on x86_64 by running a full build, install and running it.
Testing that the problem has been fixed with one of the unit tests provided.


To generate a diff of this commit:
cvs rdiff -u -r1.16 -r1.17 src/external/gpl3/gcc/dist/gcc/builtins.c
cvs rdiff -u -r1.1.1.19 -r1.2 src/external/gpl3/gcc/dist/gcc/fold-const.c
cvs rdiff -u -r1.1.1.14 -r1.2 src/external/gpl3/gcc/dist/gcc/tree.c
cvs rdiff -u -r1.1.1.12 -r1.2 src/external/gpl3/gcc/dist/gcc/tree.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/external/gpl3/gcc/dist/gcc/builtins.c
diff -u src/external/gpl3/gcc/dist/gcc/builtins.c:1.16 src/external/gpl3/gcc/dist/gcc/builtins.c:1.17
--- src/external/gpl3/gcc/dist/gcc/builtins.c:1.16	Sat Sep  5 05:12:23 2020
+++ src/external/gpl3/gcc/dist/gcc/builtins.c	Sun Oct  4 10:44:47 2020
@@ -118,7 +118,7 @@ static rtx expand_builtin_next_arg (void
 static rtx expand_builtin_va_start (tree);
 static rtx expand_builtin_va_end (tree);
 static rtx expand_builtin_va_copy (tree);
-static rtx inline_expand_builtin_string_cmp (tree, rtx);
+static rtx inline_expand_builtin_bytecmp (tree, rtx);
 static rtx expand_builtin_strcmp (tree, rtx);
 static rtx expand_builtin_strncmp (tree, rtx, machine_mode);
 static rtx builtin_memcpy_read_str (void *, HOST_WIDE_INT, scalar_int_mode);
@@ -3199,20 +3199,18 @@ expand_builtin_strnlen (tree exp, rtx ta
 }
 
 /* Callback routine for store_by_pieces.  Read GET_MODE_BITSIZE (MODE)
-   bytes from constant string DATA + OFFSET and return it as target
-   constant.  */
+   bytes from bytes at DATA + OFFSET and return it reinterpreted as
+   a target constant.  */
 
 static rtx
 builtin_memcpy_read_str (void *data, HOST_WIDE_INT offset,
 			 scalar_int_mode mode)
 {
-  const char *str = (const char *) data;
+  /* The REPresentation pointed to by DATA need not be a nul-terminated
+     string but the caller guarantees it's large enough for MODE.  */
+  const char *rep = (const char *) data;
 
-  gcc_assert (offset >= 0
-	      && ((unsigned HOST_WIDE_INT) offset + GET_MODE_SIZE (mode)
-		  <= strlen (str) + 1));
-
-  return c_readstr (str + offset, mode);
+  return c_readstr (rep + offset, mode, /*nul_terminated=*/false);
 }
 
 /* LEN specify length of the block of memcpy/memset operation.
@@ -3829,7 +3827,6 @@ static rtx
 expand_builtin_memory_copy_args (tree dest, tree src, tree len,
 				 rtx target, tree exp, memop_ret retmode)
 {
-  const char *src_str;
   unsigned int src_align = get_pointer_alignment (src);
   unsigned int dest_align = get_pointer_alignment (dest);
   rtx dest_mem, src_mem, dest_addr, len_rtx;
@@ -3859,21 +3856,29 @@ expand_builtin_memory_copy_args (tree de
   len_rtx = expand_normal (len);
   determine_block_size (len, len_rtx, &min_size, &max_size,
 			&probable_max_size);
-  src_str = c_getstr (src);
 
-  /* If SRC is a string constant and block move would be done
-     by pieces, we can avoid loading the string from memory
-     and only stored the computed constants.  */
-  if (src_str
+  /* Try to get the byte representation of the constant SRC points to,
+     with its byte size in NBYTES.  */
+  unsigned HOST_WIDE_INT nbytes;
+  const char *rep = c_getstr (src, &nbytes);
+
+  /* If the function's constant bound LEN_RTX is less than or equal
+     to the byte size of the representation of the constant argument,
+     and if block move would be done by pieces, we can avoid loading
+     the bytes from memory and only store the computed constant.
+     This works in the overlap (memmove) case as well because
+     store_by_pieces just generates a series of stores of constants
+     from the representation returned by c_getstr().  */
+  if (rep
       && CONST_INT_P (len_rtx)
-      && (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1
+      && (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= nbytes
       && can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
-			      CONST_CAST (char *, src_str),
+			      CONST_CAST (char *, rep),
 			      dest_align, false))
     {
       dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx),
 				  builtin_memcpy_read_str,
-				  CONST_CAST (char *, src_str),
+				  CONST_CAST (char *, rep),
 				  dest_align, false, retmode);
       dest_mem = force_operand (XEXP (dest_mem, 0), target);
       dest_mem = convert_memory_address (ptr_mode, dest_mem);
@@ -3889,11 +3894,9 @@ expand_builtin_memory_copy_args (tree de
       && (retmode == RETURN_BEGIN || target == const0_rtx))
     method = BLOCK_OP_TAILCALL;
   if (retmode == RETURN_END && target != const0_rtx)
-    method = BLOCK_OP_NO_LIBCALL_RET;
   dest_addr = emit_block_move_hints (dest_mem, src_mem, len_rtx, method,
 				     expected_align, expected_size,
 				     min_size, max_size, probable_max_size);
-  if (dest_addr == pc_rtx)
     return NULL_RTX;
 
   if (dest_addr == 0)
@@ -4693,7 +4696,7 @@ expand_builtin_memcmp (tree exp, rtx tar
 
   if (!result_eq && fcode != BUILT_IN_BCMP)
     {
-      result = inline_expand_builtin_string_cmp (exp, target);
+      result = inline_expand_builtin_bytecmp (exp, target);
       if (result)
 	return result;
     }
@@ -4721,26 +4724,32 @@ expand_builtin_memcmp (tree exp, rtx tar
 
   by_pieces_constfn constfn = NULL;
 
-  const char *src_str = c_getstr (arg2);
-  if (result_eq && src_str == NULL)
-    {
-      src_str = c_getstr (arg1);
-      if (src_str != NULL)
+  /* Try to get the byte representation of the constant ARG2 (or, only
+     when the function's result is used for equality to zero, ARG1)
+     points to, with its byte size in NBYTES.  */
+  unsigned HOST_WIDE_INT nbytes;
+  const char *rep = c_getstr (arg2, &nbytes);
+  if (result_eq && rep == NULL)
+    {
+      /* For equality to zero the arguments are interchangeable.  */
+      rep = c_getstr (arg1, &nbytes);
+      if (rep != NULL)
 	std::swap (arg1_rtx, arg2_rtx);
     }
 
-  /* If SRC is a string constant and block move would be done
-     by pieces, we can avoid loading the string from memory
-     and only stored the computed constants.  */
-  if (src_str
+  /* If the function's constant bound LEN_RTX is less than or equal
+     to the byte size of the representation of the constant argument,
+     and if block move would be done by pieces, we can avoid loading
+     the bytes from memory and only store the computed constant result.  */
+  if (rep
       && CONST_INT_P (len_rtx)
-      && (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1)
+      && (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= nbytes)
     constfn = builtin_memcpy_read_str;
 
   result = emit_block_cmp_hints (arg1_rtx, arg2_rtx, len_rtx,
 				 TREE_TYPE (len), target,
 				 result_eq, constfn,
-				 CONST_CAST (char *, src_str));
+				 CONST_CAST (char *, rep));
 
   if (result)
     {
@@ -4772,7 +4781,7 @@ expand_builtin_strcmp (tree exp, ATTRIBU
 
   /* Due to the performance benefit, always inline the calls first.  */
   rtx result = NULL_RTX;
-  result = inline_expand_builtin_string_cmp (exp, target);
+  result = inline_expand_builtin_bytecmp (exp, target);
   if (result)
     return result;
 
@@ -4891,7 +4900,7 @@ expand_builtin_strncmp (tree exp, ATTRIB
 
   /* Due to the performance benefit, always inline the calls first.  */
   rtx result = NULL_RTX;
-  result = inline_expand_builtin_string_cmp (exp, target);
+  result = inline_expand_builtin_bytecmp (exp, target);
   if (result)
     return result;
 
@@ -7082,18 +7091,18 @@ inline_string_cmp (rtx target, tree var_
   return result;
 }
 
-/* Inline expansion a call to str(n)cmp, with result going to
-   TARGET if that's convenient.
+/* Inline expansion of a call to str(n)cmp and memcmp, with result going
+   to TARGET if that's convenient.
    If the call is not been inlined, return NULL_RTX.  */
+
 static rtx
-inline_expand_builtin_string_cmp (tree exp, rtx target)
+inline_expand_builtin_bytecmp (tree exp, rtx target)
 {
   tree fndecl = get_callee_fndecl (exp);
   enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
-  unsigned HOST_WIDE_INT length = 0;
   bool is_ncmp = (fcode == BUILT_IN_STRNCMP || fcode == BUILT_IN_MEMCMP);
 
-  /* Do NOT apply this inlining expansion when optimizing for size or 
+  /* Do NOT apply this inlining expansion when optimizing for size or
      optimization level below 2.  */
   if (optimize < 2 || optimize_insn_for_size_p ())
     return NULL_RTX;
@@ -7116,29 +7125,47 @@ inline_expand_builtin_string_cmp (tree e
   unsigned HOST_WIDE_INT len2 = 0;
   unsigned HOST_WIDE_INT len3 = 0;
 
-  const char *src_str1 = c_getstr (arg1, &len1);
-  const char *src_str2 = c_getstr (arg2, &len2);
+  /* Get the object representation of the initializers of ARG1 and ARG2
+     as strings, provided they refer to constant objects, with their byte
+     sizes in LEN1 and LEN2, respectively.  */
+  const char *bytes1 = c_getstr (arg1, &len1);
+  const char *bytes2 = c_getstr (arg2, &len2);
 
-  /* If neither strings is constant string, the call is not qualify.  */
-  if (!src_str1 && !src_str2)
+  /* Fail if neither argument refers to an initialized constant.  */
+  if (!bytes1 && !bytes2)
     return NULL_RTX;
 
-  /* For strncmp, if the length is not a const, not qualify.  */
   if (is_ncmp)
     {
+      /* Fail if the memcmp/strncmp bound is not a constant.  */
       if (!tree_fits_uhwi_p (len3_tree))
 	return NULL_RTX;
-      else
-	len3 = tree_to_uhwi (len3_tree);
-    }
 
-  if (src_str1 != NULL)
-    len1 = strnlen (src_str1, len1) + 1;
+      len3 = tree_to_uhwi (len3_tree);
 
-  if (src_str2 != NULL)
-    len2 = strnlen (src_str2, len2) + 1;
+      if (fcode == BUILT_IN_MEMCMP)
+	{
+	  /* Fail if the memcmp bound is greater than the size of either
+	     of the two constant objects.  */
+	  if ((bytes1 && len1 < len3)
+	      || (bytes2 && len2 < len3))
+	    return NULL_RTX;
+	}
+    }
 
-  int const_str_n = 0;
+  if (fcode != BUILT_IN_MEMCMP)
+    {
+      /* For string functions (i.e., strcmp and strncmp) reduce LEN1
+	 and LEN2 to the length of the nul-terminated string stored
+	 in each.  */
+      if (bytes1 != NULL)
+	len1 = strnlen (bytes1, len1) + 1;
+      if (bytes2 != NULL)
+	len2 = strnlen (bytes2, len2) + 1;
+    }
+
+  /* See inline_string_cmp.  */
+  int const_str_n;
   if (!len1)
     const_str_n = 2;
   else if (!len2)
@@ -7148,15 +7175,16 @@ inline_expand_builtin_string_cmp (tree e
   else
     const_str_n = 2;
 
-  gcc_checking_assert (const_str_n > 0);
-  length = (const_str_n == 1) ? len1 : len2;
-
-  if (is_ncmp && len3 < length)
-    length = len3;
+  /* For strncmp only, compute the new bound as the smallest of
+     the lengths of the two strings (plus 1) and the bound provided
+     to the function.  */
+  unsigned HOST_WIDE_INT bound = (const_str_n == 1) ? len1 : len2;
+  if (is_ncmp && len3 < bound)
+    bound = len3;
 
-  /* If the length of the comparision is larger than the threshold,
+  /* If the bound of the comparison is larger than the threshold,
      do nothing.  */
-  if (length > (unsigned HOST_WIDE_INT)
+  if (bound > (unsigned HOST_WIDE_INT) 
 	       PARAM_VALUE (BUILTIN_STRING_CMP_INLINE_LENGTH))
     return NULL_RTX;
 
@@ -7164,7 +7192,7 @@ inline_expand_builtin_string_cmp (tree e
 
   /* Now, start inline expansion the call.  */
   return inline_string_cmp (target, (const_str_n == 1) ? arg2 : arg1,
-			    (const_str_n == 1) ? src_str1 : src_str2, length,
+			    (const_str_n == 1) ? bytes1 : bytes2, bound,
 			    const_str_n, mode);
 }
 

Index: src/external/gpl3/gcc/dist/gcc/fold-const.c
diff -u src/external/gpl3/gcc/dist/gcc/fold-const.c:1.1.1.19 src/external/gpl3/gcc/dist/gcc/fold-const.c:1.2
--- src/external/gpl3/gcc/dist/gcc/fold-const.c:1.1.1.19	Sat Sep  5 03:52:31 2020
+++ src/external/gpl3/gcc/dist/gcc/fold-const.c	Sun Oct  4 10:44:47 2020
@@ -14617,24 +14617,29 @@ fold_build_pointer_plus_hwi_loc (locatio
 			  ptr, size_int (off));
 }
 
-/* Return a pointer P to a NUL-terminated string representing the sequence
-   of constant characters referred to by SRC (or a subsequence of such
-   characters within it if SRC is a reference to a string plus some
-   constant offset).  If STRLEN is non-null, store the number of bytes
-   in the string constant including the terminating NUL char.  *STRLEN is
-   typically strlen(P) + 1 in the absence of embedded NUL characters.  */
+/* Return a pointer P to a NUL-terminated string containing the sequence
+   of bytes corresponding to the representation of the object referred to
+   by SRC (or a subsequence of such bytes within it if SRC is a reference
+   to an initialized constant array plus some constant offset).
+   If STRSIZE is non-null, store the number of bytes in the constant
+   sequence including the terminating NUL byte.  *STRSIZE is equal to
+   sizeof(A) - OFFSET where A is the array that stores the constant
+   sequence that SRC points to and OFFSET is the byte offset of SRC from
+   the beginning of A.  SRC need not point to a string or even an array
+   of characters but may point to an object of any type.  */
 
 const char *
-c_getstr (tree src, unsigned HOST_WIDE_INT *strlen /* = NULL */)
+c_getstr (tree src, unsigned HOST_WIDE_INT *strsize /* = NULL */)
 {
+  /* The offset into the array A storing the string, and A's byte size.  */
   tree offset_node;
   tree mem_size;
 
-  if (strlen)
-    *strlen = 0;
+  if (strsize)
+    *strsize = 0;
 
   src = string_constant (src, &offset_node, &mem_size, NULL);
-  if (src == 0)
+  if (!src)
     return NULL;
 
   unsigned HOST_WIDE_INT offset = 0;
@@ -14649,34 +14654,44 @@ c_getstr (tree src, unsigned HOST_WIDE_I
   if (!tree_fits_uhwi_p (mem_size))
     return NULL;
 
-  /* STRING_LENGTH is the size of the string literal, including any
-     embedded NULs.  STRING_SIZE is the size of the array the string
-     literal is stored in.  */
-  unsigned HOST_WIDE_INT string_length = TREE_STRING_LENGTH (src);
-  unsigned HOST_WIDE_INT string_size = tree_to_uhwi (mem_size);
+  /* ARRAY_SIZE is the byte size of the array the constant sequence
+     is stored in and equal to sizeof A.  INIT_BYTES is the number
+     of bytes in the constant sequence used to initialize the array,
+     including any embedded NULs as well as the terminating NUL (for
+     strings), but not including any trailing zeros/NULs past
+     the terminating one appended implicitly to a string literal to
+     zero out the remainder of the array it's stored in.  For example,
+     given:
+       const char a[7] = "abc\0d";
+       n = strlen (a + 1);
+     ARRAY_SIZE is 7, INIT_BYTES is 6, and OFFSET is 1.  For a valid
+     (i.e., nul-terminated) string with no embedded nuls, INIT_BYTES
+     is equal to strlen (A) + 1.  */
+  const unsigned HOST_WIDE_INT array_size = tree_to_uhwi (mem_size);
+  unsigned HOST_WIDE_INT init_bytes = TREE_STRING_LENGTH (src);
 
   /* Ideally this would turn into a gcc_checking_assert over time.  */
-  if (string_length > string_size)
-    string_length = string_size;
+  if (init_bytes > array_size)
+    init_bytes = array_size;
 
   const char *string = TREE_STRING_POINTER (src);
 
   /* Ideally this would turn into a gcc_checking_assert over time.  */
-  if (string_length > string_size)
-    string_length = string_size;
+  if (init_bytes > array_size)
+    init_bytes = array_size;
 
-  if (string_length == 0
-      || offset >= string_size)
+  if (init_bytes == 0 || offset >= array_size)
     return NULL;
 
-  if (strlen)
+  if (strsize)
     {
-      /* Compute and store the length of the substring at OFFSET.
-	 All offsets past the initial length refer to null strings.  */
-      if (offset < string_length)
-	*strlen = string_length - offset;
+      /* Compute and store the number of characters from the beginning
+	 of the substring at OFFSET to the end, including the terminating
+	 nul.  Offsets past the initial length refer to null strings.  */
+      if (offset < init_bytes)
+	*strsize = init_bytes - offset;
       else
-	*strlen = 1;
+	*strsize = 1;
     }
   else
     {
@@ -14684,11 +14699,11 @@ c_getstr (tree src, unsigned HOST_WIDE_I
       /* Support only properly NUL-terminated single byte strings.  */
       if (tree_to_uhwi (TYPE_SIZE_UNIT (eltype)) != 1)
 	return NULL;
-      if (string[string_length - 1] != '\0')
+      if (string[init_bytes - 1] != '\0')
 	return NULL;
     }
 
-  return offset < string_length ? string + offset : "";
+  return offset < init_bytes ? string + offset : "";
 }
 
 /* Given a tree T, compute which bits in T may be nonzero.  */

Index: src/external/gpl3/gcc/dist/gcc/tree.c
diff -u src/external/gpl3/gcc/dist/gcc/tree.c:1.1.1.14 src/external/gpl3/gcc/dist/gcc/tree.c:1.2
--- src/external/gpl3/gcc/dist/gcc/tree.c:1.1.1.14	Sat Sep  5 03:52:35 2020
+++ src/external/gpl3/gcc/dist/gcc/tree.c	Sun Oct  4 10:44:47 2020
@@ -2172,29 +2172,29 @@ build_real_from_int_cst (tree type, cons
   return v;
 }
 
-/* Return a newly constructed STRING_CST node whose value is
-   the LEN characters at STR.
+/* Return a newly constructed STRING_CST node whose value is the LEN
+   characters at STR when STR is nonnull, or all zeros otherwise.
    Note that for a C string literal, LEN should include the trailing NUL.
    The TREE_TYPE is not initialized.  */
 
 tree
-build_string (int len, const char *str)
+build_string (unsigned len, const char *str /*= NULL */)
 {
-  tree s;
-  size_t length;
-
   /* Do not waste bytes provided by padding of struct tree_string.  */
-  length = len + offsetof (struct tree_string, str) + 1;
+  unsigned size = len + offsetof (struct tree_string, str) + 1;
 
-  record_node_allocation_statistics (STRING_CST, length);
+  record_node_allocation_statistics (STRING_CST, size);
 
-  s = (tree) ggc_internal_alloc (length);
+  tree s = (tree) ggc_internal_alloc (size);
 
   memset (s, 0, sizeof (struct tree_typed));
   TREE_SET_CODE (s, STRING_CST);
   TREE_CONSTANT (s) = 1;
   TREE_STRING_LENGTH (s) = len;
-  memcpy (s->string.str, str, len);
+  if (str)
+    memcpy (s->string.str, str, len);
+  else
+    memset (s->string.str, 0, len);
   s->string.str[len] = '\0';
 
   return s;

Index: src/external/gpl3/gcc/dist/gcc/tree.h
diff -u src/external/gpl3/gcc/dist/gcc/tree.h:1.1.1.12 src/external/gpl3/gcc/dist/gcc/tree.h:1.2
--- src/external/gpl3/gcc/dist/gcc/tree.h:1.1.1.12	Sat Sep  5 03:52:32 2020
+++ src/external/gpl3/gcc/dist/gcc/tree.h	Sun Oct  4 10:44:47 2020
@@ -4227,7 +4227,7 @@ extern tree build_one_cst (tree);
 extern tree build_minus_one_cst (tree);
 extern tree build_all_ones_cst (tree);
 extern tree build_zero_cst (tree);
-extern tree build_string (int, const char *);
+extern tree build_string (unsigned, const char * = NULL);
 extern tree build_poly_int_cst (tree, const poly_wide_int_ref &);
 extern tree build_tree_list (tree, tree CXX_MEM_STAT_INFO);
 extern tree build_tree_list_vec (const vec<tree, va_gc> * CXX_MEM_STAT_INFO);

Reply via email to