This commit is contained in:
Brandon Thomas committed 2026-10-14 01:38:54 -04:00
commit c8f1ecd4d3
2 files changed
+38 -3

No files matched your search

+4 -3
View File
@@ -140,9 +140,10 @@ impl<'a> Ctx<'a> {
}
entries.sort_by_key(|e| e.tag);
entries.dedup_by_key(|e| e.tag);
let next_pos = table + (n as usize).saturating_mul(entry_size);
let next = if n as usize == n_read {
match self.read_off(next_pos) {
// the next-IFD offset follows the whole table, so only a table read in full has one: a count far past the
// file (a BigTIFF's is 64-bit) must not reach the arithmetic (issue #1516)
let next = if n == n_read as u64 {
match n_read.checked_mul(entry_size).and_then(|len| table.checked_add(len)).and_then(|p| self.read_off(p)) {
Some(0) | None => 0,
Some(v) => base.checked_add(v).unwrap_or(0),
}
+34
View File
@@ -393,3 +393,37 @@ proptest! {
prop_assert_eq!(t.ifds[0].f64s(501).unwrap().len(), v.len());
}
}
/// A BigTIFF whose IFD says it has an enormous number of entries, with one readable, computed where the next-IFD
/// offset would be from the advertised count: an add overflow, a panic in builds with overflow checks (issue
/// #1516). The readable entry is kept and there is no next IFD; complete chains still link.
#[test]
fn bigtiff_with_an_enormous_entry_count_does_not_panic() {
for order in ORDERS {
for count in [u64::MAX, 1 << 62, 2] {
// little-endian bytes, reversed for big-endian files
let e = |le: &[u8]| -> Vec<u8> { if order == ByteOrder::Little { le.to_vec() } else { le.iter().rev().copied().collect() } };
let mut f = if order == ByteOrder::Little { b"II".to_vec() } else { b"MM".to_vec() };
for part in [e(&43u16.to_le_bytes()), e(&8u16.to_le_bytes()), e(&0u16.to_le_bytes()), e(&16u64.to_le_bytes()), e(&count.to_le_bytes())] {
f.extend(part);
}
// one entry: ImageWidth, LONG, 1 value (inline in the 8-byte field)
for part in [e(&tags::IMAGE_WIDTH.to_le_bytes()), e(&4u16.to_le_bytes()), e(&1u64.to_le_bytes()), e(&640u32.to_le_bytes())] {
f.extend(part);
}
f.extend([0; 4]);
let (ifd, next) = parse_ifd_at(&f, 16, order, 0, true, &ParseOptions::default()).unwrap();
assert_eq!(ifd.value(tags::IMAGE_WIDTH), Some(&Value::Long(vec![640])), "{order:?} {count}");
assert_eq!(next, 0, "{order:?} {count}");
let t = Tiff::parse(&f).unwrap();
assert_eq!(t.ifds.len(), 1);
}
// a complete chain of two IFDs still links
let mut a = IfdBuilder::new();
a.set(1000, Value::Short(vec![1]));
let mut b = IfdBuilder::new();
b.set(1000, Value::Short(vec![2]));
let t = Tiff::parse(&TiffWriter::new(order, true).write(&[a, b]).unwrap()).unwrap();
assert_eq!(t.ifds.len(), 2, "{order:?}");
}
}