Commit 46611f0710fa08f1a90134a84cfccec3a1e49f94

Authored by Jay Berkenbilt
1 parent 8fe0b06c

Prevent a division by zero error (fixes #141)

Bad /W in an xref stream could cause a division by zero error. Now
this is handled as a special case.
libqpdf/QPDF.cc
@@ -917,6 +917,13 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj) @@ -917,6 +917,13 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj)
917 } 917 }
918 entry_size += W[i]; 918 entry_size += W[i];
919 } 919 }
  920 + if (entry_size == 0)
  921 + {
  922 + throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
  923 + "xref stream", xref_offset,
  924 + "Cross-reference stream's /W indicates"
  925 + " entry size of 0");
  926 + }
920 long long max_num_entries = 927 long long max_num_entries =
921 static_cast<unsigned long long>(-1) / entry_size; 928 static_cast<unsigned long long>(-1) / entry_size;
922 929
libqpdf/QPDFWriter.cc
@@ -2056,6 +2056,10 @@ QPDFWriter::generateObjectStreams() @@ -2056,6 +2056,10 @@ QPDFWriter::generateObjectStreams()
2056 std::vector<QPDFObjGen> const& eligible = 2056 std::vector<QPDFObjGen> const& eligible =
2057 QPDF::Writer::getCompressibleObjGens(this->pdf); 2057 QPDF::Writer::getCompressibleObjGens(this->pdf);
2058 unsigned int n_object_streams = (eligible.size() + 99) / 100; 2058 unsigned int n_object_streams = (eligible.size() + 99) / 100;
  2059 + if (n_object_streams == 0)
  2060 + {
  2061 + throw std::logic_error("n_object_streams == 0");
  2062 + }
2059 unsigned int n_per = eligible.size() / n_object_streams; 2063 unsigned int n_per = eligible.size() / n_object_streams;
2060 if (n_per * n_object_streams < eligible.size()) 2064 if (n_per * n_object_streams < eligible.size())
2061 { 2065 {
qpdf/qtest/qpdf.test
@@ -218,6 +218,8 @@ my @bug_tests = ( @@ -218,6 +218,8 @@ my @bug_tests = (
218 ["119", "other infinite loop", 3], 218 ["119", "other infinite loop", 3],
219 ["120", "other infinite loop", 3], 219 ["120", "other infinite loop", 3],
220 ["106", "zlib data error", 3], 220 ["106", "zlib data error", 3],
  221 + ["141a", "/W entry size 0", 2],
  222 + ["141b", "/W entry size 0", 2],
221 ); 223 );
222 $n_tests += scalar(@bug_tests); 224 $n_tests += scalar(@bug_tests);
223 foreach my $d (@bug_tests) 225 foreach my $d (@bug_tests)
qpdf/qtest/qpdf/issue-141a.out 0 → 100644
  1 +WARNING: issue-141a.pdf: can't find PDF header
  2 +WARNING: issue-141a.pdf (xref stream: object 9 0, file position 10): stream dictionary lacks /Length key
  3 +WARNING: issue-141a.pdf (xref stream: object 9 0, file position 47): attempting to recover stream length
  4 +WARNING: issue-141a.pdf (xref stream: object 9 0, file position 47): unable to recover stream data; treating stream as empty
  5 +WARNING: issue-141a.pdf: file is damaged
  6 +WARNING: issue-141a.pdf (xref stream, file position 3): Cross-reference stream's /W indicates entry size of 0
  7 +WARNING: issue-141a.pdf: Attempting to reconstruct cross-reference table
  8 +issue-141a.pdf: unable to find trailer dictionary while recovering damaged file
qpdf/qtest/qpdf/issue-141a.pdf 0 → 100644
  1 +0009 0 obj<</Type/XRef/Size 0/W[0 0 0]>>stream
  2 +endstream
  3 +endobj
  4 +startxref
  5 +3
  6 +%%EOF
qpdf/qtest/qpdf/issue-141b.out 0 → 100644
  1 +WARNING: issue-141b.pdf: can't find PDF header
  2 +WARNING: issue-141b.pdf: file is damaged
  3 +WARNING: issue-141b.pdf (file position 7): xref not found
  4 +WARNING: issue-141b.pdf: Attempting to reconstruct cross-reference table
  5 +issue-141b.pdf: unable to find trailer dictionary while recovering damaged file
qpdf/qtest/qpdf/issue-141b.pdf 0 → 100644
  1 +%PDF-100 0 obj<</Type/XRef/Size 0/[]/W[0 0 0]/ 0>>stream
  2 +0endstream
  3 +endobj
  4 +startxref
  5 +7
  6 +%%EOF
0 \ No newline at end of file 7 \ No newline at end of file