Skip to content

Commit d828548

Browse files
authored
Improve panic messages when providing invalid buffer sizes to ImageEncoders (#2116)
1 parent 445970c commit d828548

File tree

12 files changed

+90
-24
lines changed

12 files changed

+90
-24
lines changed

src/codecs/avif/encoder.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -98,16 +98,21 @@ impl<W: Write> ImageEncoder for AvifEncoder<W> {
9898
/// The encoder currently requires all data to be RGBA8, it will be converted internally if
9999
/// necessary. When data is suitably aligned, i.e. u16 channels to two bytes, then the
100100
/// conversion may be more efficient.
101+
#[track_caller]
101102
fn write_image(
102103
mut self,
103104
data: &[u8],
104105
width: u32,
105106
height: u32,
106107
color: ColorType,
107108
) -> ImageResult<()> {
109+
let expected_buffer_len =
110+
(width as u64 * height as u64).saturating_mul(color.bytes_per_pixel() as u64);
108111
assert_eq!(
109-
(width as u64 * height as u64).saturating_mul(color.bytes_per_pixel() as u64),
110-
data.len() as u64
112+
expected_buffer_len,
113+
data.len() as u64,
114+
"Invalid buffer length: expected {expected_buffer_len} got {} for {width}x{height} image",
115+
data.len(),
111116
);
112117

113118
self.set_color(color);

src/codecs/bmp/encoder.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ impl<'a, W: Write + 'a> BmpEncoder<'a, W> {
2727
/// # Panics
2828
///
2929
/// Panics if `width * height * c.bytes_per_pixel() != image.len()`.
30+
#[track_caller]
3031
pub fn encode(
3132
&mut self,
3233
image: &[u8],
@@ -43,6 +44,7 @@ impl<'a, W: Write + 'a> BmpEncoder<'a, W> {
4344
/// # Panics
4445
///
4546
/// Panics if `width * height * c.bytes_per_pixel() != image.len()`.
47+
#[track_caller]
4648
pub fn encode_with_palette(
4749
&mut self,
4850
image: &[u8],
@@ -61,9 +63,13 @@ impl<'a, W: Write + 'a> BmpEncoder<'a, W> {
6163
)));
6264
}
6365

66+
let expected_buffer_len =
67+
(width as u64 * height as u64).saturating_mul(c.bytes_per_pixel() as u64);
6468
assert_eq!(
65-
(width as u64 * height as u64).saturating_mul(c.bytes_per_pixel() as u64),
66-
image.len() as u64
69+
expected_buffer_len,
70+
image.len() as u64,
71+
"Invalid buffer length: expected {expected_buffer_len} got {} for {width}x{height} image",
72+
image.len(),
6773
);
6874

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

264270
impl<'a, W: Write> ImageEncoder for BmpEncoder<'a, W> {
271+
#[track_caller]
265272
fn write_image(
266273
mut self,
267274
buf: &[u8],

src/codecs/farbfeld.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -261,10 +261,14 @@ impl<W: Write> FarbfeldEncoder<W> {
261261
/// # Panics
262262
///
263263
/// Panics if `width * height * 8 != data.len()`.
264+
#[track_caller]
264265
pub fn encode(self, data: &[u8], width: u32, height: u32) -> ImageResult<()> {
266+
let expected_buffer_len = (width as u64 * height as u64).saturating_mul(8);
265267
assert_eq!(
266-
(width as u64 * height as u64).saturating_mul(8),
267-
data.len() as u64
268+
expected_buffer_len,
269+
data.len() as u64,
270+
"Invalid buffer length: expected {expected_buffer_len} got {} for {width}x{height} image",
271+
data.len(),
268272
);
269273
self.encode_impl(data, width, height)?;
270274
Ok(())
@@ -286,6 +290,7 @@ impl<W: Write> FarbfeldEncoder<W> {
286290
}
287291

288292
impl<W: Write> ImageEncoder for FarbfeldEncoder<W> {
293+
#[track_caller]
289294
fn write_image(
290295
self,
291296
buf: &[u8],

src/codecs/ico/encoder.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -145,16 +145,21 @@ impl<W: Write> ImageEncoder for IcoEncoder<W> {
145145
/// native endian.
146146
///
147147
/// WARNING: In image 0.23.14 and earlier this method erroneously expected buf to be in big endian.
148+
#[track_caller]
148149
fn write_image(
149150
self,
150151
buf: &[u8],
151152
width: u32,
152153
height: u32,
153154
color_type: ColorType,
154155
) -> ImageResult<()> {
156+
let expected_buffer_len =
157+
(width as u64 * height as u64).saturating_mul(color_type.bytes_per_pixel() as u64);
155158
assert_eq!(
156-
(width as u64 * height as u64).saturating_mul(color_type.bytes_per_pixel() as u64),
157-
buf.len() as u64
159+
expected_buffer_len,
160+
buf.len() as u64,
161+
"Invalid buffer length: expected {expected_buffer_len} got {} for {width}x{height} image",
162+
buf.len(),
158163
);
159164

160165
let image = IcoFrame::as_png(buf, width, height, color_type)?;

src/codecs/jpeg/encoder.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -440,16 +440,21 @@ impl<W: Write> JpegEncoder<W> {
440440
/// # Panics
441441
///
442442
/// Panics if `width * height * color_type.bytes_per_pixel() != image.len()`.
443+
#[track_caller]
443444
pub fn encode(
444445
&mut self,
445446
image: &[u8],
446447
width: u32,
447448
height: u32,
448449
color_type: ColorType,
449450
) -> ImageResult<()> {
451+
let expected_buffer_len =
452+
(width as u64 * height as u64).saturating_mul(color_type.bytes_per_pixel() as u64);
450453
assert_eq!(
451-
(width as u64 * height as u64).saturating_mul(color_type.bytes_per_pixel() as u64),
452-
image.len() as u64
454+
expected_buffer_len,
455+
image.len() as u64,
456+
"Invalid buffer length: expected {expected_buffer_len} got {} for {width}x{height} image",
457+
image.len(),
453458
);
454459

455460
match color_type {
@@ -663,6 +668,7 @@ impl<W: Write> JpegEncoder<W> {
663668
}
664669

665670
impl<W: Write> ImageEncoder for JpegEncoder<W> {
671+
#[track_caller]
666672
fn write_image(
667673
mut self,
668674
buf: &[u8],

src/codecs/openexr.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -352,16 +352,21 @@ where
352352
///
353353
/// Assumes the writer is buffered. In most cases, you should wrap your writer in a `BufWriter`
354354
/// for best performance.
355+
#[track_caller]
355356
fn write_image(
356357
self,
357358
buf: &[u8],
358359
width: u32,
359360
height: u32,
360361
color_type: ColorType,
361362
) -> ImageResult<()> {
363+
let expected_buffer_len =
364+
(width as u64 * height as u64).saturating_mul(color_type.bytes_per_pixel() as u64);
362365
assert_eq!(
363-
(width as u64 * height as u64).saturating_mul(color_type.bytes_per_pixel() as u64),
364-
buf.len() as u64
366+
expected_buffer_len,
367+
buf.len() as u64,
368+
"Invalid buffer length: expected {expected_buffer_len} got {} for {width}x{height} image",
369+
buf.len(),
365370
);
366371

367372
write_buffer(self.0, buf, width, height, color_type)

src/codecs/png.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,7 @@ impl<W: Write> ImageEncoder for PngEncoder<W> {
699699
/// For color types with 16-bit per channel or larger, the contents of `buf` should be in
700700
/// native endian. PngEncoder will automatically convert to big endian as required by the
701701
/// underlying PNG format.
702+
#[track_caller]
702703
fn write_image(
703704
self,
704705
buf: &[u8],
@@ -709,9 +710,13 @@ impl<W: Write> ImageEncoder for PngEncoder<W> {
709710
use byteorder::{BigEndian, ByteOrder, NativeEndian};
710711
use ColorType::*;
711712

713+
let expected_bufffer_len =
714+
(width as u64 * height as u64).saturating_mul(color_type.bytes_per_pixel() as u64);
712715
assert_eq!(
713-
(width as u64 * height as u64).saturating_mul(color_type.bytes_per_pixel() as u64),
714-
buf.len() as u64
716+
expected_bufffer_len,
717+
buf.len() as u64,
718+
"Invalid buffer length: expected {expected_bufffer_len} got {} for {width}x{height} image",
719+
buf.len(),
715720
);
716721

717722
// PNG images are big endian. For 16 bit per channel and larger types,

src/codecs/pnm/encoder.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -289,16 +289,21 @@ impl<W: Write> PnmEncoder<W> {
289289
}
290290

291291
impl<W: Write> ImageEncoder for PnmEncoder<W> {
292+
#[track_caller]
292293
fn write_image(
293294
mut self,
294295
buf: &[u8],
295296
width: u32,
296297
height: u32,
297298
color_type: ColorType,
298299
) -> ImageResult<()> {
300+
let expected_buffer_len =
301+
(width as u64 * height as u64).saturating_mul(color_type.bytes_per_pixel() as u64);
299302
assert_eq!(
300-
(width as u64 * height as u64).saturating_mul(color_type.bytes_per_pixel() as u64),
301-
buf.len() as u64
303+
expected_buffer_len,
304+
buf.len() as u64,
305+
"Invalid buffer length: expected {expected_buffer_len} got {} for {width}x{height} image",
306+
buf.len(),
302307
);
303308

304309
self.encode(buf, width, height, color_type)

src/codecs/qoi.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ impl<W: Write> QoiEncoder<W> {
6363
}
6464

6565
impl<W: Write> ImageEncoder for QoiEncoder<W> {
66+
#[track_caller]
6667
fn write_image(
6768
mut self,
6869
buf: &[u8],
@@ -77,9 +78,13 @@ impl<W: Write> ImageEncoder for QoiEncoder<W> {
7778
)));
7879
}
7980

81+
let expected_buffer_len =
82+
(width as u64 * height as u64).saturating_mul(color_type.bytes_per_pixel() as u64);
8083
assert_eq!(
81-
(width as u64 * height as u64).saturating_mul(color_type.bytes_per_pixel() as u64),
82-
buf.len() as u64
84+
expected_buffer_len,
85+
buf.len() as u64,
86+
"Invalid buffer length: expected {expected_buffer_len} got {} for {width}x{height} image",
87+
buf.len(),
8388
);
8489

8590
// Encode data in QOI

src/codecs/tga/encoder.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -156,16 +156,21 @@ impl<W: Write> TgaEncoder<W> {
156156
/// # Panics
157157
///
158158
/// Panics if `width * height * color_type.bytes_per_pixel() != data.len()`.
159+
#[track_caller]
159160
pub fn encode(
160161
mut self,
161162
buf: &[u8],
162163
width: u32,
163164
height: u32,
164165
color_type: ColorType,
165166
) -> ImageResult<()> {
167+
let expected_buffer_len =
168+
(width as u64 * height as u64).saturating_mul(color_type.bytes_per_pixel() as u64);
166169
assert_eq!(
167-
(width as u64 * height as u64).saturating_mul(color_type.bytes_per_pixel() as u64),
168-
buf.len() as u64
170+
expected_buffer_len,
171+
buf.len() as u64,
172+
"Invalid buffer length: expected {expected_buffer_len} got {} for {width}x{height} image",
173+
buf.len(),
169174
);
170175

171176
// Validate dimensions.
@@ -226,6 +231,7 @@ impl<W: Write> TgaEncoder<W> {
226231
}
227232

228233
impl<W: Write> ImageEncoder for TgaEncoder<W> {
234+
#[track_caller]
229235
fn write_image(
230236
self,
231237
buf: &[u8],

src/codecs/tiff.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -345,10 +345,15 @@ impl<W: Write + Seek> TiffEncoder<W> {
345345
/// # Panics
346346
///
347347
/// Panics if `width * height * color_type.bytes_per_pixel() != data.len()`.
348+
#[track_caller]
348349
pub fn encode(self, data: &[u8], width: u32, height: u32, color: ColorType) -> ImageResult<()> {
350+
let expected_buffer_len =
351+
(width as u64 * height as u64).saturating_mul(color.bytes_per_pixel() as u64);
349352
assert_eq!(
350-
(width as u64 * height as u64).saturating_mul(color.bytes_per_pixel() as u64),
351-
data.len() as u64
353+
expected_buffer_len,
354+
data.len() as u64,
355+
"Invalid buffer length: expected {expected_buffer_len} got {} for {width}x{height} image",
356+
data.len(),
352357
);
353358

354359
let mut encoder =
@@ -394,6 +399,7 @@ impl<W: Write + Seek> TiffEncoder<W> {
394399
}
395400

396401
impl<W: Write + Seek> ImageEncoder for TiffEncoder<W> {
402+
#[track_caller]
397403
fn write_image(
398404
self,
399405
buf: &[u8],

src/codecs/webp/encoder.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -704,10 +704,15 @@ impl<W: Write> WebPEncoder<W> {
704704
/// # Panics
705705
///
706706
/// Panics if `width * height * color.bytes_per_pixel() != data.len()`.
707+
#[track_caller]
707708
pub fn encode(self, data: &[u8], width: u32, height: u32, color: ColorType) -> ImageResult<()> {
709+
let expected_buffer_len =
710+
(width as u64 * height as u64).saturating_mul(color.bytes_per_pixel() as u64);
708711
assert_eq!(
709-
(width as u64 * height as u64).saturating_mul(color.bytes_per_pixel() as u64),
710-
data.len() as u64
712+
expected_buffer_len,
713+
data.len() as u64,
714+
"Invalid buffer length: expected {expected_buffer_len} got {} for {width}x{height} image",
715+
data.len(),
711716
);
712717

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

724729
impl<W: Write> ImageEncoder for WebPEncoder<W> {
730+
#[track_caller]
725731
fn write_image(
726732
self,
727733
buf: &[u8],

0 commit comments

Comments
 (0)