I ran into this through the image crate while reading an ICC profile from a small TIFF. The profile is present in the file, but icc_profile() returns Ok(None).
At the tiff layer, reading an IFD tag fails with LimitsExceeded whenever the tag is larger than decoding_buffer_size, even if it is well below ifd_value_size. This reproduces on current main (e27f6fe).
Here is a small reproducer. It writes an 8x8 RGB image (192 bytes of pixel data) with a 16 KiB ICC profile, then sets decoding_buffer_size to the image size. ifd_value_size is left at its default of 1 MiB.
use std::io::Cursor;
use tiff::decoder::{Decoder, Limits};
use tiff::encoder::{colortype, TiffEncoder};
use tiff::tags::Tag;
fn main() {
const WIDTH: u32 = 8;
const HEIGHT: u32 = 8;
const IMAGE_BYTES: usize = (WIDTH * HEIGHT * 3) as usize;
let icc: Vec<u8> = (0..16 * 1024).map(|i| i as u8).collect();
let mut file = Cursor::new(Vec::new());
{
let mut encoder = TiffEncoder::new(&mut file).unwrap();
let mut image = encoder
.new_image::<colortype::RGB8>(WIDTH, HEIGHT)
.unwrap();
image
.encoder()
.write_tag(Tag::IccProfile, &icc[..])
.unwrap();
image.write_data(&[0; IMAGE_BYTES]).unwrap();
}
let mut limits = Limits::default();
limits.decoding_buffer_size = IMAGE_BYTES;
file.set_position(0);
let mut decoder = Decoder::open(&mut file).unwrap().with_limits(limits);
decoder.next_image().unwrap();
let result = decoder
.current_ifd()
.get_tag_u8_vec(Tag::IccProfile);
println!("{result:?}");
}
The result is:
I would expect this read to succeed because the 16 KiB value fits within ifd_value_size. find_tag_buf fails in the same way.
The two checks that appear to cause this are in src/decoder/ifd.rs:
Entry::buffer_with_capacity checks the raw tag byte count against decoding_buffer_size.
Entry::vec_with_capacity checks the expanded Value representation against decoding_buffer_size.
The first check looks like it should use ifd_value_size, whose documentation describes it as the maximum size of a single IFD value. For the expanded Value allocation, intermediate_buffer_size seems like the matching limit; using ifd_value_size there would reduce the effective limit by size_of::<Value>() compared with the current behavior.
This matters for callers that size decoding_buffer_size from the decoded image. A perfectly ordinary metadata value can be larger than the pixels of a thumbnail or other small image, so the tag becomes unreadable even though the configured IFD limit allows it.
I ran into this through the
imagecrate while reading an ICC profile from a small TIFF. The profile is present in the file, buticc_profile()returnsOk(None).At the
tifflayer, reading an IFD tag fails withLimitsExceededwhenever the tag is larger thandecoding_buffer_size, even if it is well belowifd_value_size. This reproduces on current main (e27f6fe).Here is a small reproducer. It writes an 8x8 RGB image (192 bytes of pixel data) with a 16 KiB ICC profile, then sets
decoding_buffer_sizeto the image size.ifd_value_sizeis left at its default of 1 MiB.The result is:
I would expect this read to succeed because the 16 KiB value fits within
ifd_value_size.find_tag_buffails in the same way.The two checks that appear to cause this are in
src/decoder/ifd.rs:Entry::buffer_with_capacitychecks the raw tag byte count againstdecoding_buffer_size.Entry::vec_with_capacitychecks the expandedValuerepresentation againstdecoding_buffer_size.The first check looks like it should use
ifd_value_size, whose documentation describes it as the maximum size of a single IFD value. For the expandedValueallocation,intermediate_buffer_sizeseems like the matching limit; usingifd_value_sizethere would reduce the effective limit bysize_of::<Value>()compared with the current behavior.This matters for callers that size
decoding_buffer_sizefrom the decoded image. A perfectly ordinary metadata value can be larger than the pixels of a thumbnail or other small image, so the tag becomes unreadable even though the configured IFD limit allows it.