D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 6874 - heap corruption caused by std.array.insertInPlaceImpl or gc.gcx
Summary: heap corruption caused by std.array.insertInPlaceImpl or gc.gcx
Status: RESOLVED FIXED
Alias: None
Product: D
Classification: Unclassified
Component: druntime (show other issues)
Version: D2
Hardware: Other Linux
: P2 normal
Assignee: No Owner
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-11-01 10:46 UTC by Nils
Modified: 2012-01-18 18:27 UTC (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description Nils 2011-11-01 10:46:08 UTC
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 Nils 2011-11-02 21:16:44 UTC
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.