mirror of https://github.com/AxioDL/tinyxml2.git
Merge branch 'memleak2'
This commit is contained in:
commit
e84f68a68a
34
tinyxml2.cpp
34
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
tinyxml2.h
19
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
xmltest.cpp
29
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
|
||||
|
|
Loading…
Reference in New Issue