Last active
June 8, 2021 18:44
-
-
Save manmal/caa6491e7981654604bbf4b96bc0427c to your computer and use it in GitHub Desktop.
Potential reentrancy problem in Swift Actors
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
// Crashes when count is set to 683. Works fine if count < 683. | |
// Usage: | |
// func testMessagePassing() throws { | |
// let coordinator = Coordinator() | |
// let expectation = XCTestExpectation() | |
// detach { | |
// await coordinator.simulateMessengers() | |
// expectation.fulfill() | |
// } | |
// XCTAssertEqual(XCTWaiter().wait(for: [expectation], timeout: 1), .completed) | |
// } | |
actor Coordinator { | |
private(set) var counter = 0 | |
func shouldContinue(_ messenger: Messenger) -> Bool { | |
counter += 1 | |
return messenger.recipient != nil | |
} | |
func simulateMessengers(count: Int = 682) async { | |
let messengers = generateMessengers(self, count: count) | |
await withTaskGroup(of: Void.self) { group in | |
group.spawn { | |
return await messengers[0].passMessageOn(()) | |
} | |
} | |
print("shouldContinue was called " + String(counter) + " times") | |
} | |
} | |
actor Messenger { | |
let coordinator: Coordinator | |
let recipient: Messenger? | |
init(coordinator: Coordinator, recipient: Messenger?) { | |
self.coordinator = coordinator | |
self.recipient = recipient | |
} | |
func passMessageOn<T>(_ message: T) async { | |
guard | |
let recipient = recipient, | |
await coordinator.shouldContinue(self) | |
else { | |
return | |
} | |
await recipient.passMessageOn(message) | |
return | |
} | |
} | |
func generateMessengers(_ coordinator: Coordinator, count: Int) -> [Messenger] { | |
var actors = [Messenger]() | |
var previous: Messenger? | |
for _ in 0..<count { | |
let rambo = Messenger(coordinator: coordinator, recipient: previous) | |
previous = rambo | |
actors.append(rambo) | |
} | |
return actors.reversed() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment