Skip to content

Commit 4c82050

Browse files
tim-dlangdlang-bot
authored andcommittedJun 17, 2024·
Fix bugzilla 24592 - ImportC: Bitfield layout wrong for int64 on 32-bit Linux
Type ulong is 64-bit on 32-bit Linux, but has 32-bit alignment. This affects the layout of bitfields. Also add a new test for ImportC bitfields, which compares size, alignment and layout with the host C++ compiler. The existing tests compared with fixed values instead.
1 parent 86b71a2 commit 4c82050

File tree

7 files changed

+257
-6
lines changed

7 files changed

+257
-6
lines changed
 

‎compiler/src/dmd/dsymbolsem.d

+3-3
Original file line numberDiff line numberDiff line change
@@ -7270,18 +7270,18 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor
72707270
// If the bit-field spans more units of alignment than its type,
72717271
// start a new field at the next alignment boundary.
72727272
if (fieldState.bitOffset == fieldState.fieldSize * 8 &&
7273-
fieldState.bitOffset + bfd.fieldWidth > memalignsize * 8)
7273+
fieldState.bitOffset + bfd.fieldWidth > memsize * 8)
72747274
{
72757275
if (log) printf("more units of alignment than its type\n");
72767276
startNewField(); // the bit field is full
72777277
}
72787278
else
72797279
{
72807280
// if alignment boundary is crossed
7281-
uint start = fieldState.fieldOffset * 8 + fieldState.bitOffset;
7281+
uint start = (fieldState.fieldOffset * 8 + fieldState.bitOffset) % (memalignsize * 8);
72827282
uint end = start + bfd.fieldWidth;
72837283
//printf("%s start: %d end: %d memalignsize: %d\n", ad.toChars(), start, end, memalignsize);
7284-
if (start / (memalignsize * 8) != (end - 1) / (memalignsize * 8))
7284+
if (start / (memsize * 8) != (end - 1) / (memsize * 8))
72857285
{
72867286
if (log) printf("alignment is crossed\n");
72877287
startNewField();

‎compiler/src/dmd/e2ir.d

+4-3
Original file line numberDiff line numberDiff line change
@@ -3135,12 +3135,13 @@ elem* toElem(Expression e, ref IRState irs)
31353135
{
31363136
// adjust bit offset for bitfield so the type tym encloses the bitfield
31373137
const szbits = tysize(tym) * 8;
3138+
uint memalignsize = target.fieldalign(dve.type);
31383139
auto bitOffset = bf.bitOffset;
31393140
if (bitOffset + bf.fieldWidth > szbits)
31403141
{
3141-
const advance = bf.bitOffset / szbits;
3142-
voffset += advance;
3143-
bitOffset -= advance * 8;
3142+
const advance = bf.bitOffset / (memalignsize * 8);
3143+
voffset += advance * memalignsize;
3144+
bitOffset -= advance * memalignsize * 8;
31443145
assert(bitOffset + bf.fieldWidth <= szbits);
31453146
}
31463147
//printf("voffset %u bitOffset %u fieldWidth %u bits %u\n", cast(uint)voffset, bitOffset, bf.fieldWidth, szbits);

‎compiler/test/runnable/bitfieldsposix32.c

+12
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ A8 = 8 4 | 8 4
4141
A9 = 16 4 | 16 4
4242
A10 = 2 2 | 2 2
4343
A11 = 12 4 | 12 4
44+
Issue24592a = 8 4 | 8 4
45+
Issue24592b = 12 4 | 12 4
46+
Issue24592c = 24 4 | 24 4
47+
Issue24592d = 12 4 | 12 4
4448
S9 = x30200
4549
S14 = x300000201
4650
S15 = xe01
@@ -112,6 +116,10 @@ struct A9 { unsigned short a:8; long b:16; // 16 4 (32 bit) 16 8 (64 b
112116
struct A10 { unsigned short a:8; char b; }; // 2 2
113117
struct A11 { char a; int b:5, c:11, :0, d:8; // 12 4
114118
struct { int ee:8; } e; };
119+
struct Issue24592a { unsigned long long a:20, b:20, c:24; };
120+
struct Issue24592b { unsigned int x; unsigned long long a:20, b:20, c:24; };
121+
struct Issue24592c { unsigned long long a:20, b:32, c:32, d:32, e:32, f:32; };
122+
struct Issue24592d { unsigned long long a:10, b:16, c:16, d:16, e:16, f:16; };
115123

116124
int main()
117125
{
@@ -154,6 +162,10 @@ int main()
154162
printf("A9 = %d %d | 16 4\n", (int)sizeof(struct A9), (int)_Alignof(struct A9));
155163
printf("A10 = %d %d | 2 2\n", (int)sizeof(struct A10), (int)_Alignof(struct A10));
156164
printf("A11 = %d %d | 12 4\n", (int)sizeof(struct A11), (int)_Alignof(struct A11));
165+
printf("Issue24592a = %d %d | 8 4\n", (int)sizeof(struct Issue24592a), (int)_Alignof(struct Issue24592a));
166+
printf("Issue24592b = %d %d | 12 4\n", (int)sizeof(struct Issue24592b), (int)_Alignof(struct Issue24592b));
167+
printf("Issue24592c = %d %d | 24 4\n", (int)sizeof(struct Issue24592c), (int)_Alignof(struct Issue24592c));
168+
printf("Issue24592d = %d %d | 12 4\n", (int)sizeof(struct Issue24592d), (int)_Alignof(struct Issue24592d));
157169

158170
{
159171
struct S9 s;

‎compiler/test/runnable/bitfieldsposix64.c

+12
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ A8 = 8 8 | 8 8
4141
A9 = 16 8 | 16 8
4242
A10 = 2 2 | 2 2
4343
A11 = 12 4 | 12 4
44+
Issue24592a = 8 8 | 8 8
45+
Issue24592b = 16 8 | 16 8
46+
Issue24592c = 24 8 | 24 8
47+
Issue24592d = 16 8 | 16 8
4448
S9 = x30200
4549
S14 = x300000201
4650
S15 = xe01
@@ -112,6 +116,10 @@ struct A9 { unsigned short a:8; long b:16; // 16 4 (32 bit) 16 8 (64 b
112116
struct A10 { unsigned short a:8; char b; }; // 2 2
113117
struct A11 { char a; int b:5, c:11, :0, d:8; // 12 4
114118
struct { int ee:8; } e; };
119+
struct Issue24592a { unsigned long long a:20, b:20, c:24; };
120+
struct Issue24592b { unsigned int x; unsigned long long a:20, b:20, c:24; };
121+
struct Issue24592c { unsigned long long a:20, b:32, c:32, d:32, e:32, f:32; };
122+
struct Issue24592d { unsigned long long a:10, b:16, c:16, d:16, e:16, f:16; };
115123

116124
int main()
117125
{
@@ -154,6 +162,10 @@ int main()
154162
printf("A9 = %d %d | 16 8\n", (int)sizeof(struct A9), (int)_Alignof(struct A9));
155163
printf("A10 = %d %d | 2 2\n", (int)sizeof(struct A10), (int)_Alignof(struct A10));
156164
printf("A11 = %d %d | 12 4\n", (int)sizeof(struct A11), (int)_Alignof(struct A11));
165+
printf("Issue24592a = %d %d | 8 8\n", (int)sizeof(struct Issue24592a), (int)_Alignof(struct Issue24592a));
166+
printf("Issue24592b = %d %d | 16 8\n", (int)sizeof(struct Issue24592b), (int)_Alignof(struct Issue24592b));
167+
printf("Issue24592c = %d %d | 24 8\n", (int)sizeof(struct Issue24592c), (int)_Alignof(struct Issue24592c));
168+
printf("Issue24592d = %d %d | 16 8\n", (int)sizeof(struct Issue24592d), (int)_Alignof(struct Issue24592d));
157169

158170
{
159171
struct S9 s;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
extern "C"
2+
{
3+
#include "testbitfields_importc.c"
4+
}
5+
6+
#include <stdio.h>
7+
#include <string.h>
8+
9+
template<typename T>
10+
size_t getStructSize();
11+
template<typename T>
12+
size_t getStructAlign();
13+
template<typename T>
14+
void resetBitfield(T &data, const char *member);
15+
16+
#define BEGIN_STRUCT(S) \
17+
template<> \
18+
size_t getStructSize<S>() \
19+
{ \
20+
return sizeof(S); \
21+
} \
22+
template<> \
23+
size_t getStructAlign<S>() \
24+
{ \
25+
return alignof(S); \
26+
} \
27+
template<> \
28+
void resetBitfield<S>(S &data, const char *member) \
29+
{
30+
31+
#define FIELD(name) if (strcmp(member, #name) == 0) data.name = 0;
32+
#define END_STRUCT }
33+
34+
BEGIN_STRUCT(T0) FIELD(x) END_STRUCT
35+
BEGIN_STRUCT(T1) FIELD(x) END_STRUCT
36+
BEGIN_STRUCT(T2) FIELD(x) END_STRUCT
37+
BEGIN_STRUCT(T3) FIELD(a) FIELD(b) FIELD(c) FIELD(d) FIELD(x) END_STRUCT
38+
BEGIN_STRUCT(T4) FIELD(a) FIELD(b) FIELD(c) FIELD(d) FIELD(e) FIELD(f) FIELD(g) FIELD(h) FIELD(x) END_STRUCT
39+
BEGIN_STRUCT(T5) FIELD(a) FIELD(b) FIELD(c) FIELD(d) FIELD(e) FIELD(f) FIELD(g) FIELD(x) END_STRUCT
40+
BEGIN_STRUCT(S1) FIELD(f) END_STRUCT
41+
BEGIN_STRUCT(S2) FIELD(x) FIELD(y) END_STRUCT
42+
BEGIN_STRUCT(S3) FIELD(c) FIELD(x) FIELD(y) END_STRUCT
43+
BEGIN_STRUCT(S4) FIELD(x) FIELD(y) END_STRUCT
44+
BEGIN_STRUCT(S5) FIELD(x) FIELD(y) END_STRUCT
45+
BEGIN_STRUCT(S6) FIELD(x) FIELD(y) END_STRUCT
46+
BEGIN_STRUCT(S7) FIELD(x) FIELD(y) FIELD(z) END_STRUCT
47+
BEGIN_STRUCT(S8) FIELD(a) FIELD(b) FIELD(c) END_STRUCT
48+
BEGIN_STRUCT(S8A) FIELD(b) FIELD(c) END_STRUCT
49+
BEGIN_STRUCT(S8B) FIELD(a) FIELD(b) FIELD(c) END_STRUCT
50+
BEGIN_STRUCT(S8C) FIELD(a) FIELD(b) END_STRUCT
51+
BEGIN_STRUCT(S9) FIELD(a) FIELD(b) FIELD(c) END_STRUCT
52+
//BEGIN_STRUCT(S10) END_STRUCT
53+
//BEGIN_STRUCT(S11) END_STRUCT
54+
BEGIN_STRUCT(S12) FIELD(x) END_STRUCT
55+
BEGIN_STRUCT(S13) FIELD(x) FIELD(x1) FIELD(x2) FIELD(x3) FIELD(x4) FIELD(w) END_STRUCT
56+
BEGIN_STRUCT(S14) FIELD(a) FIELD(b) FIELD(c) END_STRUCT
57+
BEGIN_STRUCT(S15) FIELD(a) FIELD(b) FIELD(c) END_STRUCT
58+
BEGIN_STRUCT(S16) END_STRUCT
59+
BEGIN_STRUCT(S17) FIELD(a) END_STRUCT
60+
BEGIN_STRUCT(S18) FIELD(a) FIELD(b) END_STRUCT
61+
BEGIN_STRUCT(A0) FIELD(a) FIELD(b) FIELD(c) END_STRUCT
62+
BEGIN_STRUCT(A1) FIELD(a) FIELD(b) FIELD(c) END_STRUCT
63+
BEGIN_STRUCT(A2) FIELD(a) FIELD(b) FIELD(c) FIELD(d)
64+
FIELD(e) END_STRUCT
65+
BEGIN_STRUCT(A3) FIELD(a) FIELD(b) FIELD(c) FIELD(d)
66+
FIELD(e) END_STRUCT
67+
BEGIN_STRUCT(A4) FIELD(a) FIELD(b)
68+
FIELD(c) END_STRUCT
69+
BEGIN_STRUCT(A5) FIELD(a) FIELD(b) END_STRUCT
70+
BEGIN_STRUCT(A6) FIELD(a) FIELD(b) END_STRUCT
71+
BEGIN_STRUCT(A7) FIELD(a) FIELD(b) FIELD(c)
72+
FIELD(d) END_STRUCT
73+
BEGIN_STRUCT(A8) FIELD(a) FIELD(b)
74+
FIELD(c) END_STRUCT
75+
BEGIN_STRUCT(A9) FIELD(a) FIELD(b)
76+
FIELD(c) FIELD(d)
77+
FIELD(e) FIELD(f) END_STRUCT
78+
BEGIN_STRUCT(A10) FIELD(a) FIELD(b) END_STRUCT
79+
BEGIN_STRUCT(A11) FIELD(a) FIELD(b) FIELD(c) FIELD(d)
80+
END_STRUCT
81+
BEGIN_STRUCT(Issue24592a) FIELD(a) FIELD(b) FIELD(c) END_STRUCT
82+
BEGIN_STRUCT(Issue24592b) FIELD(x) FIELD(a) FIELD(b) FIELD(c) END_STRUCT
83+
BEGIN_STRUCT(Issue24592c) FIELD(a) FIELD(b) FIELD(c) FIELD(d) FIELD(e) FIELD(f) END_STRUCT
84+
BEGIN_STRUCT(Issue24592d) FIELD(a) FIELD(b) FIELD(c) FIELD(d) FIELD(e) FIELD(f) END_STRUCT
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
2+
struct T0 { char x:1; };
3+
struct T1 { short x:1; };
4+
struct T2 { int x:1; };
5+
struct T3 { char a,b,c,d; long long x:1; };
6+
struct T4 { char a,b,c,d,e,f,g,h; long long x:1; };
7+
struct T5 { char a,b,c,d,e,f,g; long long x:1; };
8+
struct S1 { long long int f:1; };
9+
struct S2 { int x:1; int y:1; };
10+
struct S3 { short c; int x:1; unsigned y:1; };
11+
struct S4 { int x:1; short y:1; };
12+
struct S5 { short x:1; int y:1; };
13+
struct S6 { short x:1; short y:1; };
14+
struct S7 { short x:1; int y:1; long long z:1; };
15+
struct S8 { char a; char b:1; short c:2; };
16+
struct S8A { char b:1; short c:2; };
17+
struct S8B { char a; short b:1; char c:2; };
18+
struct S8C { char a; int b:1; };
19+
struct S9 { char a; char b:2; short c:9; };
20+
//struct S10 { };
21+
//struct S11 { int :0; };
22+
struct S12 { int :0; int x; };
23+
struct S13 { unsigned x:12; unsigned x1:1; unsigned x2:1; unsigned x3:1; unsigned x4:1; int w; };
24+
struct S14 { char a; char b:4; int c:30; };
25+
struct S15 { char a; char b:2; int c:9; };
26+
struct S16 { int :32; };
27+
struct S17 { int a:32; };
28+
struct S18 { char a; long long :0; char b; };
29+
struct A0 { int a; long long b:34, c:4; };
30+
struct A1 { int a; unsigned b:11; int c; };
31+
struct A2 { int a; unsigned b:11, c:5, d:16;
32+
int e; };
33+
struct A3 { int a; unsigned b:11, c:5, :0, d:16;
34+
int e; };
35+
struct A4 { int a:8; short b:7;
36+
unsigned int c:29; };
37+
struct A5 { char a:7, b:2; };
38+
struct A6 { char a:7; short b:2; };
39+
struct A7 { short a:8; long b:16; int c;
40+
char d:7; };
41+
struct A8 { short a:8; long b:16; int :0;
42+
char c:7; };
43+
struct A9 { unsigned short a:8; long b:16;
44+
unsigned long c:29; long long d:9;
45+
unsigned long e:2, f:31; };
46+
struct A10 { unsigned short a:8; char b; };
47+
struct A11 { char a; int b:5, c:11, :0, d:8;
48+
struct { int ee:8; } e; };
49+
struct Issue24592a { unsigned long long a:20, b:20, c:24; };
50+
struct Issue24592b { unsigned int x; unsigned long long a:20, b:20, c:24; };
51+
struct Issue24592c { unsigned long long a:20, b:32, c:32, d:32, e:32, f:32; };
52+
struct Issue24592d { unsigned long long a:10, b:16, c:16, d:16, e:16, f:16; };
+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// EXTRA_CPP_SOURCES: testbitfields_cpp.cpp
2+
// EXTRA_SOURCES: extra-files/testbitfields_importc.c
3+
// CXXFLAGS(linux osx freebsd dragonflybsd): -std=c++11
4+
5+
import core.stdc.stdio;
6+
import core.stdc.stdlib;
7+
import core.stdc.string;
8+
9+
static import testbitfields_importc;
10+
11+
extern(C++) size_t getStructSize(T)();
12+
extern(C++) size_t getStructAlign(T)();
13+
extern(C++) void resetBitfield(T)(ref T data, const(char) *member);
14+
15+
bool checkType(S)()
16+
{
17+
bool different;
18+
if (S.sizeof != getStructSize!S)
19+
different = true;
20+
if (S.alignof != getStructAlign!S)
21+
different = true;
22+
static foreach (member; __traits(allMembers, S))
23+
{{
24+
static if (member[0] != '_' && typeof(__traits(getMember, S, member)).stringof[0] != '_')
25+
{
26+
S dummyD;
27+
memset(&dummyD, 0xff, S.sizeof);
28+
__traits(getMember, dummyD, member) = 0;
29+
30+
S* dummyC = cast(S*) malloc(getStructSize!S);
31+
memset(dummyC, 0xff, getStructSize!S);
32+
resetBitfield!S(*dummyC, member.ptr);
33+
if (S.sizeof == getStructSize!S && memcmp(&dummyD, dummyC, S.sizeof) != 0)
34+
different = true;
35+
free(dummyC);
36+
}
37+
}}
38+
if (different)
39+
{
40+
printf("Struct %s has different bitfield layout for C and D:\n", __traits(identifier, S).ptr);
41+
printf(" D: size=%zd align=%zd\n", S.sizeof, S.alignof);
42+
printf(" C: size=%zd align=%zd\n", getStructSize!S, getStructAlign!S);
43+
static foreach (member; __traits(allMembers, S))
44+
{{
45+
static if (member[0] != '_' && typeof(__traits(getMember, S, member)).stringof[0] != '_')
46+
{
47+
printf(" %s %s:\n", typeof(__traits(getMember, S, member)).stringof.ptr, member.ptr);
48+
printf(" D:");
49+
S dummyD;
50+
memset(&dummyD, 0xff, S.sizeof);
51+
__traits(getMember, dummyD, member) = 0;
52+
foreach (i; 0 .. S.sizeof)
53+
{
54+
if (i % 4 == 0)
55+
printf(" ");
56+
printf("%02X", 0xff & ~(cast(ubyte*) &dummyD)[i]);
57+
}
58+
59+
printf("\n C:");
60+
S* dummyC = cast(S*) malloc(getStructSize!S);
61+
memset(dummyC, 0xff, getStructSize!S);
62+
resetBitfield!S(*dummyC, member.ptr);
63+
foreach (i; 0 .. getStructSize!S)
64+
{
65+
if (i % 4 == 0)
66+
printf(" ");
67+
printf("%02X", 0xff & ~(cast(ubyte*) dummyC)[i]);
68+
}
69+
free(dummyC);
70+
printf("\n");
71+
}
72+
}}
73+
}
74+
return different;
75+
}
76+
77+
int main()
78+
{
79+
int ret;
80+
static foreach (name; __traits(allMembers, testbitfields_importc))
81+
{{
82+
alias S = __traits(getMember, testbitfields_importc, name);
83+
static if (is(S == struct) && name[0] != '_')
84+
{
85+
if (checkType!S)
86+
ret = 1;
87+
}
88+
}}
89+
return ret;
90+
}

0 commit comments

Comments
 (0)
Please sign in to comment.