LibWeb: Fix crash from SVG resource boxes outliving removed element
Problem: Crash when removing a <mask>, <clipPath>, or <pattern> element that’s referenced via url(#id), and then GC’ing it. Cause: <mask>, <clipPath>, and <pattern> are laid out as resource boxes attached to the referencing element's layout subtree, rather than their own. So those survive cleanup of their DOM ancestor. Once a removed <mask>/<clipPath>/<pattern> is collected, its resource box’s weak DOM node pointer is null. And dereferencing that trips an assert — both while painting and while tearing down the layout tree. Fix: When a <mask>, <clipPath>, or <pattern> is removed, request a full layout-tree update while the element’s still alive. That drops the stale resource boxes (whose url(#id) references no longer resolve) before the node gets collected. Fixes https://github.com/LadybirdBrowser/ladybird/issues/10127
This commit is contained in:
parent
66f313fe48
commit
4bbc5e0950
4 changed files with 48 additions and 0 deletions
|
|
@ -269,6 +269,12 @@ void SVGElement::removed_from(IsSubtreeRoot is_subtree_root, Node* old_ancestor,
|
|||
return;
|
||||
|
||||
remove_from_use_element_that_reference_this();
|
||||
|
||||
// A <mask>, <clipPath>, or <pattern> referenced via url(#id) is laid out as a resource box attached to the
|
||||
// referencing element's layout subtree. So it outlives this element's own DOM node. Rebuild the layout tree
|
||||
// while this element is still alive — so those stale resource boxes are dropped before this node is collected.
|
||||
if (id().has_value())
|
||||
document().set_needs_full_layout_tree_update(true);
|
||||
}
|
||||
|
||||
void SVGElement::remove_from_use_element_that_reference_this()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
<!DOCTYPE html>
|
||||
<svg width="200" height="200">
|
||||
<rect width="100" height="100" clip-path="url(#c)"/>
|
||||
</svg>
|
||||
<svg width="0" height="0">
|
||||
<clipPath id="c"><rect width="50" height="50"/></clipPath>
|
||||
</svg>
|
||||
<script>
|
||||
internals.dumpDisplayList();
|
||||
document.getElementById("c").remove();
|
||||
internals.dumpDisplayList();
|
||||
internals.gc();
|
||||
internals.dumpDisplayList();
|
||||
</script>
|
||||
14
Tests/LibWeb/Crash/SVG/mask-reference-removed-and-gced.html
Normal file
14
Tests/LibWeb/Crash/SVG/mask-reference-removed-and-gced.html
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<!DOCTYPE html>
|
||||
<svg width="200" height="200">
|
||||
<rect width="100" height="100" mask="url(#m)"/>
|
||||
</svg>
|
||||
<svg width="0" height="0">
|
||||
<mask id="m"><rect width="100" height="100"/></mask>
|
||||
</svg>
|
||||
<script>
|
||||
internals.dumpDisplayList();
|
||||
document.getElementById("m").remove();
|
||||
internals.dumpDisplayList();
|
||||
internals.gc();
|
||||
internals.dumpDisplayList();
|
||||
</script>
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
<!DOCTYPE html>
|
||||
<svg width="200" height="200">
|
||||
<rect width="100" height="100" fill="url(#p)"/>
|
||||
</svg>
|
||||
<svg width="0" height="0">
|
||||
<pattern id="p" width="10" height="10"><rect width="5" height="5"/></pattern>
|
||||
</svg>
|
||||
<script>
|
||||
internals.dumpDisplayList();
|
||||
document.getElementById("p").remove();
|
||||
internals.dumpDisplayList();
|
||||
internals.gc();
|
||||
internals.dumpDisplayList();
|
||||
</script>
|
||||
Loading…
Reference in a new issue