Skip to content

Commit

Permalink
[One .NET] fix code path for unhandled exceptions (#4878)
Browse files Browse the repository at this point in the history
Context: dotnet/runtime#38465

When a thread throws an exception which isn't caught, we (eventually)
hit the "unhandled exception" codepath of
`JNIEnv.PropagateUncaughtException()` (2aff4e7 & others), which
relies on the following methods which are not present in .NET 5:

  * `System.Diagnostics.Debugger.Mono_UnhandledException()`
  * `AppDomain.DoUnhandledException()`

Unfortunately, we didn't check that the `MethodInfo`s for these
methods were `null` before invoking them, which means under .NET 5 we
would throw an exception while attempting to deal with an already
"in-flight" exception, i.e. we'd throw a *nested* exception!

	Unable to initialize UncaughtExceptionHandler. Nested exception caught: System.ArgumentNullException: Value cannot be null. (Parameter 'method')
	    at System.Delegate.CreateDelegate(Type type, Object firstArgument, MethodInfo method, Boolean throwOnBindFailure, Boolean allowClosed)
	    at System.Delegate.CreateDelegate(Type type, MethodInfo method, Boolean throwOnBindFailure)
	    at System.Delegate.CreateDelegate(Type type, MethodInfo method)
	    at Android.Runtime.JNIEnv.Initialize()
	    at Android.Runtime.JNIEnv.PropagateUncaughtException(IntPtr env, IntPtr javaThreadPtr, IntPtr javaExceptionPtr)

or:

	Exception thrown while raising AppDomain.UnhandledException event: System.NullReferenceException: Object reference not set to an instance of an object
	    at Android.Runtime.JNIEnv.PropagateUncaughtException(IntPtr env, IntPtr javaThreadPtr, IntPtr javaExceptionPtr)

Add appropriate `null` checks in `JNIEnv.PropagateUncaughtException()`
to avoid generation of nested exceptions.

TODO: Work with the dotnet/mono teams so that we can reintroduce the
functionality of `AppDomain.DoUnhandledException()`/etc..
  • Loading branch information
jonathanpeppers authored Jun 30, 2020
1 parent f0d565f commit e39d947
Showing 1 changed file with 5 additions and 4 deletions.
9 changes: 5 additions & 4 deletions src/Mono.Android/Android.Runtime/JNIEnv.cs
Original file line number Diff line number Diff line change
Expand Up @@ -244,8 +244,9 @@ static void Initialize ()
{
if (mono_unhandled_exception == null) {
var mono_UnhandledException = typeof (System.Diagnostics.Debugger)
.GetMethod ("Mono_UnhandledException", BindingFlags.NonPublic | BindingFlags.Static)!;
mono_unhandled_exception = (Action<Exception>) Delegate.CreateDelegate (typeof(Action<Exception>), mono_UnhandledException);
.GetMethod ("Mono_UnhandledException", BindingFlags.NonPublic | BindingFlags.Static);
if (mono_UnhandledException != null)
mono_unhandled_exception = (Action<Exception>) Delegate.CreateDelegate (typeof(Action<Exception>), mono_UnhandledException);
}

if (AppDomain_DoUnhandledException == null) {
Expand Down Expand Up @@ -277,7 +278,7 @@ internal static void PropagateUncaughtException (IntPtr env, IntPtr javaThreadPt

// Disabled until Linker error surfaced in https://github.com/xamarin/xamarin-android/pull/4302#issuecomment-596400025 is resolved
//System.Diagnostics.Debugger.Mono_UnhandledException (javaException);
mono_unhandled_exception (javaException);
mono_unhandled_exception?.Invoke (javaException);

try {
var jltp = javaException as JavaProxyThrowable;
Expand All @@ -289,7 +290,7 @@ internal static void PropagateUncaughtException (IntPtr env, IntPtr javaThreadPt

// Disabled until Linker error surfaced in https://github.com/xamarin/xamarin-android/pull/4302#issuecomment-596400025 is resolved
//AppDomain.CurrentDomain.DoUnhandledException (args);
AppDomain_DoUnhandledException (AppDomain.CurrentDomain, args);
AppDomain_DoUnhandledException?.Invoke (AppDomain.CurrentDomain, args);
} catch (Exception e) {
Logger.Log (LogLevel.Error, "monodroid", "Exception thrown while raising AppDomain.UnhandledException event: " + e.ToString ());
}
Expand Down

0 comments on commit e39d947

Please sign in to comment.