View mode: basic / threaded / horizontal-split · Log in · Help
April 19, 2012
Access violation using chain()
Perhaps I'm just misunderstanding something about closures but 
the following code seems to behave oddly:

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

    void main()
    {
        auto lst = ["a", "b"];
        auto rng = range_gen(lst);
        writeln(rng.take(5));
    }
    auto range_gen(string[] lst)
    {
        auto a = sequence!"n+1"().map!(a=>format("%s%d", lst[0], 
a))();
        return chain(lst, a); // access violation
        //return a; // works
    }

Returning with the chain() gives an access violation after the 
writeln has processed the first two elements and gets to the 
elements generated by map(sequence()) (the output is '["a", "b", 
').  If I just return the map(sequence()) it works correctly.  If 
I don't use lst[0] in the map and instead use a literal it works 
without issue.  It also works without issue if I use a global in 
place of lst[0].

I can work around this. Moving the chain() outside to the calling 
function seems to work fine but I was making using of ResultOf to 
type a member variable which is why I had the function in the 
first place (I can manually type it but it's pretty ugly).

Regards,
Brad Anderson
April 19, 2012
Re: Access violation using chain()
"Brad Anderson" , dans le message (digitalmars.D.learn:34902), a écrit :
> Perhaps I'm just misunderstanding something about closures but 
> the following code seems to behave oddly:
> 
>      import std.stdio, std.range, std.algorithm, std.string;
> 
>      void main()
>      {
>          auto lst = ["a", "b"];
>          auto rng = range_gen(lst);
>          writeln(rng.take(5));
>      }
>      auto range_gen(string[] lst)
>      {
>          auto a = sequence!"n+1"().map!(a=>format("%s%d", lst[0], 
> a))();
>          return chain(lst, a); // access violation
>          //return a; // works
>      }

My guess is that chain takes lst by reference, just like the delegates 
for map, wo both are working on the same slice instance. The chain first 
pops elements from lst, and then calls the mapped sequence. At that 
time, lst is empty.

You can just copy lst before you give it to chain (or to map's delegate) 
to solve this bug:

auto range_gen(string[] lst)
{
    auto a = sequence!"n+1"().map!(a=>format("%s%d", lst[0], a))();
    string[] lst2 = lst;
    return chain(lst2, a); // access violation
}
April 19, 2012
Re: Access violation using chain()
On Thu, Apr 19, 2012 at 7:25 AM, Christophe <travert@phare.normalesup.org>wrote:

> "Brad Anderson" , dans le message (digitalmars.D.learn:34902), a écrit :
> > Perhaps I'm just misunderstanding something about closures but
> > the following code seems to behave oddly:
> >
> >      import std.stdio, std.range, std.algorithm, std.string;
> >
> >      void main()
> >      {
> >          auto lst = ["a", "b"];
> >          auto rng = range_gen(lst);
> >          writeln(rng.take(5));
> >      }
> >      auto range_gen(string[] lst)
> >      {
> >          auto a = sequence!"n+1"().map!(a=>format("%s%d", lst[0],
> > a))();
> >          return chain(lst, a); // access violation
> >          //return a; // works
> >      }
>
> My guess is that chain takes lst by reference, just like the delegates
> for map, wo both are working on the same slice instance. The chain first
> pops elements from lst, and then calls the mapped sequence. At that
> time, lst is empty.
>
> You can just copy lst before you give it to chain (or to map's delegate)
> to solve this bug:
>
> auto range_gen(string[] lst)
> {
>     auto a = sequence!"n+1"().map!(a=>format("%s%d", lst[0], a))();
>      string[] lst2 = lst;
>     return chain(lst2, a); // access violation
> }
>
>
Ah, that would make sense.  I'll test and make sure when I get home. Range
consumption tricks me more often than I wish.  I'll eventually learn to
look out for it more actively.

Regards,
Brad Anderson
April 22, 2012
Re: Access violation using chain()
On Thursday, 19 April 2012 at 16:19:05 UTC, Brad Anderson wrote:
> On Thu, Apr 19, 2012 at 7:25 AM, Christophe 
> <travert@phare.normalesup.org>wrote:
>
>> "Brad Anderson" , dans le message (digitalmars.D.learn:34902), 
>> a écrit :
>> > Perhaps I'm just misunderstanding something about closures 
>> > but
>> > the following code seems to behave oddly:
>> >
>> >      import std.stdio, std.range, std.algorithm, std.string;
>> >
>> >      void main()
>> >      {
>> >          auto lst = ["a", "b"];
>> >          auto rng = range_gen(lst);
>> >          writeln(rng.take(5));
>> >      }
>> >      auto range_gen(string[] lst)
>> >      {
>> >          auto a = sequence!"n+1"().map!(a=>format("%s%d", 
>> > lst[0],
>> > a))();
>> >          return chain(lst, a); // access violation
>> >          //return a; // works
>> >      }
>>
>> My guess is that chain takes lst by reference, just like the 
>> delegates
>> for map, wo both are working on the same slice instance. The 
>> chain first
>> pops elements from lst, and then calls the mapped sequence. At 
>> that
>> time, lst is empty.
>>
>> You can just copy lst before you give it to chain (or to map's 
>> delegate)
>> to solve this bug:
>>
>> auto range_gen(string[] lst)
>> {
>>     auto a = sequence!"n+1"().map!(a=>format("%s%d", lst[0], 
>> a))();
>>      string[] lst2 = lst;
>>     return chain(lst2, a); // access violation
>> }
>>
>>
> Ah, that would make sense.  I'll test and make sure when I get 
> home. Range
> consumption tricks me more often than I wish.  I'll eventually 
> learn to
> look out for it more actively.
>
> Regards,
> Brad Anderson

Ok, so this wasn't the problem.  I have no idea what the problem 
is.  Using string[] lst = list; doesn't help nor does lst.save.  
I can get some really weird behavior messing around with this.  
Access violations that appear or disappear when symbolic debug 
info is enabled.  Here's an example of a weird one:

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

    void main()
    {
        writeln(gen(["a", "b"]).take(5));
    }

    auto gen(string[] lst)
    {
        auto prefix = lst[0];
        auto a = iota(10).map!(a=>format("%s%d", prefix, a))();
        //auto a = sequence!"n+1"().map!(a=>format("%s%d", 
prefix, a))();
        return chain(lst.save, a);
    }


Compiling that using DMD 2.059 without -g results in a UTF 
exception (memory corruption?) after outputting ["a", "b",. 
Compiling with -g produces no exception but the output is 
incorrect (["a", "b", "0", "1", "2"] should be ["a", "b", "a0", 
"a1", "a2"]).  Now, if you replace the iota line with with the 
commented out sequence line it works the other way. Without -g 
gives no exception (but correct output this time), with -g 
results in a UTF exception. It's a bit unsettling that adding 
debug info can change the behavior of the program.

I suppose this makes this a bug but I'm not sure what I'd call 
it.  Is it a bug with chain() or with closures?  Is the symbolic 
debug information differences a different bug?

Regards,
Brad Anderson
Top | Discussion index | About this forum | D home