Commit 6fe7b704c7dfb517e4de20fb25536fab1de83d56

Authored by Jay Berkenbilt
1 parent 2c078337

Warn rather than segv on access after closing input source (fixes #495)

ChangeLog
  1 +2021-01-06 Jay Berkenbilt <ejb@ql.org>
  2 +
  3 + * Give warnings instead of segfaulting if a QPDF operation is
  4 + attempted after calling closeInputSource(). Fixes #495.
  5 +
1 2021-01-05 Jay Berkenbilt <ejb@ql.org> 6 2021-01-05 Jay Berkenbilt <ejb@ql.org>
2 7
3 * 10.1.0: release 8 * 10.1.0: release
libqpdf/QPDF.cc
@@ -45,6 +45,51 @@ static char const* EMPTY_PDF = @@ -45,6 +45,51 @@ static char const* EMPTY_PDF =
45 "110\n" 45 "110\n"
46 "%%EOF\n"; 46 "%%EOF\n";
47 47
  48 +class InvalidInputSource: public InputSource
  49 +{
  50 + public:
  51 + virtual ~InvalidInputSource() = default;
  52 + virtual qpdf_offset_t findAndSkipNextEOL() override
  53 + {
  54 + throwException();
  55 + return 0;
  56 + }
  57 + virtual std::string const& getName() const override
  58 + {
  59 + static std::string name("closed input source");
  60 + return name;
  61 + }
  62 + virtual qpdf_offset_t tell() override
  63 + {
  64 + throwException();
  65 + return 0;
  66 + }
  67 + virtual void seek(qpdf_offset_t offset, int whence) override
  68 + {
  69 + throwException();
  70 + }
  71 + virtual void rewind() override
  72 + {
  73 + throwException();
  74 + }
  75 + virtual size_t read(char* buffer, size_t length) override
  76 + {
  77 + throwException();
  78 + return 0;
  79 + }
  80 + virtual void unreadCh(char ch) override
  81 + {
  82 + throwException();
  83 + }
  84 +
  85 + private:
  86 + void throwException()
  87 + {
  88 + throw std::runtime_error(
  89 + "QPDF operation attempted after closing input source");
  90 + }
  91 +};
  92 +
48 QPDF::ForeignStreamData::ForeignStreamData( 93 QPDF::ForeignStreamData::ForeignStreamData(
49 PointerHolder<EncryptionParameters> encp, 94 PointerHolder<EncryptionParameters> encp,
50 PointerHolder<InputSource> file, 95 PointerHolder<InputSource> file,
@@ -254,7 +299,7 @@ QPDF::processInputSource(PointerHolder&lt;InputSource&gt; source, @@ -254,7 +299,7 @@ QPDF::processInputSource(PointerHolder&lt;InputSource&gt; source,
254 void 299 void
255 QPDF::closeInputSource() 300 QPDF::closeInputSource()
256 { 301 {
257 - this->m->file = 0; 302 + this->m->file = new InvalidInputSource();
258 } 303 }
259 304
260 void 305 void
qpdf/qtest/qpdf.test
@@ -1215,7 +1215,13 @@ $td-&gt;runtest(&quot;check output&quot;, @@ -1215,7 +1215,13 @@ $td-&gt;runtest(&quot;check output&quot;,
1215 show_ntests(); 1215 show_ntests();
1216 # ---------- 1216 # ----------
1217 $td->notify("--- Invalid objects ---"); 1217 $td->notify("--- Invalid objects ---");
1218 -$n_tests += 2; 1218 +$n_tests += 3;
  1219 +
  1220 +$td->runtest("closed input source",
  1221 + {$td->COMMAND => "test_driver 73 minimal.pdf"},
  1222 + {$td->FILE => "test73.out",
  1223 + $td->EXIT_STATUS => 0},
  1224 + $td->NORMALIZE_NEWLINES);
1219 1225
1220 $td->runtest("empty object", 1226 $td->runtest("empty object",
1221 {$td->COMMAND => "qpdf -show-object=7,0 empty-object.pdf"}, 1227 {$td->COMMAND => "qpdf -show-object=7,0 empty-object.pdf"},
qpdf/qtest/qpdf/test73.out 0 → 100644
  1 +WARNING: closed input source: object 2/0: error reading object: QPDF operation attempted after closing input source
  2 +test 73 done
qpdf/test_driver.cc
@@ -2300,6 +2300,11 @@ void runtest(int n, char const* filename1, char const* arg2) @@ -2300,6 +2300,11 @@ void runtest(int n, char const* filename1, char const* arg2)
2300 buf->getSize()); 2300 buf->getSize());
2301 assert(s.find("/bye") != std::string::npos); 2301 assert(s.find("/bye") != std::string::npos);
2302 } 2302 }
  2303 + else if (n == 73)
  2304 + {
  2305 + pdf.closeInputSource();
  2306 + pdf.getRoot().getKey("/Pages").unparseResolved();
  2307 + }
2303 else 2308 else
2304 { 2309 {
2305 throw std::runtime_error(std::string("invalid test ") + 2310 throw std::runtime_error(std::string("invalid test ") +