Skip to content

Bound encoded Pixmap input before copying buffers or reading files #697

Closed

Description

@yhay81

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_size refuses bytes, bytearray, memoryview/non-contiguous buffers, and a file with LimitError.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.
  • None opts 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

  1. added
    area:pythoncrates/pyropdf-python and python/pyropdf: the binding and the Python API
    on Nov 5, 2026
  2. added
    in-progressClaimed; the latest comment names the branch
    on Nov 5, 2026
  3. yhay81 commented on Nov 5, 2026

    @yhay81
    OwnerAuthor

    Claiming on codex/697-pixmap-input-budgets, based on main 2c5ae21. 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.

  4. yhay81 commented on Nov 5, 2026

    @yhay81
    OwnerAuthor

    Completed on codex/697-pixmap-input-budgets in PR #699, squash-merged as 70263454ae8cd4eac810b36335146acd238c98bc under the owner's standing authorization.

    The loaders check a keyword-only 256 MiB default max_size before 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 in evidence/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.

  5. removed
    in-progressClaimed; the latest comment names the branch
    on Nov 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:pythoncrates/pyropdf-python and python/pyropdf: the binding and the Python API

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions