Fix string leaking (and destructors not getting called) when there are XMLNodes that aren't in the document tree

This commit is contained in:
Lee Thomason 2017-06-05 14:35:55 -07:00
parent 53858b4490
commit 816d3fa0cd
3 changed files with 63 additions and 3 deletions

View File

@ -802,6 +802,8 @@ void XMLNode::Unlink( XMLNode* child )
child->_next->_prev = child->_prev;
}
child->_parent = 0;
child->_next = 0;
child->_prev = 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();

View File

@ -264,6 +264,12 @@ public:
return _allocated;
}
void SwapRemove(int i) {
TIXMLASSERT(i < _size);
_mem[i] = _mem[_size - 1];
--_size;
}
const T* Mem() const {
TIXMLASSERT( _mem );
return _mem;
@ -1802,6 +1808,9 @@ public:
// internal
char* Identify( char* p, XMLNode** node );
// internal
void MarkInUse(XMLNode*);
virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const {
return 0;
}
@ -1822,6 +1831,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 +1860,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;
}

View File

@ -1641,6 +1641,20 @@ int main( int argc, const char ** argv )
}
}
{
// Oh those memory leaks.
// Only way to see these is in the (Windows) allocator tracking.
{
XMLDocument doc;
doc.NewElement("LEAK 1");
}
{
XMLDocument doc;
XMLElement* ele = doc.NewElement("LEAK 2");
doc.DeleteNode(ele);
}
}
// ----------- Line Number Tracking --------------
{
struct TestUtil: XMLVisitor