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.
## 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: