Skip to main content
GameDev.net gamedev.net
🔒 Locked

Tinyxml++ exception in release build

Started by Mybowlcut Feb 11, 2009 at 10:47 PM 15 replies 4.9k views
Original Post
Mybowlcut
Mybowlcut
Usual story... release build stuffing up. Any file I try to load with tinyxml++ whilst debugging just won't load. The file is there and I've tried both relative and absolute paths for the file name to no avail. The exception points towards the end of the function at the delete [] buf line.
int main(int argc, char* args[])
{
	using namespace ticpp;

	Document xml_doc("settings.xml");
	xml_doc.LoadFile();
    
	return 0;
}
bool TiXmlDocument::LoadFile( FILE* file, TiXmlEncoding encoding )
{
        if ( !file )
        {
                SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN );
                return false;
        }

        // Delete the existing data:
        Clear();
        location.Clear();

        // Get the file size, so we can pre-allocate the string. HUGE speed impact.
        long length = 0;
        fseek( file, 0, SEEK_END );
        length = ftell( file );
        fseek( file, 0, SEEK_SET );

        // Strange case, but good to handle up front.
        if ( length <= 0 )
        {
                SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
                return false;
        }

        // If we have a file, assume it is all one big XML file, and read it in.
        // The document parser may decide the document ends sooner than the entire file, however.
        TIXML_STRING data;
        data.reserve( length );

        // Subtle bug here. TinyXml did use fgets. But from the XML spec:
        // 2.11 End-of-Line Handling
        // <snip>
        // <quote>
        // ...the XML processor MUST behave as if it normalized all line breaks in external
        // parsed entities (including the document entity) on input, before parsing, by translating
        // both the two-character sequence #xD #xA and any #xD that is not followed by #xA to
        // a single #xA character.
        // </quote>
        //
        // It is not clear fgets does that, and certainly isn't clear it works cross platform.
        // Generally, you expect fgets to translate from the convention of the OS to the c/unix
        // convention, and not work generally.

        /*
        while( fgets( buf, sizeof(buf), file ) )
        {
                data += buf;
        }
        */


        char* buf = new char[ length+1 ];
        buf[0] = 0;

        if ( fread( buf, length, 1, file ) != 1 ) {
                delete [] buf;
                SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN );
                return false;
        }

        const char* lastPos = buf;
        const char* p = buf;

        buf[length] = 0;
        while( *p ) {
                assert( p < (buf+length) );
                if ( *p == 0xa ) {
                        // Newline character. No special rules for this. Append all the characters
                        // since the last string, and include the newline.
                        data.append( lastPos, (p-lastPos+1) );  // append, include the newline
                        ++p;                                                                    // move past the newline
                        lastPos = p;                                                    // and point to the new buffer (may be 0)
                        assert( p <= (buf+length) );
                }
                else if ( *p == 0xd ) {
                        // Carriage return. Append what we have so far, then
                        // handle moving forward in the buffer.
                        if ( (p-lastPos) > 0 ) {
                                data.append( lastPos, p-lastPos );      // do not add the CR
                        }
                        data += (char)0xa;                                              // a proper newline

                        if ( *(p+1) == 0xa ) {
                                // Carriage return - new line sequence
                                p += 2;
                                lastPos = p;
                                assert( p <= (buf+length) );
                        }
                        else {
                                // it was followed by something else...that is presumably characters again.
                                ++p;
                                lastPos = p;
                                assert( p <= (buf+length) );
                        }
                }
                else {
                        ++p;
                }
        }
        // Handle any left over characters.
        if ( p-lastPos ) {
                data.append( lastPos, p-lastPos );
        }
        delete [] buf;
        buf = 0;

        Parse( data.c_str(), 0, encoding );

        if (  Error() )
        return false;
    else
                return true;
}

The tinyxml++ release build C++ command line options:
Quote:
/Od /D "TIXML_USE_TICPP" /D "UNICODE" /D "_UNICODE" /D "_CRT_SECURE_NO_DEPRECATE" /D "WIN32" /D "_CONSOLE" /D "NDEBUG" /GF /FD /EHsc /MD /Gy /Fo"obj/Release\\" /Fd"obj/Release\vc80.pdb" /W4 /nologo /c /Zi /TP /errorReport:prompt
The tinyxml++ release build linker command line options:
Quote:
/OUT:"lib/ticpp.lib" /NOLOGO
My project's release build C++ command line options:
Quote:
/Od /GL /I "E:\Dev\SDL\include" /I "E:\Dev\tinyxml++" /I "E:\Dev\Boost_old" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "USE_LOG" /D "_UNICODE" /D "UNICODE" /FD /EHsc /MD /Fo"Release\\" /Fd"Release\vc80.pdb" /W3 /nologo /c /Zi /TP /wd4996 /errorReport:prompt
My project's release build linker command line options:
Quote:
/OUT:"C:\Documents and Settings\Bill\My Documents\Visual Studio 2005\Projects\CHECKERS\Checkers_SDL\Release\Checkers_SDL.exe" /NOLOGO /LIBPATH:"E:\Dev\tinyxml++\lib" /LIBPATH:"E:\Dev\SDL\lib" /MANIFEST /MANIFESTFILE:"Release\Checkers_SDL.exe.intermediate.manifest" /NODEFAULTLIB:"(/NODEFAULTLIB:[uuid.lib" /NODEFAULTLIB:"msvcrt.lib])" /DEBUG /PDB:"c:\Documents and Settings\Bill\My Documents\Visual Studio 2005\Projects\CHECKERS\Checkers_SDL\release\Checkers_SDL.pdb" /SUBSYSTEM:CONSOLE /OPT:REF /OPT:ICF /LTCG /MACHINE:X86 /ERRORREPORT:PROMPT SDL.lib SDLmain.lib SDL_image.lib SDL_ttf.lib SDL_mixer.lib msvcrtd.lib ticpp.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib
If I run without debugging, the program is fine (ie loads all xml files properly) until I try and exit, at which point I get an exception (I do have several singletons which might be causing this). Any help with why this might be happening is greatly appreciated. Cheers.

Codarki
Codarki
Quote:
Original post by Mybowlcut
The file is there and I've tried both relative and absolute paths for the file name to no avail.

If the file loading works, that should make no difference.

Quote:
Original post by Mybowlcut
The exception points towards the end of the function at the delete [] buf line.

What kind of exception?

Is your FILE* parameter at beginning of file at LoadFile()?
Why not use std::string for text management?
Mybowlcut
Mybowlcut
LoadFile is part of a third party library - it isn't my code.

Codarki
Codarki
Oh sorry :)

Personally I manage my own file loading. You could try if that makes a difference.

void create_xml_from_text(xml& node, std::string const& text){    TiXmlDocument doc;    char const* result = doc.Parse(text.c_str());    if(!result)        throw any_error("XML parsing error");    // ...}

Mybowlcut
Mybowlcut
No probs.

I'm guessing the problem lies with the way I've built the tinyxml++ project but I'm not sure...

Mybowlcut
Mybowlcut
Can anyone suggest anything? I'd really like to be able to get this game distributed for people to play but this is a major hurdle...

Edit: Here is the output for the breakpoint that gets triggered:
HEAP[Checkers_SDL.exe]: Invalid Address specified to RtlFreeHeap( 00B00000, 00AF51D8 )Windows has triggered a breakpoint in Checkers_SDL.exe.This may be due to a corruption of the heap, and indicates a bug in Checkers_SDL.exe or any of the DLLs it has loaded.


[Edited by - Mybowlcut on February 16, 2009 10:10:43 PM]

Mybowlcut
Mybowlcut
I made a test project to see if it was maybe my project properties and it worked:
#ifndef TIXML_USE_TICPP#define TIXML_USE_TICPP#endif#ifndef TIXML_USE_STL#define TIXML_USE_STL#endif#include "ticpp.h"#include <string>int main(int argc, char* args[]){    try    {        using namespace ticpp;	    Document xml_doc;	    xml_doc.LoadFile("settings.xml");    }    catch(const std::exception& e)    {        std::cout << e.what() << std::endl;    }    	return 0;}
C++ command line options:
Quote:
/O2 /GL /I "E:\Dev\TinyXML++" /I "E:\Dev\Boost_old" /I "E:\Dev\SDL\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /FD /EHsc /MD /Fo"Release\\" /Fd"Release\vc80.pdb" /W3 /nologo /c /Wp64 /Zi /TP /errorReport:prompt
Linker command line options:
Quote:
/OUT:"C:\Documents and Settings\Bill\My Documents\Visual Studio 2005\Projects\Test\Release\Test.exe" /INCREMENTAL:NO /NOLOGO /LIBPATH:"E:\Dev\tinyxml++\lib" /MANIFEST /MANIFESTFILE:"Release\Test.exe.intermediate.manifest" /DEBUG /PDB:"c:\Documents and Settings\Bill\My Documents\Visual Studio 2005\Projects\Test\release\Test.pdb" /SUBSYSTEM:CONSOLE /OPT:REF /OPT:ICF /LTCG /MACHINE:X86 /ERRORREPORT:PROMPT ticpp.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib

But I can't get the other one to work still... I debugged it and looked at the contents of buf in LoadFile and it looks all good:
Quote:
buf 0x00af5260 "
logger_fn="log.txt"
board_dir="Board\\"
board_fn="board.xml"
audio_dir="Audio\\"
hs_dir="High Scores\\"
img_dir="Images\\"
screen_dir="Screens\\"
def_img_ext=".png"
screen_w="640"
screen_h="480"
screen_bpp="24"
screen_caption="Checkers"
def_font="C:/WINDOWS/Fonts/Arial.ttf"
def_font_size="20"
def_colour_key_r="255"
def_colour_key_g="255"
def_colour_key_b="255"
tile_width="50"
tile_height="50"
hs_write_x="60"
hs_write_y="219"
hs_row_spacing="23"
hs_detail_spacing="7"
max_scores="10"
hs_write_depth="1"
/>"
Annnnyone? :(

Mybowlcut
Mybowlcut
Bump for the release of a checkers game!

adam4813
adam4813
Whoops just reread what you posted. Where are you using buf? Try rewriting the code to not use it at all and see what happens.
Mybowlcut
Mybowlcut
Quote:
Original post by adam4813
Whoops just reread what you posted. Where are you using buf? Try rewriting the code to not use it at all and see what happens.
Hey. Cheers for the reply, but
Quote:
Original post by Mybowlcut
LoadFile is part of a third party library - it isn't my code.

adam4813
adam4813
Good point. I never had an issue with TinyXML with my docs loading at all. You should only call 1 or the other not both. e.g. "Document xml_doc("settings.xml");" or "xml_doc.LoadFile("settings.xml");" if I remember correctly. The constructor should automatically call LoadFile().
Mybowlcut
Mybowlcut
I don't think the constructor automatically calls it. You still have to call LoadFile, just with no arguments.

adam4813
adam4813
Try leaving the constructor empty and calling LoadFile("filename"). That is what works in my program.
owl
owl
In version 2.5.3 you pass the path to the constructor, then you call LoadFile. It should work. If you're getting strange stuff, maybe something else is wrong.

Building the library is just as easy as placing all the source files within a project an compiling it.
[size="2"]I like the Walrus best.
Mybowlcut
Mybowlcut
Yeah haha. I have no problem with building the library.

I tried swapping around so that I pass the string to the constructor and then call LoadFile with no args, and it worked! That's so strange... that shouldn't happen, as the docs say that either is fine and in every single place in my code I do it the other way with no problems. I'm all for just leaving it as it is and being grateful that I can move on to the next error (see below if you're interested :)), but this is a very peculiar problem that I don't want to come up against again...

