mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-04-26 09:45:06 +02:00
When an SVGElement is removed from a <use> element's shadow tree, we need to check if it was in a use element's shadow root to avoid notifying use elements about the removal of their own clones. The check was incorrectly using root() instead of old_root. Since the element has already been detached when removed_from() is called, root() no longer returns the shadow root, causing the early-return check to fail. This led to O(n) recursion depth when clearing a use element's shadow tree, as each removed clone would trigger another round of remove_all_children() on use elements referencing the same ID.
48 lines
1.5 KiB
HTML
48 lines
1.5 KiB
HTML
<!DOCTYPE html>
|
|
<script src="../include.js"></script>
|
|
<svg id="defs" style="display: none;"></svg>
|
|
<svg id="testSvg"></svg>
|
|
<script>
|
|
// Generate a deeply nested SVG structure that would cause stack overflow
|
|
// if the recursion bug in SVGElement::removed_from is present.
|
|
const depth = 100;
|
|
|
|
let inner = document.createElementNS("http://www.w3.org/2000/svg", "g");
|
|
inner.id = "level0";
|
|
|
|
for (let i = 1; i < depth; i++) {
|
|
let g = document.createElementNS("http://www.w3.org/2000/svg", "g");
|
|
g.id = `level${i}`;
|
|
g.appendChild(inner);
|
|
inner = g;
|
|
}
|
|
|
|
let symbol = document.createElementNS("http://www.w3.org/2000/svg", "symbol");
|
|
symbol.id = "deepSymbol";
|
|
symbol.appendChild(inner);
|
|
defs.appendChild(symbol);
|
|
|
|
let use = document.createElementNS("http://www.w3.org/2000/svg", "use");
|
|
use.id = "deepUse";
|
|
use.setAttribute("href", "#deepSymbol");
|
|
testSvg.appendChild(use);
|
|
|
|
function shadowChildCount(use) {
|
|
let sr = internals.getShadowRoot(use);
|
|
return sr ? sr.childNodes.length : 0;
|
|
}
|
|
|
|
asyncTest((done) => {
|
|
setTimeout(() => {
|
|
println(`Initial shadow children: ${shadowChildCount(deepUse)}`);
|
|
|
|
// This would cause stack overflow before the fix due to O(depth) recursion
|
|
document.getElementById("deepSymbol").remove();
|
|
|
|
println(`After removal shadow children: ${shadowChildCount(deepUse)}`);
|
|
println("PASS: No stack overflow from deep recursion");
|
|
done();
|
|
}, 10);
|
|
});
|
|
</script>
|