mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Convert to JSException only NSException from sync methods (#50193)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/50193 This fix makes sure that we convert to JSException only NSException thrwn by sync methods. Currently, nothing in the stack will be capable of understanding that js error if it is triggered by an exception raised by an asyc method. See https://github.com/reactwg/react-native-new-architecture/discussions/276 for further details We need to cherry pick this in 0.78 and 0.79 ## Changelog: [iOS][Fixed] - Make sure the TM infra does not crash on NSException when triggered by async method Reviewed By: fabriziocucci Differential Revision: D71619229 fbshipit-source-id: b87aef5dd2720a2641c8da0904da651866370dc6
This commit is contained in:
committed by
Fabrizio Cucci
parent
ffe7bd1471
commit
8eec35f134
+24
-13
@@ -57,7 +57,7 @@ static jsi::Value convertNSNumberToJSINumber(jsi::Runtime &runtime, NSNumber *va
|
||||
|
||||
static jsi::String convertNSStringToJSIString(jsi::Runtime &runtime, NSString *value)
|
||||
{
|
||||
return jsi::String::createFromUtf8(runtime, [value UTF8String] ?: "");
|
||||
return jsi::String::createFromUtf8(runtime, [value UTF8String] ? [value UTF8String] : "");
|
||||
}
|
||||
|
||||
static jsi::Object convertNSDictionaryToJSIObject(jsi::Runtime &runtime, NSDictionary *value)
|
||||
@@ -195,7 +195,11 @@ static jsi::Value createJSRuntimeError(jsi::Runtime &runtime, const std::string
|
||||
/**
|
||||
* Creates JSError with current JS runtime and NSException stack trace.
|
||||
*/
|
||||
static jsi::JSError convertNSExceptionToJSError(jsi::Runtime &runtime, NSException *exception)
|
||||
static jsi::JSError convertNSExceptionToJSError(
|
||||
jsi::Runtime &runtime,
|
||||
NSException *exception,
|
||||
const std::string &moduleName,
|
||||
const std::string &methodName)
|
||||
{
|
||||
std::string reason = [exception.reason UTF8String];
|
||||
|
||||
@@ -206,7 +210,8 @@ static jsi::JSError convertNSExceptionToJSError(jsi::Runtime &runtime, NSExcepti
|
||||
cause.setProperty(
|
||||
runtime, "stackReturnAddresses", convertNSArrayToJSIArray(runtime, exception.callStackReturnAddresses));
|
||||
|
||||
jsi::Value error = createJSRuntimeError(runtime, "Exception in HostFunction: " + reason);
|
||||
std::string message = moduleName + "." + methodName + " raised an exception: " + reason;
|
||||
jsi::Value error = createJSRuntimeError(runtime, message);
|
||||
error.asObject(runtime).setProperty(runtime, "cause", std::move(cause));
|
||||
return {runtime, std::move(error)};
|
||||
}
|
||||
@@ -338,28 +343,34 @@ id ObjCTurboModule::performMethodInvocation(
|
||||
}
|
||||
|
||||
if (isSync) {
|
||||
TurboModulePerfLogger::syncMethodCallExecutionStart(moduleName, methodNameStr.c_str());
|
||||
TurboModulePerfLogger::syncMethodCallExecutionStart(moduleName, methodName);
|
||||
} else {
|
||||
TurboModulePerfLogger::asyncMethodCallExecutionStart(moduleName, methodNameStr.c_str(), asyncCallCounter);
|
||||
TurboModulePerfLogger::asyncMethodCallExecutionStart(moduleName, methodName, asyncCallCounter);
|
||||
}
|
||||
|
||||
@try {
|
||||
[inv invokeWithTarget:strongModule];
|
||||
} @catch (NSException *exception) {
|
||||
throw convertNSExceptionToJSError(runtime, exception);
|
||||
if (isSync) {
|
||||
// We can only convert NSException to JSError in sync method calls.
|
||||
// See https://github.com/reactwg/react-native-new-architecture/discussions/276#discussioncomment-12567155
|
||||
throw convertNSExceptionToJSError(runtime, exception, std::string{moduleName}, methodNameStr);
|
||||
} else {
|
||||
@throw exception;
|
||||
}
|
||||
} @finally {
|
||||
[retainedObjectsForInvocation removeAllObjects];
|
||||
}
|
||||
|
||||
if (!isSync) {
|
||||
TurboModulePerfLogger::asyncMethodCallExecutionEnd(moduleName, methodNameStr.c_str(), asyncCallCounter);
|
||||
TurboModulePerfLogger::asyncMethodCallExecutionEnd(moduleName, methodName, asyncCallCounter);
|
||||
return;
|
||||
}
|
||||
|
||||
void *rawResult;
|
||||
[inv getReturnValue:&rawResult];
|
||||
result = (__bridge id)rawResult;
|
||||
TurboModulePerfLogger::syncMethodCallExecutionEnd(moduleName, methodNameStr.c_str());
|
||||
TurboModulePerfLogger::syncMethodCallExecutionEnd(moduleName, methodName);
|
||||
};
|
||||
|
||||
if (isSync) {
|
||||
@@ -401,23 +412,23 @@ void ObjCTurboModule::performVoidMethodInvocation(
|
||||
}
|
||||
|
||||
if (shouldVoidMethodsExecuteSync_) {
|
||||
TurboModulePerfLogger::syncMethodCallExecutionStart(moduleName, methodNameStr.c_str());
|
||||
TurboModulePerfLogger::syncMethodCallExecutionStart(moduleName, methodName);
|
||||
} else {
|
||||
TurboModulePerfLogger::asyncMethodCallExecutionStart(moduleName, methodNameStr.c_str(), asyncCallCounter);
|
||||
TurboModulePerfLogger::asyncMethodCallExecutionStart(moduleName, methodName, asyncCallCounter);
|
||||
}
|
||||
|
||||
@try {
|
||||
[inv invokeWithTarget:strongModule];
|
||||
} @catch (NSException *exception) {
|
||||
throw convertNSExceptionToJSError(runtime, exception);
|
||||
throw convertNSExceptionToJSError(runtime, exception, std::string{moduleName}, methodNameStr);
|
||||
} @finally {
|
||||
[retainedObjectsForInvocation removeAllObjects];
|
||||
}
|
||||
|
||||
if (shouldVoidMethodsExecuteSync_) {
|
||||
TurboModulePerfLogger::syncMethodCallExecutionEnd(moduleName, methodNameStr.c_str());
|
||||
TurboModulePerfLogger::syncMethodCallExecutionEnd(moduleName, methodName);
|
||||
} else {
|
||||
TurboModulePerfLogger::asyncMethodCallExecutionEnd(moduleName, methodNameStr.c_str(), asyncCallCounter);
|
||||
TurboModulePerfLogger::asyncMethodCallExecutionEnd(moduleName, methodName, asyncCallCounter);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user