When I close the application whilst debugging, I get the "There is no source available for the current location." message box, but if I step out I get taken to mlock.c:
/**** _unlock - Release multi-thread lock**Purpose:*       Note that it is legal for a thread to aquire _EXIT_LOCK1*       multiple times.**Entry:*       locknum = number of the lock to release**Exit:**Exceptions:********************************************************************************/void __cdecl _unlock (        int locknum        ){        /*         * leave the critical section.         */        LeaveCriticalSection( _locktable[locknum].lock );}
The exception points to the closing curly bracket. This is the output for the exception:
First-chance exception at 0x7c91b1fa in Checkers_SDL.exe: 0xC0000005: Access violation writing location 0x00000010.Unhandled exception at 0x7c91b1fa in Checkers_SDL.exe: 0xC0000005: Access violation writing location 0x00000010.The program '[1100] Checkers_SDL.exe: Native' has exited with code 0 (0x0)

This is also happening when I don't debug (aka start without debugging), unlike the previous LoadFile issue. I should mention that I use several Singletons:
int main(int argc, char* args[]){	try	{		Settings::Initialise("settings.xml");		Logger::Initialise(Settings::Get().Logger_Fn());                ticpp::XML_Data_Registry::Initialise();		// Initialise the Audio		SDL_Audio_Player::Initialise();		if(SDL_Init(SDL_INIT_EVERYTHING) == -1)		{			throw LRE_Exception(SDL_GetError());		}				Surface_Cache::Initialise();        Screen_Event_Manager::Initialise();			Checkers_Game checkers;		checkers.Run();	}	catch(const std::exception& r)	{		std::cout << "Exception caught: " << r.what() << std::endl;	}	// Clean up.	SDL_Audio_Player::Get().Clean_Up();    SDL_Quit();	Logger::Get().Save_Log();    	return 0;}
as this seems to be happening after main so I'd be dumb not to presume it would a singleton issue!

Cheers for your help!

Mybowlcut
Mybowlcut
Ok, I figured out that it's SDL.h that is causing the problems. This throws an exception:
#include "SDL.h"int main(int argc, char* args[]){	return 0;}


I've also posted here about the same problem. That thread contains information on the exception that is thrown and from where it is thrown.

Would really appreciate any help on this. Perhaps I should move it to alternative game libraries?

Cheers.

jjbongo
jjbongo
This is an old thread, so I guess I'm too late to help you with your checkers game - but I was experiencing the exact same problems and I couldn't figure out why!

I too think it was somehow related to my build settings- I've no idea exactly what it was, but my program couldn't use my tinyXml static library to load an xml document.

In the end I worked around the problem by including the tinyXml source files in my project (there are only 6, and you include most of the headers anyway if you don't use the STL build!)

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.