aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJay Berkenbilt <ejb@ql.org>2021-01-06 15:49:10 +0100
committerJay Berkenbilt <ejb@ql.org>2021-01-06 16:11:34 +0100
commit6fe7b704c7dfb517e4de20fb25536fab1de83d56 (patch)
tree5c2c15a93944ba01dc609197dfad1d7a823eae51
parent2c078337fa77e26554be817ead3cd080f31f6e9b (diff)
downloadqpdf-6fe7b704c7dfb517e4de20fb25536fab1de83d56.tar.zst
Warn rather than segv on access after closing input source (fixes #495)
-rw-r--r--ChangeLog5
-rw-r--r--libqpdf/QPDF.cc47
-rw-r--r--qpdf/qtest/qpdf.test8
-rw-r--r--qpdf/qtest/qpdf/test73.out2
-rw-r--r--qpdf/test_driver.cc5
5 files changed, 65 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index 77dc7b73..cd0a0e02 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2021-01-06 Jay Berkenbilt <ejb@ql.org>
+
+ * Give warnings instead of segfaulting if a QPDF operation is
+ attempted after calling closeInputSource(). Fixes #495.
+
2021-01-05 Jay Berkenbilt <ejb@ql.org>
* 10.1.0: release
diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc
index 29508a40..34f15706 100644
--- a/libqpdf/QPDF.cc
+++ b/libqpdf/QPDF.cc
@@ -45,6 +45,51 @@ static char const* EMPTY_PDF =
"110\n"
"%%EOF\n";
+class InvalidInputSource: public InputSource
+{
+ public:
+ virtual ~InvalidInputSource() = default;
+ virtual qpdf_offset_t findAndSkipNextEOL() override
+ {
+ throwException();
+ return 0;
+ }
+ virtual std::string const& getName() const override
+ {
+ static std::string name("closed input source");
+ return name;
+ }
+ virtual qpdf_offset_t tell() override
+ {
+ throwException();
+ return 0;
+ }
+ virtual void seek(qpdf_offset_t offset, int whence) override
+ {
+ throwException();
+ }
+ virtual void rewind() override
+ {
+ throwException();
+ }
+ virtual size_t read(char* buffer, size_t length) override
+ {
+ throwException();
+ return 0;
+ }
+ virtual void unreadCh(char ch) override
+ {
+ throwException();
+ }
+
+ private:
+ void throwException()
+ {
+ throw std::runtime_error(
+ "QPDF operation attempted after closing input source");
+ }
+};
+
QPDF::ForeignStreamData::ForeignStreamData(
PointerHolder<EncryptionParameters> encp,
PointerHolder<InputSource> file,
@@ -254,7 +299,7 @@ QPDF::processInputSource(PointerHolder<InputSource> source,
void
QPDF::closeInputSource()
{
- this->m->file = 0;
+ this->m->file = new InvalidInputSource();
}
void
diff --git a/qpdf/qtest/qpdf.test b/qpdf/qtest/qpdf.test
index 83cbacd3..2843adab 100644
--- a/qpdf/qtest/qpdf.test
+++ b/qpdf/qtest/qpdf.test
@@ -1215,7 +1215,13 @@ $td->runtest("check output",
show_ntests();
# ----------
$td->notify("--- Invalid objects ---");
-$n_tests += 2;
+$n_tests += 3;
+
+$td->runtest("closed input source",
+ {$td->COMMAND => "test_driver 73 minimal.pdf"},
+ {$td->FILE => "test73.out",
+ $td->EXIT_STATUS => 0},
+ $td->NORMALIZE_NEWLINES);
$td->runtest("empty object",
{$td->COMMAND => "qpdf -show-object=7,0 empty-object.pdf"},
diff --git a/qpdf/qtest/qpdf/test73.out b/qpdf/qtest/qpdf/test73.out
new file mode 100644
index 00000000..1b7ad0e6
--- /dev/null
+++ b/qpdf/qtest/qpdf/test73.out
@@ -0,0 +1,2 @@
+WARNING: closed input source: object 2/0: error reading object: QPDF operation attempted after closing input source
+test 73 done
diff --git a/qpdf/test_driver.cc b/qpdf/test_driver.cc
index aef46d87..1be7fbaf 100644
--- a/qpdf/test_driver.cc
+++ b/qpdf/test_driver.cc
@@ -2300,6 +2300,11 @@ void runtest(int n, char const* filename1, char const* arg2)
buf->getSize());
assert(s.find("/bye") != std::string::npos);
}
+ else if (n == 73)
+ {
+ pdf.closeInputSource();
+ pdf.getRoot().getKey("/Pages").unparseResolved();
+ }
else
{
throw std::runtime_error(std::string("invalid test ") +