February 04, 2016
https://issues.dlang.org/show_bug.cgi?id=15645

          Issue ID: 15645
           Summary: Tuple.slice() causes memory corruption.
           Product: D
           Version: D2
          Hardware: x86_64
               URL: http://forum.dlang.org/thread/ctpsgcekdbwmlsayonqs@for
                    um.dlang.org
                OS: Linux
            Status: NEW
          Severity: major
          Priority: P1
         Component: phobos
          Assignee: nobody@puremagic.com
          Reporter: Marco.Leise@gmx.de

Good thing we have @trusted to mark suspicious memory operations that are actually safe. When it covers a bug that @safe would have caught though, it leaves a bad taste...

First let's look at the implementation:

    @property
    ref Tuple!(sliceSpecs!(from, to)) slice(size_t from, size_t to)() @trusted
    if (from <= to && to <= Types.length)
    {
        return *cast(typeof(return)*) &(field[from]);
    }

To return a slice into the tuple, a pointer to the new first is reinterpreted as the new tuple type. This mirrors the effect of slicing an array, just that tuples are actually structs and that causes a serious problem. Consider we slice off the first element of the following tuple and compare the relative offsets of the 2nd and 3rd field respectively:

    pragma(msg, Tuple!(int, bool, string)._2.offsetof - Tuple!(int, bool,
string)._1.offsetof);
    pragma(msg, Tuple!(     bool, string)._1.offsetof - Tuple!(     bool,
string)._0.offsetof);

This prints:

    4LU
    8LU

So the relative offset of the string part moved which causes memory corruption when slice() reinterprets pointers. More visually the layout on amd64 is:

                           0   4   8
Tuple!(int, bool, string): int boolstring
                               0   4   8
         Tuple!(bool, string): bool    string

The memory adresses of the boolean field match, but the string moves due to its alignment constraints.

--