The enhancement to treat char initializer-lists as STRING_CSTs
committed earlier last year introduced an assumption that array
elements have a non-zero size.  As it turns out, the zero-length
array extension that makes it possible to define even multi-
dimensional zero-length array objects breaks that assumption when
it's passed as an argument to a function like memcpy. The attached
patch removes that assumption.

Tested on x86_64-linux.

Martin

PS In GCC 10, unless there is an important use case that escapes
me, I think GCC should warn for zero-length non-member array
objects, or perhaps even for internal struct members (those followed
by another member).  Not to avoid these sorts of bugs but because
they seem too dangerous to use safely.
PR middle-end/88956 - ICE: Floating point exception on a memcpy from an zero-length constant array

gcc/ChangeLog:

	PR c/88956
	* gimple-fold.c (fold_array_ctor_reference): Avoid zero-length arrays.

gcc/testsuite/ChangeLog:

	PR c/88956
	* gcc.dg/Warray-bounds-39.c: New test.

Index: gcc/gimple-fold.c
===================================================================
--- gcc/gimple-fold.c	(revision 268086)
+++ gcc/gimple-fold.c	(working copy)
@@ -6715,12 +6715,14 @@ fold_array_ctor_reference (tree type, tree ctor,
   elt_size = wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (ctor))));
 
   /* When TYPE is non-null, verify that it specifies a constant-sized
-     accessed not larger than size of array element.  */
-  if (type
-      && (!TYPE_SIZE_UNIT (type)
-	  || TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST
-	  || elt_size < wi::to_offset (TYPE_SIZE_UNIT (type))
-	  || elt_size == 0))
+     accessed not larger than size of array element.  Avoid using zero
+     ELT_SIZE, the result of an empty initializer for a zero-length
+     array.  */
+  if (elt_size == 0
+      || (type
+	  && (!TYPE_SIZE_UNIT (type)
+	      || TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST
+	      || elt_size < wi::to_offset (TYPE_SIZE_UNIT (type)))))
     return NULL_TREE;
 
   /* Compute the array index we look for.  */
Index: gcc/testsuite/gcc.dg/Warray-bounds-39.c
===================================================================
--- gcc/testsuite/gcc.dg/Warray-bounds-39.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/Warray-bounds-39.c	(working copy)
@@ -0,0 +1,115 @@
+/* PR middle-end/88956 - ICE: Floating point exception on a memcpy from
+   an zero-length constant array
+   Verify both that memory and string calls with a zero-length array
+   don't cause an ICE, and also that they emit warnings.
+   { dg-do compile }
+   { dg-options "-O2 -Wall" }  */
+
+typedef __SIZE_TYPE__ size_t;
+
+extern void* memcpy (void*, const void*, size_t);
+extern void* memmove (void*, const void*, size_t);
+extern char* strcpy (char*, const char*);
+extern char* strncpy (char*, const char*, size_t);
+
+const char s0[0] = { };
+const char s0_0[0][0] = { };
+const char s0_1[0][1] = { };
+const char s1_0[1][0] = { };
+
+char d[4];
+
+void* test_memcpy_s0_1 (void *d)
+{
+  return memcpy (d, s0, 1);       /* { dg-warning "\\\[-Warray-bounds" } */
+}
+
+void* test_memcpy_s0_2 (void *d)
+{
+  return memcpy (d, s0, 2);       /* { dg-warning "\\\[-Warray-bounds" } */
+}
+
+void* test_memcpy_s0_0_1 (void *d)
+{
+  return memcpy (d, s0_0, 1);     /* { dg-warning "\\\[-Warray-bounds" } */
+}
+
+void* test_memcpy_s0_0_2 (void *d)
+{
+  return memcpy (d, s0_0, 2);     /* { dg-warning "\\\[-Warray-bounds" } */
+}
+
+
+void* test_memcpy_s0_1_1 (void *d)
+{
+  return memcpy (d, s0_1, 1);     /* { dg-warning "\\\[-Warray-bounds" } */
+}
+
+void* test_memcpy_s0_1_2 (void *d)
+{
+  return memcpy (d, s0_1, 2);     /* { dg-warning "\\\[-Warray-bounds" } */
+}
+
+
+void* test_memcpy_s1_0_1 (void *d)
+{
+  return memcpy (d, s1_0, 1);     /* { dg-warning "\\\[-Warray-bounds" } */
+}
+
+void* test_memcpy_s1_0_2 (void *d)
+{
+  return memcpy (d, s1_0, 2);     /* { dg-warning "\\\[-Warray-bounds" } */
+}
+
+
+void* test_memmove_s0_1 (void *d)
+{
+  return memmove (d, s0, 1);      /* { dg-warning "\\\[-Warray-bounds" } */
+}
+
+void* test_memmove_s0_2 (void *d)
+{
+  return memmove (d, s0, 2);      /* { dg-warning "\\\[-Warray-bounds" } */
+}
+
+void* test_memmove_s0_0_1 (void *d)
+{
+  return memmove (d, s0_0, 1);    /* { dg-warning "\\\[-Warray-bounds" } */
+}
+
+void* test_memmove_s0_0_2 (void *d)
+{
+  return memmove (d, s0_0, 2);    /* { dg-warning "\\\[-Warray-bounds" } */
+}
+
+
+char* test_strcpy_s0 (char *d)
+{
+  return strcpy (d, s0);          /* { dg-warning "\\\[-Warray-bounds" "pr88991" { xfail *-*-* } } */
+}
+
+char* test_strcpy_s0_0 (char *d)
+{
+  return strcpy (d, s0_0[0]);     /* { dg-warning "\\\[-Warray-bounds" "pr88991" { xfail *-*-* } } */
+}
+
+
+char* test_strncpy_s0_1 (char *d)
+{
+  return strncpy (d, s0, 1);    /* { dg-warning "\\\[-Warray-bounds" "pr88991" { xfail *-*-* } } */
+}
+
+char* test_strncpy_s0_2 (char *d)
+{
+  return strncpy (d, s0, 2);    /* { dg-warning "\\\[-Warray-bounds" "pr88991" { xfail *-*-* } } */
+}
+
+char* test_strncpy_s0_0_1 (char *d)
+{
+  return strncpy (d, s0_0[0], 1); /* { dg-warning "\\\[-Warray-bounds" "pr88991" { xfail *-*-* } } */
+}
+
+char* test_strncpy_s0_0_2 (char *d)
+{
+  return strncpy (d, s0_0[0], 2); /* { dg-warning "\\\[-Warray-bounds" "pr88991" { xfail *-*-* } } */
+}

Reply via email to