Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] Unable to catch exception with NDK18b and Clang #889

Closed
alexgarret opened this issue Jan 21, 2019 · 14 comments
Closed

[BUG] Unable to catch exception with NDK18b and Clang #889

alexgarret opened this issue Jan 21, 2019 · 14 comments
Labels

Comments

@alexgarret
Copy link

alexgarret commented Jan 21, 2019

Description

Hi,

I work with a C++ stack cross-compiled for Android. It builds correctly for both armeabi-v7a and arm64-v8a architectures.
When I run the apk containing the 32 bits library, my application crashes as soon as a C++ exception is thrown (even when there is a catch all statement...). I did some research and found a lot of interesting threads about libunwind/libgcc that need to be excluded when linking, but it does not fix my problem. More over, in the toolchain given by the NDK, I saw that these linker flags were already
added... I was wondering if these flags need to be set at the end of the flags list or at the beginning ?

When I run the apk containing the 64 bits library, there is no problem with the exception thrown.

EDIT: For the description below, lib1 and lib2 are static libraries used to build my shared library.

When I set ANDROID_STL to c++_shared, I am able to catch an exception in lib1 thrown from lib1 as well, otherwise I am unable to catch an exception in lib1 thrown from lib2.
When I set ANDROID_STL to c++_static, I am directly unable to catch an exception thrown within the same lib.

Anyway, I am lacking of ideas to fix this, I am open to any suggestions.

Here is the link command output:

/Users/alex/Library/Android/ndk/android-ndk-r18b/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang++ --target=armv7-none-linux-androideabi21 --gcc-toolchain=/Users/alex/Library/Android/ndk/android-ndk-r18b/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64 --sysroot=/Users/alex/Library/Android/ndk/android-ndk-r18b/sysroot -fPIC -isystem /Users/alex/Library/Android/ndk/android-ndk-r18b/sysroot/usr/include/arm-linux-androideabi -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb -Wa,--noexecstack -Wformat -Werror=format-security -std=c++11 -frtti -fexceptions -fdiagnostics-color -Wall -Wextra -Wpedantic -Wno-deprecated-register -Wno-nested-anon-types -Wno-missing-field-initializers -Werror-implicit-function-declaration -Wnon-virtual-dtor -O0 -fno-limit-debug-info -Wl,--whole-archive /Users/alex/dev/meta_5.12_ndk18/staging/android/armv7-a/lib/libAndroidToolsBased.a -Wl,--no-whole-archive -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,/Users/alex/Library/Android/ndk/android-ndk-r18b/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/libunwind.a -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libatomic.a -nostdlib++ --sysroot /Users/alex/Library/Android/ndk/android-ndk-r18b/platforms/android-21/arch-arm -Wl,--build-id -Wl,--warn-shared-textrel -Wl,--fatal-warnings -Wl,--fix-cortex-a8 -Wl,--exclude-libs,libunwind.a -L/Users/alex/Library/Android/ndk/android-ndk-r18b/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a -Wl,--no-undefined -Wl,-z,noexecstack -Qunused-arguments -Wl,-z,relro -Wl,-z,now -shared -Wl,-soname,libblazeandroidd.so -o libblazeandroidd.so CMakeFiles/blazeandroid-jni.dir/src/SetupConfigurator.cpp.o CMakeFiles/blazeandroid-jni.dir/src/Jni.cpp.o /Users/alex/dev/meta_5.12_ndk18/staging/android/armv7-a/lib/libAndroidToolsBased.a -landroid -llog /Users/alex/Qt5.12/5.12.0/android_armv7/lib/libQt5AndroidExtras.so /Users/alex/Qt5.12/5.12.0/android_armv7/lib/libQt5Core.so -latomic -lm "/Users/alex/Library/Android/ndk/android-ndk-r18b/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/libc++_static.a" "/Users/alex/Library/Android/ndk/android-ndk-r18b/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/libc++abi.a" "/Users/alex/Library/Android/ndk/android-ndk-r18b/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/libunwind.a" "-ldl"

Environment Details

  • NDK Version: 18b
  • Build system: cmake
  • Host OS: Mac,
  • Compiler: Clang
  • ABI: armeabi-v7a
  • STL: c++_static and c++_shared
  • NDK API level: 21
  • Device API level: 26
@alexgarret alexgarret added the bug label Jan 21, 2019
@DanAlbert
Copy link
Member

