[xerces-c] branch master updated: DFAContentModel: fix memory leaks when OutOfMemoryException occurs

[email protected]
Newsgroups gmane.text.xml.xerces-c.devel
Message-ID <[email protected]>
This is an automated email from the ASF dual-hosted git repository.

rleigh pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/xerces-c.git


The following commit(s) were added to refs/heads/master by this push:
     new a65990d  DFAContentModel: fix memory leaks when OutOfMemoryException occurs
     new 6d5e52d  Merge pull request #40 from rouault/fix_memleaks_DFAContentModel
a65990d is described below

commit a65990d79d3fc333d7481f010da4e165a88b6cb3
Author: Even Rouault <[email protected]>
AuthorDate: Thu Sep 23 16:50:38 2021 +0200

    DFAContentModel: fix memory leaks when OutOfMemoryException occurs
    
    Fixes GDAL's https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=39159
---
 src/xercesc/validators/common/CMStateSet.hpp      |  11 +-
 src/xercesc/validators/common/DFAContentModel.cpp | 178 +++++++++++++++++-----
 src/xercesc/validators/common/DFAContentModel.hpp |   1 +
 3 files changed, 147 insertions(+), 43 deletions(-)

diff --git a/src/xercesc/validators/common/CMStateSet.hpp b/src/xercesc/validators/common/CMStateSet.hpp
index 6e4a393..4cfc85f 100644
--- a/src/xercesc/validators/common/CMStateSet.hpp
+++ b/src/xercesc/validators/common/CMStateSet.hpp
@@ -32,6 +32,7 @@
 //
 
 #include <xercesc/util/ArrayIndexOutOfBoundsException.hpp>
+#include <xercesc/util/OutOfMemoryException.hpp>
 #include <xercesc/util/RuntimeException.hpp>
 #include <xercesc/util/PlatformUtils.hpp>
 #include <xercesc/framework/MemoryManager.hpp>
@@ -93,7 +94,15 @@ public :
             fDynamicBuffer->fArraySize = fBitCount / CMSTATE_BITFIELD_CHUNK;
             if (fBitCount % CMSTATE_BITFIELD_CHUNK)
                 fDynamicBuffer->fArraySize++;
-            fDynamicBuffer->fBitArray = (XMLInt32**) fDynamicBuffer->fMemoryManager->allocate(fDynamicBuffer->fArraySize*sizeof(XMLInt32*));
+            try
+            {
+                fDynamicBuffer->fBitArray = (XMLInt32**) fDynamicBuffer->fMemoryManager->allocate(fDynamicBuffer->fArraySize*sizeof(XMLInt32*));
+            }
+            catch( const OutOfMemoryException& )
+            {
+                fDynamicBuffer->fMemoryManager->deallocate(fDynamicBuffer);
+                throw;
+            }
             for(XMLSize_t index = 0; index < fDynamicBuffer->fArraySize; index++)
                 fDynamicBuffer->fBitArray[index]=NULL;
         }
diff --git a/src/xercesc/validators/common/DFAContentModel.cpp b/src/xercesc/validators/common/DFAContentModel.cpp
index 5030565..ddca8ec 100644
--- a/src/xercesc/validators/common/DFAContentModel.cpp
+++ b/src/xercesc/validators/common/DFAContentModel.cpp
@@ -38,6 +38,7 @@
 #include <xercesc/validators/schema/SchemaSymbols.hpp>
 #include <xercesc/validators/schema/SubstitutionGroupComparator.hpp>
 #include <xercesc/validators/schema/XercesElementWildcard.hpp>
+#include <xercesc/util/OutOfMemoryException.hpp>
 #include <xercesc/util/RefHashTableOf.hpp>
 #include <xercesc/util/XMLInteger.hpp>
 #include <math.h>
@@ -87,7 +88,15 @@ DFAContentModel::DFAContentModel( const bool             dtd
     , fMemoryManager(manager)
 {
     // And build the DFA data structures
-    buildDFA(elemContentSpec);
+    try
+    {
+        buildDFA(elemContentSpec);
+    }
+    catch( const OutOfMemoryException& )
+    {
+        cleanup();
+        throw;
+    }
 }
 
 DFAContentModel::DFAContentModel( const bool             dtd
@@ -115,37 +124,83 @@ DFAContentModel::DFAContentModel( const bool             dtd
     , fMemoryManager(manager)
 {
     // And build the DFA data structures
-    buildDFA(elemContentSpec);
+    try
+    {
+        buildDFA(elemContentSpec);
+    }
+    catch( const OutOfMemoryException& )
+    {
+        cleanup();
+        throw;
+    }
 }
 
 DFAContentModel::~DFAContentModel()
 {
+    cleanup();
+}
+
+void DFAContentModel::cleanup()
+{
     //
     //  Clean up all the stuff that is not just temporary representation
     //  data that was cleaned up after building the DFA.
     //
-    fMemoryManager->deallocate(fFinalStateFlags); //delete [] fFinalStateFlags;
+    if( fFinalStateFlags )
+    {
+        fMemoryManager->deallocate(fFinalStateFlags); //delete [] fFinalStateFlags;
+        fFinalStateFlags = NULL;
+    }
 
     unsigned int index;
-    for (index = 0; index < fTransTableSize; index++)
-        fMemoryManager->deallocate(fTransTable[index]); //delete [] fTransTable[index];
-    fMemoryManager->deallocate(fTransTable); //delete [] fTransTable;
+    if( fTransTable )
+    {
+        for (index = 0; index < fTransTableSize; index++)
+            fMemoryManager->deallocate(fTransTable[index]); //delete [] fTransTable[index];
+        fMemoryManager->deallocate(fTransTable); //delete [] fTransTable;
+        fTransTable = NULL;
+    }
 
     if(fCountingStates)
     {
         for (unsigned int j = 0; j < fTransTableSize; ++j)
             delete fCountingStates[j];
         fMemoryManager->deallocate(fCountingStates);
+        fCountingStates = NULL;
     }
 
-    for (index = 0; index < fLeafCount; index++)
-        delete fElemMap[index];
-    fMemoryManager->deallocate(fElemMap); //delete [] fElemMap;
+    if( fElemMap )
+    {
+        for (index = 0; index < fLeafCount; index++)
+            delete fElemMap[index];
+        fMemoryManager->deallocate(fElemMap); //delete [] fElemMap;
+        fElemMap = NULL;
+    }
 
     fMemoryManager->deallocate(fElemMapType); //delete [] fElemMapType;
+    fElemMapType = NULL;
+
     fMemoryManager->deallocate(fLeafListType); //delete [] fLeafListType;
+    fLeafListType = NULL;
 
     delete fLeafNameTypeVector;
+    fLeafNameTypeVector = NULL;
+
+    // Cleanup things that might now have been clean up by buildDFA()
+    // if an exception occured.
+    if( fFollowList )
+    {
+        for (index = 0; index < fLeafCount; index++)
+            delete fFollowList[index];
+        fMemoryManager->deallocate(fFollowList); //delete [] fFollowList;
+    }
+
+    if( fLeafList )
+    {
+        for (index = 0; index < fLeafCount; index++)
+            delete fLeafList[index];
+        fMemoryManager->deallocate(fLeafList); //delete [] fLeafList;
+    }
 }
 
 
@@ -612,6 +667,8 @@ void DFAContentModel::buildDFA(ContentSpecNode* const curNode)
     //  leaf nodes. We will put them in the array according to their position values
     //
     fLeafList = (CMLeaf**) fMemoryManager->allocate(fLeafCount*sizeof(CMLeaf*)); //new CMLeaf*[fLeafCount];
+    memset(fLeafList, 0, fLeafCount*sizeof(CMLeaf*));
+
     fLeafListType = (ContentSpecNode::NodeTypes*) fMemoryManager->allocate
     (
         fLeafCount * sizeof(ContentSpecNode::NodeTypes)
@@ -625,6 +682,7 @@ void DFAContentModel::buildDFA(ContentSpecNode* const curNode)
     (
         fLeafCount * sizeof(CMStateSet*)
     ); //new CMStateSet*[fLeafCount];
+    memset(fLeafList, 0, fLeafCount*sizeof(CMStateSet*));
     for (index = 0; index < fLeafCount; index++)
         fFollowList[index] = new (fMemoryManager) CMStateSet(fLeafCount, fMemoryManager);
 
@@ -793,7 +851,7 @@ void DFAContentModel::buildDFA(ContentSpecNode* const curNode)
      **/
     // don't forget to delete it
 #ifdef OPTIMIZED_BUT_STILL_LINEAR_SEARCH
-    int *fLeafSorter = (int*) fMemoryManager->allocate
+    int *leafSorter = (int*) fMemoryManager->allocate
     (
         (fLeafCount + fElemMapSize) * sizeof(int)
     ); //new int[fLeafCount + fElemMapSize];
@@ -811,23 +869,23 @@ void DFAContentModel::buildDFA(ContentSpecNode* const curNode)
             const QName* leaf = fLeafList[leafIndex]->getElement();
             if (fDTD) {
                 if (XMLString::equals(leaf->getRawName(), elementRawName)) {
-                    fLeafSorter[fSortCount++] = leafIndex;
+                    leafSorter[fSortCount++] = leafIndex;
                 }
             }
             else {
                 if ((fElemMapType[elemIndex] == fLeafListType[leafIndex]) &&
                     (leaf->getURI() == element->getURI()) &&
                     (XMLString::equals(leaf->getLocalPart(), element->getLocalPart()))) {
-                      fLeafSorter[fSortCount++] = leafIndex;
+                      leafSorter[fSortCount++] = leafIndex;
                 }
             }
         }
-        fLeafSorter[fSortCount++] = -1;
+        leafSorter[fSortCount++] = -1;
     }
 #endif
 
     // instead of using a single array with -1 to separate elements, use a bidimensional map
-    unsigned int** fLeafSorter = (unsigned int**)fMemoryManager->allocate(fElemMapSize * sizeof(unsigned int*));
+    unsigned int** leafSorter = (unsigned int**)fMemoryManager->allocate(fElemMapSize * sizeof(unsigned int*));
     unsigned int* tmpSorter = (unsigned int*)fMemoryManager->allocate(fLeafCount * sizeof(unsigned int));
     for (unsigned int elemIndex = 0; elemIndex < fElemMapSize; elemIndex++)
     {
@@ -854,10 +912,10 @@ void DFAContentModel::buildDFA(ContentSpecNode* const curNode)
             }
         }
 
-        fLeafSorter[elemIndex]=(unsigned int*)fMemoryManager->allocate((fSortCount+1) * sizeof(unsigned int));
-        fLeafSorter[elemIndex][0]=fSortCount;
+        leafSorter[elemIndex]=(unsigned int*)fMemoryManager->allocate((fSortCount+1) * sizeof(unsigned int));
+        leafSorter[elemIndex][0]=fSortCount;
         for (unsigned int index=0;index<fSortCount;index++)
-            fLeafSorter[elemIndex][index+1]=tmpSorter[index];
+            leafSorter[elemIndex][index+1]=tmpSorter[index];
     }
     fMemoryManager->deallocate(tmpSorter);
 
