Skip to content

Commit b94053e

Browse files
authored
Merge pull request #88 from n8sh/insert-struct-init
Array.insert: don't dtor or opAssign uninitialized struct
2 parents 0ed30c2 + 00cddee commit b94053e

File tree

1 file changed

+34
-0
lines changed

1 file changed

+34
-0
lines changed

src/containers/dynamicarray.d

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,19 @@ struct DynamicArray(T, Allocator = Mallocator, bool supportGC = shouldAddGCRange
119119
GC.addRange(arr.ptr, arr.length * T.sizeof);
120120
}
121121
}
122+
import std.traits: hasElaborateAssign, hasElaborateDestructor;
123+
static if (is(T == struct) && (hasElaborateAssign!T || hasElaborateDestructor!T))
124+
{
125+
// If a destructor is run before blit or copying involves
126+
// more than just a blit, ensure that arr[l] is in a valid
127+
// state before assigning to it.
128+
import core.stdc.string : memcpy, memset;
129+
const init = typeid(T).initializer();
130+
if (init.ptr is null) // null pointer means initialize to 0s
131+
(() @trusted => memset(arr.ptr + l, 0, T.sizeof))();
132+
else
133+
(() @trusted => memcpy(arr.ptr + l, init.ptr, T.sizeof))();
134+
}
122135
arr[l++] = value;
123136
}
124137

@@ -455,3 +468,24 @@ unittest
455468
}
456469
assert(p is a[].ptr);
457470
}
471+
472+
unittest
473+
{
474+
// Ensure that Array.insert doesn't call the destructor for
475+
// a struct whose state is uninitialized memory.
476+
static struct S
477+
{
478+
int* a;
479+
~this() @nogc nothrow
480+
{
481+
if (a !is null)
482+
++(*a);
483+
}
484+
}
485+
int a = 0;
486+
DynamicArray!S arr;
487+
// This next line may segfault if destructors are called
488+
// on structs in invalid states.
489+
arr.insert(S(&a));
490+
assert(a == 1);
491+
}

0 commit comments

Comments
 (0)