Open Bug 1880992 Opened 9 months ago Updated 6 months ago

MessagePorts are not GCed after becoming disentangled

Categories

(Core :: DOM: postMessage, defect, P2)

Firefox 115
defect

Tracking

()

People

(Reporter: fergald, Unassigned)

Details

User Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36

Steps to reproduce:

https://fergald.github.io/random/html-snippets/WeakRefMessagePort/post.html

Post a MessageChannel's port to another window.
Close that window.
Force garbage collection.

Actual results:

The WeakRef to the array is garbage collected.
The WeakRef to the MessagePort is never garbage collected.

Expected results:

Both should be garbage collected. port2 was send to a window that has now been closed, so there are no references to it. The spec says that port1 should then be disentangled from port2 and now there are no references to it either.

https://html.spec.whatwg.org/multipage/web-messaging.html#ports-and-garbage-collection

I would like to attempt confirmation of your report. Would you mind re-writing the steps to reproduce more clearly?

Maybe you could correct my understanding of your steps:

  1. Load the test page in the browser: https://fergald.github.io/random/html-snippets/WeakRefMessagePort/post.html
  2. Click the "Open window and send port" button
  3. Close the newly opened tab
  4. Click the "Force GC by allocating and freeing lots of memory." button

Actual: How exactly do I verify that:
"The WeakRef to the array is garbage collected.
The WeakRef to the MessagePort is never garbage collected."?

Expected: How exactly do I verify that :
"Both should be garbage collected. port2 was sent to a window that has now been closed, so there are no references to it. The spec says that port1 should then be disentangled from port2 and now there are no references to it either."?

Thank you for your contribution and for your understanding!

Flags: needinfo?(fergald)

This doesn't need to go through normal triage; moving this to our MessagePort component since this is expected as part of spec refinements around https://github.com/whatwg/html/issues/1766 and https://github.com/fergald/explainer-messageport-close

Status: UNCONFIRMED → NEW
Component: Untriaged → DOM: postMessage
Ever confirmed: true
Flags: needinfo?(fergald)
Product: Firefox → Core
Severity: -- → S3
Priority: -- → P2

Andrew, I don't think this is expected. I'm reporting a bug that I just happened to find while exploring stuff for "close" event.

Daniel,

Before clicking "Force GC", the text in the page reads

port1_weak.deref() == [object MessagePort]
control_weak.deref() == a string

After closing the window (and maybe clicking "Force GC") the text in page updates to

port1_weak.deref() == [object MessagePort]
control_weak.deref() == undefined

indicating that the string has been GCed but the MessagePort has not.

If the MessagePort was GCed, it would read

port1_weak.deref() == undefined
control_weak.deref() == undefined

Both Chrome and Safari are easy to get into that state. FF never seems to reach that state.

It may be that something else needs to happen to make it GC harder but I don't know what that is.

(In reply to Fergal Daly from comment #3)

Andrew, I don't think this is expected. I'm reporting a bug that I just happened to find while exploring stuff for "close" event.

Bad phrasing on my part, apologies. Expected in the sense of we ~intentionally didn't want to react to the other end closing in the past. With the changes to the spec and related discussion where we have clarity that we're fine with revealing the information, you are of course correct that the correct, expected behavior is that the port will be GCed.

:annevk had asked why we don't GC and I wrote up in https://github.com/whatwg/html/issues/10201#issuecomment-2121870369 the following which I include here because it's hard to re-find these things:

In Firefox, all shipped MessagePorts go through our IPC. When our IPC layer is processing the implicit close for the collected port:

Honestly, it's not clear this behavior was entirely intentional (we will certainly spew NS_WARNINGs in the parent process when this case happens if the closed port sends us messages); the code has a bunch of technical debt and is due for a cleanup. But I think I might have avoided changing the behavior in a few bugs because it seemed like it might have been equally been intentional to avoid leaking GC, but it's hard to tell because our infrastructure makes it hard to find old discussion of things.

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