The only thing I can think to recommend is to try the usual readelf diagnosis. readelf -sW /Users/alex/dev/meta_5.12_ndk18/staging/android/armv7-a/lib/libAndroidToolsBased.a | grep _Unwind. If there are any symbols in that list that aren't marked UND, that's unusual.

/Users/alex/dev/meta_5.12_ndk18/staging/android/armv7-a/lib/libAndroidToolsBased.a

This library appears to be linked twice, and the first use of it doesn't appear to be in the right order.

I sort of doubt that's the issue since it's a static library and shouldn't contain any of the unwind pieces that usually cause this kind of problem, but it's the only thing I see here that's out of the ordinary.

I was wondering if these flags need to be set at the end of the flags list or at the beginning ?

I don't think order matters with -Wl,--exclude-libs. If it does, it would most likely be the case that it needs to appear before the matching library is linked. That's already the case here (libgcc is implicitly added by the compiler and will be added after all the flags listed here). This has been working for us with the CMake toolchain, so one of those assumptions seems to be correct.

@alexgarret
Copy link
Author

alexgarret commented Jan 23, 2019

Thank's for your reply @DanAlbert, here is the output of the readelf command for the static lib I link with:

7932: 00000000 0 NOTYPE GLOBAL DEFAULT UND _Unwind_Resume
19533: 00000000 0 NOTYPE GLOBAL DEFAULT UND _Unwind_Resume
10433: 00000000 0 NOTYPE GLOBAL DEFAULT UND _Unwind_Resume
4233: 00000000 0 NOTYPE GLOBAL DEFAULT UND _Unwind_Resume
9013: 00000000 0 NOTYPE GLOBAL DEFAULT UND _Unwind_Resume
6076: 00000000 0 NOTYPE GLOBAL DEFAULT UND _Unwind_Resume
11203: 00000000 0 NOTYPE GLOBAL DEFAULT UND _Unwind_Resume

All the symbols are marked with UND, so it seems correct.

This lib is built with Qt5.12.0 and linked against some of the prebuilt shared libraries, all the shared libs are packaged into the final apk, for example libQt5Core.so. Here is the readelf output for libQt5Core.so:

3: 001db439 104 FUNC GLOBAL DEFAULT 12 _Unwind_Resume
6282: 001db435 2 FUNC GLOBAL DEFAULT 12 _Unwind_Complete
6283: 001db509 12 FUNC GLOBAL DEFAULT 12 _Unwind_DeleteException
6284: 001db4a1 52 FUNC GLOBAL DEFAULT 12 _Unwind_GetLanguageSpecificData
6285: 001db4d5 52 FUNC GLOBAL DEFAULT 12 _Unwind_GetRegionStart
6286: 001db27d 160 FUNC GLOBAL DEFAULT 12 _Unwind_RaiseException
6287: 001daf8d 172 FUNC GLOBAL DEFAULT 12 _Unwind_VRS_Get
6288: 001dad19 628 FUNC GLOBAL DEFAULT 12 _Unwind_VRS_Interpret
6289: 001db0e5 336 FUNC GLOBAL DEFAULT 12 _Unwind_VRS_Pop
6290: 001db039 172 FUNC GLOBAL DEFAULT 12 _Unwind_VRS_Set
6304: 00000000 0 FUNC GLOBAL DEFAULT UND __gnu_Unwind_Find_exidx
21832: 001db31d 280 FUNC LOCAL DEFAULT 12 _ZL13unwind_phase2P13unw_context_tP12unw_cursor_tP21_Unwind_Control_Blockb
21833: 001db23d 48 FUNC LOCAL DEFAULT 12 _ZN12_GLOBAL__N_114unwindOneFrameEjP21_Unwind_Control_BlockP15_Unwind_Context
> 29800: 001db439 104 FUNC GLOBAL DEFAULT 12 _Unwind_Resume
36079: 001db435 2 FUNC GLOBAL DEFAULT 12 _Unwind_Complete
36080: 001db509 12 FUNC GLOBAL DEFAULT 12 _Unwind_DeleteException
36081: 001db4a1 52 FUNC GLOBAL DEFAULT 12 _Unwind_GetLanguageSpecificData
36082: 001db4d5 52 FUNC GLOBAL DEFAULT 12 _Unwind_GetRegionStart
36083: 001db27d 160 FUNC GLOBAL DEFAULT 12 _Unwind_RaiseException
36084: 001daf8d 172 FUNC GLOBAL DEFAULT 12 _Unwind_VRS_Get
36085: 001dad19 628 FUNC GLOBAL DEFAULT 12 _Unwind_VRS_Interpret
36086: 001db0e5 336 FUNC GLOBAL DEFAULT 12 _Unwind_VRS_Pop
36087: 001db039 172 FUNC GLOBAL DEFAULT 12 _Unwind_VRS_Set
36101: 00000000 0 FUNC GLOBAL DEFAULT UND __gnu_Unwind_Find_exidx

Unwind* are all marked with 12.

Here is the readelf output for my shared lib:

3: 00000000 0 FUNC GLOBAL DEFAULT UND _Unwind_Resume
7578220: 00000000 0 FUNC GLOBAL DEFAULT UND _Unwind_Resume

They are marked with UND, does it seem right for you, or is it going to conflict some way ?

EDIT: I have a little bit more of informations... For the description below, lib1 and lib2 are static libraries used to build my shared library.

When I set ANDROID_STL to c++_shared, I am able to catch an exception in lib1 thrown from lib1 as well, otherwise I am unable to catch an exception in lib1 thrown from lib2.

When I set ANDROID_STL to c++_static, I am directly unable to catch an exception thrown within the same lib.

@alexcohn
Copy link

I see only one static library (libAndroidToolsBased.a) in the link command. Being inside whole-archive, it makes no sense to have it written again, but this cannot make things worse. What can make things worse, is that QT shared libs and your libblazeandroidd.so can be both involved in one call stack, and therefore they must both use c++_shared STL.

@alexgarret
Copy link
Author

alexgarret commented Jan 23, 2019

@alexcohn I removed some static libraries from the description to make it a bit clearer. In addition to libAndroidToolsBased.a I have around 10 more static libraries to link with, they are all inside the whole-archive.

I agree with you, according to the NDK documentation I must use the c++_shared STL instead of c++_static because of the other shared libraries packaged in my apk, and this is what I am trying to do.(I assume that libQt5Core.so has been built with c++_shared as the STL as well...)

I don't understand why the 64 bits cross-compilation is not affected by that problem.

@DanAlbert
Copy link
Member

I don't understand why the 64 bits cross-compilation is not affected by that problem.

Different unwinder that's less temperamental but doesn't work on ARM32.

@DanAlbert
Copy link
Member

Based on that readelf output, your Qt libs weren't built correctly. STL static vs shared aside, they also need to be built with the -Wl,--exclude-libs flags.

@alexgarret
Copy link
Author

@DanAlbert Are you talking about the libQt5Core.so ? If yes, how did you find that libQt5Core.so was built with the static STL instead of the shared with the readelf output ?

I used the pre-built libraries, I will probably need to build them myself.

@DanAlbert
Copy link
Member

If yes, how did you find that libQt5Core.so was built with the static STL instead of the shared with the readelf output ?

I don't know that it was, I just know that the unwinder was linked incorrectly. If you do want to figure that out, readelf -sW lib | c++filt | grep std:: might be of some use. If symbols are std::blah then it's using gnustl, std::__ndk1::blah is libc++, UND means shared and not UND means static.

@alexgarret
Copy link
Author

Hi guys,

I think I've understood what is happening. To sum up, I am using c++_shared to cross-compile my static libs and use them to generate my shared lib packaged in the final apk.
In one of those libs, I define a custom exception inheriting from std::exception, and when I throw a custom exception from lib1 and try to catch it from lib2 I have a crash on the symbol Unwind_Resume in libc.so.

What I did not see directly was that the symbol before this one was an Unwind_Resume symbol in libz.so. So why libz appears in my stack trace ?
I found that some of my third dependencies (OpenSSL,...) are actually using libz, and the libz used was the one in /system/lib on my android device.
I think that when I throw an exception, the symbol Unwind_Resume is searched and unfortunately libz bundled in my system was loaded by one of the third parties and that lib defines this symbol. That's why I ended up with this strange stack using libz then libc to unwind.

I decided to package the libz bundled within the ndk into my apk and load it explicitly at the beginning of my app to force it to use the "good one" without the Unwind_ symbols, and it worked !

I am not sure my workaround is great, I don't know if this could be dangerous in some way, can you tell me what you think about this ?
I am still looking for a way to indicate my shared lib to use the libz.so I packaged within my apk instead of the one under /system/lib/, without explicitly opening this lib at the beginning of my app. I was wondering if I can use something like the rpath to do that, CMAKE_INSTALL_RPATH for example ?

Thank's in advance.

@alexcohn
Copy link

alexcohn commented Feb 5, 2019

I would rather rebuild zlib from sources. OpenSSL is a pretty dangerous dependency on its own, I believe you can have it linked to zlib statically.

@DanAlbert
Copy link
Member

I found that some of my third dependencies (OpenSSL,...) are actually using libz, and the libz used was the one in /system/lib on my android device

This is valid. libz is an NDK library.

I think that when I throw an exception, the symbol Unwind_Resume is searched and unfortunately libz bundled in my system was loaded by one of the third parties and that lib defines this symbol. That's why I ended up with this strange stack using libz then libc to unwind.

This is the part that shouldn't be happening. For one, libz shouldn't have _Unwind_Resume since it's a C library... but that's not the real problem. No exception you throw should ever be handled outside the throwing library. If you've build the library correctly it is not possible for this to happen because the loader will always prefer a LOCAL symbol to a GLOBAL symbol (I think this might actually be pre-resolved when the library is linked, so it's not even possible for the loader to screw this up?).

I decided to package the libz bundled within the ndk into my apk and load it explicitly at the beginning of my app to force it to use the "good one" without the Unwind_ symbols, and it worked !

There's no code in that library. It's a stub. I suspect the only reason this "worked" is because you haven't executed any of the libz.so code yet.

I am not sure my workaround is great, I don't know if this could be dangerous in some way, can you tell me what you think about this ?

The proper fix is to ensure that the libraries in your app have been built properly.

@alexgarret
Copy link
Author

alexgarret commented Feb 14, 2019

Hi @DanAlbert , when you say "If you've build the library correctly it is not possible for this to happen because the loader will always prefer a LOCAL symbol to a GLOBAL symbol (I think this might actually be pre-resolved when the library is linked, so it's not even possible for the loader to screw this up?).", do you mean that I need to explicitly link my shared lib with a specific lib ?

Here is the backtrace I got when using the debugger and LLDB:


* thread #1, name = '<package_name>', stop reason = signal SIGSEGV: invalid address (fault address: 0xe)
  * frame #0: 0xef66027c libc.so`__gnu_Unwind_Resume + 8
    frame #1: 0xedb6896c libz.so`_Unwind_Resume + 24
    frame #2: 0xcd304fa8 libblazeandroidd.so`Lib2::Test::Test(this=0x00000000) at Test.cpp:19
    frame #3: 0xcd28ae94 libblazeandroidd.so`Lib1::Test::Test(this=0xffce87a8) at Test.cpp:20
    frame #4: 0xcd326a4c libblazeandroidd.so`::Java_<package_name>_Application_crash(env=0xecbb2230, application=0xffce87dc) at Jni.cpp:36
    frame #5: 0xeca9e8aa libart.so`art_quick_generic_jni_trampoline + 42
    frame #6: 0xeca9ab62 libart.so`art_quick_invoke_stub_internal + 66
    frame #7: 0xeca9f0d8 libart.so`art_quick_invoke_stub + 232
    frame #8: 0xec7658ac libart.so`art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*) + 144
    frame #9: 0xec8ae3ba libart.so`art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::DexFile::CodeItem const*, art::ShadowFrame*, art::JValue*) + 242
    frame #10: 0xec8a996a libart.so`bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*) + 578
    frame #11: 0xec8c92cc libart.so`bool art::interpreter::DoInvoke<(art::InvokeType)1, false, false>(art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*) + 304
    frame #12: 0xec8c5f04 libart.so`art::JValue art::interpreter::ExecuteSwitchImpl<false, false>(art::Thread*, art::DexFile::CodeItem const*, art::ShadowFrame&, art::JValue, bool) + 31900
    frame #13: 0xec890f3c libart.so`art::interpreter::Execute(art::Thread*, art::DexFile::CodeItem const*, art::ShadowFrame&, art::JValue, bool) + 424
    frame #14: 0xec89626e libart.so`art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::DexFile::CodeItem const*, art::ShadowFrame*, art::JValue*) + 146
    frame #15: 0xec8a9954 libart.so`bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*) + 556
    frame #16: 0xec8c8098 libart.so`bool art::interpreter::DoInvoke<(art::InvokeType)2, false, false>(art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*) + 420
    frame #17: 0xec8c5ea0 libart.so`art::JValue art::interpreter::ExecuteSwitchImpl<false, false>(art::Thread*, art::DexFile::CodeItem const*, art::ShadowFrame&, art::JValue, bool) + 31800
    frame #18: 0xec890f3c libart.so`art::interpreter::Execute(art::Thread*, art::DexFile::CodeItem const*, art::ShadowFrame&, art::JValue, bool) + 424
    frame #19: 0xec89626e libart.so`art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::DexFile::CodeItem const*, art::ShadowFrame*, art::JValue*) + 146
    frame #20: 0xec8a9954 libart.so`bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*) + 556
    frame #21: 0xec8c8098 libart.so`bool art::interpreter::DoInvoke<(art::InvokeType)2, false, false>(art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*) + 420
    frame #22: 0xec8c5ea0 libart.so`art::JValue art::interpreter::ExecuteSwitchImpl<false, false>(art::Thread*, art::DexFile::CodeItem const*, art::ShadowFrame&, art::JValue, bool) + 31800
    frame #23: 0xec890f3c libart.so`art::interpreter::Execute(art::Thread*, art::DexFile::CodeItem const*, art::ShadowFrame&, art::JValue, bool) + 424
    frame #24: 0xec89626e libart.so`art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::DexFile::CodeItem const*, art::ShadowFrame*, art::JValue*) + 146
    frame #25: 0xec8a9954 libart.so`bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*) + 556
    frame #26: 0xeca85914 libart.so`MterpInvokeDirect + 364
    frame #27: 0xeca8cf18 libart.so`ExecuteMterpImpl + 14488
    frame #28: 0xec890eec libart.so`art::interpreter::Execute(art::Thread*, art::DexFile::CodeItem const*, art::ShadowFrame&, art::JValue, bool) + 344
    frame #29: 0xec89626e libart.so`art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::DexFile::CodeItem const*, art::ShadowFrame*, art::JValue*) + 146
    frame #30: 0xec8a9954 libart.so`bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*) + 556
    frame #31: 0xeca85b10 libart.so`MterpInvokeStatic + 328
    frame #32: 0xeca8cf98 libart.so`ExecuteMterpImpl + 14616
    frame #33: 0xec890eec libart.so`art::interpreter::Execute(art::Thread*, art::DexFile::CodeItem const*, art::ShadowFrame&, art::JValue, bool) + 344
    frame #34: 0xec89626e libart.so`art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::DexFile::CodeItem const*, art::ShadowFrame*, art::JValue*) + 146
    frame #35: 0xec8a9954 libart.so`bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*) + 556
    frame #36: 0xeca84a5e libart.so`MterpInvokeVirtual + 450
    frame #37: 0xeca8ce18 libart.so`ExecuteMterpImpl + 14232
    frame #38: 0xec890eec libart.so`art::interpreter::Execute(art::Thread*, art::DexFile::CodeItem const*, art::ShadowFrame&, art::JValue, bool) + 344
    frame #39: 0xec89626e libart.so`art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::DexFile::CodeItem const*, art::ShadowFrame*, art::JValue*) + 146
    frame #40: 0xec8a9954 libart.so`bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*) + 556
    frame #41: 0xeca84a5e libart.so`MterpInvokeVirtual + 450
    frame #42: 0xeca8ce18 libart.so`ExecuteMterpImpl + 14232
    frame #43: 0xec890eec libart.so`art::interpreter::Execute(art::Thread*, art::DexFile::CodeItem const*, art::ShadowFrame&, art::JValue, bool) + 344
    frame #44: 0xec89626e libart.so`art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::DexFile::CodeItem const*, art::ShadowFrame*, art::JValue*) + 146
    frame #45: 0xec8a9954 libart.so`bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*) + 556
    frame #46: 0xeca85b10 libart.so`MterpInvokeStatic + 328
    frame #47: 0xeca8cf98 libart.so`ExecuteMterpImpl + 14616
    frame #48: 0xec890eec libart.so`art::interpreter::Execute(art::Thread*, art::DexFile::CodeItem const*, art::ShadowFrame&, art::JValue, bool) + 344
    frame #49: 0xec8961bc libart.so`art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::DexFile::CodeItem const*, art::ShadowFrame*) + 96
    frame #50: 0xeca7b198 libart.so`artQuickToInterpreterBridge + 964
    frame #51: 0xeca9e924 libart.so`art_quick_to_interpreter_bridge + 36
    frame #52: 0xeca9ab62 libart.so`art_quick_invoke_stub_internal + 66
    frame #53: 0xeca9f1de libart.so`art_quick_invoke_static_stub + 230
    frame #54: 0xec7658d6 libart.so`art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*) + 186
    frame #55: 0xec9efa48 libart.so`art::InvokeWithArgArray(art::ScopedObjectAccessAlreadyRunnable const&, art::ArtMethod*, art::ArgArray*, art::JValue*, char const*) + 56
    frame #56: 0xec9f0f8e libart.so`art::InvokeMethod(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jobject*, _jobject*, unsigned int) + 950
    frame #57: 0xec99e670 libart.so`art::Method_invoke(_JNIEnv*, _jobject*, _jobject*, _jobject*) + 44
    frame #58: 0x70394bf8 boot-core-oj.oat`invoke(this=<unavailable>, (null)=<unavailable>, (null)=<unavailable>) + 112
    frame #59: 0xeca9ab62 libart.so`art_quick_invoke_stub_internal + 66
    frame #60: 0xeca9f0d8 libart.so`art_quick_invoke_stub + 232
    frame #61: 0xec7658ac libart.so`art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*) + 144
    frame #62: 0xec8ae3ba libart.so`art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::DexFile::CodeItem const*, art::ShadowFrame*, art::JValue*) + 242
    frame #63: 0xec8a996a libart.so`bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*) + 578
    frame #64: 0xeca84a5e libart.so`MterpInvokeVirtual + 450
    frame #65: 0xeca8ce18 libart.so`ExecuteMterpImpl + 14232
    frame #66: 0xec890eec libart.so`art::interpreter::Execute(art::Thread*, art::DexFile::CodeItem const*, art::ShadowFrame&, art::JValue, bool) + 344
    frame #67: 0xec8961bc libart.so`art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::DexFile::CodeItem const*, art::ShadowFrame*) + 96
    frame #68: 0xeca7b198 libart.so`artQuickToInterpreterBridge + 964
    frame #69: 0xeca9e924 libart.so`art_quick_to_interpreter_bridge + 36
    frame #70: 0x722b15d8 boot-framework.oat`main(argv=0x728ac1f0) at ZygoteInit.java:835
    frame #71: 0xeca9ab62 libart.so`art_quick_invoke_stub_internal + 66
    frame #72: 0xeca9f1de libart.so`art_quick_invoke_static_stub + 230
    frame #73: 0xec7658d6 libart.so`art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*) + 186
    frame #74: 0xec9efa48 libart.so`art::InvokeWithArgArray(art::ScopedObjectAccessAlreadyRunnable const&, art::ArtMethod*, art::ArgArray*, art::JValue*, char const*) + 56
    frame #75: 0xec9ef854 libart.so`art::InvokeWithVarArgs(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jmethodID*, std::__va_list) + 300
    frame #76: 0xec942b52 libart.so`art::JNI::CallStaticVoidMethodV(_JNIEnv*, _jclass*, _jmethodID*, std::__va_list) + 434
    frame #77: 0xecccfc5a libandroid_runtime.so
    frame #78: 0xeccd145c libandroid_runtime.so`android::AndroidRuntime::start(char const*, android::Vector<android::String8> const&, bool) + 452
    frame #79: 0xb3027afa app_process32
    frame #80: 0xef5fbe7a libc.so`__libc_init + 50
    frame #81: 0xb3027728 app_process32

