Commit a59e7ac7ec1ab018bf28518c065d8c86773db339

Authored by Jay Berkenbilt
1 parent da0b0e40

Disable copying/assigning to QPDF objects, add QPDF::create()

ChangeLog
  1 +2022-09-02 Jay Berkenbilt <ejb@ql.org>
  2 +
  3 + * Add new QPDF::create() factory method that returns
  4 + std::shared_ptr<QPDF>.
  5 +
  6 + * Prevent copying/assigning to QPDF objects in the API. It has
  7 + never been safe to do this, but the API wasn't preventing it.
  8 +
1 9 2022-09-01 Jay Berkenbilt <ejb@ql.org>
2 10  
3 11 * Remove QPDFObject.hh from include/qpdf. The only reason to
... ...
... ... @@ -4,8 +4,6 @@ Next
4 4  
5 5 Before Release:
6 6  
7   -* Consider a transition symbol for deprecation of stack-allocated QPDF
8   - objects and also make QPDF non-copiable.
9 7 * Evaluate issues tagged with `next`
10 8 * Stay on top of https://github.com/pikepdf/pikepdf/pull/315
11 9 * Consider whether otherwise unreferenced object streams should be
... ...
fuzz/qpdf_fuzzer.cc
... ... @@ -55,7 +55,7 @@ FuzzHelper::getQpdf()
55 55 {
56 56 auto is = std::shared_ptr<InputSource>(
57 57 new BufferInputSource("fuzz input", &this->input_buffer));
58   - auto qpdf = std::make_shared<QPDF>();
  58 + auto qpdf = QPDF::create();
59 59 qpdf->processInputSource(is);
60 60 return qpdf;
61 61 }
... ...
include/qpdf/QPDF.hh
... ... @@ -64,6 +64,9 @@ class QPDF
64 64 QPDF_DLL
65 65 ~QPDF();
66 66  
  67 + QPDF_DLL
  68 + static std::shared_ptr<QPDF> create();
  69 +
67 70 // Associate a file with a QPDF object and do initial parsing of
68 71 // the file. PDF objects are not read until they are needed. A
69 72 // QPDF object may be associated with only one file in its
... ... @@ -929,6 +932,15 @@ class QPDF
929 932 static bool test_json_validators();
930 933  
931 934 private:
  935 + // It has never been safe to copy QPDF objects as there is code in
  936 + // the library that assumes there are no copies of a QPDF object.
  937 + // Copying QPDF objects was not prevented by the API until qpdf
  938 + // 11. If you have been copying QPDF objects, use
  939 + // std::shared_ptr<QPDF> instead. From qpdf 11, you can use
  940 + // QPDF::create to create them.
  941 + QPDF(QPDF const&) = delete;
  942 + QPDF& operator=(QPDF const&) = delete;
  943 +
932 944 static std::string const qpdf_version;
933 945  
934 946 class ObjCache
... ...
libqpdf/QPDF.cc
... ... @@ -264,6 +264,12 @@ QPDF::~QPDF()
264 264 }
265 265 }
266 266  
  267 +std::shared_ptr<QPDF>
  268 +QPDF::create()
  269 +{
  270 + return std::make_shared<QPDF>();
  271 +}
  272 +
267 273 void
268 274 QPDF::processFile(char const* filename, char const* password)
269 275 {
... ...
libqpdf/QPDFJob.cc
... ... @@ -1981,7 +1981,7 @@ QPDFJob::doProcessOnce(
1981 1981 bool used_for_input,
1982 1982 bool main_input)
1983 1983 {
1984   - auto pdf = std::make_shared<QPDF>();
  1984 + auto pdf = QPDF::create();
1985 1985 setQPDFOptions(*pdf);
1986 1986 if (empty) {
1987 1987 pdf->emptyPDF();
... ...
libqpdf/qpdf-c.cc
... ... @@ -148,7 +148,7 @@ qpdf_init()
148 148 {
149 149 QTC::TC("qpdf", "qpdf-c called qpdf_init");
150 150 qpdf_data qpdf = new _qpdf_data();
151   - qpdf->qpdf = std::make_shared<QPDF>();
  151 + qpdf->qpdf = QPDF::create();
152 152 return qpdf;
153 153 }
154 154  
... ...
manual/release-notes.rst
... ... @@ -139,11 +139,18 @@ For a detailed list of changes, please see the file
139 139 - See :ref:`breaking-crypto-api` for specific details, and see
140 140 :ref:`weak-crypto` for a general discussion.
141 141  
142   - - QPDFObjectHandle::warnIfPossible no longer takes an optional
  142 + - ``QPDFObjectHandle::warnIfPossible`` no longer takes an optional
143 143 argument to throw an exception if there is no description. If
144 144 there is no description, it writes to the default logger's error
145 145 stream.
146 146  
  147 + - ``QPDF`` objects can no longer be copied or assigned to. It has
  148 + never been safe to do this because of assumptions made by
  149 + library code. Now it is prevented by the API. If you run into
  150 + trouble, use ``QPDF::create()`` to create ``QPDF`` shared
  151 + pointers (or create them in some other way if you need backward
  152 + compatibility with older qpdf versions).
  153 +
147 154 - CLI Enhancements
148 155  
149 156 - ``qpdf --list-attachments --verbose`` include some additional
... ... @@ -196,6 +203,9 @@ For a detailed list of changes, please see the file
196 203 generally not happen for correct code, but at least the
197 204 situation is detectible now.
198 205  
  206 + - Add new factory method ``QPDF::create()`` that returns a
  207 + ``std::shared_ptr<QPDF>``.
  208 +
199 209 - Add new ``Pipeline`` methods to reduce the amount of casting that is
200 210 needed:
201 211  
... ...
qpdf/test_driver.cc
... ... @@ -3262,12 +3262,12 @@ static void
3262 3262 test_92(QPDF& pdf, char const* arg2)
3263 3263 {
3264 3264 // Exercise indirect objects owned by destroyed QPDF object.
3265   - QPDF* qpdf = new QPDF();
  3265 + auto qpdf = QPDF::create();
3266 3266 qpdf->emptyPDF();
3267 3267 auto root = qpdf->getRoot();
3268 3268 assert(root.getOwningQPDF() != nullptr);
3269 3269 assert(root.isIndirect());
3270   - delete qpdf;
  3270 + qpdf = nullptr;
3271 3271 assert(root.getOwningQPDF() == nullptr);
3272 3272 assert(!root.isIndirect());
3273 3273 }
... ...