You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Stack trace keeps getting longer when an exception instance that is propagated through both Java and managed code is thrown and handled repeatedly
#4987
Monitor the adb logcat 'mono-stdout:* *:S' output.
Tap the envelope icon button in the lower right of the app screen a few times.
Expected behavior
The catch block should produce the same output every time:
I mono-stdout: EXCEPTION: AndroidAppSingleView1.CSharpThrows+StopException: Exception of type 'AndroidAppSingleView1.CSharpThrows+StopException' was thrown.
I mono-stdout: at AndroidAppSingleView1.CSharpThrows.Run () [0x00001] in <f2bb278a39884bc397fa66ae82cc4a31>:0
I mono-stdout: at Java.Lang.IRunnableInvoker.n_Run (System.IntPtr jnienv, System.IntPtr native__this) [0x00008] in <9a644cc3d16a46d188196736019b9821>:0
I mono-stdout: at (wrapper dynamic-method) Android.Runtime.DynamicMethodNameCounter.16(intptr,intptr)
I mono-stdout: --- End of stack trace from previous location where exception was thrown ---
I mono-stdout:
I mono-stdout: at Java.Interop.JniEnvironment+InstanceMethods.CallVoidMethod (Java.Interop.JniObjectReference instance, Java.Interop.JniMethodInfo method, Java.Interop.JniArgumentValue* args) [0x0006e] in <6cbf2f3a8f4443d6971b2a070eb221ce>:0
I mono-stdout: at Android.Runtime.JNIEnv.CallVoidMethod (System.IntPtr jobject, System.IntPtr jmethod, Android.Runtime.JValue* parms) [0x0000e] in <9a644cc3d16a46d188196736019b9821>:0
I mono-stdout: at Android.Runtime.JNIEnv.CallVoidMethod (System.IntPtr jobject, System.IntPtr jmethod, Android.Runtime.JValue[] parms) [0x00018] in <9a644cc3d16a46d188196736019b9821>:0
I mono-stdout: at AndroidAppSingleView1.MainActivity.FabOnClick (System.Object sender, System.EventArgs eventArgs) [0x00060] in <f2bb278a39884bc397fa66ae82cc4a31>:0
Actual behavior
The stack trace in the catch block output gets longer each time it runs.
First time:
I mono-stdout: EXCEPTION: AndroidAppSingleView1.CSharpThrows+StopException: Exception of type 'AndroidAppSingleView1.CSharpThrows+StopException' was thrown.
I mono-stdout: at AndroidAppSingleView1.CSharpThrows.Run () [0x00001] in <f2bb278a39884bc397fa66ae82cc4a31>:0
I mono-stdout: at Java.Lang.IRunnableInvoker.n_Run (System.IntPtr jnienv, System.IntPtr native__this) [0x00008] in <9a644cc3d16a46d188196736019b9821>:0
I mono-stdout: at (wrapper dynamic-method) Android.Runtime.DynamicMethodNameCounter.16(intptr,intptr)
I mono-stdout: --- End of stack trace from previous location where exception was thrown ---
I mono-stdout:
I mono-stdout: at Java.Interop.JniEnvironment+InstanceMethods.CallVoidMethod (Java.Interop.JniObjectReference instance, Java.Interop.JniMethodInfo method, Java.Interop.JniArgumentValue* args) [0x0006e] in <6cbf2f3a8f4443d6971b2a070eb221ce>:0
I mono-stdout: at Android.Runtime.JNIEnv.CallVoidMethod (System.IntPtr jobject, System.IntPtr jmethod, Android.Runtime.JValue* parms) [0x0000e] in <9a644cc3d16a46d188196736019b9821>:0
I mono-stdout: at Android.Runtime.JNIEnv.CallVoidMethod (System.IntPtr jobject, System.IntPtr jmethod, Android.Runtime.JValue[] parms) [0x00018] in <9a644cc3d16a46d188196736019b9821>:0
I mono-stdout: at AndroidAppSingleView1.MainActivity.FabOnClick (System.Object sender, System.EventArgs eventArgs) [0x00060] in <f2bb278a39884bc397fa66ae82cc4a31>:0
Second time:
I mono-stdout: EXCEPTION: AndroidAppSingleView1.CSharpThrows+StopException: Exception of type 'AndroidAppSingleView1.CSharpThrows+StopException' was thrown.
I mono-stdout: at AndroidAppSingleView1.CSharpThrows.Run () [0x00001] in <f2bb278a39884bc397fa66ae82cc4a31>:0
I mono-stdout: at Java.Lang.IRunnableInvoker.n_Run (System.IntPtr jnienv, System.IntPtr native__this) [0x00008] in <9a644cc3d16a46d188196736019b9821>:0
I mono-stdout: at (wrapper dynamic-method) Android.Runtime.DynamicMethodNameCounter.16(intptr,intptr)
I mono-stdout: --- End of stack trace from previous location where exception was thrown ---
I mono-stdout:
I mono-stdout: at AndroidAppSingleView1.CSharpThrows.Run () [0x00001] in <f2bb278a39884bc397fa66ae82cc4a31>:0
I mono-stdout: at Java.Lang.IRunnableInvoker.n_Run (System.IntPtr jnienv, System.IntPtr native__this) [0x00008] in <9a644cc3d16a46d188196736019b9821>:0
I mono-stdout: at (wrapper dynamic-method) Android.Runtime.DynamicMethodNameCounter.16(intptr,intptr)
I mono-stdout: --- End of stack trace from previous location where exception was thrown ---
I mono-stdout:
I mono-stdout: at Java.Interop.JniEnvironment+InstanceMethods.CallVoidMethod (Java.Interop.JniObjectReference instance, Java.Interop.JniMethodInfo method, Java.Interop.JniArgumentValue* args) [0x0006e] in <6cbf2f3a8f4443d6971b2a070eb221ce>:0
I mono-stdout: at Android.Runtime.JNIEnv.CallVoidMethod (System.IntPtr jobject, System.IntPtr jmethod, Android.Runtime.JValue* parms) [0x0000e] in <9a644cc3d16a46d188196736019b9821>:0
I mono-stdout: at Android.Runtime.JNIEnv.CallVoidMethod (System.IntPtr jobject, System.IntPtr jmethod, Android.Runtime.JValue[] parms) [0x00018] in <9a644cc3d16a46d188196736019b9821>:0
I mono-stdout: at AndroidAppSingleView1.MainActivity.FabOnClick (System.Object sender, System.EventArgs eventArgs) [0x00060] in <f2bb278a39884bc397fa66ae82cc4a31>:0
Third time:
I mono-stdout: EXCEPTION: AndroidAppSingleView1.CSharpThrows+StopException: Exception of type 'AndroidAppSingleView1.CSharpThrows+StopException' was thrown.
I mono-stdout: at AndroidAppSingleView1.CSharpThrows.Run () [0x00001] in <f2bb278a39884bc397fa66ae82cc4a31>:0
I mono-stdout: at Java.Lang.IRunnableInvoker.n_Run (System.IntPtr jnienv, System.IntPtr native__this) [0x00008] in <9a644cc3d16a46d188196736019b9821>:0
I mono-stdout: at (wrapper dynamic-method) Android.Runtime.DynamicMethodNameCounter.16(intptr,intptr)
I mono-stdout: --- End of stack trace from previous location where exception was thrown ---
I mono-stdout:
I mono-stdout: at AndroidAppSingleView1.CSharpThrows.Run () [0x00001] in <f2bb278a39884bc397fa66ae82cc4a31>:0
I mono-stdout: at Java.Lang.IRunnableInvoker.n_Run (System.IntPtr jnienv, System.IntPtr native__this) [0x00008] in <9a644cc3d16a46d188196736019b9821>:0
I mono-stdout: at (wrapper dynamic-method) Android.Runtime.DynamicMethodNameCounter.16(intptr,intptr)
I mono-stdout: --- End of stack trace from previous location where exception was thrown ---
I mono-stdout:
I mono-stdout: at AndroidAppSingleView1.CSharpThrows.Run () [0x00001] in <f2bb278a39884bc397fa66ae82cc4a31>:0
I mono-stdout: at Java.Lang.IRunnableInvoker.n_Run (System.IntPtr jnienv, System.IntPtr native__this) [0x00008] in <9a644cc3d16a46d188196736019b9821>:0
I mono-stdout: at (wrapper dynamic-method) Android.Runtime.DynamicMethodNameCounter.16(intptr,intptr)
I mono-stdout: --- End of stack trace from previous location where exception was thrown ---
I mono-stdout:
I mono-stdout: at Java.Interop.JniEnvironment+InstanceMethods.CallVoidMethod (Java.Interop.JniObjectReference instance, Java.Interop.JniMethodInfo method, Java.Interop.JniArgumentValue* args) [0x0006e] in <6cbf2f3a8f4443d6971b2a070eb221ce>:0
I mono-stdout: at Android.Runtime.JNIEnv.CallVoidMethod (System.IntPtr jobject, System.IntPtr jmethod, Android.Runtime.JValue* parms) [0x0000e] in <9a644cc3d16a46d188196736019b9821>:0
I mono-stdout: at Android.Runtime.JNIEnv.CallVoidMethod (System.IntPtr jobject, System.IntPtr jmethod, Android.Runtime.JValue[] parms) [0x00018] in <9a644cc3d16a46d188196736019b9821>:0
I mono-stdout: at AndroidAppSingleView1.MainActivity.FabOnClick (System.Object sender, System.EventArgs eventArgs) [0x00060] in <f2bb278a39884bc397fa66ae82cc4a31>:0
Partial workaround
Change CSharpThrows.Run() to create a new instance of StopException each time it is invoked:
public void Run()
{
- throw STOP_EXCEPTION;+ throw new StopException();
}
This is only a partial workaround because in other contexts, like calling CSharpThrows.Run() directly from FabOnClick(), the stack trace behaves as expected without this workaround, so some user code might have scenarios where creating new StopException instances on each throw is not desirable.
Version information
Xamarin.Android SDK 11.0.99.9 (d16-8/2bd5c33)
Testing device: arm64-v8a Android 9.0 Pie (API level 28) Google Pixel 3
The text was updated successfully, but these errors were encountered:
Because throw STOP_EXCEPTION causes the exception to be raised within Java code, and then later caught within the C# code calling the intermediate Java code, the exception marshaler behavior is equivalent to:
The use of ExcpetionDispatchInfo.Throw() causes the continually growing stack trace.
The fundamental question is, how do we fix this? I don't know of any way to check if an exception has already been logged, and even if there were it might not be a good idea to use such a mechanism! Consider a Java > Managed > Java > Managed > Java > Managed stack trace. If the rightmost stack frame throws an exception which is caught by the leftmost stack frame, you want to see the intervening managed frames!
I suppose a fix could be to use ExceptionDispatchInfo.Throw(Exception) -- which didn't exist until .NET Standard 2.1, and thus didn't exist when this was first written -- but I don't currently know if that is an actual fix, because we want the call stack to be updated! We just don't want it to be constantly updated with the "same" current call stack.
Context: #4632 (comment)
Steps to reproduce
Create a new Android App (Xamarin) > Single View App.
Similar to Fix XA_BROKEN_EXCEPTION_TRANSITIONS support #4548 (comment), add the following C# class:
And add the following in a JavaRunner.java file with the Build Action set to AndroidJavaSource:
Add the following to the
FabOnClick()
method:Launch the app without the debugger attached.
Monitor the
adb logcat 'mono-stdout:* *:S'
output.Tap the envelope icon button in the lower right of the app screen a few times.
Expected behavior
The
catch
block should produce the same output every time:Actual behavior
The stack trace in the
catch
block output gets longer each time it runs.First time:
Second time:
Third time:
Partial workaround
Change
CSharpThrows.Run()
to create a new instance ofStopException
each time it is invoked:This is only a partial workaround because in other contexts, like calling
CSharpThrows.Run()
directly fromFabOnClick()
, the stack trace behaves as expected without this workaround, so some user code might have scenarios where creating newStopException
instances on eachthrow
is not desirable.Version information
Xamarin.Android SDK 11.0.99.9 (d16-8/2bd5c33)
Testing device: arm64-v8a Android 9.0 Pie (API level 28) Google Pixel 3
The text was updated successfully, but these errors were encountered: