This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
[Bug target/52991] [6/7/8 Regression] attribute packed broken on mingw32?
- From: "jakub at gcc dot gnu.org" <gcc-bugzilla at gcc dot gnu dot org>
- To: gcc-bugs at gcc dot gnu dot org
- Date: Tue, 27 Feb 2018 21:42:45 +0000
- Subject: [Bug target/52991] [6/7/8 Regression] attribute packed broken on mingw32?
- Auto-submitted: auto-generated
- References: <bug-52991-4@http.gcc.gnu.org/bugzilla/>
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52991
--- Comment #31 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
Thanks for the hint.
So:
#include <stdio.h>
struct S {
int a : 2;
__declspec(align(8)) int b : 2;
int c : 28;
__declspec(align(16)) int d : 2;
int e : 30;
} s;
int a = sizeof (struct S);
void f1 (int x) { s.a = x; }
void f2 (int x) { s.b = x; }
void f3 (int x) { s.c = x; }
void f4 (int x) { s.d = x; }
void f5 (int x) { s.e = x; }
void
printme (void)
{
int i;
for (i = 0; i < sizeof (s); ++i)
printf ("%02x, ", ((unsigned char *) &s)[i]);
printf ("\n");
}
int
main ()
{
printf ("%d\n", (int) sizeof (s));
s.a = -1; printme ();
s.a = 0; s.b = -1; printme ();
s.b = 0; s.c = -1; printme ();
s.c = 0; s.d = -1; printme ();
s.d = 0; s.e = -1; printme ();
return 0;
}
matches what GCC with the patch emits (that is the bf-ms-layout-5.c test),
and so does:
#include <stddef.h>
#ifdef _WIN32
# ifdef _MSC_VER
# define PACK(typeDec) __pragma( pack(push, 1) ) typeDec __pragma( pack(pop) )
# else
# define PACK(typeDec) typeDec __attribute__((__packed__,ms_struct))
# endif
#else
# define PACK(typeDec) typeDec __attribute__((__packed__))
#endif
#ifdef _MSC_VER
# define ALIGN(typeDec, n) __declspec(align(n)) typeDec
#else
# define ALIGN(typeDec, n) typeDec __attribute__((aligned(n)))
#endif
#define assert_cc(expr) extern char c[(expr) ? 1 : -1]
PACK(struct test_sp1 {
int a;
short b;
int c;
char d;
});
assert_cc(sizeof(struct test_sp1) == 11);
assert_cc(offsetof(struct test_sp1, a) == 0);
assert_cc(offsetof(struct test_sp1, b) == 4);
assert_cc(offsetof(struct test_sp1, c) == 6);
assert_cc(offsetof(struct test_sp1, d) == 10);
PACK(struct test_sp3 {
int a;
ALIGN(short b, 8);
int c;
char d;
});
assert_cc(sizeof(struct test_sp3) == 16);
assert_cc(offsetof(struct test_sp3, a) == 0);
assert_cc(offsetof(struct test_sp3, b) == 8);
assert_cc(offsetof(struct test_sp3, c) == 10);
assert_cc(offsetof(struct test_sp3, d) == 14);
struct test_s4 {
int a;
short b;
int c:15;
char d;
};
#ifdef _WIN32
assert_cc(sizeof(struct test_s4) == 16);
assert_cc(offsetof(struct test_s4, a) == 0);
assert_cc(offsetof(struct test_s4, b) == 4);
assert_cc(offsetof(struct test_s4, d) == 12);
#else
assert_cc(sizeof(struct test_s4) == 12);
assert_cc(offsetof(struct test_s4, a) == 0);
assert_cc(offsetof(struct test_s4, b) == 4);
assert_cc(offsetof(struct test_s4, d) == 8);
#endif
int main () { return 0; }
(bf-ms-layout-4.c).
So does:
#define _TEST_MS_LAYOUT
#include <stddef.h>
#include <string.h>
extern void abort();
#pragma pack(8)
struct one {
int d;
unsigned char a;
unsigned short b:7;
char c;
} ;
struct two {
int d;
unsigned char a;
unsigned int b:7;
char c;
} ;
struct three {
short d;
unsigned short a:3;
unsigned short b:9;
unsigned char c:7;
} ;
/* Bitfields of size 0 have some truly odd behaviors. */
struct four {
unsigned short a:3;
unsigned short b:9;
unsigned int :0; /* forces struct alignment to int */
unsigned char c:7;
} ;
struct five {
char a;
int :0; /* ignored; prior field is not a bitfield. */
char b;
char c;
} ;
struct six {
char a :8;
int :0; /* not ignored; prior field IS a bitfield, causes
struct alignment as well. */
char b;
char c;
} ;
struct seven {
char a:8;
char :0;
int :0; /* Ignored; prior field is zero size bitfield. */
char b;
char c;
} ;
struct eight { /* ms size 4 */
short b:3;
char c;
} ;
#ifdef _MSC_VER
#define LONGLONG __int64
#else
#define LONGLONG long long
#endif
union nine { /* ms size 8 */
LONGLONG a:3;
char c;
} ;
struct ten { /* ms size 16 */
LONGLONG a:3;
LONGLONG b:3;
char c;
} ;
#define val(s,f) (s.f)
#define check_struct(_X) \
{ \
if (sizeof (struct _X) != exp_sizeof_##_X ) \
abort(); \
memcpy(&test_##_X, filler, sizeof(test_##_X));\
if (val(test_##_X,c) != exp_##_X##_c) \
abort(); \
}
#define check_union(_X) \
{ \
if (sizeof (union _X) != exp_sizeof_##_X ) \
abort(); \
memcpy(&test_##_X, filler, sizeof(test_##_X));\
if (val(test_##_X,c) != exp_##_X##_c) \
abort(); \
}
#define check_struct_size(_X) \
{ \
if (sizeof (struct _X) != exp_sizeof_##_X ) \
abort(); \
}
#define check_struct_off(_X) \
{ \
memcpy(&test_##_X, filler, sizeof(test_##_X));\
if (val(test_##_X,c) != exp_##_X##_c) \
abort(); \
}
#define check_union_size(_X) \
{ \
if (sizeof (union _X) != exp_sizeof_##_X ) \
abort(); \
}
#define check_union_off(_X) \
{ \
memcpy(&test_##_X, filler, sizeof(test_##_X));\
if (val(test_##_X,c) != exp_##_X##_c) \
abort(); \
}
int main(){
unsigned char filler[16];
struct one test_one;
struct two test_two;
struct three test_three;
struct four test_four;
struct five test_five;
struct six test_six;
struct seven test_seven;
struct eight test_eight;
union nine test_nine;
struct ten test_ten;
#if defined (_TEST_MS_LAYOUT) || defined (_MSC_VER)
size_t exp_sizeof_one = 12;
size_t exp_sizeof_two = 16;
size_t exp_sizeof_three =6;
size_t exp_sizeof_four = 8;
size_t exp_sizeof_five = 3;
size_t exp_sizeof_six = 8;
size_t exp_sizeof_seven = 3;
size_t exp_sizeof_eight = 4;
size_t exp_sizeof_nine = 8;
size_t exp_sizeof_ten = 16;
unsigned char exp_one_c = 8;
unsigned char exp_two_c = 12;
unsigned char exp_three_c = 4;
unsigned char exp_four_c = 4;
char exp_five_c = 2;
char exp_six_c = 5;
char exp_seven_c = 2;
char exp_eight_c = 2;
char exp_nine_c = 0;
char exp_ten_c = 8;
#else /* testing -mno-ms-bitfields */
size_t exp_sizeof_one = 8;
size_t exp_sizeof_two = 8;
size_t exp_sizeof_three = 6;
size_t exp_sizeof_four = 6;
size_t exp_sizeof_five = 6;
size_t exp_sizeof_six = 6;
size_t exp_sizeof_seven = 6;
size_t exp_sizeof_eight = 2;
size_t exp_sizeof_nine = 8;
size_t exp_sizeof_ten = 8;
unsigned short exp_one_c = 6;
unsigned int exp_two_c = 6;
unsigned char exp_three_c = 64;
unsigned char exp_four_c = 4;
char exp_five_c = 5;
char exp_six_c = 5;
char exp_seven_c = 5;
char exp_eight_c = 1;
char exp_nine_c = 0;
char exp_ten_c = 1;
#endif
unsigned char i;
for ( i = 0; i < 16; i++ )
filler[i] = i;
check_struct_off (one);
check_struct_off (two);
check_struct_off (three);
check_struct_off (four);
check_struct_off (five);
check_struct_off (six);
check_struct_off (seven);
check_struct_off (eight);
check_union_off (nine);
check_struct_off (ten);
check_struct_size (one);
check_struct_size (two);
check_struct_size (three);
check_struct_size (four);
check_struct_size (five);
check_struct_size (six);
check_struct_size (seven);
check_struct_size (eight);
check_union_size (nine);
check_struct_size (ten);
return 0;
}
which is the patched version of bf-ms-layout.c, and so does:
#define _TEST_MS_LAYOUT
#include <stddef.h>
#include <string.h>
extern void abort();
#pragma pack(8)
#ifdef __GNUC__
#define ATTR __attribute__ ((ms_struct))
#else
#define ATTR
#endif
struct one {
int d;
unsigned char a;
unsigned short b:7;
char c;
} ATTR;
struct two {
int d;
unsigned char a;
unsigned int b:7;
char c;
} ATTR;
struct three {
short d;
unsigned short a:3;
unsigned short b:9;
unsigned char c:7;
} ATTR;
/* Bitfields of size 0 have some truly odd behaviors. */
struct four {
unsigned short a:3;
unsigned short b:9;
unsigned int :0; /* forces struct alignment to int */
unsigned char c:7;
} ATTR;
struct five {
char a;
int :0; /* ignored; prior field is not a bitfield. */
char b;
char c;
} ATTR;
struct six {
char a :8;
int :0; /* not ignored; prior field IS a bitfield, causes
struct alignment as well. */
char b;
char c;
} ATTR;
struct seven {
char a:8;
char :0;
int :0; /* Ignored; prior field is zero size bitfield. */
char b;
char c;
} ATTR;
struct eight { /* ms size 4 */
short b:3;
char c;
} ATTR;
#ifdef _MSC_VER
#define LONGLONG __int64
#else
#define LONGLONG long long
#endif
union nine { /* ms size 8 */
LONGLONG a:3;
char c;
} ATTR;
struct ten { /* ms size 16 */
LONGLONG a:3;
LONGLONG b:3;
char c;
} ATTR;
#define val(s,f) (s.f)
#define check_struct(_X) \
{ \
if (sizeof (struct _X) != exp_sizeof_##_X ) \
abort(); \
memcpy(&test_##_X, filler, sizeof(test_##_X));\
if (val(test_##_X,c) != exp_##_X##_c) \
abort(); \
}
#define check_union(_X) \
{ \
if (sizeof (union _X) != exp_sizeof_##_X ) \
abort(); \
memcpy(&test_##_X, filler, sizeof(test_##_X));\
if (val(test_##_X,c) != exp_##_X##_c) \
abort(); \
}
#define check_struct_size(_X) \
{ \
if (sizeof (struct _X) != exp_sizeof_##_X ) \
abort(); \
}
#define check_struct_off(_X) \
{ \
memcpy(&test_##_X, filler, sizeof(test_##_X));\
if (val(test_##_X,c) != exp_##_X##_c) \
abort(); \
}
#define check_union_size(_X) \
{ \
if (sizeof (union _X) != exp_sizeof_##_X ) \
abort(); \
}
#define check_union_off(_X) \
{ \
memcpy(&test_##_X, filler, sizeof(test_##_X));\
if (val(test_##_X,c) != exp_##_X##_c) \
abort(); \
}
int main(){
unsigned char filler[16];
struct one test_one;
struct two test_two;
struct three test_three;
struct four test_four;
struct five test_five;
struct six test_six;
struct seven test_seven;
struct eight test_eight;
union nine test_nine;
struct ten test_ten;
#if defined (_TEST_MS_LAYOUT) || defined (_MSC_VER)
size_t exp_sizeof_one = 12;
size_t exp_sizeof_two = 16;
size_t exp_sizeof_three =6;
size_t exp_sizeof_four = 8;
size_t exp_sizeof_five = 3;
size_t exp_sizeof_six = 8;
size_t exp_sizeof_seven = 3;
size_t exp_sizeof_eight = 4;
size_t exp_sizeof_nine = 8;
size_t exp_sizeof_ten = 16;
unsigned char exp_one_c = 8;
unsigned char exp_two_c = 12;
unsigned char exp_three_c = 4;
unsigned char exp_four_c = 4;
char exp_five_c = 2;
char exp_six_c = 5;
char exp_seven_c = 2;
char exp_eight_c = 2;
char exp_nine_c = 0;
char exp_ten_c = 8;
#else /* testing -mno-ms-bitfields */
size_t exp_sizeof_one = 8;
size_t exp_sizeof_two = 8;
size_t exp_sizeof_three = 6;
size_t exp_sizeof_four = 6;
size_t exp_sizeof_five = 6;
size_t exp_sizeof_six = 6;
size_t exp_sizeof_seven = 6;
size_t exp_sizeof_eight = 2;
size_t exp_sizeof_nine = 8;
size_t exp_sizeof_ten = 8;
unsigned short exp_one_c = 6;
unsigned int exp_two_c = 6;
unsigned char exp_three_c = 64;
unsigned char exp_four_c = 4;
char exp_five_c = 5;
char exp_six_c = 5;
char exp_seven_c = 5;
char exp_eight_c = 1;
char exp_nine_c = 0;
char exp_ten_c = 1;
#endif
unsigned char i;
for ( i = 0; i < 16; i++ )
filler[i] = i;
check_struct_off (one);
check_struct_off (two);
check_struct_off (three);
check_struct_off (four);
check_struct_off (five);
check_struct_off (six);
check_struct_off (seven);
check_struct_off (eight);
check_union_off (nine);
check_struct_off (ten);
check_struct_size (one);
check_struct_size (two);
check_struct_size (three);
check_struct_size (four);
check_struct_size (five);
check_struct_size (six);
check_struct_size (seven);
check_struct_size (eight);
check_union_size (nine);
check_struct_size (ten);
return 0;
};
which is the patched version of bf-ms-layout-2.c (with ATTR defined to nothing
for non-__GNUC__), again the unpatched version fails.