At the NGA wrap-up this past Thursday it was mentioned that https://github.com/gaia-components/bridge/issues/69 was landed to deal with latency problems with bridge.js versus postMessage and one of the losses/wins was that structured cloning no longer happens.

In retrospect, this worried me, so I made this test: https://gist.github.com/asutherland/79d629e2c9d1b7a16a2c and runnable at https://clicky.visophyte.org/tests/iframe-entrainment/parent-root.html

The tl;dr is that holding onto any non-value objects provided in a message seems to entrain the iframe's window and all of its global/expandos (but not the DOM), which is concerning and eliminates many of the intended benefits of the use of iframes.

== Investigation:

In the test:
- We have a child iframe.
- Script in the child iframe creates a 2 megabyte Uint8Array and saves it on its window and a 3 megabyte Uint8Array (that may end up as a 4 meg allocation) and saves it on a DOM node as an expando. This helps us tell what gets entrained. - Script in the child iframe creates an object and posts it to the parent using MessageEvent and dispatchEvent as used by bridge.js
- The parent retains a reference to the data posted on its window.
- The parent kills off the child iframe.

And then I as a tester using firefox nightly:
- Use about:memory to force aggressive GC by hitting the "minimize memory usage" button.
- "Measure" a "verbose" memory report.
- Search for "child-frame.html" and see that the window still exists with its compartment in a detached window at "top(none)/detached/window(http://localhost/t-html/iframes/child-frame.html)" and that the compartment includes "2,097,296 B (03.15%) -- class(ArrayBuffer)"

Testing variations:
- If we do not save off the data in the parent by commenting out only the saving line, then the child window is not entrained. (So there's nothing I'm screwing up in the parent or child otherwise to cause the iframe/its window to be entrained.) - If the child saves a reference to the expando DOM node, then we have 5 MiB of ArrayBuffer still around. - Creating the data using Object.create(null) to avoid the prototype chain has no beneficial effect, the window/global is still entrained. - Trying to just clobber the contents of the iframe via setting the `src` to a data URI does not avoid the leak.

This suggests that cross-compartment wrapper-cutting does not occur in this case (makes sense) and that although the DOM and its expandos are able to be collected if there are no window-rooted references, the window global is otherwise kept alive as a static root.

Since one of the main goals of the iframes seems to be to make it impossible or at least harder for buggy code in the iframes to leak data, this seems concerning.

Is this something that we're aware of and are there platform mitigation bugs that exist? (I doubt wrapper-cutting is viable for the web as it exists, but maybe the platform could reap the window global or its expandos?) It sounded like the apparent performance of the NGA-ported apps really depends on the https://github.com/gaia-components/bridge/issues/69 fix to avoid yielding to the busy event loop. Unfortunately JSON.parse(JSON.stringify(message.data)) in the receiving window is the only easy way that jumps out at me to try and "bless" the objects into the current compartment using mechanism available to non-chrome code, but: - That's not viable unless we're throwing away all the fidelity of structured cloning. - That means the GC engine is still on the hook to actually reap those references out of the receiving window before the iframe can be totally GC'ed, we're just upper-bounding their lifetime by avoiding any possibility of the bridge.js consumers of holding onto data.

But maybe a structured clone polyfill like https://github.com/traviskaufman/cycloneJS could work, noting that I haven't audited that it really avoids any references to the source object after the fact.

Andrew
_______________________________________________
dev-fxos mailing list
[email protected]
https://lists.mozilla.org/listinfo/dev-fxos

Reply via email to