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