-
Notifications
You must be signed in to change notification settings - Fork 54
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Java.Interop] Dispose, *then* Remove #708
Merged
jonpryor
merged 1 commit into
dotnet:master
from
jonpryor:jonp-fix-disposepeer-semantics
Sep 5, 2020
Merged
[Java.Interop] Dispose, *then* Remove #708
jonpryor
merged 1 commit into
dotnet:master
from
jonpryor:jonp-fix-disposepeer-semantics
Sep 5, 2020
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Fixes: https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1193891 A bug was found in Xamarin.Android 11.1.0.2, candidate for Visual Studio 16.8 Preview 3: 1. Create a new "Shell Forms App" 2. Build & Run the app 3. Tap the "Browse" button. Expected results: it works! Actual results: A rather abrupt crash: Unhandled Exception: System.NotSupportedException: Unable to activate instance of type Xamarin.Forms.Platform.Android.PageRenderer from native handle 0x69 (key_handle 0x33efaa1). ---> System.MissingMethodException: No constructor found for Xamarin.Forms.Platform.Android.PageRenderer::.ctor(System.IntPtr, Android.Runtime.JniHandleOwnership) ---> Java.Interop.JavaLocationException: Exception of type 'Java.Interop.JavaLocationException' was thrown. --- End of inner exception stack trace --- at Java.Interop.TypeManager.CreateProxy (System.Type type, System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer) at Java.Interop.TypeManager.CreateInstance (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type targetType) --- End of inner exception stack trace --- at (wrapper dynamic-method) Android.Runtime.DynamicMethodNameCounter.64(intptr,intptr) at (wrapper native-to-managed) Android.Runtime.DynamicMethodNameCounter.64(intptr,intptr) The crash was caused by commit 007b35b, which changed `JniRuntime.JniValueManager.DisposePeer()` semantics from: value.Disposed (); RemovePeer (value); and reversed this to: RemovePeer (value); value.Disposed (); (Why? Unmentioned in 007b35b -- doh! -- but as @jonpryor is the one who did this, "it seemed like a good idea at the time!") (Very clearly, this wasn't a good idea.) The crash was caused by commit 007b35b interacting with Xamarin.Forms' [`VisualElementPackager.Dispose(bool)`][0], which can call back into Java code, potentially causing `this` to need to be returned. When `RemovePeer()` is done *first*, as was done in 007b35b, then there may be no available instance to return, causing the `NotSupportedException` to be thrown. The new `JavaObjectTest.DisposeAccessesThis()` test and associated `Java.InteropTests.GetThis` type & Java peer trigger this scenario. Without the fix, `DisposeAccessesThis()` fails with: System.NotSupportedException : Could not find an appropriate constructable wrapper type for Java type 'com/xamarin/interop/GetThis', targetType='Java.InteropTests.GetThis'. at Java.Interop.JniRuntime+JniValueManager.CreatePeer (Java.Interop.JniObjectReference& reference, Java.Interop.JniObjectReferenceOptions transfer, System.Type targetType) at Java.Interop.JavaPeerableValueMarshaler.CreateGenericValue (Java.Interop.JniObjectReference& reference, Java.Interop.JniObjectReferenceOptions options, System.Type targetType) at Java.Interop.JniRuntime+JniValueManager.GetValue[T] (Java.Interop.JniObjectReference& reference, Java.Interop.JniObjectReferenceOptions options, System.Type targetType) at Java.InteropTests.GetThis.get_This () at Java.InteropTests.GetThis.Dispose (System.Boolean disposing) at Java.Interop.JavaObject.Java.Interop.IJavaPeerable.Disposed () at Java.Interop.JniRuntime+JniValueManager.DisposePeer (Java.Interop.IJavaPeerable value) at Java.Interop.JavaObject.Dispose () demonstrating how `RemovePeer(value)` *must not* happen before `value.Disposed()`. [0]: https://github.com/xamarin/Xamarin.Forms/blob/17881ec93d6b3fb0ee5e1a2be46d7eeadef23529/Xamarin.Forms.Platform.Android/VisualElementPackager.cs#L65-L108
bacc25f
to
9498459
Compare
jpobst
approved these changes
Sep 5, 2020
jonpryor
added a commit
that referenced
this pull request
Sep 5, 2020
Fixes: https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1193891 A bug was found in Xamarin.Android 11.1.0.2, candidate for Visual Studio 16.8 Preview 3: 1. Create a new "Shell Forms App" 2. Build & Run the app 3. Tap the "Browse" button. Expected results: it works! Actual results: A rather abrupt crash: Unhandled Exception: System.NotSupportedException: Unable to activate instance of type Xamarin.Forms.Platform.Android.PageRenderer from native handle 0x69 (key_handle 0x33efaa1). ---> System.MissingMethodException: No constructor found for Xamarin.Forms.Platform.Android.PageRenderer::.ctor(System.IntPtr, Android.Runtime.JniHandleOwnership) ---> Java.Interop.JavaLocationException: Exception of type 'Java.Interop.JavaLocationException' was thrown. --- End of inner exception stack trace --- at Java.Interop.TypeManager.CreateProxy (System.Type type, System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer) at Java.Interop.TypeManager.CreateInstance (System.IntPtr handle, Android.Runtime.JniHandleOwnership transfer, System.Type targetType) --- End of inner exception stack trace --- at (wrapper dynamic-method) Android.Runtime.DynamicMethodNameCounter.64(intptr,intptr) at (wrapper native-to-managed) Android.Runtime.DynamicMethodNameCounter.64(intptr,intptr) The crash was caused by commit 007b35b, which changed `JniRuntime.JniValueManager.DisposePeer()` semantics from: value.Disposed (); RemovePeer (value); and reversed this to: RemovePeer (value); value.Disposed (); (Why this reversal? Unmentioned in 007b35b -- doh! -- but as @jonpryor is the one who did this, "it seemed like a good idea at the time!") (Very clearly, this wasn't a good idea.) The crash was caused by commit 007b35b interacting with Xamarin.Forms' [`VisualElementPackager.Dispose(bool)`][0], which can call back into Java code, potentially causing `this` to need to be returned. When `RemovePeer()` is done *first*, as was done in 007b35b, then there may be no available instance to return, causing the `NotSupportedException` to be thrown. The new `JavaObjectTest.DisposeAccessesThis()` test and associated `Java.InteropTests.GetThis` type & Java peer trigger this scenario. Without the fix, `DisposeAccessesThis()` fails with: System.NotSupportedException : Could not find an appropriate constructable wrapper type for Java type 'com/xamarin/interop/GetThis', targetType='Java.InteropTests.GetThis'. at Java.Interop.JniRuntime+JniValueManager.CreatePeer (Java.Interop.JniObjectReference& reference, Java.Interop.JniObjectReferenceOptions transfer, System.Type targetType) at Java.Interop.JavaPeerableValueMarshaler.CreateGenericValue (Java.Interop.JniObjectReference& reference, Java.Interop.JniObjectReferenceOptions options, System.Type targetType) at Java.Interop.JniRuntime+JniValueManager.GetValue[T] (Java.Interop.JniObjectReference& reference, Java.Interop.JniObjectReferenceOptions options, System.Type targetType) at Java.InteropTests.GetThis.get_This () at Java.InteropTests.GetThis.Dispose (System.Boolean disposing) at Java.Interop.JavaObject.Java.Interop.IJavaPeerable.Disposed () at Java.Interop.JniRuntime+JniValueManager.DisposePeer (Java.Interop.IJavaPeerable value) at Java.Interop.JavaObject.Dispose () demonstrating how `RemovePeer(value)` *must not* happen before `value.Disposed()`. [0]: https://github.com/xamarin/Xamarin.Forms/blob/17881ec93d6b3fb0ee5e1a2be46d7eeadef23529/Xamarin.Forms.Platform.Android/VisualElementPackager.cs#L65-L108
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Fixes: https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1193891
A bug was found in Xamarin.Android 11.1.0.2, candidate for
Visual Studio 16.8 Preview 3:
Expected results: it works!
Actual results: A rather abrupt crash:
The crash was caused by commit 007b35b, which changed
JniRuntime.JniValueManager.DisposePeer()
semantics from:and reversed this to:
(Why? Unmentioned in 007b35b -- doh! -- but as @jonpryor is the one
who did this, "it seemed like a good idea at the time!")
(Very clearly, this wasn't a good idea.)
The crash was caused by commit 007b35b interacting with Xamarin.Forms'
VisualElementPackager.Dispose(bool)
, which can call back intoJava code, potentially causing
this
to need to be returned.When
RemovePeer()
is done first, as was done in 007b35b, thenthere may be no available instance to return, causing the
NotSupportedException
to be thrown.The new
JavaObjectTest.DisposeAccessesThis()
test and associatedJava.InteropTests.GetThis
type & Java peer trigger this scenario.Without the fix,
DisposeAccessesThis()
fails with:demonstrating how
RemovePeer(value)
must not happen beforevalue.Disposed()
.