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!