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

Commit 1c74ef3

Browse files
committed
Fix potential memory corruption
As the union version casts away any const/immutable qualifiers in @trusted code.
1 parent 24269b8 commit 1c74ef3

File tree

1 file changed

+59
-19
lines changed

1 file changed

+59
-19
lines changed

src/core/internal/lifetime.d

Lines changed: 59 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -89,39 +89,79 @@ Emplaces T.init.
8989
In contrast to `emplaceRef(chunk)`, there are no checks for disabled default
9090
constructors etc.
9191
+/
92-
nothrow pure @trusted
93-
void emplaceInitializer(T)(scope ref T chunk)
92+
void emplaceInitializer(T)(scope ref T chunk) nothrow pure @trusted
93+
if (!is(T == const) && !is(T == immutable) && !is(T == inout))
9494
{
9595
import core.internal.traits : hasElaborateAssign;
9696

9797
static if (!hasElaborateAssign!T && __traits(compiles, chunk = T.init))
9898
{
9999
chunk = T.init;
100100
}
101+
else static if (__traits(isZeroInit, T))
102+
{
103+
static if (is(T U == shared U))
104+
alias Unshared = U;
105+
else
106+
alias Unshared = T;
107+
108+
import core.stdc.string : memset;
109+
memset(cast(Unshared*) &chunk, 0, T.sizeof);
110+
}
101111
else
102112
{
103-
static if (__traits(isZeroInit, T))
104-
{
105-
static if (is(T U == shared U))
106-
alias Unshared = U;
107-
else
108-
alias Unshared = T;
113+
// emplace T.init (an rvalue) without extra variable (and according destruction)
114+
alias RawBytes = void[T.sizeof];
109115

110-
import core.stdc.string : memset;
111-
memset(cast(Unshared*) &chunk, 0, T.sizeof);
116+
static union U
117+
{
118+
T dummy = T.init; // U.init corresponds to T.init
119+
RawBytes data;
112120
}
113-
else
121+
122+
*cast(RawBytes*) &chunk = U.init.data;
123+
}
124+
}
125+
126+
@safe unittest
127+
{
128+
static void testInitializer(T)()
129+
{
130+
// mutable T
114131
{
115-
// emplace T.init (an rvalue) without extra variable (and according destruction)
116-
alias RawBytes = void[T.sizeof];
132+
T dst = void;
133+
emplaceInitializer(dst);
134+
assert(dst is T.init);
135+
}
117136

118-
static union U
119-
{
120-
T dummy = T.init; // U.init corresponds to T.init
121-
RawBytes data;
122-
}
137+
// shared T
138+
{
139+
shared T dst = void;
140+
emplaceInitializer(dst);
141+
assert(dst is shared(T).init);
142+
}
123143

124-
*cast(RawBytes*) &chunk = U.init.data;
144+
// const T
145+
{
146+
const T dst = void;
147+
static assert(!__traits(compiles, emplaceInitializer(dst)));
125148
}
126149
}
150+
151+
static struct ElaborateAndZero
152+
{
153+
int a;
154+
this(this) {}
155+
}
156+
157+
static struct ElaborateAndNonZero
158+
{
159+
int a = 42;
160+
this(this) {}
161+
}
162+
163+
testInitializer!int();
164+
testInitializer!double();
165+
testInitializer!ElaborateAndZero();
166+
testInitializer!ElaborateAndNonZero();
127167
}

0 commit comments

Comments
 (0)