Author: amassari
Date: Fri Apr 15 15:19:16 2011
New Revision: 1092737

URL: http://svn.apache.org/viewvc?rev=1092737&view=rev
Log:
Avoid recursion when dealing with ContentSpecNode objects; it can easily turn 
into a stack overflow (XERCESC-1935)

Modified:
    xerces/c/branches/xerces-2/   (props changed)
    xerces/c/branches/xerces-2/scripts/sanityTest_ExpectedResult.log
    xerces/c/branches/xerces-2/src/xercesc/validators/common/ContentSpecNode.cpp
    xerces/c/branches/xerces-2/src/xercesc/validators/common/ContentSpecNode.hpp

Propchange: xerces/c/branches/xerces-2/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Fri Apr 15 15:19:16 2011
@@ -1,5 +1,6 @@
+Build
 Makefile
 bin
+include
 lib
 obj
-include

Propchange: xerces/c/branches/xerces-2/
------------------------------------------------------------------------------
    svn:mergeinfo = /xerces/c/trunk:1092729

Modified: xerces/c/branches/xerces-2/scripts/sanityTest_ExpectedResult.log
URL: 
http://svn.apache.org/viewvc/xerces/c/branches/xerces-2/scripts/sanityTest_ExpectedResult.log?rev=1092737&r1=1092736&r2=1092737&view=diff
==============================================================================
--- xerces/c/branches/xerces-2/scripts/sanityTest_ExpectedResult.log (original)
+++ xerces/c/branches/xerces-2/scripts/sanityTest_ExpectedResult.log Fri Apr 15 
15:19:16 2011
@@ -982,7 +982,7 @@ Name:                       personnel
 Model Type:            Children
 Create Reason: Declared
 ContentType:   
-Content Model: (person,)
+Content Model: (person+)
 ComplexType:
        TypeName:       ,__AnonC0
        ContentType:    
@@ -991,7 +991,7 @@ Name:                       person
 Model Type:            Children
 Create Reason: Declared
 ContentType:   
-Content Model: ((name,email,url),link)
+Content Model: (name,email*,url*,link?)
 ComplexType:
        TypeName:       ,__AnonC1
        ContentType:    

Modified: 
xerces/c/branches/xerces-2/src/xercesc/validators/common/ContentSpecNode.cpp
URL: 
http://svn.apache.org/viewvc/xerces/c/branches/xerces-2/src/xercesc/validators/common/ContentSpecNode.cpp?rev=1092737&r1=1092736&r2=1092737&view=diff
==============================================================================
--- 
xerces/c/branches/xerces-2/src/xercesc/validators/common/ContentSpecNode.cpp 
(original)
+++ 
xerces/c/branches/xerces-2/src/xercesc/validators/common/ContentSpecNode.cpp 
Fri Apr 15 15:19:16 2011
@@ -26,6 +26,7 @@
 #include <xercesc/framework/XMLBuffer.hpp>
 #include <xercesc/validators/common/ContentSpecNode.hpp>
 #include <xercesc/validators/schema/SchemaSymbols.hpp>
+#include <xercesc/util/ValueStackOf.hpp>
 
 XERCES_CPP_NAMESPACE_BEGIN
 
@@ -64,107 +65,191 @@ ContentSpecNode::ContentSpecNode(const C
         fSecond = new (fMemoryManager) ContentSpecNode(*tmp);
 }
 
+ContentSpecNode::~ContentSpecNode()
+{
+    // Delete our children, avoiding recursive cleanup
+    if (fAdoptFirst && fFirst) {
+               deleteChildNode(fFirst);
+    }
+
+    if (fAdoptSecond && fSecond) {
+               deleteChildNode(fSecond);
+    }
+
+    delete fElement;
+}
+
+void ContentSpecNode::deleteChildNode(ContentSpecNode* node)
+{
+       ValueStackOf<ContentSpecNode*> toBeDeleted(10, fMemoryManager);
+       toBeDeleted.push(node);
+       while(!toBeDeleted.empty())
+       {
+               ContentSpecNode* node = toBeDeleted.pop();
+               if(node==0)
+                       continue;
+               if(node->isFirstAdopted())
+                       toBeDeleted.push(node->orphanFirst());
+               if(node->isSecondAdopted())
+                       toBeDeleted.push(node->orphanSecond());
+               delete node;
+       }
+}
+
+class formatNodeHolder
+{
+public:
+       formatNodeHolder(const ContentSpecNode* n, const 
ContentSpecNode::NodeTypes p, XMLCh c) : node(n), parentType(p), character(c) {}
+       formatNodeHolder& operator =(const formatNodeHolder* other)
+       {
+               node=other->node;
+               parentType=other->parentType;
+               character=other->character;
+       }
+
+       const ContentSpecNode* node;
+       ContentSpecNode::NodeTypes parentType;
+       XMLCh character;
+};
+
 // ---------------------------------------------------------------------------
 //  Local methods
 // ---------------------------------------------------------------------------
 static void formatNode( const   ContentSpecNode* const      curNode
-                        , const ContentSpecNode::NodeTypes  parentType
-                        ,       XMLBuffer&                  bufToFill)
+                        ,       XMLBuffer&                  bufToFill
+                                               ,               MemoryManager* 
const            memMgr)
 {
     if (!curNode)
         return;
 
-    const ContentSpecNode* first = curNode->getFirst();
-    const ContentSpecNode* second = curNode->getSecond();
-    const ContentSpecNode::NodeTypes curType = curNode->getType();
-
-    // Get the type of the first node
-    const ContentSpecNode::NodeTypes firstType = first ?
-                                                 first->getType() :
-                                                 ContentSpecNode::Leaf;
-
-    // Calculate the parens flag for the rep nodes
-    bool doRepParens = false;
-    if (((firstType != ContentSpecNode::Leaf)
-            && (parentType != ContentSpecNode::UnknownType))
-    ||  ((firstType == ContentSpecNode::Leaf)
-            && (parentType == ContentSpecNode::UnknownType)))
-    {
-        doRepParens = true;
-    }
+       ValueStackOf<formatNodeHolder> toBeProcessed(10, memMgr);
+       toBeProcessed.push(formatNodeHolder(curNode, 
ContentSpecNode::UnknownType, 0));
 
-    // Now handle our type
-    switch(curType & 0x0f)
-    {
-        case ContentSpecNode::Leaf :
-            if (curNode->getElement()->getURI() == 
XMLElementDecl::fgPCDataElemId)
-                bufToFill.append(XMLElementDecl::fgPCDataElemName);
-            else
-                bufToFill.append(curNode->getElement()->getRawName());
-            break;
-
-        case ContentSpecNode::ZeroOrOne :
-            if (doRepParens)
-                bufToFill.append(chOpenParen);
-            formatNode(first, curType, bufToFill);
-            if (doRepParens)
-                bufToFill.append(chCloseParen);
-            bufToFill.append(chQuestion);
-            break;
-
-        case ContentSpecNode::ZeroOrMore :
-            if (doRepParens)
-                bufToFill.append(chOpenParen);
-            formatNode(first, curType, bufToFill);
-            if (doRepParens)
-                bufToFill.append(chCloseParen);
-            bufToFill.append(chAsterisk);
-            break;
-
-        case ContentSpecNode::OneOrMore :
-            if (doRepParens)
-                bufToFill.append(chOpenParen);
-            formatNode(first, curType, bufToFill);
-            if (doRepParens)
-                bufToFill.append(chCloseParen);
-            bufToFill.append(chPlus);
-            break;
-
-        case ContentSpecNode::Choice :
-            if (parentType != curType)
-                bufToFill.append(chOpenParen);
-            formatNode(first, curType, bufToFill);
-            bufToFill.append(chPipe);
-            formatNode(second, curType, bufToFill);
-            if (parentType != curType)
-                bufToFill.append(chCloseParen);
-            break;
-
-        case ContentSpecNode::Sequence :
-            if (parentType != curType)
-                bufToFill.append(chOpenParen);
-            formatNode(first, curType, bufToFill);
-            bufToFill.append(chComma);
-            formatNode(second, curType, bufToFill);
-            if (parentType != curType)
-                bufToFill.append(chCloseParen);
-            break;
-
-        case ContentSpecNode::All :
-            if (parentType != curType)
-                       {
-                bufToFill.append(chLatin_A);
-                bufToFill.append(chLatin_l);
-                bufToFill.append(chLatin_l);
-                bufToFill.append(chOpenParen);
-                       }
-            formatNode(first, curType, bufToFill);
-            bufToFill.append(chComma);
-            formatNode(second, curType, bufToFill);
-            if (parentType != curType)
-                bufToFill.append(chCloseParen);
-            break;
-    }
+       while(!toBeProcessed.empty())
+       {
+               formatNodeHolder item=toBeProcessed.pop();
+               if(item.character!=0)
+               {
+                       bufToFill.append(item.character);
+                       continue;
+               }
+               const ContentSpecNode* curNode = item.node;
+               if(!curNode)
+                       continue;
+               const ContentSpecNode::NodeTypes parentType = item.parentType; 
+               const ContentSpecNode* first = curNode->getFirst();
+               const ContentSpecNode* second = curNode->getSecond();
+               const ContentSpecNode::NodeTypes curType = curNode->getType();
+
+               // Get the type of the first node
+               const ContentSpecNode::NodeTypes firstType = first ?
+                                                                               
                         first->getType() :
+                                                                               
                         ContentSpecNode::Leaf;
+
+               // Calculate the parens flag for the rep nodes
+               bool doRepParens = false;
+               if (((firstType != ContentSpecNode::Leaf)
+                               && (parentType != ContentSpecNode::UnknownType))
+               ||  ((firstType == ContentSpecNode::Leaf)
+                               && (parentType == 
ContentSpecNode::UnknownType)))
+               {
+                       doRepParens = true;
+               }
+
+               // Now handle our type
+               switch(curType & 0x0f)
+               {
+                       case ContentSpecNode::Leaf :
+                               if (curNode->getElement()->getURI() == 
XMLElementDecl::fgPCDataElemId)
+                                       
bufToFill.append(XMLElementDecl::fgPCDataElemName);
+                               else
+                               {
+                                       
bufToFill.append(curNode->getElement()->getRawName());
+                                       // show the + and * modifiers also when 
we have a non-infinite number of repetitions
+                                       if(curNode->getMinOccurs()==0 && 
(curNode->getMaxOccurs()==-1 || curNode->getMaxOccurs()>1))
+                                               bufToFill.append(chAsterisk);
+                                       else if(curNode->getMinOccurs()==0 && 
curNode->getMaxOccurs()==1)
+                                               bufToFill.append(chQuestion);
+                                       else if(curNode->getMinOccurs()==1 && 
(curNode->getMaxOccurs()==-1 || curNode->getMaxOccurs()>1))
+                                               bufToFill.append(chPlus);
+                               }
+                               break;
+
+                       case ContentSpecNode::ZeroOrOne :
+                               if (doRepParens)
+                                       bufToFill.append(chOpenParen);
+
+                               toBeProcessed.push(formatNodeHolder(0, 
ContentSpecNode::UnknownType, chQuestion));
+                               if (doRepParens)
+                                       toBeProcessed.push(formatNodeHolder(0, 
ContentSpecNode::UnknownType, chCloseParen));
+                               toBeProcessed.push(formatNodeHolder(first, 
curType, 0));
+                               break;
+
+                       case ContentSpecNode::ZeroOrMore :
+                               if (doRepParens)
+                                       bufToFill.append(chOpenParen);
+
+                               toBeProcessed.push(formatNodeHolder(0, 
ContentSpecNode::UnknownType, chAsterisk));
+                               if (doRepParens)
+                                       toBeProcessed.push(formatNodeHolder(0, 
ContentSpecNode::UnknownType, chCloseParen));
+                               toBeProcessed.push(formatNodeHolder(first, 
curType, 0));
+                               break;
+
+                       case ContentSpecNode::OneOrMore :
+                               if (doRepParens)
+                                       bufToFill.append(chOpenParen);
+
+                               toBeProcessed.push(formatNodeHolder(0, 
ContentSpecNode::UnknownType, chPlus));
+                               if (doRepParens)
+                                       toBeProcessed.push(formatNodeHolder(0, 
ContentSpecNode::UnknownType, chCloseParen));
+                               toBeProcessed.push(formatNodeHolder(first, 
curType, 0));
+                               break;
+
+                       case ContentSpecNode::Choice :
+                               if ((parentType & 0x0f) != (curType & 0x0f))
+                                       bufToFill.append(chOpenParen);
+
+                               if ((parentType & 0x0f) != (curType & 0x0f))
+                                       toBeProcessed.push(formatNodeHolder(0, 
ContentSpecNode::UnknownType, chCloseParen));
+                               if(second!=NULL)
+                               {
+                                       
toBeProcessed.push(formatNodeHolder(second, curType, 0));
+                                       toBeProcessed.push(formatNodeHolder(0, 
ContentSpecNode::UnknownType, chPipe));
+                               }
+                               toBeProcessed.push(formatNodeHolder(first, 
curType, 0));
+                               break;
+
+                       case ContentSpecNode::Sequence :
+                               if ((parentType & 0x0f) != (curType & 0x0f))
+                                       bufToFill.append(chOpenParen);
+
+                               if ((parentType & 0x0f) != (curType & 0x0f))
+                                       toBeProcessed.push(formatNodeHolder(0, 
ContentSpecNode::UnknownType, chCloseParen));
+                               if(second!=NULL)
+                               {
+                                       
toBeProcessed.push(formatNodeHolder(second, curType, 0));
+                                       toBeProcessed.push(formatNodeHolder(0, 
ContentSpecNode::UnknownType, chComma));
+                               }
+                               toBeProcessed.push(formatNodeHolder(first, 
curType, 0));
+                               break;
+
+                       case ContentSpecNode::All :
+                               if ((parentType & 0x0f) != (curType & 0x0f))
+                               {
+                                       bufToFill.append(chLatin_A);
+                                       bufToFill.append(chLatin_l);
+                                       bufToFill.append(chLatin_l);
+                                       bufToFill.append(chOpenParen);
+                               }
+
+                               if ((parentType & 0x0f) != (curType & 0x0f))
+                                       toBeProcessed.push(formatNodeHolder(0, 
ContentSpecNode::UnknownType, chCloseParen));
+                               toBeProcessed.push(formatNodeHolder(second, 
curType, 0));
+                               toBeProcessed.push(formatNodeHolder(0, 
ContentSpecNode::UnknownType, chComma));
+                               toBeProcessed.push(formatNodeHolder(first, 
curType, 0));
+                               break;
+               }
+       }
 }
 
 
@@ -181,8 +266,8 @@ void ContentSpecNode::formatSpec(XMLBuff
     formatNode
     (
         this
-        , UnknownType
-        , bufToFill
+               , bufToFill
+        , fMemoryManager
     );
     if (fType == ContentSpecNode::Leaf)
         bufToFill.append(chCloseParen);

Modified: 
xerces/c/branches/xerces-2/src/xercesc/validators/common/ContentSpecNode.hpp
URL: 
http://svn.apache.org/viewvc/xerces/c/branches/xerces-2/src/xercesc/validators/common/ContentSpecNode.hpp?rev=1092737&r1=1092736&r2=1092737&view=diff
==============================================================================
--- 
xerces/c/branches/xerces-2/src/xercesc/validators/common/ContentSpecNode.hpp 
(original)
+++ 
xerces/c/branches/xerces-2/src/xercesc/validators/common/ContentSpecNode.hpp 
Fri Apr 15 15:19:16 2011
@@ -150,6 +150,10 @@ private :
     // -----------------------------------------------------------------------
     ContentSpecNode& operator=(const ContentSpecNode&);
 
+       // 
-----------------------------------------------------------------------
+    // Helper functions
+    // -----------------------------------------------------------------------
+       void deleteChildNode(ContentSpecNode* node);
 
     // -----------------------------------------------------------------------
     //  Private Data Members
@@ -303,20 +307,6 @@ ContentSpecNode::ContentSpecNode(const  
 {
 }
 
-inline ContentSpecNode::~ContentSpecNode()
-{
-    // Delete our children, which cause recursive cleanup
-    if (fAdoptFirst) {
-               delete fFirst;
-    }
-
-    if (fAdoptSecond) {
-               delete fSecond;
-    }
-
-    delete fElement;
-}
-
 // ---------------------------------------------------------------------------
 //  ContentSpecNode: Getter methods
 // ---------------------------------------------------------------------------



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to