https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118232
Bug ID: 118232 Summary: wrong union member size identification in -Os optimization, starting from gcc 11 till current Product: gcc Version: 14.2.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c Assignee: unassigned at gcc dot gnu.org Reporter: bat-sheva.honigstein at intel dot com Target Milestone: --- The code below has a union called REQUEST_RESPONSE that holds request/response - each contain structs of size 6 chars - request holds a 6 char array of address, response holds 2 arrays - 4 chars for handle, 2 reserved. However, when calling a function that receives one of the struct members (the address) as first argument, whereas if it is received as last argument, no warning is issued. this behavior has 2 workarounds - (1) change the function argument order (2) call a function before just with the address. This behavior is confirmed using compiler explorer (https://godbolt.org/) with x86-64 gcc compiler versions 11.1 up to current, including 14.2 and trunk. compilation flags: -Os -Wall -Wextra -Wno-unused-variable warning: <source>: In function 'foo': <source>:60:12: warning: 'bar' accessing 6 bytes in a region of size 4 [-Wstringop-overflow=] 60 | int t = bar(pRequestResponse->Request.EthernetAddress, 0, pRequestResponse->Response.Handle); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ <source>:60:12: note: referencing argument 1 of type 'unsigned char[6]' <source>:60:12: note: referencing argument 3 of type 'unsigned char[4]' <source>:21:5: note: in a call to function 'bar' 21 | int bar ( unsigned char address[6], int bCopyToHost, unsigned char Handle[4]){ | ^~~ ASM generation compiler returned: 0 code: #include <stdio.h> #include <stdlib.h> typedef struct _REQUEST { unsigned char EthernetAddress[6]; } REQUEST; typedef struct _RESPONSE { unsigned char Handle[4]; unsigned char reserverd[2]; }RESPONSE ; typedef union _REQUEST_RESPONSE { REQUEST Request ; RESPONSE Response; }REQUEST_RESPONSE ; __attribute__((noinline)) int bar ( unsigned char address[6], int bCopyToHost, unsigned char Handle[4]){ printf ("m is %uc, h is %p", address[0], Handle); if (bCopyToHost){ return 0; } return 1; } __attribute__((noinline)) int bar2 ( unsigned char Handle[4], int bCopyToHost, unsigned char address[6] ){ printf ("m is %uc, h is %p", address[0], Handle); if (bCopyToHost){ return 0; } return 1; } __attribute__((noinline)) int test(unsigned char address[6]){ printf ("test is %uc", address[0]); return 9; } __attribute__((noinline)) int test2(unsigned char Handle[4] ){ printf ("test is %p", Handle); return 9; } __attribute__((noinline)) int foo(void * pBuffer) { REQUEST_RESPONSE *pRequestResponse = pBuffer; //int status1 =test(pRequestResponse->Request.EthernetAddress); int t = bar(pRequestResponse->Request.EthernetAddress, 0, pRequestResponse->Response.Handle); //int t2 = bar2(pRequestResponse->Response.Handle, 0, pRequestResponse->Request.EthernetAddress); return 0; } workarounds - (1) uncomment line int status1 =test(pRequestResponse->Request.EthernetAddress); (2) instead - comment line calling bar and use the line calling bar2 Merry Xmas and happy new year!