Commit c7a4967d10fb9688f235baa8e57a1fb578f5387d

Authored by Jay Berkenbilt
1 parent dba61da1

Change reset to disconnect and clarify comments

I decided that it's actually fine to copy a direct object to another
QPDF. Even if we eventually prevent a QPDFObject from having multiple
parents, this could happen if an object is moved.
... ... @@ -785,7 +785,7 @@ Rejected Ideas
785 785 and too much toil for library users to be worth the small benefit of
786 786 not having to call resetObjGen in QPDF's destructor.
787 787  
788   -* Fix Multiple Direct Object Owner Issue
  788 +* Fix Multiple Direct Object Parent Issue
789 789  
790 790 These are some ideas I had before m-holger's changes to split
791 791 QPDFValue from QPDFObject. These notes were written prior to the
... ... @@ -811,12 +811,3 @@ Rejected Ideas
811 811 Note that arrays and dictionaries still need to contain
812 812 QPDFObjectHandle because of indirect objects. This only pertains to
813 813 direct objects, which are always "resolved" in QPDFObjectHandle.
814   -
815   - If this is addressed, read comments in the following places:
816   - * QPDFWriter.cc::enqueueObject near the call to getOwningQPDF
817   - * QPDFValueProxy::reset and QPDFValueProxy::destroy
818   - * QPDF::~QPDF()
819   - * test 92 in test_driver.cc
820   - * QPDFObjectHandle.hh near isDestroyed
821   - All these references were from the release of qpdf 11 (in case they
822   - have moved by such time as this might be resurrected).
... ...
include/qpdf/QPDFObjectHandle.hh
... ... @@ -392,7 +392,8 @@ class QPDFObjectHandle
392 392 inline bool isIndirect() const;
393 393  
394 394 // This returns true for indirect objects from a QPDF that has
395   - // been destroyed.
  395 + // been destroyed. Trying unparse such an object will throw a
  396 + // logic_error.
396 397 QPDF_DLL
397 398 bool isDestroyed();
398 399  
... ... @@ -1540,8 +1541,8 @@ class QPDFObjectHandle
1540 1541 friend class ObjAccessor;
1541 1542  
1542 1543 // Provide access to specific classes for recursive
1543   - // reset().
1544   - class Resetter
  1544 + // disconnected().
  1545 + class DisconnectAccess
1545 1546 {
1546 1547 friend class QPDF_Dictionary;
1547 1548 friend class QPDF_Stream;
... ... @@ -1549,9 +1550,9 @@ class QPDFObjectHandle
1549 1550  
1550 1551 private:
1551 1552 static void
1552   - reset(QPDFObjectHandle& o)
  1553 + disconnect(QPDFObjectHandle& o)
1553 1554 {
1554   - o.reset();
  1555 + o.disconnect();
1555 1556 }
1556 1557 };
1557 1558 friend class Resetter;
... ... @@ -1653,7 +1654,7 @@ class QPDFObjectHandle
1653 1654 bool first_level_only,
1654 1655 bool stop_at_streams);
1655 1656 void shallowCopyInternal(QPDFObjectHandle& oh, bool first_level_only);
1656   - void reset();
  1657 + void disconnect();
1657 1658 void setParsedOffset(qpdf_offset_t offset);
1658 1659 void parseContentStream_internal(
1659 1660 std::string const& description, ParserCallbacks* callbacks);
... ...
libqpdf/QPDF.cc
... ... @@ -252,9 +252,11 @@ QPDF::~QPDF()
252 252 // resolved indirect references by replacing them with an internal
253 253 // object type representing that they have been destroyed. Note
254 254 // that we can't break references like this at any time when the
255   - // QPDF object is active. The call to reset also causes all
  255 + // QPDF object is active. The call to reset also causes all direct
256 256 // QPDFObjectHandle objects that are reachable from this object to
257   - // release their association with this QPDF.
  257 + // release their association with this QPDF. Direct objects are
  258 + // not destroyed since they can be moved to other QPDF objects
  259 + // safely.
258 260  
259 261 // At this point, obviously no one is still using the QPDF object,
260 262 // but we'll explicitly clear the xref table anyway just to
... ... @@ -262,9 +264,7 @@ QPDF::~QPDF()
262 264 this->m->xref_table.clear();
263 265 auto null_obj = QPDF_Null::create();
264 266 for (auto const& iter: this->m->obj_cache) {
265   - iter.second.object->reset();
266   - // It would be better if reset() could call destroy(), but it
267   - // can't -- see comments in QPDFValueProxy::reset().
  267 + iter.second.object->disconnect();
268 268 iter.second.object->destroy();
269 269 }
270 270 }
... ...
libqpdf/QPDFObjectHandle.cc
... ... @@ -249,7 +249,7 @@ QPDFObjectHandle::operator!=(QPDFObjectHandle const& rhs) const
249 249 }
250 250  
251 251 void
252   -QPDFObjectHandle::reset()
  252 +QPDFObjectHandle::disconnect()
