Skip to content

Commit 553fe92

Browse files
committed
Image size checks
1 parent 787ba49 commit 553fe92

File tree

2 files changed

+35
-9
lines changed

2 files changed

+35
-9
lines changed

src/image.rs

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use crate::error::*;
44
use crate::pal::{f_pixel, PalF, PalIndexRemap, MAX_COLORS, MIN_OPAQUE_A, RGBA};
55
use crate::remap::DitherMapMode;
66
use crate::rows::{DynamicRows, PixelsSource};
7-
use crate::seacow::Pointer;
87
use crate::seacow::RowBitmap;
98
use crate::seacow::SeaCow;
109
use crate::PushInCapacity;
@@ -67,7 +66,9 @@ impl<'pixels> Image<'pixels> {
6766
/// This function is marked as unsafe, because the callback function MUST initialize the entire row (call `write` on every `MaybeUninit` pixel).
6867
///
6968
pub unsafe fn new_fn<F: 'pixels + Fn(&mut [MaybeUninit<RGBA>], usize) + Send + Sync>(attr: &Attributes, convert_row_fn: F, width: usize, height: usize, gamma: f64) -> Result<Self, Error> {
70-
Image::new_internal(attr, PixelsSource::Callback(Box::new(convert_row_fn)), width as u32, height as u32, gamma)
69+
let width = width.try_into().map_err(|_| ValueOutOfRange)?;
70+
let height = height.try_into().map_err(|_| ValueOutOfRange)?;
71+
Image::new_internal(attr, PixelsSource::Callback(Box::new(convert_row_fn)), width, height, gamma)
7172
}
7273

7374
pub(crate) fn free_histogram_inputs(&mut self) {
@@ -325,14 +326,19 @@ impl<'pixels> Image<'pixels> {
325326
}
326327

327328
fn new_stride_internal<'a>(attr: &Attributes, pixels: SeaCow<'a, RGBA>, width: usize, height: usize, stride: usize, gamma: f64) -> Result<Image<'a>, Error> {
328-
let slice = pixels.as_slice();
329-
if slice.len() < (stride * height + width - stride) {
330-
attr.verbose_print(format!("Buffer length is {} bytes, which is not enough for {}×{}×4 RGBA bytes", slice.len()*4, stride, height));
331-
return Err(BufferTooSmall);
332-
}
329+
let width = width.try_into().map_err(|_| ValueOutOfRange)?;
330+
let height = height.try_into().map_err(|_| ValueOutOfRange)?;
331+
let stride = stride.try_into().map_err(|_| ValueOutOfRange)?;
333332

334-
let rows = SeaCow::boxed(slice.chunks(stride).map(|row| Pointer(row.as_ptr())).take(height).collect());
335-
Image::new_internal(attr, PixelsSource::Pixels { rows, pixels: Some(pixels) }, width as u32, height as u32, gamma)
333+
let pixels_len = pixels.as_slice().len();
334+
let pixels_rows = match PixelsSource::for_pixels(pixels, width, height, stride) {
335+
Ok(p) => p,
336+
Err(e) => {
337+
attr.verbose_print(format!("Buffer length is {} bytes, which is not enough for {}×{}×4 RGBA bytes", pixels_len*4, stride, height));
338+
return Err(e)
339+
},
340+
};
341+
Image::new_internal(attr, pixels_rows, width, height, gamma)
336342
}
337343
}
338344

src/rows.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,26 @@ pub(crate) enum PixelsSource<'pixels, 'rows> {
1717
Callback(Box<RowCallback<'rows>>),
1818
}
1919

20+
impl<'pixels, 'rows> PixelsSource<'pixels, 'rows> {
21+
pub(crate) fn for_pixels(pixels: SeaCow<'pixels, RGBA>, width: u32, height: u32, stride: u32) -> Result<Self, Error> {
22+
if stride < width || height == 0 || width == 0 {
23+
return Err(Error::ValueOutOfRange);
24+
}
25+
let stride = stride as usize;
26+
let width = width as usize;
27+
let height = height as usize;
28+
29+
let slice = pixels.as_slice();
30+
let min_area = stride.checked_mul(height).and_then(|a| a.checked_add(width)).ok_or(Error::ValueOutOfRange)? - stride;
31+
if slice.len() < min_area {
32+
return Err(Error::BufferTooSmall);
33+
}
34+
35+
let rows = SeaCow::boxed(slice.chunks(stride).map(|row| Pointer(row.as_ptr())).take(height).collect());
36+
Ok(Self::Pixels { rows, pixels: Some(pixels) })
37+
}
38+
}
39+
2040
pub(crate) struct DynamicRows<'pixels, 'rows> {
2141
pub(crate) width: u32,
2242
pub(crate) height: u32,

0 commit comments

Comments
 (0)