Thread overview
ranges reading garbage
Feb 15, 2015
John Colvin
Feb 15, 2015
bearophile
Feb 15, 2015
FG
Feb 15, 2015
bearophile
Feb 15, 2015
John Colvin
Feb 15, 2015
anonymous
Feb 15, 2015
anonymous
Feb 16, 2015
anonymous
February 15, 2015
Simplified from something bigger:

import std.range, std.algorithm, std.stdio;

void foo(float[] data, float[] xs, float[] ys)
{
    auto indices = iota(0, data.length, ys.length)
        .map!(xBase =>
                iota(xBase, xBase + ys.length - 1)
                .map!(y =>
                    only(y, y+ys.length, y+ys.length+1, y+1))
                .joiner())
        .joiner();
    writeln(indices);
}

void main()
{
    foo([1,2,3,4,5,6,7,8],
            [0.1,0.2], [10,20,30,40]);
}

prints things like [0, 4, 5, 1, 1, 1459971595, 1459971596, 2, 2, 1459971596, 1459971597, 3, 4, 8, 9, 5, 5, 4441427819, 4441427820, 6, 6, 4441427820, 4441427821, 7] but the output isn't consistent, the big numbers change on each run.
February 15, 2015
John Colvin:

> prints things like [0, 4, 5, 1, 1, 1459971595, 1459971596, 2, 2, 1459971596, 1459971597, 3, 4, 8, 9, 5, 5, 4441427819, 4441427820, 6, 6, 4441427820, 4441427821, 7] but the output isn't consistent, the big numbers change on each run.

Try to replace the only() with:

[y, y+ys.length, y+ys.length+1, y+1]

Like this:


import std.range, std.algorithm, std.stdio;

void foo(in float[] data, in float[] xs, in float[] ys) @safe {
    iota(0, data.length, ys.length)
    .map!(xBase => iota(xBase, xBase + ys.length - 1)
                   .map!(y => [y, y+ys.length, y+ys.length+1, y+1])
                   .joiner)
    .joiner
    .writeln;
}

void main() {
    foo([1,2,3,4,5,6,7,8], [0.1,0.2], [10,20,30,40]);
}



In Rust the compiler enforces that all stack-allocated data doesn't come from dead stack frames. In D you have to be careful to avoid doing it. In future this kind of bugs will be hopefully avoided by a better tracking of the memory.

I am not sure if http://wiki.dlang.org/DIP69 is able to avoid this bug, if it can't, then DIP69 needs to be improved.

Bye,
bearophile
February 15, 2015
On 2015-02-15 at 19:43, bearophile wrote:
> void foo(in float[] data, in float[] xs, in float[] ys) @safe {
>      iota(0, data.length, ys.length)
>      .map!(xBase => iota(xBase, xBase + ys.length - 1)
>                     .map!(y => [y, y+ys.length, y+ys.length+1, y+1])
>                     .joiner)
>      .joiner
>      .writeln;
> }
>
> void main() {
>      foo([1,2,3,4,5,6,7,8], [0.1,0.2], [10,20,30,40]);
> }

Odd... Still something is wrong. It prints:
[0, 4, 5, 1, 1, 5, 6, 2, 2, 6, 7, 3, 4, 8, 9, 5, 5, 5, 6, 6, 6, 6, 7, 7]

instead of this:
[0, 4, 5, 1, 1, 5, 6, 2, 2, 6, 7, 3, 4, 8, 9, 5, 5, 9, 10, 6, 6, 10, 11, 7]
February 15, 2015
On Sunday, 15 February 2015 at 18:43:35 UTC, bearophile wrote:
> John Colvin:
>
>> prints things like [0, 4, 5, 1, 1, 1459971595, 1459971596, 2, 2, 1459971596, 1459971597, 3, 4, 8, 9, 5, 5, 4441427819, 4441427820, 6, 6, 4441427820, 4441427821, 7] but the output isn't consistent, the big numbers change on each run.
>
> Try to replace the only() with:
>
> [y, y+ys.length, y+ys.length+1, y+1]
>
> Like this:
>
>
> import std.range, std.algorithm, std.stdio;
>
> void foo(in float[] data, in float[] xs, in float[] ys) @safe {
>     iota(0, data.length, ys.length)
>     .map!(xBase => iota(xBase, xBase + ys.length - 1)
>                    .map!(y => [y, y+ys.length, y+ys.length+1, y+1])
>                    .joiner)
>     .joiner
>     .writeln;
> }
>
> void main() {
>     foo([1,2,3,4,5,6,7,8], [0.1,0.2], [10,20,30,40]);
> }
>
>
>
> In Rust the compiler enforces that all stack-allocated data doesn't come from dead stack frames. In D you have to be careful to avoid doing it. In future this kind of bugs will be hopefully avoided by a better tracking of the memory.
>
> I am not sure if http://wiki.dlang.org/DIP69 is able to avoid this bug, if it can't, then DIP69 needs to be improved.
>
> Bye,
> bearophile

But std.range.OnlyResult!(size_t, 4) is a value type, I don't see where the stack reference is being leaked.
February 15, 2015
FG:

> Odd... Still something is wrong. It prints:
> [0, 4, 5, 1, 1, 5, 6, 2, 2, 6, 7, 3, 4, 8, 9, 5, 5, 5, 6, 6, 6, 6, 7, 7]
>
> instead of this:
> [0, 4, 5, 1, 1, 5, 6, 2, 2, 6, 7, 3, 4, 8, 9, 5, 5, 9, 10, 6, 6, 10, 11, 7]

This is less lazy and gives another result:

import std.range, std.algorithm, std.stdio;

void foo(in float[] data, in float[] xs, in float[] ys) @safe {
    iota(0, data.length, ys.length)
    .map!(xBase => iota(xBase, xBase + ys.length - 1)
                   .map!(y => [y, y+ys.length, y+ys.length+1, y+1])
                   .join)
    .join
    .writeln;
}

void main() {
    foo([1,2,3,4,5,6,7,8], [0.1,0.2], [10,20,30,40]);
}


What a fun program :-)

Bye,
bearophile
February 15, 2015
On Sunday, 15 February 2015 at 18:13:44 UTC, John Colvin wrote:
> Simplified from something bigger:
>
> import std.range, std.algorithm, std.stdio;
>
> void foo(float[] data, float[] xs, float[] ys)
> {
>     auto indices = iota(0, data.length, ys.length)
>         .map!(xBase =>
>                 iota(xBase, xBase + ys.length - 1)
>                 .map!(y =>
>                     only(y, y+ys.length, y+ys.length+1, y+1))
>                 .joiner())
>         .joiner();
>     writeln(indices);
> }
>
> void main()
> {
>     foo([1,2,3,4,5,6,7,8],
>             [0.1,0.2], [10,20,30,40]);
> }
>
> prints things like [0, 4, 5, 1, 1, 1459971595, 1459971596, 2, 2, 1459971596, 1459971597, 3, 4, 8, 9, 5, 5, 4441427819, 4441427820, 6, 6, 4441427820, 4441427821, 7] but the output isn't consistent, the big numbers change on each run.

Reduced some more:

import std.algorithm, std.stdio;
void main()
{
    int ys_length = 4;
    auto indices = [0]
        .map!(xBase => [0].map!(y => ys_length))
        .joiner();
    writeln(indices);
}
February 15, 2015
On Sunday, 15 February 2015 at 19:54:45 UTC, anonymous wrote:
> Reduced some more:
>
> import std.algorithm, std.stdio;
> void main()
> {
>     int ys_length = 4;
>     auto indices = [0]
>         .map!(xBase => [0].map!(y => ys_length))
>         .joiner();
>     writeln(indices);
> }

And more:

import std.stdio;
struct MapResult(alias fun)
{
    @property int front() {return fun();}
    @property auto save() {return typeof(this)();}
}
void main()
{
    int ys_length = 4;
    auto dg = {return MapResult!({return ys_length;})();};
    writeln(dg().front); /* 4, correct */
    writeln(dg().save.front); /* garbage */
}
February 16, 2015
On Sunday, 15 February 2015 at 22:38:20 UTC, anonymous wrote:
> And more:
>
> import std.stdio;
> struct MapResult(alias fun)
> {
>     @property int front() {return fun();}
>     @property auto save() {return typeof(this)();}
> }
> void main()
> {
>     int ys_length = 4;
>     auto dg = {return MapResult!({return ys_length;})();};
>     writeln(dg().front); /* 4, correct */
>     writeln(dg().save.front); /* garbage */
> }

It's already in bugzilla: https://issues.dlang.org/show_bug.cgi?id=9685