Replace some CPDF_Array::Add() calls with AddNew<>().
Ditto for InsertAt() and SetAt().
AddNew<>() is safer because it can not introduce a direct
cycle of objects into the array since it creates a new object
that can not have references to any old objects [cycles through
indirect objects are always possible, but do not affect memory
management when using RetainPtr<>].
This reduces the number of Add() calls that might need auditing
should a cycle be discovered in arrays again someday.
Change-Id: Ic423fcd4baefed0c692bd60961b360f6bb506e43
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/53870
Commit-Queue: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/edit/cpdf_pagecontentmanager.cpp b/core/fpdfapi/edit/cpdf_pagecontentmanager.cpp
index 0191f47..f4d51c6 100644
--- a/core/fpdfapi/edit/cpdf_pagecontentmanager.cpp
+++ b/core/fpdfapi/edit/cpdf_pagecontentmanager.cpp
@@ -66,8 +66,10 @@
// create an array with the old and the new one. The new one's index is 1.
if (contents_stream_) {
CPDF_Array* new_contents_array = doc_->NewIndirect<CPDF_Array>();
- new_contents_array->Add(contents_stream_->MakeReference(doc_.Get()));
- new_contents_array->Add(new_stream->MakeReference(doc_.Get()));
+ new_contents_array->AddNew<CPDF_Reference>(doc_.Get(),
+ contents_stream_->GetObjNum());
+ new_contents_array->AddNew<CPDF_Reference>(doc_.Get(),
+ new_stream->GetObjNum());
CPDF_Dictionary* page_dict = obj_holder_->GetDict();
page_dict->SetNewFor<CPDF_Reference>("Contents", doc_.Get(),
@@ -79,7 +81,8 @@
// If there is an array, just add the new stream to it, at the last position.
if (contents_array_) {
- contents_array_->Add(new_stream->MakeReference(doc_.Get()));
+ contents_array_->AddNew<CPDF_Reference>(doc_.Get(),
+ new_stream->GetObjNum());
return contents_array_->size() - 1;
}
diff --git a/core/fpdfapi/page/cpdf_image.cpp b/core/fpdfapi/page/cpdf_image.cpp
index 2a44215..1d01edb 100644
--- a/core/fpdfapi/page/cpdf_image.cpp
+++ b/core/fpdfapi/page/cpdf_image.cpp
@@ -246,7 +246,7 @@
auto pNewDict = m_pDocument->New<CPDF_Dictionary>();
CPDF_Stream* pCTS = m_pDocument->NewIndirect<CPDF_Stream>(
std::move(pColorTable), iPalette * 3, std::move(pNewDict));
- pCS->Add(pCTS->MakeReference(m_pDocument.Get()));
+ pCS->AddNew<CPDF_Reference>(m_pDocument.Get(), pCTS->GetObjNum());
pDict->SetNewFor<CPDF_Reference>("ColorSpace", m_pDocument.Get(),
pCS->GetObjNum());
} else {
diff --git a/core/fpdfapi/parser/cpdf_array.h b/core/fpdfapi/parser/cpdf_array.h
index 55d4cd6..7922e83 100644
--- a/core/fpdfapi/parser/cpdf_array.h
+++ b/core/fpdfapi/parser/cpdf_array.h
@@ -54,14 +54,11 @@
CFX_Matrix GetMatrix() const;
CFX_FloatRect GetRect() const;
- // Takes ownership of |pObj|, returns unowned pointer to it.
- CPDF_Object* Add(RetainPtr<CPDF_Object> pObj);
- CPDF_Object* SetAt(size_t index, RetainPtr<CPDF_Object> pObj);
- CPDF_Object* InsertAt(size_t index, RetainPtr<CPDF_Object> pObj);
-
// Creates object owned by the array, returns unowned pointer to it.
// We have special cases for objects that can intern strings from
- // a ByteStringPool.
+ // a ByteStringPool. Prefer using these templates over direct calls
+ // to Add()/SetAt()/InsertAt() since by creating a new object with no
+ // previous references, they ensure cycles can not be introduced.
template <typename T, typename... Args>
typename std::enable_if<!CanInternStrings<T>::value, T*>::type AddNew(
Args&&... args) {
@@ -103,6 +100,11 @@
index, pdfium::MakeRetain<T>(m_pPool, std::forward<Args>(args)...)));
}
+ // Takes ownership of |pObj|, returns unowned pointer to it.
+ CPDF_Object* Add(RetainPtr<CPDF_Object> pObj);
+ CPDF_Object* SetAt(size_t index, RetainPtr<CPDF_Object> pObj);
+ CPDF_Object* InsertAt(size_t index, RetainPtr<CPDF_Object> pObj);
+
void Clear();
void RemoveAt(size_t index);
void ConvertToIndirectObjectAt(size_t index, CPDF_IndirectObjectHolder* pDoc);
diff --git a/core/fpdfapi/parser/cpdf_document.cpp b/core/fpdfapi/parser/cpdf_document.cpp
index 835b086..be04432 100644
--- a/core/fpdfapi/parser/cpdf_document.cpp
+++ b/core/fpdfapi/parser/cpdf_document.cpp
@@ -540,7 +540,7 @@
continue;
}
if (bInsert) {
- pKidList->InsertAt(i, pPageDict->MakeReference(this));
+ pKidList->InsertNewAt<CPDF_Reference>(i, this, pPageDict->GetObjNum());
pPageDict->SetNewFor<CPDF_Reference>("Parent", this,
pPages->GetObjNum());
} else {
@@ -584,7 +584,7 @@
CPDF_Array* pPagesList = pPages->GetArrayFor("Kids");
if (!pPagesList)
pPagesList = pPages->SetNewFor<CPDF_Array>("Kids");
- pPagesList->Add(pPageDict->MakeReference(this));
+ pPagesList->AddNew<CPDF_Reference>(this, pPageDict->GetObjNum());
pPages->SetNewFor<CPDF_Number>("Count", nPages + 1);
pPageDict->SetNewFor<CPDF_Reference>("Parent", this, pPages->GetObjNum());
ResetTraversal();
@@ -722,7 +722,7 @@
pCIDSysInfo->SetNewFor<CPDF_Number>("Supplement", supplement);
CPDF_Array* pArray = pBaseDict->SetNewFor<CPDF_Array>("DescendantFonts");
- pArray->Add(pFontDict->MakeReference(this));
+ pArray->AddNew<CPDF_Reference>(this, pFontDict->GetObjNum());
return pFontDict;
}
diff --git a/fpdfsdk/fpdf_edittext.cpp b/fpdfsdk/fpdf_edittext.cpp
index e39da48..ddb0ee7 100644
--- a/fpdfsdk/fpdf_edittext.cpp
+++ b/fpdfsdk/fpdf_edittext.cpp
@@ -419,7 +419,7 @@
// TODO(npm): Support vertical writing
auto* pDescendant = pFontDict->SetNewFor<CPDF_Array>("DescendantFonts");
- pDescendant->Add(pCIDFont->MakeReference(pDoc));
+ pDescendant->AddNew<CPDF_Reference>(pDoc, pCIDFont->GetObjNum());
CPDF_Stream* toUnicodeStream = LoadUnicode(pDoc, to_unicode);
pFontDict->SetNewFor<CPDF_Reference>("ToUnicode", pDoc,
diff --git a/fpdfsdk/fpdf_flatten.cpp b/fpdfsdk/fpdf_flatten.cpp
index 94cc288..d6dbe9a 100644
--- a/fpdfsdk/fpdf_flatten.cpp
+++ b/fpdfsdk/fpdf_flatten.cpp
@@ -214,7 +214,8 @@
}
pContentsStream->SetDataAndRemoveFilter(sStream.AsRawSpan());
pContentsArray = pDocument->NewIndirect<CPDF_Array>();
- pContentsArray->Add(pContentsStream->MakeReference(pDocument));
+ pContentsArray->AddNew<CPDF_Reference>(pDocument,
+ pContentsStream->GetObjNum());
pPage->SetNewFor<CPDF_Reference>(pdfium::page_object::kContents, pDocument,
pContentsArray->GetObjNum());
}
diff --git a/fpdfsdk/fpdf_save.cpp b/fpdfsdk/fpdf_save.cpp
index 76a434d..22af561 100644
--- a/fpdfsdk/fpdf_save.cpp
+++ b/fpdfsdk/fpdf_save.cpp
@@ -140,7 +140,8 @@
pData->InitStreamFromFile(pDsfileWrite, std::move(pDataDict));
int iLast = pArray->size() - 2;
pArray->InsertNewAt<CPDF_String>(iLast, "datasets", false);
- pArray->InsertAt(iLast + 1, pData->MakeReference(pPDFDocument));
+ pArray->InsertNewAt<CPDF_Reference>(iLast + 1, pPDFDocument,
+ pData->GetObjNum());
}
fileList->push_back(std::move(pDsfileWrite));
}
@@ -164,7 +165,8 @@
pData->InitStreamFromFile(pfileWrite, std::move(pDataDict));
int iLast = pArray->size() - 2;
pArray->InsertNewAt<CPDF_String>(iLast, "form", false);
- pArray->InsertAt(iLast + 1, pData->MakeReference(pPDFDocument));
+ pArray->InsertNewAt<CPDF_Reference>(iLast + 1, pPDFDocument,
+ pData->GetObjNum());
}
fileList->push_back(std::move(pfileWrite));
}
diff --git a/fpdfsdk/fpdf_transformpage.cpp b/fpdfsdk/fpdf_transformpage.cpp
index 3ffbb3b..80101ae 100644
--- a/fpdfsdk/fpdf_transformpage.cpp
+++ b/fpdfsdk/fpdf_transformpage.cpp
@@ -203,13 +203,13 @@
pEndStream->SetData(ByteStringView(" Q").raw_span());
if (CPDF_Array* pContentArray = ToArray(pContentObj)) {
- pContentArray->InsertAt(0, pStream->MakeReference(pDoc));
- pContentArray->Add(pEndStream->MakeReference(pDoc));
+ pContentArray->InsertNewAt<CPDF_Reference>(0, pDoc, pStream->GetObjNum());
+ pContentArray->AddNew<CPDF_Reference>(pDoc, pEndStream->GetObjNum());
} else if (pContentObj->IsStream() && !pContentObj->IsInline()) {
pContentArray = pDoc->NewIndirect<CPDF_Array>();
- pContentArray->Add(pStream->MakeReference(pDoc));
- pContentArray->Add(pContentObj->MakeReference(pDoc));
- pContentArray->Add(pEndStream->MakeReference(pDoc));
+ pContentArray->AddNew<CPDF_Reference>(pDoc, pStream->GetObjNum());
+ pContentArray->AddNew<CPDF_Reference>(pDoc, pContentObj->GetObjNum());
+ pContentArray->AddNew<CPDF_Reference>(pDoc, pEndStream->GetObjNum());
pPageDict->SetNewFor<CPDF_Reference>(pdfium::page_object::kContents, pDoc,
pContentArray->GetObjNum());
}
@@ -359,11 +359,11 @@
pStream->SetDataFromStringstream(&strClip);
if (CPDF_Array* pArray = ToArray(pContentObj)) {
- pArray->InsertAt(0, pStream->MakeReference(pDoc));
+ pArray->InsertNewAt<CPDF_Reference>(0, pDoc, pStream->GetObjNum());
} else if (pContentObj->IsStream() && !pContentObj->IsInline()) {
CPDF_Array* pContentArray = pDoc->NewIndirect<CPDF_Array>();
- pContentArray->Add(pStream->MakeReference(pDoc));
- pContentArray->Add(pContentObj->MakeReference(pDoc));
+ pContentArray->AddNew<CPDF_Reference>(pDoc, pStream->GetObjNum());
+ pContentArray->AddNew<CPDF_Reference>(pDoc, pContentObj->GetObjNum());
pPageDict->SetNewFor<CPDF_Reference>(pdfium::page_object::kContents, pDoc,
pContentArray->GetObjNum());
}