Skip to content

IndexOutOfBoundsException in PdfReader #1601

Description

@andreasrosdal

IndexOutOfBoundsException in PdfReader

Describe the bug

java.lang.IndexOutOfBoundsException: Index 57407 out of bounds for length 899
  at java.util.ArrayList.get
  at com.lowagie.text.pdf.PdfReader.readDocObj(PdfReader.java:1957)
  at com.lowagie.text.pdf.PdfReader.<init>

Root cause: The full stack shows the exception originates inside the OpenPDF library.

57407 is a PDF object number and 899 the parsed-object-list size — the classic signature of a broken PDF cross-reference table. Invoice.writePdf merges each invoice attachment's stored bytes, and PdfDocument.write re-parses each with OpenPDF's PdfReader. One attachment on this invoice is a corrupt/malformed PDF whose xref points at object 57407 while only 899 exist → the legacy reader throws a raw IndexOutOfBoundsException instead of a clean parse error.

Preview of a preliminary project invoice. Single occurrence for this exact stack signature in the retained window; deterministic for the one corrupt attachment, no loop / no data corruption / no retry-storm. Company & user details withheld here per sensitive-data policy.

Fails only the one request, but blocks every PDF render of that invoice (preview/print/likely send) until the bad attachment is removed. Same class recurs for any invoice carrying a corrupt PDF attachment.

Master branch:
https://github.com/LibrePDF/OpenPDF/blob/master/openpdf-core/src/main/java/org/openpdf/text/pdf/PdfReader.java#L1965

2.0.3 version:
https://github.com/LibrePDF/OpenPDF/blob/2.0.3/openpdf/src/main/java/com/lowagie/text/pdf/PdfReader.java#L1957

Summary of the report: IndexOutOfBoundsException in PdfReader when parsing a PDF with a corrupt/malformed cross-reference (xref) stream — an object number referenced by the xref stream exceeds the size of the parsed object list.

What I verified in the current code (openpdf-core/src/main/java/org/openpdf/text/pdf/PdfReader.java):

  1. readXrefStream (~line 2294-2318): when parsing a cross-reference stream (type 2 entries, i.e. compressed objects living inside an object stream), it reads field2 — the object number of the containing object stream — directly from stream bytes and stores it as a key in objStmMark via objStmMark.put(on, seq). This value is never bounds-checked against the actual parsed object count; ensureXrefSize is only called for start/length (the compressed object's own number), not for field2.
  2. readDocObj (line 1965):
    readObjStm((PRStream) xrefObj.get(n), h);
  3. n comes straight from an objStmMark key — no range check before calling .get(n).
  4. Contrast with getPdfObject(int idx) (line 1738-1744), just ~200 lines above, which does the correct thing:
    if (idx < 0 || idx >= xrefObj.size()) {
    return null;
    }

That inconsistency is exactly the bug: one accessor validates bounds, the other doesn't, and a malformed/corrupt xref stream can point at an object number (e.g. 57407) far beyond the actual object list size (e.g. 899), producing the raw ArrayList.get IndexOutOfBoundsException instead of a handled parse error.

Conclusion: Yes, still a valid, unfixed bug on master. It's a missing-bounds-check issue, not something masked by input sanitization elsewhere, and it also affects 2.0.3 as noted in the issue.

Fix would be small: add the same n < 0 || n >= xrefObj.size() guard at line 1965 (skip/log and continue rather than crash), and ideally validate field2 in readXrefStream before storing it in objStmMark.

System

  • OS: Ubuntu Linux
  • OpenPDF version: 2.0.3

Your real name

Andreas Røsdal

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions