Commit ddd78c1b7f53f09710431d58cd94659271f325cc

Authored by Jay Berkenbilt
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.
include/qpdf/QPDFObjectHandle.hh
@@ -514,10 +514,11 @@ class QPDFObjectHandle @@ -514,10 +514,11 @@ class QPDFObjectHandle
514 QPDF_DLL 514 QPDF_DLL
515 QPDF* getOwningQPDF(); 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 QPDF_DLL 522 QPDF_DLL
522 QPDFObjectHandle shallowCopy(); 523 QPDFObjectHandle shallowCopy();
523 524
@@ -880,7 +881,7 @@ class QPDFObjectHandle @@ -880,7 +881,7 @@ class QPDFObjectHandle
880 void objectWarning(std::string const& warning); 881 void objectWarning(std::string const& warning);
881 void assertType(char const* type_name, bool istype); 882 void assertType(char const* type_name, bool istype);
882 void dereference(); 883 void dereference();
883 - void makeDirectInternal(std::set<int>& visited); 884 + void copyObject(std::set<QPDFObjGen>& visited, bool cross_indirect);
884 void releaseResolved(); 885 void releaseResolved();
885 static void setObjectDescriptionFromInput( 886 static void setObjectDescriptionFromInput(
886 QPDFObjectHandle, QPDF*, std::string const&, 887 QPDFObjectHandle, QPDF*, std::string const&,
libqpdf/QPDFObjectHandle.cc
@@ -2025,11 +2025,14 @@ QPDFObjectHandle::shallowCopy() @@ -2025,11 +2025,14 @@ QPDFObjectHandle::shallowCopy()
2025 new_obj = *this; 2025 new_obj = *this;
2026 } 2026 }
2027 2027
  2028 + std::set<QPDFObjGen> visited;
  2029 + new_obj.copyObject(visited, false);
2028 return new_obj; 2030 return new_obj;
2029 } 2031 }
2030 2032
2031 void 2033 void
2032 -QPDFObjectHandle::makeDirectInternal(std::set<int>& visited) 2034 +QPDFObjectHandle::copyObject(std::set<QPDFObjGen>& visited,
  2035 + bool cross_indirect)
2033 { 2036 {
2034 assertInitialized(); 2037 assertInitialized();
2035 2038
@@ -2040,17 +2043,17 @@ QPDFObjectHandle::makeDirectInternal(std::set&lt;int&gt;&amp; visited) @@ -2040,17 +2043,17 @@ QPDFObjectHandle::makeDirectInternal(std::set&lt;int&gt;&amp; visited)
2040 "attempt to make a stream into a direct object"); 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 QTC::TC("qpdf", "QPDFObjectHandle makeDirect loop"); 2051 QTC::TC("qpdf", "QPDFObjectHandle makeDirect loop");
2049 throw std::runtime_error( 2052 throw std::runtime_error(
2050 "loop detected while converting object from " 2053 "loop detected while converting object from "
2051 "indirect to direct"); 2054 "indirect to direct");
2052 } 2055 }
2053 - visited.insert(cur_objid); 2056 + visited.insert(cur_og);
2054 } 2057 }
2055 2058
2056 if (isReserved()) 2059 if (isReserved())
@@ -2105,7 +2108,10 @@ QPDFObjectHandle::makeDirectInternal(std::set&lt;int&gt;&amp; visited) @@ -2105,7 +2108,10 @@ QPDFObjectHandle::makeDirectInternal(std::set&lt;int&gt;&amp; visited)
2105 for (int i = 0; i < n; ++i) 2108 for (int i = 0; i < n; ++i)
2106 { 2109 {
2107 items.push_back(getArrayItem(i)); 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 new_obj = new QPDF_Array(items); 2116 new_obj = new QPDF_Array(items);
2111 } 2117 }
@@ -2118,7 +2124,10 @@ QPDFObjectHandle::makeDirectInternal(std::set&lt;int&gt;&amp; visited) @@ -2118,7 +2124,10 @@ QPDFObjectHandle::makeDirectInternal(std::set&lt;int&gt;&amp; visited)
2118 iter != keys.end(); ++iter) 2124 iter != keys.end(); ++iter)
2119 { 2125 {
2120 items[*iter] = getKey(*iter); 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 new_obj = new QPDF_Dictionary(items); 2132 new_obj = new QPDF_Dictionary(items);
2124 } 2133 }
@@ -2130,17 +2139,17 @@ QPDFObjectHandle::makeDirectInternal(std::set&lt;int&gt;&amp; visited) @@ -2130,17 +2139,17 @@ QPDFObjectHandle::makeDirectInternal(std::set&lt;int&gt;&amp; visited)
2130 2139
2131 this->m->obj = new_obj; 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 void 2148 void
2140 QPDFObjectHandle::makeDirect() 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 void 2155 void
qpdf/qtest/qpdf/good10.qdf
@@ -5,17 +5,22 @@ @@ -5,17 +5,22 @@
5 %% Original object ID: 1 0 5 %% Original object ID: 1 0
6 1 0 obj 6 1 0 obj
7 << 7 <<
8 - /Pages 2 0 R 8 + /Pages 3 0 R
9 /Type /Catalog 9 /Type /Catalog
10 >> 10 >>
11 endobj 11 endobj
12 12
13 -%% Original object ID: 2 0 13 +%% Original object ID: 8 0
14 2 0 obj 14 2 0 obj
  15 +null
  16 +endobj
  17 +
  18 +%% Original object ID: 2 0
  19 +3 0 obj
15 << 20 <<
16 /Count 1 21 /Count 1
17 /Kids [ 22 /Kids [
18 - 3 0 R 23 + 4 0 R
19 ] 24 ]
20 /Type /Pages 25 /Type /Pages
21 >> 26 >>
@@ -23,21 +28,21 @@ endobj @@ -23,21 +28,21 @@ endobj
23 28
24 %% Page 1 29 %% Page 1
25 %% Original object ID: 3 0 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 /MediaBox [ 34 /MediaBox [
30 0 35 0
31 0 36 0
32 612 37 612
33 792 38 792
34 ] 39 ]
35 - /Parent 2 0 R 40 + /Parent 3 0 R
36 /Resources << 41 /Resources <<
37 /Font << 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 /Type /Page 47 /Type /Page
43 >> 48 >>
@@ -45,9 +50,9 @@ endobj @@ -45,9 +50,9 @@ endobj
45 50
46 %% Contents for page 1 51 %% Contents for page 1
47 %% Original object ID: 4 0 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 stream 57 stream
53 BT 58 BT
@@ -58,12 +63,12 @@ ET @@ -58,12 +63,12 @@ ET
58 endstream 63 endstream
59 endobj 64 endobj
60 65
61 -5 0 obj 66 +6 0 obj
62 44 67 44
63 endobj 68 endobj
64 69
65 %% Original object ID: 6 0 70 %% Original object ID: 6 0
66 -6 0 obj 71 +7 0 obj
67 << 72 <<
68 /BaseFont /Helvetica 73 /BaseFont /Helvetica
69 /Encoding /WinAnsiEncoding 74 /Encoding /WinAnsiEncoding
@@ -74,7 +79,7 @@ endobj @@ -74,7 +79,7 @@ endobj
74 endobj 79 endobj
75 80
76 %% Original object ID: 5 0 81 %% Original object ID: 5 0
77 -7 0 obj 82 +8 0 obj
78 [ 83 [
79 /PDF 84 /PDF
80 /Text 85 /Text
@@ -82,29 +87,30 @@ endobj @@ -82,29 +87,30 @@ endobj
82 endobj 87 endobj
83 88
84 xref 89 xref
85 -0 8 90 +0 9
86 0000000000 65535 f 91 0000000000 65535 f
87 0000000052 00000 n 92 0000000052 00000 n
88 0000000133 00000 n 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 trailer << 100 trailer <<
95 /QTest [ 101 /QTest [
96 1 102 1
97 (2) 103 (2)
98 - null 104 + 2 0 R
99 0.0 105 0.0
100 -0.0 106 -0.0
101 0. 107 0.
102 -0. 108 -0.
103 ] 109 ]
104 /Root 1 0 R 110 /Root 1 0 R
105 - /Size 8 111 + /Size 9
106 /ID [<31415926535897932384626433832795><31415926535897932384626433832795>] 112 /ID [<31415926535897932384626433832795><31415926535897932384626433832795>]
107 >> 113 >>
108 startxref 114 startxref
109 -809 115 +857
110 %%EOF 116 %%EOF