Skip to content

Resolve references to missing objects as null in the object reader - #568

Merged
Velli20 merged 1 commit into
mainfrom
resolve-missing-objects-to-null
Oct 13, 2026
Merged

Velli20 merged 1 commit into
mainfrom
resolve-missing-objects-to-null

Conversation

@Velli20

@Velli20 Velli20 commented Oct 13, 2026

Copy link
Copy Markdown
Owner

Summary

ISO 32000 §7.3.10 treats a reference to a nonexistent object as null. The object reader raised MissingObject instead. Decoders worked around that one by one with is_absent checks, for page /Contents and /Annots among others. Every other optional read failed outright instead of returning None.

  • Reader: ReadSession::load_object resolves an absent object to Null. ObjectReadError::MissingObject is removed. optional / optional_shared now return None for these references through the existing Option<T> null handling.
  • Object collection: ObjectCollection::insert decodes stream filters while objects are still loading, where a missing object may be defined later. It now reads through a private LoadedObjects source that fails on unloaded objects, so those streams stay encoded and are decoded later, as before.
  • Cleanup: the /Contents and /Annots workarounds are gone, and is_absent is now a plain null check.

Required reads of a missing object still fail, now with a TypeMismatch that reports Null. Some documents that failed to read before may now read; the conformance comment on this PR will show any changes.

Test plan

  • cargo fmt --check, cargo clippy --all --workspace
  • cargo test --workspace (Skia crates excluded locally); includes insert_preserves_encoded_state_when_filter_dependencies_are_unresolved
  • Conformance read comparison on this PR

🤖 Generated with Claude Code

ISO 32000 §7.3.10 treats a reference to a nonexistent object as null, but
the reader raised MissingObject. Decoders worked around it one by one with
is_absent checks, and every other optional read failed instead of
yielding None.

The reader now resolves an absent object to null and MissingObject is
removed. ObjectCollection::insert decodes stream filters while objects
are still loading, where a missing object may be defined later, so it
reads through a source that fails on unloaded objects and keeps such
streams encoded as before.

The /Contents and /Annots workarounds are removed and is_absent becomes
a plain null check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Conformance reads

Documents that Safe-PDF reads differently from the base commit, compared with PDFium. A read
regresses when Safe-PDF fails to open a document it opened before, crashes or times out, or
counts a different number of pages than PDFium.

pdf.js corpus

1008 documents compared with 066c847: 1 read worse, 0 read better.

Regressions

Document Base This pull request
issue17190_1 read, 1 page timeout: time limit exceeded (stage safe-read)

840 documents of the PDFium corpus read as on 066c847.

Details are in the job summaries of the workflow run. Rerun a case locally with
cargo conformance run --corpus <corpus> --read-only --case <id>.

@Velli20
Velli20 merged commit b5ace5c into main Oct 13, 2026
10 checks passed
@Velli20
Velli20 deleted the resolve-missing-objects-to-null branch October 13, 2026 19:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant