Bug 92380 - Bogus -Warray-bounds warning with structures, one of which has a flexible array member
Summary: Bogus -Warray-bounds warning with structures, one of which has a flexible arr...
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: middle-end (show other bugs)
Version: 10.0
: P3 minor
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: diagnostic
Depends on:
Blocks: Warray-bounds flexmembers
  Show dependency treegraph
 
Reported: 2019-11-05 15:34 UTC by Franz Sirl
Modified: 2020-01-30 15:25 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2020-01-30 00:00:00


Attachments
testcase (235 bytes, text/plain)
2019-11-05 15:34 UTC, Franz Sirl
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Franz Sirl 2019-11-05 15:34:17 UTC
Created attachment 47176 [details]
testcase

This code:

typedef struct {
        char cs[256];
} inner_small_struct;

typedef struct {
        char cl[512];
} inner_large_struct;

typedef union {
        inner_large_struct large;
        inner_small_struct small;
} inner_union;

typedef struct {
        int y;
        inner_union inner;
} outer_struct;

typedef struct  {
        int x;
        char s[];
} flexarr_struct;

char *t1(outer_struct *p, char str[240])
{
        flexarr_struct *l = (flexarr_struct *) ((char *) p + sizeof(*p) - (sizeof(inner_large_struct) - sizeof(inner_small_struct)));
        __builtin_strcpy(l->s, str);
        return l->s;
}

warns with trunk@277817 like that:

> gcc-trunk -c -O2 -W -Wall -Warray-bounds=1 testcase.c
testcase.c: In function 't1':
testcase.c:28:2: warning: '__builtin_strcpy' offset 264 from the object at 'p' is out of the bounds of referenced subobject 's' with type 'char[0]' at offset 264 [\-Warray-bounds=\]
   28 |  __builtin_strcpy(l->s, str);
      |  ^~~~~~~~~~~~~~~~~~~~~~~~~~~
testcase.c:22:7: note: subobject 's' declared here
   22 |  char s[];
      |       ^

Since gcc already knows about 'p' and the offset, it should also consider sizeof(*p) when deciding to warn. Otherwise it's unfortunate that a flexible array (compared to a size 1 array s[1]) suppresses UBSAN warnings, but -Warray-bounds now warns.
Comment 1 Martin Sebor 2019-11-05 19:15:43 UTC
The warning was introduced in r275981 which was an enhancement to detect more instances of inadvertent accesses past the end of struct members.  It might be possible to relax the warning to handle some of these cases but I'm not convinced it's a good idea or worth the trouble for code that does these sorts of type-punning tricks.

I suggest to rewrite the code in a more straightforward way and without the casts, e.g., like so:

  char *t1 (outer_struct *p, char str[240])
  {
    char *q = (char*)p + sizeof *p - (sizeof(inner_large_struct) - sizeof(inner_small_struct)) + offsetof (flexarr_struct, s);
    __builtin_strcpy (q, str);
    return q;
  }

When starting with a pointer to the the enclosing object GCC treats as valid accesses to the whole object if it's known (or to the largest array of such objects when it isn't).  Otherwise, only accesses to the same member are considered valid when using a pointer derived from the address of that member.