253 253 {
254 254 // Recursively remove association with any QPDF object. This
255 255 // method may only be called during final destruction.
... ... @@ -257,7 +257,7 @@ QPDFObjectHandle::reset()
257 257 // pointer itself, so we don't do that here. Other objects call it
258 258 // through this method.
259 259 if (!isIndirect()) {
260   - this->obj->reset();
  260 + this->obj->disconnect();
261 261 }
262 262 }
263 263  
... ...
libqpdf/QPDFValueProxy.cc
... ... @@ -13,6 +13,5 @@ QPDFValueProxy::doResolve()
13 13 void
14 14 QPDFValueProxy::destroy()
15 15 {
16   - // See comments in reset() for why this isn't part of reset.
17 16 value = QPDF_Destroyed::getInstance();
18 17 }
... ...
libqpdf/QPDFWriter.cc
... ... @@ -1198,14 +1198,12 @@ void
1198 1198 QPDFWriter::enqueueObject(QPDFObjectHandle object)
1199 1199 {
1200 1200 if (object.isIndirect()) {
1201   - // This owner check should really be done for all objects, not
1202   - // just indirect objects. As of the time of the release of
1203   - // qpdf 11, it is known that there are cases of direct objects
1204   - // from other files getting copied into multiple QPDF objects.
1205   - // This definitely happens in the page splitting code. If we
1206   - // were to implement strong checks to prevent objects from
1207   - // having multiple owners, once that was complete phased in,
1208   - // this check could be moved outside the if statement.
  1201 + // This owner check can only be done for indirect objects. It
  1202 + // is possible for a direct object to have an owning QPDF that
  1203 + // is from another file if a direct QPDFObjectHandle from one
  1204 + // file was insert into another file without copying. Doing
  1205 + // that is safe even if the original QPDF gets destroyed,
  1206 + // which just disconnects the QPDFObjectHandle from its owner.
1209 1207 if (object.getOwningQPDF() != &(this->m->pdf)) {
1210 1208 QTC::TC("qpdf", "QPDFWriter foreign object");
1211 1209 throw std::logic_error(
... ...
libqpdf/QPDF_Array.cc
... ... @@ -35,9 +35,9 @@ QPDF_Array::shallowCopy()
35 35 }
36 36  
37 37 void
38   -QPDF_Array::reset()
  38 +QPDF_Array::disconnect()
39 39 {
40   - elements.reset();
  40 + elements.disconnect();
41 41 }
42 42  
43 43 std::string
... ...
libqpdf/QPDF_Dictionary.cc
... ... @@ -22,10 +22,10 @@ QPDF_Dictionary::shallowCopy()
22 22 }
23 23  
24 24 void
25   -QPDF_Dictionary::reset()
  25 +QPDF_Dictionary::disconnect()
26 26 {
27 27 for (auto& iter: this->items) {
28   - QPDFObjectHandle::Resetter::reset(iter.second);
  28 + QPDFObjectHandle::DisconnectAccess::disconnect(iter.second);
29 29 }
30 30 }
31 31  
... ...
libqpdf/QPDF_Stream.cc
... ... @@ -168,10 +168,10 @@ QPDF_Stream::getFilterOnWrite() const
168 168 }
169 169  
170 170 void
171   -QPDF_Stream::reset()
  171 +QPDF_Stream::disconnect()
172 172 {
173 173 this->stream_provider = nullptr;
174   - QPDFObjectHandle::Resetter::reset(this->stream_dict);
  174 + QPDFObjectHandle::DisconnectAccess::disconnect(this->stream_dict);
175 175 }
176 176  
177 177 void
... ...
libqpdf/SparseOHArray.cc
... ... @@ -49,10 +49,10 @@ SparseOHArray::remove_last()
49 49 }
50 50  
51 51 void
52   -SparseOHArray::reset()
  52 +SparseOHArray::disconnect()
53 53 {
54 54 for (auto& iter: this->elements) {
55   - QPDFObjectHandle::Resetter::reset(iter.second);
  55 + QPDFObjectHandle::DisconnectAccess::disconnect(iter.second);
56 56 }
57 57 }
58 58  
... ...
libqpdf/qpdf/QPDFValue.hh
... ... @@ -64,7 +64,7 @@ class QPDFValue
64 64 return og;
65 65 }
66 66 virtual void
67   - reset()
  67 + disconnect()
