Skip to content

Commit

Permalink
Improve panic messages when providing invalid buffer sizes to `ImageE…
Browse files Browse the repository at this point in the history
…ncoder`s (#2116)
  • Loading branch information
MrGunflame authored Feb 2, 2024
1 parent 445970c commit d828548
Show file tree
Hide file tree
Showing 12 changed files with 90 additions and 24 deletions.
9 changes: 7 additions & 2 deletions src/codecs/avif/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,16 +98,21 @@ impl<W: Write> ImageEncoder for AvifEncoder<W> {
/// The encoder currently requires all data to be RGBA8, it will be converted internally if
/// necessary. When data is suitably aligned, i.e. u16 channels to two bytes, then the
/// conversion may be more efficient.
#[track_caller]
fn write_image(
mut self,
data: &[u8],
width: u32,
height: u32,
color: ColorType,
) -> ImageResult<()> {
let expected_buffer_len =
(width as u64 * height as u64).saturating_mul(color.bytes_per_pixel() as u64);
assert_eq!(
(width as u64 * height as u64).saturating_mul(color.bytes_per_pixel() as u64),
data.len() as u64
expected_buffer_len,
data.len() as u64,
"Invalid buffer length: expected {expected_buffer_len} got {} for {width}x{height} image",
data.len(),
);

self.set_color(color);
Expand Down
11 changes: 9 additions & 2 deletions src/codecs/bmp/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ impl<'a, W: Write + 'a> BmpEncoder<'a, W> {
/// # Panics
///
/// Panics if `width * height * c.bytes_per_pixel() != image.len()`.
#[track_caller]
pub fn encode(
&mut self,
image: &[u8],
Expand All @@ -43,6 +44,7 @@ impl<'a, W: Write + 'a> BmpEncoder<'a, W> {
/// # Panics
///
/// Panics if `width * height * c.bytes_per_pixel() != image.len()`.
#[track_caller]
pub fn encode_with_palette(
&mut self,
image: &[u8],
Expand All @@ -61,9 +63,13 @@ impl<'a, W: Write + 'a> BmpEncoder<'a, W> {
)));
}

let expected_buffer_len =
(width as u64 * height as u64).saturating_mul(c.bytes_per_pixel() as u64);
assert_eq!(
(width as u64 * height as u64).saturating_mul(c.bytes_per_pixel() as u64),
image.len() as u64
expected_buffer_len,
image.len() as u64,
"Invalid buffer length: expected {expected_buffer_len} got {} for {width}x{height} image",
image.len(),
);

let bmp_header_size = BITMAPFILEHEADER_SIZE;
Expand Down Expand Up @@ -262,6 +268,7 @@ impl<'a, W: Write + 'a> BmpEncoder<'a, W> {
}

