https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81977

            Bug ID: 81977
           Summary: Possible issue with inline memcpy with packed
                    structures
           Product: gcc
           Version: 6.3.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: vvarada at codeaurora dot org
  Target Milestone: ---

g++ -DOUTER  bug.cc -Wall -Wextra -fno-strict-aliasing -fwrapv

The following source yields different results when building with and without
optimizations (-O2). Compiling source did not result in any warnings.

Without: optimizations it prints 0xabcd which is expected
With -O2 optimization it prints 0x1617 

The issue appears to be due to incorrect offsets being computed for the
relevant fields resulting from the inlining of memcpy. 

If you look at the disassembly with -O2 the %edi argument on X64 is set to a
constant 0x1617 (5655 decimal) indicating the bug is at the compiler optimizer
itself.

By changing the size of *uint16_t header_info[2];* one gets different results
with -O2 as it picks different portions of _prefz.z for _pref.x.   

Thanks,
-Vijay

---------------------------------------------------------------


#include <iostream>
#include <cstdint>
#include <cstring>

using namespace std;

void printval(int x) __attribute__((noinline));
void printval(int x)
{
   cout << hex << x << endl;
}

#define PACKED __attribute__((packed, aligned(1)))

typedef struct
{
   uint16_t  x ;
   uint16_t  y ;
   uint64_t  z ;
} PACKED TestMsgType;


struct Payload
{
  uint16_t header_info[2];
  TestMsgType _pref;
  void Pack(uint8_t *buffer)
  {
     memcpy(buffer, &_pref, sizeof(_pref));
  }
  void UnPack(uint8_t *buffer)
  {
     memcpy(&_pref, buffer, sizeof(_pref));
  }
};


struct Msg
{
   Payload _payload;
   void Pack(uint8_t *buffer)
   {
      _payload.Pack(buffer);
   }

   void UnPack(uint8_t *buffer)
   {
      _payload.UnPack(buffer);
   }
};

int main()
{
   uint8_t * buffer = new uint8_t [30];
   Msg msg;
   Msg msg1;
   msg._payload._pref.x             = 0xabcd;
   msg._payload._pref.y             = 0xa;
   msg._payload._pref.z             = 0x0001020304051617;
   msg.Pack(&buffer[0]);
   msg1.UnPack(&buffer[0]);
   printval(msg1._payload._pref.x);
   delete [] buffer;
}

Reply via email to