Lee Thomason пре 8 година
родитељ
комит
e84f68a68a
3 измењених фајлова са 79 додато и 3 уклоњено
  1. 31 3
      tinyxml2.cpp
  2. 19 0
      tinyxml2.h
  3. 29 0
      xmltest.cpp

+ 31 - 3
tinyxml2.cpp

@@ -797,9 +797,11 @@ void XMLNode::Unlink( XMLNode* child )
 
     if ( child->_prev ) {
         child->_prev->_next = child->_next;
+        child->_prev = 0;
     }
     if ( child->_next ) {
         child->_next->_prev = child->_prev;
+        child->_next = 0;
     }
 	child->_parent = 0;
 }
@@ -811,6 +813,9 @@ void XMLNode::DeleteChild( XMLNode* node )
     TIXMLASSERT( node->_document == _document );
     TIXMLASSERT( node->_parent == this );
     Unlink( node );
+	TIXMLASSERT(node->_prev == 0);
+	TIXMLASSERT(node->_next == 0);
+	TIXMLASSERT(node->_parent == 0);
     DeleteNode( node );
 }
 
@@ -1055,11 +1060,16 @@ char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
     return 0;
 }
 
-void XMLNode::DeleteNode( XMLNode* node )
+/*static*/ void XMLNode::DeleteNode( XMLNode* node )
 {
     if ( node == 0 ) {
         return;
     }
+	TIXMLASSERT(node->_document);
+	if (!node->ToDocument()) {
+		node->_document->MarkInUse(node);
+	}
+
     MemPool* pool = node->_memPool;
     node->~XMLNode();
     pool->Free( node );
@@ -1070,10 +1080,13 @@ void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
     TIXMLASSERT( insertThis );
     TIXMLASSERT( insertThis->_document == _document );
 
-    if ( insertThis->_parent )
+	if (insertThis->_parent) {
         insertThis->_parent->Unlink( insertThis );
-    else
+	}
+	else {
+		insertThis->_document->MarkInUse(insertThis);
         insertThis->_memPool->SetTracked();
+	}
 }
 
 const XMLElement* XMLNode::ToElementWithName( const char* name ) const
@@ -1979,9 +1992,24 @@ XMLDocument::~XMLDocument()
 }
 
 
+void XMLDocument::MarkInUse(XMLNode* node)
+{
+	TIXMLASSERT(node->_parent == 0);
+
+	for (int i = 0; i < _unlinked.Size(); ++i) {
+		if (node == _unlinked[i]) {
+			_unlinked.SwapRemove(i);
+			break;
+		}
+	}
+}
+
 void XMLDocument::Clear()
 {
     DeleteChildren();
+	while( _unlinked.Size()) {
+		DeleteNode(_unlinked[0]);	// Will remove from _unlinked as part of delete.
+	}
 
 #ifdef DEBUG
     const bool hadError = Error();

+ 19 - 0
tinyxml2.h

@@ -264,6 +264,13 @@ public:
         return _allocated;
     }
 
+	void SwapRemove(int i) {
+        TIXMLASSERT(i >= 0);
+		TIXMLASSERT(i < _size);
+		_mem[i] = _mem[_size - 1];
+		--_size;
+	}
+
     const T* Mem() const				{
         TIXMLASSERT( _mem );
         return _mem;
@@ -1802,6 +1809,9 @@ public:
     // internal
     char* Identify( char* p, XMLNode** node );
 
+	// internal
+	void MarkInUse(XMLNode*);
+
     virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const	{
         return 0;
     }
@@ -1822,6 +1832,13 @@ private:
     int             _errorLineNum;
     char*			_charBuffer;
     int				_parseCurLineNum;
+	// Memory tracking does add some overhead.
+	// However, the code assumes that you don't
+	// have a bunch of unlinked nodes around.
+	// Therefore it takes less memory to track
+	// in the document vs. a linked list in the XMLNode,
+	// and the performance is the same.
+	DynArray<XMLNode*, 10> _unlinked;
 
     MemPoolT< sizeof(XMLElement) >	 _elementPool;
     MemPoolT< sizeof(XMLAttribute) > _attributePool;
@@ -1844,6 +1861,8 @@ inline NodeType* XMLDocument::CreateUnlinkedNode( MemPoolT<PoolElementSize>& poo
     NodeType* returnNode = new (pool.Alloc()) NodeType( this );
     TIXMLASSERT( returnNode );
     returnNode->_memPool = &pool;
+
+	_unlinked.Push(returnNode);
     return returnNode;
 }
 

+ 29 - 0
xmltest.cpp

@@ -1641,6 +1641,35 @@ int main( int argc, const char ** argv )
 		}
 	}
 
+	{
+		// Evil memory leaks. 
+		// If an XMLElement (etc) is allocated via NewElement() (etc.)
+		// and NOT added to the XMLDocument, what happens?
+		//
+		// Previously (buggy):
+		//		The memory would be free'd when the XMLDocument is
+		//      destructed. But the destructor wasn't called, so that
+		//      memory allocated by the XMLElement would not be free'd.
+		//      In practice this meant strings allocated by the XMLElement
+		//      would leak. An edge case, but annoying.
+		// Now:
+		//      The destructor is called. But the list of unlinked nodes
+		//      has to be tracked. This has a minor performance impact
+		//   	that can become significant if you have a lot. (But why
+		//      would you do that?)
+		// The only way to see this bug is in a leak tracker. This
+		// is compiled in by default on Windows Debug.
+		{
+			XMLDocument doc;
+			doc.NewElement("LEAK 1");
+		}
+		{
+			XMLDocument doc;
+			XMLElement* ele = doc.NewElement("LEAK 2");
+			doc.DeleteNode(ele);
+		}
+	}
+
     // ----------- Line Number Tracking --------------
     {
         struct TestUtil: XMLVisitor