From 9140bfc4d46c7669c3fa22167c9091db4bc1ee77 Mon Sep 17 00:00:00 2001 From: Si Beaumont Date: Tue, 16 Jan 2024 08:01:52 +0000 Subject: [PATCH] Set OutputStream.delegate to nil in HTTPBodyOutputStreamBridge.deinit When running the cancellation tests in a loop, very occasionally there would be a crash with the following backtrace: ``` ``` This seems to indicate that the output stream is trying to access its delegate. However, when running with debug logging enabled I can see that the delegate has already been deinitialized. This is likely a result of the delegate itself owning the stream and setting the stream delegate to `self`, which IIUC is an established pattern. This presents a race in teardown. This patch sets the output stream delegate to `nil` in the delegate `deinit`. With this patch, the failing test passes when run an order of magnitude more times than were required to reliably reproduce the crash without the patch. --- .../HTTPBodyOutputStreamBridge.swift | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Sources/OpenAPIURLSession/URLSessionBidirectionalStreaming/HTTPBodyOutputStreamBridge.swift b/Sources/OpenAPIURLSession/URLSessionBidirectionalStreaming/HTTPBodyOutputStreamBridge.swift index 3b89d62..f3d040a 100644 --- a/Sources/OpenAPIURLSession/URLSessionBidirectionalStreaming/HTTPBodyOutputStreamBridge.swift +++ b/Sources/OpenAPIURLSession/URLSessionBidirectionalStreaming/HTTPBodyOutputStreamBridge.swift @@ -36,7 +36,10 @@ final class HTTPBodyOutputStreamBridge: NSObject, StreamDelegate { self.outputStream.open() } - deinit { debug("Output stream delegate deinit") } + deinit { + debug("Output stream delegate deinit") + self.outputStream.delegate = nil + } func performAction(_ action: State.Action) { debug("Output stream delegate performing action from state machine: \(action)")