Skip to content

Commit 6649804

Browse files
committed
solve leak, must destroy before dealloc
1 parent 7a621e4 commit 6649804

File tree

3 files changed

+18
-26
lines changed

3 files changed

+18
-26
lines changed

lib/IRGen/GenDistributed.cpp

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -495,12 +495,8 @@ void DistributedAccessor::decodeArgument(unsigned argumentIdx,
495495
case ParameterConvention::Pack_Inout:
496496
llvm_unreachable("pack parameters are not supported");
497497

498-
case ParameterConvention::Direct_Guaranteed: {
499-
fprintf(stderr, "[%s:%d](%s) Direct_Guaranteed\n", __FILE_NAME__, __LINE__, __FUNCTION__);
500-
LLVM_FALLTHROUGH;
501-
}
498+
case ParameterConvention::Direct_Guaranteed:
502499
case ParameterConvention::Direct_Unowned: {
503-
fprintf(stderr, "[%s:%d](%s) UNOWNED\n", __FILE_NAME__, __LINE__, __FUNCTION__);
504500
auto paramTy = param.getSILStorageInterfaceType();
505501
Address eltPtr = IGF.Builder.CreateElementBitCast(
506502
resultValue.getAddress(), IGM.getStorageType(paramTy));
@@ -587,6 +583,13 @@ void DistributedAccessor::emitLoadOfWitnessTables(llvm::Value *witnessTables,
587583
}
588584

589585
void DistributedAccessor::emitReturn(llvm::Value *errorValue) {
586+
// Destroy loaded arguments.
587+
// This MUST be done before deallocating, as otherwise we'd try to swift_release freed memory,
588+
// which will be a no-op, however that also would mean we never drop retain counts to 0 and miss to run deinitializers of classes!
589+
llvm::for_each(LoadedArguments, [&](const auto &argInfo) {
590+
emitDestroyCall(IGF, argInfo.second, argInfo.first);
591+
});
592+
590593
// Deallocate all of the copied arguments. Since allocations happened
591594
// on stack they have to be deallocated in reverse order.
592595
{
@@ -596,13 +599,6 @@ void DistributedAccessor::emitReturn(llvm::Value *errorValue) {
596599
}
597600
}
598601

599-
// Destroy loaded arguments.
600-
for (auto argInfo = LoadedArguments.rbegin();
601-
argInfo != LoadedArguments.rend(); ++argInfo) {
602-
603-
emitDestroyCall(IGF, argInfo->second, argInfo->first);
604-
}
605-
606602
Explosion voidResult;
607603

608604
Explosion error;

test/Distributed/Runtime/distributed_actor_func_calls_decoded_args_deinit.swift

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ struct S<T> : Codable {
3939

4040
distributed actor Greeter {
4141
distributed func test1<T>(_ value: SomeClass<T>) {
42-
print("RETAIN COUNT IN [TEST1]: \(_swift_retainCount(value))")
4342
}
4443
distributed func test2<T>(_ value: S<T>) {}
4544
}
@@ -51,11 +50,11 @@ func test() async throws {
5150
let local = Greeter(actorSystem: system)
5251
let ref = try Greeter.resolve(id: local.id, using: system)
5352

54-
var value = SomeClass<Int>()
55-
try await ref.test1(value)
56-
print("RETAIN COUNT: \(_swift_retainCount(value))")
57-
// _swift_release(value) // FIXME: we're missing a release!
58-
print("RETAIN COUNT: \(_swift_retainCount(value))")
53+
try await ref.test1(SomeClass<Int>())
54+
// CHECK: SomeClass: init
55+
// CHECK: SomeClass: deinit
56+
57+
try await ref.test2(S(data: SomeClass<Int>()))
5958
// CHECK: SomeClass: init
6059
// CHECK: SomeClass: deinit
6160
}
@@ -65,8 +64,3 @@ func test() async throws {
6564
try! await test()
6665
}
6766
}
68-
69-
@_silgen_name("swift_release")
70-
func _swift_release(_: AnyObject)
71-
@_silgen_name("swift_retainCount")
72-
func _swift_retainCount(_: AnyObject) -> Int

test/Distributed/distributed_actor_thunk_doesnt_leak_class_arguments.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// RUN: %target-swift-frontend-emit-module -emit-module-path %t/FakeDistributedActorSystems.swiftmodule -module-name FakeDistributedActorSystems -disable-availability-checking %S/Inputs/FakeDistributedActorSystems.swift
2-
// RUN: %target-swift-frontend -module-name no_to_arg_leaks -emit-irgen -disable-availability-checking -I %t 2>&1 %s | %IRGenFileCheck %s -check-prefix CHECK-%target-import-type --dump-input=always
2+
// RUN: %target-swift-frontend -module-name no_to_arg_leaks -emit-irgen -disable-availability-checking -I %t 2>&1 %s | %IRGenFileCheck %s -check-prefix CHECK-%target-import-type
33

44
// UNSUPPORTED: back_deploy_concurrency
55
// REQUIRES: concurrency
@@ -25,18 +25,20 @@ struct S<T> : Codable {
2525

2626
distributed actor Greeter {
2727
// CHECK-LABEL: define linkonce_odr hidden swifttailcc void @"$s15no_to_arg_leaks7GreeterC5test1yyAA9SomeClassCyxGYaKlFTETF"
28-
// CHECK: [[ARG_ADDR:%.*]] = bitcast i8* {{.*}} to %T15no_to_arg_leaks9SomeClassC**
28+
// CHECK: [[ARG_ADDR:%.*]] = bitcast i8* [[PARAM:%.*]] to %T15no_to_arg_leaks9SomeClassC**
2929
// CHECK: %destroy = bitcast i8* {{.*}} to void (%swift.opaque*, %swift.type*)*
3030
// CHECK-NEXT: [[OPAQUE_ARG_ADDR:%.*]] = bitcast %T15no_to_arg_leaks9SomeClassC** [[ARG_ADDR]] to %swift.opaque*
3131
// CHECK-NEXT: call void %destroy(%swift.opaque* noalias [[OPAQUE_ARG_ADDR]], %swift.type* %arg_type)
32+
// CHECK-NEXT: call swiftcc void @swift_task_dealloc(i8* [[PARAM]])
3233
distributed func test1<T>(_: SomeClass<T>) {
3334
}
3435

3536
// CHECK-LABEL: define linkonce_odr hidden swifttailcc void @"$s15no_to_arg_leaks7GreeterC5test2yyAA1SVyxGYaKlFTETF"
36-
// CHECK: [[ARG_ADDR:%.*]] = bitcast i8* {{.*}} to %T15no_to_arg_leaks1SV*
37+
// CHECK: [[ARG_ADDR:%.*]] = bitcast i8* [[PARAM:%.*]] to %T15no_to_arg_leaks1SV*
3738
// CHECK: %destroy = bitcast i8* {{.*}} to void (%swift.opaque*, %swift.type*)*
3839
// CHECK-NEXT: [[OPAQUE_ARG_ADDR:%.*]] = bitcast %T15no_to_arg_leaks1SV* [[ARG_ADDR]] to %swift.opaque*
3940
// CHECK-NEXT: call void %destroy(%swift.opaque* noalias [[OPAQUE_ARG_ADDR]], %swift.type* %arg_type)
41+
// CHECK-NEXT: call swiftcc void @swift_task_dealloc(i8* [[PARAM]])
4042
distributed func test2<T>(_: S<T>) {}
4143
}
4244

0 commit comments

Comments
 (0)