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!

Reply via email to