Commit ddd78c1b7f53f09710431d58cd94659271f325cc
1 parent
84cd53f5
Fix QPDFObjectHandle::shallowCopy
It's not really a shallow copy. It just doesn't cross indirect object boundaries. The old implementation had a bug that would cause multiple shallow copies of the same object to share memory, which was not the intention.
Showing
3 changed files
with
54 additions
and
38 deletions
include/qpdf/QPDFObjectHandle.hh
| ... | ... | @@ -514,10 +514,11 @@ class QPDFObjectHandle |
| 514 | 514 | QPDF_DLL |
| 515 | 515 | QPDF* getOwningQPDF(); |
| 516 | 516 | |
| 517 | - // Create a shallow copy of an object as a direct object. Since | |
| 518 | - // this is a shallow copy, for dictionaries and arrays, any keys | |
| 519 | - // or items that were indirect objects will still be indirect | |
| 520 | - // objects that point to the same place. | |
| 517 | + // Create a shallow of an object as a direct object, but do not | |
| 518 | + // traverse across indirect object boundaries. That means that, | |
| 519 | + // for dictionaries and arrays, any keys or items that were | |
| 520 | + // indirect objects will still be indirect objects that point to | |
| 521 | + // the same place. | |
| 521 | 522 | QPDF_DLL |
| 522 | 523 | QPDFObjectHandle shallowCopy(); |
| 523 | 524 | |
| ... | ... | @@ -880,7 +881,7 @@ class QPDFObjectHandle |
| 880 | 881 | void objectWarning(std::string const& warning); |
| 881 | 882 | void assertType(char const* type_name, bool istype); |
| 882 | 883 | void dereference(); |
| 883 | - void makeDirectInternal(std::set<int>& visited); | |
| 884 | + void copyObject(std::set<QPDFObjGen>& visited, bool cross_indirect); | |
| 884 | 885 | void releaseResolved(); |
| 885 | 886 | static void setObjectDescriptionFromInput( |
| 886 | 887 | QPDFObjectHandle, QPDF*, std::string const&, | ... | ... |
libqpdf/QPDFObjectHandle.cc
| ... | ... | @@ -2025,11 +2025,14 @@ QPDFObjectHandle::shallowCopy() |
| 2025 | 2025 | new_obj = *this; |
| 2026 | 2026 | } |
| 2027 | 2027 | |
| 2028 | + std::set<QPDFObjGen> visited; | |
| 2029 | + new_obj.copyObject(visited, false); | |
| 2028 | 2030 | return new_obj; |
| 2029 | 2031 | } |
| 2030 | 2032 | |
| 2031 | 2033 | void |
| 2032 | -QPDFObjectHandle::makeDirectInternal(std::set<int>& visited) | |
| 2034 | +QPDFObjectHandle::copyObject(std::set<QPDFObjGen>& visited, | |
| 2035 | + bool cross_indirect) | |
| 2033 | 2036 | { |
| 2034 | 2037 | assertInitialized(); |
| 2035 | 2038 | |
| ... | ... | @@ -2040,17 +2043,17 @@ QPDFObjectHandle::makeDirectInternal(std::set<int>& visited) |
| 2040 | 2043 | "attempt to make a stream into a direct object"); |
| 2041 | 2044 | } |
| 2042 | 2045 | |
| 2043 | - int cur_objid = this->m->objid; | |
| 2044 | - if (cur_objid != 0) | |
| 2046 | + QPDFObjGen cur_og(this->m->objid, this->m->generation); | |
| 2047 | + if (cur_og.getObj() != 0) | |
| 2045 | 2048 | { |
| 2046 | - if (visited.count(cur_objid)) | |
| 2049 | + if (visited.count(cur_og)) | |
| 2047 | 2050 | { |
| 2048 | 2051 | QTC::TC("qpdf", "QPDFObjectHandle makeDirect loop"); |
| 2049 | 2052 | throw std::runtime_error( |
| 2050 | 2053 | "loop detected while converting object from " |
| 2051 | 2054 | "indirect to direct"); |
| 2052 | 2055 | } |
| 2053 | - visited.insert(cur_objid); | |
| 2056 | + visited.insert(cur_og); | |
| 2054 | 2057 | } |
| 2055 | 2058 | |
| 2056 | 2059 | if (isReserved()) |
| ... | ... | @@ -2105,7 +2108,10 @@ QPDFObjectHandle::makeDirectInternal(std::set<int>& visited) |
| 2105 | 2108 | for (int i = 0; i < n; ++i) |
| 2106 | 2109 | { |
| 2107 | 2110 | items.push_back(getArrayItem(i)); |
| 2108 | - items.back().makeDirectInternal(visited); | |
| 2111 | + if (cross_indirect || (! items.back().isIndirect())) | |
| 2112 | + { | |
| 2113 | + items.back().copyObject(visited, cross_indirect); | |
| 2114 | + } | |
| 2109 | 2115 | } |
| 2110 | 2116 | new_obj = new QPDF_Array(items); |
| 2111 | 2117 | } |
| ... | ... | @@ -2118,7 +2124,10 @@ QPDFObjectHandle::makeDirectInternal(std::set<int>& visited) |
| 2118 | 2124 | iter != keys.end(); ++iter) |
| 2119 | 2125 | { |
| 2120 | 2126 | items[*iter] = getKey(*iter); |
| 2121 | - items[*iter].makeDirectInternal(visited); | |
| 2127 | + if (cross_indirect || (! items[*iter].isIndirect())) | |
| 2128 | + { | |
| 2129 | + items[*iter].copyObject(visited, cross_indirect); | |
| 2130 | + } | |
| 2122 | 2131 | } |
| 2123 | 2132 | new_obj = new QPDF_Dictionary(items); |
| 2124 | 2133 | } |
| ... | ... | @@ -2130,17 +2139,17 @@ QPDFObjectHandle::makeDirectInternal(std::set<int>& visited) |
| 2130 | 2139 | |
| 2131 | 2140 | this->m->obj = new_obj; |
| 2132 | 2141 | |
| 2133 | - if (cur_objid) | |
| 2142 | + if (cur_og.getObj()) | |
| 2134 | 2143 | { |
| 2135 | - visited.erase(cur_objid); | |
| 2144 | + visited.erase(cur_og); | |
| 2136 | 2145 | } |
| 2137 | 2146 | } |
| 2138 | 2147 | |
| 2139 | 2148 | void |
| 2140 | 2149 | QPDFObjectHandle::makeDirect() |
| 2141 | 2150 | { |
| 2142 | - std::set<int> visited; | |
| 2143 | - makeDirectInternal(visited); | |
| 2151 | + std::set<QPDFObjGen> visited; | |
| 2152 | + copyObject(visited, true); | |
| 2144 | 2153 | } |
| 2145 | 2154 | |
| 2146 | 2155 | void | ... | ... |
qpdf/qtest/qpdf/good10.qdf
| ... | ... | @@ -5,17 +5,22 @@ |
| 5 | 5 | %% Original object ID: 1 0 |
| 6 | 6 | 1 0 obj |
| 7 | 7 | << |
| 8 | - /Pages 2 0 R | |
| 8 | + /Pages 3 0 R | |
| 9 | 9 | /Type /Catalog |
| 10 | 10 | >> |
| 11 | 11 | endobj |
| 12 | 12 | |
| 13 | -%% Original object ID: 2 0 | |
| 13 | +%% Original object ID: 8 0 | |
| 14 | 14 | 2 0 obj |
| 15 | +null | |
| 16 | +endobj | |
| 17 | + | |
| 18 | +%% Original object ID: 2 0 | |
| 19 | +3 0 obj | |
| 15 | 20 | << |
| 16 | 21 | /Count 1 |
| 17 | 22 | /Kids [ |
| 18 | - 3 0 R | |
| 23 | + 4 0 R | |
| 19 | 24 | ] |
| 20 | 25 | /Type /Pages |
| 21 | 26 | >> |
| ... | ... | @@ -23,21 +28,21 @@ endobj |
| 23 | 28 | |
| 24 | 29 | %% Page 1 |
| 25 | 30 | %% Original object ID: 3 0 |
| 26 | -3 0 obj | |
| 31 | +4 0 obj | |
| 27 | 32 | << |
| 28 | - /Contents 4 0 R | |
| 33 | + /Contents 5 0 R | |
| 29 | 34 | /MediaBox [ |
| 30 | 35 | 0 |
| 31 | 36 | 0 |
| 32 | 37 | 612 |
| 33 | 38 | 792 |
| 34 | 39 | ] |
| 35 | - /Parent 2 0 R | |
| 40 | + /Parent 3 0 R | |
| 36 | 41 | /Resources << |
| 37 | 42 | /Font << |
| 38 | - /F1 6 0 R | |
| 43 | + /F1 7 0 R | |
| 39 | 44 | >> |
| 40 | - /ProcSet 7 0 R | |
| 45 | + /ProcSet 8 0 R | |
| 41 | 46 | >> |
| 42 | 47 | /Type /Page |
| 43 | 48 | >> |
| ... | ... | @@ -45,9 +50,9 @@ endobj |
| 45 | 50 | |
| 46 | 51 | %% Contents for page 1 |
| 47 | 52 | %% Original object ID: 4 0 |
| 48 | -4 0 obj | |
| 53 | +5 0 obj | |
| 49 | 54 | << |
| 50 | - /Length 5 0 R | |
| 55 | + /Length 6 0 R | |
| 51 | 56 | >> |
| 52 | 57 | stream |
| 53 | 58 | BT |
| ... | ... | @@ -58,12 +63,12 @@ ET |
| 58 | 63 | endstream |
| 59 | 64 | endobj |
| 60 | 65 | |
| 61 | -5 0 obj | |
| 66 | +6 0 obj | |
| 62 | 67 | 44 |
| 63 | 68 | endobj |
| 64 | 69 | |
| 65 | 70 | %% Original object ID: 6 0 |
| 66 | -6 0 obj | |
| 71 | +7 0 obj | |
| 67 | 72 | << |
| 68 | 73 | /BaseFont /Helvetica |
| 69 | 74 | /Encoding /WinAnsiEncoding |
| ... | ... | @@ -74,7 +79,7 @@ endobj |
| 74 | 79 | endobj |
| 75 | 80 | |
| 76 | 81 | %% Original object ID: 5 0 |
| 77 | -7 0 obj | |
| 82 | +8 0 obj | |
| 78 | 83 | [ |
| 79 | 84 | |
| 80 | 85 | /Text |
| ... | ... | @@ -82,29 +87,30 @@ endobj |
| 82 | 87 | endobj |
| 83 | 88 | |
| 84 | 89 | xref |
| 85 | -0 8 | |
| 90 | +0 9 | |
| 86 | 91 | 0000000000 65535 f |
| 87 | 92 | 0000000052 00000 n |
| 88 | 93 | 0000000133 00000 n |
| 89 | -0000000242 00000 n | |
| 90 | -0000000484 00000 n | |
| 91 | -0000000583 00000 n | |
| 92 | -0000000629 00000 n | |
| 93 | -0000000774 00000 n | |
| 94 | +0000000181 00000 n | |
| 95 | +0000000290 00000 n | |
| 96 | +0000000532 00000 n | |
| 97 | +0000000631 00000 n | |
| 98 | +0000000677 00000 n | |
| 99 | +0000000822 00000 n | |
| 94 | 100 | trailer << |
| 95 | 101 | /QTest [ |
| 96 | 102 | 1 |
| 97 | 103 | (2) |
| 98 | - null | |
| 104 | + 2 0 R | |
| 99 | 105 | 0.0 |
| 100 | 106 | -0.0 |
| 101 | 107 | 0. |
| 102 | 108 | -0. |
| 103 | 109 | ] |
| 104 | 110 | /Root 1 0 R |
| 105 | - /Size 8 | |
| 111 | + /Size 9 | |
| 106 | 112 | /ID [<31415926535897932384626433832795><31415926535897932384626433832795>] |
| 107 | 113 | >> |
| 108 | 114 | startxref |
| 109 | -809 | |
| 115 | +857 | |
| 110 | 116 | %%EOF | ... | ... |