From 9469ec746651e1c36a7dfd45fb60f103bf4c451f Mon Sep 17 00:00:00 2001 From: Zhi Zhou <15802618634@163.com> Date: Tue, 18 Feb 2025 05:03:27 -0800 Subject: [PATCH] fix: iOS app crash caused by the request operation canceling (#48350) Summary: Currently we observed many iOS app crashes caused by the `[RCTFileRequestHanlder invalidate]` method, just as the below screenshot. image ## Changelog: [IOS] [FIXED] - app crash caused by the `[RCTFileRequestHanlder invalidate]` method Pull Request resolved: https://github.com/facebook/react-native/pull/48350 Test Plan: I am not able to reproduce this issue locally either, so the changes in this PR are totally from my inference, I am not sure if it really makes sense, so please help take a deeper look, thanks. Reviewed By: javache Differential Revision: D69751695 Pulled By: cipolleschi fbshipit-source-id: aa4654a30f5dfac99b72ed1bda0dae1e0dc881c9 --- .../Network/RCTDataRequestHandler.mm | 20 ++++++++++++++++--- .../Network/RCTFileRequestHandler.mm | 20 ++++++++++++++++--- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/packages/react-native/Libraries/Network/RCTDataRequestHandler.mm b/packages/react-native/Libraries/Network/RCTDataRequestHandler.mm index f95d0c078e0..2aff977cf65 100644 --- a/packages/react-native/Libraries/Network/RCTDataRequestHandler.mm +++ b/packages/react-native/Libraries/Network/RCTDataRequestHandler.mm @@ -8,6 +8,8 @@ #import #import +#import + #import "RCTNetworkPlugins.h" @interface RCTDataRequestHandler () @@ -15,14 +17,22 @@ @implementation RCTDataRequestHandler { NSOperationQueue *_queue; + std::mutex _operationHandlerMutexLock; } RCT_EXPORT_MODULE() - (void)invalidate { - [_queue cancelAllOperations]; - _queue = nil; + std::lock_guard lock(_operationHandlerMutexLock); + if (_queue) { + for (NSOperation *operation in _queue.operations) { + if (!operation.isCancelled && !operation.isFinished) { + [operation cancel]; + } + } + _queue = nil; + } } - (BOOL)canHandleRequest:(NSURLRequest *)request @@ -32,6 +42,7 @@ RCT_EXPORT_MODULE() - (NSOperation *)sendRequest:(NSURLRequest *)request withDelegate:(id)delegate { + std::lock_guard lock(_operationHandlerMutexLock); // Lazy setup if (!_queue) { _queue = [NSOperationQueue new]; @@ -69,7 +80,10 @@ RCT_EXPORT_MODULE() - (void)cancelRequest:(NSOperation *)op { - [op cancel]; + std::lock_guard lock(_operationHandlerMutexLock); + if (!op.isCancelled && !op.isFinished) { + [op cancel]; + } } - (std::shared_ptr)getTurboModule: diff --git a/packages/react-native/Libraries/Network/RCTFileRequestHandler.mm b/packages/react-native/Libraries/Network/RCTFileRequestHandler.mm index 19d025c51e1..4ca36256c68 100644 --- a/packages/react-native/Libraries/Network/RCTFileRequestHandler.mm +++ b/packages/react-native/Libraries/Network/RCTFileRequestHandler.mm @@ -7,6 +7,8 @@ #import +#import + #import #import @@ -19,14 +21,22 @@ @implementation RCTFileRequestHandler { NSOperationQueue *_fileQueue; + std::mutex _operationHandlerMutexLock; } RCT_EXPORT_MODULE() - (void)invalidate { - [_fileQueue cancelAllOperations]; - _fileQueue = nil; + std::lock_guard lock(_operationHandlerMutexLock); + if (_fileQueue) { + for (NSOperation *operation in _fileQueue.operations) { + if (!operation.isCancelled && !operation.isFinished) { + [operation cancel]; + } + } + _fileQueue = nil; + } } - (BOOL)canHandleRequest:(NSURLRequest *)request @@ -36,6 +46,7 @@ RCT_EXPORT_MODULE() - (NSOperation *)sendRequest:(NSURLRequest *)request withDelegate:(id)delegate { + std::lock_guard lock(_operationHandlerMutexLock); // Lazy setup if (!_fileQueue) { _fileQueue = [NSOperationQueue new]; @@ -83,7 +94,10 @@ RCT_EXPORT_MODULE() - (void)cancelRequest:(NSOperation *)op { - [op cancel]; + std::lock_guard lock(_operationHandlerMutexLock); + if (!op.isCancelled && !op.isFinished) { + [op cancel]; + } } - (std::shared_ptr)getTurboModule: