fix: harden comment serialization and DOMSnapshot recursion depth

fix: harden comment serialization and DOMSnapshot recursion depth
This commit is contained in:
SGavrl authored and GitHub committed 2026-07-01 16:02:55 +00:00
commit f72234d99e
2 files changed
+26 -5

No files matched your search

+16 -5
View File
@@ -84,21 +84,32 @@ impl Interner {
} }
/// Pre-order DFS from the document, recording each node and its parent's index. /// Pre-order DFS from the document, recording each node and its parent's index.
/// Iterative with an explicit stack: the MAX_NODES cap bounds the node count,
/// but recursion depth is a separate axis. A deeply nested linear chain (script
/// can build thousands of nested elements) would recurse that many frames deep
/// and could overflow the stack before the count guard triggers. An explicit
/// stack keeps the depth on the heap (issue #341).
fn walk( fn walk(
dom: &DomTree, dom: &DomTree,
id: NodeId, root: NodeId,
parent: i64, root_parent: i64,
order: &mut Vec<NodeId>, order: &mut Vec<NodeId>,
parent_idx: &mut Vec<i64>, parent_idx: &mut Vec<i64>,
) { ) {
// (node, parent_index). Children are pushed in reverse so they pop in
// document order, preserving the original pre-order traversal.
let mut stack: Vec<(NodeId, i64)> = vec![(root, root_parent)];
while let Some((id, parent)) = stack.pop() {
if order.len() >= MAX_NODES { if order.len() >= MAX_NODES {
return; break;
} }
let my = order.len() as i64; let my = order.len() as i64;
order.push(id); order.push(id);
parent_idx.push(parent); parent_idx.push(parent);
for child in dom.children(id) { let children: Vec<NodeId> = dom.children(id);
walk(dom, child, my, order, parent_idx); for child in children.into_iter().rev() {
stack.push((child, my));
}
} }
} }
+10
View File
@@ -72,7 +72,17 @@ impl DomTree {
} }
NodeData::Comment { contents } => { NodeData::Comment { contents } => {
buf.push_str("<!--"); buf.push_str("<!--");
// The HTML parser can never produce a comment whose data contains
// "-->" (that ends the comment), but script can via
// document.createComment("a-->b"). Emitting it verbatim would close
// the comment early and let the trailing text escape into markup.
// Neutralize the terminator so the serialized output round-trips as
// a single comment.
if contents.contains("-->") {
buf.push_str(&contents.replace("-->", "--&gt;"));
} else {
buf.push_str(contents); buf.push_str(contents);
}
buf.push_str("-->"); buf.push_str("-->");
} }
NodeData::ProcessingInstruction { target, data } => { NodeData::ProcessingInstruction { target, data } => {