@@ -1015,7 +1073,7 @@ void DFAContentModel::buildDFA(ContentSpecNode* const curNode)
 
 #ifdef OPTIMIZED_BUT_STILL_LINEAR_SEARCH
             // Optimization(Jan, 2001)
-            int leafIndex = fLeafSorter[sorterIndex++];
+            int leafIndex = leafSorter[sorterIndex++];
 
             while (leafIndex != -1)
             {
@@ -1029,11 +1087,11 @@ void DFAContentModel::buildDFA(ContentSpecNode* const curNode)
                     //
                     *newSet |= *fFollowList[leafIndex];
                 }
-                leafIndex = fLeafSorter[sorterIndex++];
+                leafIndex = leafSorter[sorterIndex++];
             } // while (leafIndex != -1)
 #endif
 
-            unsigned int* fLeafIndexes=fLeafSorter[elemIndex];
+            unsigned int* fLeafIndexes=leafSorter[elemIndex];
             unsigned int fNumItems=fLeafIndexes[0];
             if(fNumItems!=0)
             {
@@ -1245,6 +1303,7 @@ void DFAContentModel::buildDFA(ContentSpecNode* const curNode)
     for (index = 0; index < fLeafCount; index++)
         delete fFollowList[index];
     fMemoryManager->deallocate(fFollowList); //delete [] fFollowList;
+    fFollowList = NULL;
 
     //
     // removeAll() will delete all data, XMLInteger,
@@ -1260,13 +1319,14 @@ void DFAContentModel::buildDFA(ContentSpecNode* const curNode)
     for (index = 0; index < fLeafCount; index++)
         delete fLeafList[index];
     fMemoryManager->deallocate(fLeafList); //delete [] fLeafList;
+    fLeafList = NULL;
 
 #ifdef OPTIMIZED_BUT_STILL_LINEAR_SEARCH
-    fMemoryManager->deallocate(fLeafSorter); //delete [] fLeafSorter;
+    fMemoryManager->deallocate(leafSorter); //delete [] leafSorter;
 #endif
     for (index=0; index < fElemMapSize; index++)
-        fMemoryManager->deallocate(fLeafSorter[index]);
-    fMemoryManager->deallocate(fLeafSorter);
+        fMemoryManager->deallocate(leafSorter[index]);
+    fMemoryManager->deallocate(leafSorter);
 }
 
 unsigned int DFAContentModel::countLeafNodes(ContentSpecNode* const curNode)
