Automatic update from web-platform-tests
DOM: Fix gmail event handler registry crash
`EventHandlerRegistry` is used indirectly by the compositor to determine
if a local frame root has a node with an event listener for certain
types of events that the compositor could otherwise fast-path around
to avoid the main thread, if there are no relevant event listeners.
This class is 1:1 with local frame roots, which means there must be
logic to register/unregister nodes that move across same-origin
local roots. This ensures a cross-document adopted node's *old* local
frame root no longer tracks nodes that move out of it, and the node's
*new* local root starts tracking adopted nodes that have the relevant
event listeners that EHR cares about.
This logic exists in `Node::WillMoveToNewDocument()` and
`Node::MoveEventListenersToNewDocument()`, however before this CL it
was broken. It would only trigger a transfer across
EventHandlerRegistries if the document was moving across blink::Page
objects. However, there can be multiple same-origin local frame roots
in the same blink::Page, so the transfer logic was kicking in under
fewer circumstances that it should have.
This made it possible to:
1. A trigger a DCHECK() in `EventHandlerRegistry::CheckConsistency()`
that ensures every tracked event target shares the local frame
root that's associated with the given EHR. The most notable site
triggering this DCHECK() was gmail, which is how this issue was
discovered.
2. Transfer a node from one local frame root to another and break
the event listeners on that node that the compositor cares about
(see `EventHandlerRegistry::EventHandlerClass`) because the
compositor would never know about these listener after the node
transferred to its *new* local frame root's registry.
This CL fixes the update logic to transfer event targets across
registries whenever event targets move across local frame roots, and
adds two tests, one for each scenario above.
R=dbaron
Bug: 40277823
Change-Id: Icde11417e80850fe7c512d90895c90ddae9ac85b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6674259
Reviewed-by: David Baron <dbaron@chromium.org>
Commit-Queue: Dominic Farolino <dom@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1480989}
--
wpt-commits: 41b057990dc2e3d79492353eb7925e2503902051
wpt-pr: 53510
62 lines
2.7 KiB
HTML
62 lines
2.7 KiB
HTML
<!DOCTYPE html>
|
|
<title>Node moves to another document</title>
|
|
<link rel="author" title="Dominic Farolino" href="mailto:dom@chromium.org">
|
|
<link rel="help" href="https://crbug.com/40277823">
|
|
<script src="/resources/testharness.js"></script>
|
|
<script src="/resources/testharnessreport.js"></script>
|
|
<script src="/common/get-host-info.sub.js"></script>
|
|
|
|
<body>
|
|
<button id=button></button>
|
|
<script>
|
|
// This is a regression test for a Chromium crash: https://crbug.com/40277823.
|
|
// The test is reproducible by:
|
|
// 1. Creating a node with an event listener for an event type that the
|
|
// compositor cares about; `touchmove` in this case.
|
|
// 2. Adopting that node into a tree with a *different* local root (i.e., a
|
|
// tree where the root is a local frame, different from this document, with
|
|
// a remote parent).
|
|
// 3. Maintaining a reference to the node that now exists in a different local
|
|
// frame root.
|
|
// 4. Add a same-type event listener to the document that used to host the
|
|
// now-adopted node. This fails an assertion in the event handler
|
|
// registry's consistency checker, which is mistakenly holding a reference
|
|
// to the node that is now hosted in a different local frame root, which
|
|
// the checker does not expect.
|
|
promise_test(async t => {
|
|
const crossOriginChild = document.createElement('iframe');
|
|
const crossOriginChildURL = new URL('resources/cross-origin-middle-frame.html', get_host_info().HTTP_REMOTE_ORIGIN + location.pathname);
|
|
crossOriginChild.src = crossOriginChildURL;
|
|
|
|
const grandchildLoadPromise = new Promise(resolve => {
|
|
window.onmessage = e => {
|
|
if (e.data === 'grandchild loaded') {
|
|
resolve();
|
|
}
|
|
}
|
|
});
|
|
document.body.append(crossOriginChild);
|
|
await grandchildLoadPromise;
|
|
|
|
const sameOriginGrandchild = window.frames[0][0];
|
|
assert_not_equals(sameOriginGrandchild.document, null,
|
|
"same-origin grandchild frame exists");
|
|
|
|
button.addEventListener('touchmove', e => {});
|
|
|
|
// This is important because before https://crbug.com/40277823 was fixed, it
|
|
// would prevent the garbage collector from removing `button` from this
|
|
// document's event handler registry. As long as it's still (incorrectly) in
|
|
// the registry when we add the `touchmove` event handler is added to this
|
|
// document later (post-adoption), the registry's consistency checker would
|
|
// crash, asserting that the still-tracked event target is rooted at its *old*
|
|
// local frame root.
|
|
window.buttonHolder = button;
|
|
|
|
sameOriginGrandchild.document.adoptNode(button);
|
|
// This below would previously cause the Chromium crash.
|
|
document.body.addEventListener('touchmove', e => {});
|
|
}, "Event handler-bearing node moved across local roots in the same tab/page");
|
|
</script>
|
|
</body>
|