Hi all,

I think the assumption in builtin_memref::set_base_and_offset
(gimple-ssa-warn-restrict.c) is not correct. It seems multiple levels of
indirection may confuse gcc. When it loses the reference to the original
buffer (e.g.the buffer is allocated by one of the parent class but it's
used by a different parent class), the subsequent tree::component_ref_size
will just return NULL_TREE.

In that case, the refsize will remain as 0 incorrectly set by the code
below (set_base_and_offset). The problem is unique for char[1]. For the
char array with more than 1 elements, the size of the domain is always
returned.

In builtin_memref::set_base_and_offset (gimple-ssa-warn-restrict.c)
-
-      if (!integer_zerop (memrefoff))
-       /* A non-zero offset into an array of struct with flexible array
-          members implies that the array is empty because there is no
-          way to initialize such a member when it belongs to an array.
-          This must be some sort of a bug.  */
-       refsize = 0;

I've attached the patch with the test case and I'd suggest removal of the
code block here. It seems to me it's ok for non-zero offset here.

$ g++ -v
Using built-in specs.
COLLECT_GCC=/local/usr/bin/g++
COLLECT_LTO_WRAPPER=/local/usr/libexec/gcc/x86_64-pc-linux-gnu/11.0.0/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: ../configure --prefix=/local/usr --disable-multilib
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 11.0.0 20200505 (experimental) (GCC)

Thanks,
Joey
From f9fecbdf485e3cbc29d4aeab3e31c5217e5f2050 Mon Sep 17 00:00:00 2001
From: Joey Liu <joeyjy...@gmail.com>
Date: Wed, 6 May 2020 17:51:57 -0400
Subject: [PATCH] False-positive -Warray-bounds for char[1] on a non-zero offset in a referenced buffer

---
 gcc/gimple-ssa-warn-restrict.c       |  7 ----
 gcc/testsuite/g++.dg/Warray-bounds.C | 62 ++++++++++++++++++++++++++++
 2 files changed, 62 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/Warray-bounds.C

diff --git a/gcc/gimple-ssa-warn-restrict.c b/gcc/gimple-ssa-warn-restrict.c
index 19d2ec09aa5..65bee84cad2 100644
--- a/gcc/gimple-ssa-warn-restrict.c
+++ b/gcc/gimple-ssa-warn-restrict.c
@@ -519,13 +519,6 @@ builtin_memref::set_base_and_offset (tree expr)
 	  offset_int off = tree_to_shwi (memrefoff);
 	  refoff += off;
       	}
-
-      if (!integer_zerop (memrefoff))
-	/* A non-zero offset into an array of struct with flexible array
-	   members implies that the array is empty because there is no
-	   way to initialize such a member when it belongs to an array.
-	   This must be some sort of a bug.  */
-	refsize = 0;
     }

   if (TREE_CODE (ref) == COMPONENT_REF)
diff --git a/gcc/testsuite/g++.dg/Warray-bounds.C b/gcc/testsuite/g++.dg/Warray-bounds.C
new file mode 100644
index 00000000000..9aaf40c5f64
--- /dev/null
+++ b/gcc/testsuite/g++.dg/Warray-bounds.C
@@ -0,0 +1,62 @@
+/* PR c/??? - false positive in -Warray-bounds
+{ dg-do compile }
+{ dg-options "-O2 -Wall -Werror" } */
+
+#include <string.h>
+
+template <size_t N> struct cstr
+{
+  void strncpy (char *src, size_t n)
+  {
+    ::strncpy (data (), src, n);
+
+    if (n < N)
+      data ()[n] = '\0';
+  }
+
+  char get () { return data ()[0]; }
+
+  char *data () { return m_data; }
+
+  char m_data[N];
+};
+
+struct Msg
+{
+  char dummy;
+  cstr<1> m_field;
+};
+
+struct Storage
+{
+  char *data () { return m_data; }
+
+  char m_data[1024];
+};
+
+struct MsgBase
+{
+  Msg *body () { return m_data; }
+
+  MsgBase (char *data) : m_data (reinterpret_cast<Msg *> (data)) {}
+
+  Msg *m_data;
+};
+
+struct ExtMsg : private Storage, public MsgBase
+{
+  ExtMsg () : MsgBase (Storage::data ()) {}
+};
+
+ExtMsg global_m;
+
+// it should not raise any -Warray-bounds warnings
+char
+test_non_zero_offset_into_memarray (char c)
+{
+  ExtMsg &m = global_m;
+
+  m.body ()->m_field.strncpy (&c, sizeof (char));
+
+  return m.body ()->m_field.get ();
+}
--
2.17.1

Reply via email to