The exception thrown is in the constructor of the object Test in Lib2. Lib1 just instantiates a Lib2::Test in a try catch statement :

Lib1:

Test::Test() 
{
    try
    {
        Lib2::Test test;
    }
    catch( const Lib3::Exception& e )
    {
        //
    }
}

Lib2:

Test::Test() 
{
    Lib3::Exception e;
    throw e;
}

Application, Jni.cpp:

JNIEXPORT void JNICALL
Java_<package_name>_Application_crash(
    JNIEnv* env,
    jobject application )
{
    Lib1::Test t;
}

In Lib2, I create an exception and throw it, so it is copied when thrown, the first object is correctly deleted but the second one is deleted before going into the catch statement... This is the first problem I saw. I have printed the address of this in the destructor of the exception and I saw that the first object destroyed is corresponding to the first object I created. For the second object, the address of this is not corresponding to the address of the copied object.

Exception constructor, this = 0xffce86f4
Exception copy constructor, this = 0xe176cb20
~Exception destructor, this = 0xffce86f4
~Exception destructor, this = 0xffce869c

@alexgarret
Copy link
Author

alexgarret commented Feb 16, 2019

@DanAlbert , can you please explain me why in the Android CMake toolchain in the NDK the libunwind.a is excluded (for 32bit only)?
list(APPEND ANDROID_LINKER_FLAGS -Wl, --exclude-libs, libunwind.a)

