You are viewing a plain text version of this content. The canonical link for it is here.
Posted to c-dev@xerces.apache.org by rl...@apache.org on 2021/10/24 07:01:52 UTC

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

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 <ev...@spatialys.com>
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;

---------------------------------------------------------------------
To unsubscribe, e-mail: c-dev-unsubscribe@xerces.apache.org
For additional commands, e-mail: c-dev-help@xerces.apache.org