Bug 6874 – heap corruption caused by std.array.insertInPlaceImpl or gc.gcx
Status
RESOLVED
Resolution
FIXED
Severity
normal
Priority
P2
Component
druntime
Product
D
Version
D2
Platform
Other
OS
Linux
Creation time
2011-11-01T10:46:00Z
Last change time
2012-01-18T18:27:00Z
Assigned to
nobody
Creator
nilsbossung
Comments
Comment #0 by nilsbossung — 2011-11-01T10:46:08Z
module test;
import std.array;
/* This should grow and shrink its -b- -n- times.
Instead, it pushes an array through the heap, nulling everything in its way,
because the involved functions keep thinking that the allocated block starts at
b.ptr while it is moving through the heap.
I can't say exactly which function is misbehaving, but I guess that one of
insertInPlace(), reallocNoSync(), findSize(), etc doesn't correctly handle
pointers that are not the base address of the allocated block. */
void berserk(size_t n) {
int[] b = [0];
foreach(i; 0 .. n) {
version(length_is_fine) {
b.length += 1;
} else {
b.insertInPlace(1, [0]);
}
b = b[1 .. $];
}
}
void main() {
int[] a = [1, 2, 3];
berserk(5);
assert(a == [1, 2, 3]); // fails
}
Comment #1 by nilsbossung — 2011-11-02T21:16:44Z
What happens is this: b.insertInPlaceImpl(...) does
realloc(b.ptr, newLength * b[0].sizeof), assuming that realloc will allocate
enough space to safely write newLength values from b.ptr on.
But realloc does not guarantee that as it compares the requested size with
the result of gcx.findSize(b.ptr) to determine if it needs to allocate,
and gcx.findSize returns the size of the full block the pointer is in,
not of the space behind it. And b = [1 .. $]; moves b.ptr into the allocated
block.