Skip to content

Commit 9f54e9c

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 13ff3fe commit 9f54e9c

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
@@ -178,20 +178,28 @@ void SILGenFunction::emitBackDeploymentThunk(SILDeclRef thunk) {
178178

179179
F.setGenericEnvironment(SGM.Types.getConstantGenericEnvironment(thunk));
180180

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

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

200+
prepareEpilog(FD->getResultInterfaceType(), FD->hasThrows(),
201+
CleanupLocation(FD));
202+
195203
SILBasicBlock *availableBB = createBasicBlock("availableBB");
196204
SILBasicBlock *unavailableBB = createBasicBlock("unavailableBB");
197205

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)