Commit Graph
7 Commits
Author SHA1 Message Date
wstock a2bc0d3570 lopdf: a rebuilt trailer's /Root must match its generation (#2365 review)
usable() and is_catalog() checked the object number only, so a later stream
with /Root 1 1 R outranked the trailer naming 1 0 R; get_offset then found no
such object and Document Properties lost the catalog. cos resolves by number
alone, so its rank needs no change.

Test: inspect::tests::rebuilt_file_prefers_a_trailer_whose_root_is_the_catalog
2026-10-18 16:05:33 +00:00
wstock d75d440ad9 lopdf: a rebuild prefers a trailer whose /Root is the catalog (#2365 review)
The mirror of the cos change for render::inspect: a later cross-reference
stream whose /Root points at /Info replaced the earlier trailer, and Document
Properties lost the catalog. A candidate whose /Root is /Type /Catalog or has
/Pages now wins; another dictionary is still taken when nothing better is
there (FDF).

Test: inspect::tests::rebuilt_file_prefers_a_trailer_whose_root_is_the_catalog
2026-10-18 15:23:38 +00:00
wstock 1c12615032 lopdf: a rebuild takes the trailer from a cross-reference stream (PdfCraft patch 6)
Document Properties are read through the inspector: the lazy cos
reader refuses a file that needed repair, and lopdf's rebuild only
looked for the trailer keyword, so a file whose only trailer is a
cross-reference stream failed to load there and every field showed
empty. lopdf's rebuild now takes a /Type /XRef stream dictionary as
the trailer, the latest in the file winning as a later trailer
keyword would.
2026-10-18 11:25:48 +00:00
Ikki NishiharaandClaude Sonnet 5.5 559859ca61 lopdf: bound object lookups through compressed containers and object-stream members (#771)
A compressed object's container was resolved with a fresh cycle set and
without checking that it is an ordinary object, and indirect /Length
chains had no depth limit, so self-containing or chained lookups
overflowed the stack. Pass the caller's set on, require an in-file
container and cap the chain at 16 lookups. Object-stream members were
each parsed to the end of the decoded stream, so repeated or nested
offsets kept many copies of one large object: parse each member within
its own extent and skip repeated offsets.

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-10 15:51:25 -04:00
8c90a8d1fd M2: bound lopdf predictor scratch to available samples (#470)
* M2: bound lopdf predictor scratch to available samples

Return empty PNG predictor frames before allocating row buffers. Reject
overflowing packed TIFF row dimensions and bound component scratch to the
samples present in the input, aligning with the existing lopdf#589 fix.

Cover hostile dimensions and valid packed rows with synthetic regressions
and record the vendored patch and its upstream proposal.

Co-Authored-By: OpenAI Codex <codex@openai.com>

* Keep main's M1 roadmap row after merging main

---------

Co-authored-by: OpenAI Codex <codex@openai.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-09 09:21:21 -04:00
Brandon ThomasandClaude Opus 5.5 d3db99818f Rename PrintCraft to PdfCraft (#174)
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>
2026-10-07 16:03:57 -04:00
Brandon ThomasandClaude Opus 5.5 1449b71a19 Never crash: bound the allocations behind the nightly fuzz runner's out-of-memory deaths
Fuzzed inputs drove one check-one process to 2-6 GB (the 16 GB CI runner
running two of them was killed every night). Three causes, each with a test:
- lopdf (bootstrap inspector) sized PNG predictor rows from /Columns before
  reading data: /Columns 4294967295 allocated two 4 GiB rows. Vendored lopdf
  0.45.0 refuses rows longer than the data (and uses saturating row widths);
  its load-time stream decoding also gets a 256 MiB limit (it had none).
- hayro sized a tiling pattern's cell pixmap from /XStep x scale, bounded only
  by u16: a step far beyond /BBox allocated 2 GB. The vendored patch keeps
  the cell within 3000 px a side, lowering the resolution instead.
- cos decoded cross-reference streams up to the general 1 GiB limit; they now
  stop at what 8,388,607 objects' rows can hold (~200 MB at most), and the
  section is reconstructed (logged) instead.

On the nightly's seed (41) the worst captured input fell from 6.2 GB to 6 MB,
and a 300 s fuzz run had no process above 300 MB (before: many at 2-5 GB).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 17:59:25 -04:00