sw/source/filter/html/htmlctxt.cxx | 14 ++++++++------ sw/source/filter/html/swhtml.cxx | 13 ++++++++++--- sw/source/filter/html/swhtml.hxx | 4 +++- 3 files changed, 21 insertions(+), 10 deletions(-)
New commits: commit 9a79d74342a05f87365ab60ad057b1329a3bf216 Author: Caolán McNamara <[email protected]> AuthorDate: Fri Mar 6 09:00:40 2026 +0000 Commit: Caolán McNamara <[email protected]> CommitDate: Fri Mar 6 13:55:17 2026 +0100 ofz#390465661 Timeout on deeply nested tags Try a nested element depth of 1024. Browsers have some: "adoption agency algorithm" thing that might be relevant to this: https://html.spec.whatwg.org/multipage/parsing.html#adoption-agency-algorithm but that's a complicated thing. Change-Id: I469873ee0b3d569b709b562fb39b118a14a99be4 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/201109 Reviewed-by: Caolán McNamara <[email protected]> Tested-by: Jenkins diff --git a/sw/source/filter/html/htmlctxt.cxx b/sw/source/filter/html/htmlctxt.cxx index b32ce055efb2..ac8b70f61ad7 100644 --- a/sw/source/filter/html/htmlctxt.cxx +++ b/sw/source/filter/html/htmlctxt.cxx @@ -768,11 +768,12 @@ void SwHTMLParser::InsertAttrs( SfxItemSet &rItemSet, if( ppAttr ) { // Set the attribute - NewAttr(m_xAttrTab, ppAttr, *pItem); - - // and save context information - HTMLAttrs &rAttrs = pContext->GetAttrs(); - rAttrs.push_back( *ppAttr ); + if (NewAttr(m_xAttrTab, ppAttr, *pItem)) + { + // and save context information + HTMLAttrs &rAttrs = pContext->GetAttrs(); + rAttrs.push_back( *ppAttr ); + } } } @@ -791,7 +792,8 @@ void SwHTMLParser::InsertAttr( HTMLAttr **ppAttr, const SfxPoolItem & rItem, } // Set the attribute - NewAttr(m_xAttrTab, ppAttr, rItem); + if (!NewAttr(m_xAttrTab, ppAttr, rItem)) + return; // save context information HTMLAttrs &rAttrs = pCntxt->GetAttrs(); diff --git a/sw/source/filter/html/swhtml.cxx b/sw/source/filter/html/swhtml.cxx index df2bfcb1dcd7..11fe83cd96cb 100644 --- a/sw/source/filter/html/swhtml.cxx +++ b/sw/source/filter/html/swhtml.cxx @@ -3105,7 +3105,7 @@ void SwHTMLParser::SetAttr_( bool bChkEnd, bool bBeforeTable, aFields.clear(); } -void SwHTMLParser::NewAttr(const std::shared_ptr<HTMLAttrTable>& rAttrTable, HTMLAttr **ppAttr, const SfxPoolItem& rItem ) +bool SwHTMLParser::NewAttr(const std::shared_ptr<HTMLAttrTable>& rAttrTable, HTMLAttr **ppAttr, const SfxPoolItem& rItem ) { // Font height and font colour as well as escape attributes may not be // combined. Therefore they're saved in a list and in it the last opened @@ -3113,12 +3113,17 @@ void SwHTMLParser::NewAttr(const std::shared_ptr<HTMLAttrTable>& rAttrTable, HTM // attributes count is just incremented. if( *ppAttr ) { + // limit chain depth to avoid getting stuck in BuildPortions + if ((*ppAttr)->m_nChainDepth >= HTMLAttr::MAX_CHAIN_DEPTH) + return false; HTMLAttr *pAttr = new HTMLAttr(*m_pPam->GetPoint(), rItem, ppAttr, rAttrTable); + pAttr->m_nChainDepth = (*ppAttr)->m_nChainDepth + 1; pAttr->InsertNext( *ppAttr ); (*ppAttr) = pAttr; } else (*ppAttr) = new HTMLAttr(*m_pPam->GetPoint(), rItem, ppAttr, rAttrTable); + return true; } bool SwHTMLParser::EndAttr( HTMLAttr* pAttr, bool bChkEmpty ) @@ -5539,7 +5544,8 @@ HTMLAttr::HTMLAttr( const SwPosition& rPos, const SfxPoolItem& rItem, m_xAttrTab(std::move( xAttrTab )), m_pNext( nullptr ), m_pPrev( nullptr ), - m_ppHead( ppHd ) + m_ppHead( ppHd ), + m_nChainDepth( 0 ) { } @@ -5556,7 +5562,8 @@ HTMLAttr::HTMLAttr( const HTMLAttr &rAttr, const SwNode &rEndPara, m_xAttrTab(std::move( xAttrTab )), m_pNext( nullptr ), m_pPrev( nullptr ), - m_ppHead( ppHd ) + m_ppHead( ppHd ), + m_nChainDepth( 0 ) { } diff --git a/sw/source/filter/html/swhtml.hxx b/sw/source/filter/html/swhtml.hxx index 5147d8e8c6fa..08d6e052ab81 100644 --- a/sw/source/filter/html/swhtml.hxx +++ b/sw/source/filter/html/swhtml.hxx @@ -149,6 +149,8 @@ class HTMLAttr HTMLAttr *m_pNext; // still to close attributes with different values HTMLAttr *m_pPrev; // already closed but not set attributes HTMLAttr **m_ppHead; // list head + sal_uInt16 m_nChainDepth; // depth of m_pNext chain + static constexpr sal_uInt16 MAX_CHAIN_DEPTH = 1024; HTMLAttr( const SwPosition& rPos, const SfxPoolItem& rItem, HTMLAttr **pHd, std::shared_ptr<HTMLAttrTable> xAttrTab ); @@ -533,7 +535,7 @@ class SwHTMLParser : public SfxHTMLParser, public SvtListener // start/end an attribute // ppDepAttr indicated an attribute table entry, which attribute has to be // set, before the attribute is closed - void NewAttr(const std::shared_ptr<HTMLAttrTable>& rAttrTab, HTMLAttr **ppAttr, const SfxPoolItem& rItem); + bool NewAttr(const std::shared_ptr<HTMLAttrTable>& rAttrTab, HTMLAttr **ppAttr, const SfxPoolItem& rItem); bool EndAttr( HTMLAttr *pAttr, bool bChkEmpty=true ); void DeleteAttr( HTMLAttr* pAttr );
