Skip to content

Commit 9c9787a

Browse files
committed
SILGen: Fix double-free of __owned parameters of functions with @_backDeploy.
The following program crashed when compiled with the Swift 5.7 and 5.8 compilers: ``` @available(macOS 12, *) @_backDeploy(before: macOS 99) public func foo<T>(_ t: __owned T) { print("foo") } class C { deinit { print("deinit") } } foo(C()) print("done") ``` ``` > ./test foo deinit [1] 49162 segmentation fault ./test ``` The root cause is that generated SIL for the back deployment thunk for `foo(_:)` included its own `destroy_addr` instruction for the value of `t`, but didn't copy the parameter before passing it to the real function implementation which also destroys the value. The fix is to forward ownership of the parameter values to the called function, which causes cleanup generation to be skipped. Resolves rdar://104436515
1 parent 14ed022 commit 9c9787a

File tree

3 files changed

+67
-17
lines changed

3 files changed

+67
-17
lines changed

lib/SILGen/SILGenBackDeploy.cpp

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -176,20 +176,28 @@ void SILGenFunction::emitBackDeploymentThunk(SILDeclRef thunk) {
176176

177177
F.setGenericEnvironment(SGM.Types.getConstantGenericEnvironment(thunk));
178178

179-
emitBasicProlog(FD->getParameters(), FD->getImplicitSelfDecl(),
180-
FD->getResultInterfaceType(), FD, FD->hasThrows(),
181-
FD->getThrowsLoc());
182-
prepareEpilog(FD->getResultInterfaceType(), FD->hasThrows(),
183-
CleanupLocation(FD));
179+
// Generate the thunk prolog by collecting parameters.
180+
SmallVector<ManagedValue, 4> params;
181+
SmallVector<SILArgument *, 4> indirectParams;
182+
collectThunkParams(loc, params, &indirectParams);
184183

185-
// Gather the entry block's arguments up so that we can forward them.
184+
// Build up the list of arguments that we're going to invoke the the real
185+
// function with.
186186
SmallVector<SILValue, 8> paramsForForwarding;
187-
SILBasicBlock *entryBlock = getFunction().getEntryBlock();
188-
for (SILArgument *arg :
189-
make_range(entryBlock->args_begin(), entryBlock->args_end())) {
190-
paramsForForwarding.emplace_back(arg);
187+
for (auto indirectParam : indirectParams) {
188+
paramsForForwarding.emplace_back(indirectParam);
189+
}
190+
191+
for (auto param : params) {
192+
// We're going to directly call either the original function or the fallback
193+
// function with these arguments and then return. Therefore we just forward
194+
// the arguments instead of handling their ownership conventions.
195+
paramsForForwarding.emplace_back(param.forward(*this));
191196
}
192197

198+
prepareEpilog(FD->getResultInterfaceType(), FD->hasThrows(),
199+
CleanupLocation(FD));
200+
193201
SILBasicBlock *availableBB = createBasicBlock("availableBB");
194202
SILBasicBlock *unavailableBB = createBasicBlock("unavailableBB");
195203

test/SILGen/back_deploy_attribute_generic_func.swift

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@
55

66
// REQUIRES: OS=macosx
77

8-
// -- Fallback definition of genericFunc()
8+
// -- Fallback definition of genericFunc(_:)
99
// CHECK-LABEL: sil non_abi [serialized] [ossa] @$s11back_deploy11genericFuncyxxlFTwB : $@convention(thin) <T> (@in_guaranteed T) -> @out T
1010
// CHECK: bb0([[OUT_ARG:%.*]] : $*T, [[IN_ARG:%.*]] : $*T):
1111
// CHECK: copy_addr [[IN_ARG]] to [init] [[OUT_ARG]] : $*T
1212
// CHECK: [[RESULT:%.*]] = tuple ()
1313
// CHECK: return [[RESULT]] : $()
1414

15-
// -- Back deployment thunk for genericFunc()
15+
// -- Back deployment thunk for genericFunc(_:)
1616
// CHECK-LABEL: sil non_abi [serialized] [thunk] [ossa] @$s11back_deploy11genericFuncyxxlFTwb : $@convention(thin) <T> (@in_guaranteed T) -> @out T
1717
// CHECK: bb0([[OUT_ARG:%.*]] : $*T, [[IN_ARG:%.*]] : $*T):
1818
// CHECK: [[MAJOR:%.*]] = integer_literal $Builtin.Word, 10
@@ -36,16 +36,58 @@
3636
// CHECK: [[RESULT:%.*]] = tuple ()
3737
// CHECK: return [[RESULT]] : $()
3838

39-
// -- Original definition of genericFunc()
39+
// -- Original definition of genericFunc(_:)
4040
// CHECK-LABEL: sil [available 10.52] [ossa] @$s11back_deploy11genericFuncyxxlF : $@convention(thin) <T> (@in_guaranteed T) -> @out T
4141
@_backDeploy(before: macOS 10.52)
4242
public func genericFunc<T>(_ t: T) -> T {
4343
return t
4444
}
4545

46+
// -- Fallback definition of genericFuncWithOwnedParam(_:)
47+
// CHECK-LABEL: sil non_abi [serialized] [ossa] @$s11back_deploy25genericFuncWithOwnedParamyyxnlFTwB : $@convention(thin) <T> (@in T) -> ()
48+
// CHECK: bb0([[IN_ARG:%.*]] : $*T):
49+
// CHECK: destroy_addr [[IN_ARG]] : $*T
50+
// CHECK: [[RESULT:%.*]] = tuple ()
51+
// CHECK: return [[RESULT]] : $()
52+
53+
// -- Back deployment thunk for genericFuncWithOwnedParam(_:)
54+
// CHECK-LABEL: sil non_abi [serialized] [thunk] [ossa] @$s11back_deploy25genericFuncWithOwnedParamyyxnlFTwb : $@convention(thin) <T> (@in T) -> ()
55+
// CHECK: bb0([[IN_ARG:%.*]] : $*T):
56+
// CHECK: [[MAJOR:%.*]] = integer_literal $Builtin.Word, 10
57+
// CHECK: [[MINOR:%.*]] = integer_literal $Builtin.Word, 52
58+
// CHECK: [[PATCH:%.*]] = integer_literal $Builtin.Word, 0
59+
// CHECK: [[OSVFN:%.*]] = function_ref @$ss26_stdlib_isOSVersionAtLeastyBi1_Bw_BwBwtF : $@convention(thin) (Builtin.Word, Builtin.Word, Builtin.Word) -> Builtin.Int1
60+
// CHECK: [[AVAIL:%.*]] = apply [[OSVFN]]([[MAJOR]], [[MINOR]], [[PATCH]]) : $@convention(thin) (Builtin.Word, Builtin.Word, Builtin.Word) -> Builtin.Int1
61+
// CHECK: cond_br [[AVAIL]], [[AVAIL_BB:bb[0-9]+]], [[UNAVAIL_BB:bb[0-9]+]]
62+
//
63+
// CHECK: [[UNAVAIL_BB]]:
64+
// CHECK: [[FALLBACKFN:%.*]] = function_ref @$s11back_deploy25genericFuncWithOwnedParamyyxnlFTwB : $@convention(thin) <τ_0_0> (@in τ_0_0) -> ()
65+
// CHECK: {{%.*}} = apply [[FALLBACKFN]]<T>([[IN_ARG]]) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> ()
66+
// CHECK: br [[RETURN_BB:bb[0-9]+]]
67+
//
68+
// CHECK: [[AVAIL_BB]]:
69+
// CHECK: [[ORIGFN:%.*]] = function_ref @$s11back_deploy25genericFuncWithOwnedParamyyxnlF : $@convention(thin) <τ_0_0> (@in τ_0_0) -> ()
70+
// CHECK: {{%.*}} = apply [[ORIGFN]]<T>([[IN_ARG]]) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> ()
71+
// CHECK: br [[RETURN_BB]]
72+
//
73+
// CHECK: [[RETURN_BB]]
74+
// CHECK-NOT: destroy_addr
75+
// CHECK: [[RESULT:%.*]] = tuple ()
76+
// CHECK: return [[RESULT]] : $()
77+
78+
// -- Original definition of genericFuncWithOwnedParam(_:)
79+
// CHECK-LABEL: sil [available 10.52] [ossa] @$s11back_deploy25genericFuncWithOwnedParamyyxnlF : $@convention(thin) <T> (@in T) -> ()
80+
@_backDeploy(before: macOS 10.52)
81+
public func genericFuncWithOwnedParam<T>(_ t: __owned T) { }
82+
83+
struct S {}
84+
4685
// CHECK-LABEL: sil hidden [ossa] @$s11back_deploy6calleryyF : $@convention(thin) () -> ()
4786
func caller() {
48-
// -- Verify the thunk is called
87+
// -- Verify the thunks are called
4988
// CHECK: {{%.*}} = function_ref @$s11back_deploy11genericFuncyxxlFTwb : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> @out τ_0_0
50-
_ = genericFunc(Int32(1))
89+
_ = genericFunc(S())
90+
91+
// CHECK: {{%.*}} = function_ref @$s11back_deploy25genericFuncWithOwnedParamyyxnlFTwb : $@convention(thin) <τ_0_0> (@in τ_0_0) -> ()
92+
genericFuncWithOwnedParam(S())
5193
}

test/attr/Inputs/BackDeployHelper.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public func v2APIsAreStripped() -> Bool {
3535
/// Describes types that can be appended to.
3636
public protocol Appendable {
3737
associatedtype Element
38-
mutating func append(_ x: Element)
38+
mutating func append(_ x: __owned Element)
3939
}
4040

4141
/// Describes types that can be counted.
@@ -107,7 +107,7 @@ public func pleaseThrow(_ shouldThrow: Bool) throws -> Bool {
107107
@_backDeploy(before: BackDeploy 2.0)
108108
public func genericAppend<T: Appendable>(
109109
_ a: inout T,
110-
_ x: T.Element
110+
_ x: __owned T.Element
111111
) {
112112
return a.append(x)
113113
}

0 commit comments

Comments
 (0)