The logic std.format uses for detecting overlap of anonymous unions is incorrect.
It looks at the difference in .offsetof for consecutive members in .tupleof, but doesn't account for nested unions.
```
import std;
struct S {
union {
struct {
union {
string a = "string a";
long overlapsAlength;
}
string b = "string b";
}
string[2] overlapsAandB;
}
}
void main() @safe {
S s;
s.overlapsAlength = 32;
writeln(s);
}
```
Prints:
S(#{overlap a, overlapsAlength}, "string b", ["string a\0string b\0%s\0/dlang/dmd-", "string b"])
It only detects the overlap of `a` and `overlapsAlength`, while `overlapsAandB` gets printed, resulting in memory corruption.
The example calls writeln on s, but writeln is simply a wrapper around formatValue which is at the heart of the issue:
```
auto a = appender!string;
auto f = singleSpec("%s");
formatValue(a, s, f);
writeln(a.data);
```
The specific logic can be found here:
https://github.com/dlang/phobos/blob/cc977c37b8fa7af5fc54bc64a6aad14714e5cf2d/std/format.d#L4411
Comment #1 by bugzilla — 2021-04-21T18:03:17Z
IMHO, there is more about this: members of unions are only printed, if they are members of structs, but not stand alone unions. They are just formatted as their name.
I think, either, members of unions should always be printed (and then correctly) or not at all.
Comment #2 by robert.schadek — 2024-12-01T16:36:09Z