diff --git a/include/qpdf/QPDFXRefEntry.hh b/include/qpdf/QPDFXRefEntry.hh index 1dc28c7..07ff16e 100644 --- a/include/qpdf/QPDFXRefEntry.hh +++ b/include/qpdf/QPDFXRefEntry.hh @@ -62,6 +62,9 @@ class QPDFXRefEntry private: // This class does not use the Members pattern to avoid a memory allocation for every one of // these. A lot of these get created. + + // The layout can be changed to reduce the size from 24 to 16 bytes. However, this would have a + // definite runtime cost. int type{0}; qpdf_offset_t field1{0}; int field2{0}; diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index 074d544..430a7c5 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -25,6 +25,7 @@ #include using namespace qpdf; +using namespace std::literals; // This must be a fixed value. This API returns a const reference to it, and the C API relies on its // being static as well. @@ -1967,6 +1968,7 @@ QPDF::resolveObjectsInStream(int obj_stream_number) (m->file->getName() + " object stream " + std::to_string(obj_stream_number)), bp.get())); + long long last_offset = -1; for (int i = 0; i < n; ++i) { QPDFTokenizer::Token tnum = readToken(*input); QPDFTokenizer::Token toffset = readToken(*input); @@ -1980,9 +1982,7 @@ QPDF::resolveObjectsInStream(int obj_stream_number) int num = QUtil::string_to_int(tnum.getValue().c_str()); long long offset = QUtil::string_to_int(toffset.getValue().c_str()); - if (num > m->xref_table_max_id) { - continue; - } + if (num == obj_stream_number) { QTC::TC("qpdf", "QPDF ignore self-referential object stream"); warn(damagedPDF( @@ -1992,6 +1992,33 @@ QPDF::resolveObjectsInStream(int obj_stream_number) "object stream claims to contain itself")); continue; } + + if (num < 1) { + QTC::TC("qpdf", "QPDF object stream contains id < 1"); + warn(damagedPDF( + *input, + "object "s + std::to_string(num) + " 0, offset " + std::to_string(offset), + 0, + "object id is invalid"s)); + continue; + } + + if (offset <= last_offset) { + QTC::TC("qpdf", "QPDF object stream offsets not increasing"); + warn(damagedPDF( + *input, + "object "s + std::to_string(num) + " 0, offset " + std::to_string(offset), + 0, + "offset is invalid (must be larger than previous offset " + + std::to_string(last_offset) + ")")); + continue; + } + last_offset = offset; + + if (num > m->xref_table_max_id) { + continue; + } + offsets[num] = toI(offset + first); } diff --git a/manual/release-notes.rst b/manual/release-notes.rst index 41cb83e..63b90aa 100644 --- a/manual/release-notes.rst +++ b/manual/release-notes.rst @@ -81,6 +81,12 @@ more detail. copies the file ``check`` to ``out.pdf`` but may in future check ``out.pdf``. Use ``qpdf ./check out.pdf`` or ``qpdf -- check out.pdf`` instead. + + - Bug fixes + + - In object streams ignore objects with invalid offset. Report objects with invalid + id or offset. + - Library Enhancements - ``QPDFObjectHandle`` supports move construction/assignment. diff --git a/qpdf/qpdf.testcov b/qpdf/qpdf.testcov index 6c0450a..2254239 100644 --- a/qpdf/qpdf.testcov +++ b/qpdf/qpdf.testcov @@ -4,7 +4,9 @@ QPDF err wrong objid/generation 0 QPDF check objid 1 QPDF check generation 1 QPDF check obj 1 +QPDF object stream offsets not increasing 0 QPDF ignore self-referential object stream 0 +QPDF object stream contains id < 1 0 QPDF hint table length indirect 0 QPDF hint table length direct 0 QPDF P absent in lindict 0 diff --git a/qpdf/qtest/qpdf/issue-143.out b/qpdf/qtest/qpdf/issue-143.out index 7f78727..d6aa959 100644 --- a/qpdf/qtest/qpdf/issue-143.out +++ b/qpdf/qtest/qpdf/issue-143.out @@ -14,5 +14,9 @@ WARNING: issue-143.pdf (object 1 0, offset 24): expected dictionary key but foun WARNING: issue-143.pdf (object 1 0, offset 21): stream dictionary lacks /Length key 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 stream 1 (object 0 0, offset 0): object id is invalid +WARNING: issue-143.pdf object stream 1 (object 0 0, offset 0): object id is invalid +WARNING: issue-143.pdf object stream 1 (object 6 0, offset 0): offset is invalid (must be larger than previous offset 0) +WARNING: issue-143.pdf object stream 1 (object 0 0, offset 0): object id is invalid WARNING: issue-143.pdf object stream 1 (object 2 0, offset 33): expected dictionary key but found non-name object; inserting key /QPDFFake1 qpdf: issue-143.pdf: unable to find page tree diff --git a/qpdf/qtest/qpdf/issue-143.pdf b/qpdf/qtest/qpdf/issue-143.pdf index b62e68a..8b8bb6c 100644 --- a/qpdf/qtest/qpdf/issue-143.pdf +++ b/qpdf/qtest/qpdf/issue-143.pdf