mrousavy / nitro

🔥 Insanely fast native C++, Swift or Kotlin modules with a statically compiled binding layer to JSI
https://nitro.margelo.com
MIT License
665 stars 22 forks source link

Crash in android release mode during runtime in example app #314

Closed hannojg closed 2 weeks ago

hannojg commented 2 weeks ago

What's happening?

Running the example app in release mode causes a crash

Reproduceable Code

Relevant log output

2024-11-09 10:22:41.486  5023-5080  ReactNativeJS           com.margelo.nitroexample             I  Bridgeless mode is enabled
2024-11-09 10:22:41.488  5023-5080  ReactNativeJS           com.margelo.nitroexample             I  Running "NitroExample"
2024-11-09 10:22:41.498  5023-5080  NitroModules            com.margelo.nitroexample             I  Loading NitroModules C++ library...
2024-11-09 10:22:41.500  5023-5080  NitroModules            com.margelo.nitroexample             I  Successfully loaded NitroModules C++ library!
2024-11-09 10:22:41.501  5023-5080  HybridImageFactorySpec  com.margelo.nitroexample             I  Loading NitroImage C++ library...
2024-11-09 10:22:41.502  5023-5080  HybridImageFactorySpec  com.margelo.nitroexample             I  Successfully loaded NitroImage C++ library!
2024-11-09 10:22:41.502  5023-5080  HybridTest...KotlinSpec com.margelo.nitroexample             I  Loading NitroImage C++ library...
2024-11-09 10:22:41.503  5023-5080  HybridTest...KotlinSpec com.margelo.nitroexample             I  Successfully loaded NitroImage C++ library!
2024-11-09 10:22:41.503  5023-5080  HybridBaseSpec          com.margelo.nitroexample             I  Loading NitroImage C++ library...
2024-11-09 10:22:41.504  5023-5080  HybridBaseSpec          com.margelo.nitroexample             I  Successfully loaded NitroImage C++ library!
2024-11-09 10:22:41.504  5023-5080  HybridChildSpec         com.margelo.nitroexample             I  Loading NitroImage C++ library...
2024-11-09 10:22:41.504  5023-5080  HybridChildSpec         com.margelo.nitroexample             I  Successfully loaded NitroImage C++ library!
2024-11-09 10:22:41.504  5023-5080  ReactNativeJS           com.margelo.nitroexample             I  Prototype chain of Child:
2024-11-09 10:22:41.505  5023-5080  ReactNativeJS           com.margelo.nitroexample             I    Child (0 props)
2024-11-09 10:22:41.520  5023-5080  ReactNativeJS           com.margelo.nitroexample             I     ∟ {} (1 props)
2024-11-09 10:22:41.520  5023-5080  ReactNativeJS           com.margelo.nitroexample             I        ∟ {} (1 props)
2024-11-09 10:22:41.520  5023-5080  ReactNativeJS           com.margelo.nitroexample             I           ∟ {} (4 props)
2024-11-09 10:22:41.520  5023-5080  ReactNativeJS           com.margelo.nitroexample             I              ∟ {} (0 props)
2024-11-09 10:22:41.520  5023-5080  ReactNativeJS           com.margelo.nitroexample             I                 ∟ {} (0 props)
2024-11-09 10:22:41.520  5023-5080  ReactNativeJS           com.margelo.nitroexample             I  10
2024-11-09 10:22:41.520  5023-5080  ReactNativeJS           com.margelo.nitroexample             I  20
2024-11-09 10:22:41.521  5023-5080  ReactNativeJS           com.margelo.nitroexample             I  30
2024-11-09 10:22:41.521  5023-5080  ReactNativeJS           com.margelo.nitroexample             I  Prototype chain of TestObjectCpp:
2024-11-09 10:22:41.521  5023-5080  ReactNativeJS           com.margelo.nitroexample             I    TestObjectCpp (0 props)
2024-11-09 10:22:41.521  5023-5080  ReactNativeJS           com.margelo.nitroexample             I     ∟ {} (1 props)
2024-11-09 10:22:41.521  5023-5080  ReactNativeJS           com.margelo.nitroexample             I        ∟ {} (57 props)
2024-11-09 10:22:41.521  5023-5080  ReactNativeJS           com.margelo.nitroexample             I           ∟ {} (4 props)
2024-11-09 10:22:41.521  5023-5080  ReactNativeJS           com.margelo.nitroexample             I              ∟ {} (0 props)
2024-11-09 10:22:41.521  5023-5080  ReactNativeJS           com.margelo.nitroexample             I                 ∟ {} (0 props)
2024-11-09 10:22:41.585  5023-5080  ReactNativeJS           com.margelo.nitroexample             I  Showing Tests for HybridObject "TestObjectCpp"
2024-11-09 10:22:41.712  5023-5023  Compatibil...geReporter com.margelo.nitroexample             D  Compat change id reported: 210923482; UID 10193; state: ENABLED
2024-11-09 10:22:42.733  5023-5023  Compatibil...geReporter com.margelo.nitroexample             D  Compat change id reported: 171228096; UID 10193; state: ENABLED
2024-11-09 10:22:42.797  5023-5080  ReactNativeJS           com.margelo.nitroexample             I  Showing Tests for HybridObject "TestObjectCpp"
2024-11-09 10:22:43.153  5023-5048  EGL_emulation           com.margelo.nitroexample             D  app_time_stats: avg=1048.23ms min=588.69ms max=1507.77ms count=2
2024-11-09 10:22:44.281  5023-5080  Compatibil...geReporter com.margelo.nitroexample             D  Compat change id reported: 289878283; UID 10193; state: ENABLED
2024-11-09 10:22:44.314  5023-5048  EGL_emulation           com.margelo.nitroexample             D  app_time_stats: avg=192.53ms min=6.79ms max=993.85ms count=6
2024-11-09 10:22:44.358  5023-5080  ReactNativeJS           com.margelo.nitroexample             I  Showing Tests for HybridObject "TestObjectCpp"
2024-11-09 10:22:44.519  5023-5080  ReactNativeJS           com.margelo.nitroexample             I  ⏳ Test "HybridObject.prototype is valid" started...
2024-11-09 10:22:44.520  5023-5080  ReactNativeJS           com.margelo.nitroexample             I  ✅ Test "HybridObject.prototype is valid" passed!
2024-11-09 10:22:44.520  5023-5080  libc                    com.margelo.nitroexample             A  Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x3b637ffff0 in tid 5080 (mqt_v_js), pid 5023 (lo.nitroexample)
2024-11-09 10:22:44.920  5099-5099  DEBUG                   pid-5099                             A  Cmdline: com.margelo.nitroexample
2024-11-09 10:22:44.920  5099-5099  DEBUG                   pid-5099                             A  pid: 5023, tid: 5080, name: mqt_v_js  >>> com.margelo.nitroexample <<<
2024-11-09 10:22:44.920  5099-5099  DEBUG                   pid-5099                             A        #00 pc 00000000000b176c  /data/app/~~zz4h7X7D_XggNeymJ1k82w==/com.margelo.nitroexample-wVR229i9TnWsolzHcppGUg==/base.apk!libhermes.so (offset 0x838000) (BuildId: e70878b706682e356226475d11c138e044ca065f)
2024-11-09 10:22:44.920  5099-5099  DEBUG                   pid-5099                             A        #01 pc 000000000005f520  /data/app/~~zz4h7X7D_XggNeymJ1k82w==/com.margelo.nitroexample-wVR229i9TnWsolzHcppGUg==/base.apk!libNitroModules.so (offset 0x5f8000) (std::__ndk1::shared_ptr<margelo::nitro::HybridObject> margelo::nitro::HybridFunction::getHybridObjectNativeState<margelo::nitro::HybridObject>(facebook::jsi::Runtime&, facebook::jsi::Value const&, margelo::nitro::FunctionKind, std::__ndk1::basic_string<char, std::__ndk1::char_traits<char>, std::__ndk1::allocator<char> > const&)+84) (BuildId: a0d6a70708ebb7b54d7cb0cc61d47975c4d45e5a)
2024-11-09 10:22:44.920  5099-5099  DEBUG                   pid-5099                             A        #02 pc 000000000005eec0  /data/app/~~zz4h7X7D_XggNeymJ1k82w==/com.margelo.nitroexample-wVR229i9TnWsolzHcppGUg==/base.apk!libNitroModules.so (offset 0x5f8000) (margelo::nitro::HybridFunction margelo::nitro::HybridFunction::createHybridFunction<margelo::nitro::HybridObject, std::__ndk1::basic_string<char, std::__ndk1::char_traits<char>, std::__ndk1::allocator<char> > >(std::__ndk1::basic_string<char, std::__ndk1::char_traits<char>, std::__ndk1::allocator<char> > const&, std::__ndk1::basic_string<char, std::__ndk1::char_traits<char>, std::__ndk1::allocator<char> > (margelo::nitro::HybridObject::*)(), margelo::nitro::FunctionKind)::'lambda'(facebook::jsi::Runtime&, facebook::jsi::Value const&, facebook::jsi::Value const*, unsigned long)::operator()(facebook::jsi::Runtime&, facebook::jsi::Value const&, facebook::jsi::Value const*, unsigned long) const+84) (BuildId: a0d6a70708ebb7b54d7cb0cc61d47975c4d45e5a)
2024-11-09 10:22:44.920  5099-5099  DEBUG                   pid-5099                             A        #03 pc 00000000000bb7f0  /data/app/~~zz4h7X7D_XggNeymJ1k82w==/com.margelo.nitroexample-wVR229i9TnWsolzHcppGUg==/base.apk!libhermes.so (offset 0x838000) (BuildId: e70878b706682e356226475d11c138e044ca065f)
2024-11-09 10:22:44.920  5099-5099  DEBUG                   pid-5099                             A        #04 pc 00000000000bb450  /data/app/~~zz4h7X7D_XggNeymJ1k82w==/com.margelo.nitroexample-wVR229i9TnWsolzHcppGUg==/base.apk!libhermes.so (offset 0x838000) (BuildId: e70878b706682e356226475d11c138e044ca065f)
2024-11-09 10:22:44.920  5099-5099  DEBUG                   pid-5099                             A        #05 pc 00000000000c2528  /data/app/~~zz4h7X7D_XggNeymJ1k82w==/com.margelo.nitroexample-wVR229i9TnWsolzHcppGUg==/base.apk!libhermes.so (offset 0x838000) (BuildId: e70878b706682e356226475d11c138e044ca065f)
2024-11-09 10:22:44.920  5099-5099  DEBUG                   pid-5099                             A        #06 pc 00000000000d2874  /data/app/~~zz4h7X7D_XggNeymJ1k82w==/com.margelo.nitroexample-wVR229i9TnWsolzHcppGUg==/base.apk!libhermes.so (offset 0x838000) (BuildId: e70878b706682e356226475d11c138e044ca065f)
2024-11-09 10:22:44.920  5099-5099  DEBUG                   pid-5099                             A        #07 pc 00000000000d4224  /data/app/~~zz4h7X7D_XggNeymJ1k82w==/com.margelo.nitroexample-wVR229i9TnWsolzHcppGUg==/base.apk!libhermes.so (offset 0x838000) (BuildId: e70878b706682e356226475d11c138e044ca065f)
2024-11-09 10:22:44.920  5099-5099  DEBUG                   pid-5099                             A        #08 pc 00000000000d38e0  /data/app/~~zz4h7X7D_XggNeymJ1k82w==/com.margelo.nitroexample-wVR229i9TnWsolzHcppGUg==/base.apk!libhermes.so (offset 0x838000) (BuildId: e70878b706682e356226475d11c138e044ca065f)
2024-11-09 10:22:44.920  5099-5099  DEBUG                   pid-5099                             A        #09 pc 00000000000c2e38  /data/app/~~zz4h7X7D_XggNeymJ1k82w==/com.margelo.nitroexample-wVR229i9TnWsolzHcppGUg==/base.apk!libhermes.so (offset 0x838000) (BuildId: e70878b706682e356226475d11c138e044ca065f)
2024-11-09 10:22:44.920  5099-5099  DEBUG                   pid-5099                             A        #10 pc 0000000000136c90  /data/app/~~zz4h7X7D_XggNeymJ1k82w==/com.margelo.nitroexample-wVR229i9TnWsolzHcppGUg==/base.apk!libhermes.so (offset 0x838000) (BuildId: e70878b706682e356226475d11c138e044ca065f)
2024-11-09 10:22:44.920  5099-5099  DEBUG                   pid-5099                             A        #11 pc 00000000000c2528  /data/app/~~zz4h7X7D_XggNeymJ1k82w==/com.margelo.nitroexample-wVR229i9TnWsolzHcppGUg==/base.apk!libhermes.so (offset 0x838000) (BuildId: e70878b706682e356226475d11c138e044ca065f)
2024-11-09 10:22:44.920  5099-5099  DEBUG                   pid-5099                             A        #12 pc 00000000000d2874  /data/app/~~zz4h7X7D_XggNeymJ1k82w==/com.margelo.nitroexample-wVR229i9TnWsolzHcppGUg==/base.apk!libhermes.so (offset 0x838000) (BuildId: e70878b706682e356226475d11c138e044ca065f)
2024-11-09 10:22:44.920  5099-5099  DEBUG                   pid-5099                             A        #13 pc 00000000000d4224  /data/app/~~zz4h7X7D_XggNeymJ1k82w==/com.margelo.nitroexample-wVR229i9TnWsolzHcppGUg==/base.apk!libhermes.so (offset 0x838000) (BuildId: e70878b706682e356226475d11c138e044ca065f)
2024-11-09 10:22:44.920  5099-5099  DEBUG                   pid-5099                             A        #14 pc 00000000000d38e0  /data/app/~~zz4h7X7D_XggNeymJ1k82w==/com.margelo.nitroexample-wVR229i9TnWsolzHcppGUg==/base.apk!libhermes.so (offset 0x838000) (BuildId: e70878b706682e356226475d11c138e044ca065f)
2024-11-09 10:22:44.920  5099-5099  DEBUG                   pid-5099                             A        #15 pc 00000000000c2628  /data/app/~~zz4h7X7D_XggNeymJ1k82w==/com.margelo.nitroexample-wVR229i9TnWsolzHcppGUg==/base.apk!libhermes.so (offset 0x838000) (BuildId: e70878b706682e356226475d11c138e044ca065f)
2024-11-09 10:22:44.920  5099-5099  DEBUG                   pid-5099                             A        #16 pc 00000000000c0f04  /data/app/~~zz4h7X7D_XggNeymJ1k82w==/com.margelo.nitroexample-wVR229i9TnWsolzHcppGUg==/base.apk!libhermes.so (offset 0x838000) (BuildId: e70878b706682e356226475d11c138e044ca065f)
2024-11-09 10:22:44.920  5099-5099  DEBUG                   pid-5099                             A        #17 pc 0000000000109254  /data/app/~~zz4h7X7D_XggNeymJ1k82w==/com.margelo.nitroexample-wVR229i9TnWsolzHcppGUg==/base.apk!libhermes.so (offset 0x838000) (BuildId: e70878b706682e356226475d11c138e044ca065f)
2024-11-09 10:22:44.920  5099-5099  DEBUG                   pid-5099                             A        #18 pc 00000000000af970  /data/app/~~zz4h7X7D_XggNeymJ1k82w==/com.margelo.nitroexample-wVR229i9TnWsolzHcppGUg==/base.apk!libhermes.so (offset 0x838000) (BuildId: e70878b706682e356226475d11c138e044ca065f)
2024-11-09 10:22:44.920  5099-5099  DEBUG                   pid-5099                             A        #19 pc 00000000004de8ac  /data/app/~~zz4h7X7D_XggNeymJ1k82w==/com.margelo.nitroexample-wVR229i9TnWsolzHcppGUg==/base.apk!libreactnative.so (offset 0xba8000) (facebook::react::RuntimeScheduler_Modern::performMicrotaskCheckpoint(facebook::jsi::Runtime&)+60) (BuildId: f7df2c604e5072c2)
2024-11-09 10:22:44.920  5099-5099  DEBUG                   pid-5099                             A        #20 pc 00000000004ddf14  /data/app/~~zz4h7X7D_XggNeymJ1k82w==/com.margelo.nitroexample-wVR229i9TnWsolzHcppGUg==/base.apk!libreactnative.so (offset 0xba8000) (facebook::react::RuntimeScheduler_Modern::runEventLoopTick(facebook::jsi::Runtime&, facebook::react::Task&, std::__ndk1::chrono::time_point<std::__ndk1::chrono::steady_clock, std::__ndk1::chrono::duration<long long, std::__ndk1::ratio<1l, 1000000000l> > >)+128) (BuildId: f7df2c604e5072c2)
2024-11-09 10:22:44.920  5099-5099  DEBUG                   pid-5099                             A        #21 pc 00000000004de26c  /data/app/~~zz4h7X7D_XggNeymJ1k82w==/com.margelo.nitroexample-wVR229i9TnWsolzHcppGUg==/base.apk!libreactnative.so (offset 0xba8000) (facebook::react::RuntimeScheduler_Modern::runEventLoop(facebook::jsi::Runtime&, bool)+144) (BuildId: f7df2c604e5072c2)
2024-11-09 10:22:44.920  5099-5099  DEBUG                   pid-5099                             A        #22 pc 000000000034a468  /data/app/~~zz4h7X7D_XggNeymJ1k82w==/com.margelo.nitroexample-wVR229i9TnWsolzHcppGUg==/base.apk!libreactnative.so (offset 0xba8000) (BuildId: f7df2c604e5072c2)
2024-11-09 10:22:44.920  5099-5099  DEBUG                   pid-5099                             A        #23 pc 000000000051bdf4  /data/app/~~zz4h7X7D_XggNeymJ1k82w==/com.margelo.nitroexample-wVR229i9TnWsolzHcppGUg==/base.apk!libreactnative.so (offset 0xba8000) (BuildId: f7df2c604e5072c2)
2024-11-09 10:22:44.920  5099-5099  DEBUG                   pid-5099                             A        #24 pc 0000000000019804  /data/app/~~zz4h7X7D_XggNeymJ1k82w==/com.margelo.nitroexample-wVR229i9TnWsolzHcppGUg==/base.apk!libfbjni.so (offset 0x808000) (facebook::jni::detail::MethodWrapper<void (facebook::jni::JNativeRunnable::*)(), &(facebook::jni::JNativeRunnable::run()), facebook::jni::JNativeRunnable, void>::dispatch(facebook::jni::alias_ref<facebook::jni::detail::JTypeFor<facebook::jni::HybridClass<facebook::jni::JNativeRunnable, facebook::jni::JRunnable>::JavaPart, facebook::jni::JRunnable, void>::_javaobject*>)+72) (BuildId: a22242831a7971267de570e06121acb588ce64cd)
2024-11-09 10:22:44.920  5099-5099  DEBUG                   pid-5099                             A        #25 pc 0000000000019744  /data/app/~~zz4h7X7D_XggNeymJ1k82w==/com.margelo.nitroexample-wVR229i9TnWsolzHcppGUg==/base.apk!libfbjni.so (offset 0x808000) (facebook::jni::detail::FunctionWrapper<void (*)(facebook::jni::alias_ref<facebook::jni::detail::JTypeFor<facebook::jni::HybridClass<facebook::jni::JNativeRunnable, facebook::jni::JRunnable>::JavaPart, facebook::jni::JRunnable, void>::_javaobject*>), facebook::jni::detail::JTypeFor<facebook::jni::HybridClass<facebook::jni::JNativeRunnable, facebook::jni::JRunnable>::JavaPart, facebook::jni::JRunnable, void>::_javaobject*, void>::call(_JNIEnv*, _jobject*, void (*)(facebook::jni::alias_ref<facebook::jni::detail::JTypeFor<facebook::jni::HybridClass<facebook::jni::JNativeRunnable, facebook::jni::JRunnable>::JavaPart, facebook::jni::JRunnable, void>::_javaobject*>))+60) (BuildId: a22242831a7971267de570e06121acb588ce64cd)
2024-11-09 10:22:44.920  5099-5099  DEBUG                   pid-5099                             A        #26 pc 0000000000025344  /data/app/~~zz4h7X7D_XggNeymJ1k82w==/com.margelo.nitroexample-wVR229i9TnWsolzHcppGUg==/oat/arm64/base.odex (art_jni_trampoline+116)
2024-11-09 10:22:44.920  5099-5099  DEBUG                   pid-5099                             A        #29 pc 00000000002ba80c  /data/app/~~zz4h7X7D_XggNeymJ1k82w==/com.margelo.nitroexample-wVR229i9TnWsolzHcppGUg==/oat/arm64/base.vdex (com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage+0)
2024-11-09 10:22:44.920  5099-5099  DEBUG                   pid-5099                             A        #33 pc 00000000002badb2  /data/app/~~zz4h7X7D_XggNeymJ1k82w==/com.margelo.nitroexample-wVR229i9TnWsolzHcppGUg==/oat/arm64/base.vdex (com.facebook.react.bridge.queue.MessageQueueThreadImpl.lambda$startNewBackgroundThread$2+70)
2024-11-09 10:22:44.920  5099-5099  DEBUG                   pid-5099                             A        #35 pc 00000000002ba8a4  /data/app/~~zz4h7X7D_XggNeymJ1k82w==/com.margelo.nitroexample-wVR229i9TnWsolzHcppGUg==/oat/arm64/base.vdex (com.facebook.react.bridge.queue.MessageQueueThreadImpl$$ExternalSyntheticLambda1.run+4)

Device

android emulator / device doesn't matter

Nitro Modules Version

0.15.0

Nitrogen Version

0.15.0

Can you reproduce this issue in the Nitro Example app here?

Yes, I can reproduce the same issue in the Example app here

Additional information

hannojg commented 2 weeks ago

Update: at first i thought this would be only an issue when building react native from source, but I just realized that its always happening in release mode on android (for the example app at least)

mrousavy commented 2 weeks ago
mrousavy commented 2 weeks ago

Hanno can you try to run each test individually to find out which test is actually crashing?

mrousavy commented 2 weeks ago

And second thing we can try is to edit NitroDefines.hpp to just always set NITRO_DEBUG to 0/undef'd, even in debug mode.

Then run the app in debug and see if it still crashes. If no, then maybe there is something happening in Hermes with NativeState.

hannojg commented 2 weeks ago

sure, let me test!

hannojg commented 2 weeks ago

Its the first two tests that are crashing:

The other tests seem to all work:

https://github.com/user-attachments/assets/fe27694e-aefc-4746-beef-b1bea660f8a3

mrousavy commented 2 weeks ago

Hm, could this be a Hermes bug? 🙈

The code that this test essentially runs is:

const prototype = Object.getPrototypeOf(testObject)
typeof prototype === 'object'
prototype[simpleFunc] != null || Object.keys(prototype).includes("simpleFunc")

Where testObject is an object created by Nitro via Object.create(XXX) (XXX being the prototype we want to test here) with NativeState.

cc @tmikov anything I'm doing wrong here?

hannojg commented 2 weeks ago

@mrousavy if i remove NITRO_DEBUG and run in debug mode the same tests are crashing!

mrousavy commented 2 weeks ago

wait whaaat

This function didn't throw when NITRO_DEBUG was true, so why should it suddenly fail if we remove those checks?

https://github.com/mrousavy/nitro/blob/6682b2d6fde2ecd4c479ed13e17d7d325c82dfc2/packages/react-native-nitro-modules/cpp/core/HybridFunction.hpp#L170-L221

..or do you think there's some kind of flattening going on? The object has a single __type property in debug, which is not available on release: https://github.com/mrousavy/nitro/blob/6682b2d6fde2ecd4c479ed13e17d7d325c82dfc2/packages/react-native-nitro-modules/cpp/core/HybridObject.cpp#L74-L77

hannojg commented 2 weeks ago

I think this isn't the place where its crashing:

https://github.com/mrousavy/nitro/blob/6682b2d6fde2ecd4c479ed13e17d7d325c82dfc2/packages/react-native-nitro-modules/cpp/core/HybridFunction.hpp#L170-L221

The place where its actually crashing is here:

