Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.

Commit c5ff8be

Browse files
MoonlightSentineldlang-bot
authored andcommitted
Fix 21983 - Initialize remaining elements in a partially dup'ed array...
... if postblit/copy ctor throws This ensures deterministic behaviour in case of an exception and avoids dtor calls on uninitialized elements.
1 parent 60a2149 commit c5ff8be

1 file changed

Lines changed: 74 additions & 1 deletion

File tree

src/object.d

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3514,7 +3514,15 @@ private U[] _dup(T, U)(T[] a) if (!__traits(isPOD, T))
35143514
import core.lifetime: copyEmplace;
35153515
U[] res = () @trusted {
35163516
auto arr = cast(U*) _d_newarrayU(typeid(T[]), a.length);
3517-
foreach (i; 0..a.length)
3517+
size_t i;
3518+
scope (failure)
3519+
{
3520+
import core.internal.lifetime: emplaceInitializer;
3521+
// Initialize all remaining elements to not destruct garbage
3522+
foreach (j; i .. a.length)
3523+
emplaceInitializer(cast() arr[j]);
3524+
}
3525+
for (; i < a.length; i++)
35183526
{
35193527
copyEmplace(a.ptr[i], arr[i]);
35203528
}
@@ -3932,6 +3940,71 @@ private void _doPostblit(T)(T[] arr)
39323940
auto a = arr.dup; // dup does escape
39333941
}
39343942

3943+
// https://issues.dlang.org/show_bug.cgi?id=21983
3944+
// dup/idup destroys partially constructed arrays on failure
3945+
@safe unittest
3946+
{
3947+
static struct SImpl(bool postblit)
3948+
{
3949+
int num;
3950+
long l = 0xDEADBEEF;
3951+
3952+
static if (postblit)
3953+
{
3954+
this(this)
3955+
{
3956+
if (this.num == 3)
3957+
throw new Exception("");
3958+
}
3959+
}
3960+
else
3961+
{
3962+
this(scope ref const SImpl other)
3963+
{
3964+
if (other.num == 3)
3965+
throw new Exception("");
3966+
3967+
this.num = other.num;
3968+
this.l = other.l;
3969+
}
3970+
}
3971+
3972+
~this() @trusted
3973+
{
3974+
if (l != 0xDEADBEEF)
3975+
{
3976+
import core.stdc.stdio;
3977+
printf("Unexpected value: %lld\n", l);
3978+
fflush(stdout);
3979+
assert(false);
3980+
}
3981+
}
3982+
}
3983+
3984+
alias Postblit = SImpl!true;
3985+
alias Copy = SImpl!false;
3986+
3987+
static int test(S)()
3988+
{
3989+
S[4] arr = [ S(1), S(2), S(3), S(4) ];
3990+
try
3991+
{
3992+
arr.dup();
3993+
assert(false);
3994+
}
3995+
catch (Exception)
3996+
{
3997+
return 1;
3998+
}
3999+
}
4000+
4001+
static assert(test!Postblit());
4002+
assert(test!Postblit());
4003+
4004+
static assert(test!Copy());
4005+
assert(test!Copy());
4006+
}
4007+
39354008
/**
39364009
Destroys the given object and optionally resets to initial state. It's used to
39374010
_destroy an object, calling its destructor or finalizer so it no longer

0 commit comments

Comments
 (0)