From 2d1fabda1f931b1dc3ef82ae6df65b38044da7e0 Mon Sep 17 00:00:00 2001 From: NetterSilver <133535268+Silvertree2010@users.noreply.github.com> Date: Sat, 24 Oct 2026 11:10:23 +0200 Subject: [PATCH] Reject non-finite percent strings for lineHeight and letterSpacing Found while testing crates/engine/src/cmd/props.rs:145 (line_height) and :153 (letter_spacing) Co-Authored-By: Claude Haiku 5.5 Co-Authored-By: Claude Sonnet 5.5 --- crates/engine/src/cmd/props.rs | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/crates/engine/src/cmd/props.rs b/crates/engine/src/cmd/props.rs index b5889d8c..9ee499fc 100644 --- a/crates/engine/src/cmd/props.rs +++ b/crates/engine/src/cmd/props.rs @@ -144,7 +144,9 @@ pub(crate) fn sizing(v: &Value) -> Option { pub(crate) fn line_height(v: &Value) -> Option { match v { Value::String(s) if s.eq_ignore_ascii_case("auto") => Some(LineHeight::Auto), - Value::String(s) if s.trim().ends_with('%') => s.trim().trim_end_matches('%').trim().parse().ok().map(LineHeight::Percent), + Value::String(s) if s.trim().ends_with('%') => { + s.trim().trim_end_matches('%').trim().parse().ok().filter(|f: &f64| f.is_finite()).map(LineHeight::Percent) + } Value::Object(_) => serde_json::from_value(v.clone()).ok(), other => f64_of(other).map(LineHeight::Pixels), } @@ -152,7 +154,9 @@ pub(crate) fn line_height(v: &Value) -> Option { pub(crate) fn letter_spacing(v: &Value) -> Option { match v { - Value::String(s) if s.trim().ends_with('%') => s.trim().trim_end_matches('%').trim().parse().ok().map(LetterSpacing::Percent), + Value::String(s) if s.trim().ends_with('%') => { + s.trim().trim_end_matches('%').trim().parse().ok().filter(|f: &f64| f.is_finite()).map(LetterSpacing::Percent) + } Value::Object(_) => serde_json::from_value(v.clone()).ok(), other => f64_of(other).map(LetterSpacing::Pixels), } @@ -1277,3 +1281,17 @@ pub fn describe(doc: &Document, id: NodeId) -> Value { let _ = Color::BLACK; v } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn non_finite_percent_strings_are_rejected() { + for s in ["NaN%", "inf%", "-inf%"] { + assert!(line_height(&json!(s)).is_none(), "line_height accepted {s}"); + assert!(letter_spacing(&json!(s)).is_none(), "letter_spacing accepted {s}"); + } + assert!(matches!(line_height(&json!("150%")), Some(LineHeight::Percent(p)) if p == 150.0)); + } +}