Skip to content

Commit fa407f6

Browse files
committed
fix: fix exception handling in C++ native code
1 parent 13006f3 commit fa407f6

File tree

6 files changed

+56
-28
lines changed

6 files changed

+56
-28
lines changed

android/src/main/cpp/ETInstallerModule.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ void ETInstallerModule::injectJSIBindings() {
5353
jbyteArray byteData =
5454
(jbyteArray)env->CallStaticObjectMethod(cls, method, jUrl);
5555

56+
if (env->IsSameObject(byteData, NULL)) {
57+
throw std::runtime_error("Error fetching data from a url");
58+
}
59+
5660
int size = env->GetArrayLength(byteData);
5761
jbyte *bytes = env->GetByteArrayElements(byteData, JNI_FALSE);
5862
std::byte *dataBytePtr = reinterpret_cast<std::byte *>(bytes);

android/src/main/java/com/swmansion/rnexecutorch/ETInstaller.kt

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,20 @@ class ETInstaller(
2121
@JvmStatic
2222
@DoNotStrip
2323
@Throws(Exception::class)
24-
fun fetchByteDataFromUrl(source: String): ByteArray {
25-
val url = URL(source)
26-
val connection = url.openConnection()
27-
connection.connect()
24+
fun fetchByteDataFromUrl(source: String): ByteArray? {
25+
try {
26+
val url = URL(source)
27+
val connection = url.openConnection()
28+
connection.connect()
2829

29-
val inputStream: InputStream = connection.getInputStream()
30-
val data = inputStream.readBytes()
31-
inputStream.close()
30+
val inputStream: InputStream = connection.getInputStream()
31+
val data = inputStream.readBytes()
32+
inputStream.close()
3233

33-
return data
34+
return data
35+
} catch (exception: Throwable) {
36+
return null
37+
}
3438
}
3539
}
3640

common/rnexecutorch/data_processing/ImageProcessing.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,14 @@ cv::Mat readImage(const std::string &imageURI) {
9999
// local file
100100
auto url = ada::parse(imageURI);
101101
image = cv::imread(std::string{url->get_pathname()}, cv::IMREAD_COLOR);
102-
} else {
102+
} else if (imageURI.starts_with("http")) {
103103
// remote file
104104
std::vector<std::byte> imageData = fetchUrlFunc(imageURI);
105105
image = cv::imdecode(
106106
cv::Mat(1, imageData.size(), CV_8UC1, (void *)imageData.data()),
107107
cv::IMREAD_COLOR);
108+
} else {
109+
throw std::runtime_error("Read image error: unknown protocol");
108110
}
109111

110112
if (image.empty()) {

common/rnexecutorch/host_objects/ModelHostObject.h

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ template <typename Model> class ModelHostObject : public JsiHostObject {
2222
}
2323

2424
JSI_HOST_FUNCTION(forward) {
25-
2625
auto promise = promiseVendor.createPromise(
2726
[this, count, args, &runtime](std::shared_ptr<Promise> promise) {
2827
std::thread([this, promise = std::move(promise), count, args,
@@ -40,20 +39,33 @@ template <typename Model> class ModelHostObject : public JsiHostObject {
4039
return;
4140
}
4241

42+
// Do the asynchronous work
43+
std::thread([this, promise = std::move(promise), args, &runtime]() {
4344
try {
4445
auto argsConverted = jsiconversion::createArgsTupleFromJsi(
4546
&Model::forward, args, runtime);
46-
promise->resolve([this, argsConverted = std::move(argsConverted)](
47-
jsi::Runtime &runtime) {
48-
auto result = std::apply(
49-
std::bind_front(&Model::forward, model), argsConverted);
50-
auto resultValue =
51-
jsiconversion::getJsiValue(std::move(result), runtime);
52-
return resultValue;
47+
auto result = std::apply(std::bind_front(&Model::forward, model),
48+
argsConverted);
49+
50+
promise->resolve([result =
51+
std::move(result)](jsi::Runtime &runtime) {
52+
return jsiconversion::getJsiValue(std::move(result), runtime);
5353
});
54+
} catch (const std::runtime_error &e) {
55+
// This catch should be merged with the next one
56+
// (std::runtime_error inherits from std::exception) HOWEVER react
57+
// native has broken RTTI which breaks proper exception type
58+
// checking. Remove when the following change is present in our
59+
// version:
60+
// https://github.com/facebook/react-native/commit/3132cc88dd46f95898a756456bebeeb6c248f20e
61+
promise->reject(e.what());
62+
return;
5463
} catch (const std::exception &e) {
5564
promise->reject(e.what());
5665
return;
66+
} catch (...) {
67+
promise->reject("Unknown error");
68+
return;
5769
}
5870
}).detach();
5971
});

common/rnexecutorch/jsi/JsiPromise.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@ jsi::Value PromiseVendor::createPromise(
4040

4141
auto rejectWrapper = [reject, &runtime, callInvoker](
4242
const std::string &errorMessage) -> void {
43-
auto error = jsi::JSError(runtime, errorMessage);
44-
auto errorShared = std::make_shared<jsi::JSError>(error);
45-
callInvoker->invokeAsync([reject, &runtime, errorShared]() -> void {
43+
callInvoker->invokeAsync([reject, &runtime, errorMessage]() -> void {
44+
auto error = jsi::JSError(runtime, errorMessage);
45+
auto errorShared = std::make_shared<jsi::JSError>(error);
4646
reject->call(runtime, errorShared->value());
4747
});
4848
};

ios/RnExecutorch/ETInstaller.mm

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#import <React/RCTCallInvoker.h>
66
#import <ReactCommon/RCTTurboModule.h>
77
#include <rnexecutorch/RnExecutorchInstaller.h>
8+
#include <stdexcept>
89

910
using namespace facebook::react;
1011

@@ -26,14 +27,19 @@ @implementation ETInstaller
2627
assert(jsiRuntime != nullptr);
2728

2829
auto fetchUrl = [](std::string url) {
29-
NSString *nsUrlStr =
30-
[NSString stringWithCString:url.c_str()
31-
encoding:[NSString defaultCStringEncoding]];
32-
NSURL *nsUrl = [NSURL URLWithString:nsUrlStr];
33-
NSData *data = [NSData dataWithContentsOfURL:nsUrl];
34-
const std::byte *bytePtr = reinterpret_cast<const std::byte *>(data.bytes);
35-
int bufferLength = [data length];
36-
return std::vector<std::byte>(bytePtr, bytePtr + bufferLength);
30+
@try {
31+
NSString *nsUrlStr =
32+
[NSString stringWithCString:url.c_str()
33+
encoding:[NSString defaultCStringEncoding]];
34+
NSURL *nsUrl = [NSURL URLWithString:nsUrlStr];
35+
NSData *data = [NSData dataWithContentsOfURL:nsUrl];
36+
const std::byte *bytePtr =
37+
reinterpret_cast<const std::byte *>(data.bytes);
38+
int bufferLength = [data length];
39+
return std::vector<std::byte>(bytePtr, bytePtr + bufferLength);
40+
} @catch (NSException *exception) {
41+
throw std::runtime_error("Error fetching data from a url");
42+
}
3743
};
3844
rnexecutorch::RnExecutorchInstaller::injectJSIBindings(
3945
jsiRuntime, jsCallInvoker, fetchUrl);

0 commit comments

Comments
 (0)