App crashes when loading certain class. EXC_BAD_ACCESS in ART's class_linker.cc

Hello,

I have a quite complex project with > 20 dependent libraries. I have experienced problems when loading certain classes. The app instantaneously crashes when running on the simulator and hangs when running on the device.

It would be great to get some hints on what could be causing the crash.

After finding out how to run the project with XCode I have some detailed information about the crash, which seems to be located in ART’s class_linker.cc as can be found here (version unclear):

ERROR:

EXC_BAD_ACCESS (code=1, address=oxef5abbd4)

STACK:

main (1)Queue : com.apple.main-thread (serial)
#0	0x04aa2de7 in art::ClassLinker::LinkVirtualMethods(art::Thread*, art::Handle<art::mirror::Class>, std::__1::unordered_map<unsigned long, art::ArtMethod*, std::__1::hash<unsigned long>, std::__1::equal_to<unsigned long>, std::__1::allocator<std::__1::pair<unsigned long const, art::ArtMethod*> > >*) ()
#1	0x04aa0de9 in art::ClassLinker::LinkMethods(art::Thread*, art::Handle<art::mirror::Class>, art::Handle<art::mirror::ObjectArray<art::mirror::Class> >, art::ArtMethod**) ()
#2	0x04a92d26 in art::ClassLinker::LinkClass(art::Thread*, char const*, art::Handle<art::mirror::Class>, art::Handle<art::mirror::ObjectArray<art::mirror::Class> >, art::MutableHandle<art::mirror::Class>*) ()
#3	0x04a8f945 in art::ClassLinker::DefineClass(art::Thread*, char const*, unsigned long, art::Handle<art::mirror::ClassLoader>, art::DexFile const&, art::DexFile::ClassDef const&) ()
#4	0x04a7fff9 in art::ClassLinker::FindClass(art::Thread*, char const*, art::Handle<art::mirror::ClassLoader>) ()
#5	0x04aa94a7 in art::ClassLinker::ResolveType(art::DexFile const&, unsigned short, art::Handle<art::mirror::DexCache>, art::Handle<art::mirror::ClassLoader>) ()
#6	0x04b3645c in art::ClassLinker::ResolveType(unsigned short, art::ArtMethod*) ()
#7	0x04be06cc in artAllocObjectFromCodeRosAlloc ()
#8	0x04e0c5ac in art_quick_alloc_object_rosalloc ()
Enqueued from com.apple.main-thread (Thread 1)Queue : com.apple.main-thread (serial)
#0	0x061f0699 in _dispatch_introspection_queue_item_enqueue ()
#1	0x061c8d00 in _dispatch_queue_push ()
#2	0x061c9025 in _dispatch_continuation_push ()
#3	0x061c7b15 in _dispatch_continuation_async ()
#4	0x061ca338 in dispatch_async ()
#5	0x05001968 in ffi_call_i386 ()

ASSEMBLY with error position (arrow):

`MOEart::ClassLinker::LinkVirtualMethods:
    ... (shortened)
    0x4aa2bc5 <+2685>: movl   $0xffffffff, 0x10(%esp)   ; imm = 0xFFFFFFFF 
    0x4aa2bcd <+2693>: movl   $0x2, 0xc(%esp)
    0x4aa2bd5 <+2701>: movl   $0x125e, 0x8(%esp)        ; imm = 0x125E 
    0x4aa2bdd <+2709>: calll  0x4b92f40                 ; art::LogMessage::LogMessage(char const*, unsigned int, art::LogSeverity, int)
    0x4aa2be2 <+2714>: addl   $0x20, %esp
    0x4aa2be5 <+2717>: subl   $0x10, %esp
    0x4aa2be8 <+2720>: leal   -0xa0(%ebp), %eax
    0x4aa2bee <+2726>: movl   %eax, (%esp)
    0x4aa2bf1 <+2729>: calll  0x4b92f4a                 ; art::LogMessage::stream()
    0x4aa2bf6 <+2734>: addl   $0x10, %esp
    0x4aa2bf9 <+2737>: subl   $0x10, %esp
    0x4aa2bfc <+2740>: movl   -0x114(%ebp), %ecx
    0x4aa2c02 <+2746>: movl   %ecx, 0x4(%esp)
    0x4aa2c06 <+2750>: movl   %eax, (%esp)
    0x4aa2c09 <+2753>: movl   $0x7, 0x8(%esp)
    0x4aa2c11 <+2761>: calll  0x4ac1e50                 ; std::__1::basic_ostream<char, std::__1::char_traits<char> >& std::__1::__put_character_sequence<char, std::__1::char_traits<char> >(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, char const*, unsigned long)
    0x4aa2c16 <+2766>: addl   $0x10, %esp
    0x4aa2c19 <+2769>: movl   %eax, %esi
    0x4aa2c1b <+2771>: subl   $0x10, %esp
    0x4aa2c1e <+2774>: movl   -0xd4(%ebp), %eax
    0x4aa2c24 <+2780>: movl   %eax, 0x4(%esp)
    0x4aa2c28 <+2784>: leal   -0x88(%ebp), %eax
    0x4aa2c2e <+2790>: movl   %eax, (%esp)
    0x4aa2c31 <+2793>: movl   $0x1, 0x8(%esp)
    0x4aa2c39 <+2801>: calll  0x4ccc1d1                 ; art::PrettyMethod(art::ArtMethod*, bool)
    0x4aa2c3e <+2806>: addl   $0xc, %esp
    0x4aa2c41 <+2809>: movzbl -0x88(%ebp), %eax
    0x4aa2c48 <+2816>: movl   %eax, %ecx
    0x4aa2c4a <+2818>: movb   $0x1, %dl
    0x4aa2c4c <+2820>: andb   %dl, %cl
    0x4aa2c4e <+2822>: movl   -0x80(%ebp), %edx
    0x4aa2c51 <+2825>: leal   -0x87(%ebp), %edi
    0x4aa2c57 <+2831>: cmovel %edi, %edx
    0x4aa2c5a <+2834>: shrl   %eax
    0x4aa2c5c <+2836>: testb  %cl, %cl
    0x4aa2c5e <+2838>: cmovnel -0x84(%ebp), %eax
    0x4aa2c65 <+2845>: subl   $0x10, %esp
    0x4aa2c68 <+2848>: movl   %eax, 0x8(%esp)
    0x4aa2c6c <+2852>: movl   %edx, 0x4(%esp)
    0x4aa2c70 <+2856>: movl   %esi, (%esp)
    0x4aa2c73 <+2859>: calll  0x4ac1e50                 ; std::__1::basic_ostream<char, std::__1::char_traits<char> >& std::__1::__put_character_sequence<char, std::__1::char_traits<char> >(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, char const*, unsigned long)
    0x4aa2c78 <+2864>: addl   $0x10, %esp
    0x4aa2c7b <+2867>: subl   $0x10, %esp
    0x4aa2c7e <+2870>: movl   -0x110(%ebp), %ecx
    0x4aa2c84 <+2876>: movl   %ecx, 0x4(%esp)
    0x4aa2c88 <+2880>: movl   %eax, (%esp)
    0x4aa2c8b <+2883>: movl   $0x17, 0x8(%esp)
    0x4aa2c93 <+2891>: calll  0x4ac1e50                 ; std::__1::basic_ostream<char, std::__1::char_traits<char> >& std::__1::__put_character_sequence<char, std::__1::char_traits<char> >(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, char const*, unsigned long)
    0x4aa2c98 <+2896>: addl   $0x10, %esp
    0x4aa2c9b <+2899>: movl   %eax, %edi
    0x4aa2c9d <+2901>: subl   $0x10, %esp
    0x4aa2ca0 <+2904>: movl   -0x104(%ebp), %eax
    0x4aa2ca6 <+2910>: movl   %eax, 0x4(%esp)
    0x4aa2caa <+2914>: leal   -0xb0(%ebp), %eax
    0x4aa2cb0 <+2920>: movl   %eax, (%esp)
    0x4aa2cb3 <+2923>: movl   $0x1, 0x8(%esp)
    0x4aa2cbb <+2931>: calll  0x4ccc1d1                 ; art::PrettyMethod(art::ArtMethod*, bool)
    0x4aa2cc0 <+2936>: addl   $0xc, %esp
    0x4aa2cc3 <+2939>: movzbl -0xb0(%ebp), %eax
    0x4aa2cca <+2946>: movl   %eax, %ecx
    0x4aa2ccc <+2948>: movb   $0x1, %dl
    0x4aa2cce <+2950>: andb   %dl, %cl
    0x4aa2cd0 <+2952>: movl   -0xa8(%ebp), %edx
    0x4aa2cd6 <+2958>: leal   -0xaf(%ebp), %esi
    0x4aa2cdc <+2964>: cmovel %esi, %edx
    0x4aa2cdf <+2967>: shrl   %eax
    0x4aa2ce1 <+2969>: testb  %cl, %cl
    0x4aa2ce3 <+2971>: cmovnel -0xac(%ebp), %eax
    0x4aa2cea <+2978>: subl   $0x10, %esp
    0x4aa2ced <+2981>: movl   %eax, 0x8(%esp)
    0x4aa2cf1 <+2985>: movl   %edx, 0x4(%esp)
    0x4aa2cf5 <+2989>: movl   %edi, (%esp)
    0x4aa2cf8 <+2992>: calll  0x4ac1e50                 ; std::__1::basic_ostream<char, std::__1::char_traits<char> >& std::__1::__put_character_sequence<char, std::__1::char_traits<char> >(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, char const*, unsigned long)
    0x4aa2cfd <+2997>: addl   $0x10, %esp
    0x4aa2d00 <+3000>: subl   $0x10, %esp
    0x4aa2d03 <+3003>: movl   -0x10c(%ebp), %ecx
    0x4aa2d09 <+3009>: movl   %ecx, 0x4(%esp)
    0x4aa2d0d <+3013>: movl   %eax, (%esp)
    0x4aa2d10 <+3016>: movl   $0x4, 0x8(%esp)
    0x4aa2d18 <+3024>: calll  0x4ac1e50                 ; std::__1::basic_ostream<char, std::__1::char_traits<char> >& std::__1::__put_character_sequence<char, std::__1::char_traits<char> >(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, char const*, unsigned long)
    0x4aa2d1d <+3029>: addl   $0x10, %esp
    0x4aa2d20 <+3032>: movl   %eax, %esi
    0x4aa2d22 <+3034>: movl   0x10(%ebp), %eax
    0x4aa2d25 <+3037>: movl   (%eax), %eax
    0x4aa2d27 <+3039>: movl   (%eax), %eax
    0x4aa2d29 <+3041>: subl   $0x10, %esp
    0x4aa2d2c <+3044>: movl   %eax, 0x4(%esp)
    0x4aa2d30 <+3048>: leal   -0xc0(%ebp), %eax
    0x4aa2d36 <+3054>: movl   %eax, (%esp)
    0x4aa2d39 <+3057>: calll  0x4cccdf0                 ; art::PrettyClass(art::mirror::Class*)
    0x4aa2d3e <+3062>: addl   $0xc, %esp
    0x4aa2d41 <+3065>: movzbl -0xc0(%ebp), %eax
    0x4aa2d48 <+3072>: movl   %eax, %ecx
    0x4aa2d4a <+3074>: movb   $0x1, %dl
    0x4aa2d4c <+3076>: andb   %dl, %cl
    0x4aa2d4e <+3078>: movl   -0xb8(%ebp), %edx
    0x4aa2d54 <+3084>: leal   -0xbf(%ebp), %edi
    0x4aa2d5a <+3090>: cmovel %edi, %edx
    0x4aa2d5d <+3093>: shrl   %eax
    0x4aa2d5f <+3095>: testb  %cl, %cl
    0x4aa2d61 <+3097>: cmovnel -0xbc(%ebp), %eax
    0x4aa2d68 <+3104>: subl   $0x10, %esp
    0x4aa2d6b <+3107>: movl   %eax, 0x8(%esp)
    0x4aa2d6f <+3111>: movl   %edx, 0x4(%esp)
    0x4aa2d73 <+3115>: movl   %esi, (%esp)
    0x4aa2d76 <+3118>: calll  0x4ac1e50                 ; std::__1::basic_ostream<char, std::__1::char_traits<char> >& std::__1::__put_character_sequence<char, std::__1::char_traits<char> >(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, char const*, unsigned long)
    0x4aa2d7b <+3123>: addl   $0x10, %esp
    0x4aa2d7e <+3126>: subl   $0x10, %esp
    0x4aa2d81 <+3129>: leal   -0xc0(%ebp), %eax
    0x4aa2d87 <+3135>: movl   %eax, (%esp)
    0x4aa2d8a <+3138>: calll  0x5207734                 ; symbol stub for: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::~basic_string()
    0x4aa2d8f <+3143>: leal   -0xb0(%ebp), %eax
    0x4aa2d95 <+3149>: movl   %eax, (%esp)
    0x4aa2d98 <+3152>: calll  0x5207734                 ; symbol stub for: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::~basic_string()
    0x4aa2d9d <+3157>: leal   -0x88(%ebp), %eax
    0x4aa2da3 <+3163>: movl   %eax, (%esp)
    0x4aa2da6 <+3166>: calll  0x5207734                 ; symbol stub for: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::~basic_string()
    0x4aa2dab <+3171>: leal   -0xa0(%ebp), %eax
    0x4aa2db1 <+3177>: movl   %eax, (%esp)
    0x4aa2db4 <+3180>: calll  0x4b92f68                 ; art::LogMessage::~LogMessage()
    0x4aa2db9 <+3185>: addl   $0x10, %esp
    0x4aa2dbc <+3188>: movl   -0xdc(%ebp), %edi
    0x4aa2dc2 <+3194>: jmp    0x4aa2ba8                 ; <+2656>
    0x4aa2dc7 <+3199>: movl   (%edi), %ecx
    0x4aa2dc9 <+3201>: movl   0x8(%ebp), %eax
    0x4aa2dcc <+3204>: movl   0x158(%eax), %eax
    0x4aa2dd2 <+3210>: cmpl   $0x8, %eax
    0x4aa2dd5 <+3213>: jne    0x4aa2ddd                 ; <+3221>
    0x4aa2dd7 <+3215>: movl   0x10(%ecx,%esi,8), %edx
    0x4aa2ddb <+3219>: jmp    0x4aa2de1                 ; <+3225>
    0x4aa2ddd <+3221>: movl   0xc(%ecx,%esi,4), %edx
    0x4aa2de1 <+3225>: movl   %esi, -0xd8(%ebp)
->  0x4aa2de7 <+3231>: movl   (%edx), %ecx
    0x4aa2de9 <+3233>: movl   0x50(%ecx), %ecx
    0x4aa2dec <+3236>: testl  $0x40000, %ecx            ; imm = 0x40000 
    0x4aa2df2 <+3242>: movl   %edx, -0xd4(%ebp)
    0x4aa2df8 <+3248>: movl   %edx, %ecx
    0x4aa2dfa <+3250>: jne    0x4aa28b7                 ; <+1903>
    0x4aa2e00 <+3256>: movl   (%ecx), %eax
    0x4aa2e02 <+3258>: movl   0x10(%eax), %eax
    0x4aa2e05 <+3261>: movl   0x10(%eax), %eax
    0x4aa2e08 <+3264>: movl   %eax, -0x50(%ebp)
    0x4aa2e0b <+3267>: movl   0xc(%ecx), %ecx
    0x4aa2e0e <+3270>: shll   $0x3, %ecx
    0x4aa2e11 <+3273>: addl   0x30(%eax), %ecx
    0x4aa2e14 <+3276>: movl   %ecx, -0x4c(%ebp)
    0x4aa2e17 <+3279>: xorl   %eax, %eax
    0x4aa2e19 <+3281>: movl   %eax, -0x48(%ebp)
    0x4aa2e1c <+3284>: movl   %eax, -0x44(%ebp)
    0x4aa2e1f <+3287>: subl   $0x10, %esp
    0x4aa2e22 <+3290>: leal   -0x50(%ebp), %eax
    0x4aa2e25 <+3293>: movl   %eax, 0x4(%esp)
    0x4aa2e29 <+3297>: leal   -0x40(%ebp), %eax
    0x4aa2e2c <+3300>: movl   %eax, (%esp)
    0x4aa2e2f <+3303>: calll  0x4aa639a                 ; art::LinkVirtualHashTable::FindAndRemove(art::MethodNameAndSignatureComparator*)
	...`