68 68 {
69 69 }
70 70  
... ...
libqpdf/qpdf/QPDFValueProxy.hh
... ... @@ -102,33 +102,24 @@ class QPDFValueProxy
102 102 o->value->og = og;
103 103 }
104 104  
105   - // The following two methods are for use by class QPDF only
106 105 void
107 106 setObjGen(QPDF* qpdf, QPDFObjGen const& og)
108 107 {
  108 + // Intended for use by the QPDF class
109 109 value->qpdf = qpdf;
110 110 value->og = og;
111 111 }
112 112 void
113   - reset()
114   - {
115   - value->reset();
116   - // It would be better if, rather than clearing value->qpdf and
117   - // value->og, we completely replaced value with
118   - // QPDF_Destroyed. However, at the time of the release of qpdf
119   - // 11, this causes test failures and would likely break a lot
120   - // of code since it possible for a direct object that
121   - // recursively contains no indirect objects to be copied into
122   - // multiple QPDF objects. For that reason, we have to break
123   - // the association with the owning QPDF but not otherwise
124   - // mutate the object. For indirect objects, QPDF::~QPDF
125   - // replaces indirect objects with QPDF_Destroyed, which clears
126   - // circular references. If this code were able to do that,
127   - // that code would not have to.
  113 + disconnect()
  114 + {
  115 + // Disconnect an object from its owning QPDF. This is called
  116 + // by QPDF's destructor.
  117 + value->disconnect();
128 118 value->qpdf = nullptr;
129 119 value->og = QPDFObjGen();
130 120 }
131   -
  121 + // Mark an object as destroyed. Used by QPDF's destructor for its
  122 + // indirect objects.
132 123 void destroy();
133 124  
134 125 bool
... ...
libqpdf/qpdf/QPDF_Array.hh
... ... @@ -17,7 +17,7 @@ class QPDF_Array: public QPDFValue
17 17 virtual std::shared_ptr<QPDFValueProxy> shallowCopy();
18 18 virtual std::string unparse();
19 19 virtual JSON getJSON(int json_version);
20   - virtual void reset();
  20 + virtual void disconnect();
21 21  
22 22 int getNItems() const;
23 23 QPDFObjectHandle getItem(int n) const;
... ...
libqpdf/qpdf/QPDF_Dictionary.hh
... ... @@ -17,7 +17,7 @@ class QPDF_Dictionary: public QPDFValue
17 17 virtual std::shared_ptr<QPDFValueProxy> shallowCopy();
18 18 virtual std::string unparse();
19 19 virtual JSON getJSON(int json_version);
20   - virtual void reset();
  20 + virtual void disconnect();
21 21  
22 22 // hasKey() and getKeys() treat keys with null values as if they
23 23 // aren't there. getKey() returns null for the value of a
... ...
libqpdf/qpdf/QPDF_Stream.hh
... ... @@ -27,7 +27,7 @@ class QPDF_Stream: public QPDFValue
27 27 virtual std::string unparse();
28 28 virtual JSON getJSON(int json_version);
29 29 virtual void setDescription(QPDF*, std::string const&);
30   - virtual void reset();
  30 + virtual void disconnect();
31 31 QPDFObjectHandle getDict() const;
32 32 bool isDataModified() const;
33 33 void setFilterOnWrite(bool);
... ...
libqpdf/qpdf/SparseOHArray.hh
... ... @@ -15,7 +15,7 @@ class SparseOHArray
15 15 void setAt(size_t idx, QPDFObjectHandle oh);
16 16 void erase(size_t idx);
17 17 void insert(size_t idx, QPDFObjectHandle oh);
18   - void reset();
  18 + void disconnect();
19 19  
20 20 typedef std::unordered_map<size_t, QPDFObjectHandle>::const_iterator
21 21 const_iterator;
... ...
qpdf/test_driver.cc
... ... @@ -3316,8 +3316,8 @@ test_92(QPDF&amp; pdf, char const* arg2)
3316 3316 check(contents);
3317 3317 check(contents_dict);
3318 3318 // Objects that were originally indirect should be destroyed.
3319   - // Otherwise, they should have retained their old values. See
3320   - // comments in QPDFValueProxy::reset for why this is the case.
  3319 + // Otherwise, they should have retained their old values but just
  3320 + // lost their connection to the owning QPDF.
3321 3321 assert(root.isDestroyed());
3322 3322 assert(page1.isDestroyed());
3323 3323 assert(contents.isDestroyed());
... ...