[xerces-c] 01/02: Merge pull request #40 from rouault/fix_memleaks_DFAContentModel

[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.

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

commit 0b6165652fc7b8d93cb4af820de7c7f5a5998beb
Author: Roger Leigh <[email protected]>
AuthorDate: Sun Oct 24 08:01:46 2021 +0100

    Merge pull request #40 from rouault/fix_memleaks_DFAContentModel
    
    [XERCESC-2228] DFAContentModel: fix memory leaks when OutOfMemoryException occurs
---
 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 6bb275892..e018dc80a 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 2ae4b7d8e..56d77311d 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;
     }
@@ -1482,7 +1550,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))
             {
                 //
@@ -1504,14 +1581,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
@@ -1555,9 +1641,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 f0836e175..1ef847baf 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.