From 9caae9c542ada7656986ecb87d32a89e8b51e6bd Mon Sep 17 00:00:00 2001 From: NetterSilver <133535268+Silvertree2010@users.noreply.github.com> Date: Sat, 31 Oct 2026 14:07:33 +0100 Subject: [PATCH] Drop XML-forbidden control characters from math SVG text Found while testing crates/engine/src/math.rs:909 (to_svg, the `esc` closure used for each glyph) Co-Authored-By: Claude Haiku 5.5 Co-Authored-By: Claude Sonnet 5.5 --- crates/engine/src/math.rs | 4 ++++ crates/engine/src/math/tests.rs | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/crates/engine/src/math.rs b/crates/engine/src/math.rs index 468ce1c5a..6cfd5e2e9 100644 --- a/crates/engine/src/math.rs +++ b/crates/engine/src/math.rs @@ -916,6 +916,10 @@ pub fn to_svg(latex: &str, size: f64) -> (Vec, (f64, f64)) { let face = f.face(c, *italic); let fam = if std::ptr::eq(face, &*f.fallback) { FALLBACK } else { FAMILY }; let it = *italic && !std::ptr::eq(face, &*f.fallback); + // XML 1.0 forbids most control characters and U+FFFE/U+FFFF. + if !matches!(c, '\t' | '\n' | '\r' | '\u{20}'..='\u{D7FF}' | '\u{E000}'..='\u{FFFD}' | '\u{10000}'..='\u{10FFFF}') { + continue; + } let _ = write!( svg, "{}", diff --git a/crates/engine/src/math/tests.rs b/crates/engine/src/math/tests.rs index 9d1e75884..bd35c74bd 100644 --- a/crates/engine/src/math/tests.rs +++ b/crates/engine/src/math/tests.rs @@ -474,3 +474,10 @@ fn deep_nodes_drop_when_replaced_or_owned_by_unwinding_continuations() { }); assert!(result.is_err(), "the intentional panic must actually unwind the owned frames"); } + +#[test] +fn svg_drops_control_characters_forbidden_by_xml() { + let (svg, _) = to_svg("a\u{1}b\u{c}", 12.0); + let svg = String::from_utf8(svg).unwrap(); + assert!(!svg.chars().any(|c| c < ' ' && !matches!(c, '\t' | '\n' | '\r')), "control character in SVG: {svg:?}"); +}