If I understand correctly we do not want to embed the symbols of libunwind in the library(ies) ? The implementation is supposed to be directly embedded (memory jump at addr xxx) ?

Here is the readelf output of my shared libs I package for my 32bit version:
for i in *.so; echo $i && ~/Library/Android/ndk/android-ndk-r18b/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-readelf -sW $i | grep "Unwind_Resume"

libQt5Core.so
     3: 001db9b1   104 FUNC    GLOBAL DEFAULT   12 _Unwind_Resume
 29844: 001db9b1   104 FUNC    GLOBAL DEFAULT   12 _Unwind_Resume
libQt5Network.so
libQt5WebSockets.so
libblazeandroidd.so
     3: 00000000     0 FUNC    GLOBAL DEFAULT  UND _Unwind_Resume
7816780: 00000000     0 FUNC    GLOBAL DEFAULT  UND _Unwind_Resume
libc++_shared.so
 36528: 0007472d   104 FUNC    LOCAL  HIDDEN    12 _Unwind_Resume
libcrypto.so
 10896: 001babc0   116 FUNC    LOCAL  DEFAULT   11 __gnu_Unwind_Resume
 10897: 001bac34    32 FUNC    LOCAL  DEFAULT   11 __gnu_Unwind_Resume_or_Rethrow
 10918: 001bb6c0    36 FUNC    LOCAL  DEFAULT   11 ___Unwind_Resume
 10919: 001bb6c0    36 FUNC    LOCAL  DEFAULT   11 _Unwind_Resume
 10920: 001bb6e4    36 FUNC    LOCAL  DEFAULT   11 ___Unwind_Resume_or_Rethrow
 10921: 001bb6e4    36 FUNC    LOCAL  DEFAULT   11 _Unwind_Resume_or_Rethrow
libssl.so
  2160: 00060d48   116 FUNC    LOCAL  DEFAULT   11 __gnu_Unwind_Resume
  2161: 00060dbc    32 FUNC    LOCAL  DEFAULT   11 __gnu_Unwind_Resume_or_Rethrow
  2182: 00061848    36 FUNC    LOCAL  DEFAULT   11 ___Unwind_Resume
  2183: 00061848    36 FUNC    LOCAL  DEFAULT   11 _Unwind_Resume
  2184: 0006186c    36 FUNC    LOCAL  DEFAULT   11 ___Unwind_Resume_or_Rethrow
  2185: 0006186c    36 FUNC    LOCAL  DEFAULT   11 _Unwind_Resume_or_Rethrow

As you can see, some libraries define Unwind symbols, I guess this is what is wrong...

I managed to rebuild all my dependencies with the linker flags -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libunwind.a as you told me, here is the readelf output :
for i in *.so; echo $i && ~/Library/Android/ndk/android-ndk-r18b/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-readelf -sW $i | grep "Unwind_Resume"

libQt5AndroidExtras.so
   869: 00011228   116 FUNC    LOCAL  HIDDEN    11 __gnu_Unwind_Resume
   870: 0001129c    32 FUNC    LOCAL  HIDDEN    11 __gnu_Unwind_Resume_or_Rethrow
   891: 00011d28    36 FUNC    LOCAL  HIDDEN    11 ___Unwind_Resume
   892: 00011d28    36 FUNC    LOCAL  HIDDEN    11 _Unwind_Resume
   893: 00011d4c    36 FUNC    LOCAL  HIDDEN    11 ___Unwind_Resume_or_Rethrow
   894: 00011d4c    36 FUNC    LOCAL  HIDDEN    11 _Unwind_Resume_or_Rethrow
