January 05, 2020
https://issues.dlang.org/show_bug.cgi?id=20482

          Issue ID: 20482
           Summary: formatValue overlap detection does not account for
                    nested anonymous unions
           Product: D
           Version: D2
          Hardware: All
                OS: All
            Status: NEW
          Keywords: safe
          Severity: normal
          Priority: P1
         Component: phobos
          Assignee: nobody@puremagic.com
          Reporter: dkorpel@live.nl

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

--