3398 – Attributes inside a union screws data alignment

D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 3398 - Attributes inside a union screws data alignment
Summary: Attributes inside a union screws data alignment
Status: RESOLVED FIXED
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: Other Windows
: P2 critical
Assignee: No Owner
URL:
Keywords: patch, wrong-code
Depends on:
Blocks:
Reported: 2009年10月14日 07:23 UTC by Koroskin Denis
Modified: 2015年06月09日 01:28 UTC (History)
3 users (show)

See Also:


Attachments
Add an attachment (proposed patch, testcase, etc.)

Note You need to log in before you can comment on or make changes to this issue.
Description Koroskin Denis 2009年10月14日 07:23:40 UTC
Here is a test case:
union Foo1
{
 int a;
 float b;
}
version = Test;
union Foo2
{
 version (Test) {
 int a;
 float b;
 }
}
pragma(msg, Foo1.sizeof.stringof); // 4u (okay)
pragma(msg, Foo2.sizeof.stringof); // 8u (wrong)
Comment 1 Don 2010年04月21日 01:14:12 UTC
This applies not just to version declarations; it applies to any attribute.
union Foo1 {
 double[2] a;
 double[2] b; 
}
union Foo2 {
public:
 double[2] a;
 double[2] b; 
}
static assert(Foo1.sizeof == Foo2.sizeof);
---
bug.d(32): Error: static assert (16u == 32u) is false
Subtle and disastrous bug (especially when dealing with C libraries), escalating severity.
Here's a mitigation to create an error message, rather than generate wrong code.
MITIGATION: struct.c StructDeclaration::semantic() line 384.
The problem is that AttribDeclaration::semantic has it's own loop for
doing the semantic on members, which does NOT include setting the offset to 0
if it's a union. Fixing this would not be difficult, but would require a minor structural change in the compiler.
---
 for (int i = 0; i < members_dim; i++)
 {
 Dsymbol *s = (Dsymbol *)members->data[i];
+ if (isUnionDeclaration() && s->isAttribDeclaration())
+ error("Attributes don't yet work inside unions, see Bugzilla 3398");
 s->semantic(sc2);
 if (isUnionDeclaration())
 sc2->offset = 0;
-------
Comment 2 Don 2010年04月22日 06:28:52 UTC
One instance where wrong code is currently generated is in 
std.c.windows.winsock.d, in_addr and in6_addr.
My mitigation would break existing code, though, in cases where the AttribDeclaration is actually an AnonDeclaration.
Comment 3 Don 2010年06月09日 00:31:56 UTC
PATCH: Currently, after processing every field, sc->offset gets changed, and StructDeclaration::semantic() sets the offset back to zero if it was a union.
This patch moves the processing to AggregateDeclaration::addField() instead. If it's a union, don't change the offset in the first place.
Index: struct.c
===================================================================
--- struct.c	(revision 527)
+++ struct.c	(working copy)
@@ -194,20 +194,23 @@
 sizeok = 2; // cannot finish; flag as forward referenced
 return;
 }
+ size_t ofs = sc->offset;
 
 memsize = t->size(loc);
 memalignsize = t->alignsize();
 xalign = t->memalign(sc->structalign);
- alignmember(xalign, memalignsize, &sc->offset);
- v->offset = sc->offset;
- sc->offset += memsize;
- if (sc->offset > structsize)
- structsize = sc->offset;
+ alignmember(xalign, memalignsize, &ofs);
+ v->offset = ofs;
+ ofs += memsize;
+ if (ofs > structsize)
+ structsize = ofs;
 if (sc->structalign < memalignsize)
 memalignsize = sc->structalign;
 if (alignsize < memalignsize)
 alignsize = memalignsize;
 //printf("\talignsize = %d\n", alignsize);
+ if (!isUnionDeclaration())
+ sc->offset = ofs;
 
 v->storage_class |= STCfield;
 //printf(" addField '%s' to '%s' at offset %d, size = %d\n", v->toChars(), toChars(), v->offset, memsize);
@@ -386,8 +389,6 @@
 {
 Dsymbol *s = (Dsymbol *)members->data[i];
 s->semantic(sc2);
- if (isUnionDeclaration())
- sc2->offset = 0;
 #if 0
 if (sizeok == 2)
 { //printf("forward reference\n");
Comment 4 Walter Bright 2010年06月09日 16:37:24 UTC
http://www.dsource.org/projects/dmd/changeset/529 


AltStyle によって変換されたページ (->オリジナル) /