Bug 97027

Summary: missing warning on buffer overflow storing a larger scalar into a smaller array
Product: gcc Reporter: Martin Sebor <msebor>
Component: middle-endAssignee: Martin Sebor <msebor>
Status: RESOLVED FIXED    
Severity: normal CC: clyon
Priority: P3 Keywords: diagnostic, missed-optimization, patch
Version: 11.0   
Target Milestone: 12.0   
Host: Target:
Build: Known to work:
Known to fail: Last reconfirmed: 2020-10-13 00:00:00
Bug Depends on:    
Bug Blocks: 88443    

Description Martin Sebor 2020-09-11 21:10:42 UTC
None of the obviously out-of-bounds stores in the functions below is diagnosed.  They all should and easily could be.

typedef __INT64_TYPE__ int64_t;
typedef __attribute__ ((__vector_size__ (8))) char V8;
typedef __attribute__ ((__vector_size__ (64))) char V64;

void f0 (int i)
{
  char a[1];
  void *p = a;
  *(int64_t*)p = i;   // storing 8 bytes into a one-byte array
  __builtin_puts (a);
}

void f1 (int i)
{
  char a[1];
  if (i < 1 || 2 < i) i = 1;
  void *p = a + i;
  *(int64_t*)p = i;   // storing 8 bytes at offset 1 into a one-byte array
  __builtin_puts (a);
}

void g0 (int i)
{
  char a[1];
  void *p = a;
  *(V8*)p = (V8){ i };   // storing 8 bytes into a one-byte array
  __builtin_puts (a);
}

void g1 (int i)
{
  char a[1];
  if (i < 1 || 2 < i) i = 1;
  void *p = a + i;
  *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
  __builtin_puts (a);
}
Comment 1 Martin Sebor 2020-10-13 16:53:55 UTC
Whether or not this is diagnosed depends on the form of the IL and that in turn depends on the target.  For example, when configured for aarch64-linux, GCC doesn't issue any warnings for the test case in comment #0.  When configured for x86_64 it issues the following barrage of warnings (for g1 only).

This is behind failures in the gcc.dg/Wstringop-overflow-47.c test reported here: https://gcc.gnu.org/pipermail/gcc-patches/2020-October/556049.html

$ gcc -O2 -S pr97027.c
pr97027.c: In function ‘g1’:
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 1 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 2 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 3 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 4 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 5 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 6 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 7 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 8 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 9 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 10 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 11 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 12 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 13 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 14 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 15 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 16 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 17 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 18 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 19 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 20 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 21 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 22 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 23 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 24 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 25 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 26 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 27 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 28 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 29 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 30 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 31 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 32 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 33 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 34 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 35 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 36 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 37 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 38 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 39 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 40 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 41 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 42 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 43 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 44 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 45 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 46 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 47 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 48 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 49 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 50 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 51 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 52 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 53 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 54 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 55 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 56 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 57 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 58 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 59 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 60 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 61 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 62 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 63 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
pr97027.c:36:12: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   36 |   *(V64*)p = (V64){ i };   // storing 64 bytes at offset 1 into a one-byte array
      |   ~~~~~~~~~^~~~~~~~~~~~
pr97027.c:33:8: note: at offset 64 to object ‘a’ with size 1 declared here
   33 |   char a[1];
      |        ^
Comment 2 Martin Sebor 2020-10-13 16:55:01 UTC
Another test case.  Of the buffer overflow in the four functions in it, only a subset is diagnosed.  The subset depends on the form of the assignment in the IL which in turn changes from target to target.  The output below is for aarch64 which is different for x86_64.

$ cat xx.c && gcc -O2 -S -fdump-tree-optimized=/dev/stdout xx.c
void f16 (char c)
{
  typedef __attribute__ ((__vector_size__ (16))) char C16;

  extern char a16[16];
  void *p = a16 + 1;
  *(C16*)p = (C16){ c };
}

void f32 (char c)
{
  typedef __attribute__ ((__vector_size__ (32))) char C32;

  extern char a32[32];
  void *p = a32 + 1;
  *(C32*)p = (C32){ c };
}

void f64 (char c)
{
  typedef __attribute__ ((__vector_size__ (64))) char C64;

  extern char a64[64];
  void *p = a64 + 1;
  *(C64*)p = (C64){ c };
}

void f128 (char c)
{
  typedef __attribute__ ((__vector_size__ (128))) char C128;

  extern char a128[128];
  void *p = a128 + 1;
  *(C128*)p = (C128){ c };
}


