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; }