Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[runtime] Fix segfault when accessing MonoImage in certain cases
Context: 7117414 7117414 introduced native code which queries the Mono runtime to obtain an instance of `MonoClass` for a given `MonoReflectionType` as well as the `MonoImage` associated with the class. However, it appears that in certain cases the class pointer stored `MonoReflectionType` doesn't lead us to getting a valid `MonoImage` instance, causing a segfault similar to: 04-08 15:52:55.015 19030 19030 F libc : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x3000021 in tid 19030 (s.swipeviewdemo), pid 19030 (s.swipeviewdemo) 04-08 15:52:55.037 19061 19061 I crash_dump32: obtaining output fd from tombstoned, type: kDebuggerdTombstone 04-08 15:52:55.037 1834 1834 I /system/bin/tombstoned: received crash request for pid 19030 04-08 15:52:55.038 19061 19061 I crash_dump32: performing dump of process 19030 (target tid = 19030) 04-08 15:52:55.042 19061 19061 F DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 04-08 15:52:55.042 19061 19061 F DEBUG : Build fingerprint: 'google/sdk_gphone_x86/generic_x86:10/QSR1.191030.002/5978551:userdebug/dev-keys' 04-08 15:52:55.043 19061 19061 F DEBUG : Revision: '0' 04-08 15:52:55.043 19061 19061 F DEBUG : ABI: 'x86' 04-08 15:52:55.043 19061 19061 F DEBUG : Timestamp: 2020-04-08 15:52:55+0200 04-08 15:52:55.043 19061 19061 F DEBUG : pid: 19030, tid: 19030, name: s.swipeviewdemo >>> nl.versluis.swipeviewdemo <<< 04-08 15:52:55.043 19061 19061 F DEBUG : uid: 10135 04-08 15:52:55.043 19061 19061 F DEBUG : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x3000021 04-08 15:52:55.043 19061 19061 F DEBUG : eax 03000005 ebx cb9f4d24 ecx 7191c13b edx 00000004 04-08 15:52:55.043 19061 19061 F DEBUG : edi 03000005 esi ffb22080 04-08 15:52:55.043 19061 19061 F DEBUG : ebp ffb22108 esp ffb2206c eip cbcfc1e4 04-08 15:52:55.077 19061 19061 F DEBUG : 04-08 15:52:55.077 19061 19061 F DEBUG : backtrace: 04-08 15:52:55.077 19061 19061 F DEBUG : #00 pc 001b41e4 /data/app/Mono.Android.DebugRuntime-umHhDz421s4-tshrHwha0w==/lib/x86/libmonosgen-32bit-2.0.so (mono_image_get_name+4) 04-08 15:52:55.077 19061 19061 F DEBUG : #1 pc 0000cac7 /data/app/nl.versluis.swipeviewdemo-jCFH_bcCNuFx1tLUhaJ4nw==/lib/x86/libmonodroid.so (xamarin::android::internal::EmbeddedAssemblies::typemap_managed_to_java(_MonoType*, _MonoClass*, unsigned char const*)+263) (BuildId: a2585ad379f788049e463af58c8686e9cdc1e778) 04-08 15:52:55.077 19061 19061 F DEBUG : #2 pc 0000c8cc /data/app/nl.versluis.swipeviewdemo-jCFH_bcCNuFx1tLUhaJ4nw==/lib/x86/libmonodroid.so (xamarin::android::internal::EmbeddedAssemblies::typemap_managed_to_java(_MonoReflectionType*, unsigned char const*)+124) (BuildId: a2585ad379f788049e463af58c8686e9cdc1e778) 04-08 15:52:55.077 19061 19061 F DEBUG : #3 pc 0001621a /data/app/nl.versluis.swipeviewdemo-jCFH_bcCNuFx1tLUhaJ4nw==/lib/x86/libmonodroid.so (xamarin::android::internal::MonodroidRuntime::typemap_managed_to_java(_MonoReflectionType*, unsigned char const*)+42) (BuildId: a2585ad379f788049e463af58c8686e9cdc1e778) 04-08 15:52:55.077 19061 19061 F DEBUG : dotnet#4 pc 000325af <anonymous:c7858000> Investigating the issue I discovered that one of two things happened: 1. the returned `MonoImage` instance was invalid, or 2. the instance was valid but image name stored in `MonoImage` was `null` In case of 1. I would see something similar to this in the crash log: 04-08 15:52:55.015 19030 19030 I monodroid: const char *xamarin::android::internal::EmbeddedAssemblies::typemap_managed_to_java(MonoType *, MonoClass *, const uint8_t *) 04-08 15:52:55.015 19030 19030 I monodroid: type == 0xc6e60d3c, klass == 0xc6e60cb8, mvid == 0xc8c02d90 04-08 15:52:55.015 19030 19030 I monodroid: type name == Xamarin.Forms.Platform.Android.AppCompat.FormsFragmentPagerAdapter`1[Xamarin.Forms.Page] 04-08 15:52:55.015 19030 19030 I monodroid: calling mono_class_get_image (0xc6e60cb8) 04-08 15:52:55.015 19030 19030 I monodroid: image == 0x3000005 It would happen in 32-bit builds only, the 64-bit builds would lead to a different issue, the 2. above: 04-08 16:05:13.446 28985 28985 I monodroid: const char *xamarin::android::internal::EmbeddedAssemblies::typemap_managed_to_java(MonoType *, MonoClass *, const uint8_t *) 04-08 16:05:13.447 28985 28985 I monodroid: type == 0x7ce3fecc78, klass == 0x7ce3fecb98, mvid == 0x7ce9404520 04-08 16:05:13.447 28985 28985 I monodroid: type name == Xamarin.Forms.Platform.Android.AppCompat.FormsFragmentPagerAdapter`1[Xamarin.Forms.Page] 04-08 16:05:13.447 28985 28985 I monodroid: calling mono_class_get_image (0x7ce3fecb98) 04-08 16:05:13.447 28985 28985 I monodroid: image == 0x7ce3fecbc8 04-08 16:05:13.447 28985 28985 I monodroid: image_name == <null> Case 1. would result in a segfault inside the `mono_image_get_name` call, because the pointer value was clearly invalid, while case 2. would result in a crash inside `strlen` which was passed a `null` pointer. I found out that the root cause was in the `mono_type_get_class` call which is supposed to be used with great caution as it eventually calls the `mono_type_get_class_internal` function which is supposed to be called only for object types `MONO_TYPE_CLASS` and `MONO_TYPE_VALUETYPE` but not `MONO_TYPE_GENERICINST` type which is precisely the type that caused the crash. The fix is to call the `mono_class_from_mono_type` function instead which, albeit slower, is safer and works correctly in all cases. Fixing this led to the next issue, a managed exception thrown after the runtime failed to map managed type name to Java type name: 04-08 18:08:58.886 30726 30726 W monodroid-assembly: typemap: unable to find mapping to a Java type from managed type 'Xamarin.Forms.Platform.Android.AppCompat.FormsFragmentPagerAdapter`1[T], Xamarin.Forms.Platform.Android' 04-08 18:08:58.886 30726 30726 I monodroid-timing: Typemap.managed_to_java: end, total time; elapsed: 0s:0::33177 04-08 18:08:58.888 30726 30726 D Mono : DllImport attempting to load: '/system/lib64/liblog.so'. 04-08 18:08:58.889 30726 30726 D Mono : DllImport loaded library '/system/lib64/liblog.so'. 04-08 18:08:58.889 30726 30726 D Mono : DllImport searching in: '/system/lib64/liblog.so' ('/system/lib64/liblog.so'). 04-08 18:08:58.889 30726 30726 D Mono : Searching for '__android_log_print'. 04-08 18:08:58.889 30726 30726 D Mono : Probing '__android_log_print'. 04-08 18:08:58.889 30726 30726 D Mono : Found as '__android_log_print'. 04-08 18:08:58.891 30726 30726 I MonoDroid: UNHANDLED EXCEPTION: 04-08 18:08:58.899 30726 30726 I MonoDroid: System.NotSupportedException: Cannot create instance of type 'Xamarin.Forms.Platform.Android.AppCompat.FormsFragmentPagerAdapter`1[[Xamarin.Forms.Page, Xamarin.Forms.Core, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null]]': no Java peer type found. 04-08 18:08:58.899 30726 30726 I MonoDroid: at Java.Interop.JniPeerMembers+JniInstanceMethods..ctor (System.Type declaringType) [0x0004b] in <514e1249792e47a180b3f1293306b972>:0 04-08 18:08:58.899 30726 30726 I MonoDroid: at Java.Interop.JniPeerMembers+JniInstanceMethods.GetConstructorsForType (System.Type declaringType) [0x00031] in <514e1249792e47a180b3f1293306b972>:0 04-08 18:08:58.899 30726 30726 I MonoDroid: at Java.Interop.JniPeerMembers+JniInstanceMethods.StartCreateInstance (System.String constructorSignature, System.Type declaringType, Java.Interop.JniArgumentValue* parameters) [0x00038] in <514e1249792e47a180b3f1293306b972>:0 04-08 18:08:58.899 30726 30726 I MonoDroid: at Android.Support.V4.App.FragmentPagerAdapter..ctor (Android.Support.V4.App.FragmentManager fm) [0x0005b] in <fefee6c2c695459088a9df092723e052>:0 04-08 18:08:58.899 30726 30726 I MonoDroid: at Xamarin.Forms.Platform.Android.AppCompat.FormsFragmentPagerAdapter`1[T]..ctor (Xamarin.Forms.MultiPage`1[T] page, Android.Support.V4.App.FragmentManager fragmentManager) [0x00000] in <9d12bb15abb54c508c4bee636d1b3a42>:0 04-08 18:08:58.899 30726 30726 I MonoDroid: at Xamarin.Forms.Platform.Android.AppCompat.TabbedPageRenderer.CreateFormsViewPager (Android.Content.Context context, Xamarin.Forms.TabbedPage tabbedPage) [0x00033] in <9d12bb15abb54c508c4bee636d1b3a42>:0 04-08 18:08:58.899 30726 30726 I MonoDroid: at Xamarin.Forms.Platform.Android.AppCompat.TabbedPageRenderer.OnElementChanged (Xamarin.Forms.Platform.Android.ElementChangedEventArgs`1[TElement] e) [0x001cd] in <9d12bb15abb54c508c4bee636d1b3a42>:0 04-08 18:08:58.899 30726 30726 I MonoDroid: at Xamarin.Forms.Platform.Android.VisualElementRenderer`1[TElement].SetElement (TElement element) [0x000c0] in <9d12bb15abb54c508c4bee636d1b3a42>:0 04-08 18:08:58.899 30726 30726 I MonoDroid: at Xamarin.Forms.Platform.Android.VisualElementRenderer`1[TElement].Xamarin.Forms.Platform.Android.IVisualElementRenderer.SetElement (Xamarin.Forms.VisualElement element) [0x00033] in <9d12bb15abb54c508c4bee636d1b3a42>:0 04-08 18:08:58.899 30726 30726 I MonoDroid: at Xamarin.Forms.Platform.Android.Platform.CreateRenderer (Xamarin.Forms.VisualElement element, Android.Content.Context context) [0x0001f] in <9d12bb15abb54c508c4bee636d1b3a42>:0 04-08 18:08:58.899 30726 30726 I MonoDroid: at Xamarin.Forms.Platform.Android.AppCompat.Platform.AddChild (Xamarin.Forms.Page page, System.Boolean layout) [0x0000d] in <9d12bb15abb54c508c4bee636d1b3a42>:0 04-08 18:08:58.899 30726 30726 I MonoDroid: at Xamarin.Forms.Platform.Android.AppCompat.Platform.SetPageInternal (Xamarin.Forms.Page newRoot) [0x00061] in <9d12bb15abb54c508c4bee636d1b3a42>:0 04-08 18:08:58.899 30726 30726 I MonoDroid: at Xamarin.Forms.Platform.Android.AppCompat.Platform.SetPage (Xamarin.Forms.Page newRoot) [0x000e6] in <9d12bb15abb54c508c4bee636d1b3a42>:0 04-08 18:08:58.899 30726 30726 I MonoDroid: at Xamarin.Forms.Platform.Android.FormsAppCompatActivity.InternalSetPage (Xamarin.Forms.Page page) [0x0003f] in <9d12bb15abb54c508c4bee636d1b3a42>:0 04-08 18:08:58.899 30726 30726 I MonoDroid: at Xamarin.Forms.Platform.Android.FormsAppCompatActivity.SetMainPage () [0x0000c] in <9d12bb15abb54c508c4bee636d1b3a42>:0 04-08 18:08:58.899 30726 30726 I MonoDroid: at Xamarin.Forms.Platform.Android.FormsAppCompatActivity.LoadApplication (Xamarin.Forms.Application application) [0x00140] in <9d12bb15abb54c508c4bee636d1b3a42>:0 04-08 18:08:58.899 30726 30726 I MonoDroid: at SwipeViewDemo.Droid.MainActivity.OnCreate (Android.OS.Bundle savedInstanceState) [0x00035] in <15e30af50bb64ff6b6d20ac6fd546763>:0 04-08 18:08:58.899 30726 30726 I MonoDroid: at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_ (System.IntPtr jnienv, System.IntPtr native__this, System.IntPtr native_savedInstanceState) [0x0000f] in <515e813169e54876823978ab785f569a>:0 04-08 18:08:58.899 30726 30726 I MonoDroid: at (wrapper dynamic-method) Android.Runtime.DynamicMethodNameCounter.7(intptr,intptr,intptr) Note that the type name as seen by the native code (via `mono_get_type_name_full`) is `Xamarin.Forms.Platform.Android.AppCompat.FormsFragmentPagerAdapter`1[T], Xamarin.Forms.Platform.Android` while we should be looking for `Xamarin.Forms.Platform.Android.AppCompat.FormsFragmentPagerAdapter`1` instead. The discrepancy was caused by calling `mono_get_type_name_full` with its format parameter set to `MONO_TYPE_NAME_FORMAT_REFLECTION`, while what we needed to do is to pass it the format value of `MONO_TYPE_NAME_FORMAT_FULL_NAME` which this commit implements.
- Loading branch information