From 2796f3de0d3553a3e15c4a9e4b365ddac7a55a72 Mon Sep 17 00:00:00 2001 From: Marco Arnulfo <103679419+marcoarnulfo@users.noreply.github.com> Date: Mon, 12 Oct 2026 12:27:50 +0200 Subject: [PATCH] fix(print): refuse huge posters at the sheet limit instead of overflowing (#1335) (#1376) A poster scale large enough to make both tile counts saturate at usize::MAX overflowed when they were multiplied for the 1024-sheet check: a panic with overflow checks, and a product that wraps to 1 without them, which let the sheet loops run. The headless doc_print tool accepts any finite positive scale, so a script could reach it. Multiply with checked_mul and treat an overflow as over the limit, so the request gets the existing "more than 1024 sheets" error. Adds tests::huge_posters_are_refused_at_the_sheet_limit, which panics before this change and passes with and without overflow checks after it. --- crates/print/src/lib.rs | 3 ++- crates/print/src/tests.rs | 11 +++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/crates/print/src/lib.rs b/crates/print/src/lib.rs index 1a2868d7a4..3c8a2a7bda 100644 --- a/crates/print/src/lib.rs +++ b/crates/print/src/lib.rs @@ -467,7 +467,8 @@ pub fn layout(sizes: &[(f64, f64)], settings: &Settings) -> Result, P let (stepx, stepy) = (tw - overlap, th - overlap); let nx = (((sw - overlap) / stepx).ceil() as usize).max(1); let ny = (((sh - overlap) / stepy).ceil() as usize).max(1); - if nx * ny > 1024 { + // The counts saturate at usize::MAX for a huge scale, so their product can overflow. + if nx.checked_mul(ny).is_none_or(|n| n > 1024) { return Err(PrintError::Invalid("the poster would need more than 1024 sheets".into())); } // Tiles from the top-left, row by row. diff --git a/crates/print/src/tests.rs b/crates/print/src/tests.rs index 3ae29f5243..22ae44424a 100644 --- a/crates/print/src/tests.rs +++ b/crates/print/src/tests.rs @@ -192,6 +192,17 @@ fn posters_tile_with_overlap() { assert!(layout(&[(200.0, 300.0)], &settings(vec![0], Layout::Poster { scale: 400.0, overlap: 400.0, cut_marks: false })).is_err()); } +/// Issue #1335: a scale so large that the tile counts saturate is refused with the sheet-limit +/// error, not an overflow in counting the sheets. +#[test] +fn huge_posters_are_refused_at_the_sheet_limit() { + let refused = Err(PrintError::Invalid("the poster would need more than 1024 sheets".into())); + for scale in [100_000.0, 1e22, f64::MAX] { + let poster = settings(vec![0], Layout::Poster { scale, overlap: 18.0, cut_marks: true }); + assert_eq!(layout(&[(200.0, 300.0)], &poster), refused, "scale {scale}"); + } +} + #[test] fn imposed_pdf_has_the_sheets_and_honours_comments_and_forms() { let doc = fixture(3);