diff --git a/crates/cad/src/import/build.rs b/crates/cad/src/import/build.rs index ff2e84bb8..1df9c0ea1 100644 --- a/crates/cad/src/import/build.rs +++ b/crates/cad/src/import/build.rs @@ -23,6 +23,8 @@ const PT_PER_MM: f64 = 72.0 / 25.4; const THINNEST: f64 = 0.25; /// The most objects an import makes. const MAX_NODES: usize = 2_000_000; +/// The most block visits (one per insert copy) an import makes, whatever they produce. +const MAX_VISITS: usize = 10_000_000; /// How far from the origin art may lie (points): the canvas. pub(crate) const MAX_EXTENT: f64 = 4.0e6; @@ -63,6 +65,7 @@ pub(crate) struct Build<'d, 'a> { /// Lineweights are multiplied by this. lw_scale: f64, nodes: usize, + visits: usize, warnings: Vec, } @@ -118,6 +121,7 @@ impl<'d, 'a> Build<'d, 'a> { symbol_map: Affine::IDENTITY, lw_scale: 1.0, nodes: 0, + visits: 0, warnings: vec![], } } @@ -557,6 +561,13 @@ impl<'d, 'a> Build<'d, 'a> { /// The art of block `name` drawn by `map`, as one object. fn art(&mut self, name: &str, map: Affine, inh: &Inherit, depth: u32) -> Option { + self.visits += 1; + if self.visits > MAX_VISITS { + if self.visits == MAX_VISITS + 1 { + self.warn(TOO_MANY); + } + return None; + } let items = self.block(name)?; if !self.enter(name, depth) { return None; diff --git a/crates/cad/src/import/tests.rs b/crates/cad/src/import/tests.rs index 9e8780513..61ba1dbf4 100644 --- a/crates/cad/src/import/tests.rs +++ b/crates/cad/src/import/tests.rs @@ -799,6 +799,24 @@ fn array_inserts_attributes_and_dimensions() { assert_eq!(bounds(&leaves(&doc)[0]).width(), 50.0); } +#[test] +fn nested_array_inserts_of_nothing_stop_at_the_work_budget() { + let block = |name: &'static str, inner: Option<&'static str>| { + let mut b = vec![(0, "BLOCK"), (2, name), (70, "1"), (10, "0"), (20, "0")]; + if let Some(i) = inner { + b.extend([(0, "INSERT"), (2, i), (10, "0"), (20, "0"), (70, "300"), (44, "1")]); + } + b.push((0, "ENDBLK")); + b + }; + let mut blocks = block("*A", Some("*B")); + blocks.extend(block("*B", Some("*C"))); + blocks.extend(block("*C", None)); + let top = [(0, "INSERT"), (2, "*A"), (10, "0"), (20, "0"), (70, "300"), (44, "1")]; + let r = open(&drawing(&[], &[], &blocks, &top), &points()); + assert!(r.warnings.iter().any(|w| w.contains("more than")), "{:?}", r.warnings); +} + #[test] fn blocks_inside_themselves_are_left_out_without_hanging() { let blocks = [