libQt5Core.so
 29054: 001d961d   104 FUNC    LOCAL  HIDDEN    12 _Unwind_Resume
libQt5Network.so
 13399: 000a9c28   116 FUNC    LOCAL  HIDDEN    11 __gnu_Unwind_Resume
 13400: 000a9c9c    32 FUNC    LOCAL  HIDDEN    11 __gnu_Unwind_Resume_or_Rethrow
 13421: 000aa728    36 FUNC    LOCAL  HIDDEN    11 ___Unwind_Resume
 13422: 000aa728    36 FUNC    LOCAL  HIDDEN    11 _Unwind_Resume
 13423: 000aa74c    36 FUNC    LOCAL  HIDDEN    11 ___Unwind_Resume_or_Rethrow
 13424: 000aa74c    36 FUNC    LOCAL  HIDDEN    11 _Unwind_Resume_or_Rethrow
libQt5WebSockets.so
  1417: 00013cc4   116 FUNC    LOCAL  HIDDEN    11 __gnu_Unwind_Resume
  1418: 00013d38    32 FUNC    LOCAL  HIDDEN    11 __gnu_Unwind_Resume_or_Rethrow
  1439: 000147c4    36 FUNC    LOCAL  HIDDEN    11 ___Unwind_Resume
  1440: 000147c4    36 FUNC    LOCAL  HIDDEN    11 _Unwind_Resume
  1441: 000147e8    36 FUNC    LOCAL  HIDDEN    11 ___Unwind_Resume_or_Rethrow
  1442: 000147e8    36 FUNC    LOCAL  HIDDEN    11 _Unwind_Resume_or_Rethrow
libblazeandroidd.so
7817705: 0097adc1   104 FUNC    LOCAL  HIDDEN    12 _Unwind_Resume
libc++_shared.so
 36528: 0007472d   104 FUNC    LOCAL  HIDDEN    12 _Unwind_Resume
libcrypto.so
 10896: 001babc0   116 FUNC    LOCAL  HIDDEN    11 __gnu_Unwind_Resume
 10897: 001bac34    32 FUNC    LOCAL  HIDDEN    11 __gnu_Unwind_Resume_or_Rethrow
 10918: 001bb6c0    36 FUNC    LOCAL  HIDDEN    11 ___Unwind_Resume
 10919: 001bb6c0    36 FUNC    LOCAL  HIDDEN    11 _Unwind_Resume
 10920: 001bb6e4    36 FUNC    LOCAL  HIDDEN    11 ___Unwind_Resume_or_Rethrow
 10921: 001bb6e4    36 FUNC    LOCAL  HIDDEN    11 _Unwind_Resume_or_Rethrow
libssl.so
  2160: 00060d48   116 FUNC    LOCAL  HIDDEN    11 __gnu_Unwind_Resume
  2161: 00060dbc    32 FUNC    LOCAL  HIDDEN    11 __gnu_Unwind_Resume_or_Rethrow
  2182: 00061848    36 FUNC    LOCAL  HIDDEN    11 ___Unwind_Resume
  2183: 00061848    36 FUNC    LOCAL  HIDDEN    11 _Unwind_Resume
  2184: 0006186c    36 FUNC    LOCAL  HIDDEN    11 ___Unwind_Resume_or_Rethrow
  2185: 0006186c    36 FUNC    LOCAL  HIDDEN    11 _Unwind_Resume_or_Rethrow

This time they are all hidden, and it seems to work ! Some Unwind symbols appeared in lib where they were not present before (libQt5Network for example), but still HIDDEN, do you think it could be a problem ?

I will perform more tests next week with multiple devices and let you know, in the mean time if you see something strange in the readelf output, please let me know !

@DanAlbert
Copy link
Member

@DanAlbert , can you please explain me why in the Android CMake toolchain in the NDK the libunwind.a is excluded (for 32bit only)?

https://android.googlesource.com/platform/ndk/+/master/docs/BuildSystemMaintainers.md#Unwinding

Some Unwind symbols appeared in lib where they were not present before (libQt5Network for example), but still HIDDEN, do you think it could be a problem ?

No. That's the correct behavior.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants