You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@xerces.apache.org by am...@apache.org on 2011/04/15 16:56:36 UTC

svn commit: r1092729 - in /xerces/c/trunk/src/xercesc/validators/common: ContentSpecNode.cpp ContentSpecNode.hpp

Author: amassari
Date: Fri Apr 15 14:56:36 2011
New Revision: 1092729

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

Modified:
    xerces/c/trunk/src/xercesc/validators/common/ContentSpecNode.cpp
    xerces/c/trunk/src/xercesc/validators/common/ContentSpecNode.hpp

Modified: xerces/c/trunk/src/xercesc/validators/common/ContentSpecNode.cpp
URL: http://svn.apache.org/viewvc/xerces/c/trunk/src/xercesc/validators/common/ContentSpecNode.cpp?rev=1092729&r1=1092728&r2=1092729&view=diff
==============================================================================
--- xerces/c/trunk/src/xercesc/validators/common/ContentSpecNode.cpp (original)
+++ xerces/c/trunk/src/xercesc/validators/common/ContentSpecNode.cpp Fri Apr 15 14:56:36 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,122 +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;
-    }
-
-    // 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;
+	ValueStackOf<formatNodeHolder> toBeProcessed(10, memMgr);
+	toBeProcessed.push(formatNodeHolder(curNode, ContentSpecNode::UnknownType, 0));
 
-        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 & 0x0f) != (curType & 0x0f))
-                bufToFill.append(chOpenParen);
-            formatNode(first, curType, bufToFill);
-            if(second!=NULL)
-            {
-                bufToFill.append(chPipe);
-                formatNode(second, curType, bufToFill);
-            }
-            if ((parentType & 0x0f) != (curType & 0x0f))
-                bufToFill.append(chCloseParen);
-            break;
-
-        case ContentSpecNode::Sequence :
-            if ((parentType & 0x0f) != (curType & 0x0f))
-                bufToFill.append(chOpenParen);
-            formatNode(first, curType, bufToFill);
-            if(second!=NULL)
-            {
-                bufToFill.append(chComma);
-                formatNode(second, curType, bufToFill);
-            }
-            if ((parentType & 0x0f) != (curType & 0x0f))
-                bufToFill.append(chCloseParen);
-            break;
-
-        case ContentSpecNode::All :
-            if ((parentType & 0x0f) != (curType & 0x0f))
-			{
-                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 & 0x0f) != (curType & 0x0f))
-                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;
+		}
+	}
 }
 
 
@@ -196,8 +266,8 @@ void ContentSpecNode::formatSpec(XMLBuff
     formatNode
     (
         this
-        , UnknownType
-        , bufToFill
+		, bufToFill
+        , fMemoryManager
     );
     if (fType == ContentSpecNode::Leaf)
         bufToFill.append(chCloseParen);

Modified: xerces/c/trunk/src/xercesc/validators/common/ContentSpecNode.hpp
URL: http://svn.apache.org/viewvc/xerces/c/trunk/src/xercesc/validators/common/ContentSpecNode.hpp?rev=1092729&r1=1092728&r2=1092729&view=diff
==============================================================================
--- xerces/c/trunk/src/xercesc/validators/common/ContentSpecNode.hpp (original)
+++ xerces/c/trunk/src/xercesc/validators/common/ContentSpecNode.hpp Fri Apr 15 14:56:36 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: commits-unsubscribe@xerces.apache.org
For additional commands, e-mail: commits-help@xerces.apache.org