mirror of
https://github.com/mozilla/pdf.js.git
synced 2025-04-19 06:38:07 +02:00
Catch circular references in /Form XObjects (issue 19800)
For simplicity we will abort /Form XObject parsing *immediately* when encountering a circular reference, rather than letting it continue up until some limit (as e.g. PDFium appears to do), which should be fine since there are never any guarantees if/how *corrupt* PDF documents will render.
This commit is contained in:
parent
7a94fafd30
commit
1048508dd1
4 changed files with 143 additions and 5 deletions
|
@ -462,7 +462,8 @@ class PartialEvaluator {
|
||||||
operatorList,
|
operatorList,
|
||||||
task,
|
task,
|
||||||
initialState,
|
initialState,
|
||||||
localColorSpaceCache
|
localColorSpaceCache,
|
||||||
|
seenRefs
|
||||||
) {
|
) {
|
||||||
const dict = xobj.dict;
|
const dict = xobj.dict;
|
||||||
const matrix = lookupMatrix(dict.getArray("Matrix"), null);
|
const matrix = lookupMatrix(dict.getArray("Matrix"), null);
|
||||||
|
@ -526,6 +527,7 @@ class PartialEvaluator {
|
||||||
resources: dict.get("Resources") || resources,
|
resources: dict.get("Resources") || resources,
|
||||||
operatorList,
|
operatorList,
|
||||||
initialState,
|
initialState,
|
||||||
|
prevRefs: seenRefs,
|
||||||
});
|
});
|
||||||
operatorList.addOp(OPS.paintFormXObjectEnd, []);
|
operatorList.addOp(OPS.paintFormXObjectEnd, []);
|
||||||
|
|
||||||
|
@ -850,7 +852,8 @@ class PartialEvaluator {
|
||||||
operatorList,
|
operatorList,
|
||||||
task,
|
task,
|
||||||
stateManager,
|
stateManager,
|
||||||
localColorSpaceCache
|
localColorSpaceCache,
|
||||||
|
seenRefs
|
||||||
) {
|
) {
|
||||||
const smaskContent = smask.get("G");
|
const smaskContent = smask.get("G");
|
||||||
const smaskOptions = {
|
const smaskOptions = {
|
||||||
|
@ -880,7 +883,8 @@ class PartialEvaluator {
|
||||||
operatorList,
|
operatorList,
|
||||||
task,
|
task,
|
||||||
stateManager.state.clone({ newPath: true }),
|
stateManager.state.clone({ newPath: true }),
|
||||||
localColorSpaceCache
|
localColorSpaceCache,
|
||||||
|
seenRefs
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1065,6 +1069,7 @@ class PartialEvaluator {
|
||||||
stateManager,
|
stateManager,
|
||||||
localGStateCache,
|
localGStateCache,
|
||||||
localColorSpaceCache,
|
localColorSpaceCache,
|
||||||
|
seenRefs,
|
||||||
}) {
|
}) {
|
||||||
const gStateRef = gState.objId;
|
const gStateRef = gState.objId;
|
||||||
let isSimpleGState = true;
|
let isSimpleGState = true;
|
||||||
|
@ -1127,7 +1132,8 @@ class PartialEvaluator {
|
||||||
operatorList,
|
operatorList,
|
||||||
task,
|
task,
|
||||||
stateManager,
|
stateManager,
|
||||||
localColorSpaceCache
|
localColorSpaceCache,
|
||||||
|
seenRefs
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
gStateObj.push([key, true]);
|
gStateObj.push([key, true]);
|
||||||
|
@ -1696,7 +1702,19 @@ class PartialEvaluator {
|
||||||
operatorList,
|
operatorList,
|
||||||
initialState = null,
|
initialState = null,
|
||||||
fallbackFontDict = null,
|
fallbackFontDict = null,
|
||||||
|
prevRefs = null,
|
||||||
}) {
|
}) {
|
||||||
|
const objId = stream.dict?.objId;
|
||||||
|
const seenRefs = new RefSet(prevRefs);
|
||||||
|
|
||||||
|
if (objId) {
|
||||||
|
if (prevRefs?.has(objId)) {
|
||||||
|
throw new Error(
|
||||||
|
`getOperatorList - ignoring circular reference: ${objId}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
seenRefs.put(objId);
|
||||||
|
}
|
||||||
// Ensure that `resources`/`initialState` is correctly initialized,
|
// Ensure that `resources`/`initialState` is correctly initialized,
|
||||||
// even if the provided parameter is e.g. `null`.
|
// even if the provided parameter is e.g. `null`.
|
||||||
resources ||= Dict.empty;
|
resources ||= Dict.empty;
|
||||||
|
@ -1808,7 +1826,8 @@ class PartialEvaluator {
|
||||||
operatorList,
|
operatorList,
|
||||||
task,
|
task,
|
||||||
stateManager.state.clone({ newPath: true }),
|
stateManager.state.clone({ newPath: true }),
|
||||||
localColorSpaceCache
|
localColorSpaceCache,
|
||||||
|
seenRefs
|
||||||
)
|
)
|
||||||
.then(function () {
|
.then(function () {
|
||||||
stateManager.restore();
|
stateManager.restore();
|
||||||
|
@ -2158,6 +2177,7 @@ class PartialEvaluator {
|
||||||
stateManager,
|
stateManager,
|
||||||
localGStateCache,
|
localGStateCache,
|
||||||
localColorSpaceCache,
|
localColorSpaceCache,
|
||||||
|
seenRefs,
|
||||||
})
|
})
|
||||||
.then(resolveGState, rejectGState);
|
.then(resolveGState, rejectGState);
|
||||||
}).catch(function (reason) {
|
}).catch(function (reason) {
|
||||||
|
@ -2339,7 +2359,19 @@ class PartialEvaluator {
|
||||||
markedContentData = null,
|
markedContentData = null,
|
||||||
disableNormalization = false,
|
disableNormalization = false,
|
||||||
keepWhiteSpace = false,
|
keepWhiteSpace = false,
|
||||||
|
prevRefs = null,
|
||||||
}) {
|
}) {
|
||||||
|
const objId = stream.dict?.objId;
|
||||||
|
const seenRefs = new RefSet(prevRefs);
|
||||||
|
|
||||||
|
if (objId) {
|
||||||
|
if (prevRefs?.has(objId)) {
|
||||||
|
throw new Error(
|
||||||
|
`getTextContent - ignoring circular reference: ${objId}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
seenRefs.put(objId);
|
||||||
|
}
|
||||||
// Ensure that `resources`/`stateManager` is correctly initialized,
|
// Ensure that `resources`/`stateManager` is correctly initialized,
|
||||||
// even if the provided parameter is e.g. `null`.
|
// even if the provided parameter is e.g. `null`.
|
||||||
resources ||= Dict.empty;
|
resources ||= Dict.empty;
|
||||||
|
@ -3326,6 +3358,7 @@ class PartialEvaluator {
|
||||||
markedContentData,
|
markedContentData,
|
||||||
disableNormalization,
|
disableNormalization,
|
||||||
keepWhiteSpace,
|
keepWhiteSpace,
|
||||||
|
prevRefs: seenRefs,
|
||||||
})
|
})
|
||||||
.then(function () {
|
.then(function () {
|
||||||
if (!sinkWrapper.enqueueInvoked) {
|
if (!sinkWrapper.enqueueInvoked) {
|
||||||
|
|
1
test/pdfs/.gitignore
vendored
1
test/pdfs/.gitignore
vendored
|
@ -206,6 +206,7 @@
|
||||||
!issue3928.pdf
|
!issue3928.pdf
|
||||||
!issue8565.pdf
|
!issue8565.pdf
|
||||||
!clippath.pdf
|
!clippath.pdf
|
||||||
|
!issue19800.pdf
|
||||||
!issue8795_reduced.pdf
|
!issue8795_reduced.pdf
|
||||||
!bug1755507.pdf
|
!bug1755507.pdf
|
||||||
!close-path-bug.pdf
|
!close-path-bug.pdf
|
||||||
|
|
90
test/pdfs/issue19800.pdf
Normal file
90
test/pdfs/issue19800.pdf
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
%PDF-1.4
|
||||||
|
1 0 obj
|
||||||
|
<<
|
||||||
|
/Type /Catalog
|
||||||
|
/Outlines 2 0 R
|
||||||
|
/Pages 3 0 R
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
2 0 obj
|
||||||
|
<<
|
||||||
|
/Type /Outlines
|
||||||
|
/Count 0
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
3 0 obj
|
||||||
|
<<
|
||||||
|
/Type /Pages
|
||||||
|
/Kids [ 4 0 R ]
|
||||||
|
/Count 1
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
4 0 obj
|
||||||
|
<<
|
||||||
|
/Type /Page
|
||||||
|
/Parent 3 0 R
|
||||||
|
/MediaBox [ 0 0 500 300 ]
|
||||||
|
/Contents 5 0 R
|
||||||
|
/Resources <<
|
||||||
|
/ProcSet [ /PDF /Text ]
|
||||||
|
/XObject << /X1 6 0 R >>
|
||||||
|
>>
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
5 0 obj
|
||||||
|
<< /Length 24 >>
|
||||||
|
stream
|
||||||
|
1 0 0 1 25 25 cm /X1 Do
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
6 0 obj
|
||||||
|
<< /Subtype /Form
|
||||||
|
/BBox [0 0 1000 1000]
|
||||||
|
/Length 61
|
||||||
|
/Resources <<
|
||||||
|
/ProcSet [ /PDF /Text ]
|
||||||
|
/Font << /F1 7 0 R >>
|
||||||
|
/XObject << /X0 8 0 R >>
|
||||||
|
>>
|
||||||
|
>>
|
||||||
|
stream
|
||||||
|
BT
|
||||||
|
/F1 24 Tf
|
||||||
|
(Hello world) Tj
|
||||||
|
ET
|
||||||
|
0.5 0 0 0.5 25 25 cm /X0 Do
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
7 0 obj
|
||||||
|
<<
|
||||||
|
/Type /Font
|
||||||
|
/Subtype /Type1
|
||||||
|
/Name /F1
|
||||||
|
/BaseFont /Helvetica
|
||||||
|
/Encoding /MacRomanEncoding
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
8 0 obj
|
||||||
|
<< /Subtype /Form
|
||||||
|
/BBox [0 0 1000 1000]
|
||||||
|
/Length 61
|
||||||
|
/Resources <<
|
||||||
|
/ProcSet [ /PDF /Text ]
|
||||||
|
/Font << /F1 7 0 R >>
|
||||||
|
/XObject << /X1 6 0 R >>
|
||||||
|
>>
|
||||||
|
>>
|
||||||
|
stream
|
||||||
|
BT
|
||||||
|
/F1 24 Tf
|
||||||
|
(Hello world) Tj
|
||||||
|
ET
|
||||||
|
0.5 0 0 0.5 25 25 cm /X1 Do
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
trailer
|
||||||
|
<<
|
||||||
|
/Size 8
|
||||||
|
/Root 1 0 R
|
||||||
|
>>
|
||||||
|
%%EOF
|
|
@ -6897,6 +6897,20 @@
|
||||||
"lastPage": 2,
|
"lastPage": 2,
|
||||||
"type": "eq"
|
"type": "eq"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "issue19800-eq",
|
||||||
|
"file": "pdfs/issue19800.pdf",
|
||||||
|
"md5": "92825d3178196bdd01096c4081609efd",
|
||||||
|
"rounds": 1,
|
||||||
|
"type": "eq"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "issue19800-text",
|
||||||
|
"file": "pdfs/issue19800.pdf",
|
||||||
|
"md5": "92825d3178196bdd01096c4081609efd",
|
||||||
|
"rounds": 1,
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "issue3438",
|
"id": "issue3438",
|
||||||
"file": "pdfs/issue3438.pdf",
|
"file": "pdfs/issue3438.pdf",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue