sw/source/core/doc/list.cxx                    |   12 +
 xmloff/source/text/XMLTextListBlockContext.cxx |  172 +++++++++++++------------
 2 files changed, 101 insertions(+), 83 deletions(-)

New commits:
commit da798460e370a97597ecc9a06634f400c4b2e0cc
Author:     Noel Grandin <noel.gran...@collabora.co.uk>
AuthorDate: Thu Dec 8 14:50:54 2022 +0200
Commit:     Noel Grandin <noel.gran...@collabora.co.uk>
CommitDate: Thu Dec 8 18:24:22 2022 +0000

    crashtesting ooo84576-1.odt
    
    prevent the OOM by detecting cycles in SwList::SwList and throwing an
    exception.
    
    (1) However, that means we need to catch the exception in
        XMLTextListBlockContext::XMLTextListBlockContext
    and undo some registration, otherwise we will get a use-after-free.
    
    The need to catch it is why I'm using an UNO exception here,
    it seemed like a bad idea to throw and then catch and std::foo
    exception.
    
    (2) this is still not the end of the story, a further exception
    is thrown during SwDoc destruction, for which I don't have a
    solution.
    
    Change-Id: I48be3d8acbdc0f9ca948a958f1124b158ba77ac0
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/143820
    Tested-by: Jenkins
    Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk>

diff --git a/sw/source/core/doc/list.cxx b/sw/source/core/doc/list.cxx
index aa4c06f473aa..5095d4e6c9a9 100644
--- a/sw/source/core/doc/list.cxx
+++ b/sw/source/core/doc/list.cxx
@@ -33,8 +33,18 @@ SwList::SwList( OUString sListId,
 {
     // create empty list trees for the document ranges
     const SwNode* pNode = rNodes[SwNodeOffset(0)];
+    std::vector<bool> aVisited(static_cast<sal_Int32>(rNodes.Count()), false);
     do
     {
+        SwNodeOffset nIndex = pNode->GetIndex();
+        if (aVisited[static_cast<sal_Int32>(nIndex)])
+        {
+            // crashtesting ooo84576-1.odt, which manages to trigger a broken 
document structure
+            // in our code. This is just a workaround to prevent an infinite 
loop leading to OOM.
+            SAL_WARN("sw.core", "corrupt document structure, bailing out of 
infinite loop");
+            throw css::uno::RuntimeException("corrupt document structure, 
bailing out of infinite loop");
+        }
+        aVisited[static_cast<sal_Int32>(nIndex)] = true;
         SwPaM aPam( *pNode, *pNode->EndOfSectionNode() );
 
         maListTrees.emplace_back(
@@ -46,7 +56,7 @@ SwList::SwList( OUString sListId,
         pNode = pNode->EndOfSectionNode();
         if (pNode != &rNodes.GetEndOfContent())
         {
-            SwNodeOffset nIndex = pNode->GetIndex();
+            nIndex = pNode->GetIndex();
             nIndex++;
             pNode = rNodes[nIndex];
         }
diff --git a/xmloff/source/text/XMLTextListBlockContext.cxx 
b/xmloff/source/text/XMLTextListBlockContext.cxx
index 7c688f4c5e6c..c22eb2e221f2 100644
--- a/xmloff/source/text/XMLTextListBlockContext.cxx
+++ b/xmloff/source/text/XMLTextListBlockContext.cxx
@@ -110,113 +110,121 @@ XMLTextListBlockContext::XMLTextListBlockContext(
 
     // Remember this list block.
     mrTxtImport.GetTextListHelper().PushListContext( this );
+    try
+    {
+        mxNumRules = XMLTextListsHelper::MakeNumRule(GetImport(), mxNumRules,
+            sParentListStyleName, msListStyleName,
+            mnLevel, &mbRestartNumbering, &mbSetDefaults );
+        if( !mxNumRules.is() )
+            return;
 
-    mxNumRules = XMLTextListsHelper::MakeNumRule(GetImport(), mxNumRules,
-        sParentListStyleName, msListStyleName,
-        mnLevel, &mbRestartNumbering, &mbSetDefaults );
-    if( !mxNumRules.is() )
-        return;
-
-    if ( mnLevel != 0 ) // root <list> element
-        return;
+        if ( mnLevel != 0 ) // root <list> element
+            return;
 
-    XMLTextListsHelper& rTextListsHelper( mrTxtImport.GetTextListHelper() );
-    // Inconsistent behavior regarding lists (#i92811#)
-    OUString sListStyleDefaultListId;
-    {
-        uno::Reference< beans::XPropertySet > xNumRuleProps( mxNumRules, 
UNO_QUERY );
-        if ( xNumRuleProps.is() )
+        XMLTextListsHelper& rTextListsHelper( mrTxtImport.GetTextListHelper() 
);
+        // Inconsistent behavior regarding lists (#i92811#)
+        OUString sListStyleDefaultListId;
         {
-            uno::Reference< beans::XPropertySetInfo > xNumRulePropSetInfo(
-                                        xNumRuleProps->getPropertySetInfo());
-            if (xNumRulePropSetInfo.is() &&
-                xNumRulePropSetInfo->hasPropertyByName(
-                     s_PropNameDefaultListId))
+            uno::Reference< beans::XPropertySet > xNumRuleProps( mxNumRules, 
UNO_QUERY );
+            if ( xNumRuleProps.is() )
             {
-                xNumRuleProps->getPropertyValue(s_PropNameDefaultListId)
-                    >>= sListStyleDefaultListId;
-                SAL_WARN_IF( sListStyleDefaultListId.isEmpty(), "xmloff",
-                            "no default list id found at numbering rules 
instance. Serious defect." );
+                uno::Reference< beans::XPropertySetInfo > xNumRulePropSetInfo(
+                                            
xNumRuleProps->getPropertySetInfo());
+                if (xNumRulePropSetInfo.is() &&
+                    xNumRulePropSetInfo->hasPropertyByName(
+                         s_PropNameDefaultListId))
+                {
+                    xNumRuleProps->getPropertyValue(s_PropNameDefaultListId)
+                        >>= sListStyleDefaultListId;
+                    SAL_WARN_IF( sListStyleDefaultListId.isEmpty(), "xmloff",
+                                "no default list id found at numbering rules 
instance. Serious defect." );
+                }
             }
         }
-    }
-    if ( msListId.isEmpty() )  // no text:id property found
-    {
-        sal_Int32 nUPD( 0 );
-        sal_Int32 nBuild( 0 );
-        const bool bBuildIdFound = GetImport().getBuildIds( nUPD, nBuild );
-        if ( rImport.IsTextDocInOOoFileFormat() ||
-             ( bBuildIdFound && nUPD == 680 ) )
+        if ( msListId.isEmpty() )  // no text:id property found
         {
-            /* handling former documents written by OpenOffice.org:
-               use default list id of numbering rules instance, if existing
-               (#i92811#)
-            */
-            if ( !sListStyleDefaultListId.isEmpty() )
+            sal_Int32 nUPD( 0 );
+            sal_Int32 nBuild( 0 );
+            const bool bBuildIdFound = GetImport().getBuildIds( nUPD, nBuild );
+            if ( rImport.IsTextDocInOOoFileFormat() ||
+                 ( bBuildIdFound && nUPD == 680 ) )
             {
-                msListId = sListStyleDefaultListId;
-                if ( !bIsContinueNumberingAttributePresent &&
-                     !mbRestartNumbering &&
-                     rTextListsHelper.IsListProcessed( msListId ) )
+                /* handling former documents written by OpenOffice.org:
+                   use default list id of numbering rules instance, if existing
+                   (#i92811#)
+                */
+                if ( !sListStyleDefaultListId.isEmpty() )
                 {
-                    mbRestartNumbering = true;
+                    msListId = sListStyleDefaultListId;
+                    if ( !bIsContinueNumberingAttributePresent &&
+                         !mbRestartNumbering &&
+                         rTextListsHelper.IsListProcessed( msListId ) )
+                    {
+                        mbRestartNumbering = true;
+                    }
                 }
             }
+            if ( msListId.isEmpty() )
+            {
+                // generate a new list id for the list
+                msListId = rTextListsHelper.GenerateNewListId();
+            }
         }
-        if ( msListId.isEmpty() )
-        {
-            // generate a new list id for the list
-            msListId = rTextListsHelper.GenerateNewListId();
-        }
-    }
 
-    if ( bIsContinueNumberingAttributePresent && !mbRestartNumbering &&
-         msContinueListId.isEmpty() )
-    {
-        const OUString& Last( rTextListsHelper.GetLastProcessedListId() );
-        if ( rTextListsHelper.GetListStyleOfLastProcessedList() == 
msListStyleName
-             && Last != msListId )
+        if ( bIsContinueNumberingAttributePresent && !mbRestartNumbering &&
+             msContinueListId.isEmpty() )
         {
-            msContinueListId = Last;
+            const OUString& Last( rTextListsHelper.GetLastProcessedListId() );
+            if ( rTextListsHelper.GetListStyleOfLastProcessedList() == 
msListStyleName
+                 && Last != msListId )
+            {
+                msContinueListId = Last;
+            }
         }
-    }
 
-    bool bContinueNumbering = bIsContinueNumberingAttributePresent && 
!mbRestartNumbering;
-    if (msContinueListId.isEmpty() && bContinueNumbering && 
GetImport().IsMSO())
-    {
-        // No "continue list" id, but continue numbering was requested. 
Connect to the last list of
-        // the same list style in the Word case, even if there was a different 
list in the meantime.
-        msContinueListId = 
rTextListsHelper.GetLastIdOfStyleName(msListStyleName);
-    }
-
-    if ( !msContinueListId.isEmpty() )
-    {
-        if ( !rTextListsHelper.IsListProcessed( msContinueListId ) )
+        bool bContinueNumbering = bIsContinueNumberingAttributePresent && 
!mbRestartNumbering;
+        if (msContinueListId.isEmpty() && bContinueNumbering && 
GetImport().IsMSO())
         {
-            msContinueListId.clear();
+            // No "continue list" id, but continue numbering was requested. 
Connect to the last list of
+            // the same list style in the Word case, even if there was a 
different list in the meantime.
+            msContinueListId = 
rTextListsHelper.GetLastIdOfStyleName(msListStyleName);
         }
-        else
+
+        if ( !msContinueListId.isEmpty() )
         {
-            // search continue list chain for master list and
-            // continue the master list.
-            OUString sTmpStr =
-                rTextListsHelper.GetContinueListIdOfProcessedList( 
msContinueListId );
-            while ( !sTmpStr.isEmpty() )
+            if ( !rTextListsHelper.IsListProcessed( msContinueListId ) )
             {
-                msContinueListId = sTmpStr;
-
-                sTmpStr =
+                msContinueListId.clear();
+            }
+            else
+            {
+                // search continue list chain for master list and
+                // continue the master list.
+                OUString sTmpStr =
                     rTextListsHelper.GetContinueListIdOfProcessedList( 
msContinueListId );
+                while ( !sTmpStr.isEmpty() )
+                {
+                    msContinueListId = sTmpStr;
+
+                    sTmpStr =
+                        rTextListsHelper.GetContinueListIdOfProcessedList( 
msContinueListId );
+                }
             }
         }
-    }
 
-    if ( !rTextListsHelper.IsListProcessed( msListId ) )
+        if ( !rTextListsHelper.IsListProcessed( msListId ) )
+        {
+            // Inconsistent behavior regarding lists (#i92811#)
+            rTextListsHelper.KeepListAsProcessed(
+                msListId, msListStyleName, msContinueListId,
+                sListStyleDefaultListId );
+        }
+    }
+    catch (uno::Exception&)
     {
-        // Inconsistent behavior regarding lists (#i92811#)
-        rTextListsHelper.KeepListAsProcessed(
-            msListId, msListStyleName, msContinueListId,
-            sListStyleDefaultListId );
+        // pop ourselves if anything goes wrong to avoid use-after-free
+        rTxtImp.GetTextListHelper().PopListContext();
+        throw;
     }
 }
 

Reply via email to