Skip to content

SILGen: Fix double-free of __owned parameters of functions with @_backDeploy #63114

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 18 additions & 10 deletions lib/SILGen/SILGenBackDeploy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,20 +178,28 @@ void SILGenFunction::emitBackDeploymentThunk(SILDeclRef thunk) {

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

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

// Gather the entry block's arguments up so that we can forward them.
// Build up the list of arguments that we're going to invoke the the real
// function with.
SmallVector<SILValue, 8> paramsForForwarding;
SILBasicBlock *entryBlock = getFunction().getEntryBlock();
for (SILArgument *arg :
make_range(entryBlock->args_begin(), entryBlock->args_end())) {
paramsForForwarding.emplace_back(arg);
for (auto indirectParam : indirectParams) {
paramsForForwarding.emplace_back(indirectParam);
}

for (auto param : params) {
// We're going to directly call either the original function or the fallback
// function with these arguments and then return. Therefore we just forward
// the arguments instead of handling their ownership conventions.
paramsForForwarding.emplace_back(param.forward(*this));
}

prepareEpilog(FD->getResultInterfaceType(), FD->hasThrows(),
CleanupLocation(FD));

SILBasicBlock *availableBB = createBasicBlock("availableBB");
SILBasicBlock *unavailableBB = createBasicBlock("unavailableBB");

Expand Down
52 changes: 47 additions & 5 deletions test/SILGen/back_deploy_attribute_generic_func.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@

// REQUIRES: OS=macosx

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

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

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

// -- Fallback definition of genericFuncWithOwnedParam(_:)
// CHECK-LABEL: sil non_abi [serialized] [ossa] @$s11back_deploy25genericFuncWithOwnedParamyyxnlFTwB : $@convention(thin) <T> (@in T) -> ()
// CHECK: bb0([[IN_ARG:%.*]] : $*T):
// CHECK: destroy_addr [[IN_ARG]] : $*T
// CHECK: [[RESULT:%.*]] = tuple ()
// CHECK: return [[RESULT]] : $()

// -- Back deployment thunk for genericFuncWithOwnedParam(_:)
// CHECK-LABEL: sil non_abi [serialized] [thunk] [ossa] @$s11back_deploy25genericFuncWithOwnedParamyyxnlFTwb : $@convention(thin) <T> (@in T) -> ()
// CHECK: bb0([[IN_ARG:%.*]] : $*T):
// CHECK: [[MAJOR:%.*]] = integer_literal $Builtin.Word, 10
// CHECK: [[MINOR:%.*]] = integer_literal $Builtin.Word, 52
// CHECK: [[PATCH:%.*]] = integer_literal $Builtin.Word, 0
// CHECK: [[OSVFN:%.*]] = function_ref @$ss26_stdlib_isOSVersionAtLeastyBi1_Bw_BwBwtF : $@convention(thin) (Builtin.Word, Builtin.Word, Builtin.Word) -> Builtin.Int1
// CHECK: [[AVAIL:%.*]] = apply [[OSVFN]]([[MAJOR]], [[MINOR]], [[PATCH]]) : $@convention(thin) (Builtin.Word, Builtin.Word, Builtin.Word) -> Builtin.Int1
// CHECK: cond_br [[AVAIL]], [[AVAIL_BB:bb[0-9]+]], [[UNAVAIL_BB:bb[0-9]+]]
//
// CHECK: [[UNAVAIL_BB]]:
// CHECK: [[FALLBACKFN:%.*]] = function_ref @$s11back_deploy25genericFuncWithOwnedParamyyxnlFTwB : $@convention(thin) <τ_0_0> (@in τ_0_0) -> ()
// CHECK: {{%.*}} = apply [[FALLBACKFN]]<T>([[IN_ARG]]) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> ()
// CHECK: br [[RETURN_BB:bb[0-9]+]]
//
// CHECK: [[AVAIL_BB]]:
// CHECK: [[ORIGFN:%.*]] = function_ref @$s11back_deploy25genericFuncWithOwnedParamyyxnlF : $@convention(thin) <τ_0_0> (@in τ_0_0) -> ()
// CHECK: {{%.*}} = apply [[ORIGFN]]<T>([[IN_ARG]]) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> ()
// CHECK: br [[RETURN_BB]]
//
// CHECK: [[RETURN_BB]]
// CHECK-NOT: destroy_addr
// CHECK: [[RESULT:%.*]] = tuple ()
// CHECK: return [[RESULT]] : $()

// -- Original definition of genericFuncWithOwnedParam(_:)
// CHECK-LABEL: sil [available 10.52] [ossa] @$s11back_deploy25genericFuncWithOwnedParamyyxnlF : $@convention(thin) <T> (@in T) -> ()
@_backDeploy(before: macOS 10.52)
public func genericFuncWithOwnedParam<T>(_ t: __owned T) { }

struct S {}

// CHECK-LABEL: sil hidden [ossa] @$s11back_deploy6calleryyF : $@convention(thin) () -> ()
func caller() {
// -- Verify the thunk is called
// -- Verify the thunks are called
// CHECK: {{%.*}} = function_ref @$s11back_deploy11genericFuncyxxlFTwb : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> @out τ_0_0
_ = genericFunc(Int32(1))
_ = genericFunc(S())

// CHECK: {{%.*}} = function_ref @$s11back_deploy25genericFuncWithOwnedParamyyxnlFTwb : $@convention(thin) <τ_0_0> (@in τ_0_0) -> ()
genericFuncWithOwnedParam(S())
}
4 changes: 2 additions & 2 deletions test/attr/Inputs/BackDeployHelper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public func v2APIsAreStripped() -> Bool {
/// Describes types that can be appended to.
public protocol Appendable {
associatedtype Element
mutating func append(_ x: Element)
mutating func append(_ x: __owned Element)
}

/// Describes types that can be counted.
Expand Down Expand Up @@ -107,7 +107,7 @@ public func pleaseThrow(_ shouldThrow: Bool) throws -> Bool {
@_backDeploy(before: BackDeploy 2.0)
public func genericAppend<T: Appendable>(
_ a: inout T,
_ x: T.Element
_ x: __owned T.Element
) {
return a.append(x)
}
Expand Down