Open cwensley opened 4 years ago
Note that this also has the opposite effect where if you use this API on the main thread, and another object is created on a background thread thread between steps 2 and 4 above (e.g. for example an object used for NSApplication.SharedApplication.InvokeOnMainThread
), it can possibly unregister that new object, which then would try to re-create said object which does not have a constructor with an IntPtr handle (and adding the constructor would not solve the problem).
I can reproduce the problem with the test project, it also makes sense from your description (great debugging btw!)
We might be able to fix this by not registering handles until init has been called, but this is a rather invasive change, so it will likely take some time until we're able to release a fix (at the very least because a lot of thinking and testing would be required first).
Thanks @rolfbjarne, doing as you suggest (not registering until after init is called) was my thinking as well to avoid the race condition.
I understand that it'll take a while to get that fix in, but one thing that would help greatly in the meantime is to have some debug output or some way to detect if other objects do the same so we can work around them, perhaps a simple test in InitializeHandle
to see if the handle is different than the one created in AllocIfNeeded.
This case is the only one we have found so far after many years of trying to find the cause of these crashes and issues, but they are usually impossible to find. We just fluked out with one specific set of code that pinpointed the issue.
When calling an init method that returns a different handle than the one created with alloc, a race condition occurs where for a small period of time a dealloc'd handle is incorrectly mapped to that object until it is reassigned with the one returned from the init method. I am not sure of all the API's that cause this issue, but we are running into this one a LOT:
NSBitmapImageRep(NSData)
. This is causing many random crashes in our application.Calling the constructor in Xamarin.Mac appears to do this:
[NSBitmapImageRep alloc]
, which returns a handleRuntime.object_map
[NSBitmapImageRep initWithData:]
, which returns a different handleBetween 3 and 4 there is a possibility that a different thread may try to allocate an object and incorrectly return the
NSBitmapImageRep
instead of the returned object. In this case I'm just callingCopy()
on aNSMutableParagraphStyle
which was part of our specific example, but any API that returns an object could also cause the same issue.To give some background, we are calling this API to load images from a web service in a background thread while the UI stays responsive.
Steps to Reproduce
*it takes longer to reproduce in debug mode.
Expected Behavior
No messages should ever occur, and
NSMutableParagraphStyle.Copy()
should always return anNSParagraphStyle
Actual Behavior
NSMutableParagraphStyle.Copy()
returns anNSBitmapImageRep
sometimes.Environment
Example Project (If Possible)
TestXamMacConstructorIssue.zip