react-native icon indicating copy to clipboard operation
react-native copied to clipboard

App Crashes on Android 32bit When emit event from TurboModule

Open vladimirivanoviliev opened this issue 6 months ago • 8 comments

Description

Hello again everyone, @javache @cortinico.

This is continuation of this thread.

After testing the latest RC and nighly builds, crash appeared when emitting events from turbo modules on 32bit Android devices. The crash is always reproducible only on 32bit devices on signed production builds. I have created reproduction demo, which is basically the official demo code for creating turbo module with event:

note: nightly and v0.80-RC3 versions can be seen as PRs

Steps to reproduce

  1. Pull the repo, install the dependencies
  2. Run codegen on android
  3. Build signed apk. To create it you will need to create new demo key-store.
  4. To install the build apk in 32bit mode you can use adb -s YOURDEVICE install --abi armeabi-v7a android/app/release/app-release.apk
  5. Run the app, create key, save it. Than update the key and save it again. The app crashes when try to emit event from the turbo module.

React Native Version

0.80-rc3, nightly

Affected Platforms

Runtime - Android

Output of npx @react-native-community/cli info

System:
  OS: macOS 15.5
  CPU: (12) arm64 Apple M3 Pro
  Memory: 120.23 MB / 36.00 GB
  Shell:
    version: "5.9"
    path: /bin/zsh
Binaries:
  Node:
    version: 22.12.0
    path: /opt/homebrew/opt/nvm/versions/node/v22.12.0/bin/node
  Yarn:
    version: 1.22.22
    path: /opt/homebrew/opt/nvm/versions/node/v22.12.0/bin/yarn
  npm:
    version: 10.9.0
    path: /opt/homebrew/opt/nvm/versions/node/v22.12.0/bin/npm
  Watchman:
    version: 2024.12.02.00
    path: /opt/homebrew/bin/watchman
Managers:
  CocoaPods: Not Found
SDKs:
  iOS SDK:
    Platforms:
      - DriverKit 24.4
      - iOS 18.4
      - macOS 15.4
      - tvOS 18.4
      - visionOS 2.4
      - watchOS 11.4
  Android SDK:
    API Levels:
      - "28"
      - "29"
      - "30"
      - "34"
      - "35"
    Build Tools:
      - 34.0.0
      - 35.0.0
    System Images:
      - android-28 | Google APIs ARM 64 v8a
      - android-28 | Google ARM64-V8a Play ARM 64 v8a
      - android-29 | Google APIs ARM 64 v8a
      - android-29 | Google Play ARM 64 v8a
      - android-30 | Google APIs ARM 64 v8a
      - android-30 | Google Play ARM 64 v8a
      - android-34 | Google APIs ARM 64 v8a
      - android-34 | Google Play ARM 64 v8a
      - android-35 | Google Play ARM 64 v8a
      - android-35 | Pre-Release 16 KB Page Size Google Play ARM 64 v8a
      - android-Baklava | Pre-Release 16 KB Page Size Google Play ARM 64 v8a
    Android NDK: Not Found
IDEs:
  Android Studio: 2024.3 AI-243.24978.46.2431.13363775
  Xcode:
    version: 16.3/16E140
    path: /usr/bin/xcodebuild
Languages:
  Java:
    version: 17.0.12
    path: /usr/bin/javac
  Ruby:
    version: 2.6.10
    path: /usr/bin/ruby
npmPackages:
  "@react-native-community/cli":
    installed: 19.0.0
    wanted: 19.0.0
  react:
    installed: 19.1.0
    wanted: 19.1.0
  react-native:
    installed: 0.81.0-nightly-20250527-6c053006b
    wanted: nightly
  react-native-macos: Not Found
npmGlobalPackages:
  "*react-native*": Not Found
Android:
  hermesEnabled: true
  newArchEnabled: true
iOS:
  hermesEnabled: true
  newArchEnabled: true

Stacktrace or Logs

05-27 11:51:02.686  1426  2117 I ActivityManager: Killing 9327:com.android.keychain/1000 (adj 999): empty #21
05-27 11:51:02.687  1426  2117 I ActivityManager: Changes in 10254 5 to 19, 8 to 0
05-27 11:51:02.688  1426  1674 I UMR     : B|Compact com.google.android.googlequicksearchbox:search(18732)
05-27 11:51:02.689 18732 18732 I cmvo    : onStop
05-27 11:51:02.693  1426  1550 I libprocessgroup: Successfully killed process cgroup uid 1000 pid 9327 in 5ms
05-27 11:51:02.703  1426  1674 I UMR     : E|Compact d_rss=1372KB
05-27 11:51:02.709   904   904 I Zygote  : Process 9327 exited due to signal 9 (Killed)
05-27 11:51:02.833 11790 11790 F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
05-27 11:51:02.833 11790 11790 F DEBUG   : Build fingerprint: 'samsung/a32xeea/a32x:13/TP1A.220624.014/A326BXXSDCXJA:user/release-keys'
05-27 11:51:02.833 11790 11790 F DEBUG   : Revision: '7'
05-27 11:51:02.833 11790 11790 F DEBUG   : ABI: 'arm'
05-27 11:51:02.833 11790 11790 F DEBUG   : Processor: '7'
05-27 11:51:02.833 11790 11790 F DEBUG   : Timestamp: 2025-05-27 11:51:02.250465306+0300
05-27 11:51:02.833 11790 11790 F DEBUG   : Process uptime: 1s
05-27 11:51:02.833 11790 11790 F DEBUG   : Cmdline: com.awesomeproject
05-27 11:51:02.833 11790 11790 F DEBUG   : pid: 11740, tid: 11779, name: mqt_v_js  >>> com.awesomeproject <<<
05-27 11:51:02.833 11790 11790 F DEBUG   : uid: 10521
05-27 11:51:02.833 11790 11790 F DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x00000004
05-27 11:51:02.833 11790 11790 F DEBUG   : Cause: null pointer dereference
05-27 11:51:02.833 11790 11790 F DEBUG   :     r0  b7df5f00  r1  b7df5fa4  r2  00000004  r3  b7df5ff8
05-27 11:51:02.833 11790 11790 F DEBUG   :     r4  00000001  r5  e464cc9c  r6  b7df5f10  r7  00000000
05-27 11:51:02.833 11790 11790 F DEBUG   :     r8  e4001609  r9  b7df5f9c  r10 145fe958  r11 b7df5fa4
05-27 11:51:02.833 11790 11790 F DEBUG   :     ip  00000002  sp  b7df5ee0  lr  e1cca50b  pc  e1cc9a84
05-27 11:51:02.833 11790 11790 F DEBUG   : backtrace:
05-27 11:51:02.833 11790 11790 F DEBUG   :       #00 pc 0052ba84  /apex/com.android.art/lib/libart.so (art::(anonymous namespace)::ArgArray::BuildArgArrayFromVarArgs(art::ScopedObjectAccessAlreadyRunnable const&, art::ObjPtr<art::mirror::Object>, std::__va_list) (.__uniq.245181933781456475607640333933569312899)+164) (BuildId: bbc8525991a1fb6be508c71defdd34d8)
05-27 11:51:02.833 11790 11790 F DEBUG   :       #01 pc 0052c507  /apex/com.android.art/lib/libart.so (art::JValue art::InvokeVirtualOrInterfaceWithVarArgs<_jmethodID*>(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jmethodID*, std::__va_list)+386) (BuildId: bbc8525991a1fb6be508c71defdd34d8)
05-27 11:51:02.834 11790 11790 F DEBUG   :       #02 pc 003ded8d  /apex/com.android.art/lib/libart.so (art::JNI<false>::CallVoidMethodV(_JNIEnv*, _jobject*, _jmethodID*, std::__va_list)+444) (BuildId: bbc8525991a1fb6be508c71defdd34d8)
05-27 11:51:02.834 11790 11790 F DEBUG   :       #03 pc 00261129  /data/app/~~Rsv22hk04KoUaJ1tmZphlg==/com.awesomeproject-W_5OFIiJQo4tJbFAusGdfA==/base.apk!libreactnative.so (BuildId: aab956e17a170a7f)
05-27 11:51:02.834 11790 11790 F DEBUG   :       #04 pc 00333923  /data/app/~~Rsv22hk04KoUaJ1tmZphlg==/com.awesomeproject-W_5OFIiJQo4tJbFAusGdfA==/base.apk!libreactnative.so (facebook::react::JavaTurboModule::setEventEmitterCallback(facebook::jni::alias_ref<_jobject*>)+338) (BuildId: aab956e17a170a7f)
05-27 11:51:02.834 11790 11790 F DEBUG   :       #05 pc 0000b545  /data/app/~~Rsv22hk04KoUaJ1tmZphlg==/com.awesomeproject-W_5OFIiJQo4tJbFAusGdfA==/base.apk!libappmodules.so (facebook::react::NativeLocalStorageSpecJSI::NativeLocalStorageSpecJSI(facebook::react::JavaTurboModule::InitParams const&)+568) (BuildId: 1845c84c5d9dc31b8d30e3074a8418d7c586f3c5)
05-27 11:51:02.834 11790 11790 F DEBUG   :       #06 pc 0000ba05  /data/app/~~Rsv22hk04KoUaJ1tmZphlg==/com.awesomeproject-W_5OFIiJQo4tJbFAusGdfA==/base.apk!libappmodules.so (facebook::react::NativeLocalStorageSpec_ModuleProvider(std::__ndk1::basic_string<char, std::__ndk1::char_traits<char>, std::__ndk1::allocator<char> > const&, facebook::react::JavaTurboModule::InitParams const&)+84) (BuildId: 1845c84c5d9dc31b8d30e3074a8418d7c586f3c5)
05-27 11:51:02.834 11790 11790 F DEBUG   :       #07 pc 0000fa03  /data/app/~~Rsv22hk04KoUaJ1tmZphlg==/com.awesomeproject-W_5OFIiJQo4tJbFAusGdfA==/base.apk!libappmodules.so (facebook::react::javaModuleProvider(std::__ndk1::basic_string<char, std::__ndk1::char_traits<char>, std::__ndk1::allocator<char> > const&, facebook::react::JavaTurboModule::InitParams const&)+30) (BuildId: 1845c84c5d9dc31b8d30e3074a8418d7c586f3c5)
05-27 11:51:02.834 11790 11790 F DEBUG   :

MANDATORY Reproducer

https://github.com/vladimirivanoviliev/rn079eventcrash

Screenshots and Videos

No response

vladimirivanoviliev avatar May 27 '25 13:05 vladimirivanoviliev

It seems that on arm32 in packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java

this method

https://github.com/facebook/react-native/blob/e7901a720bcf3877e8a011f7b211c7d59c694853/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java#L139

is called with a null eventEmitterCallback which is assigned to mEventEmitterCallback in the following line. mEventEmitterCallback is then used to emit an event, but being null the app crashes.

lcarrettin avatar May 27 '25 14:05 lcarrettin

Hmm, I wonder if caching jmethodId here is unsafe. The base implementation of this method is shared across all classes though.

Could you try replacing static jmethodID cachedMethodId = nullptr; with jmethodID cachedMethodId = nullptr;?

It seems that on arm32 in packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java

this method

react-native/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java

Line 139 in e7901a7

protected void setEventEmitterCallback(CxxCallbackImpl eventEmitterCallback) { is called with a null eventEmitterCallback which is assigned to mEventEmitterCallback in the following line. mEventEmitterCallback is then used to emit an event, but being null the app crashes.

That would show up as a null pointer exception, which is not the error we're seeing.

javache avatar May 27 '25 15:05 javache

I started getting the same SIGABRT crashes after upgrading to 0.79.1. It seems to affect many users, but I haven’t found any reliable solution yet.

Image

burakakyol avatar May 27 '25 20:05 burakakyol

@javache I tried removing the cached method id, but that didn't help. Investigating the code seems that the culpitt might be the use of CallVoidMethod variadic function, which is unsafe on 32bit. I tried using the CallVoidMethodA instead on my side and the crash is fixed:

void JavaTurboModule::configureEventEmitterCallback() {
  JNIEnv* env = jni::Environment::current();
  static jmethodID cachedMethodId = nullptr;
  if (cachedMethodId == nullptr) {
    jclass cls = env->GetObjectClass(instance_.get());
    cachedMethodId = env->GetMethodID(
        cls,
        "setEventEmitterCallback",
        "(Lcom/facebook/react/bridge/CxxCallbackImpl;)V");
    FACEBOOK_JNI_THROW_PENDING_EXCEPTION();
  }

  auto callback = JCxxCallbackImpl::newObjectCxxArgs([&](folly::dynamic args) {
    auto eventName = args.at(0).asString();
    auto& eventEmitter = static_cast<AsyncEventEmitter<folly::dynamic>&>(
        *eventEmitterMap_[eventName].get());
    eventEmitter.emit(args.size() > 1 ? std::move(args).at(1) : nullptr);
  });

  jvalue args[1];
  args[0].l = callback.release();
  env->CallVoidMethodA(instance_.get(), cachedMethodId, args);
  FACEBOOK_JNI_THROW_PENDING_EXCEPTION();
}

@javache could you please verify that the fix is valid?

vladimirivanoviliev avatar May 28 '25 06:05 vladimirivanoviliev

Investigating the code seems that the culpitt might be the use of CallVoidMethod variadic function, which is unsafe on 32bit.

Do you have any references on why that would be unsafe on 32-bit? Switching to CallVoidMethodA seems fine, but we'd need a comment to explain why we're doing so.

javache avatar May 28 '25 10:05 javache

@javache From what I found, the variadic functions like CallVoidMethod are unsafe on 32bit due to not type checking the passed arguments at compile time. As far as I understand the 64bit cpus and ABIs are more forgiving with alignment and calling conventions. On 32bit the ABIs are strict as arguments are passed on the stack and if there is type/size/alignment issue it reads the wrong memory, which causes the SIGEGV crashes.

Edit: I also done extensive testing on my application with the above patch and everything seems stable now.

vladimirivanoviliev avatar May 28 '25 12:05 vladimirivanoviliev

Hey @javache , @cortinico, Do you think it's possible this fix to be reviewed and included in the 0.80 as the Turbo modules events are still broken in that version?

vladimirivanoviliev avatar May 29 '25 17:05 vladimirivanoviliev

@vladimirivanoviliev do you have a PR for this?

CaptainJeff avatar May 29 '25 20:05 CaptainJeff

Hey everyone, @CaptainJeff, @javache, @cortinico, I just opened PR with the above change:

  • https://github.com/facebook/react-native/pull/51695

vladimirivanoviliev avatar May 30 '25 13:05 vladimirivanoviliev

Is there any news or date on when the Stable release for the 0.8? been encountering so many errors doing with the PR to just fix this issue :'(

kenziy avatar May 31 '25 06:05 kenziy

@kenziy you can apply the patches manually as I already mentioned in the linked issue.

vladimirivanoviliev avatar Jun 01 '25 07:06 vladimirivanoviliev

Thanks @vladimirivanoviliev I encountered multiple issue working on the PR and I am still new to react-native infact this is my first application, but I am wondering.. is this issue didn't exist on previous version. as I am considering to try to downgrade the version. if YES can you suggest on what version?

kenziy avatar Jun 01 '25 08:06 kenziy

If this is your first application than most probably you are having different issues than the one we are discussing here. This issue is experienced only on 32bit android phones, and only when emitting events from custom turbo modules.

vladimirivanoviliev avatar Jun 01 '25 09:06 vladimirivanoviliev

No, I am having the similar issue on a 32bit the Stack trace shows facebook::react::JavaTurboModule::setEventEmitterCallback(facebook,... and due to it the crash rating on my apps in google play is keep on increasing, at the moment I am reaching 3%.. but yeah thanks, probably I will retry your resolution while waiting for the actual stable release

Thank you

kenziy avatar Jun 01 '25 09:06 kenziy

I'm also seeing this crash coming in a lot for my custom turbo module.

On RN 0.77.2

Image

sepperousseau avatar Jun 01 '25 10:06 sepperousseau

@sepperousseau I can confirm I'm facing the same issue with React Native 0.77.2, specifically on low-end Android devices. 52046

bonnmh avatar Jun 17 '25 08:06 bonnmh

Also having this issue on 0.77.2, 0.79.3 and 0.79.4. Tried applying the patch from @vladimirivanoviliev with variants using instance_ and jinstance, but neither are working unfortunately. Does anyone have a fix for 0.77 or 0.79?

m9tdev avatar Jun 18 '25 11:06 m9tdev

Tried applying the patch from @vladimirivanoviliev with variants using instance_ and jinstance, but neither are working unfortunately.

@mathieupost are you using build from source? As Android is prebuilt so applying patches will have no effects: https://reactnative.dev/contributing/how-to-build-from-source#update-your-project-to-build-from-source

cortinico avatar Jun 18 '25 13:06 cortinico

Applying the patch and building from source resolved the issue for me! RN 0.79.4

RyanTG avatar Jun 23 '25 19:06 RyanTG

Any chance this can be merged in a 0.79.5 release?

sepperousseau avatar Jun 24 '25 09:06 sepperousseau

Closing as this has been fixed and will ship in 0.80.1

cortinico avatar Jun 24 '25 10:06 cortinico

anyone tried with older versions? 0.76.9 ? shouldnt it be backported to at least >= 0.76 ?

OskarAtJoint avatar Aug 19 '25 06:08 OskarAtJoint

Yes it needs backporting if at all possible as it's present on our 0.76 version - updating to 0.79+ just isn't possible in the time we've got to resolve the crash.

domness avatar Aug 28 '25 20:08 domness

ended up disabling new arch for android.... building out the source with the fix created lots of other problems... build problems etc

OskarAtJoint avatar Aug 29 '25 06:08 OskarAtJoint

ended up disabling new arch for android.... building out the source with the fix created lots of other problems... build problems etc

What types of issues did you find after trying the build from source change?

domness avatar Aug 29 '25 08:08 domness

ended up disabling new arch for android.... building out the source with the fix created lots of other problems... build problems etc

What types of issues did you find after trying the build from source change?

mostly random timeouts and out of memory issues, building both locally and on circle, and dont wanna change to whole build setup......

OskarAtJoint avatar Aug 29 '25 08:08 OskarAtJoint