Integration: #2180 keep the pixel limit as the only size cap

This commit is contained in:
aiongg
2026-10-21 14:49:18 +00:00
parent 1a4d81fd5a
commit 8ec24dc868
+8 -10
View File
@@ -339,14 +339,11 @@ pub fn decode_thumbnail_with(bytes: &[u8], opts: &ThumbnailOptions) -> Result<Th
})
}
/// Cap on total decoded samples. Mirrors `lightcraft_raw::MAX_SAMPLES` (codecs does not depend on
/// lightcraft-raw, so the value is restated here).
const MAX_SAMPLES: u64 = 1 << 30;
/// Checked sample-buffer length `width × height × ch`, in u64: `None` on overflow, a zero dimension,
/// or a product past [`MAX_SAMPLES`].
/// Checked sample-buffer length `width × height × ch`, in u64: `None` on overflow or a zero
/// dimension. Image size is capped by `DecodeOptions::max_pixels` alone; once the buffer is known to
/// hold this many samples, every later `usize` product is bounded by an allocation that exists.
pub(crate) fn checked_sample_buf_len(width: usize, height: usize, ch: usize) -> Option<u64> {
(width as u64).checked_mul(height as u64).and_then(|n| n.checked_mul(ch as u64)).filter(|&n| n > 0 && n <= MAX_SAMPLES)
(width as u64).checked_mul(height as u64).and_then(|n| n.checked_mul(ch as u64)).filter(|&n| n > 0)
}
#[cfg(test)]
@@ -355,14 +352,15 @@ mod checked_arithmetic_tests {
#[test]
fn checked_sample_buf_len_wrap_inputs_rejected() {
// 2^30 px × 4 ch = 2^32 samples wraps on 32-bit usize and is past the 2^30-sample cap.
assert_eq!(checked_sample_buf_len(1 << 30, 1, 4), None);
assert_eq!(checked_sample_buf_len(u32::MAX as usize, 1, 2), None);
assert_eq!(checked_sample_buf_len(usize::MAX, usize::MAX, 4), None);
assert_eq!(checked_sample_buf_len(0, 1, 3), None);
}
#[test]
fn checked_sample_buf_len_normal_accepted() {
assert_eq!(checked_sample_buf_len(100, 1, 3), Some(300));
assert_eq!(checked_sample_buf_len(1, 1, 1), Some(1));
// 300 Mpx RGBA is within the default pixel limit, so it must not be refused by sample count.
assert_eq!(checked_sample_buf_len(20_000, 15_000, 4), Some(1_200_000_000));
}
}