facebook / react-native

A framework for building native applications using React
https://reactnative.dev
MIT License
119.56k stars 24.37k forks source link

E/libc++abi: terminating with uncaught exception of type std::bad_cast: std::bad_cast #29377

Closed Nikituh closed 1 year ago

Nikituh commented 4 years ago

Description

As of version 0.62.0, there's a conflict in libc++_shared.so between react-native and tesseract. This issue can be observed with any version of ScanbotSDK, however, it only shows up as of 0.62.0 react-native version.

I already faced SDK linking issues with this version of react-native when I first tried it out. Then found that an additional required step is now adding the following to settings.gradle:

include ':react-native-scanbot-sdk'
project(':react-native-scanbot-sdk').projectDir =
        new File(rootProject.projectDir, '../node_modules/react-native-scanbot-sdk/android/app')

But, as I am posting this, it's still not enough. Workaround and details below.

React Native version:

System:
    OS: macOS 10.15.6
    CPU: (16) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
    Memory: 3.03 GB / 32.00 GB
    Shell: 5.7.1 - /bin/zsh
  Binaries:
    Node: 12.13.0 - ~/.nvm/versions/node/v12.13.0/bin/node
    npm: 6.12.0 - ~/.nvm/versions/node/v12.13.0/bin/npm
    Watchman: 4.9.0 - /usr/local/bin/watchman
  SDKs:
    iOS SDK:
      Platforms: iOS 13.5, DriverKit 19.0, macOS 10.15, tvOS 13.4, watchOS 6.2
    Android SDK:
      API Levels: 26, 28, 29
      Build Tools: 27.0.3, 28.0.3, 29.0.2, 29.0.3
      System Images: android-28 | Google Play Intel x86 Atom
      Android NDK: 21.0.6113669
  IDEs:
    Android Studio: 4.0 AI-193.6911.18.40.6514223
    Xcode: 11.5/11E608c - /usr/bin/xcodebuild
  npmPackages:
    react: 16.11.0 => 16.11.0 
    react-native: 0.62.2 => 0.62.2 
  npmGlobalPackages:
    react-native: 0.61.4

Steps To Reproduce

  1. Clone https://github.com/doo/scanbot-sdk-example-react-native/tree/v4.1.0
  2. Change "react-native-scanbot-sdk": "4.1.0-rc2", back to "react-native-scanbot-sdk": "4.1.0-beta10",
  3. react-native run-android
  4. Press Scan MRZ on ID Card
  5. E/libc++abi: terminating with uncaught exception of type std::bad_cast: std::bad_cast

The same can be reproduced with a hello-world app created via npx react-native init AwesomeProject

Expected Results

Well, I'd expect the MRZ Scanner to start. As you can observe when you change "react-native-scanbot-sdk" back to "4.1.0-rc2", where I've implemented the workaround.

Or you can change "react-native" to anything below "0.62", and it will run as expected.

Snack, code example, screenshot, or link to a repository:

Instead of snacking, I'll explain the process and workaround that I found.

First, the issue. When compiling our core with debug symbols attached, I can see that the bad_cast is, in fact, inside tesseract. In a relatively harmless piece of code, nonetheless:

const char* buffer = "NULL 0 NULL 0\n";
std::istringstream stream(buffer);
stream.imbue(std::locale::classic());
// 标 1 0,255,0,255,0,0,0,0,0,0 Han 68 0 68 标  # 标 [6807 ]x
stream >> std::setw(255) >> unichar >> std::hex >> properties >> std::dec;

If I move that same block back into our core, it passes through it with a breeze... but inside tesseract it crashes with the bad_cast exception inside c++ shared library. It cannot find a facet, that should be there in every case.

Well, at this point I was pretty dumbfounded, and cannot debug shared library without debug symbols and with optimizations.

Off to my next adventure: Building the standard library in debug mode. But of course, that cannot be done separately, so I had to download all of Google's monorepo (60gb, woo) and compile the entirety android NDK from source in debug, so I could see what the hell was going on in locale.cpp.

That step was a bit easier than I thought. Just sprinkled some of the following around in different makefiles:

LOCAL_CFLAGS += -O0 -UNDEBUG -g
LOCAL_CPPFLAGS += -O0 -UNDEBUG -g

Now I have the debug build of libc++_shared.so, weighing just shy of 6mb (a bit less than 1mb in release), that I copied to my NDK directory: /Users/$USER/Library/Android/sdk/ndk/19.2.5345600/sources/cxx-stl/llvm-libc++/libs/arm64-v8a

I specifically used the same NDK react-native is compiled with, as described here. And I also built react-native from source, just so I could control every aspect of it and specify which NDK to use in all cases...

And it works. No more crash. Cannot reproduce the issue with the debug build of libc++_shared.so. Well, what now?

So I included the debug build in our SDK and wrote a simple "postinstall" script that copies the binary to project/app/src/main/jniLibs and now the correct c++ standard library is included in the apk.

As you can see, that's still a... well, relatively dirty workaround. Still not sure what exactly changed in react-native builds between versions 0.61 and 0.62 on that level. Anyone?

Thank you for coming to my TED talk

TheLartians commented 4 years ago

We're experiencing a similar crash in our app after upgrading React Native from 0.61.5 to 0.63.2. While we are not using tesseract, we have our own C++ libraries which have worked fine before. After updating, we are experiencing a std::bad_cast exception in the yaml-cpp library originating from this line, which also uses a basic stringstream operation. In lldb I could verify that key is a valid, null-terminated char array, so the error appears to originate from the standard library itself. The problem persisted after linking against React Native's NDK version (19.2.5345600). Interestingly, we were able to 'resolve' the issue by also statically linking our library against the stl (setting the CMake parameter ANDROID_STL=c++_static), after which no exception is thrown and our code appears to run as expected. We have yet to test on a device outside of the simulator. Could the libc++_shared.so be broken somehow?

vikramuqudo commented 4 years ago

I am also facing the same issue on 0.62 and above. Although it seems to be working on 0.61.5 as commented above. I am using an android library which also contains the native libC++_shared.so. I have also checked with the latest NDK, but that does not solve the issue with 0.62 and above.

Waiting for a solution on this.

lendvir commented 4 years ago

Hi, Also experiencing similar issues. Using std such as stringstream stopped working, and causing crashes. It was working fine when using 0.61. Hoping to get this fixed. Thank you.

minhchienwikipedia commented 4 years ago

Any update about this issue? I get the same issue with "react-native": "0.62.2", anyone can help me resolve this issue? Thank you!

minhchienwikipedia commented 4 years ago

@Nikituh Can you share your script, file and steps to fix this issue at the moment?

TheLartians commented 4 years ago

FYI, I can confirm that for us statically linking against the STL (e.g. by passing the CMake parameter ANDROID_STL=c++_static) solved the issue for us in simulator and on-device.

minhchienwikipedia commented 4 years ago

@TheLartians Can you give me more detail? I mean steps to do it to resolve this issue. Thank you

TheLartians commented 4 years ago

Sure, though I'm not sure if this will be of much use to you, as we fixed the issue for our own self-maintained C++ library and don't use tesseract or derived projects. We simply added the following line to the gradle script, which is responsible for calling CMake.

    externalNativeBuild {
      cmake {
        arguments.add("-DCMAKE_BUILD_TYPE=Release")
+       arguments.add("-DANDROID_STL=c++_static")
        targets.add("path/to/CMake/project")
      }
    }

By statically linking against the STD, our library will not use the libc++_shared.so that is used by React Native, which fixed the crash for us. I guess a similar patch could temporarily fix tesseract as well, but I don't really know how it's built for React Native.

minhchienwikipedia commented 4 years ago

@TheLartians Thank you, I had to try it, it's no more crash but the app always reopens and not work as well. I think I'll downgrade to RN 0.61 and waiting for RN fix this problem!

Nikituh commented 4 years ago

@minhchienwikipedia I wouldn't count on the RN team addressing this issue any time soon. Not because I do not have faith in them, but simply because it's very difficult to even diagnose what exactly is causing this issue. My best guess is it'll happen when they upgrade the NDK.

Anyway, everything I did, with the jnilibs directory and custom libc++_shared.so build, is openly available within the package: https://www.npmjs.com/package/react-native-scanbot-sdk 😄

minhchienwikipedia commented 4 years ago

@Nikituh I resolved this issue by custom libc++_shared.so, thank you so much :D

pjivers-bom commented 4 years ago

Having the same problem with react-native 0.62.0 AND 0.63.2

ghost commented 4 years ago

This issue is preventing me upgrading from 0.61, and unfortunately none of the mentioned workarounds are of use as a 3rd party library is providing their own libc++_shared.so

decin commented 4 years ago

It seems to be a problem caused by the flipper library, and the restoration of the 0.61.0 flipper integration method seems to take effect If it goes back to 0.61.0, it seems that the picture is not rendered on ios 14.x devices?

Assaf1010 commented 4 years ago

Hi, Any expected date to fix this issue? How can we get the React-Native team to respond? The proposed "workarounds" are not acceptable. We need a fix!! This issue was opened on July 15 and I have yet to see any response from the react team....

khattab93 commented 3 years ago

Any updates?

cmario commented 3 years ago

Any updates?

tientruongvan1995 commented 3 years ago

I got this issue when implementing latest ZoomSDK. Please fix this.

qq435150756 commented 3 years ago

将Android NDK中C++ STL库动态链接改为静态链接 externalNativeBuild { cmake { cppFlags "" arguments "-DANDROID_STL=c++_static" //c++_shared } }

qq435150756 commented 3 years ago

将Android NDK中C ++ STL库动态链接 替换为静态链接 externalNativeBuild { cmake { cppFlags“” 参数“ -DANDROIDSTL = c ++ static” // c ++ _ shared } }

可解决.so库冲突问题

ph-teven commented 3 years ago

Having the same issue when using the HERE map sdk.

bibinprathap commented 3 years ago

Having Same issue with react-native v.0.63.3 with ArcGIS SDK v100.10.0 on Android Please Check Below repository for reproducing this issue. https://github.com/bibinprathap/ReactNative0.63.xarcgis

bibinprathap commented 3 years ago

After upgrading to react-native v0.64.0 , ArcGIS SDK v100.10.0 is working fine on android

TOrnelas commented 3 years ago

@minhchienwikipedia I wouldn't count on the RN team addressing this issue any time soon. Not because I do not have faith in them, but simply because it's very difficult to even diagnose what exactly is causing this issue. My best guess is it'll happen when they upgrade the NDK.

Anyway, everything I did, with the jnilibs directory and custom libc++_shared.so build, is openly available within the package: https://www.npmjs.com/package/react-native-scanbot-sdk 😄

I would just like to say you are a life saver!

Nikituh commented 3 years ago

I must say, having someone on GitHub tell me I'm a lifesaver is very humbling. Some day I'm going to tell my grandchildren about this.

Anyway, I also tried it out and, as @bibinprathap mentioned, this does indeed appear to be solved in v0.64.0. However, I'm reluctant to remove my workaround without a proper explanation of what the hell was going on.

TOrnelas commented 3 years ago

I am running v0.64.0 and it wasn't working for me until I added your files. However, my use case is a bit different. I am integrating OpenCV Android SDK v4.5.2 with React Native

Nikituh commented 3 years ago

For my test, I upgraded based on the guide here: https://react-native-community.github.io/upgrade-helper/?from=0.63.4&to=0.64.0

And I believe, specifically, the following line that forces a specific ndk version may be relevant:

ndkVersion = "20.1.5948944"
TOrnelas commented 3 years ago

That could be it. I had updated my NDK version to 22.1.7171670 prior to finding this solution. And the project I created, was already on v0.64.0. No need to upgrade RN version for me.

dulmandakh commented 3 years ago

We regularly update NDK version used in RN, and Android NDK deprecated libstdc++, then switched to libc++, so we had to switch from to libc++. See https://developer.android.com/ndk/guides/cpp-support

Also there is a notice for library developers.

Caution: JNI libraries distributed with Java AARs must not use the shared runtime to avoid conflicting with other libraries and the app. The warnings below still apply. See the documentation for Middleware Vendors for more information.

So I think it's best to file an issue to third party library provider

Kudo commented 3 years ago

The problem may come from conflict version of libc++_shared.so (between r20 and r21)

scanbot sdk bundled libc++_shared.so with ndk r21. checked from the sdk 1.70.1 here

react native 0.62/0.63 bundled with ndk r20

some suggestion to add packagingOptions.pickFirst in build.gradle, but the reality is that which libc++_shared.so to be picked is uncertain. that's why i proposed to remove packagingOptions.pickFirst in react native template after 0.63.

even as far as i know, ndk maintains ABI stability well between updates. don't know what happened between ndk r20 and r21. the formal solution might be to build react native from source with ndk r21 + pickFirst (assuming scanbot sdk cannot build from source). but if what @Nikituh mention that react native 0.64 fixed the problem, maybe ndk fixed the compatibility issue after r20b (react native 0.64 bump ndk to r20b)

Zshay2203 commented 3 years ago

Hi,

In the past weeks, I tried to investigate the issue, and apparently, the only solution for it (unless Facebook solves the issue before) is to build your native code using the static version of libc++.

In addition, I kept looking for workarounds, and today I found a one, which some of you (including me) will call dirty or nasty - but it works. I am sharing it with you so can provide your opinions on it (and maybe use it too...), and MORE: explain why it works and whether it could affect RN's functionality:

In the method onCreate() of the RN's class MainApplication.java was changed so its first action is loading libc++_shared.so to the app's memory before any other library RN's code loads:

From:

@Override
  public void onCreate() {
    super.onCreate();
    SoLoader.init(this, /* native exopackage */ false);
    initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
  }

To:

@Override
  public void onCreate() {
    System.loadLibrary("c++_shared");
    super.onCreate();
    SoLoader.init(this, /* native exopackage */ false);
    initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
  }

The reason I took the liberty to make this change is that this class must change whenever a Native module is added to the RN class (See RN's documentation https://reactnative.dev/docs/0.61/native-modules-android#register-the-module) ...

In order to test the change, I used two examples:

  1. The sample code that fails, which is included in the issue's description (with some minor adaptations...) - (Verified that the substring "NULL" from buffer is no successfully assigned to unichar)
    const char* buffer = "NULL 0 NULL 0\n";
    std::istringstream stream(buffer);
    stream.imbue(std::locale::classic());
    // 标 1 0,255,0,255,0,0,0,0,0,0 Han 68 0 68 标  # 标 [6807 ]x
    stream >> std::setw(255) >> unichar >> std::hex >> properties >> std::dec;
  2. A conversion from a string to a number, which failed In my company's code:
    std::string in_str_ = "1234"; 
    double out_number_ = 0.0;
    std::istringstream iss(in_str_);
    iss >> out_number_;

    Thanks Shay

Zshay2203 commented 3 years ago

Hi @Kudo,

Last week I found a workaround to the above failure - by explicitly loading libc++_shared.so before RN loads its own Native Shared Libraries. This change does not require any other change and was verified on different RN apps.

If the issue is still relevant for you, I will be more than happy to have your comments on it. Thanks Shay

murtazabeans commented 3 years ago

@Zshay2203 , you're a rockstar. Though I am still struggling to figure out the future impacts with react native after applying this fix. Do you have any updates on this?

Zshay2203 commented 3 years ago

@Zshay2203 , you're a rockstar. Though I am still struggling to figure out the future impacts with react native after applying this fix. Do you have any updates on this?

@murtazabeans, You've got me, I am actually Elvis Presley ... Thanks for the compliment!

Regarding your question, a couple of customers of the company I am working for have applied the workaround in their app without any side effects.

Thinking logically, I really don't think this fix should have any side effect on RN's functionality for the following reasons:

  1. As stated in the issue's description, a call to a steam's ">>" operator fails due to a missing facet. Using Android Studio's debugger, I reached the point of failure: Attempt to read an invalid value, which is stored in _Facet::id - in the file: __locale under /sources/cxx-stl/llvm-libc++/include:

    template <class _Facet>
    inline _LIBCPP_INLINE_VISIBILITY
    const _Facet&
    use_facet(const locale& __l)
    {
    return static_cast<const _Facet&>(*__l.use_facet(_Facet::id));
    }

    My 100% guess is that RN's c++ code sets a locale with it starts when it does not have a specific value, and probably deallocates but its reference is stored in _Facet::id.

  2. Since the failure lies deep inside a commonly used C++ STL code and ONLY the C++ of RN Bridges is affected by it and not a C++ code of RN then I can conclude that RN does not use it at all.

It would be great if one of RN's developers could comment on that.

thanks again Shay

murtazabeans commented 3 years ago

@Zshay2203 , I think react native team should update the NDK. Currently the ndk used by react native is 20.1.5948944 which is marked as Unsupported type. It will resolve the problem if the ndk is updated sometime in future.

I have opened a bug on their team for this - https://github.com/facebook/react-native/issues/31701

abarbeitohub commented 3 years ago

Here still waiting for the fix from RN. I have issue with amazon-chime-sdk

github-actions[bot] commented 1 year ago

This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.

github-actions[bot] commented 1 year ago

This issue was closed because it has been stalled for 7 days with no activity.