From 9194e62ee18126b74e947d751c6936836ac5fead Mon Sep 17 00:00:00 2001 From: Saurabh Das Date: Fri, 5 Feb 2016 17:48:09 +0530 Subject: [PATCH 1/3] Fix issue 15645 - Tuple.slice() causes memory corruption This approach fixes the issue without changing the layout of the tuple. Changes that need consideration: 1. Return type of Tuple.slice - 'ref' removed. Does this affect how Tuple.slice() is expected to behave? --- std/typecons.d | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/std/typecons.d b/std/typecons.d index d13aee40608..40540ab1827 100644 --- a/std/typecons.d +++ b/std/typecons.d @@ -740,10 +740,10 @@ template Tuple(Specs...) * the original. */ @property - ref Tuple!(sliceSpecs!(from, to)) slice(size_t from, size_t to)() @trusted + Tuple!(sliceSpecs!(from, to)) slice(size_t from, size_t to)() @safe const if (from <= to && to <= Types.length) { - return *cast(typeof(return)*) &(field[from]); + return typeof(return)(field[from .. to]); } /// @@ -755,6 +755,14 @@ template Tuple(Specs...) auto s = a.slice!(1, 3); static assert(is(typeof(s) == Tuple!(string, float))); assert(s[0] == "abc" && s[1] == 4.5); + + // Phobos issue #15645 + Tuple!(int, int, long) b; + b[1] = 42; + b[2] = 101; + auto t = b.slice!(1, 3); + static assert(is(typeof(t) == Tuple!(int, long))); + assert(t[0] == 42 && t[1] == 102); } /** From 0d5f2c8abb779b298f3776657dc0ad7e1640405a Mon Sep 17 00:00:00 2001 From: Saurabh Das Date: Sat, 6 Feb 2016 10:53:51 +0530 Subject: [PATCH 2/3] Make Tuple.slice() work with inout --- std/typecons.d | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/std/typecons.d b/std/typecons.d index 40540ab1827..14a50be8df1 100644 --- a/std/typecons.d +++ b/std/typecons.d @@ -740,14 +740,14 @@ template Tuple(Specs...) * the original. */ @property - Tuple!(sliceSpecs!(from, to)) slice(size_t from, size_t to)() @safe const + inout(Tuple!(sliceSpecs!(from, to))) slice(size_t from, size_t to)() inout if (from <= to && to <= Types.length) { - return typeof(return)(field[from .. to]); + return Tuple!(sliceSpecs!(from, to))(field[from .. to]); } /// - unittest + @safe unittest { Tuple!(int, string, float, double) a; a[1] = "abc"; @@ -755,14 +755,6 @@ template Tuple(Specs...) auto s = a.slice!(1, 3); static assert(is(typeof(s) == Tuple!(string, float))); assert(s[0] == "abc" && s[1] == 4.5); - - // Phobos issue #15645 - Tuple!(int, int, long) b; - b[1] = 42; - b[2] = 101; - auto t = b.slice!(1, 3); - static assert(is(typeof(t) == Tuple!(int, long))); - assert(t[0] == 42 && t[1] == 102); } /** @@ -991,6 +983,24 @@ private template ReverseTupleType(T) alias ReverseTupleType = Tuple!(ReverseTupleSpecs!A); } +/* Phobos issue #15645: Tuple.slice() causes memory corruption + https://issues.dlang.org/show_bug.cgi?id=15645 */ +@safe unittest +{ + Tuple!(int, int, long) b; + b[1] = 42; + b[2] = 101; + auto t = b.slice!(1, 3); + static assert(is(typeof(t) == Tuple!(int, long))); + assert(t[0] == 42 && t[1] == 102); + + const auto c = tuple!("a", "b", "c")(42, true, "somestring"); + auto u = c.slice!(1, 3); + static assert(is(typeof(u) == const(Tuple!(bool, "b", string, "c")))); + assert(c.b == true && c.c == "somestring"); +} + + /* Reverse the Specs of a Tuple. */ private template ReverseTupleSpecs(T...) { From 0f8d900152e8652d3ac5bf696439d9d19ccb2b5e Mon Sep 17 00:00:00 2001 From: Saurabh Das Date: Sat, 6 Feb 2016 11:01:01 +0530 Subject: [PATCH 3/3] Tuple.slice() - Use 'expand' instead of 'field' --- std/typecons.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/typecons.d b/std/typecons.d index 14a50be8df1..02d7a8860f5 100644 --- a/std/typecons.d +++ b/std/typecons.d @@ -743,7 +743,7 @@ template Tuple(Specs...) inout(Tuple!(sliceSpecs!(from, to))) slice(size_t from, size_t to)() inout if (from <= to && to <= Types.length) { - return Tuple!(sliceSpecs!(from, to))(field[from .. to]); + return Tuple!(sliceSpecs!(from, to))(expand[from .. to]); } ///