@@ -1369,13 +1429,21 @@ CMNode* DFAContentModel::buildSyntaxTree(ContentSpecNode* const curNode
             , fLeafCount
             , fMemoryManager
         );
-        fLeafList[curIndex] = new (fMemoryManager) CMLeaf
-        (
-            curNode->getElement()
-            , curIndex
-            , fLeafCount
-            , fMemoryManager
-        );
+        try
+        {
+            fLeafList[curIndex] = new (fMemoryManager) CMLeaf
+            (
+                curNode->getElement()
+                , curIndex
+                , fLeafCount
+                , fMemoryManager
+            );
+        }
+        catch( const OutOfMemoryException& )
+        {
+            delete retNode;
+            throw;
+        }
         fLeafListType[curIndex] = ContentSpecNode::Leaf;
         ++curIndex;
     }
@@ -1470,7 +1538,16 @@ CMNode* DFAContentModel::buildSyntaxTree(ContentSpecNode* const curNode
             //  same type as the source.
             //
             CMNode* newLeft = buildSyntaxTree(leftNode, curIndex);
-            CMNode* newRight = buildSyntaxTree(rightNode, curIndex);
+            CMNode* newRight;
+            try
+            {
+                newRight = buildSyntaxTree(rightNode, curIndex);
+            }
+            catch( const OutOfMemoryException& )
+            {
+                delete newLeft;
+                throw;
+            }
             if(((curType & 0x0f) == ContentSpecNode::Sequence))
             {
                 //
@@ -1492,14 +1569,23 @@ CMNode* DFAContentModel::buildSyntaxTree(ContentSpecNode* const curNode
                     *fFollowList[index] |= first;
                 }
             }
-            retNode = new (fMemoryManager) CMBinaryOp
-            (
-                curType
-                , newLeft
-                , newRight
-                , fLeafCount
-                , fMemoryManager
-            );
+            try
+            {
+                retNode = new (fMemoryManager) CMBinaryOp
+                (
+                    curType
+                    , newLeft
+                    , newRight
+                    , fLeafCount
+                    , fMemoryManager
+                );
+            }
+            catch( const OutOfMemoryException& )
+            {
+                delete newLeft;
+                delete newRight;
+                throw;
+            }
         }
          else if (curType == ContentSpecNode::ZeroOrMore
                || curType == ContentSpecNode::ZeroOrOne
@@ -1543,9 +1629,17 @@ CMNode* DFAContentModel::buildSyntaxTree(ContentSpecNode* const curNode
         }
     }
     // fault in the first and last pos, then delete it children
-    retNode->getFirstPos();
-    retNode->getLastPos();
-    retNode->orphanChild();
+    try
+    {
+        retNode->getFirstPos();
+        retNode->getLastPos();
+        retNode->orphanChild();
+    }
+    catch( const OutOfMemoryException& )
+    {
+        delete retNode;
+        throw;
+    }
     return retNode;
 }
 
diff --git a/src/xercesc/validators/common/DFAContentModel.hpp b/src/xercesc/validators/common/DFAContentModel.hpp
index d0439d1..c6f9143 100644
--- a/src/xercesc/validators/common/DFAContentModel.hpp
+++ b/src/xercesc/validators/common/DFAContentModel.hpp
@@ -128,6 +128,7 @@ private :
     // -----------------------------------------------------------------------
     //  Private helper methods
     // -----------------------------------------------------------------------
+    void cleanup();
     void buildDFA(ContentSpecNode* const curNode);
     CMNode* buildSyntaxTree(ContentSpecNode* const curNode, unsigned int& curIndex);
     unsigned int* makeDefStateList() const;
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.