Possible bug in associative array implementation (and/or @safe checking)

Steven Schveighoffer schveiguy at gmail.com
Thu Aug 16 17:20:23 UTC 2018


On 8/16/18 12:51 PM, Aaron D. Trout wrote:
> Hello all! I'm a mathematician at Chatham University in Pittsburgh, PA 
> (USA). I use D for research, and I'm a frequent lurker on the forums. I 
> think I found a bug, but I want to make sure I'm not just doing 
> something silly. (I'm happy to file a bugzilla issue if it turns out to 
> be a legitimate and previously unknown bug.) Thanks in advance for the 
> feedback.
> 
> Tested on 64-bit linux, DMD 2.080.0 and LDC 1.9.0.
> 
> code:
> ---------------------------------------------------
> import std.range, std.algorithm, std.conv, std.stdio;
> 
> // return a newly constructed immutable static array
> immutable(int)[len] toImmutStaticArray(size_t len, R)(R range)
> {
>      int[len] r;
>      copy(range, r[]);
>      return r;
> }
> 
> void main() @safe
> {
>      int[int[]] aaHeapKeys;
>      int[int[]] aaStackKeys;
>      int[int[2]] aaStaticKeys;
> 
>      int[] setA = [2,3,5];
>      int[] setB = [2,4,3,9,5,25];
> 
>      // range of ranges: [[5, 25], [2, 4], [3, 9]]
>      auto sets = setA.map!(j => setB.filter!(i => i % j == 0));
> 
>      foreach(s; sets)
>      {
>          // insert using a slice of imuutable(int) on the heap as the key
>          auto heapSlice = s.array.idup;
>          aaHeapKeys[heapSlice] = 0;
> 
>          // insert using an identical slice of immutable(int) on the stack
>          // as the key
>          auto buffer = s.toImmutStaticArray!2;
>          auto stackSlice = buffer[0 .. s.walkLength];

Here is the problem. stackSlice is pointing to buffer. buffer's stack 
space is REUSED for each iteration through the loop, so it's going to 
change every time through the foreach. In essence, the current buffer 
goes out of scope and a new buffer is allocated in it's place.

In general, it's dangerous to have immutable pointer to stack data, 
because the stack will eventually go away and get reallocated, which 
makes the data not so immutable.

>          assert(stackSlice == heapSlice);
>          aaStackKeys[stackSlice] = 0;
> 
>          // insert using the static array buffer as key
>          aaStaticKeys[buffer] = 0;
>      }
> 
>      assert(aaHeapKeys   == [[5, 25]:0, [2, 4]:0, [3, 9]:0]); // OK
>      // assert(aaStackKeys  == [[5, 25]:0, [2, 4]:0, [3, 9]:0]); // FAILS!
>      assert(aaStaticKeys == [[5, 25]:0, [2, 4]:0, [3, 
> 9]:0].to!(int[int[2]])); // OK
> 
>      // Note that aaStackKeys seems corrupted. Printing out aaStackKeys
>      // gives: [[5, 25]:0, [5, 25]:0, [5, 25]:0]
>      // aaStackKeys.writeln;
> }

Yes, this is the effect I would expect.

D has traditionally simply allowed slicing stack data without question 
(even in @safe code), but that will change when dip1000 is fully 
realized. It will be allowed, but only when assigning to scope variables.

-Steve


More information about the Digitalmars-d-learn mailing list