Bug 101854

Summary: [11 Regression] Invalid warning -Wstringop-overflow wrong argument
Product: gcc Reporter: nightstrike <nightstrike>
Component: tree-optimizationAssignee: Martin Sebor <msebor>
Status: ASSIGNED ---    
Severity: normal CC: msebor
Priority: P3 Keywords: diagnostic
Version: 11.2.0   
Target Milestone: 11.4   
See Also: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103770
Host: Target:
Build: Known to work:
Known to fail: 11.2.0 Last reconfirmed: 2021-08-12 00:00:00
Bug Depends on:    
Bug Blocks: 88443    

Description nightstrike 2021-08-10 23:39:52 UTC
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)
Comment 1 Andrew Pinski 2021-08-10 23:44:22 UTC
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);
}
Comment 2 nightstrike 2021-08-10 23:45:00 UTC
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.
Comment 3 Andrew Pinski 2021-08-10 23:48:25 UTC
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);
}
Comment 4 nightstrike 2021-08-10 23:50:02 UTC
(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.
Comment 5 Andrew Pinski 2021-08-10 23:51:53 UTC
__attribute__((access ("^0[2]^1[6]", )))
struct Weird g (const float * Q, const float[8] * null)

  ss = g (&q, 0B); [return slot optimization]
Comment 6 Andrew Pinski 2021-08-10 23:58:15 UTC
(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.
Comment 7 Martin Sebor 2021-08-12 22:30:05 UTC
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]);
      |          ^
Comment 8 CVS Commits 2021-08-17 20:51:36 UTC
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.
Comment 9 Martin Sebor 2021-08-17 20:53:20 UTC
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);
            }
        }
Comment 10 Richard Biener 2022-04-21 07:50:08 UTC
GCC 11.3 is being released, retargeting bugs to GCC 11.4.