Merge branch 'properStrPairAssignment' of https://github.com/Dmitry-Me/tinyxml2 into Dmitry-Me-properStrPairAssignment

This commit is contained in:
Lee Thomason 2014-11-15 17:46:23 -08:00
commit 327d5c142e
4 changed files with 115 additions and 41 deletions

View File

@ -70,6 +70,29 @@ StrPair::~StrPair()
} }
void StrPair::TransferTo( StrPair& other )
{
if ( this == &other ) {
return;
}
// This in effect implements the assignment operator by "moving"
// ownership (as in auto_ptr).
TIXMLASSERT( other._flags == 0 );
TIXMLASSERT( other._start == 0 );
TIXMLASSERT( other._end == 0 );
other.Reset();
other._flags = _flags;
other._start = _start;
other._end = _end;
_flags = 0;
_start = 0;
_end = 0;
}
void StrPair::Reset() void StrPair::Reset()
{ {
if ( _flags & NEEDS_DELETE ) { if ( _flags & NEEDS_DELETE ) {
@ -212,12 +235,13 @@ const char* StrPair::GetStr()
else { else {
int i=0; int i=0;
for(; i<NUM_ENTITIES; ++i ) { for(; i<NUM_ENTITIES; ++i ) {
if ( strncmp( p+1, entities[i].pattern, entities[i].length ) == 0 const Entity& entity = entities[i];
&& *(p+entities[i].length+1) == ';' ) { if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
// Found an entity convert; && *( p + entity.length + 1 ) == ';' ) {
*q = entities[i].value; // Found an entity - convert.
*q = entity.value;
++q; ++q;
p += entities[i].length + 2; p += entity.length + 2;
break; break;
} }
} }
@ -823,7 +847,7 @@ char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
// We read the end tag. Return it to the parent. // We read the end tag. Return it to the parent.
if ( ele && ele->ClosingType() == XMLElement::CLOSING ) { if ( ele && ele->ClosingType() == XMLElement::CLOSING ) {
if ( parentEnd ) { if ( parentEnd ) {
*parentEnd = ele->_value; ele->_value.TransferTo( *parentEnd );
} }
node->_memPool->SetTracked(); // created and then immediately deleted. node->_memPool->SetTracked(); // created and then immediately deleted.
DeleteNode( node ); DeleteNode( node );
@ -1257,7 +1281,7 @@ const char* XMLElement::Attribute( const char* name, const char* value ) const
const char* XMLElement::GetText() const const char* XMLElement::GetText() const
{ {
if ( FirstChild() && FirstChild()->ToText() ) { if ( FirstChild() && FirstChild()->ToText() ) {
return FirstChild()->ToText()->Value(); return FirstChild()->Value();
} }
return 0; return 0;
} }
@ -1317,7 +1341,7 @@ void XMLElement::SetText( double v )
XMLError XMLElement::QueryIntText( int* ival ) const XMLError XMLElement::QueryIntText( int* ival ) const
{ {
if ( FirstChild() && FirstChild()->ToText() ) { if ( FirstChild() && FirstChild()->ToText() ) {
const char* t = FirstChild()->ToText()->Value(); const char* t = FirstChild()->Value();
if ( XMLUtil::ToInt( t, ival ) ) { if ( XMLUtil::ToInt( t, ival ) ) {
return XML_SUCCESS; return XML_SUCCESS;
} }
@ -1330,7 +1354,7 @@ XMLError XMLElement::QueryIntText( int* ival ) const
XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
{ {
if ( FirstChild() && FirstChild()->ToText() ) { if ( FirstChild() && FirstChild()->ToText() ) {
const char* t = FirstChild()->ToText()->Value(); const char* t = FirstChild()->Value();
if ( XMLUtil::ToUnsigned( t, uval ) ) { if ( XMLUtil::ToUnsigned( t, uval ) ) {
return XML_SUCCESS; return XML_SUCCESS;
} }
@ -1343,7 +1367,7 @@ XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
XMLError XMLElement::QueryBoolText( bool* bval ) const XMLError XMLElement::QueryBoolText( bool* bval ) const
{ {
if ( FirstChild() && FirstChild()->ToText() ) { if ( FirstChild() && FirstChild()->ToText() ) {
const char* t = FirstChild()->ToText()->Value(); const char* t = FirstChild()->Value();
if ( XMLUtil::ToBool( t, bval ) ) { if ( XMLUtil::ToBool( t, bval ) ) {
return XML_SUCCESS; return XML_SUCCESS;
} }
@ -1356,7 +1380,7 @@ XMLError XMLElement::QueryBoolText( bool* bval ) const
XMLError XMLElement::QueryDoubleText( double* dval ) const XMLError XMLElement::QueryDoubleText( double* dval ) const
{ {
if ( FirstChild() && FirstChild()->ToText() ) { if ( FirstChild() && FirstChild()->ToText() ) {
const char* t = FirstChild()->ToText()->Value(); const char* t = FirstChild()->Value();
if ( XMLUtil::ToDouble( t, dval ) ) { if ( XMLUtil::ToDouble( t, dval ) ) {
return XML_SUCCESS; return XML_SUCCESS;
} }
@ -1369,7 +1393,7 @@ XMLError XMLElement::QueryDoubleText( double* dval ) const
XMLError XMLElement::QueryFloatText( float* fval ) const XMLError XMLElement::QueryFloatText( float* fval ) const
{ {
if ( FirstChild() && FirstChild()->ToText() ) { if ( FirstChild() && FirstChild()->ToText() ) {
const char* t = FirstChild()->ToText()->Value(); const char* t = FirstChild()->Value();
if ( XMLUtil::ToFloat( t, fval ) ) { if ( XMLUtil::ToFloat( t, fval ) ) {
return XML_SUCCESS; return XML_SUCCESS;
} }
@ -1621,9 +1645,21 @@ XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
XMLDocument::~XMLDocument() XMLDocument::~XMLDocument()
{
Clear();
}
void XMLDocument::Clear()
{ {
DeleteChildren(); DeleteChildren();
_errorID = XML_NO_ERROR;
_errorStr1 = 0;
_errorStr2 = 0;
delete [] _charBuffer; delete [] _charBuffer;
_charBuffer = 0;
#if 0 #if 0
_textPool.Trace( "text" ); _textPool.Trace( "text" );
@ -1643,19 +1679,6 @@ XMLDocument::~XMLDocument()
} }
void XMLDocument::Clear()
{
DeleteChildren();
_errorID = XML_NO_ERROR;
_errorStr1 = 0;
_errorStr2 = 0;
delete [] _charBuffer;
_charBuffer = 0;
}
XMLElement* XMLDocument::NewElement( const char* name ) XMLElement* XMLDocument::NewElement( const char* name )
{ {
XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this ); XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
@ -1820,6 +1843,16 @@ XMLError XMLDocument::Parse( const char* p, size_t len )
ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc. ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc.
ParseDeep( _charBuffer+delta, 0 ); ParseDeep( _charBuffer+delta, 0 );
if (_errorID) {
// clean up now essentially dangling memory.
// and the parse fail can put objects in the
// pools that are dead and inaccessible.
DeleteChildren();
_elementPool.Clear();
_attributePool.Clear();
_textPool.Clear();
_commentPool.Clear();
}
return _errorID; return _errorID;
} }

View File

@ -14,7 +14,6 @@ not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation software in a product, an acknowledgment in the product documentation
would be appreciated but is not required. would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and 2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software. must not be misrepresented as being the original software.
@ -185,6 +184,8 @@ public:
char* ParseText( char* in, const char* endTag, int strFlags ); char* ParseText( char* in, const char* endTag, int strFlags );
char* ParseName( char* in ); char* ParseName( char* in );
void TransferTo( StrPair& other );
private: private:
void operator=(const StrPair& rhs); void operator=(const StrPair& rhs);
@ -200,6 +201,9 @@ private:
int _flags; int _flags;
char* _start; char* _start;
char* _end; char* _end;
StrPair( const StrPair& other ); // not supported
void operator=( StrPair& other ); // not supported, use TransferTo()
}; };
@ -319,6 +323,7 @@ public:
virtual void* Alloc() = 0; virtual void* Alloc() = 0;
virtual void Free( void* ) = 0; virtual void Free( void* ) = 0;
virtual void SetTracked() = 0; virtual void SetTracked() = 0;
virtual void Clear() = 0;
}; };
@ -331,10 +336,20 @@ class MemPoolT : public MemPool
public: public:
MemPoolT() : _root(0), _currentAllocs(0), _nAllocs(0), _maxAllocs(0), _nUntracked(0) {} MemPoolT() : _root(0), _currentAllocs(0), _nAllocs(0), _maxAllocs(0), _nUntracked(0) {}
~MemPoolT() { ~MemPoolT() {
// Delete the blocks. Clear();
for( int i=0; i<_blockPtrs.Size(); ++i ) {
delete _blockPtrs[i];
} }
void Clear() {
// Delete the blocks.
while( !_blockPtrs.Empty()) {
Block* b = _blockPtrs.Pop();
delete b;
}
_root = 0;
_currentAllocs = 0;
_nAllocs = 0;
_maxAllocs = 0;
_nUntracked = 0;
} }
virtual int ItemSize() const { virtual int ItemSize() const {
@ -367,6 +382,7 @@ public:
_nUntracked++; _nUntracked++;
return result; return result;
} }
virtual void Free( void* mem ) { virtual void Free( void* mem ) {
if ( !mem ) { if ( !mem ) {
return; return;
@ -516,10 +532,8 @@ enum XMLError {
class XMLUtil class XMLUtil
{ {
public: public:
// Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't
// correct, but simple, and usually works.
static const char* SkipWhiteSpace( const char* p ) { static const char* SkipWhiteSpace( const char* p ) {
while( !IsUTF8Continuation(*p) && isspace( *reinterpret_cast<const unsigned char*>(p) ) ) { while( IsWhiteSpace(*p) ) {
++p; ++p;
} }
return p; return p;
@ -527,6 +541,9 @@ public:
static char* SkipWhiteSpace( char* p ) { static char* SkipWhiteSpace( char* p ) {
return const_cast<char*>( SkipWhiteSpace( const_cast<const char*>(p) ) ); return const_cast<char*>( SkipWhiteSpace( const_cast<const char*>(p) ) );
} }
// Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't
// correct, but simple, and usually works.
static bool IsWhiteSpace( char p ) { static bool IsWhiteSpace( char p ) {
return !IsUTF8Continuation(p) && isspace( static_cast<unsigned char>(p) ); return !IsUTF8Continuation(p) && isspace( static_cast<unsigned char>(p) );
} }

View File

@ -96,6 +96,9 @@
/* Begin PBXProject section */ /* Begin PBXProject section */
037AE058151CCC5200E0F29F /* Project object */ = { 037AE058151CCC5200E0F29F /* Project object */ = {
isa = PBXProject; isa = PBXProject;
attributes = {
LastUpgradeCheck = 0610;
};
buildConfigurationList = 037AE05B151CCC5200E0F29F /* Build configuration list for PBXProject "tinyxml2" */; buildConfigurationList = 037AE05B151CCC5200E0F29F /* Build configuration list for PBXProject "tinyxml2" */;
compatibilityVersion = "Xcode 3.2"; compatibilityVersion = "Xcode 3.2";
developmentRegion = English; developmentRegion = English;
@ -134,6 +137,8 @@
buildSettings = { buildSettings = {
CONFIGURATION_BUILD_DIR = "$(SYMROOT)/Debug"; CONFIGURATION_BUILD_DIR = "$(SYMROOT)/Debug";
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
"GCC_PREPROCESSOR_DEFINITIONS[arch=*]" = DEBUG;
ONLY_ACTIVE_ARCH = YES;
SYMROOT = build; SYMROOT = build;
}; };
name = Debug; name = Debug;
@ -156,6 +161,7 @@
GCC_MODEL_TUNING = G5; GCC_MODEL_TUNING = G5;
GCC_OPTIMIZATION_LEVEL = 0; GCC_OPTIMIZATION_LEVEL = 0;
INSTALL_PATH = /usr/local/bin; INSTALL_PATH = /usr/local/bin;
MACOSX_DEPLOYMENT_TARGET = "";
PREBINDING = NO; PREBINDING = NO;
PRODUCT_NAME = xmltest; PRODUCT_NAME = xmltest;
}; };
@ -171,6 +177,7 @@
GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_MODEL_TUNING = G5; GCC_MODEL_TUNING = G5;
INSTALL_PATH = /usr/local/bin; INSTALL_PATH = /usr/local/bin;
MACOSX_DEPLOYMENT_TARGET = "";
PREBINDING = NO; PREBINDING = NO;
PRODUCT_NAME = tinyxml2; PRODUCT_NAME = tinyxml2;
ZERO_LINK = NO; ZERO_LINK = NO;

View File

@ -279,6 +279,8 @@ int main( int argc, const char ** argv )
{ {
#if defined( _MSC_VER ) && defined( DEBUG ) #if defined( _MSC_VER ) && defined( DEBUG )
_CrtMemCheckpoint( &startMemState ); _CrtMemCheckpoint( &startMemState );
// Enable MS Visual C++ debug heap memory leaks dump on exit
_CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
#endif #endif
#if defined(_MSC_VER) || defined(MINGW32) || defined(__MINGW32__) #if defined(_MSC_VER) || defined(MINGW32) || defined(__MINGW32__)
@ -1372,6 +1374,21 @@ int main( int argc, const char ** argv )
} }
#endif #endif
{
// Issue #184
// If it doesn't assert, it passes. Caused by objects
// getting created during parsing which are then
// inaccessible in the memory pools.
{
XMLDocument doc;
doc.Parse("<?xml version=\"1.0\" encoding=\"UTF-8\"?><test>");
}
{
XMLDocument doc;
doc.Parse("<?xml version=\"1.0\" encoding=\"UTF-8\"?><test>");
doc.Clear();
}
}
// ----------- Performance tracking -------------- // ----------- Performance tracking --------------