void f() { struct Weird { float a; // Comment out any member float b; // to silence the warning float c; float d; float e; }; struct Weird g(float const Q[2], float const null[6][8]) { return (struct Weird){0}; } float const q[2]; struct Weird ss = g(q, (void *)0); } $ gcc -c a.c a.c: In function 'f': a.c:14:27: warning: 'g' accessing 192 bytes in a region of size 8 [-Wstringop-overflow=] 14 | struct Weird ss = g(q, (void *)0); | ^~~~~~~~~~~~~~~ a.c:14:27: note: referencing argument 2 of type 'const float (*)[8]' a.c:9:22: note: in a call to function 'g' 9 | struct Weird g(float const Q[2], float const null[6][8]) { | ^ $ gcc -v Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/tmp/bin/../libexec/gcc/x86_64-pc-linux-gnu/11.2.0/lto-wrapper Target: x86_64-pc-linux-gnu Configured with: ../src/gcc-11.2.0/configure --disable-nls --disable-multilib --enable-languages=all --prefix=/tmp Thread model: posix Supported LTO compression algorithms: zlib gcc version 11.2.0 (GCC)
Slightly more reduced: void f() { struct Weird { float a[5]; // decrease to 4 will cause the warning to disappear }; struct Weird g(float const Q[2], float const null[6][8]) { return (struct Weird){0}; } float const q[2]; struct Weird ss = g(q, (void *)0); }
So to clarify, the "192 bytes" is the size of the flagged argument #2. The "size 8" is the size of the first argument. If you change q and Q to be 3 elements, then size is 12, etc.
So this is not related to nested functions at all (just in case people thought it was): struct Weird { float a[5]; // decrease to 4 will cause the warning to disappear }; struct Weird g(float const Q[2], float const null[6][8]) { return (struct Weird){0}; } void f() { float const q[2]={0}; struct Weird ss = g(q, (void *)0); }
(In reply to Andrew Pinski from comment #3) > So this is not related to nested functions at all (just in case people > thought it was): It's also not due to flexible array members, given the change from 5 members to an array. I only mention it because I've submitted a report in the past about a different warning that was affected by that feature of C.
__attribute__((access ("^0[2]^1[6]", ))) struct Weird g (const float * Q, const float[8] * null) ss = g (&q, 0B); [return slot optimization]
(In reply to Andrew Pinski from comment #5) > __attribute__((access ("^0[2]^1[6]", ))) > struct Weird g (const float * Q, const float[8] * null) > > ss = g (&q, 0B); [return slot optimization] In the 4 case we get: ss = g (&q, 0B); So no RSO. So yes the code looks like it is counting wrong somewhere.
Below is a further simplified test case. The code in initialize_argument_information() that computes the sizes of actual arguments to array parameters and issues a warning if the former is less than expected doesn't consider the implicit pointer argument passed to functions that return structs by value. It's off by one for those. $ cat t.c && gcc -S -Wall t.c struct A { int a[5]; }; struct A g (int*, int[6][8]); struct A f (void) { int a[2]; return g (a, 0); } t.c: In function ‘f’: t.c:8:10: warning: ‘g’ accessing 192 bytes in a region of size 8 [-Wstringop-overflow=] 8 | return g (a, 0); | ^~~~~~~~ t.c:8:10: note: referencing argument 2 of type ‘int (*)[8]’ t.c:3:10: note: in a call to function ‘g’ 3 | struct A g (int*, int[6][8]); | ^
The master branch has been updated by Martin Sebor <msebor@gcc.gnu.org>: https://gcc.gnu.org/g:b48d4e6818674898f90d9358378c127511ef0f9f commit r12-2976-gb48d4e6818674898f90d9358378c127511ef0f9f Author: Martin Sebor <msebor@redhat.com> Date: Tue Aug 17 14:49:05 2021 -0600 Move more warning code to gimple-ssa-warn-access etc. Also resolves: PR middle-end/101854 - Invalid warning -Wstringop-overflow wrong argument gcc/ChangeLog: PR middle-end/101854 * builtins.c (expand_builtin_alloca): Move warning code to check_alloca in gimple-ssa-warn-access.cc. * calls.c (alloc_max_size): Move code to check_alloca. (get_size_range): Move to pointer-query.cc. (maybe_warn_alloc_args_overflow): Move to gimple-ssa-warn-access.cc. (get_attr_nonstring_decl): Move to tree.c. (fntype_argno_type): Move to gimple-ssa-warn-access.cc. (append_attrname): Same. (maybe_warn_rdwr_sizes): Same. (initialize_argument_information): Move code to gimple-ssa-warn-access.cc. * calls.h (maybe_warn_alloc_args_overflow): Move to gimple-ssa-warn-access.h. (get_attr_nonstring_decl): Move to tree.h. (maybe_warn_nonstring_arg): Move to gimple-ssa-warn-access.h. (enum size_range_flags): Move to pointer-query.h. (get_size_range): Same. * gimple-ssa-warn-access.cc (has_location): Remove unused overload to avoid Clang -Wunused-function. (get_size_range): Declare static. (maybe_emit_free_warning): Rename... (maybe_check_dealloc_call): ...to this for consistency. (class pass_waccess): Add members. (pass_waccess::~pass_waccess): Defined. (alloc_max_size): Move here from calls.c. (maybe_warn_alloc_args_overflow): Same. (check_alloca): New function. (check_alloc_size_call): New function. (check_strncat): Handle another warning flag. (pass_waccess::check_builtin): Handle alloca. (fntype_argno_type): Move here from calls.c. (append_attrname): Same. (maybe_warn_rdwr_sizes): Same. (pass_waccess::check_call): Define. (check_nonstring_args): New function. (pass_waccess::check): Call new member functions. (pass_waccess::execute): Enable ranger. * gimple-ssa-warn-access.h (get_size_range): Move here from calls.h. (maybe_warn_nonstring_arg): Same. * gimple-ssa-warn-restrict.c: Remove #include. * pointer-query.cc (get_size_range): Move here from calls.c. * pointer-query.h (enum size_range_flags): Same. (get_size_range): Same. * tree.c (get_attr_nonstring_decl): Move here from calls.c. * tree.h (get_attr_nonstring_decl): Move here from calls.h. gcc/testsuite/ChangeLog: * gcc.dg/attr-alloc_size-5.c: Adjust optimization to -O1. * gcc.dg/attr-alloc_size-7.c: Use #pragmas to adjust optimization. * gcc.dg/attr-alloc_size-8.c: Adjust optimization to -O1. PR middle-end/101854 * gcc.dg/Wstringop-overflow-72.c: New test.
Fixed for GCC 12. The patch is far too intrusive to backport but the following should fix the problem in GCC 11: diff --git a/gcc/calls.c b/gcc/calls.c index fcb0d6dec69..f116923c890 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -2295,14 +2295,15 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, operand for later processing. */ if (attr_access *access = rdwr_idx.get (argpos)) { + int idx = i - !!struct_value_addr_value; if (POINTER_TYPE_P (type)) { - access->ptr = args[i].tree_value; + access->ptr = args[idx].tree_value; // A nonnull ACCESS->SIZE contains VLA bounds. */ } else { - access->size = args[i].tree_value; + access->size = args[idx].tree_value; gcc_assert (access->ptr == NULL_TREE); } }
GCC 11.3 is being released, retargeting bugs to GCC 11.4.
(In reply to Martin Sebor from comment #9) > Fixed for GCC 12. The patch is far too intrusive to backport but the > following should fix the problem in GCC 11: Would you mind applying it to 11? Thanks! Also, I think in your diff below, there's "// A nonnull" that should be "/* A nonnull"... / to * > diff --git a/gcc/calls.c b/gcc/calls.c > index fcb0d6dec69..f116923c890 100644 > --- a/gcc/calls.c > +++ b/gcc/calls.c > @@ -2295,14 +2295,15 @@ initialize_argument_information (int num_actuals > ATTRIBUTE_UNUSED, > operand for later processing. */ > if (attr_access *access = rdwr_idx.get (argpos)) > { > + int idx = i - !!struct_value_addr_value; > if (POINTER_TYPE_P (type)) > { > - access->ptr = args[i].tree_value; > + access->ptr = args[idx].tree_value; > // A nonnull ACCESS->SIZE contains VLA bounds. */ > } > else > { > - access->size = args[i].tree_value; > + access->size = args[idx].tree_value; > gcc_assert (access->ptr == NULL_TREE); > } > }
GCC 11.4 is being released, retargeting bugs to GCC 11.5.
Fixed in GCC 12.