From 36cfc8566ea004d7a42e2c9ce9930b62a6863860 Mon Sep 17 00:00:00 2001 From: mtlcl410 <2368091+mtlcl410@users.noreply.github.com> Date: Mon, 19 Oct 2026 01:53:12 +0800 Subject: [PATCH] M10: dynamicRender is read only from markup whose closing tags match (#3180) Review follow-up on #3192. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Gv2WwdgjmBz33GWkwgNn3Q --- crates/render/src/inspect.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/crates/render/src/inspect.rs b/crates/render/src/inspect.rs index 5d0de3d7d..12c7204ca 100644 --- a/crates/render/src/inspect.rs +++ b/crates/render/src/inspect.rs @@ -1710,25 +1710,29 @@ fn next_tag(xml: &str, mut from: usize) -> Option> { /// it closes itself, or it is never closed. fn xml_child_body<'a>(xml: &'a str, name: &str) -> Option<&'a str> { let mut at = 0; - let mut depth = 0_usize; + // The elements open around `at`, innermost last: a closing tag must name the innermost one, + // or the markup is malformed and has no value. + let mut open_tags: Vec<&str> = Vec::new(); // Where the wanted element's content starts, once its opening tag is seen at the top level. let mut open = None; loop { let tag = next_tag(xml, at)?; at = tag.end; if tag.close { - depth = depth.checked_sub(1)?; - if depth == 0 + if open_tags.pop()? != tag.local { + return None; + } + if open_tags.is_empty() && let Some(start) = open { return xml.get(start..tag.start); } } else if !tag.empty { - if depth == 0 && tag.local == name { + if open_tags.is_empty() && tag.local == name { open = Some(tag.end); } - depth = depth.saturating_add(1); - } else if depth == 0 && tag.local == name { + open_tags.push(tag.local); + } else if open_tags.is_empty() && tag.local == name { return None; } } @@ -2771,6 +2775,9 @@ trailer << /Root 1 0 R >> assert_eq!(text(&config("")), None); assert_eq!(text(&config("")), None); assert_eq!(text(&config("forbidden")), None); + // Closing tags that don't match what they close: malformed, no value (review on #3192). + assert_eq!(text(&config("forbidden")), None); + assert_eq!(text("forbidden"), None); // The same name anywhere but config/acrobat/acrobat7 (form data, another config branch). let xdp = "forbiddenforbidden"; assert_eq!(text(xdp), None);