diff --git a/fuzz/CMakeLists.txt b/fuzz/CMakeLists.txt index 944920e0..5857dc32 100644 --- a/fuzz/CMakeLists.txt +++ b/fuzz/CMakeLists.txt @@ -129,6 +129,7 @@ set(CORPUS_OTHER 69977b.fuzz 69977c.fuzz 69977d.fuzz + 69977e.fuzz 70055.fuzz 70245.fuzz 70306.fuzz diff --git a/fuzz/qpdf_extra/69977e.fuzz b/fuzz/qpdf_extra/69977e.fuzz new file mode 100644 index 00000000..4e2f534b Binary files /dev/null and b/fuzz/qpdf_extra/69977e.fuzz differ diff --git a/fuzz/qtest/fuzz.test b/fuzz/qtest/fuzz.test index eb9123b6..92f44cda 100644 --- a/fuzz/qtest/fuzz.test +++ b/fuzz/qtest/fuzz.test @@ -21,7 +21,7 @@ my @fuzzers = ( ['pngpredictor' => 1], ['runlength' => 6], ['tiffpredictor' => 2], - ['qpdf' => 74], # increment when adding new files + ['qpdf' => 75], # increment when adding new files ); my $n_tests = 0; diff --git a/include/qpdf/Pl_RunLength.hh b/include/qpdf/Pl_RunLength.hh index 5f5c7ab3..4ee8fba0 100644 --- a/include/qpdf/Pl_RunLength.hh +++ b/include/qpdf/Pl_RunLength.hh @@ -62,6 +62,7 @@ class QPDF_DLL_CLASS Pl_RunLength: public Pipeline state_e state; unsigned char buf[128]; unsigned int length; + std::string out; }; std::shared_ptr m; diff --git a/libqpdf/Pl_RunLength.cc b/libqpdf/Pl_RunLength.cc index 0d3bba2c..1031eb88 100644 --- a/libqpdf/Pl_RunLength.cc +++ b/libqpdf/Pl_RunLength.cc @@ -66,8 +66,9 @@ Pl_RunLength::encode(unsigned char const* data, size_t len) void Pl_RunLength::decode(unsigned char const* data, size_t len) { + m->out.reserve(len); for (size_t i = 0; i < len; ++i) { - unsigned char ch = data[i]; + unsigned char const& ch = data[i]; switch (m->state) { case st_top: if (ch < 128) { @@ -85,16 +86,14 @@ Pl_RunLength::decode(unsigned char const* data, size_t len) break; case st_copying: - this->getNext()->write(&ch, 1); + m->out.append(1, static_cast(ch)); if (--m->length == 0) { m->state = st_top; } break; case st_run: - for (unsigned int j = 0; j < m->length; ++j) { - this->getNext()->write(&ch, 1); - } + m->out.append(m->length, static_cast(ch)); m->state = st_top; break; } @@ -137,10 +136,13 @@ Pl_RunLength::finish() // When decoding, we might have read a length byte not followed by data, which means the stream // was terminated early, but we will just ignore this case since this is the only sensible thing // to do. + auto next = getNext(); if (m->action == a_encode) { flush_encode(); unsigned char ch = 128; - this->getNext()->write(&ch, 1); + next->write(&ch, 1); + } else { + next->writeString(m->out); } - this->getNext()->finish(); + next->finish(); }