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

Reply via email to