;; Function f16 (f16, funcdef_no=0, decl_uid=3585, cgraph_uid=1, symbol_order=0)

f16 (char c)
{
  vector(16) char _1;

  <bb 2> [local count: 1073741824]:
  _1 = {c_2(D)};
  MEM[(C16 *)&a16 + 1B] = _1;
  return;

}



;; Function f32 (f32, funcdef_no=1, decl_uid=3593, cgraph_uid=2, symbol_order=1)

f32 (char c)
{
  vector(32) char _1;

  <bb 2> [local count: 1073741824]:
  _1 = {c_2(D)};
  MEM[(C32 *)&a32 + 1B] = _1;
  return;

}



;; Function f64 (f64, funcdef_no=2, decl_uid=3601, cgraph_uid=3, symbol_order=2)

f64 (char c)
{
  vector(64) char _1;

  <bb 2> [local count: 1073741824]:
  _1 = {c_2(D)};
  MEM[(C64 *)&a64 + 1B] = _1;
  return;

}


xx.c: In function 'f128':
xx.c:34:13: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
   34 |   *(C128*)p = (C128){ c };
      |   ~~~~~~~~~~^~~~~~~~~~~~~
xx.c:32:15: note: at offset 128 to object 'a128' with size 128 declared here
   32 |   extern char a128[128];
      |               ^~~~

;; Function f128 (f128, funcdef_no=3, decl_uid=3609, cgraph_uid=4, symbol_order=3)

f128 (char c)
{
  <bb 2> [local count: 1073741824]:
  BIT_FIELD_REF <MEM[(C128 *)&a128 + 1B], 8, 0> = c_2(D);
  MEM <unsigned long> [(C128 *)&a128 + 2B] = 0;
  MEM <unsigned long> [(C128 *)&a128 + 10B] = 0;
  MEM <unsigned long> [(C128 *)&a128 + 18B] = 0;
  MEM <unsigned long> [(C128 *)&a128 + 26B] = 0;
  MEM <unsigned long> [(C128 *)&a128 + 34B] = 0;
  MEM <unsigned long> [(C128 *)&a128 + 42B] = 0;
  MEM <unsigned long> [(C128 *)&a128 + 50B] = 0;
  MEM <unsigned long> [(C128 *)&a128 + 58B] = 0;
  MEM <unsigned long> [(C128 *)&a128 + 66B] = 0;
  MEM <unsigned long> [(C128 *)&a128 + 74B] = 0;
  MEM <unsigned long> [(C128 *)&a128 + 82B] = 0;
  MEM <unsigned long> [(C128 *)&a128 + 90B] = 0;
  MEM <unsigned long> [(C128 *)&a128 + 98B] = 0;
  MEM <unsigned long> [(C128 *)&a128 + 106B] = 0;
  MEM <unsigned long> [(C128 *)&a128 + 114B] = 0;
  MEM <unsigned int> [(C128 *)&a128 + 122B] = 0;
  MEM <unsigned short> [(C128 *)&a128 + 126B] = 0;
  BIT_FIELD_REF <MEM[(C128 *)&a128 + 1B], 8, 1016> = 0;
  return;

}
Comment 3 Martin Sebor 2020-10-13 19:07:52 UTC
The following change seems to take care of the problem:

diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c
index ebb17cd852c..f04a1e4297d 100644
--- a/gcc/tree-ssa-strlen.c
+++ b/gcc/tree-ssa-strlen.c
@@ -4678,9 +4678,10 @@ count_nonzero_bytes (tree exp, unsigned HOST_WIDE_INT offset,
       if (gimple_assign_single_p (stmt))
 	{
 	  exp = gimple_assign_rhs1 (stmt);
-	  if (TREE_CODE (exp) != MEM_REF)
+	  if (TREE_CODE (exp) != CONSTRUCTOR
+	      && TREE_CODE (exp) != MEM_REF)
 	    return false;
-	  /* Handle MEM_REF below.  */
+	  /* Handle CONSTRUCTOR and MEM_REF below.  */
 	}
       else if (gimple_code (stmt) == GIMPLE_PHI)
 	{
@@ -4704,6 +4705,23 @@ count_nonzero_bytes (tree exp, unsigned HOST_WIDE_INT offset,
 	}
     }
 
+  if (TREE_CODE (exp) == CONSTRUCTOR)
+    {
+      if (nbytes)
+	return false;
+
+      tree type = TREE_TYPE (exp);
+      tree size = TYPE_SIZE_UNIT (type);
+      if (!size || !tree_fits_uhwi_p (size))
+	return false;
+
+      unsigned HOST_WIDE_INT byte_size = tree_to_uhwi (size);
+      if (byte_size < offset)
+	return false;
+
+      nbytes = byte_size - offset;
+    }
+
   if (TREE_CODE (exp) == MEM_REF)
     {
       if (nbytes)
Comment 4 GCC Commits 2021-07-07 20:14:14 UTC
The master branch has been updated by Martin Sebor <msebor@gcc.gnu.org>:

https://gcc.gnu.org/g:a110855667782dac7b674d3e328b253b3b3c919b

commit r12-2132-ga110855667782dac7b674d3e328b253b3b3c919b
Author: Martin Sebor <msebor@redhat.com>
Date:   Wed Jul 7 14:05:25 2021 -0600

    Correct handling of variable offset minus constant in -Warray-bounds [PR100137]
    
    Resolves:
    PR tree-optimization/100137 - -Warray-bounds false positive on varying offset plus negative
    PR tree-optimization/99121 - ICE in -Warray-bounds on a multidimensional
    PR tree-optimization/97027 - missing warning on buffer overflow storing a larger scalar into a smaller array
    
    gcc/ChangeLog:
    
            PR tree-optimization/100137
            PR tree-optimization/99121
            PR tree-optimization/97027
            * builtins.c (access_ref::access_ref): Also set offmax.
            (access_ref::offset_in_range): Define new function.
            (access_ref::add_offset): Set offmax.
            (access_ref::inform_access): Handle access_none.
            (handle_mem_ref): Clear ostype.
            (compute_objsize_r): Handle ASSERT_EXPR.
            * builtins.h (struct access_ref): Add offmax member.
            * gimple-array-bounds.cc (array_bounds_checker::check_mem_ref): Use
            compute_objsize() and simplify.
    
    gcc/testsuite/ChangeLog:
    
            PR tree-optimization/100137
            PR tree-optimization/99121
            PR tree-optimization/97027
            * c-c++-common/Warray-bounds-3.c: Remove xfail
            * c-c++-common/Warray-bounds-4.c: Add an expected warning.
            * c-c++-common/Warray-bounds-9.c: New test.
            * c-c++-common/Warray-bounds-10.c: New test.
            * g++.dg/asan/asan_test.C: Suppress expected warnings.
            * g++.dg/pr95768.C: Same.
            * g++.dg/warn/Warray-bounds-10.C: Adjust text of expected messages.
            * g++.dg/warn/Warray-bounds-11.C: Same.
            * g++.dg/warn/Warray-bounds-12.C: Same.
            * g++.dg/warn/Warray-bounds-13.C: Same.
            * g++.dg/warn/Warray-bounds-17.C: Same.
            * g++.dg/warn/Warray-bounds-20.C: Same.
            * gcc.dg/Warray-bounds-29.c: Same.
            * gcc.dg/Warray-bounds-30.c: Add xfail.
            * gcc.dg/Warray-bounds-31.c: Adjust text of expected messages.
            * gcc.dg/Warray-bounds-32.c: Same.
            * gcc.dg/Warray-bounds-52.c: Same.
            * gcc.dg/Warray-bounds-53.c: Same.
            * gcc.dg/Warray-bounds-58.c: Remove xfail.
            * gcc.dg/Warray-bounds-63.c: Adjust text of expected messages.
            * gcc.dg/Warray-bounds-66.c: Same.
            * gcc.dg/Warray-bounds-69.c: Same.
            * gcc.dg/Wstringop-overflow-34.c: Same.
            * gcc.dg/Wstringop-overflow-47.c: Same.
            * gcc.dg/Wstringop-overflow-61.c: Same.
            * gcc.dg/Warray-bounds-77.c: New test.
            * gcc.dg/Warray-bounds-78.c: New test.
            * gcc.dg/Warray-bounds-79.c: New test.
Comment 5 Martin Sebor 2021-07-07 20:30:08 UTC
Fixed in GCC 12.0.
Comment 6 Martin Sebor 2021-07-09 17:38:38 UTC
Still not completely fixed.  gcc.dg/Wstringop-overflow-47.c still fails on aarch64 due to the different IL.  The test below (extracted from Wstringop-overflow-47.c) is diagnosed as expected with an x86_64 native GCC but now with an aarch64 cross.

$ cat t.c && /build/aarch64-linux/gcc-master/gcc/xgcc -B /build/aarch64-linux/gcc-master/gcc -O2 -S -fdump-tree-optimized=/dev/stdout t.c
typedef __INT16_TYPE__                         int16_t;
typedef __attribute__ ((__vector_size__ (32))) char C32;

void warn_c32 (char c)
{
  extern char warn_a32[32];   // { dg-message "at offset 32 into destination object 'warn_a32' of size 32" "pr97027" }

  void *p = warn_a32 + 1;
  *(C32*)p = (C32){ c };      // { dg-warning "writing 1 byte into a region of size 0" "pr97027" }
}

;; Function warn_c32 (warn_c32, funcdef_no=0, decl_uid=3908, cgraph_uid=1, symbol_order=0)

void warn_c32 (char c)
{
  vector(32) char _1;

  <bb 2> [local count: 1073741824]:
  _1 = {c_2(D)};
  MEM[(C32 *)&warn_a32 + 1B] = _1;
  return;

}
Comment 7 Martin Sebor 2021-07-09 17:54:36 UTC
Something like the patch in comment 3 to handle the overflow in tree-ssa-strlen.c is still needed.  Otherwise GCC does issue a -Warray-bounds but that's enabled only with -Wall (the test expects buffer overflow to be detected without -Wall).
Comment 8 Martin Sebor 2021-07-13 19:27:44 UTC
Another patch: https://gcc.gnu.org/pipermail/gcc-patches/2021-July/575117.html
Comment 9 Christophe Lyon 2021-07-15 09:22:10 UTC
Note that we still have failures on arm similar to what you mention on aarch64.
FAIL: gcc.dg/Wstringop-overflow-47.c pr97027 (test for warnings, line 34)
FAIL: gcc.dg/Wstringop-overflow-47.c pr97027 (test for warnings, line 37)
FAIL: gcc.dg/Wstringop-overflow-47.c pr97027 (test for warnings, line 42)
Comment 10 GCC Commits 2021-07-15 19:16:32 UTC
The master branch has been updated by Martin Sebor <msebor@gcc.gnu.org>:

https://gcc.gnu.org/g:f0500db3692276f60e0562c17c87a0cb03e34398

commit r12-2338-gf0500db3692276f60e0562c17c87a0cb03e34398
Author: Martin Sebor <msebor@redhat.com>
Date:   Thu Jul 15 13:15:03 2021 -0600

    Detect buffer overflow by aggregate and vector stores [PR97027].
    
    Resolves:
    PR middle-end/97027 - missing warning on buffer overflow storing a larger scalar into a smaller array
    
    gcc/ChangeLog:
    
            PR middle-end/97027
            * tree-ssa-strlen.c (handle_assign): New function.
            (maybe_warn_overflow): Add argument.
            (nonzero_bytes_for_type): New function.
            (count_nonzero_bytes): Handle more tree types.  Call
            nonzero_bytes_for_tye.
            (count_nonzero_bytes): Handle types.
            (handle_store): Handle stores from function calls.
            (strlen_check_and_optimize_call): Move code to handle_assign.  Call
            it for assignments from function calls.
    
    gcc/testsuite/ChangeLog:
    
            PR middle-end/97027
            * gcc.dg/Wstringop-overflow-15.c: Remove an xfail.
            * gcc.dg/Wstringop-overflow-47.c: Adjust xfails.
            * gcc.dg/torture/pr69170.c: Avoid valid warnings.
            * gcc.dg/torture/pr70025.c: Prune out a false positive.
            * gcc.dg/vect/pr97769.c: Initialize a loop control variable.
            * gcc.target/i386/pr92658-avx512bw-trunc.c: Increase buffer size
            to avoid overflow.
            * gcc.target/i386/pr92658-avx512f.c: Same.
            * gcc.dg/Wstringop-overflow-68.c: New test.
            * gcc.dg/Wstringop-overflow-69.c: New test.
            * gcc.dg/Wstringop-overflow-70.c: New test.
            * gcc.dg/Wstringop-overflow-71.c: New test.
            * gcc.dg/strlenopt-95.c: New test.
Comment 11 Martin Sebor 2021-07-15 19:22:23 UTC
With r12-2338 Wstringop-overflow-47.c passes on aarch64, arm, as well as x86_64, so this can now be fully resolved.