Thank you
Daniel

Hi Daniel,

we have not run into this issue yet, even in large projects. In order to provide any assistance, we would need access to the source code. If you can create a test project, that you can share publicly, we can take a look. We also offer commercial support packages, to support commercial projects.

You can also try to build a debug SDK yourself, the instructions should be in the Github docs here and here.

Best Regards,
Gergely

Hi Gergely,

thanks for your reply. At the moment, I cannot (yet) publicly share the affected sources. The commercial support is an option. However, I am still in an evaluation scenario testing different solutions for Java in iOS. These were my first steps with MOE and I will possibly come back to your proposal, if the competitors have similar problems.

Just to let you know, what my current concerns with MOE are:

  • Class Loading (as described here)
  • Build times (RoboVM/BugVM is about 3 times faster)
  • RAM requirements (I am measuring 600MB for a MOE Hello World app vs. 5MB for RoboVM/BugVM or a Swift-App). Guess, this is a bug.
  • Binary size

I read, that you are planning to release a first 2.0 build this week. I will try it with my setup immediately. Maybe the problems will disappear. Looking forward to it.

Best wishes,
Daniel

Hi Daniel,

thank you for sharing this.

  • For the class loading issue, without something to test or debug it is hard to say anything definite.
  • RAM requirements: can you provide a reproducible test case for this? How do you measure RAM usage? We had a case a few months ago, where iOS reported way more memory use than the real usage, but it was fixed a long time ago.
  • Build times: Do you have measurements that we can look at? How did you measure this? Incremental or full rebuilds? Release or debug builds? With or without ProGuard? Which Gradle version is used? With or without Gradle daemon? Were the builds started from the command line or from an IDE?
  • Binary size: it is known that the HelloWorld MOE app is bigger than the same from RoboVM, but it is mostly due to the fact that the MOE framework is bigger than RoboVM. In our experience, for real world, large apps, the difference is much smaller, compared to the size of the app.

For MOE 2.0 we implemented a tool that provides us with very accurate size measurements for each app and the framework as well, down to the function / method level. It is integrated into the SDK / Gradle plugin, so you will be able to run it yourself as well.

This will allow us to apply the necessary size optimizations where it will count the most. For example, we already see that the Java ICU library (used in OpenJDK / Android 7) uses 4 MB per architecture + 10 MB for data files. This is definitely something that will need to be looked at.

When comparing MOE to RoboVM you should also consider other factors, for example:

  • lack of debugger in RoboVM
  • limited coverage of iOS APIs
  • generally lack of further development - I could be wrong about this, but I don’t see much activity on GH, if there is a place where RoboVM / BugVM is actively developed, please point me to it.

I think this is a complex topic, and we should definitely discuss it further. We (MIgeran) are very interested in having a great tool for Java on iOS, and we have a lot of plans going forward, e.g. beating React(-Native) at their own game. It is also clear, that we will need the support of the community to realize all these plans.

Best Regards,
Gergely

A post was split to a new topic: High RAM Usage in MOE

A post was split to a new topic: Long build times with MOE

A post was split to a new topic: MOE Binary Size

2 posts were split to a new topic: Thoughts on RoboVM