From 3624a50423aefedcc09adc207d92e874c3f153ab Mon Sep 17 00:00:00 2001 From: Michael Anderson Date: Tue, 13 Oct 2026 07:34:27 -0500 Subject: [PATCH] Never crash: Refuse raw data with two samples per pixel (#1511) The demosaic read past each pixel. DNG decode and validation refuse it now. --- crates/raw/src/demosaic/mod.rs | 15 ++++++++++++++- crates/raw/src/dng.rs | 3 ++- crates/raw/src/lib.rs | 4 ++++ crates/raw/tests/dng.rs | 25 +++++++++++++++++++++++++ 4 files changed, 45 insertions(+), 2 deletions(-) diff --git a/crates/raw/src/demosaic/mod.rs b/crates/raw/src/demosaic/mod.rs index c868dc6aa..b8a3c599a 100644 --- a/crates/raw/src/demosaic/mod.rs +++ b/crates/raw/src/demosaic/mod.rs @@ -79,7 +79,20 @@ pub fn demosaic(n: &Normalized, method: Method) -> Rgb32f { } match (&n.cfa, n.cpp) { (_, 3) => Rgb32f { width: w, height: h, data: n.data.as_chunks::<3>().0.iter().map(|c| [c[0], c[1], c[2]]).collect() }, - (_, cpp) if cpp != 1 => Rgb32f { width: w, height: h, data: n.data.chunks_exact(cpp).map(|c| [c[0], c[1], c[2]]).collect() }, + // four colours develop from their first three; narrower data (refused by `RawImage::validate`, issue #1511) + // repeats its last sample instead of reading past the pixel + (_, cpp) if cpp != 1 => Rgb32f { + width: w, + height: h, + data: n + .data + .chunks_exact(cpp.max(1)) + .map(|c| { + let s = |i: usize| c.get(i).or(c.last()).copied().unwrap_or(0.0); + [s(0), s(1), s(2)] + }) + .collect(), + }, (None, _) => Rgb32f { width: w, height: h, data: n.data.iter().map(|&v| [v; 3]).collect() }, (Some(cfa), _) => { let m = Mosaic { w, h, data: &n.data, cfa }; diff --git a/crates/raw/src/dng.rs b/crates/raw/src/dng.rs index 3c7ece61b..de14e412b 100644 --- a/crates/raw/src/dng.rs +++ b/crates/raw/src/dng.rs @@ -207,7 +207,8 @@ pub(crate) fn decode_as(bytes: &[u8], mode: Mode, format: RawFormat) -> Result