Tracker: Bugs

5 pack-struct option is broken - ID: 3495771
Last Update: Comment added ( cutealien )

$ i686-w64-mingw32-gcc --version
i686-w64-mingw32-gcc (GCC) 4.7.0 20120224 (Fedora MinGW 4.7.0-0.5.20120224.fc16_cross)

I am attaching test case that you can easily see the problem.

$ gcc -m32 test-ps.c
$ ./a.out
size: 12
$ gcc -fpack-struct -m32 test-ps.c
size: 6
$ i686-w64-mingw32-gcc test-ps.c
$ wine ./a-1.exe
size: 12
$ i686-w64-mingw32-gcc -fpack-struct test-ps.c
$ wine ./a.exe
size: 9


Michael Cronenworth ( Michael Cronenworth ) - 2012-02-29 10:52:57 PST

5

Open

Accepted

Nobody/Anonymous

None

None

Public


Comments ( 8 )

Date: 2012-06-29 03:40:52 PDT
Sender: cutealien

I run into this as well and I don't think the change is correct. I get now
_different_ results from compiling with Microsoft Compiler and packing when
using -m-ms-bitfields while I get _identical_ results when compiling with
-mno-ms-bitfields. And when __attribute__ ((__packed)) applies only to last
field of struct then m[no]-ms-bitfields shouldn't really make a difference
in my case:

#include <cstdio>

#if defined(_MSC_VER)
#pragma pack( push, packing )
#pragma pack( 1 )
#endif

struct Header
{
unsigned char IdLength;
unsigned char ColorMapType;
unsigned char ImageType;
unsigned char FirstEntryIndex[2];
unsigned short ColorMapLength;
unsigned char ColorMapEntrySize;
unsigned char XOrigin[2];
unsigned char YOrigin[2];
unsigned short ImageWidth;
}
#if defined(__GNUC__)
__attribute__((packed))
#endif
;

#if defined(_MSC_VER)
#pragma pack( pop, packing )
#endif

int main ()
{
printf("sizeof(Header): %d\n", sizeof(Header));
return 0;
}

But my results for size are:
With VS 2010 (32 bit as well as 64-bit): 14
Compiled with gcc 4.7 and -mno-ms-bitfields: 14
gcc 4.7 and new default (or with -mms-bitfields explicitly): 16

So gcc 4.7 is now incompatible with MS compiler as well as with gcc 4.6 as
far as I can see.


Date: 2012-03-02 11:45:06 PST
Sender: Michael Cronenworth

My last comment was a false alarm. Adding "-mno-ms-bitfields" solves all my
issues. I use software that heavily relies on bitfields and packed structs
(yes, it is very old).

I agree with sezero, even if I am an outside nobody. This is a drastic
change in defaults.

Perhaps this "bug" needs to be changed to an "enhancement" to change the
defaults back to pre-4.7 values to prevent further problems with other
projects.


Date: 2012-03-01 23:06:25 PST
Sender: sezero

The remark of "__attribute__ ((__packed)) applies only to last field of
struct" is curious: I never experienced that before in any gcc versions,
and if that is a gcc-4.7 thing it is a devastatingly incompatible change.
For the record, I just compiled Michael's testcase with gcc45 for win32 and
it prints 6 when ran under wine. Same when compiled for x86-linux. Is your
remark accurate Kai?


Date: 2012-03-01 03:18:15 PST
Sender: ktietz70Project AdminAccepting Donations

The general issue is that the __attribute__ ((__packed)) applies only to
last field of struct. This is the cause for the size of 9. Trick is here
'#pragma pack(1)'. By it you get expected sizes. The issue is that this
field-alignment gets applied even for struct/union's marked to be packed
(or via -fpack-struct option).


Date: 2012-02-29 15:07:19 PST
Sender: Michael Cronenworth

I was too quick to say it is fixed. There seem to be other byte alignment
issues. I will continue investigating.


Date: 2012-02-29 15:05:31 PST
Sender: Michael Cronenworth

Adding -mno-ms-bitfields does fix the issue that I am having. I was
expecting 6 and not 8 (or 9). I did not know about the defaults change.
Should I report the 9 issue upstream (gcc)?


Date: 2012-02-29 13:21:20 PST
Sender: ktietz70Project AdminAccepting Donations

Ah, I missed that default-alignment is treated now for ms_struct
union/struct-s too.
You can solve the issue also by additing explicit #pragma pack(1) of
__attribute__ ((pack(1))).

The cause why it gets aligned to 9 is that. Default alignment of fields is
4 on 32-bit.
So first char a[1]; is placed in 4-bytes, long b also, and the last element
has 4 too.
By enabling struct-pack, All fields in structure getting merged.
So char a[1]; has one byte size, long b has 4 byte size, plus char c[1] has
1. But by structure-alignment of 4, structure gets expanded in the last
field to 4.

I see that here alignment is one too big ... hmm, maybe an issue indeed.

Work-a-round use explicit #pragma pack(1), if you don't want structure
alignment at end.




Date: 2012-02-29 13:10:24 PST
Sender: ktietz70Project AdminAccepting Donations

The gcc 4.7 gcc for mingw has by default -mms-bitfields activated. Which
means struct-layout has changed and alignment in struct.
You can force a specific layout by using attribute ms_struct or by
attribute gcc_struct.

The difference between those two layouts is in bitfield packing and in
alignment of those field members.

For example:

struct {
unsigned long long c : 1;
unsigned int a : 1;
unsigned int b : 1;
}

will be layout differently.

For gcc-layout all bits geting merged together within one bitfield. gcc
struct makes no difference in actual type-sizes for bitfields.
For ms-layout c will end in a 8-byte field, and just a and b getting merged
together as they have same type-size.


This is to be expected behavior. You might want to try here
-mno-ms-bitfields.



Attached File ( 1 )

Filename Description Download
test-ps.c test case Download

Changes ( 7 )

Field Old Value Date By
close_date 2012-02-29 13:10 2012-02-29 15:05:31 PST Michael Cronenworth
status_id Pending 2012-02-29 15:05:31 PST Michael Cronenworth
resolution_id Invalid 2012-02-29 13:21:20 PST ktietz70
close_date - 2012-02-29 13:10:24 PST ktietz70
status_id Open 2012-02-29 13:10:24 PST ktietz70
resolution_id None 2012-02-29 13:10:24 PST ktietz70
File Added 437059: test-ps.c 2012-02-29 10:52:58 PST Michael Cronenworth