Repository navigation
Description
Context
DESIGN.md F6 and section 9 require one operation budget and checking borrowed Python buffers before copying them. The #677 audit found that Pixmap.from_bytes calls PyBuffer::to_vec and Pixmap.open calls fs::read before any encoded-input size check. The 64,000,000-pixel decoder cap bounds raster dimensions, but a small image can carry arbitrarily large encoded input or metadata. The TIFF palette workaround also copies that input. PyO3 conversions before the binding are excluded from #677; these copies occur inside the binding and need an explicit public input-limit contract.
Goal
Standalone Pixmap loading checks encoded input before allocating its copy or reading the complete file, and reports LimitError with code image_input_size when it exceeds the caller's limit.
Scope
In: add a keyword-only max_size to Pixmap.from_bytes and Pixmap.open, defaulting to the registry's 256 MiB ImageInputSize default, with None as the explicit opt-out; validate it consistently; bound file reads even if the file grows after its metadata is read; share the decode operation budget with any binding-owned encoded-input copy; preserve supported formats, non-contiguous buffers, image resolution, and pixel-count checks.
Out: third-party decoder-internal allocations (existing upstream work), new image formats, and document rendering APIs.
Paths
crates/pyropdf-python/src/pixmap.rs, crates/pyropdf-python/src/pixel_ops.rs, crates/pyropdf-python/src/codecs.rs, python/pyropdf/_core.pyi, Pixmap tests in tests/, docs/en/api/rendering.md and its Japanese generated counterpart if applicable, and evidence/ if a hot path changes.
Acceptance
- A tiny
max_sizerefuses bytes, bytearray, memoryview/non-contiguous buffers, and a file withLimitError.code == "image_input_size"before decoding; normal-size inputs still decode. - The file read itself is bounded, including growth after a metadata check, and preserves file-not-found/permission errors.
-
Noneopts out; invalid limits are rejected without reading or copying input. - TIFF palette handling uses the same input bound/budget; no unchecked extra whole-input copy remains.
- Existing format, metadata, and pixel-limit tests pass; type stubs and API documentation match the callable signatures.
Notes
The registry default is in crates/pyropdf-store/src/budget/code.rs. Reuse the repository's existing bounded-file/buffer patterns and error mapping. Keep the #677 collection-lint expectations precise when modifying the decoder interfaces. No external publication or owner design decision is needed.
Activity
yhay81 commentedon Nov 5, 2026
Claiming on
codex/697-pixmap-input-budgets, based on main2c5ae21. The issue has no open blockers or linked implementation PR. I will add the registry-default encoded-input limit to both Pixmap loaders, check buffers before copying and bound the file read itself, propagate the same budget into the TIFF workaround, and verify refusal codes, supported formats, and API documentation. Main CI for #698 is still running and will continue to be checked; a failure will be investigated before unrelated work proceeds.yhay81 commentedon Nov 5, 2026
Completed on
codex/697-pixmap-input-budgetsin PR #699, squash-merged as70263454ae8cd4eac810b36335146acd238c98bcunder the owner's standing authorization.The loaders check a keyword-only 256 MiB default
max_sizebefore copying/reserving, bound actual file reads, and share the operation budget with the TIFF palette copy. Stubs, generated API docs, and reproducible timing evidence are included inevidence/pixmap-input-budgets/.All eight local checks passed: 7,263 Python tests passed / 697 skipped, plus Ruff, formatting, ty, workspace Clippy, and Rust tests. Pixmap/docs regressions: 386 passed / 8 skipped. All six executed PR checks passed, including Python 3.11, 3.15, and 3.15t on Linux with the pipe and permission cases; documentation deployment is intentionally skipped on PRs. Current-head review checks found no unresolved reviews. Issue closure and claim removal are verified.
Post-merge main CI also passed: https://github.com/yhay81/pyropdf/actions/runs/42073326848. This issue is complete. Work continues on #645; #670 is also ready, and PR #695 / #610 retains its explicit next-minor-release gate.