Skip to content

Commit 7020cf3

Browse files
authored
Merge pull request #67392 from ktoso/wip-reenable-async_taskgroup_discarding_dontLeak_class_error.swift
2 parents a57c97b + d01abcb commit 7020cf3

File tree

2 files changed

+53
-10
lines changed

2 files changed

+53
-10
lines changed

stdlib/public/Concurrency/TaskGroup.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1810,9 +1810,12 @@ void TaskGroupBase::waitAll(SwiftError* bodyError, AsyncTask *waitingTask,
18101810
swift_release(completedTask);
18111811
}
18121812

1813-
waitingTask->runInFullyEstablishedContext();
1814-
1813+
// We MUST release the lock before we resume the waiting task, because the resumption
1814+
// will allow it to destroy the task group, in which case the unlock()
1815+
// would be performed on freed memory (!)
18151816
unlock();
1817+
1818+
waitingTask->runInFullyEstablishedContext();
18161819
return;
18171820
}
18181821

test/Concurrency/Runtime/async_taskgroup_discarding_dontLeak_class_error.swift

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,35 +12,75 @@
1212

1313
import _Concurrency
1414

15+
actor SimpleCountDownLatch {
16+
let from: Int
17+
var count: Int
18+
19+
var continuation: CheckedContinuation<Void, Never>?
20+
21+
init(from: Int) {
22+
self.from = from
23+
self.count = from
24+
}
25+
26+
func hit() {
27+
defer { count -= 1 }
28+
if count == 0 {
29+
fatalError("Counted down more times than expected! (From: \(from))")
30+
} else if count == 1 {
31+
continuation?.resume()
32+
}
33+
}
34+
35+
func wait() async {
36+
guard self.count > 0 else {
37+
return // we're done
38+
}
39+
40+
return await withCheckedContinuation { cc in
41+
self.continuation = cc
42+
}
43+
}
44+
}
45+
1546
final class ClassBoom: Error {
1647
let id: String
48+
let latch: SimpleCountDownLatch
1749

18-
init(file: String = #fileID, line: UInt = #line) {
50+
init(latch: SimpleCountDownLatch, file: String = #fileID, line: UInt = #line) {
51+
self.latch = latch
1952
self.id = "\(file):\(line)"
2053
print("INIT OF ClassBoom from \(id)")
2154
}
2255

2356
deinit {
2457
print("DEINIT OF ClassBoom from \(id)")
58+
Task { [latch] in await latch.hit() }
2559
}
2660
}
2761

2862
@main struct Main {
2963
static func main() async {
64+
let latch = SimpleCountDownLatch(from: 4)
3065

3166
// many errors
3267
_ = try? await withThrowingDiscardingTaskGroup() { group in
33-
group.addTask { throw ClassBoom() }
34-
group.addTask { throw ClassBoom() }
35-
group.addTask { throw ClassBoom() }
36-
group.addTask { throw ClassBoom() }
37-
group.addTask { 12 }
38-
return 12
68+
group.addTask { throw ClassBoom(latch: latch) }
69+
group.addTask { throw ClassBoom(latch: latch) }
70+
group.addTask { throw ClassBoom(latch: latch) }
71+
group.addTask { throw ClassBoom(latch: latch) }
72+
group.addTask {
73+
12 // ignore this on purpose
74+
}
75+
return 42
3976

4077
// CHECK: DEINIT OF ClassBoom
4178
// CHECK: DEINIT OF ClassBoom
4279
// CHECK: DEINIT OF ClassBoom
4380
// CHECK: DEINIT OF ClassBoom
4481
}
82+
83+
await latch.wait()
84+
print("done") // CHECK: done
4585
}
46-
}
86+
}

0 commit comments

Comments
 (0)