Skip to content

Commit 1e8f306

Browse files
authored
Merge pull request #59288 from DougGregor/back-deploy-concurrency-task-leak
2 parents aff121b + 3c6f6f2 commit 1e8f306

File tree

3 files changed

+57
-4
lines changed

3 files changed

+57
-4
lines changed

stdlib/public/BackDeployConcurrency/Actor.h

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
//
1515
//===----------------------------------------------------------------------===//
1616

17-
#ifndef SWIFT_ABI_ACTOR_H
18-
#define SWIFT_ABI_ACTOR_H
17+
#ifndef SWIFT_ABI_ACTOR_BACKDEPLOYED_H
18+
#define SWIFT_ABI_ACTOR_BACKDEPLOYED_H
1919

2020
#include "swift/ABI/HeapObject.h"
2121
#include "swift/ABI/MetadataValues.h"
@@ -31,11 +31,21 @@ class alignas(Alignment_DefaultActor) DefaultActor : public HeapObject {
3131
// destructor does not destroy the actor instance; you must call
3232
// swift_defaultActor_{initialize,destroy} yourself.
3333
constexpr DefaultActor(const HeapMetadata *metadata)
34-
: HeapObject(metadata), PrivateData{} {}
34+
: HeapObject(metadata), PrivateData{} {
35+
initHeapObject();
36+
}
3537

3638
constexpr DefaultActor(const HeapMetadata *metadata,
3739
InlineRefCounts::Immortal_t immortal)
38-
: HeapObject(metadata, immortal), PrivateData{} {}
40+
: HeapObject(metadata, immortal), PrivateData{} {
41+
// By a lucky coincidence, the modern bit pattern for immortal objects also
42+
// sets the immortal bit for older runtimes, so we don't need an immortal
43+
// equivalent to initHeapObject().
44+
}
45+
46+
void initHeapObject() {
47+
_swift_instantiateInertHeapObject(this, metadata);
48+
}
3949

4050
void *PrivateData[NumWords_DefaultActor];
4151
};

stdlib/public/BackDeployConcurrency/Task.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ class alignas(2 * alignof(void*)) Job :
9595
Job(JobFlags flags, JobInvokeFunction *invoke,
9696
const HeapMetadata *metadata = &jobHeapMetadata)
9797
: HeapObject(metadata), Flags(flags), RunJob(invoke) {
98+
initHeapObject();
9899
Voucher = voucher_copy();
99100
assert(!isAsyncTask() && "wrong constructor for a task");
100101
}
@@ -103,6 +104,7 @@ class alignas(2 * alignof(void*)) Job :
103104
const HeapMetadata *metadata = &jobHeapMetadata,
104105
bool captureCurrentVoucher = true)
105106
: HeapObject(metadata), Flags(flags), ResumeTask(invoke) {
107+
initHeapObject();
106108
if (captureCurrentVoucher)
107109
Voucher = voucher_copy();
108110
assert(isAsyncTask() && "wrong constructor for a non-task job");
@@ -114,11 +116,18 @@ class alignas(2 * alignof(void*)) Job :
114116
const HeapMetadata *metadata, InlineRefCounts::Immortal_t immortal,
115117
bool captureCurrentVoucher = true)
116118
: HeapObject(metadata, immortal), Flags(flags), ResumeTask(invoke) {
119+
// By a lucky coincidence, the modern bit pattern for immortal objects also
120+
// sets the immortal bit for older runtimes, so we don't need an immortal
121+
// equivalent to initHeapObject().
117122
if (captureCurrentVoucher)
118123
Voucher = voucher_copy();
119124
assert(isAsyncTask() && "wrong constructor for a non-task job");
120125
}
121126

127+
void initHeapObject() {
128+
_swift_instantiateInertHeapObject(this, metadata);
129+
}
130+
122131
~Job() { swift_voucher_release(Voucher); }
123132

124133
bool isAsyncTask() const {
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// RUN: %target-run-simple-swift(-parse-as-library -Xfrontend -disable-availability-checking) | %FileCheck %s
2+
// REQUIRES: executable_test
3+
// REQUIRES: concurrency
4+
// REQUIRES: concurrency_runtime
5+
6+
// UNSUPPORTED: back_deployment_runtime
7+
8+
class C {}
9+
10+
@_silgen_name("exit")
11+
func exit(_ code : UInt32) -> Never
12+
13+
@main
14+
enum Main {
15+
static func main() async {
16+
weak var weakRef: C?
17+
do {
18+
let c = C()
19+
let t = Task.detached { return c }
20+
weakRef = c
21+
}
22+
Task.detached {
23+
try await Task.sleep(nanoseconds: 10_000_000_000)
24+
print("Fail!")
25+
exit(1)
26+
}
27+
28+
while weakRef != nil {
29+
await Task.yield()
30+
}
31+
// CHECK: Success
32+
print("Success!")
33+
}
34+
}

0 commit comments

Comments
 (0)