Clearing the pixels of a partly covered image decoded its stream with
the global 1 GiB allowance and only then cut it to the raster length its
Width, Height and bit depth declare. A small Flate stream could make
every such image allocate and inflate far more than it can use. Decoding
now stops at twice the raster plus a byte per row (filter-chain and
predictor overhead) and a little slack; an image past that is removed
whole, as an undecodable one already is.
* fix(redact): size image clearing with checked arithmetic (#2177)
An ICCBased image's /N comes from the file and was cast with `as usize`, then multiplied
unchecked into the row size. /N 2^60 overflowed it (debug: overflow panic; release: a zero row
emptied the buffer and the write loop indexed out of bounds), and a negative /N wrapped.
/N is now limited to 1, 3 or 4 (ISO 32000-2 §8.6.5.5), every size product is checked, and the
pixel writes use `get_mut`. An image that fails any of these is refused, and the caller already
removes it whole (fail-closed). Regression test covers /N 2^60, -1 and 2.
* redact tests: pass the pixel array by value (clippy needless_borrows_for_generic_args)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The app, crates, binaries, bundle id, packaging, icons, screenshots and docs are now
PdfCraft / pdfcraft (repo storytold/pdfcraft). On first launch the desktop app moves the
PrintCraft settings and crash-recovery folders to the new name, and both apps read settings
saved under the old storage key, so upgrades keep recent files, preferences and unsaved work.
The signing test fixtures keep their PrintCraft subject names (they are binary).
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>