The sizeof() a packed structure is returning a result different from the additive size of the individual elements of the structure.
The size of the packed structure should be 16 bytes, but sizeof() is returning 17. This has worked correctly under every version of mingw-gcc up until 4.7.3.
Please see the attached file.
$ i686-pc-mingw32-gcc-4.7.3.exe -v
Using built-in specs.
COLLECT_GCC=i686-pc-mingw32-gcc-4.7.3
COLLECT_LTO_WRAPPER=/usr/lib/gcc/i686-pc-mingw32/4.7.3/lto-wrapper.exe
Target: i686-pc-mingw32
Configured with: /usr/src/packages/mingw-gcc/32/mingw-gcc-4.7.3-1/src/gcc-4.7.3/configure --srcdir=/usr/src/packages/mingw-gcc/32/mingw-gcc-4.7.3-1/src/gcc-4.7.3 --prefix=/usr --exec-prefix=/usr --bindir=/usr/bin --sbindir=/usr/sbin --libexecdir=/usr/lib --datadir=/usr/share --localstatedir=/var --sysconfdir=/etc --datarootdir=/usr/share --docdir=/usr/share/doc/mingw-gcc -C --build=i686-pc-cygwin --host=i686-pc-cygwin --target=i686-pc-mingw32 --without-libiconv-prefix --without-libintl-prefix --with-sysroot=/usr/i686-pc-mingw32/sys-root --with-build-sysroot=/usr/i686-pc-mingw32/sys-root --enable-languages=c,c++,ada,fortran,objc,obj-c++ --disable-sjlj-exceptions --with-dwarf2 --enable-shared --enable-libgomp --disable-win32-registry --enable-libstdcxx-debug --disable-build-poststage1-with-cxx --enable-version-specific-runtime-libs --disable-multilib --enable-decimal-float=bid --disable-werror --enable-lto
Thread model: win32
gcc version 4.7.3 (GCC)
$ i686-pc-mingw32-ld -v
GNU ld (GNU Binutils) 2.23.1
$ uname -a
CYGWIN_NT-6.1-WOW64 itsrealvm 1.7.21(0.267/5/3) 2013-07-15 12:17 i686 Cygwin
GCC 4.7.3 isn't ours. Shouldn't OP be advised to file his bug report with the actual provider of his compiler?
I was testing it with my local builds of 4.8.1 before blowing back to Cygwin. The bug must be in GCC or binutils.
OP (me) would be happy to, but I was under the impression that since it's the mingw version of GCC, that would be this group? Whom would you suggest? Cygwin or GCC?
We do not provide Cygwin with binaries particularly unless one of the other maintainers just do it to be nice. However, this continues in 4.8.1, which is what I've been building natively.
You'll probably need to bring this to the attention of the GCC or perhaps binutils maintainers. I found that -fpack-struct=1 gives 16, any other value gives 17.
This looks like it's a case of gcc bug 52991:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52991
(although, that's assuming this problem here exists since gcc 4.7.0 and not just gcc 4.7.3)
With the example test.c from the opening post, using offsetof() reveals that the
version
field starts at byte offset 2 instead of 1 in the structure, meaning there is a padding byte inserted between thetag
andversion
fields, despite the__attribute__((packed))
. Apparently the struct has no tail padding, but there is padding between fields; this looks exactly like the mentioned gcc bug.A possible work-around is to use
__attribute__((gcc_struct, packed))
instead of just__attribute__((packed))
, or compiling with-mno-ms-bitfields
(perhaps less preferable because it could perhaps affect unrelated structures in system headers), both of which override the implicit (default since gcc 4.7.0)__attribute__((ms_struct))
which seems to be the problem's cause. Doing this removes that padding byte, and gives me the expected sizeof() == 16. (tested with MinGW.org gcc 4.8.1)Grumble. The previous maintainers script used -mms-bitfields in the configure step. I removed that since I didn't think it should be used. I didn't realize that it was the default. I think I like the
__attribute__((gcc_struct, packed))
idea the best since it would give the correct result regardless of the compiler. Maybe a patch to the compiler bits, I assume this default must be in a config/i386 file somewhere; we could modify the default.Looking at this more, the sizeof() operation is correct. The user is expecting something that isn't real. The result of 17 is correct for the ms_struct method of packing which should be the default since it makes a more compatible binary between the GCC and MSVC compiler sets. The options as dkls points out are:
__attribute__((gcc_struct, packed))
for a particular structure to be affected.While you may believe it's "correct", breaking Dog knows how much software because structure packing no longer works like it used to is insane.
While your average desktop application may not care that a packed structure is now a little longer, the number of embedded systems that rely on the behavior to be correct is huge.
Luckily for me, I have a lot of sanity checks in my code base, because the application that I use this compiler for has to talk to other processor architectures like PICs and AVRs. I know that my packed structure should be of 'X' bytes in size, and what the various offsets should be.
But to silently decide to start changing how packed structures work... Nope, I think you're 100% wrong here.
You'll need to change the minds of the GCC upstream maintainers. But you have options to use if you don't want the ms-bitfields structure packing. You could use a specialized specs file to make -mno-ms-bitfields be the default. It wasn't I who made the decision to make it the default but I do agree with the decision.
From the discussion on that gcc bug report it seemed to me like (at least one of the) GCC mingw target maintainers agreed that not removing the padding bytes is unintentional behaviour for ms_struct+packed, and even a patch was suggested, though not yet applied.