Prevent cxfa_contentlayoutitem linked lists from getting entangled.
Implement the basic linked-list primitives, and use them
consistently. Currently the code is doing ad-hoc manipulations
of these pointers, and creating circular lists somewhere. This
causes re-frees as we walk down the list freeing every item.
Use UnownedPtr<> to try to catch any future botches.
Tested against the test case in 925790 (CF fuzzer will subsequently
verify 913564).
Bug: chromium:913564, chromium:925790
Change-Id: I2b735b3137aa715e5bb6b1c4472a1d2fd68ae286
Reviewed-on: https://pdfium-review.googlesource.com/c/49350
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/xfa/fxfa/parser/cxfa_contentlayoutitem.cpp b/xfa/fxfa/parser/cxfa_contentlayoutitem.cpp
index 6878c8e..79b3cb7 100644
--- a/xfa/fxfa/parser/cxfa_contentlayoutitem.cpp
+++ b/xfa/fxfa/parser/cxfa_contentlayoutitem.cpp
@@ -14,6 +14,7 @@
: CXFA_LayoutItem(pNode, kContentItem) {}
CXFA_ContentLayoutItem::~CXFA_ContentLayoutItem() {
+ RemoveSelf();
if (m_pFormNode->JSObject()->GetLayoutItem() == this)
m_pFormNode->JSObject()->SetLayoutItem(nullptr);
}
@@ -24,20 +25,36 @@
CXFA_ContentLayoutItem* CXFA_ContentLayoutItem::GetFirst() {
CXFA_ContentLayoutItem* pCurNode = this;
- while (pCurNode->m_pPrev)
- pCurNode = pCurNode->m_pPrev;
+ while (auto* pPrev = pCurNode->GetPrev())
+ pCurNode = pPrev;
return pCurNode;
}
CXFA_ContentLayoutItem* CXFA_ContentLayoutItem::GetLast() {
CXFA_ContentLayoutItem* pCurNode = this;
- while (pCurNode->m_pNext)
- pCurNode = pCurNode->m_pNext;
+ while (auto* pNext = pCurNode->GetNext())
+ pCurNode = pNext;
return pCurNode;
}
+void CXFA_ContentLayoutItem::InsertAfter(CXFA_ContentLayoutItem* pItem) {
+ pItem->RemoveSelf();
+ pItem->m_pNext = m_pNext;
+ pItem->m_pPrev = this;
+ m_pNext = pItem;
+ if (pItem->m_pNext)
+ pItem->m_pNext->m_pPrev = pItem;
+}
+
+void CXFA_ContentLayoutItem::RemoveSelf() {
+ if (m_pNext)
+ m_pNext->m_pPrev = m_pPrev;
+ if (m_pPrev)
+ m_pPrev->m_pNext = m_pNext;
+}
+
CFX_RectF CXFA_ContentLayoutItem::GetRect(bool bRelative) const {
CFX_PointF sPos = m_sPos;
CFX_SizeF sSize = m_sSize;
@@ -83,8 +100,8 @@
int32_t CXFA_ContentLayoutItem::GetIndex() const {
int32_t iIndex = 0;
const CXFA_ContentLayoutItem* pCurNode = this;
- while (pCurNode->m_pPrev) {
- pCurNode = pCurNode->m_pPrev;
+ while (auto* pPrev = pCurNode->GetPrev()) {
+ pCurNode = pPrev;
++iIndex;
}
return iIndex;
@@ -93,8 +110,8 @@
int32_t CXFA_ContentLayoutItem::GetCount() const {
int32_t iCount = GetIndex() + 1;
const CXFA_ContentLayoutItem* pCurNode = this;
- while (pCurNode->m_pNext) {
- pCurNode = pCurNode->m_pNext;
+ while (auto* pNext = pCurNode->GetNext()) {
+ pCurNode = pNext;
iCount++;
}
return iCount;
diff --git a/xfa/fxfa/parser/cxfa_contentlayoutitem.h b/xfa/fxfa/parser/cxfa_contentlayoutitem.h
index ac2d8f2..7313a1e 100644
--- a/xfa/fxfa/parser/cxfa_contentlayoutitem.h
+++ b/xfa/fxfa/parser/cxfa_contentlayoutitem.h
@@ -7,6 +7,7 @@
#ifndef XFA_FXFA_PARSER_CXFA_CONTENTLAYOUTITEM_H_
#define XFA_FXFA_PARSER_CXFA_CONTENTLAYOUTITEM_H_
+#include "core/fxcrt/unowned_ptr.h"
#include "xfa/fxfa/parser/cxfa_layoutitem.h"
class CXFA_FFWidget;
@@ -20,18 +21,23 @@
CXFA_ContentLayoutItem* GetFirst();
CXFA_ContentLayoutItem* GetLast();
- CXFA_ContentLayoutItem* GetPrev() const { return m_pPrev; }
- CXFA_ContentLayoutItem* GetNext() const { return m_pNext; }
+ CXFA_ContentLayoutItem* GetPrev() const { return m_pPrev.Get(); }
+ CXFA_ContentLayoutItem* GetNext() const { return m_pNext.Get(); }
+ void InsertAfter(CXFA_ContentLayoutItem* pNext);
CFX_RectF GetRect(bool bRelative) const;
int32_t GetIndex() const;
int32_t GetCount() const;
- CXFA_ContentLayoutItem* m_pPrev = nullptr;
- CXFA_ContentLayoutItem* m_pNext = nullptr;
CFX_PointF m_sPos;
CFX_SizeF m_sSize;
mutable uint32_t m_dwStatus = 0;
+
+ private:
+ void RemoveSelf();
+
+ UnownedPtr<CXFA_ContentLayoutItem> m_pPrev;
+ UnownedPtr<CXFA_ContentLayoutItem> m_pNext;
};
inline CXFA_FFWidget* ToFFWidget(CXFA_ContentLayoutItem* item) {
diff --git a/xfa/fxfa/parser/cxfa_itemlayoutprocessor.cpp b/xfa/fxfa/parser/cxfa_itemlayoutprocessor.cpp
index db24066..f91f3f0 100644
--- a/xfa/fxfa/parser/cxfa_itemlayoutprocessor.cpp
+++ b/xfa/fxfa/parser/cxfa_itemlayoutprocessor.cpp
@@ -444,7 +444,7 @@
CXFA_ContentLayoutItem* pCurLayoutItem =
ToContentLayoutItem(pNode->JSObject()->GetLayoutItem());
while (pCurLayoutItem) {
- CXFA_ContentLayoutItem* pNextLayoutItem = pCurLayoutItem->m_pNext;
+ CXFA_ContentLayoutItem* pNextLayoutItem = pCurLayoutItem->GetNext();
pNotify->OnLayoutItemRemoving(pDocLayout, pCurLayoutItem);
delete pCurLayoutItem;
pCurLayoutItem = pNextLayoutItem;
@@ -643,7 +643,7 @@
CXFA_ContentLayoutItem* pLayoutItem = nullptr;
if (m_pOldLayoutItem) {
pLayoutItem = m_pOldLayoutItem;
- m_pOldLayoutItem = m_pOldLayoutItem->m_pNext;
+ m_pOldLayoutItem = m_pOldLayoutItem->GetNext();
return pLayoutItem;
}
pLayoutItem = pFormNode->GetDocument()
@@ -653,11 +653,7 @@
CXFA_ContentLayoutItem* pPrevLayoutItem =
ToContentLayoutItem(pFormNode->JSObject()->GetLayoutItem());
if (pPrevLayoutItem) {
- while (pPrevLayoutItem->m_pNext)
- pPrevLayoutItem = pPrevLayoutItem->m_pNext;
-
- pPrevLayoutItem->m_pNext = pLayoutItem;
- pLayoutItem->m_pPrev = pPrevLayoutItem;
+ pPrevLayoutItem->GetLast()->InsertAfter(pLayoutItem);
} else {
pFormNode->JSObject()->SetLayoutItem(pLayoutItem);
}
@@ -818,16 +814,13 @@
return pLayoutItem;
}
- if (m_pOldLayoutItem->m_pPrev)
- m_pOldLayoutItem->m_pPrev->m_pNext = nullptr;
-
CXFA_FFNotify* pNotify =
m_pOldLayoutItem->GetFormNode()->GetDocument()->GetNotify();
CXFA_LayoutProcessor* pDocLayout =
m_pOldLayoutItem->GetFormNode()->GetDocument()->GetLayoutProcessor();
CXFA_ContentLayoutItem* pOldLayoutItem = m_pOldLayoutItem;
while (pOldLayoutItem) {
- CXFA_ContentLayoutItem* pNextOldLayoutItem = pOldLayoutItem->m_pNext;
+ CXFA_ContentLayoutItem* pNextOldLayoutItem = pOldLayoutItem->GetNext();
pNotify->OnLayoutItemRemoving(pDocLayout, pOldLayoutItem);
if (pOldLayoutItem->m_pParent)
pOldLayoutItem->m_pParent->RemoveChild(pOldLayoutItem);
@@ -1725,7 +1718,7 @@
if (!pLayoutNext->m_pNextSibling && m_pCurChildPreprocessor &&
m_pCurChildPreprocessor->GetFormNode() ==
pLayoutNext->GetFormNode()) {
- pLayoutNext->m_pNext = m_pCurChildPreprocessor->m_pLayoutItem;
+ pLayoutNext->InsertAfter(m_pCurChildPreprocessor->m_pLayoutItem);
m_pCurChildPreprocessor->m_pLayoutItem = pLayoutNext;
break;
}