Merge pull request #39 from rouault/memleak_fixes_ContentSpecNode_ComplexTypeInfo

[XERCESC-2227] Memleak fixes in ContentSpecNode and ComplexTypeInfo classes
diff --git a/src/xercesc/validators/common/ContentSpecNode.cpp b/src/xercesc/validators/common/ContentSpecNode.cpp
index 9fc0233..387dfca 100644
--- a/src/xercesc/validators/common/ContentSpecNode.cpp
+++ b/src/xercesc/validators/common/ContentSpecNode.cpp
@@ -26,6 +26,7 @@
 #include <xercesc/framework/XMLBuffer.hpp>
 #include <xercesc/validators/common/ContentSpecNode.hpp>
 #include <xercesc/validators/schema/SchemaSymbols.hpp>
+#include <xercesc/util/OutOfMemoryException.hpp>
 #include <xercesc/util/ValueStackOf.hpp>
 
 namespace XERCES_CPP_NAMESPACE {
@@ -52,31 +53,49 @@
     , fMinOccurs(toCopy.fMinOccurs)
     , fMaxOccurs(toCopy.fMaxOccurs)
 {
-    const QName* tempElement = toCopy.getElement();
-    if (tempElement)
-        fElement = new (fMemoryManager) QName(*tempElement);
+    try
+    {
+        const QName* tempElement = toCopy.getElement();
+        if (tempElement)
+            fElement = new (fMemoryManager) QName(*tempElement);
 
-    const ContentSpecNode *tmp = toCopy.getFirst();
-    if (tmp)
-        fFirst = new (fMemoryManager) ContentSpecNode(*tmp);
+        const ContentSpecNode *tmp = toCopy.getFirst();
+        if (tmp)
+            fFirst = new (fMemoryManager) ContentSpecNode(*tmp);
 
-    tmp = toCopy.getSecond();
-    if (tmp)
-        fSecond = new (fMemoryManager) ContentSpecNode(*tmp);
+        tmp = toCopy.getSecond();
+        if (tmp)
+            fSecond = new (fMemoryManager) ContentSpecNode(*tmp);
+    }
+    catch (const OutOfMemoryException&)
+    {
+        cleanup();
+
+        throw;
+    }
+
 }
 
 ContentSpecNode::~ContentSpecNode()
 {
+    cleanup();
+}
+
+void ContentSpecNode::cleanup()
+{
     // Delete our children, avoiding recursive cleanup
     if (fAdoptFirst && fFirst) {
-		deleteChildNode(fFirst);
+        deleteChildNode(fFirst);
+        fFirst = NULL;
     }
 
     if (fAdoptSecond && fSecond) {
-		deleteChildNode(fSecond);
+        deleteChildNode(fSecond);
+        fSecond = NULL;
     }
 
     delete fElement;
+    fElement = NULL;
 }
 
 void ContentSpecNode::deleteChildNode(ContentSpecNode* node)
diff --git a/src/xercesc/validators/common/ContentSpecNode.hpp b/src/xercesc/validators/common/ContentSpecNode.hpp
index 1b174e3..38deeb3 100644
--- a/src/xercesc/validators/common/ContentSpecNode.hpp
+++ b/src/xercesc/validators/common/ContentSpecNode.hpp
@@ -150,6 +150,8 @@
     // -----------------------------------------------------------------------
     ContentSpecNode& operator=(const ContentSpecNode&);
 
+    void cleanup();
+
 	// -----------------------------------------------------------------------
     // Helper functions
     // -----------------------------------------------------------------------
diff --git a/src/xercesc/validators/schema/ComplexTypeInfo.cpp b/src/xercesc/validators/schema/ComplexTypeInfo.cpp
index 1822e3f..ee650ce 100644
--- a/src/xercesc/validators/schema/ComplexTypeInfo.cpp
+++ b/src/xercesc/validators/schema/ComplexTypeInfo.cpp
@@ -32,6 +32,7 @@
 #include <xercesc/validators/common/SimpleContentModel.hpp>
 #include <xercesc/validators/schema/XSDLocator.hpp>
 #include <xercesc/internal/XTemplateSerializer.hpp>
+#include <xercesc/util/OutOfMemoryException.hpp>
 #include <xercesc/util/XMLInitializer.hpp>
 
 namespace XERCES_CPP_NAMESPACE {
@@ -323,10 +324,19 @@
     ContentSpecNode* aSpecNode = new (fMemoryManager) ContentSpecNode(*fContentSpec);
 
     if (checkUPA) {
-        fContentSpecOrgURI = (unsigned int*) fMemoryManager->allocate
-        (
-            fContentSpecOrgURISize * sizeof(unsigned int)
-        ); //new unsigned int[fContentSpecOrgURISize];
+        try
+        {
+            fContentSpecOrgURI = (unsigned int*) fMemoryManager->allocate
+            (
+                fContentSpecOrgURISize * sizeof(unsigned int)
+            ); //new unsigned int[fContentSpecOrgURISize];
+        }
+        catch (const OutOfMemoryException&)
+        {
+            delete aSpecNode;
+
+            throw;
+        }
     }
 
     aSpecNode = convertContentSpecTree(aSpecNode, checkUPA, useRepeatingLeafNodes(aSpecNode));
@@ -516,12 +526,31 @@
         ||   ((curType & 0x0f) == ContentSpecNode::Sequence))
     {
         ContentSpecNode* childNode = curNode->getFirst();
-        ContentSpecNode* leftNode = convertContentSpecTree(childNode, checkUPA, bAllowCompactSyntax);
+        ContentSpecNode* leftNode;
+        try
+        {
+            leftNode = convertContentSpecTree(childNode, checkUPA, bAllowCompactSyntax);
+        }
+        catch( const OutOfMemoryException& )
+        {
+            curNode->setAdoptFirst(false);
+            delete curNode;
+            throw;
+        }
         ContentSpecNode* rightNode = curNode->getSecond();
 
         if (!rightNode) {
 
-            retNode = expandContentModel(leftNode, minOccurs, maxOccurs, bAllowCompactSyntax);
+            try
+            {
+                retNode = expandContentModel(leftNode, minOccurs, maxOccurs, bAllowCompactSyntax);
+            }
+            catch( const OutOfMemoryException& )
+            {
+                curNode->setAdoptFirst(false);
+                delete curNode;
+                throw;
+            }
             curNode->setAdoptFirst(false);
             delete curNode;
             return retNode;
@@ -535,7 +564,16 @@
         }
 
         childNode = rightNode;
-        rightNode =  convertContentSpecTree(childNode, checkUPA, bAllowCompactSyntax);
+        try
+        {
+            rightNode =  convertContentSpecTree(childNode, checkUPA, bAllowCompactSyntax);
+        }
+        catch( const OutOfMemoryException& )
+        {
+            curNode->setAdoptSecond(false);
+            delete curNode;
+            throw;
+        }
 
         if (rightNode != childNode) {
 
@@ -559,65 +597,26 @@
         return 0;
     }
 
-    ContentSpecNode* saveNode = specNode;
+    ContentSpecNode* const saveNode = specNode;
     ContentSpecNode* retNode = specNode;
 
-    if (minOccurs == 1 && maxOccurs == 1) {
-    }
-    else if (minOccurs == 0 && maxOccurs == 1) {
-
-        retNode = new (fMemoryManager) ContentSpecNode
-        (
-            ContentSpecNode::ZeroOrOne
-            , retNode
-            , 0
-            , true
-            , true
-            , fMemoryManager
-        );
-    }
-    else if (minOccurs == 0 && maxOccurs == -1) {
-        retNode = new (fMemoryManager) ContentSpecNode
-        (
-            ContentSpecNode::ZeroOrMore
-            , retNode
-            , 0
-            , true
-            , true
-            , fMemoryManager
-        );
-    }
-    else if (minOccurs == 1 && maxOccurs == -1) {
-        retNode = new (fMemoryManager) ContentSpecNode
-        (
-            ContentSpecNode::OneOrMore
-            , retNode
-            , 0
-            , true
-            , true
-            , fMemoryManager
-        );
-    }
-    // if what is being repeated is a leaf avoid expanding the tree
-    else if(bAllowCompactSyntax &&
-        (saveNode->getType()==ContentSpecNode::Leaf ||
-        (saveNode->getType() & 0x0f)==ContentSpecNode::Any ||
-        (saveNode->getType() & 0x0f)==ContentSpecNode::Any_Other ||
-        (saveNode->getType() & 0x0f)==ContentSpecNode::Any_NS))
+    try
     {
-        retNode = new (fMemoryManager) ContentSpecNode
-        (
-            ContentSpecNode::Loop
-            , retNode
-            , 0
-            , true
-            , true
-            , fMemoryManager
-        );
-        retNode->setMinOccurs(minOccurs);
-        retNode->setMaxOccurs(maxOccurs);
+        if (minOccurs == 1 && maxOccurs == 1) {
+        }
+        else if (minOccurs == 0 && maxOccurs == 1) {
 
-        if(minOccurs==0)
+            retNode = new (fMemoryManager) ContentSpecNode
+            (
+                ContentSpecNode::ZeroOrOne
+                , retNode
+                , 0
+                , true
+                , true
+                , fMemoryManager
+            );
+        }
+        else if (minOccurs == 0 && maxOccurs == -1) {
             retNode = new (fMemoryManager) ContentSpecNode
             (
                 ContentSpecNode::ZeroOrMore
@@ -627,7 +626,61 @@
                 , true
                 , fMemoryManager
             );
-        else
+        }
+        else if (minOccurs == 1 && maxOccurs == -1) {
+            retNode = new (fMemoryManager) ContentSpecNode
+            (
+                ContentSpecNode::OneOrMore
+                , retNode
+                , 0
+                , true
+                , true
+                , fMemoryManager
+            );
+        }
+        // if what is being repeated is a leaf avoid expanding the tree
+        else if(bAllowCompactSyntax &&
+            (saveNode->getType()==ContentSpecNode::Leaf ||
+            (saveNode->getType() & 0x0f)==ContentSpecNode::Any ||
+            (saveNode->getType() & 0x0f)==ContentSpecNode::Any_Other ||
+            (saveNode->getType() & 0x0f)==ContentSpecNode::Any_NS))
+        {
+            retNode = new (fMemoryManager) ContentSpecNode
+            (
+                ContentSpecNode::Loop
+                , retNode
+                , 0
+                , true
+                , true
+                , fMemoryManager
+            );
+            retNode->setMinOccurs(minOccurs);
+            retNode->setMaxOccurs(maxOccurs);
+
+            if(minOccurs==0)
+                retNode = new (fMemoryManager) ContentSpecNode
+                (
+                    ContentSpecNode::ZeroOrMore
+                    , retNode
+                    , 0
+                    , true
+                    , true
+                    , fMemoryManager
+                );
+            else
+                retNode = new (fMemoryManager) ContentSpecNode
+                (
+                    ContentSpecNode::OneOrMore
+                    , retNode
+                    , 0
+                    , true
+                    , true
+                    , fMemoryManager
+                );
+
+        }
+        else if (maxOccurs == -1) {
+
             retNode = new (fMemoryManager) ContentSpecNode
             (
                 ContentSpecNode::OneOrMore
@@ -638,112 +691,35 @@
                 , fMemoryManager
             );
 
-    }
-    else if (maxOccurs == -1) {
-
-        retNode = new (fMemoryManager) ContentSpecNode
-        (
-            ContentSpecNode::OneOrMore
-            , retNode
-            , 0
-            , true
-            , true
-            , fMemoryManager
-        );
-
-        for (int i=0; i < (minOccurs-1); i++) {
-            retNode = new (fMemoryManager) ContentSpecNode
-            (
-                ContentSpecNode::Sequence
-                , saveNode
-                , retNode
-                , false
-                , true
-                , fMemoryManager
-            );
-        }
-    }
-    else {
-
-        if (minOccurs == 0) {
-
-            ContentSpecNode* optional = new (fMemoryManager) ContentSpecNode
-            (
-                ContentSpecNode::ZeroOrOne
-                , saveNode
-                , 0
-                , true
-                , true
-                , fMemoryManager
-            );
-
-            retNode = optional;
-
-            for (int i=0; i < (maxOccurs-1); i++) {
+            for (int i=0; i < (minOccurs-1); i++) {
                 retNode = new (fMemoryManager) ContentSpecNode
                 (
                     ContentSpecNode::Sequence
+                    , saveNode
                     , retNode
-                    , optional
-                    , true
                     , false
+                    , true
                     , fMemoryManager
                 );
             }
         }
         else {
 
-            if (minOccurs > 1) {
-
-                retNode = new (fMemoryManager) ContentSpecNode
-                (
-                    ContentSpecNode::Sequence
-                    , retNode
-                    , saveNode
-                    , true
-                    , false
-                    , fMemoryManager
-                );
-
-                for (int i=1; i < (minOccurs-1); i++) {
-                    retNode = new (fMemoryManager) ContentSpecNode
-                    (
-                        ContentSpecNode::Sequence
-                        , retNode
-                        , saveNode
-                        , true
-                        , false
-                        , fMemoryManager
-                    );
-                }
-            }
-
-            int counter = maxOccurs-minOccurs;
-
-            if (counter > 0) {
+            if (minOccurs == 0) {
 
                 ContentSpecNode* optional = new (fMemoryManager) ContentSpecNode
                 (
                     ContentSpecNode::ZeroOrOne
                     , saveNode
                     , 0
-                    , false
-                    , true
-                    , fMemoryManager
-                );
-
-                retNode = new (fMemoryManager) ContentSpecNode
-                (
-                    ContentSpecNode::Sequence
-                    , retNode
-                    , optional
                     , true
                     , true
                     , fMemoryManager
                 );
 
-                for (int j=1; j < counter; j++) {
+                retNode = optional;
 
+                for (int i=0; i < (maxOccurs-1); i++) {
                     retNode = new (fMemoryManager) ContentSpecNode
                     (
                         ContentSpecNode::Sequence
@@ -755,8 +731,86 @@
                     );
                 }
             }
+            else {
+
+                if (minOccurs > 1) {
+
+                    retNode = new (fMemoryManager) ContentSpecNode
+                    (
+                        ContentSpecNode::Sequence
+                        , retNode
+                        , saveNode
+                        , true
+                        , false
+                        , fMemoryManager
+                    );
+
+                    for (int i=1; i < (minOccurs-1); i++) {
+                        retNode = new (fMemoryManager) ContentSpecNode
+                        (
+                            ContentSpecNode::Sequence
+                            , retNode
+                            , saveNode
+                            , true
+                            , false
+                            , fMemoryManager
+                        );
+                    }
+                }
+
+                int counter = maxOccurs-minOccurs;
+
+                if (counter > 0) {
+
+                    ContentSpecNode* optional = new (fMemoryManager) ContentSpecNode
+                    (
+                        ContentSpecNode::ZeroOrOne
+                        , saveNode
+                        , 0
+                        , false
+                        , true
+                        , fMemoryManager
+                    );
+
+                    try
+                    {
+                        retNode = new (fMemoryManager) ContentSpecNode
+                        (
+                            ContentSpecNode::Sequence
+                            , retNode
+                            , optional
+                            , true
+                            , true
+                            , fMemoryManager
+                        );
+                    }
+                    catch( const OutOfMemoryException& )
+                    {
+                        delete optional;
+                        throw;
+                    }
+
+                    for (int j=1; j < counter; j++) {
+
+                        retNode = new (fMemoryManager) ContentSpecNode
+                        (
+                            ContentSpecNode::Sequence
+                            , retNode
+                            , optional
+                            , true
+                            , false
+                            , fMemoryManager
+                        );
+                    }
+                }
+            }
         }
     }
+    catch( const OutOfMemoryException& )
+    {
+        delete retNode;
+        throw;
+    }
 
     return retNode;
 }