diff --git a/crates/svg/src/import/importer.rs b/crates/svg/src/import/importer.rs index 5b96ea5bd..2e3bc14c2 100644 --- a/crates/svg/src/import/importer.rs +++ b/crates/svg/src/import/importer.rs @@ -664,7 +664,7 @@ impl Importer { return None; } if self.nested_svg_images >= crate::MAX_NESTED_SVG_IMAGES { - self.error = Some(SvgError::TooLarge(self.max_nodes)); + self.error = Some(SvgError::TooManyImages(crate::MAX_NESTED_SVG_IMAGES)); return None; } self.nested_svg_images += 1; @@ -682,3 +682,47 @@ impl Importer { art } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::import::files::Files; + use crate::import::text::TextSlots; + use std::collections::{HashMap, HashSet}; + use vectorcraft_doc::Document; + + #[test] + fn svg_image_cap_sets_too_many_images_error() { + let mut im = Importer { + doc: Document::new(100.0, 100.0), + warnings: vec![], + mask_flags: HashMap::new(), + links: HashMap::new(), + slots: TextSlots::default(), + patterns: HashMap::new(), + midpoints: HashMap::new(), + labels: HashMap::new(), + hidden: HashSet::new(), + uses: HashMap::new(), + symbols: HashMap::new(), + blends: HashMap::new(), + files: Files::default(), + non_scaling: HashSet::new(), + data: HashMap::new(), + events: HashMap::new(), + foreign: HashMap::new(), + sublayers: HashSet::new(), + sublayer_groups: HashSet::new(), + screen: 1.0, + converted_nodes: 0, + max_nodes: 1000, + error: None, + nested_svg_images: crate::MAX_NESTED_SVG_IMAGES, + }; + let tree = usvg::Tree::from_str(r#""#, &usvg::Options::default()).unwrap(); + let res = im.svg_image(&tree, Affine::IDENTITY); + assert!(res.is_none()); + assert!(matches!(im.error, Some(SvgError::TooManyImages(crate::MAX_NESTED_SVG_IMAGES)))); + assert_eq!(im.error.unwrap().to_string(), "the SVG expands to more than 256 nested SVG images"); + } +} diff --git a/crates/svg/src/import/text.rs b/crates/svg/src/import/text.rs index a922a70e3..0e26fc524 100644 --- a/crates/svg/src/import/text.rs +++ b/crates/svg/src/import/text.rs @@ -162,6 +162,7 @@ pub(super) struct PendingText { } /// The texts [`prepare`] replaced, by placeholder index. +#[derive(Default)] pub(super) struct TextSlots { prefix: String, pub texts: Vec, diff --git a/crates/svg/src/lib.rs b/crates/svg/src/lib.rs index 7a0c5ddf9..ccc154a38 100644 --- a/crates/svg/src/lib.rs +++ b/crates/svg/src/lib.rs @@ -347,6 +347,10 @@ pub enum SvgError { /// nested-image expansion bombs, #3564). #[error("the SVG expands to more than {0} objects")] TooLarge(usize), + /// The SVG expands to more nested SVG images than the reader takes (a guard against + /// nested-image expansion bombs, #3564). + #[error("the SVG expands to more than {0} nested SVG images")] + TooManyImages(usize), } /// Export a document as an SVG string (linked images are not returned: see [`export_full`]).