On Tue, Nov 17, 2015 at 5:22 AM, Andrew Sutherland
<[email protected]> wrote:
> 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.

The window global is the parent of the objects you obtained from the
message, so it will be held alive here. Wrapper cutting doesn't come
into play because everything involved here is content. If we *did* cut
wrappers (in other words, if your parent frame here were chrome)
attempting to access what you obtained from the message would throw
exceptions.

> 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.

It's impossible to reap the global as long as any objects parented to
it are held alive.

Is the actual performance problem here just returning to (and waiting
for) the event loop to continue execution?

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

Reply via email to