From a4f36b10d25c7fa859ccdf55796ca64a066f647e Mon Sep 17 00:00:00 2001 From: onevcat Date: Fri, 15 Nov 2024 23:44:05 +0900 Subject: [PATCH] Fix a potential duplicated completion invoking when task cancel There seems to be a short period that the callback can be accessed from another thread before the next lock --- Sources/Networking/SessionDataTask.swift | 5 ++++- Sources/Networking/SessionDelegate.swift | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Sources/Networking/SessionDataTask.swift b/Sources/Networking/SessionDataTask.swift index cd6c4e21d..ae5448e22 100644 --- a/Sources/Networking/SessionDataTask.swift +++ b/Sources/Networking/SessionDataTask.swift @@ -101,10 +101,13 @@ public class SessionDataTask: @unchecked Sendable { return nil } - func removeAllCallbacks() -> Void { + @discardableResult + func removeAllCallbacks() -> [TaskCallback] { lock.lock() defer { lock.unlock() } + let callbacks = callbacksStore.values callbacksStore.removeAll() + return Array(callbacks) } func resume() { diff --git a/Sources/Networking/SessionDelegate.swift b/Sources/Networking/SessionDelegate.swift index 9c901d811..63470896b 100644 --- a/Sources/Networking/SessionDelegate.swift +++ b/Sources/Networking/SessionDelegate.swift @@ -263,7 +263,8 @@ extension SessionDelegate: URLSessionDataDelegate { guard let sessionTask = self.task(for: task) else { return } - sessionTask.onTaskDone.call((result, sessionTask.callbacks)) + let callbacks = sessionTask.removeAllCallbacks() + sessionTask.onTaskDone.call((result, callbacks)) remove(sessionTask) } }