Files
lightcraft/crates/tiff
Alex ChambersandClaude Opus 5.5 8feda7a997 LR-IMP-FORMATS: the TIFF reader's next-IFD pointer no longer overflows on huge BigTIFF entry counts
Pre-existing on main. The reader computed the position of a directory's next-IFD pointer before it
checked that every declared entry had been read: a saturating multiplication of the declared count,
then an unchecked addition. A 44-byte BigTIFF declaring u64::MAX entries therefore panicked with
overflow checks on. The position is now computed only for a directory read whole, with checked
arithmetic.

32-bit note: the same guard compared the counts after narrowing the declared one to usize, so on
wasm32 a BigTIFF declaring 4,294,967,297 entries but holding one passed for a whole directory and its
next pointer was followed. The counts now compare as 64-bit numbers (reads_every_entry). On wasm32 the
old comparison followed all six malformed test chains and the new one follows none; 64-bit results
are unchanged for every directory whose count is read whole.

Regression tests (crates/tiff/src/reader.rs):
a_bigtiff_directory_declaring_u64_max_entries_parses_without_overflow, which panicked before;
a_bigtiff_count_past_u32_max_never_follows_the_next_pointer (the whole chain, on every target); and
only_a_directory_read_whole_has_a_next_pointer (the comparison itself, on every target).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 08:40:42 +02:00
..
2026-09-30 11:00:48 -04:00

lightcraft-tiff (L0)

TIFF / IFD reader and writer. Used by lightcraft-raw (DNG, CR2, NEF, ARW…), lightcraft-meta (Exif) and later the TIFF/DNG exporters.

Features

  • Classic TIFF and BigTIFF, little- and big-endian (II/MM). Also accepts the TIFF-like magic numbers of some raw formats (ORF IIRO/IIRS, RW2 IIU) when ParseOptions::accept_raw_magic is set (default).
  • Every field type: BYTE, ASCII, SHORT, LONG, RATIONAL, SBYTE, UNDEFINED, SSHORT, SLONG, SRATIONAL, FLOAT, DOUBLE, IFD, LONG8, SLONG8, IFD8.
  • IFD chain + SubIFDs (330) + Exif (34665) / GPS (34853) / Interoperability (40965) pointer IFDs, resolved into a tree (Ifd::sub_ifds, exif, gps, interop). Entry::offset records the absolute position of each value (needed for maker notes and embedded blobs).
  • parse_ifd_at(data, offset, order, base, bigtiff, opts) parses an IFD whose offsets are relative to an arbitrary base; makernote::parse_makernote knows the header / byte-order / offset-base conventions of Canon, Nikon (types 1 and 3), Sony, Fujifilm, Olympus (old and new), Panasonic and Pentax notes.
  • image::ImageInfo — width/height, bits, samples, compression, photometric, planar config, predictor, sample format and the strip or tile chunk list (chunks(), chunk_bytes()); missing byte counts are inferred.
  • directory_entries, entry_span, ParseOptions::budget_for and decode_value are the reader's own rules (directory layout and entry limit, which entries it reads, its value budget, value decoding), for callers that must select entries exactly as parse_ifd_at would without decoding the whole directory (lightcraft-raw's Sony SR2Private lookup).
  • TiffWriter writes IFD chains with strips or tiles, SubIFDs and pointer IFDs, in either byte order, classic or BigTIFF; writer::rational / srational approximate floats as rationals.

Robustness

The reader never panics on malformed input (proptests feed random and mutated files): offsets are bounds-checked; out-of-range or unknown-type entries are skipped; IFD loops are detected; IFD count, nesting depth and entries per IFD are limited; a next-IFD pointer is followed only when every declared entry was read, with the counts compared as 64-bit numbers (a BigTIFF declaring 4,294,967,297 entries but holding one can't pass for a whole directory on a 32-bit target); the total bytes of decoded values are capped at 8 × input + 1 MiB so a file cannot make us allocate far more than its own size.

Sources

Public specifications only: TIFF 6.0 (Adobe, 1992), the TIFF 6.0 supplements (IFD type, SubIFDs), the BigTIFF format description (AWare Systems), Adobe DNG Specification 1.7 (tag numbers), CIPA DC-008 Exif 2.32, and the ExifTool tag-name documentation (maker-note header conventions, prose only). No third-party code was consulted.