aboutsummaryrefslogtreecommitdiff
path: root/libphobos/src/std/array.d
diff options
context:
space:
mode:
Diffstat (limited to 'libphobos/src/std/array.d')
-rw-r--r--libphobos/src/std/array.d59
1 files changed, 58 insertions, 1 deletions
diff --git a/libphobos/src/std/array.d b/libphobos/src/std/array.d
index acd5311..3313dbb 100644
--- a/libphobos/src/std/array.d
+++ b/libphobos/src/std/array.d
@@ -3639,6 +3639,7 @@ if (isDynamicArray!A)
}
else
{
+ import core.stdc.string : memcpy, memset;
// Time to reallocate.
// We need to almost duplicate what's in druntime, except we
// have better access to the capacity field.
@@ -3650,6 +3651,15 @@ if (isDynamicArray!A)
if (u)
{
// extend worked, update the capacity
+ // if the type has indirections, we need to zero any new
+ // data that we requested, as the existing data may point
+ // at large unused blocks.
+ static if (hasIndirections!T)
+ {
+ immutable addedSize = u - (_data.capacity * T.sizeof);
+ () @trusted { memset(_data.arr.ptr + _data.capacity, 0, addedSize); }();
+ }
+
_data.capacity = u / T.sizeof;
return;
}
@@ -3665,10 +3675,20 @@ if (isDynamicArray!A)
auto bi = (() @trusted => GC.qalloc(nbytes, blockAttribute!T))();
_data.capacity = bi.size / T.sizeof;
- import core.stdc.string : memcpy;
if (len)
() @trusted { memcpy(bi.base, _data.arr.ptr, len * T.sizeof); }();
+
_data.arr = (() @trusted => (cast(Unqual!T*) bi.base)[0 .. len])();
+
+ // we requested new bytes that are not in the existing
+ // data. If T has pointers, then this new data could point at stale
+ // objects from the last time this block was allocated. Zero that
+ // new data out, it may point at large unused blocks!
+ static if (hasIndirections!T)
+ () @trusted {
+ memset(bi.base + (len * T.sizeof), 0, (newlen - len) * T.sizeof);
+ }();
+
_data.tryExtendBlock = true;
// leave the old data, for safety reasons
}
@@ -4047,6 +4067,43 @@ if (isDynamicArray!A)
app2.toString();
}
+// https://issues.dlang.org/show_bug.cgi?id=24856
+@system unittest
+{
+ import core.memory : GC;
+ import std.stdio : writeln;
+ import std.algorithm.searching : canFind;
+ GC.disable();
+ scope(exit) GC.enable();
+ void*[] freeme;
+ // generate some poison blocks to allocate from.
+ auto poison = cast(void*) 0xdeadbeef;
+ foreach (i; 0 .. 10)
+ {
+ auto blk = new void*[7];
+ blk[] = poison;
+ freeme ~= blk.ptr;
+ }
+
+ foreach (p; freeme)
+ GC.free(p);
+
+ int tests = 0;
+ foreach (i; 0 .. 10)
+ {
+ Appender!(void*[]) app;
+ app.put(null);
+ // if not a realloc of one of the deadbeef pointers, continue
+ if (!freeme.canFind(app.data.ptr))
+ continue;
+ ++tests;
+ assert(!app.data.ptr[0 .. app.capacity].canFind(poison), "Appender not zeroing data!");
+ }
+ // just notify in the log whether this test actually could be done.
+ if (tests == 0)
+ writeln("WARNING: test of Appender zeroing did not occur");
+}
+
//Calculates an efficient growth scheme based on the old capacity
//of data, and the minimum requested capacity.
//arg curLen: The current length