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 <even.roua...@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-unsubscr...@xerces.apache.org For additional commands, e-mail: c-dev-h...@xerces.apache.org