Repository navigation
PDFBOX-6200: Link the document state to substructures without recursion - #539
sharanggupta wants to merge 1 commit into
Conversation
COSUpdateState.setOriginDocumentState() descended into the entries of dictionaries and arrays and into dereferenced indirect objects through recursive calls, so linking the document state to a deeply nested structure, such as the objects of large CAD documents being signed with an incremental save, failed with a StackOverflowError (also reported in PDFBOX-6039). Traverse the structure with an explicit stack instead, as suggested on PDFBOX-6039, rather than limiting the depth.
|
Why not just do it the classic way by using a "visited" Set? Like in PageTree and Splitter? |
|
The recursive version already has the equivalent of a visited set: The test shows this: its chain of 50,000 nested objects has no cycle, and trunk still throws a |
|
Ah, sorry, now I get it. The point is to eliminate recursion. (Which you mentioned in the code 🤦♂️) |
…on, by Sharang Gupta; closes #539 git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/3.0@1939135 13f79535-47bb-0310-9956-ffa450edef68
|
Thank you for your contribution, I have committed it; the PR should close automatically with the next commit (for some reason the github mirror is often 1 commit behind) |
Fixes PDFBOX-6200 (and the same problem reported as PDFBOX-6039).
COSUpdateState.setOriginDocumentState()links the document state to the managed object and to all its substructures by calling itself for each entry of a dictionary or an array and for the target of a dereferencedCOSObject. A deeply nested structure therefore overflows the stack, which is what the DSS users signing large AutoCAD documents with an incremental save hit in PDFBOX-6200.As Michael Klink suggested on PDFBOX-6039, the recursion is replaced by a loop over an explicit stack (
ArrayDeque) rather than a depth limit, so no structure is left without its document state. The traversal visits the same objects with the same rules: a state that already has an origin is skipped (which also stops at cycles),update()is called unless dereferencing, and the substructures are those of dictionaries, arrays and dereferenced indirect objects. Only the visiting order differs, which does not matter as each state is updated independently.Test:
TestCOSUpdateInfo.testSetOriginDocumentStateOfDeeplyNestedStructurelinks a document state to a chain of 50,000 nested dictionaries, arrays and indirect objects and checks that the deepest one is linked and marked as updated. Ontrunkit fails with aStackOverflowErrorthrown by the recursivesetOriginDocumentState()calls; with the change it passes. Thecos,pdfwriterandPDDocumenttests pass, and the fullpdfboxmodule build passes locally.