Bug 59235 - [mono-2017-06] android.runtime.JavaProxyThrowable: System.ObjectDisposedException: Cannot access a disposed object.
Summary: [mono-2017-06] android.runtime.JavaProxyThrowable: System.ObjectDisposedExcep...
Status: RESOLVED FIXED
Alias: None
Product: Android
Classification: Xamarin
Component: Mono runtime / AOT Compiler (show other bugs)
Version: unspecified
Hardware: PC Mac OS
: --- normal
Target Milestone: 15.5
Assignee: Bernhard Urban
URL:
Depends on:
Blocks:
 
Reported: 2017-09-05 16:36 UTC by Bernhard Urban
Modified: 2017-09-07 10:02 UTC (History)
4 users (show)

See Also:
Tags: mono-2017-06
Is this bug a regression?: ---
Last known good build:


Attachments

Description Bernhard Urban 2017-09-05 16:36:11 UTC
I/mono-stdout( 2709): 	InnerExceptionIsSet Passed
		    I/mono-stdout( 2709): ExceptionTest : 15.403 ms
		    I/mono-stdout( 2709): HandlerTest
		    I/monodroid-timing( 2709): Runtime.register: start time: 1504530876326 ms
		    I/monodroid-timing( 2709): JNIEnv.RegisterJniNatives ("Java.Lang.Runnable, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=84e04ff9cfb79065", 0xa1d50e24) start: 1504530876326.93
		    I/monodroid-timing( 2709): JNIEnv.RegisterJniNatives total time: 1504530876327.08 [elapsed: 0.148 ms]
		    I/monodroid-timing( 2709): Runtime.register: end time: 1504530876327 [elapsed 1 ms]
		    D/Mono    ( 2709): DllImport searching in: '__Internal' ('(null)').
		    D/Mono    ( 2709): Searching for 'java_interop_jnienv_call_nonvirtual_int_method_a'.
		    D/Mono    ( 2709): Probing 'java_interop_jnienv_call_nonvirtual_int_method_a'.
		    D/Mono    ( 2709): Found as 'java_interop_jnienv_call_nonvirtual_int_method_a'.
		    I/MonoDroid( 2709): UNHANDLED EXCEPTION:
		    I/mono-stdout( 2709): 	RemoveDisposedInstance Passed
		    I/mono-stdout( 2709): HandlerTest : 15.305 ms
		    I/mono-stdout( 2709): TimeZoneTest
		    I/MonoDroid( 2709): System.ObjectDisposedException: Cannot access a disposed object.
		    I/MonoDroid( 2709): Object name: 'Java.Lang.Runnable'.
		    I/MonoDroid( 2709):   at Java.Interop.JniPeerMembers.AssertSelf (Java.Interop.IJavaPeerable self) [0x00029] in <02673ec0d04c46ea85d735718099f909>:0 
		    I/MonoDroid( 2709):   at Java.Interop.JniPeerMembers+JniInstanceMethods.InvokeVirtualInt32Method (System.String encodedMember, Java.Interop.IJavaPeerable self, Java.Interop.JniArgumentValue* parameters) [0x00000] in <02673ec0d04c46ea85d735718099f909>:0 
		    I/MonoDroid( 2709):   at Java.Lang.Object.GetHashCode () [0x0000a] in <01c4ad44191a473f88e7e8b5f5a6f769>:0 
		    I/MonoDroid( 2709):   at System.Delegate.GetHashCode () [0x00023] in <1fd9ddf6108f4f659a582583057a6285>:0 
		    I/MonoDroid( 2709):   at System.MulticastDelegate.GetHashCode () [0x00000] in <1fd9ddf6108f4f659a582583057a6285>:0 
		    I/MonoDroid( 2709):   at System.Collections.Generic.ObjectEqualityComparer`1[T].GetHashCode (T obj) [0x0000a] in <1fd9ddf6108f4f659a582583057a6285>:0 
		    I/MonoDroid( 2709):   at System.Collections.Generic.Dictionary`2[TKey,TValue].Remove (TKey key) [0x0001e] in <1fd9ddf6108f4f659a582583057a6285>:0 
		    I/MonoDroid( 2709):   at Java.Lang.Thread+RunnableImplementor.Run () [0x0002b] in <01c4ad44191a473f88e7e8b5f5a6f769>:0 
		    I/MonoDroid( 2709):   at Java.Lang.IRunnableInvoker.n_Run (System.IntPtr jnienv, System.IntPtr native__this) [0x00008] in <01c4ad44191a473f88e7e8b5f5a6f769>:0 
		    I/MonoDroid( 2709):   at (wrapper dynamic-method) System.Object:c66d85c0-2fc5-4ece-a7a6-bc077f553278 (intptr,intptr)
		    --------- beginning of crash
		    E/AndroidRuntime( 2709): FATAL EXCEPTION: RemoveDisposedInstance
		    E/AndroidRuntime( 2709): Process: Mono.Android_Tests, PID: 2709
		    E/AndroidRuntime( 2709): android.runtime.JavaProxyThrowable: System.ObjectDisposedException: Cannot access a disposed object.
		    E/AndroidRuntime( 2709): Object name: 'Java.Lang.Runnable'.
		    E/AndroidRuntime( 2709):   at Java.Interop.JniPeerMembers.AssertSelf (Java.Interop.IJavaPeerable self) [0x00029] in <02673ec0d04c46ea85d735718099f909>:0 
		    E/AndroidRuntime( 2709):   at Java.Interop.JniPeerMembers+JniInstanceMethods.InvokeVirtualInt32Method (System.String encodedMember, Java.Interop.IJavaPeerable self, Java.Interop.JniArgumentValue* parameters) [0x00000] in <02673ec0d04c46ea85d735718099f909>:0 
		    E/AndroidRuntime( 2709):   at Java.Lang.Object.GetHashCode () [0x0000a] in <01c4ad44191a473f88e7e8b5f5a6f769>:0 
		    E/AndroidRuntime( 2709):   at System.Delegate.GetHashCode () [0x00023] in <1fd9ddf6108f4f659a582583057a6285>:0 
		    E/AndroidRuntime( 2709):   at System.MulticastDelegate.GetHashCode () [0x00000] in <1fd9ddf6108f4f659a582583057a6285>:0 
		    E/AndroidRuntime( 2709):   at System.Collections.Generic.ObjectEqualityComparer`1[T].GetHashCode (T obj) [0x0000a] in <1fd9ddf6108f4f659a582583057a6285>:0 
		    E/AndroidRuntime( 2709):   at System.Collections.Generic.Dictionary`2[TKey,TValue].Remove (TKey key) [0x0001e] in <1fd9ddf6108f4f659a582583057a6285>:0 
		    E/AndroidRuntime( 2709):   at Java.Lang.Thread+RunnableImplementor.Run () [0x0002b] in <01c4ad44191a473f88e7e8b5f5a6f769>:0 
		    E/AndroidRuntime( 2709):   at Java.Lang.IRunnableInvoker.n_Run (System.IntPtr jnienv, System.IntPtr native__this) [0x00008] in <01c4ad44191a473f88e7e8b5f5a6f769>:0 
		    E/AndroidRuntime( 2709):   at (wrapper dynamic-method) System.Object:c66d85c0-2fc5-4ece-a7a6-bc077f553278 (intptr,intptr)
		    E/AndroidRuntime( 2709): 	at mono.java.lang.RunnableImplementor.n_run(Native Method)
		    E/AndroidRuntime( 2709): 	at mono.java.lang.RunnableImplementor.run(RunnableImplementor.java:30)
		    E/AndroidRuntime( 2709): 	at android.os.Handler.handleCallback(Handler.java:739)
		    E/AndroidRuntime( 2709): 	at android.os.Handler.dispatchMessage(Handler.java:95)
		    E/AndroidRuntime( 2709): 	at android.os.Looper.loop(Looper.java:135)
		    E/AndroidRuntime( 2709): 	at android.os.HandlerThread.run(HandlerThread.java:61)
		    W/ActivityManager( 1502): Error in app Mono.Android_Tests running instrumentation ComponentInfo{Mono.Android_Tests/xamarin.android.runtimetests.TestInstrumentation}:
		    W/ActivityManager( 1502):   android.runtime.JavaProxyThrowable
		    W/ActivityManager( 1502):   android.runtime.JavaProxyThrowable: System.ObjectDisposedException: Cannot access a disposed object.
		    W/ActivityManager( 1502): Object name: 'Java.Lang.Runnable'.
		    W/ActivityManager( 1502):   at Java.Interop.JniPeerMembers.AssertSelf (Java.Interop.IJavaPeerable self) [0x00029] in <02673ec0d04c46ea85d735718099f909>:0 
		    W/ActivityManager( 1502):   at Java.Interop.JniPeerMembers+JniInstanceMethods.InvokeVirtualInt32Method (System.String encodedMember, Java.Interop.IJavaPeerable self, Java.Interop.JniArgumentValue* parameters) [0x00000] in <02673ec0d04c46ea85d735718099f909>:0 
		    W/ActivityManager( 1502):   at Java.Lang.Object.GetHashCode () [0x0000a] in <01c4ad44191a473f88e7e8b5f5a6f769>:0 
		    W/ActivityManager( 1502):   at System.Delegate.GetHashCode () [0x00023] in <1fd9ddf6108f4f659a582583057a6285>:0 
		    W/ActivityManager( 1502):   at System.MulticastDelegate.GetHashCode () [0x00000] in <1fd9ddf6108f4f659a582583057a6285>:0 
		    W/ActivityManager( 1502):   at System.Collections.Generic.ObjectEqualityComparer`1[T].GetHashCode (T obj) [0x0000a] in <1fd9ddf6108f4f659a582583057a6285>:0 
		    W/ActivityManager( 1502):   at System.Collections.Generic.Dictionary`2[TKey,TValue].Remove (TKey key) [0x0001e] in <1fd9ddf6108f4f659a582583057a6285>:0 
		    W/ActivityManager( 1502):   at Java.Lang.Thread+RunnableImplementor.Run () [0x0002b] in <01c4ad44191a473f88e7e8b5f5a6f769>:0 
		    W/ActivityManager( 1502):   at Java.Lang.IRunnableInvoker.n_Run (System.IntPtr jnienv, System.IntPtr native__this) [0x00008] in <01c4ad44191a473f88e7e8b5f5a6f769>:0 
		    W/ActivityManager( 1502):   at (wrapper dynamic-method) System.Object:c66d85c0-2fc5-4ece-a7a6-bc077f553278 (intptr,intptr)
		    D/AndroidRuntime( 2697): Shutting down VM
Comment 1 Bernhard Urban 2017-09-05 16:38:46 UTC
this happens in the `test-runtime` and `test-runtime-aot` step on wrench, e.g.: https://wrench.internalx.com/Wrench/ViewLane.aspx?lane_id=5000&host_id=163&revision_id=910774
Comment 2 Jonathan Pryor 2017-09-05 17:27:23 UTC
The `ObjectDisposedException` is coming from:

https://github.com/xamarin/xamarin-android/blob/5777337/src/Mono.Android/Java.Lang/Thread.cs#L39

which in turn is via this test:

https://github.com/xamarin/xamarin-android/blob/1b3a76c/src/Mono.Android/Test/Android.OS/HandlerTest.cs#L13-L30

(Apologies for the indentation!)

This is presumably a unit test for some bug, but I'm having difficulty finding when that test was added. I will continue hunting.

In the meantime, the test:

1. Creates a HandlerThread and associated Handler instance.
2. Creates a new Java.Lang.Runnable which, when invoked, disposes of itself.
3. Posts the Runnable.Run method to the handler.

(3) will *implicitly* create a `Thread.RunnableImplementor` instance, which invokes the provided delegate, which will be `Runnable.Run`.

We thus have an object graph:

> RunnableImplementor.Handler -> Runnable.Run > Runnable instance

When the Handler executes:

E1. It pulls off the RunnableImplementor instance, calling `RunnableImplementor.Run()`.

E2. `RunnableImplementor.Run()` invokes Handler()

E3. Handler() is `Runnable.Run()`, which *disposes* of the Runnable instance.

E4. `RunnableImplementor.Run()` then unregisters `Handler` from the `RunnalbeImplementor.instances`.

E5. `Dictionary<TKey, TValue>.Remove()` then executes Handler.GetHashCode(), which touches the *now disposed* Handler.Target value, which throws the ObjectDisposedException.

`Delegate.GetHashCode()` should *not* be touching `Delegate.Target`. *That* is the bug.

From some additional searching on Slack, this test *might* be related to:

https://bugzilla.xamarin.com/show_bug.cgi?id=31338#c11
Comment 3 Aleksey Kliger 2017-09-05 17:40:59 UTC
https://github.com/mono/mono/commit/a48bc439850869e565833d7fe6330c289beffe40 change in 2017-06 that started looking at Delegate.Target in GetHashCode ().

(Corresponding master and 2017-08 commit https://github.com/mono/mono/commit/a48bc439850869e565833d7fe6330c289beffe40)

Note that that was a fix for a performance regression on a pathological example.
Comment 4 Jonathan Pryor 2017-09-05 19:11:09 UTC
Regarding the question of "Where did `HandlerTest` come from?", I suspect that I forgot to `git add` the file, and through pure happenstance added that file to the OSS repo.

What luck?

That said, I did find this conversation in Slack:

https://xamarinhq.slack.com/archives/C03CELHQQ/p1440002022008528

> @jonp:
>   Delegate.GetHashCode() is breaking me :wink:
>   https://bugzilla.xamarin.com/show_bug.cgi?id=31338#c11
>   largely because mono’s Delegate.GetHashCode() invokes
>   Delegate.Target.GetHashCode(), while .NET’s doesn’t.
> @kumpera:
>   interesting
>   well, we should import equals/hashcode semantics then
> @mareks:
>   I suggested to switch to reference sources Delegate too but was always rejected
> @jonp:
>   then we should fix Equals() and GetHashCode()?

This was in fact fixed in:

https://github.com/mono/mono/commit/ff17686542746d660b9013920446e95d71dcd294

(...not that the commit message mentions the above conversation in any way, or what bug was being fixed, or...anything else that might be useful...)

The above fix was effectively reverted in:

https://github.com/mono/mono/commit/3acee7af00ae05348ab663e6702d298bd071ce55

This was to fix Bug #58399.
Comment 5 Bernhard Urban 2017-09-05 22:29:58 UTC
https://github.com/mono/mono/pull/5511

once it is merged, I'll take care for the bumping of android.
Comment 6 Bernhard Urban 2017-09-06 12:13:41 UTC
https://github.com/xamarin/xamarin-android/pull/820

Note You need to log in before you can comment on or make changes to this bug.