Bug 88991

Summary: missing warning on a strcpy and strlen from a zero-length array
Product: gcc Reporter: Martin Sebor <msebor>
Component: middle-endAssignee: Not yet assigned to anyone <unassigned>
Status: NEW ---    
Severity: normal Keywords: diagnostic
Priority: P3    
Version: 8.0   
Target Milestone: ---   
See Also: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88956
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88992
Host: Target:
Build: Known to work:
Known to fail: 8.3.0, 9.2.0 Last reconfirmed: 2019-08-28 00:00:00
Bug Depends on:    
Bug Blocks: 83819, 88443    

Description Martin Sebor 2019-01-22 18:03:41 UTC
GCC diagnoses the undefined behavior in function f() in the test case below but fails to diagnose the same bug in g() or h().

However, the warning issued for f() should be (also) for the call to strlen(s) which is also undefined.  Worse, in g() neither the call to strlen(s) nor memcpy() is diagnosed.

$ cat t.c && gcc -O2 -S -Wall t.c

void f (char *d)
{
  __builtin_memcpy (d, s, __builtin_strlen (s) + 1);
}

void g (char *d)
{
  unsigned n = __builtin_strlen (s) + 1;   // missing warning
  __builtin_memcpy (d, s, n);              // same here
}

void h (char *d)
{
  __builtin_strcpy (d, s);                 // missing warning here too
}
t.c: In function ‘f’:
t.c:5:3: warning: ‘__builtin_memcpy’ forming offset [1, 9223372036854775805] is out of the bounds [0, 0] of object ‘s’ with type ‘const char[]’ [-Warray-bounds]
    5 |   __builtin_memcpy (d, s, __builtin_strlen (s) + 1);
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
t.c:1:12: note: ‘s’ declared here
    1 | const char s[0] = { };
      |            ^
Comment 1 Martin Sebor 2019-01-22 18:04:48 UTC
This was noticed while adding a test case for the fix for bug 88956.
Comment 2 Martin Sebor 2019-01-22 18:28:12 UTC
The most appropriate warning in all these cases is probably -Wstringop-overflow rather than -Warray-bounds, since the former is meant to diagnose both writing and reading past the end of an array by string functions.
Comment 3 Martin Sebor 2019-08-28 22:02:46 UTC
The test case in comment #0 seems to wrong/incomplete and doesn't compile.  Below is a test case that compiles and shows that GCC 9 issues warnings for the first and third function but misses the one in the middle.

$ cat pr88991.c && gcc -O2 -S -Wall pr88991.c
char a[0], *s;

void f (void)
{
  __builtin_memcpy (a, s, __builtin_strlen (s) + 1);   // warning (good)
}

void g (void)
{
  unsigned n = __builtin_strlen (s) + 1;   // missing warning
  __builtin_memcpy (a, s, n);              // same here
}

void h (void)
{
  __builtin_strcpy (a, s);                 // warning (good)
}
pr88991.c: In function ‘f’:
pr88991.c:5:3: warning: ‘__builtin_memcpy’ forming offset [1, 9223372036854775806] is out of the bounds [0, 0] of object ‘a’ with type ‘char[]’ [-Warray-bounds]
    5 |   __builtin_memcpy (a, s, __builtin_strlen (s) + 1);   // warning (good)
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
pr88991.c:1:6: note: ‘a’ declared here
    1 | char a[0], *s;
      |      ^
pr88991.c: In function ‘h’:
pr88991.c:16:3: warning: ‘__builtin_strcpy’ forming offset 1 is out of the bounds [0, 0] of object ‘a’ with type ‘char[]’ [-Warray-bounds]
   16 |   __builtin_strcpy (a, s);                 // warning (good)
      |   ^~~~~~~~~~~~~~~~~~~~~~~
pr88991.c:1:6: note: ‘a’ declared here
    1 | char a[0], *s;
      |      ^


With -Warray-bounds disabled, GCC 9 issues the following:

pr88991.c: In function ‘f’:
pr88991.c:5:3: warning: ‘__builtin_memcpy’ writing between 1 and 9223372036854775806 bytes into a region of size 0 overflows the destination [-Wstringop-overflow=]
    5 |   __builtin_memcpy (a, s, __builtin_strlen (s) + 1);
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
pr88991.c: In function ‘h’:
pr88991.c:16:3: warning: ‘__builtin_strcpy’ writing 1 or more bytes into a region of size 0 overflows the destination [-Wstringop-overflow=]
   16 |   __builtin_strcpy (a, s);
      |   ^~~~~~~~~~~~~~~~~~~~~~~