Access violation using chain()

Brad Anderson eco at gnuk.net
Sun Apr 22 02:20:08 PDT 2012


On Thursday, 19 April 2012 at 16:19:05 UTC, Brad Anderson wrote:
> On Thu, Apr 19, 2012 at 7:25 AM, Christophe 
> <travert at 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



More information about the Digitalmars-d-learn mailing list