Branch: refs/heads/main
Home: https://github.com/WebKit/WebKit
Commit: 9414a9722a8439557c0c3972eec476dc922a1566
https://github.com/WebKit/WebKit/commit/9414a9722a8439557c0c3972eec476dc922a1566
Author: Ryosuke Niwa <[email protected]>
Date: 2026-06-12 (Fri, 12 Jun 2026)
Changed paths:
M Source/WebCore/dom/ContainerNodeAlgorithms.cpp
M Source/WebCore/dom/Node.cpp
M Source/WebCore/dom/Node.h
Log Message:
-----------
REGRESSION: Use-after-free in Node::m_shadowIncludingRoot via destructor
cascade not propagating into shadow roots
https://bugs.webkit.org/show_bug.cgi?id=312712
rdar://175103172
Reviewed by Geoffrey Garen.
When a document is torn down via Document::removedLastRef through
removeDetachedChildrenInContainer,
the <html> element is removed from the document. Since <html> is still in tree
scope at this point,
notifyChildNodeRemoved is called, which walks the entire subtree - including
shadow roots - and sets
m_shadowIncludingRoot to <html> for all descendants. This is correct at that
moment.
Then <html> is freed when the loop's RefPtr releases it (children don't
ref-count their parents -
m_parentNode is CheckedPtr). This triggers a destructor cascade:
~ContainerNode(<html>) via
removeDetachedChildrenInContainer(<html>) processes <body>, then
~ContainerNode(<body>) processes
the <video> element, and so on. Each step calls resetShadowIncludingRoot() on
the direct child,
fixing that node's cache. However, since IsConnected and IsInShadowTree flags
were cleared during
the initial notifyChildNodeRemoved walk, isInTreeScope() returns false, so
notifyChildNodeRemoved
is skipped in this case. This means the shadow root and its descendants are
never updated -
m_shadowIncludingRoot of these nodes still point to the now-freed <html>.
Nodes kept alive by mechanisms other than JS wrappers - such as
HTMLMediaElement which survives as
an ActiveDOMObject - retain their shadow DOM with dangling
m_shadowIncludingRoot pointers. When
these nodes are subsequently used (e.g., VTT cue display tree updates via an
event loop task), the
stale pointer is dereferenced, causing an use-after-free.
This PR fixes this use-after-free bug by updating m_shadowIncludingRoot for
removed subtrees when
the root's refCount is greater than 1 (i.e. there is an external reference to
the node beyond the
RefPtr in removeDetachedChildrenInContainer).
No new tests since existing media tests such as
media/track/webvtt-parser-does-not-leak.html would
hit debug assertions without this fix, and this bug requires a node to be kept
alive by C++ code.
* Source/WebCore/dom/ContainerNodeAlgorithms.cpp:
(WebCore::removeDetachedChildrenInContainer):
* Source/WebCore/dom/Node.cpp:
(WebCore::Node::updateShadowIncludingRootForSubtree):
* Source/WebCore/dom/Node.h:
Originally-landed-as: 305413.700@safari-7624-branch (5d07bda85f02).
rdar://176059252
Canonical link: https://commits.webkit.org/315148@main
To unsubscribe from these emails, change your notification settings at
https://github.com/WebKit/WebKit/settings/notifications