impl<'a, W: Write> ImageEncoder for BmpEncoder<'a, W> {
#[track_caller]
fn write_image(
mut self,
buf: &[u8],
Expand Down
9 changes: 7 additions & 2 deletions src/codecs/farbfeld.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,10 +261,14 @@ impl<W: Write> FarbfeldEncoder<W> {
/// # Panics
///
/// Panics if `width * height * 8 != data.len()`.
#[track_caller]
pub fn encode(self, data: &[u8], width: u32, height: u32) -> ImageResult<()> {
let expected_buffer_len = (width as u64 * height as u64).saturating_mul(8);
assert_eq!(
(width as u64 * height as u64).saturating_mul(8),
data.len() as u64
expected_buffer_len,
data.len() as u64,
"Invalid buffer length: expected {expected_buffer_len} got {} for {width}x{height} image",
data.len(),
);
self.encode_impl(data, width, height)?;
Ok(())
Expand All @@ -286,6 +290,7 @@ impl<W: Write> FarbfeldEncoder<W> {
}

impl<W: Write> ImageEncoder for FarbfeldEncoder<W> {
#[track_caller]
fn write_image(
self,
buf: &[u8],
Expand Down
9 changes: 7 additions & 2 deletions src/codecs/ico/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,16 +145,21 @@ impl<W: Write> ImageEncoder for IcoEncoder<W> {
/// native endian.
///
/// WARNING: In image 0.23.14 and earlier this method erroneously expected buf to be in big endian.
#[track_caller]
fn write_image(
self,
buf: &[u8],
width: u32,
height: u32,
color_type: ColorType,
) -> ImageResult<()> {
let expected_buffer_len =
(width as u64 * height as u64).saturating_mul(color_type.bytes_per_pixel() as u64);
assert_eq!(
(width as u64 * height as u64).saturating_mul(color_type.bytes_per_pixel() as u64),
buf.len() as u64
expected_buffer_len,
buf.len() as u64,
"Invalid buffer length: expected {expected_buffer_len} got {} for {width}x{height} image",
buf.len(),
);

let image = IcoFrame::as_png(buf, width, height, color_type)?;
Expand Down
10 changes: 8 additions & 2 deletions src/codecs/jpeg/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -440,16 +440,21 @@ impl<W: Write> JpegEncoder<W> {
/// # Panics
///
/// Panics if `width * height * color_type.bytes_per_pixel() != image.len()`.
#[track_caller]
pub fn encode(
&mut self,
image: &[u8],
width: u32,
height: u32,
color_type: ColorType,
) -> ImageResult<()> {
let expected_buffer_len =
(width as u64 * height as u64).saturating_mul(color_type.bytes_per_pixel() as u64);
assert_eq!(
(width as u64 * height as u64).saturating_mul(color_type.bytes_per_pixel() as u64),
image.len() as u64
expected_buffer_len,
image.len() as u64,
"Invalid buffer length: expected {expected_buffer_len} got {} for {width}x{height} image",
image.len(),
);

match color_type {
Expand Down Expand Up @@ -663,6 +668,7 @@ impl<W: Write> JpegEncoder<W> {
}

impl<W: Write> ImageEncoder for JpegEncoder<W> {
#[track_caller]
fn write_image(
mut self,
buf: &[u8],
Expand Down
9 changes: 7 additions & 2 deletions src/codecs/openexr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -352,16 +352,21 @@ where
///
/// Assumes the writer is buffered. In most cases, you should wrap your writer in a `BufWriter`
/// for best performance.
#[track_caller]
fn write_image(
self,
buf: &[u8],
width: u32,
height: u32,
color_type: ColorType,
) -> ImageResult<()> {
let expected_buffer_len =
(width as u64 * height as u64).saturating_mul(color_type.bytes_per_pixel() as u64);
assert_eq!(
(width as u64 * height as u64).saturating_mul(color_type.bytes_per_pixel() as u64),
buf.len() as u64
expected_buffer_len,
buf.len() as u64,
"Invalid buffer length: expected {expected_buffer_len} got {} for {width}x{height} image",
buf.len(),
);

write_buffer(self.0, buf, width, height, color_type)
Expand Down
9 changes: 7 additions & 2 deletions src/codecs/png.rs
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,7 @@ impl<W: Write> ImageEncoder for PngEncoder<W> {
/// For color types with 16-bit per channel or larger, the contents of `buf` should be in
/// native endian. PngEncoder will automatically convert to big endian as required by the
/// underlying PNG format.
#[track_caller]
fn write_image(
self,
buf: &[u8],
Expand All @@ -709,9 +710,13 @@ impl<W: Write> ImageEncoder for PngEncoder<W> {
use byteorder::{BigEndian, ByteOrder, NativeEndian};
use ColorType::*;

let expected_bufffer_len =
(width as u64 * height as u64).saturating_mul(color_type.bytes_per_pixel() as u64);
assert_eq!(
(width as u64 * height as u64).saturating_mul(color_type.bytes_per_pixel() as u64),
buf.len() as u64
expected_bufffer_len,
buf.len() as u64,
"Invalid buffer length: expected {expected_bufffer_len} got {} for {width}x{height} image",
buf.len(),
);

// PNG images are big endian. For 16 bit per channel and larger types,
Expand Down
9 changes: 7 additions & 2 deletions src/codecs/pnm/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,16 +289,21 @@ impl<W: Write> PnmEncoder<W> {
}

impl<W: Write> ImageEncoder for PnmEncoder<W> {
#[track_caller]
fn write_image(
mut self,
buf: &[u8],
width: u32,
height: u32,
color_type: ColorType,
) -> ImageResult<()> {
let expected_buffer_len =
(width as u64 * height as u64).saturating_mul(color_type.bytes_per_pixel() as u64);
assert_eq!(
(width as u64 * height as u64).saturating_mul(color_type.bytes_per_pixel() as u64),
buf.len() as u64
expected_buffer_len,
buf.len() as u64,
"Invalid buffer length: expected {expected_buffer_len} got {} for {width}x{height} image",
buf.len(),
);

self.encode(buf, width, height, color_type)
Expand Down
9 changes: 7 additions & 2 deletions src/codecs/qoi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ impl<W: Write> QoiEncoder<W> {
}

impl<W: Write> ImageEncoder for QoiEncoder<W> {
#[track_caller]
fn write_image(
mut self,
buf: &[u8],
Expand All @@ -77,9 +78,13 @@ impl<W: Write> ImageEncoder for QoiEncoder<W> {
)));
}

let expected_buffer_len =
(width as u64 * height as u64).saturating_mul(color_type.bytes_per_pixel() as u64);
assert_eq!(
(width as u64 * height as u64).saturating_mul(color_type.bytes_per_pixel() as u64),
buf.len() as u64
expected_buffer_len,
buf.len() as u64,
"Invalid buffer length: expected {expected_buffer_len} got {} for {width}x{height} image",
buf.len(),
);

// Encode data in QOI
Expand Down
10 changes: 8 additions & 2 deletions src/codecs/tga/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,16 +156,21 @@ impl<W: Write> TgaEncoder<W> {
/// # Panics
///
/// Panics if `width * height * color_type.bytes_per_pixel() != data.len()`.
#[track_caller]
pub fn encode(
mut self,
buf: &[u8],
width: u32,
height: u32,
color_type: ColorType,
) -> ImageResult<()> {
let expected_buffer_len =
(width as u64 * height as u64).saturating_mul(color_type.bytes_per_pixel() as u64);
assert_eq!(
(width as u64 * height as u64).saturating_mul(color_type.bytes_per_pixel() as u64),
buf.len() as u64
expected_buffer_len,
buf.len() as u64,
"Invalid buffer length: expected {expected_buffer_len} got {} for {width}x{height} image",
buf.len(),
);

// Validate dimensions.
Expand Down Expand Up @@ -226,6 +231,7 @@ impl<W: Write> TgaEncoder<W> {
}

impl<W: Write> ImageEncoder for TgaEncoder<W> {
#[track_caller]
fn write_image(
self,
buf: &[u8],
Expand Down
10 changes: 8 additions & 2 deletions src/codecs/tiff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -345,10 +345,15 @@ impl<W: Write + Seek> TiffEncoder<W> {
/// # Panics
///
/// Panics if `width * height * color_type.bytes_per_pixel() != data.len()`.
#[track_caller]
pub fn encode(self, data: &[u8], width: u32, height: u32, color: ColorType) -> ImageResult<()> {
let expected_buffer_len =
(width as u64 * height as u64).saturating_mul(color.bytes_per_pixel() as u64);
assert_eq!(
(width as u64 * height as u64).saturating_mul(color.bytes_per_pixel() as u64),
data.len() as u64
expected_buffer_len,
data.len() as u64,
"Invalid buffer length: expected {expected_buffer_len} got {} for {width}x{height} image",
data.len(),
);

let mut encoder =
Expand Down Expand Up @@ -394,6 +399,7 @@ impl<W: Write + Seek> TiffEncoder<W> {
}

impl<W: Write + Seek> ImageEncoder for TiffEncoder<W> {
#[track_caller]
fn write_image(
self,
buf: &[u8],
Expand Down
10 changes: 8 additions & 2 deletions src/codecs/webp/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -704,10 +704,15 @@ impl<W: Write> WebPEncoder<W> {
/// # Panics
///
/// Panics if `width * height * color.bytes_per_pixel() != data.len()`.
#[track_caller]
pub fn encode(self, data: &[u8], width: u32, height: u32, color: ColorType) -> ImageResult<()> {
let expected_buffer_len =
(width as u64 * height as u64).saturating_mul(color.bytes_per_pixel() as u64);
assert_eq!(
(width as u64 * height as u64).saturating_mul(color.bytes_per_pixel() as u64),
data.len() as u64
expected_buffer_len,
data.len() as u64,
"Invalid buffer length: expected {expected_buffer_len} got {} for {width}x{height} image",
data.len(),
);

if let WebPQuality(Quality::Lossless) = self.quality {
Expand All @@ -722,6 +727,7 @@ impl<W: Write> WebPEncoder<W> {
}

impl<W: Write> ImageEncoder for WebPEncoder<W> {
#[track_caller]
fn write_image(
self,
buf: &[u8],
Expand Down

0 comments on commit d828548

Please sign in to comment.