Skip to content

Commit ade2df1

Browse files
committed
[silgen] Fix SILGenBuilder::emitDestructureValueOperation to create all sub-ManagedValues before invoking the user defined function.
This is necessary since our func may want to emit conditional code with an early exit, emitting unused cleanups from the current scope via the function emitBranchAndCleanups(). If we have not yet created those cleanups, we will introduce a leak along that path. rdar://49990484
1 parent 2022b5c commit ade2df1

File tree

3 files changed

+97
-4
lines changed

3 files changed

+97
-4
lines changed

lib/SILGen/SILGenBuilder.cpp

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -819,10 +819,21 @@ void SILGenBuilder::emitDestructureValueOperation(
819819
SILLocation loc, ManagedValue value,
820820
llvm::function_ref<void(unsigned, ManagedValue)> func) {
821821
CleanupCloner cloner(*this, value);
822-
emitDestructureValueOperation(loc, value.forward(SGF),
823-
[&](unsigned index, SILValue subValue) {
824-
return func(index, cloner.clone(subValue));
825-
});
822+
823+
// NOTE: We can not directly use SILBuilder::emitDestructureValueOperation()
824+
// here since we need to create all of our cleanups before invoking \p
825+
// func. This is necessary since our func may want to emit conditional code
826+
// with an early exit, emitting unused cleanups from the current scope via the
827+
// function emitBranchAndCleanups(). If we have not yet created those
828+
// cleanups, we will introduce a leak along that path.
829+
SmallVector<ManagedValue, 8> destructuredValues;
830+
emitDestructureValueOperation(
831+
loc, value.forward(SGF), [&](unsigned index, SILValue subValue) {
832+
destructuredValues.push_back(cloner.clone(subValue));
833+
});
834+
for (auto p : llvm::enumerate(destructuredValues)) {
835+
func(p.index(), p.value());
836+
}
826837
}
827838

828839
ManagedValue SILGenBuilder::createProjectBox(SILLocation loc, ManagedValue mv,

test/Interpreter/switch.swift

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,4 +237,49 @@ SwitchTestSuite.test("Protocol Conformance Check Leaks") {
237237
}
238238
}
239239

240+
SwitchTestSuite.test("Enum Initialization Leaks") {
241+
enum Enum1 {
242+
case case1(LifetimeTracked)
243+
case case2(LifetimeTracked, Int)
244+
}
245+
246+
enum Enum2 {
247+
case case1(LifetimeTracked)
248+
case case2(Enum1, LifetimeTracked)
249+
}
250+
251+
struct Struct {
252+
var value: Enum2 = .case2(.case1(LifetimeTracked(0)), LifetimeTracked(1))
253+
254+
func doSomethingIfLet() {
255+
if case let .case2(.case2(k, _), _) = value {
256+
return
257+
}
258+
}
259+
260+
func doSomethingSwitch() {
261+
switch value {
262+
case let .case2(.case2(k, _), _):
263+
return
264+
default:
265+
return
266+
}
267+
return
268+
}
269+
270+
func doSomethingGuardLet() {
271+
guard case let .case2(.case2(k, _), _) = value else {
272+
return
273+
}
274+
}
275+
}
276+
277+
do {
278+
let s = Struct()
279+
s.doSomethingIfLet()
280+
s.doSomethingSwitch()
281+
s.doSomethingGuardLet()
282+
}
283+
}
284+
240285
runAllTests()

test/SILGen/switch.swift

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1583,3 +1583,40 @@ enum Storage {
15831583
}
15841584
}
15851585

1586+
// Make sure that we do not leak tuple elements if we fail to match the first
1587+
// tuple element.
1588+
enum rdar49990484Enum1 {
1589+
case case1(Klass)
1590+
case case2(Klass, Int)
1591+
}
1592+
1593+
enum rdar49990484Enum2 {
1594+
case case1(Klass)
1595+
case case2(rdar49990484Enum1, Klass)
1596+
}
1597+
1598+
struct rdar49990484Struct {
1599+
var value: rdar49990484Enum2
1600+
1601+
func doSomethingIfLet() {
1602+
if case let .case2(.case2(k, _), _) = value {
1603+
return
1604+
}
1605+
}
1606+
1607+
func doSomethingSwitch() {
1608+
switch value {
1609+
case let .case2(.case2(k, _), _):
1610+
return
1611+
default:
1612+
return
1613+
}
1614+
return
1615+
}
1616+
1617+
func doSomethingGuardLet() {
1618+
guard case let .case2(.case2(k, _), _) = value else {
1619+
return
1620+
}
1621+
}
1622+
}

0 commit comments

Comments
 (0)