Skip to content
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

warning: Tried to create a managed reference from an object that already has a managed reference #15089

Open
spouliot opened this issue May 20, 2022 · 6 comments
Labels
bug If an issue is a bug or a pull request a bug fix
Milestone

Comments

@spouliot
Copy link
Contributor

Steps to Reproduce

  1. an NSObject subclass is finalized
  2. this calls object_queued_for_finalization and set NSObjectFlagsInFinalizerQueue in the instance's flags
  3. the call to Dispose(false) calls GC.ReRegisterForFinalize(this);
  4. that has no effect (notification/callback) to change the instance's flags so it's still has NSObjectFlagsInFinalizerQueue set
  5. something calls the instance itself (e.g. RemoveFromSuperview)
  6. GetNSObject is used to get the instance, TryGetNSObject looks for one using evenInFinalizerQueue: false
  7. since NSObjectFlagsInFinalizerQueue is set the method returns null
  8. however the call xamarin_set_gchandle_with_flags_safe will find a GCHandle (because a managed peer exists) and return false
  9. that will make the warning appears in the logs

Expected Behavior

The warning should not be printed and it the condition it checks should not occur.

Actual Behavior

The logs shows the warning Tried to create a managed reference from an object that already has a managed reference. Some NSObject instances are resurfaced needlessly since they already exists in managed land.

Environment

The issue exists in master

Notes

Build Logs

Not useful.

Example Project (If Possible)

It's easier to repro using Xamarin.Mac since NSView.RemoveFromSuperview calls the Superview property. However the warning is also seen on iOS but the conditions might be a little different.

Building Uno SampleApp for macOS and selecting the Border sample will print the warning. The generated Dispose can be seen in the generator code.

If needed I'll try to create a smaller sample. I had no luck earlier (on iOS) but I had not yet found the root issue.

@spouliot
Copy link
Contributor Author

The fact it's easier to dupe on macOS is because the bindings include custom code

[Export ("removeFromSuperview")]
[PreSnippet ("var mySuper = Superview;", Optimizable = true)]
[PostSnippet ("if (mySuper != null) {\n\t#pragma warning disable 168\n\tvar flush = mySuper.Subviews;\n#pragma warning restore 168\n\t}", Optimizable = true)]
void RemoveFromSuperview ();

AFAIK this is not needed anymore (since newrefcount become the default with the unified API). However I can't see/blame the source code from the era to confirm. If that's the case then NSView has a few more places that needs scrubbing.

@spouliot
Copy link
Contributor Author

Quick followup

On iOS the warning appears because there are calls to the Superview property (in between the first Dispose() (from finalizer) and the second Dispose() calls (dispatched from the first one).

IOW the call to RemoveFromSuperview is not the trigger of the problem on iOS, just on macOS. This confirms the extra, custom code on the macOS side is triggering the issue.

reference: unoplatform/uno#8688 (comment)

@spouliot
Copy link
Contributor Author

spouliot commented May 23, 2022

Using the following code, just after the call to GC.ReRegisterForFinalize(this); solves the issue. IOW the original managed instance is returned by GetNSObject.

const byte InFinalizerQueue = 16; // see NSObject2.cs
var poker = Unsafe.As<NSObjectMemoryRepresentation>(this);
poker.flags = (byte)(poker.flags & ~InFinalizerQueue);

@rolfbjarne
Copy link
Member

However I can't see/blame the source code from the era to confirm.

It was added here: https://gist.github.com/rolfbjarne/b44c6e86bca3a9f46997a4d8f6a1aaf9

rolfbjarne added a commit to rolfbjarne/xamarin-macios that referenced this issue May 24, 2022
Remove code that we needed at some point due to memory related issues. These
issues were fixed several years ago (newrefcount), so we no longer need this
code (in fact it causes problems, see xamarin#15089).
@rolfbjarne
Copy link
Member

I created a PR to remove those Pre/Post snippets: #15103.

That doesn't fix the underlying problem though (resurrected managed peers only half resurrected), so I'll leave this bug open for now.

@rolfbjarne rolfbjarne added the bug If an issue is a bug or a pull request a bug fix label May 24, 2022
@spouliot
Copy link
Contributor Author

note: this does not seems to be an issue for net6-macos, which uses coreclr and a different mechanism to get notified

rolfbjarne added a commit that referenced this issue May 30, 2022
Remove code that we needed at some point due to memory related issues. These
issues were fixed several years ago (newrefcount), so we no longer need this
code (in fact it causes problems, see #15089).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug If an issue is a bug or a pull request a bug fix
Projects
None yet
Development

No branches or pull requests

3 participants