CleanShot 2024-11-11 at 15 48 30

CleanShot 2024-11-11 at 15 48 50

mrousavy commented 2 weeks ago

Yes I know that it's crashing in getNativeState because apparently hasNativeState is false here.

I'm trying to figure out why hasNativeState is false; for that I was wondering where we actually have a different code-path than before (NITRO_DEBUG on vs off). The only place where there is actually a different code-path is where I set a __type property on the object that has a NativeState or Prototype - only here we have a different code-path in NITRO_DEBUG than in release.

Is there maybe something happening with the NativeState when the object does not have any properties? You can check this by reverting all changes again and just removing those 4 lines here and run it again: https://github.com/mrousavy/nitro/blob/6682b2d6fde2ecd4c479ed13e17d7d325c82dfc2/packages/react-native-nitro-modules/cpp/core/HybridObject.cpp#L74-L77

hannojg commented 2 weeks ago

Its still working in debug with the mentioned lines removed 🤔

mrousavy commented 2 weeks ago

Hm, maybe it is trying to call toString() on the Prototype which does not have a bound this/NativeState?

mrousavy commented 2 weeks ago

I finally figured it out after hours of debugging.

Context

In the Example app, we run tests and each tests then logs the result of the test. The first two tests of the example app tested the prototype of a HybridObject - so that's Object.getPrototypeOf(hybridObject).

All HybridObjects can be logged by calling hybridObject.toString(), and toString() is a method defined on the highest Prototype of the HybridObject prototype chain - HybridObject itself.

The way it works is simple - it gets the NativeState, unwraps it to the C++ class HybridObject, and calls HybridObject::toString() - which just returns the C++ _name.

This is a problem though - for HybridObjects (objects with NativeState) this works, but if we call it on the prototype directly it does not have a NativeState - because it's the prototype, not an actual instance of it.

toString() throws in debug

Calling toString() on an unbound prototype (the prototype itself, without NativeState) this throws , and in release it fully crashes the app.

The reason this worked before in debug is because of this code; https://github.com/mrousavy/nitro/blob/328a6e12519424e326550c1589d1bd546040952c/example/src/utils.ts#L20-L29

We caught the error, and just returned { [Object] ... } in this case. The error was silently swallowed.

Why assert(...) didn't catch this in release

Well, dumb mistake on my end - assert is compiled out in release.

Why value.toString() worked

Apparently this also threw, which silently caught the error. No idea why.

Solution

Now, I added some checks to my toString() function in the example to prevent calling toString() on an unbound prototype (so a object without NativeState). This now no longer crashes and just logs something different for prototypes, which is absolutely desireable.

Alternatively I could've made toString() work without NativeState, but that would've been a lot of code complexity, and potentially also a minor performance hit for an absolutely unnecessary feature; who in their right mind would stringify an object's prototype in a release build?