Bug 8583 – [64 bit] AA ushort[dchar] byValue range is corrupted on x86_64
Status
RESOLVED
Resolution
FIXED
Severity
critical
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
x86_64
OS
All
Creation time
2012-08-24T14:00:00Z
Last change time
2013-02-11T23:12:16Z
Keywords
wrong-code
Assigned to
nobody
Creator
dmitry.olsh
Comments
Comment #0 by dmitry.olsh — 2012-08-24T14:00:21Z
The following sample outlines the problem:
void main(){
ushort[dchar] simpleIndices = ['A':437];
assert(simpleIndices['A'] == 437);
assert(simpleIndices.byKey.front == 'A');
assert(simpleIndices.byValue.front == 437); // this fails on x64
//assert(simpleIndices.byValue.front == 0); //and this passes on x64 WTF??!
}
compiled with -m32 it passes
with -m64 it fails and instead the value is 0.
Looking through my corrupted data in the wild I assume it may as well be something else then 0 too.
Tested both with latest git and vanila 2.060 on OS Linux x64 & Win32.
There is a workaround of using .values which does allocate an array of values. Still I consider it critical as corrupted value bug is usually hard to spot and narrow down.
Comment #1 by edmccard — 2012-08-24T19:40:31Z
From my tests, the problem occurs whenever keytype.sizeof <= 8, for any value type. For example, ushort[string], ushort[uint[3]] and ushort[Foo] are ok, where
struct Foo { int x; int y; int z; }
but ushort[uint], ushort[uint[2]] and ushort[Bar] fail, where
struct Bar { int x; int y; }
Comment #2 by edmccard — 2012-08-24T20:05:06Z
(In reply to comment #1)
> From my tests, the problem occurs whenever keytype.sizeof <= 8, for any value
> type.
Spoke too soon; the problem is not that simple, or does not depend solely on the size of the key type. For example, string[uint[3]] works but ushort[uint[3]] fails, ushort[uint[4]] works, but both string[uint[5]] and ushort[uint[5]] fail. (replace uint[x] with a struct of the same size, and the same things happen).
Sorry for the noise.
Comment #3 by clugdbug — 2012-11-14T02:46:21Z
*** Issue 7632 has been marked as a duplicate of this issue. ***
Comment #4 by dlang — 2013-01-16T07:37:10Z
Something interesting I found in rt/aaA.d, line 106: aligntsize() on 64-bit compilation returns a value aligned to 16 bytes. _aaGetX uses this function on key sizes when creating new elements. So for AAs whose key is <= 8 bytes, the value is still 16 bytes further on in memory.
You can check this by repeating the same alignment trick on the addresses of byValue.front:
void testAAType(K, V)(V[K] aa)
{
writefln("testAAType with key %s, value %s", typeid(K), typeid(V));
for (auto v = aa.byValue; !v.empty; v.popFront()) { // emulated foreach (v ; aa.byValue)
V* fp = &v.front();
writef("Unaligned: <%s>", *fp);
V* fpaligned = cast(V*) (( (cast(ptrdiff_t) fp) + 15) & ~15); // copy what aligntsize does on x64
version(D_LP64) {
writefln("; Aligned: <%s>", *fp.alignto16());
}
else {
writefln(" (Not testing aligned value on a 32-bit executable)");
}
}
}
Looking at the key sizes seems to match the pass/fail results in comment #2, with one exception: ushort[uint[3]]. Not sure why the alignment trick is needed here, given that uint[3].sizeof > 8. Maybe DMD aligns AssociativeArray!(uint[3], ushort).Slot to 4 bytes to save space, and since _aaGetX uses a completely different type set, alignment info gets lost somewhere.
Tested with DMD 2.060 and 2.061 on OS X 10.8.2.
Comment #5 by github-bugzilla — 2013-01-21T10:28:09Z