Bug 94881 - [10/11 Regression] incorrect Wstringop-overflow warning with thread sanitizer since r10-5451-gef29b12cfbb4979a
Summary: [10/11 Regression] incorrect Wstringop-overflow warning with thread sanitizer...
Status: RESOLVED DUPLICATE of bug 94655
Alias: None
Product: gcc
Classification: Unclassified
Component: sanitizer (show other bugs)
Version: 10.0
: P3 normal
Target Milestone: 10.0
Assignee: Not yet assigned to anyone
URL:
Keywords: diagnostic
Depends on:
Blocks: Wstringop-overflow
  Show dependency treegraph
 
Reported: 2020-04-30 12:34 UTC by Arnd Bergmann
Modified: 2020-04-30 16:14 UTC (History)
6 users (show)

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


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Arnd Bergmann 2020-04-30 12:34:29 UTC
A gcc-10 snapshot from earlier this month (dated 2020-04-13) produced a -Wstringop-overflow warning that made no sense when building the Linux kernel.
I reduced it to a small test case

https://godbolt.org/z/NyjxvH

struct a {
  char b[50];
};
struct c {
  short action;
  struct a d;
};
struct f {
  short command;
  struct c e;
};
void i(struct f *f, int *g, unsigned h) {
  struct c *j = &f->e;
  j->action = 0;
  __builtin_memcpy(&j->d.b[h], g, 16);
}

$ x86_64-linux-gcc -O2 -Wall -fsanitize=thread test.c -c
test.c:In function 'i':
test.c:15:3: warning: writing 16 bytes into a region of size 0 [-Wstringop-overflow=]
   15 |   __builtin_memcpy(&j->d.b[h], g, 16);
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.c:5:9: note: at offset 0 to object 'action' with size 2 declared here
    5 |   short action;
      |         ^~~~~~
Comment 1 Martin Liška 2020-04-30 12:38:33 UTC
Confirmed, started with r10-5451-gef29b12cfbb4979a.
Comment 2 Arnd Bergmann 2020-04-30 15:09:18 UTC
I ran into another file that triggered this problem, reducing that one gave me a slightly simpler test case:

struct a {
  char b[8];
};
struct e {
  unsigned c;
  struct a d[2];
};
void i(struct e *e, void *g) {
  struct e *f = e + 1;
  __builtin_memcpy(f->d[f->c].b, g, 1);
}
Comment 3 Martin Sebor 2020-04-30 16:14:39 UTC
The warning is issued based on the last MEM_REF in the IL below which stores 16 bytes to the address _1.  The address is computed by adding (h + 2) to _12, the address of the action member on type int.  The middle-end treats the address of a member plus its size as interchangeable for the address of the next member, while the warning relies on the two being distinct (it's invalid to access a member using a pointer to another).  If, instead of using &MEM[(struct c *)f_2(D) + 2B].action, it used the equivalent but strictly (according to C/C++ rules) valid &MEM[(short *)f_2(D) + 2B], i.e., the address of the enclosing struct, this wouldn't be a problem because all stores at that address are valid up to the size of the struct and the warning interprets that as the store to the member that begins at that offset.  Of course, referencing the member to which the store applies would be ideal.

A similar false positive with the same root cause was reported in pr94655 so resolving as a dupe.

  <bb 2> [local count: 1073741824]:
  _12 = &MEM[(struct c *)f_2(D) + 2B].action;   <<< address of f->c.e.action
  .ASAN_CHECK (7, _12, 2, 2);
  MEM[(struct c *)f_2(D) + 2B].action = 0;
  _9 = (sizetype) h_5(D);
  _10 = _9 + 2;
  _1 = _12 + _10;
  .ASAN_CHECK (4, g_6(D), 16, 1);
  _7 = MEM <__int128 unsigned> [(char * {ref-all})g_6(D)];
  .ASAN_CHECK (5, _1, 16, 1);
  MEM <__int128 unsigned> [(char * {ref-all})_1] = _7;   <<< store at f->c.e.action + h that's bigger than size of action

Incidentally, replacing the '__builtin_memcpy(&j->d.b[h], g, 16)' call with the equivalent '__builtin_memcpy(j->d.b + h, g, 16)' avoids the waning because the IL emitted in that case corresponds to valid code (as far as the warning is concerned); see below.  It also implies that these differences in the IL are incidental rather than a deliberate feature and could with some effort be avoided.

  <bb 2> [local count: 1073741824]:
  _11 = &MEM[(struct c *)f_4(D) + 2B].action;
  .ASAN_CHECK (7, _11, 2, 2);
  MEM[(struct c *)f_4(D) + 2B].action = 0;
  _1 = &MEM[(struct c *)f_4(D) + 2B].d.b;   <<< address of f->c.d.b
  _2 = (sizetype) h_7(D);
  _3 = _1 + _2;
  .ASAN_CHECK (4, g_8(D), 16, 1);
  _9 = MEM <__int128 unsigned> [(char * {ref-all})g_8(D)];
  .ASAN_CHECK (5, _3, 16, 1);
  MEM <__int128 unsigned> [(char * {ref-all})_3] = _9;   <<< in-bounds store at f->c.d.b + h

*** This bug has been marked as a duplicate of bug 94655 ***