mirror of
https://github.com/qpdf/qpdf.git
synced 2024-11-14 00:34:03 +00:00
Merge pull request #1221 from m-holger/fuzz
Refine handling of severely damaged files
This commit is contained in:
commit
3d569e2171
@ -118,6 +118,7 @@ set(CORPUS_OTHER
|
|||||||
68377.fuzz
|
68377.fuzz
|
||||||
68668.fuzz
|
68668.fuzz
|
||||||
68915.fuzz
|
68915.fuzz
|
||||||
|
69857.fuzz
|
||||||
)
|
)
|
||||||
|
|
||||||
set(CORPUS_DIR ${CMAKE_CURRENT_BINARY_DIR}/qpdf_corpus)
|
set(CORPUS_DIR ${CMAKE_CURRENT_BINARY_DIR}/qpdf_corpus)
|
||||||
|
BIN
fuzz/qpdf_extra/69857.fuzz
Normal file
BIN
fuzz/qpdf_extra/69857.fuzz
Normal file
Binary file not shown.
@ -21,7 +21,7 @@ my @fuzzers = (
|
|||||||
['pngpredictor' => 1],
|
['pngpredictor' => 1],
|
||||||
['runlength' => 6],
|
['runlength' => 6],
|
||||||
['tiffpredictor' => 2],
|
['tiffpredictor' => 2],
|
||||||
['qpdf' => 60], # increment when adding new files
|
['qpdf' => 61], # increment when adding new files
|
||||||
);
|
);
|
||||||
|
|
||||||
my $n_tests = 0;
|
my $n_tests = 0;
|
||||||
|
@ -471,6 +471,10 @@ QPDF::parse(char const* password)
|
|||||||
|
|
||||||
initializeEncryption();
|
initializeEncryption();
|
||||||
m->parsed = true;
|
m->parsed = true;
|
||||||
|
if (m->xref_table.size() > 0 && !getRoot().getKey("/Pages").isDictionary()) {
|
||||||
|
// QPDFs created from JSON have an empty xref table and no root object yet.
|
||||||
|
throw damagedPDF("", 0, "unable to find page tree");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -543,6 +547,9 @@ QPDF::reconstruct_xref(QPDFExc& e)
|
|||||||
|
|
||||||
m->file->seek(0, SEEK_END);
|
m->file->seek(0, SEEK_END);
|
||||||
qpdf_offset_t eof = m->file->tell();
|
qpdf_offset_t eof = m->file->tell();
|
||||||
|
// Sanity check on object ids. All objects must appear in xref table / stream. In all realistic
|
||||||
|
// scenarios at leat 3 bytes are required.
|
||||||
|
auto max_obj_id = eof / 3;
|
||||||
m->file->seek(0, SEEK_SET);
|
m->file->seek(0, SEEK_SET);
|
||||||
qpdf_offset_t line_start = 0;
|
qpdf_offset_t line_start = 0;
|
||||||
// Don't allow very long tokens here during recovery.
|
// Don't allow very long tokens here during recovery.
|
||||||
@ -560,7 +567,12 @@ QPDF::reconstruct_xref(QPDFExc& e)
|
|||||||
if ((t2.isInteger()) && (readToken(m->file, MAX_LEN).isWord("obj"))) {
|
if ((t2.isInteger()) && (readToken(m->file, MAX_LEN).isWord("obj"))) {
|
||||||
int obj = QUtil::string_to_int(t1.getValue().c_str());
|
int obj = QUtil::string_to_int(t1.getValue().c_str());
|
||||||
int gen = QUtil::string_to_int(t2.getValue().c_str());
|
int gen = QUtil::string_to_int(t2.getValue().c_str());
|
||||||
|
if (obj <= max_obj_id) {
|
||||||
insertReconstructedXrefEntry(obj, token_start, gen);
|
insertReconstructedXrefEntry(obj, token_start, gen);
|
||||||
|
} else {
|
||||||
|
warn(damagedPDF(
|
||||||
|
"", 0, "ignoring object with impossibly large id " + std::to_string(obj)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (!m->trailer.isInitialized() && t1.isWord("trailer")) {
|
} else if (!m->trailer.isInitialized() && t1.isWord("trailer")) {
|
||||||
QPDFObjectHandle t = readTrailer();
|
QPDFObjectHandle t = readTrailer();
|
||||||
|
@ -1121,7 +1121,6 @@ QPDFWriter::enqueueObject(QPDFObjectHandle object)
|
|||||||
} else if (obj.renumber == -1) {
|
} else if (obj.renumber == -1) {
|
||||||
// This can happen if a specially constructed file indicates that an object stream is
|
// This can happen if a specially constructed file indicates that an object stream is
|
||||||
// inside itself.
|
// inside itself.
|
||||||
QTC::TC("qpdf", "QPDFWriter ignore self-referential object stream");
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} else if (!m->linearized) {
|
} else if (!m->linearized) {
|
||||||
|
@ -277,7 +277,6 @@ QPDF ignore first extra space in xref entry 0
|
|||||||
QPDF ignore second extra space in xref entry 0
|
QPDF ignore second extra space in xref entry 0
|
||||||
QPDF ignore length error xref entry 0
|
QPDF ignore length error xref entry 0
|
||||||
QPDF_encryption pad short parameter 0
|
QPDF_encryption pad short parameter 0
|
||||||
QPDFWriter ignore self-referential object stream 0
|
|
||||||
QPDFObjectHandle found old angle 1
|
QPDFObjectHandle found old angle 1
|
||||||
QPDF_Stream special filters 3
|
QPDF_Stream special filters 3
|
||||||
QPDFTokenizer block long token 0
|
QPDFTokenizer block long token 0
|
||||||
|
@ -19,7 +19,7 @@ my $n_tests = 4;
|
|||||||
$td->runtest("closed input source",
|
$td->runtest("closed input source",
|
||||||
{$td->COMMAND => "test_driver 73 minimal.pdf"},
|
{$td->COMMAND => "test_driver 73 minimal.pdf"},
|
||||||
{$td->FILE => "test73.out",
|
{$td->FILE => "test73.out",
|
||||||
$td->EXIT_STATUS => 2},
|
$td->EXIT_STATUS => 0},
|
||||||
$td->NORMALIZE_NEWLINES);
|
$td->NORMALIZE_NEWLINES);
|
||||||
|
|
||||||
$td->runtest("empty object",
|
$td->runtest("empty object",
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
WARNING: bad11.pdf: file is damaged
|
WARNING: bad11.pdf: file is damaged
|
||||||
WARNING: bad11.pdf (trailer, offset 905): /Prev key in trailer dictionary is not an integer
|
WARNING: bad11.pdf (trailer, offset 905): /Prev key in trailer dictionary is not an integer
|
||||||
WARNING: bad11.pdf: Attempting to reconstruct cross-reference table
|
WARNING: bad11.pdf: Attempting to reconstruct cross-reference table
|
||||||
|
WARNING: bad11.pdf (object 2 0, offset 128): expected endobj
|
||||||
/QTest is implicit
|
/QTest is implicit
|
||||||
/QTest is direct and has type null (2)
|
/QTest is direct and has type null (2)
|
||||||
/QTest is null
|
/QTest is null
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
WARNING: bad12.pdf: reported number of objects (9) is not one plus the highest object number (7)
|
WARNING: bad12.pdf: reported number of objects (9) is not one plus the highest object number (7)
|
||||||
|
WARNING: bad12.pdf (object 2 0, offset 128): expected endobj
|
||||||
/QTest is implicit
|
/QTest is implicit
|
||||||
/QTest is direct and has type null (2)
|
/QTest is direct and has type null (2)
|
||||||
/QTest is null
|
/QTest is null
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
WARNING: bad12.pdf: reported number of objects (9) is not one plus the highest object number (7)
|
WARNING: bad12.pdf: reported number of objects (9) is not one plus the highest object number (7)
|
||||||
|
WARNING: bad12.pdf (object 2 0, offset 128): expected endobj
|
||||||
/QTest is implicit
|
/QTest is implicit
|
||||||
/QTest is direct and has type null (2)
|
/QTest is direct and has type null (2)
|
||||||
/QTest is null
|
/QTest is null
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
WARNING: bad2.pdf: file is damaged
|
WARNING: bad2.pdf: file is damaged
|
||||||
WARNING: bad2.pdf: can't find startxref
|
WARNING: bad2.pdf: can't find startxref
|
||||||
WARNING: bad2.pdf: Attempting to reconstruct cross-reference table
|
WARNING: bad2.pdf: Attempting to reconstruct cross-reference table
|
||||||
|
WARNING: bad2.pdf (object 2 0, offset 128): expected endobj
|
||||||
/QTest is implicit
|
/QTest is implicit
|
||||||
/QTest is direct and has type null (2)
|
/QTest is direct and has type null (2)
|
||||||
/QTest is null
|
/QTest is null
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
WARNING: bad3.pdf: file is damaged
|
WARNING: bad3.pdf: file is damaged
|
||||||
WARNING: bad3.pdf (offset 542): xref not found
|
WARNING: bad3.pdf (offset 542): xref not found
|
||||||
WARNING: bad3.pdf: Attempting to reconstruct cross-reference table
|
WARNING: bad3.pdf: Attempting to reconstruct cross-reference table
|
||||||
|
WARNING: bad3.pdf (object 2 0, offset 128): expected endobj
|
||||||
/QTest is implicit
|
/QTest is implicit
|
||||||
/QTest is direct and has type null (2)
|
/QTest is direct and has type null (2)
|
||||||
/QTest is null
|
/QTest is null
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
WARNING: bad4.pdf: file is damaged
|
WARNING: bad4.pdf: file is damaged
|
||||||
WARNING: bad4.pdf (xref table, offset 547): xref syntax invalid
|
WARNING: bad4.pdf (xref table, offset 547): xref syntax invalid
|
||||||
WARNING: bad4.pdf: Attempting to reconstruct cross-reference table
|
WARNING: bad4.pdf: Attempting to reconstruct cross-reference table
|
||||||
|
WARNING: bad4.pdf (object 2 0, offset 128): expected endobj
|
||||||
/QTest is implicit
|
/QTest is implicit
|
||||||
/QTest is direct and has type null (2)
|
/QTest is direct and has type null (2)
|
||||||
/QTest is null
|
/QTest is null
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
WARNING: bad5.pdf: file is damaged
|
WARNING: bad5.pdf: file is damaged
|
||||||
WARNING: bad5.pdf (xref table, offset 591): invalid xref entry (obj=2)
|
WARNING: bad5.pdf (xref table, offset 591): invalid xref entry (obj=2)
|
||||||
WARNING: bad5.pdf: Attempting to reconstruct cross-reference table
|
WARNING: bad5.pdf: Attempting to reconstruct cross-reference table
|
||||||
|
WARNING: bad5.pdf (object 2 0, offset 128): expected endobj
|
||||||
/QTest is implicit
|
/QTest is implicit
|
||||||
/QTest is direct and has type null (2)
|
/QTest is direct and has type null (2)
|
||||||
/QTest is null
|
/QTest is null
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
WARNING: bad6.pdf (object 2 0, offset 128): expected endobj
|
||||||
/QTest is implicit
|
/QTest is implicit
|
||||||
/QTest is direct and has type null (2)
|
/QTest is direct and has type null (2)
|
||||||
/QTest is null
|
/QTest is null
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
WARNING: bad6.pdf (object 2 0, offset 128): expected endobj
|
||||||
/QTest is implicit
|
/QTest is implicit
|
||||||
/QTest is direct and has type null (2)
|
/QTest is direct and has type null (2)
|
||||||
/QTest is null
|
/QTest is null
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
WARNING: bad8.pdf: file is damaged
|
WARNING: bad8.pdf: file is damaged
|
||||||
WARNING: bad8.pdf (offset 543): xref not found
|
WARNING: bad8.pdf (offset 543): xref not found
|
||||||
WARNING: bad8.pdf: Attempting to reconstruct cross-reference table
|
WARNING: bad8.pdf: Attempting to reconstruct cross-reference table
|
||||||
|
WARNING: bad8.pdf (object 2 0, offset 128): expected endobj
|
||||||
/QTest is implicit
|
/QTest is implicit
|
||||||
/QTest is direct and has type null (2)
|
/QTest is direct and has type null (2)
|
||||||
/QTest is null
|
/QTest is null
|
||||||
|
@ -11,8 +11,8 @@ WARNING: fuzz-16214.pdf (object 1 0, offset 7189): expected n n obj
|
|||||||
WARNING: fuzz-16214.pdf: Attempting to reconstruct cross-reference table
|
WARNING: fuzz-16214.pdf: Attempting to reconstruct cross-reference table
|
||||||
WARNING: fuzz-16214.pdf (offset 7207): error decoding stream data for object 2 0: stream inflate: inflate: data: invalid code lengths set
|
WARNING: fuzz-16214.pdf (offset 7207): error decoding stream data for object 2 0: stream inflate: inflate: data: invalid code lengths set
|
||||||
WARNING: fuzz-16214.pdf (offset 7207): getStreamData called on unfilterable stream
|
WARNING: fuzz-16214.pdf (offset 7207): getStreamData called on unfilterable stream
|
||||||
WARNING: fuzz-16214.pdf (object 11 0, offset 11551): supposed object stream 5 has wrong type
|
WARNING: fuzz-16214.pdf (object 8 0, offset 7207): supposed object stream 5 has wrong type
|
||||||
WARNING: fuzz-16214.pdf (object 11 0, offset 11551): object stream 5 has incorrect keys
|
WARNING: fuzz-16214.pdf (object 8 0, offset 7207): object stream 5 has incorrect keys
|
||||||
WARNING: fuzz-16214.pdf (object 21 0, offset 3639): expected endstream
|
WARNING: fuzz-16214.pdf (object 21 0, offset 3639): expected endstream
|
||||||
WARNING: fuzz-16214.pdf (object 21 0, offset 3112): attempting to recover stream length
|
WARNING: fuzz-16214.pdf (object 21 0, offset 3112): attempting to recover stream length
|
||||||
WARNING: fuzz-16214.pdf (object 21 0, offset 3112): recovered stream length: 340
|
WARNING: fuzz-16214.pdf (object 21 0, offset 3112): recovered stream length: 340
|
||||||
|
@ -1,3 +1 @@
|
|||||||
WARNING: issue-119.pdf (object 4 0, offset 298): expected dictionary key but found non-name object; inserting key /QPDFFake1
|
qpdf: issue-119.pdf: unable to find page tree
|
||||||
WARNING: issue-119.pdf (object 4 0, offset 298): expected dictionary key but found non-name object; inserting key /QPDFFake2
|
|
||||||
qpdf: operation succeeded with warnings; resulting file may have some problems
|
|
||||||
|
@ -1,7 +1 @@
|
|||||||
WARNING: issue-120.pdf (offset 85): loop detected resolving object 3 0
|
qpdf: issue-120.pdf: unable to find page tree
|
||||||
WARNING: issue-120.pdf (object 6 0, offset 85): supposed object stream 3 is not a stream
|
|
||||||
WARNING: issue-120.pdf: file is damaged
|
|
||||||
WARNING: issue-120.pdf (object 8 10, offset 26880): expected n n obj
|
|
||||||
WARNING: issue-120.pdf: Attempting to reconstruct cross-reference table
|
|
||||||
WARNING: issue-120.pdf: object 8 10 not found in file after regenerating cross reference table
|
|
||||||
qpdf: operation succeeded with warnings; resulting file may have some problems
|
|
||||||
|
@ -14,6 +14,4 @@ WARNING: issue-143.pdf (object 1 0, offset 21): stream dictionary lacks /Length
|
|||||||
WARNING: issue-143.pdf (object 1 0, offset 84): attempting to recover stream length
|
WARNING: issue-143.pdf (object 1 0, offset 84): attempting to recover stream length
|
||||||
WARNING: issue-143.pdf (object 1 0, offset 84): recovered stream length: 606
|
WARNING: issue-143.pdf (object 1 0, offset 84): recovered stream length: 606
|
||||||
WARNING: issue-143.pdf object stream 1 (object 2 0, offset 33): expected dictionary key but found non-name object; inserting key /QPDFFake1
|
WARNING: issue-143.pdf object stream 1 (object 2 0, offset 33): expected dictionary key but found non-name object; inserting key /QPDFFake1
|
||||||
WARNING: issue-143.pdf: object 0/0 has unexpected xref entry type
|
qpdf: issue-143.pdf: unable to find page tree
|
||||||
WARNING: issue-143.pdf (object 2 0, offset 84): supposed object stream 12336 is not a stream
|
|
||||||
qpdf: operation succeeded with warnings; resulting file may have some problems
|
|
||||||
|
@ -3,6 +3,5 @@ WARNING: issue-147.pdf: file is damaged
|
|||||||
WARNING: issue-147.pdf: can't find startxref
|
WARNING: issue-147.pdf: can't find startxref
|
||||||
WARNING: issue-147.pdf: Attempting to reconstruct cross-reference table
|
WARNING: issue-147.pdf: Attempting to reconstruct cross-reference table
|
||||||
WARNING: issue-147.pdf (trailer, offset 9): expected dictionary key but found non-name object; inserting key /QPDFFake1
|
WARNING: issue-147.pdf (trailer, offset 9): expected dictionary key but found non-name object; inserting key /QPDFFake1
|
||||||
WARNING: issue-147.pdf (object 62 0, offset 88): expected endobj
|
WARNING: issue-147.pdf: ignoring object with impossibly large id 62
|
||||||
WARNING: issue-147.pdf (trailer, offset 90): invalid /ID in trailer dictionary
|
qpdf: issue-147.pdf: unable to find /Root dictionary
|
||||||
qpdf: issue-147.pdf: invalid password
|
|
||||||
|
@ -2,15 +2,4 @@ WARNING: issue-51.pdf: can't find PDF header
|
|||||||
WARNING: issue-51.pdf: reported number of objects (0) is not one plus the highest object number (8)
|
WARNING: issue-51.pdf: reported number of objects (0) is not one plus the highest object number (8)
|
||||||
WARNING: issue-51.pdf (object 7 0, offset 476): dictionary has duplicated key /0000; last occurrence overrides earlier ones
|
WARNING: issue-51.pdf (object 7 0, offset 476): dictionary has duplicated key /0000; last occurrence overrides earlier ones
|
||||||
WARNING: issue-51.pdf (object 7 0, offset 553): expected endobj
|
WARNING: issue-51.pdf (object 7 0, offset 553): expected endobj
|
||||||
WARNING: issue-51.pdf (object 1 0, offset 236): dictionary has duplicated key /00000000; last occurrence overrides earlier ones
|
issue-51.pdf: unable to find page tree
|
||||||
WARNING: issue-51.pdf (object 1 0, offset 359): expected endobj
|
|
||||||
WARNING: issue-51.pdf (offset 70): loop detected resolving object 2 0
|
|
||||||
WARNING: issue-51.pdf (object 2 0, offset 26): stream dictionary lacks /Length key
|
|
||||||
WARNING: issue-51.pdf (object 2 0, offset 71): attempting to recover stream length
|
|
||||||
WARNING: issue-51.pdf (object 2 0, offset 71): unable to recover stream data; treating stream as empty
|
|
||||||
WARNING: issue-51.pdf (object 2 0, offset 977): expected endobj
|
|
||||||
WARNING: issue-51.pdf (object 3 0): object has offset 0
|
|
||||||
WARNING: issue-51.pdf (object 4 0): object has offset 0
|
|
||||||
WARNING: issue-51.pdf (object 5 0): object has offset 0
|
|
||||||
WARNING: issue-51.pdf (object 6 0): object has offset 0
|
|
||||||
WARNING: issue-51.pdf (object 8 0): object has offset 0
|
|
||||||
|
@ -21,6 +21,7 @@ captured stderr
|
|||||||
WARNING: bad2.pdf: file is damaged
|
WARNING: bad2.pdf: file is damaged
|
||||||
WARNING: bad2.pdf: can't find startxref
|
WARNING: bad2.pdf: can't find startxref
|
||||||
WARNING: bad2.pdf: Attempting to reconstruct cross-reference table
|
WARNING: bad2.pdf: Attempting to reconstruct cross-reference table
|
||||||
|
WARNING: bad2.pdf (object 2 0, offset 128): expected endobj
|
||||||
WARNING: bad2.pdf (object 4 0, offset 389): expected endobj
|
WARNING: bad2.pdf (object 4 0, offset 389): expected endobj
|
||||||
qpdf: operation succeeded with warnings
|
qpdf: operation succeeded with warnings
|
||||||
test 84 done
|
test 84 done
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
getRoot: attempted to dereference an uninitialized QPDFObjectHandle
|
getRoot: attempted to dereference an uninitialized QPDFObjectHandle
|
||||||
WARNING: closed input source: object 1/0: error reading object: QPDF operation attempted on a QPDF object with no input source. QPDF operations are invalid before processFile (or another process method) or after closeInputSource
|
WARNING: closed input source: object 4/0: error reading object: QPDF operation attempted on a QPDF object with no input source. QPDF operations are invalid before processFile (or another process method) or after closeInputSource
|
||||||
closed input source: unable to find /Root dictionary
|
test 73 done
|
||||||
|
@ -16,19 +16,19 @@ my $td = new TestDriver('specific-bugs');
|
|||||||
|
|
||||||
# The number is the github issue number in which the bug was reported.
|
# The number is the github issue number in which the bug was reported.
|
||||||
my @bug_tests = (
|
my @bug_tests = (
|
||||||
["51", "resolve loop", 3],
|
["51", "resolve loop", 2],
|
||||||
["99", "object 0", 2],
|
["99", "object 0", 2],
|
||||||
["99b", "object 0", 2],
|
["99b", "object 0", 2],
|
||||||
["100", "xref reconstruction loop", 2],
|
["100", "xref reconstruction loop", 2],
|
||||||
["101", "resolve for exception text", 2],
|
["101", "resolve for exception text", 2],
|
||||||
["117", "other infinite loop", 3],
|
["117", "other infinite loop", 3],
|
||||||
["118", "other infinite loop", 2],
|
["118", "other infinite loop", 2],
|
||||||
["119", "other infinite loop", 3],
|
["119", "other infinite loop", 2],
|
||||||
["120", "other infinite loop", 3],
|
["120", "other infinite loop", 2],
|
||||||
["106", "zlib data error", 3],
|
["106", "zlib data error", 3],
|
||||||
["141a", "/W entry size 0", 2],
|
["141a", "/W entry size 0", 2],
|
||||||
["141b", "/W entry size 0", 2],
|
["141b", "/W entry size 0", 2],
|
||||||
["143", "self-referential ostream", 3, "--preserve-unreferenced"],
|
["143", "self-referential ostream", 2, "--preserve-unreferenced"],
|
||||||
["146", "very deeply nested array", 2],
|
["146", "very deeply nested array", 2],
|
||||||
["147", "previously caused memory error", 2],
|
["147", "previously caused memory error", 2],
|
||||||
["148", "free memory on bad flate", 2],
|
["148", "free memory on bad flate", 2],
|
||||||
|
@ -2496,7 +2496,7 @@ test_73(QPDF& pdf, char const* arg2)
|
|||||||
}
|
}
|
||||||
|
|
||||||
pdf.closeInputSource();
|
pdf.closeInputSource();
|
||||||
pdf.getRoot().getKey("/Pages").unparseResolved();
|
pdf.getObject(4, 0).unparseResolved();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
Loading…
Reference in New Issue
Block a user