-2

I was experimenting with CryptoPP library and I noticed it crashes in some cases, on investigating further, I saw that when it threw an exception, on linux it caught it too , but on android, it doesnt. So i made a very simple sanity check, here it is :

void random_test() {
    LOGD("EXCEPTION  : THROW ");
  throw Exception();
}

And then I call it so :

try {
    random_test();
} catch (Exception e ) {
    LOGD("EXCEPTION CAUGHT");
}

It doesnt go to Exception caught. This is the output from logcat:

2022-07-07 01:54:23.156 24102-24186/ D/JNIpart: EXCEPTION : THROW 2022-07-07 01:54:23.157 24102-24186/ E/libc++abi: terminating with uncaught exception of type cv::Exception

Then I tried this

try {
    random_test();
} catch (...) {
    LOGD("EXCEPTION CAUGHT");
}

And this catches the exception.

Now in CryptoPP library: https://github.com/weidai11/cryptopp/blob/9ea66ce4d97d59d61e49c93f5af191107ebd1925/asn.cpp#L559 This is where exception is thrown, and when we try to catch it like this :

catch (const BERDecodeErr e)
{
    LOGD("QRCPP : CATCH THE EXCEPTION FFS  %s ", e.what());
}

And the code still crashes, even with this code :

catch (...)
{
    LOGD("QRCPP : CATCH THE EXCEPTION FFS  %s ", e.what());
}
Hardik Gupta
  • 1
  • 1
  • 4
  • To be clear, we dont get this exception with same code on iOS , Linux and Windows. – Hardik Gupta Jul 07 '22 at 00:10
  • 2
    The error message says that the type really is `cv::Exception`. Are you sure that both `Exception` in the `throw` and in the `catch` are referring to the same type? How are you importing that type into the scope(s)? – user17732522 Jul 07 '22 at 00:12
  • Let me make it both cv::Exception, I do have namespace cv:: included, so maybe thats why. – Hardik Gupta Jul 07 '22 at 00:13
  • For a test globally qualify both, i.e. `::cv::Exception`. Also make sure that `Exception` is not part of any unnamed namespace (assuming the `throw` and `catch` are in different translation units), because then they will be different types. – user17732522 Jul 07 '22 at 00:14
  • Side note: [Prefer to catch by `const` reference.](https://stackoverflow.com/questions/2145147/why-catch-an-exception-as-reference-to-const) – user4581301 Jul 07 '22 at 00:16
  • If you catch by-value, then if the copy constructor throws an exception, the program will call `std::terminate` (and abort) as well. So it is safer to catch by-reference. – user17732522 Jul 07 '22 at 00:16
  • Both are cv::Exception, still it doesnt catch it, but ... does catch it, That doesnt work with BERDecodeErr – Hardik Gupta Jul 07 '22 at 00:18
  • I tried catch (const BERDecodeErr&) { } Still same error . This works on every other platform, even wasm. – Hardik Gupta Jul 07 '22 at 00:19
  • Are exceptions enabled in every relevant translation unit and library? I don't know anything about Android NDK, so that is where my ability to help ends, but from what I can tell in other questions here, they are disabled by-default. E.g.: https://stackoverflow.com/questions/30777590/android-ndk-exceptions, https://stackoverflow.com/questions/4663291/android-ndk-r5-and-support-of-c-exception – user17732522 Jul 07 '22 at 00:24
  • 2022-07-07 02:24:21.209 28471-28648/com.identy.ocr.customer E/libc++abi: terminating with uncaught exception of type CryptoPP::BERDecodeErr: BER decode error This is the output with const reference. The library is built by cmake which then adds a subdirectory, which adds cryptocpp as another subdirectory, I have added "-fexceptions" in CMAKE_CXX_FLAGS – Hardik Gupta Jul 07 '22 at 00:26
  • So the exception is defined as :class CRYPTOPP_DLL BERDecodeErr : public InvalidArgument { public: BERDecodeErr() : InvalidArgument("BER decode error") {} BERDecodeErr(const std::string &s) : InvalidArgument(s) {} }; InvalidArguments is defined as : class CRYPTOPP_DLL InvalidArgument : public Exception { public explicit InvalidArgument(const std::string &s) : Exception(INVALID_ARGUMENT, s) {} }; Exception as : class CRYPTOPP_DLL Exception : public std::exception { ....} So it does inherit std::exception, so it should work. – Hardik Gupta Jul 07 '22 at 00:29

1 Answers1

0

The most common cause is exception types that are missing key functions. https://developer.android.com/ndk/guides/common-problems#rttiexceptions_not_working_across_library_boundaries

RTTI behaves differently in a plugin environment like JNI than it does in a typical executable. Without key functions, type info may not merge correctly depending on your exact library load order and symbol use. If they do not merged, they are different types according to the C++ ABI. Adding a key function to your classes ensures that a single definition of the typeinfo will be emitted and that no merging is required.

Some platforms do not follow the C++ ABI, and allow two types to be equal if their type names match (as defined by strcmp). This can result in false positives, so Android follows the spec explicitly. aiui Apple does too. GNU is the only platform I know of that doesn't.

Dan Albert
  • 10,079
  • 2
  • 36
  • 79