mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-11-10 13:01:29 +00:00
resource_ops parsed the content and each form it follows whole before checking its 2,000,000-operator limit, and content_draws parsed whole streams with no limit at all. A parsed operator takes about 120 bytes, and a form of `n` operators outside the mark cost 78 to 138 bytes of memory per byte of content. Measured as the growth of the process's peak: 629 MiB at 8 MiB, 1,253 MiB at 16 MiB and 4,415 MiB at 32 MiB, so tens of GiB at the 256 MiB the page's allowance admits, from a file of a few hundred KiB. The page's check of what it still draws (prune), added in this branch, reads such forms on pages with no fonts or properties too. On main the font and property cleanups read them, and the unlinking check (content_draws) on any page that shares a dictionary with a removed image, so the content_draws half fixes what main does too. Both now read with pdfcraft_content::ops, one operator at a time. resource_ops holds at most one past its limit, and content_draws holds no operators, as it only looks for Do. Measured as the peak resident memory of the whole process (dev profile): the page's check over a form of 8, 16 and 64 MiB of `n` takes 311, 327 and 422 MiB, and the unlinking check over one of 16 MiB takes 69 MiB, against 1,269 before (2,527 MiB at 32 MiB). This bounds the operators held, not their operands: the parser still holds the operands that no operator ends, so content of operands alone costs about 30 bytes per byte (974 MiB for 32 MiB of `0`). Bounding those is pdfcraft-content's, for every reader of content. It also drops resource_ops' check that it followed no more than 2,000,000 forms. Each form it follows is a Do among the operators it holds, which the operator limit already bounds, so that check could never fail; cargo-mutants found it untested. Test the_forms_followed_through_resources_are_read_one_operator_at_a_time (tests/operator_memory.rs, a binary of its own) measures how much the process's peak grows over 32 MiB of `n` operators through each check, on Linux, and fails with either read reverted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY