From 5e18a7fd922510fc7c3108a827a35fbe5b1abd09 Mon Sep 17 00:00:00 2001 From: midasmatterhorn <248507632+midasmatterhorn@users.noreply.github.com> Date: Thu, 15 Oct 2026 16:10:10 +0300 Subject: [PATCH 1/4] pdf: an inline image with absurd dimensions falls back to the EI scan MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit inline_len computed (w * n * bpc).div_ceil(8) * h with Width/Height taken straight from the content stream and no size validation — unlike decode() and mask_image, which bound their geometry first. /W 5000000000000000000 overflows the multiply in debug and test builds; in release it wraps to a small length and the caller slices the wrong bytes, misparsing the image and shifting the EI resync. Chain the arithmetic through checked_mul and return None, which the caller already routes to the EI-scan fallback. Regression test: inline_image_with_absurd_dimensions_falls_back_to_ei_scan — panics at crates/pdf/src/image.rs:85 on main, passes with the chain. --- crates/pdf/src/image.rs | 5 ++++- crates/pdf/src/tests_import.rs | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/crates/pdf/src/image.rs b/crates/pdf/src/image.rs index 5e6c49a5..69ff911e 100644 --- a/crates/pdf/src/image.rs +++ b/crates/pdf/src/image.rs @@ -82,7 +82,10 @@ pub(crate) fn inline_len(file: &File, d: &Dict, res: Option<&Dict>) -> Option Date: Fri, 16 Oct 2026 17:36:11 +0700 Subject: [PATCH 2/4] pdf: an inline image just under usize::MAX bytes doesn't overflow its end offset Co-Authored-By: Claude Opus 5.5 --- crates/pdf/src/page.rs | 2 +- crates/pdf/src/tests_import.rs | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/crates/pdf/src/page.rs b/crates/pdf/src/page.rs index 13e98b3c..1d84c0fb 100644 --- a/crates/pdf/src/page.rs +++ b/crates/pdf/src/page.rs @@ -515,7 +515,7 @@ impl<'a> Interp<'a> { && (p + 2 == data.len() || crate::object::is_white(data[p + 2])) }; let end = match crate::image::inline_len(self.file, &d, Some(res)) { - Some(len) => (start + len).min(data.len()), + Some(len) => start.saturating_add(len).min(data.len()), None => { let mut p = start; while p + 1 < data.len() && !is_ei(p) { diff --git a/crates/pdf/src/tests_import.rs b/crates/pdf/src/tests_import.rs index 3e7cd570..2e103d5e 100644 --- a/crates/pdf/src/tests_import.rs +++ b/crates/pdf/src/tests_import.rs @@ -276,6 +276,11 @@ fn inline_image_with_absurd_dimensions_falls_back_to_ei_scan() { let doc = parse(&bytes).unwrap(); let _ = render(&doc); assert!(!doc.skipped.is_empty()); + // A length just under `usize::MAX` passes the row math; past byte 4096 of the content the + // caller's `start + len` would then overflow. + let content = format!("{}q 10 0 0 10 0 0 cm BI /W 2305843009213693440 /H 8 /CS /G /BPC 8 ID EI Q", " ".repeat(5000)); + let doc = parse(&page_pdf(&content, "", vec![])).unwrap(); + let _ = render(&doc); } #[test] From f8b587503decbf0bde625e08514b1bc3710eb228 Mon Sep 17 00:00:00 2001 From: bflatastic Date: Fri, 16 Oct 2026 17:36:55 +0700 Subject: [PATCH 3/4] pdf: rustfmt the inline-image test Co-Authored-By: Claude Opus 5.5 --- crates/pdf/src/tests_import.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/crates/pdf/src/tests_import.rs b/crates/pdf/src/tests_import.rs index 2e103d5e..ad918bf4 100644 --- a/crates/pdf/src/tests_import.rs +++ b/crates/pdf/src/tests_import.rs @@ -268,11 +268,7 @@ fn inline_image_with_absurd_dimensions_falls_back_to_ei_scan() { // `/W 5000000000000000000` overflows the row math (`* bpc` alone exceeds usize::MAX): // `inline_len` must return `None` (scan for `EI`) instead of overflowing; the oversized // image itself is then refused by size. - let bytes = page_pdf( - "q 10 0 0 10 0 0 cm BI /W 5000000000000000000 /H 100 /CS /G /BPC 8 ID \0 EI Q", - "", - vec![], - ); + let bytes = page_pdf("q 10 0 0 10 0 0 cm BI /W 5000000000000000000 /H 100 /CS /G /BPC 8 ID \0 EI Q", "", vec![]); let doc = parse(&bytes).unwrap(); let _ = render(&doc); assert!(!doc.skipped.is_empty()); From 6f2f98b3982da86374f1949ca37c92291b755cdc Mon Sep 17 00:00:00 2001 From: bflatastic Date: Fri, 16 Oct 2026 17:48:08 +0700 Subject: [PATCH 4/4] pdf: inline_len returns the checked product directly (clippy) Co-Authored-By: Claude Opus 5.5 --- crates/pdf/src/image.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/pdf/src/image.rs b/crates/pdf/src/image.rs index 69ff911e..2c8adda6 100644 --- a/crates/pdf/src/image.rs +++ b/crates/pdf/src/image.rs @@ -85,7 +85,7 @@ pub(crate) fn inline_len(file: &File, d: &Dict, res: Option<&Dict>) -> Option