The Array.Payload.length setter calls realloc() when length increases, but doesn't call GC.removeRange and GC.addRange. When data in the array contains pointers to some managed objects, GC may collect those objects and now we have dangling pointers in the array, which later causes Access Violations. The following program crashes on 2.066: module main; import std.stdio, std.container.array, core.memory; class C { void hi() { writeln("hi"); } } void main(string[] argv) { Array!C arr; enum N = 10; //arr.reserve(N); // uncomment this and it will work fine arr.length = N; foreach(ref x; arr) x = new C; // create N objects GC.collect(); // do a GC arr[1].hi(); // now this object is dead! }
Right, the realloc in length(size_t) should be replaced with similar code to reserve, i.e.: static if (hasIndirections!T) // use malloc/copy/free along with GC.addRange & GC.removeRange else // use realloc
Commits pushed to master at https://github.com/dlang/phobos https://github.com/dlang/phobos/commit/e837813478298593fdb2799e5af99b40a3ccb7b3 Fix issue 13642 - Change of length reallocates without notifying GC https://github.com/dlang/phobos/commit/997464b4b2a4a0af0fd6eeef1a9b3770c54762b9 Merge pull request #4885 from rjframe/arraymem Fix issue 13642 - Change of length reallocates without notifying GC merged-on-behalf-of: Jack Stouffer <jack@jackstouffer.com>