From 133e53080e3ccdafeed5c5f79d115f2e3184e35c Mon Sep 17 00:00:00 2001 From: m-holger Date: Thu, 20 Nov 2025 16:09:09 +0000 Subject: [PATCH] Improve handling of xref stream anomalies and update tests. --- fuzz/CMakeLists.txt | 1 + fuzz/qpdf_extra/4876793183272960.fuzz | Bin 0 -> 45 bytes fuzz/qtest/fuzz.test | 2 +- libqpdf/QPDF_objects.cc | 2 +- qpdf/qtest/error-condition.test | 3 ++- qpdf/qtest/qpdf/bad12-recover.out | 2 +- qpdf/qtest/qpdf/bad12.out | 2 +- qpdf/qtest/qpdf/bad40-recover.out | 8 ++++++++ qpdf/qtest/qpdf/bad40.out | 8 ++++++++ qpdf/qtest/qpdf/bad40.pdf | Bin 0 -> 788 bytes 10 files changed, 23 insertions(+), 5 deletions(-) create mode 100644 fuzz/qpdf_extra/4876793183272960.fuzz create mode 100644 qpdf/qtest/qpdf/bad40-recover.out create mode 100644 qpdf/qtest/qpdf/bad40.out create mode 100644 qpdf/qtest/qpdf/bad40.pdf diff --git a/fuzz/CMakeLists.txt b/fuzz/CMakeLists.txt index 96e85e3..04d90ea 100644 --- a/fuzz/CMakeLists.txt +++ b/fuzz/CMakeLists.txt @@ -162,6 +162,7 @@ set(CORPUS_OTHER 440599107.fuzz 440747125.fuzz 4720043549327360.fuzz + 4876793183272960.fuzz 5109284021272576.fuzz 5344352869351424.fuzz 5828408539152384.fuzz diff --git a/fuzz/qpdf_extra/4876793183272960.fuzz b/fuzz/qpdf_extra/4876793183272960.fuzz new file mode 100644 index 0000000..f4c77f6 Binary files /dev/null and b/fuzz/qpdf_extra/4876793183272960.fuzz differ diff --git a/fuzz/qtest/fuzz.test b/fuzz/qtest/fuzz.test index 3acd790..8925369 100644 --- a/fuzz/qtest/fuzz.test +++ b/fuzz/qtest/fuzz.test @@ -11,7 +11,7 @@ my $td = new TestDriver('fuzz'); my $qpdf_corpus = $ENV{'QPDF_FUZZ_CORPUS'} || die "must set QPDF_FUZZ_CORPUS"; -my $n_qpdf_files = 105; # increment when adding new files +my $n_qpdf_files = 106; # increment when adding new files my @fuzzers = ( ['ascii85' => 1], diff --git a/libqpdf/QPDF_objects.cc b/libqpdf/QPDF_objects.cc index 388a221..800a182 100644 --- a/libqpdf/QPDF_objects.cc +++ b/libqpdf/QPDF_objects.cc @@ -533,7 +533,7 @@ Objects::read_xref(qpdf_offset_t xref_offset, bool in_stream_recovery) max_obj = std::max(max_obj, *(m->deleted_objects.rbegin())); } if (size < 1 || (size - 1) != max_obj) { - if ((size - 2) == max_obj) { //&& qpdf.getObject(max_obj, 0).isStreamOfType("/XRef")) { + if (size == (max_obj + 2) && qpdf.getObject(max_obj +1, 0).isStreamOfType("/XRef")) { warn(damagedPDF( "", -1, diff --git a/qpdf/qtest/error-condition.test b/qpdf/qtest/error-condition.test index 0f31f67..66b317a 100644 --- a/qpdf/qtest/error-condition.test +++ b/qpdf/qtest/error-condition.test @@ -56,6 +56,7 @@ my @badfiles = ("not a PDF file", # 1 "space before xref", # 37 "startxref to space then eof", # 38 "stream lenth revocery overlapping", # 39 + "xref stream no entry for self", # 40 ); $n_tests += @badfiles + 8; @@ -66,7 +67,7 @@ $n_tests += @badfiles + 8; # have error conditions that used to be fatal but are now considered # non-fatal. my %badtest_overrides = (); -for(6, 12..15, 17, 18..32, 34..37, 39) +for(6, 12..15, 17, 18..32, 34..37, 39, 40) { $badtest_overrides{$_} = 0; } diff --git a/qpdf/qtest/qpdf/bad12-recover.out b/qpdf/qtest/qpdf/bad12-recover.out index 43ccd2a..428460f 100644 --- a/qpdf/qtest/qpdf/bad12-recover.out +++ b/qpdf/qtest/qpdf/bad12-recover.out @@ -1,4 +1,4 @@ -WARNING: bad12.pdf: xref entry for the xref stream itself is missing - a common error handled correctly by qpdf and most other applications +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 direct and has type null (2) diff --git a/qpdf/qtest/qpdf/bad12.out b/qpdf/qtest/qpdf/bad12.out index c89d599..8904a33 100644 --- a/qpdf/qtest/qpdf/bad12.out +++ b/qpdf/qtest/qpdf/bad12.out @@ -1,4 +1,4 @@ -WARNING: bad12.pdf: xref entry for the xref stream itself is missing - a common error handled correctly by qpdf and most other applications +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 direct and has type null (2) diff --git a/qpdf/qtest/qpdf/bad40-recover.out b/qpdf/qtest/qpdf/bad40-recover.out new file mode 100644 index 0000000..99dcd62 --- /dev/null +++ b/qpdf/qtest/qpdf/bad40-recover.out @@ -0,0 +1,8 @@ +WARNING: bad40.pdf: xref entry for the xref stream itself is missing - a common error handled correctly by qpdf and most other applications +WARNING: bad40.pdf object stream 1 (object 1 0, offset 0): object stream claims to contain itself +/QTest is implicit +/QTest is direct and has type null (2) +/QTest is null +unparse: null +unparseResolved: null +test 1 done diff --git a/qpdf/qtest/qpdf/bad40.out b/qpdf/qtest/qpdf/bad40.out new file mode 100644 index 0000000..879a734 --- /dev/null +++ b/qpdf/qtest/qpdf/bad40.out @@ -0,0 +1,8 @@ +WARNING: bad40.pdf: xref entry for the xref stream itself is missing - a common error handled correctly by qpdf and most other applications +WARNING: bad40.pdf object stream 1 (object 1 0, offset 0): object stream claims to contain itself +/QTest is implicit +/QTest is direct and has type null (2) +/QTest is null +unparse: null +unparseResolved: null +test 0 done diff --git a/qpdf/qtest/qpdf/bad40.pdf b/qpdf/qtest/qpdf/bad40.pdf new file mode 100644 index 0000000..357844e Binary files /dev/null and b/qpdf/qtest/qpdf/bad40.pdf differ -- libgit2 0.21.4