PR tree-optimization/89688 - -Wstringop-overflow confused by const 2D array of char
authorMartin Sebor <msebor@redhat.com>
Tue, 19 Mar 2019 22:43:10 +0000 (22:43 +0000)
committerMartin Sebor <msebor@gcc.gnu.org>
Tue, 19 Mar 2019 22:43:10 +0000 (16:43 -0600)
gcc/c/ChangeLog:

PR tree-optimization/89688
* c-decl.c (finish_decl): Call braced_lists_to_string for more
kinds of initializers.

gcc/c-family/ChangeLog:

PR tree-optimization/89688
* c-common.c (braced_list_to_string): Make static.
(braced_lists_to_strings): Define new function.
* c-common.h (braced_list_to_string): Remove.
(braced_lists_to_strings): Declare.

gcc/cp/ChangeLog:

PR tree-optimization/89688
* typeck2.c (store_init_value): Call braced_lists_to_string for more
kinds of initializers.

gcc/testsuite/ChangeLog:

PR tree-optimization/89688
* gcc.dg/strlenopt-61.c: New test.
* g++.dg/warn/Wstringop-overflow-2.C: New test.

From-SVN: r269814

gcc/c-family/ChangeLog
gcc/c-family/c-common.c
gcc/c-family/c-common.h
gcc/c/ChangeLog
gcc/c/c-decl.c
gcc/cp/ChangeLog
gcc/cp/typeck2.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/warn/Wstringop-overflow-2.C [new file with mode: 0644]
gcc/testsuite/gcc.dg/strlenopt-61.c [new file with mode: 0644]

index 910cee859419f8daade879a51507428e5af0682d..df61b693205ee0e12275ec322b4837b21d4e7bbf 100644 (file)
@@ -1,3 +1,11 @@
+2019-03-19  Martin Sebor  <msebor@redhat.com>
+
+       PR tree-optimization/89688
+       * c-common.c (braced_list_to_string): Make static.
+       (braced_lists_to_strings): Define new function.
+       * c-common.h (braced_list_to_string): Remove.
+       (braced_lists_to_strings): Declare.
+
 2019-03-12  Martin Liska  <mliska@suse.cz>
 
        * c-opts.c (c_common_handle_option): Wrap option with %< and %>.
index 019f108292272fc026101cbd31632606a8fd6428..0e17fef881853fd56e7aeebe841832e5da110179 100644 (file)
@@ -8814,7 +8814,7 @@ maybe_add_include_fixit (rich_location *richloc, const char *header,
    TYPE into a STRING_CST for convenience and efficiency.  Return
    the converted string on success or the original ctor on failure.  */
 
-tree
+static tree
 braced_list_to_string (tree type, tree ctor)
 {
   if (!tree_fits_uhwi_p (TYPE_SIZE_UNIT (type)))
@@ -8895,4 +8895,52 @@ braced_list_to_string (tree type, tree ctor)
   return res;
 }
 
+/* Attempt to convert a CTOR containing braced array initializer lists
+   for array TYPE into one containing STRING_CSTs, for convenience and
+   efficiency.  Recurse for arrays of arrays and member initializers.
+   Return the converted CTOR or STRING_CST on success or the original
+   CTOR otherwise.  */
+
+tree
+braced_lists_to_strings (tree type, tree ctor)
+{
+  if (TREE_CODE (ctor) != CONSTRUCTOR)
+    return ctor;
+
+  tree_code code = TREE_CODE (type);
+
+  tree ttp;
+  if (code == ARRAY_TYPE)
+    ttp = TREE_TYPE (type);
+  else if (code == RECORD_TYPE)
+    {
+      ttp = TREE_TYPE (ctor);
+      if (TREE_CODE (ttp) == ARRAY_TYPE)
+       {
+         type = ttp;
+         ttp = TREE_TYPE (ttp);
+       }
+    }
+  else
+    return ctor;
+
+  if (TYPE_STRING_FLAG (ttp))
+    return braced_list_to_string (type, ctor);
+
+  code = TREE_CODE (ttp);
+  if (code == ARRAY_TYPE || code == RECORD_TYPE)
+    {
+      /* Handle array of arrays or struct member initializers.  */
+      tree val;
+      unsigned HOST_WIDE_INT idx;
+      FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (ctor), idx, val)
+       {
+         val = braced_lists_to_strings (ttp, val);
+         CONSTRUCTOR_ELT (ctor, idx)->value = val;
+       }
+    }
+
+  return ctor;
+}
+
 #include "gt-c-family-c-common.h"
index 394a0ea1c895959df42979f783d6dc3e8c675351..104c74226def1b692074a5791d821ed81e9dfd6c 100644 (file)
@@ -1372,7 +1372,8 @@ extern void maybe_add_include_fixit (rich_location *, const char *, bool);
 extern void maybe_suggest_missing_token_insertion (rich_location *richloc,
                                                   enum cpp_ttype token_type,
                                                   location_t prev_token_loc);
-extern tree braced_list_to_string (tree, tree);
+extern tree braced_lists_to_strings (tree, tree);
+
 extern bool has_attribute (location_t, tree, tree, tree (*)(tree));
 
 #if CHECKING_P
index fd3d009f13ed206588ffc299b35d63307aa1b32a..fc8049e832e74fc49e0a5f7d9e96de577ed0cac5 100644 (file)
@@ -1,3 +1,9 @@
+2019-03-19  Martin Sebor  <msebor@redhat.com>
+
+       PR tree-optimization/89688
+       * c-decl.c (finish_decl): Call braced_lists_to_string for more
+       kinds of initializers.
+
 2019-03-19  Jakub Jelinek  <jakub@redhat.com>
 
        PR c/89734
index e8b7ca4ae5b9ec834d1b474399df13a1258eb378..8d5c35ab4751154f40ec0fca97117d6d6d328d5a 100644 (file)
@@ -5165,11 +5165,10 @@ finish_decl (tree decl, location_t init_loc, tree init,
       relayout_decl (decl);
     }
 
-  if (TREE_CODE (type) == ARRAY_TYPE
-      && TYPE_STRING_FLAG (TREE_TYPE (type))
-      && DECL_INITIAL (decl)
-      && TREE_CODE (DECL_INITIAL (decl)) == CONSTRUCTOR)
-    DECL_INITIAL (decl) = braced_list_to_string (type, DECL_INITIAL (decl));
+  /* Look for braced array initializers for character arrays and
+     recursively convert them into STRING_CSTs.  */
+  if (tree init = DECL_INITIAL (decl))
+    DECL_INITIAL (decl) = braced_lists_to_strings (type, init);
 
   if (VAR_P (decl))
     {
index 76bc8ffaa6852bbe9992551c894b3551cf0c5728..2157496745e5d33d568bd6b8a7f1c924a974fbb6 100644 (file)
@@ -1,3 +1,9 @@
+2019-03-19  Martin Sebor  <msebor@redhat.com>
+
+       PR tree-optimization/89688
+       * typeck2.c (store_init_value): Call braced_lists_to_string for more
+       kinds of initializers.
+
 2019-03-18  Jason Merrill  <jason@redhat.com>
 
        PR c++/89630 - ICE with dependent using-decl as template arg.
index 456c4fcb74847bfd43f6bf8fb5a546213b7eb6b9..e50d6ed83c3795a3f316e97a409dc0735f240106 100644 (file)
@@ -824,10 +824,9 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
       value = digest_init_flags (type, init, flags, tf_warning_or_error);
     }
 
-  if (TREE_CODE (type) == ARRAY_TYPE
-      && TYPE_STRING_FLAG (TREE_TYPE (type))
-      && TREE_CODE (value) == CONSTRUCTOR)
-    value = braced_list_to_string (type, value);
+  /* Look for braced array initializers for character arrays and
+     recursively convert them into STRING_CSTs.  */
+  value = braced_lists_to_strings (type, value);
 
   current_ref_temp_count = 0;
   value = extend_ref_init_temps (decl, value, cleanups);
index 7ad6ccc1e4a0758aece2a0d8f276f36e536d40b0..e60ec93ced399011cf4aeddb311ebfe728a535cb 100644 (file)
@@ -1,3 +1,9 @@
+2019-03-19  Martin Sebor  <msebor@redhat.com>
+
+       PR tree-optimization/89688
+       * gcc.dg/strlenopt-61.c: New test.
+       * g++.dg/warn/Wstringop-overflow-2.C: New test.
+
 2019-03-19  Jim Wilson  <jimw@sifive.com>
 
        PR target/89411
diff --git a/gcc/testsuite/g++.dg/warn/Wstringop-overflow-2.C b/gcc/testsuite/g++.dg/warn/Wstringop-overflow-2.C
new file mode 100644 (file)
index 0000000..425ba83
--- /dev/null
@@ -0,0 +1,29 @@
+/* PR tree-optimization/89688 - -Wstringop-overflow confused by const 2D
+   array of char
+   { dg-do compile }
+   { dg-options "-Wall -fdump-tree-gimple -fdump-tree-optimized" } */
+
+extern "C" __SIZE_TYPE__ strlen (const char*);
+
+const char a2[2] = { '1' };
+
+void a2_len ()
+{
+  if (strlen (a2) != 1)
+    __builtin_abort ();
+}
+
+const char a2_2[2][3] = { { '1' }, { '1', '2' } };
+
+void a2_2_len ()
+{
+  if  (strlen (a2_2[0]) != 1)   // { dg-bogus "-Wstringop-overflow" }
+    __builtin_abort ();
+
+  if  (strlen (a2_2[1]) != 2)   // { dg-bogus "-Wstringop-overflow" }
+    __builtin_abort ();
+}
+
+
+/* { dg-final { scan-tree-dump-not "abort" "optimized" } }
+   { dg-final { scan-tree-dump-not "strlen" "gimple" } } */
diff --git a/gcc/testsuite/gcc.dg/strlenopt-61.c b/gcc/testsuite/gcc.dg/strlenopt-61.c
new file mode 100644 (file)
index 0000000..4f8e9c0
--- /dev/null
@@ -0,0 +1,218 @@
+/* PR tree-optimization/89688 - -Wstringop-overflow confused by const
+   2D array of char
+   { dg-do compile }
+   { dg-options "-Wall -fdump-tree-gimple -fdump-tree-optimized" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+size_t strlen (const char*);
+#define CAT(x, y) x ## y
+#define CONCAT(x, y) CAT (x, y)
+#define FAILNAME(name) CONCAT (call_ ## name ##_on_line_, __LINE__)
+
+#define FAIL(name) do {                         \
+    extern __attribute__ ((noreturn)) void FAILNAME (name) (void);     \
+    FAILNAME (name)();                          \
+  } while (0)
+
+#define A(ref, len)                                    \
+  if (strlen (ref) != len) FAIL (failure); else (void)0
+
+const char a3_4[3][4] = { { 1 }, { 1, 2 }, { 1, 2, 3 } };
+
+void test_a4_4 (void)
+{
+  A (a3_4[0], 1);
+  A (a3_4[1], 2);
+  A (a3_4[2], 3);
+
+  A (&a3_4[0][0], 1);
+  A (&a3_4[0][1], 0);
+  A (&a3_4[0][2], 0);
+  A (&a3_4[0][3], 0);
+
+  A (&a3_4[1][0], 2);
+  A (&a3_4[1][1], 1);
+  A (&a3_4[1][2], 0);
+  A (&a3_4[1][3], 0);
+
+  A (&a3_4[2][0], 3);
+  A (&a3_4[2][1], 2);
+  A (&a3_4[2][2], 1);
+  A (&a3_4[2][3], 0);
+}
+
+
+const char a3_4_5[3][4][5] =
+  {
+   { { 1 }, { 1, 2 }, { 1, 2, 3 }, { 1, 2, 3, 4 } },
+   { { 1, 2 }, { 1, 2, 3 }, { 1, 2, 3, 4 }, { 1 } },
+   { { 1, 2, 3 }, { 1, 2, 3, 4 }, { 1 }, { 1, 2 } },
+  };
+
+void test_a3_4_5 (void)
+{
+  A (a3_4_5[0][0], 1);
+  A (a3_4_5[0][1], 2);
+  A (a3_4_5[0][2], 3);
+  A (a3_4_5[0][3], 4);
+
+  A (a3_4_5[1][0], 2);
+  A (a3_4_5[1][1], 3);
+  A (a3_4_5[1][2], 4);
+  A (a3_4_5[1][3], 1);
+
+  A (a3_4_5[2][0], 3);
+  A (a3_4_5[2][1], 4);
+  A (a3_4_5[2][2], 1);
+  A (a3_4_5[2][3], 2);
+}
+
+
+struct S
+{
+  char a3[3];
+  char a4_5[4][5];
+};
+
+const struct S sa4[4] =
+  {
+   { .a3 = { 0 },
+     .a4_5 =
+     {
+      { 1 }, { 1, 2 }, { 1, 2, 3 }, { 1, 2, 3, 4 }
+     }
+   },
+   { .a3 = { 1 },
+     .a4_5 =
+     {
+      { 1, 2 }, { 1, 2, 3 }, { 1, 2, 3, 4 }, { 1 }
+     }
+   },
+   { .a3 = { 1, 2 },
+     .a4_5 =
+     {
+      { 1, 2, 3 }, { 1, 2, 3, 4 }, { 1 }, { 1, 2 }
+     }
+   },
+   { .a3 = { 1 },
+     .a4_5 =
+     {
+      { 1, 2, 3, 4 }, "1", { 1, 2 }, "123"
+     }
+   }
+  };
+
+void test_sa4 (void)
+{
+  A (sa4[0].a3, 0);
+  A (sa4[0].a4_5[0], 1);
+  A (sa4[0].a4_5[1], 2);
+  A (sa4[0].a4_5[2], 3);
+  A (sa4[0].a4_5[3], 4);
+
+  A (sa4[1].a3, 1);
+  A (sa4[1].a4_5[0], 2);
+  A (sa4[1].a4_5[1], 3);
+  A (sa4[1].a4_5[2], 4);
+  A (sa4[1].a4_5[3], 1);
+
+  A (sa4[2].a3, 2);
+  A (sa4[2].a4_5[0], 3);
+  A (sa4[2].a4_5[1], 4);
+  A (sa4[2].a4_5[2], 1);
+  A (sa4[2].a4_5[3], 2);
+
+  A (sa4[3].a3, 1);
+  A (sa4[3].a4_5[0], 4);
+  A (sa4[3].a4_5[1], 1);
+  A (sa4[3].a4_5[2], 2);
+  A (sa4[3].a4_5[3], 3);
+}
+
+
+struct T
+{
+  struct S sa2[2];
+  char a4[4];
+};
+
+const struct T ta2[2] =
+  {
+   [0] =
+   {
+    .sa2 =
+    {
+     [0] =
+     { .a3 = { 0 },
+       .a4_5 =
+       {
+       { 1 }, { 1, 2 }, { 1, 2, 3 }, { 1, 2, 3, 4 }
+       }
+     },
+     [1] =
+     { .a3 = { 1 },
+       .a4_5 =
+       {
+       { 1, 2 }, { 1, 2, 3 }, { 1, 2, 3, 4 }, { 1 }
+       }
+     },
+    },
+    .a4 = "12"
+   },
+
+   [1] =
+   {
+    .sa2 =
+    {
+     [0] =
+     { .a3 = { 1, 2 },
+       .a4_5 =
+       {
+       { 1, 2, 3 }, { 1, 2, 3, 4 }, { 1 }, { 1, 2 }
+       }
+     },
+     { .a3 = { 1 },
+       .a4_5 =
+       {
+       { 1, 2, 3, 4 }, "1", { 1, 2 }, "123"
+       }
+     }
+    },
+    .a4 = "123"
+   }
+  };
+
+void test_ta2 (void)
+{
+  A (ta2[0].sa2[0].a3, 0);
+  A (ta2[0].sa2[0].a4_5[0], 1);
+  A (ta2[0].sa2[0].a4_5[1], 2);
+  A (ta2[0].sa2[0].a4_5[2], 3);
+  A (ta2[0].sa2[0].a4_5[3], 4);
+
+  A (ta2[0].sa2[1].a3, 1);
+  A (ta2[0].sa2[1].a4_5[0], 2);
+  A (ta2[0].sa2[1].a4_5[1], 3);
+  A (ta2[0].sa2[1].a4_5[2], 4);
+  A (ta2[0].sa2[1].a4_5[3], 1);
+
+  A (ta2[0].a4, 2);
+
+  A (ta2[1].sa2[0].a3, 2);
+  A (ta2[1].sa2[0].a4_5[0], 3);
+  A (ta2[1].sa2[0].a4_5[1], 4);
+  A (ta2[1].sa2[0].a4_5[2], 1);
+  A (ta2[1].sa2[0].a4_5[3], 2);
+
+  A (ta2[1].sa2[1].a3, 1);
+  A (ta2[1].sa2[1].a4_5[0], 4);
+  A (ta2[1].sa2[1].a4_5[1], 1);
+  A (ta2[1].sa2[1].a4_5[2], 2);
+  A (ta2[1].sa2[1].a4_5[3], 3);
+
+  A (ta2[1].a4, 3);
+}
+
+/* { dg-final { scan-tree-dump-not "failure" "optimized" } }
+   { dg-final { scan-tree-dump-not "strlen" "gimple" } } */