2
1
mirror of https://github.com/qpdf/qpdf.git synced 2024-06-17 01:12:21 +00:00

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.
This commit is contained in:
Jay Berkenbilt 2018-06-21 20:33:38 -04:00
parent 84cd53f5af
commit ddd78c1b7f
3 changed files with 54 additions and 38 deletions

View File

@ -514,10 +514,11 @@ class QPDFObjectHandle
QPDF_DLL QPDF_DLL
QPDF* getOwningQPDF(); QPDF* getOwningQPDF();
// Create a shallow copy of an object as a direct object. Since // Create a shallow of an object as a direct object, but do not
// this is a shallow copy, for dictionaries and arrays, any keys // traverse across indirect object boundaries. That means that,
// or items that were indirect objects will still be indirect // for dictionaries and arrays, any keys or items that were
// objects that point to the same place. // indirect objects will still be indirect objects that point to
// the same place.
QPDF_DLL QPDF_DLL
QPDFObjectHandle shallowCopy(); QPDFObjectHandle shallowCopy();
@ -880,7 +881,7 @@ class QPDFObjectHandle
void objectWarning(std::string const& warning); void objectWarning(std::string const& warning);
void assertType(char const* type_name, bool istype); void assertType(char const* type_name, bool istype);
void dereference(); void dereference();
void makeDirectInternal(std::set<int>& visited); void copyObject(std::set<QPDFObjGen>& visited, bool cross_indirect);
void releaseResolved(); void releaseResolved();
static void setObjectDescriptionFromInput( static void setObjectDescriptionFromInput(
QPDFObjectHandle, QPDF*, std::string const&, QPDFObjectHandle, QPDF*, std::string const&,

View File

@ -2025,11 +2025,14 @@ QPDFObjectHandle::shallowCopy()
new_obj = *this; new_obj = *this;
} }
std::set<QPDFObjGen> visited;
new_obj.copyObject(visited, false);
return new_obj; return new_obj;
} }
void void
QPDFObjectHandle::makeDirectInternal(std::set<int>& visited) QPDFObjectHandle::copyObject(std::set<QPDFObjGen>& visited,
bool cross_indirect)
{ {
assertInitialized(); assertInitialized();
@ -2040,17 +2043,17 @@ QPDFObjectHandle::makeDirectInternal(std::set<int>& visited)
"attempt to make a stream into a direct object"); "attempt to make a stream into a direct object");
} }
int cur_objid = this->m->objid; QPDFObjGen cur_og(this->m->objid, this->m->generation);
if (cur_objid != 0) if (cur_og.getObj() != 0)
{ {
if (visited.count(cur_objid)) if (visited.count(cur_og))
{ {
QTC::TC("qpdf", "QPDFObjectHandle makeDirect loop"); QTC::TC("qpdf", "QPDFObjectHandle makeDirect loop");
throw std::runtime_error( throw std::runtime_error(
"loop detected while converting object from " "loop detected while converting object from "
"indirect to direct"); "indirect to direct");
} }
visited.insert(cur_objid); visited.insert(cur_og);
} }
if (isReserved()) if (isReserved())
@ -2105,7 +2108,10 @@ QPDFObjectHandle::makeDirectInternal(std::set<int>& visited)
for (int i = 0; i < n; ++i) for (int i = 0; i < n; ++i)
{ {
items.push_back(getArrayItem(i)); items.push_back(getArrayItem(i));
items.back().makeDirectInternal(visited); if (cross_indirect || (! items.back().isIndirect()))
{
items.back().copyObject(visited, cross_indirect);
}
} }
new_obj = new QPDF_Array(items); new_obj = new QPDF_Array(items);
} }
@ -2118,7 +2124,10 @@ QPDFObjectHandle::makeDirectInternal(std::set<int>& visited)
iter != keys.end(); ++iter) iter != keys.end(); ++iter)
{ {
items[*iter] = getKey(*iter); items[*iter] = getKey(*iter);
items[*iter].makeDirectInternal(visited); if (cross_indirect || (! items[*iter].isIndirect()))
{
items[*iter].copyObject(visited, cross_indirect);
}
} }
new_obj = new QPDF_Dictionary(items); new_obj = new QPDF_Dictionary(items);
} }
@ -2130,17 +2139,17 @@ QPDFObjectHandle::makeDirectInternal(std::set<int>& visited)
this->m->obj = new_obj; this->m->obj = new_obj;
if (cur_objid) if (cur_og.getObj())
{ {
visited.erase(cur_objid); visited.erase(cur_og);
} }
} }
void void
QPDFObjectHandle::makeDirect() QPDFObjectHandle::makeDirect()
{ {
std::set<int> visited; std::set<QPDFObjGen> visited;
makeDirectInternal(visited); copyObject(visited, true);
} }
void void

View File

@ -5,17 +5,22 @@
%% Original object ID: 1 0 %% Original object ID: 1 0
1 0 obj 1 0 obj
<< <<
/Pages 2 0 R /Pages 3 0 R
/Type /Catalog /Type /Catalog
>> >>
endobj endobj
%% Original object ID: 2 0 %% Original object ID: 8 0
2 0 obj 2 0 obj
null
endobj
%% Original object ID: 2 0
3 0 obj
<< <<
/Count 1 /Count 1
/Kids [ /Kids [
3 0 R 4 0 R
] ]
/Type /Pages /Type /Pages
>> >>
@ -23,21 +28,21 @@ endobj
%% Page 1 %% Page 1
%% Original object ID: 3 0 %% Original object ID: 3 0
3 0 obj 4 0 obj
<< <<
/Contents 4 0 R /Contents 5 0 R
/MediaBox [ /MediaBox [
0 0
0 0
612 612
792 792
] ]
/Parent 2 0 R /Parent 3 0 R
/Resources << /Resources <<
/Font << /Font <<
/F1 6 0 R /F1 7 0 R
>> >>
/ProcSet 7 0 R /ProcSet 8 0 R
>> >>
/Type /Page /Type /Page
>> >>
@ -45,9 +50,9 @@ endobj
%% Contents for page 1 %% Contents for page 1
%% Original object ID: 4 0 %% Original object ID: 4 0
4 0 obj 5 0 obj
<< <<
/Length 5 0 R /Length 6 0 R
>> >>
stream stream
BT BT
@ -58,12 +63,12 @@ ET
endstream endstream
endobj endobj
5 0 obj 6 0 obj
44 44
endobj endobj
%% Original object ID: 6 0 %% Original object ID: 6 0
6 0 obj 7 0 obj
<< <<
/BaseFont /Helvetica /BaseFont /Helvetica
/Encoding /WinAnsiEncoding /Encoding /WinAnsiEncoding
@ -74,7 +79,7 @@ endobj
endobj endobj
%% Original object ID: 5 0 %% Original object ID: 5 0
7 0 obj 8 0 obj
[ [
/PDF /PDF
/Text /Text
@ -82,29 +87,30 @@ endobj
endobj endobj
xref xref
0 8 0 9
0000000000 65535 f 0000000000 65535 f
0000000052 00000 n 0000000052 00000 n
0000000133 00000 n 0000000133 00000 n
0000000242 00000 n 0000000181 00000 n
0000000484 00000 n 0000000290 00000 n
0000000583 00000 n 0000000532 00000 n
0000000629 00000 n 0000000631 00000 n
0000000774 00000 n 0000000677 00000 n
0000000822 00000 n
trailer << trailer <<
/QTest [ /QTest [
1 1
(2) (2)
null 2 0 R
0.0 0.0
-0.0 -0.0
0. 0.
-0. -0.
] ]
/Root 1 0 R /Root 1 0 R
/Size 8 /Size 9
/ID [<31415926535897932384626433832795><31415926535897932384626433832795>] /ID [<31415926535897932384626433832795><31415926535897932384626433832795>]
>> >>
startxref startxref
809 857
%%EOF %%EOF