Jump to content
  • Advertisement
Sign in to follow this  
Noods

Handling exceptions...

This topic is 3809 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have never had to deal with exceptions before and I am having problems tracking down the problem in my program. When I execute a debug build of my program it functions perfectly. However, when I execute a release build of my program and then open an XML file (an otherwise normal operation) my program throws me this exception: Unhandled exception at 0x7c81eb33 in Sprite Viewer.exe: Microsoft C++ exception: std::bad_alloc at memory location 0x0012f9dc.. When the exception happens, Visual C++ debug mode points me back to DispatchMessage(&msg); in my main message loop as the next statement to execute. From what I have read this is usually due to memory allocation errors. When I open an XML file in my program, it parses the XML to find how many animations are in my sprite and then performs a vector.resize(); to create room for each animation. This is the only thing that I can think would be causing memory allocation errors. I have spent all day today trying to track this down to no avail. Does anyone have any suggestions as to how I can approach this problem? Here is my code that executes when I select an XML file via an open dialog box.
//global declared earlier in the program
std::vector<Animations> animation;     //Animations object for storing sprite information




BOOL InputXML(std::string *Filename, HWND hWnd)
{
	TiXmlDocument doc(Filename->c_str());   //Create a document object that points to the XML file we are to open
	bool loadOkay = doc.LoadFile();         //Load the file

	if(!loadOkay)   //If we didn't load the file
	{
		MessageBox( NULL, "Sprite Viewer could not load the specified XML file.", "Sprite Viewer has encountered a problem", MB_ICONERROR );
		return FALSE;
	}

	TiXmlElement* XMLElement;   //Create a element object for grabbing attribute information

	int iVal,
		iNoOfAnimations,
		iNoOfFrames,
		iAnimationCounter,
		iFrameCounter,
		iInputTest;

	TiXmlNode* RootNode = 0;         //Object for the root node
	TiXmlNode* ChildNode = 0;        //Object for animation nodes
	TiXmlNode* GrandChildNode = 0;   //Object for frame nodes

	RootNode = doc.RootElement();    //Grab the root node
	XMLElement = RootNode->ToElement();									 //Cast the RootNode object to an element so we can grab the attributes
	iInputTest = XMLElement->QueryIntAttribute("NoOfAnimations", &iNoOfAnimations);   //Grab the number of animations

	if(iInputTest==TIXML_NO_ATTRIBUTE)   //If we didn't load the number of animation
	{
		MessageBox( NULL, "Sprite Viewer could not load the number of animations. Please check your XML file.", "Sprite Viewer has encountered a problem", MB_ICONERROR );
		animation.clear();   //Remove the elements from our Animation vector
		return FALSE;
	}

	animation.resize(iNoOfAnimations);                       //Allocate an Animations object for each animation
	const char *cSpriteName=XMLElement->Attribute("Name");   //Grab the sprite name from the XML
	if(!cSpriteName)   //If we didn't load the sprite name
	{
		MessageBox( NULL, "Sprite Viewer could not load the sprite name. Please check your XML file.", "Sprite Viewer has encountered a problem", MB_ICONERROR );
		animation.clear();   //Remove the elements from our Animation vector
		return FALSE;
	}

	Filename->assign(cSpriteName);        //Set the sprite name in the pointer
	ChildNode = RootNode->FirstChild();   //Find the first child of the root node, which is the first animation node

	for(iAnimationCounter=1; iAnimationCounter<=iNoOfAnimations; iAnimationCounter++)   //For each animation node
	{
		XMLElement = ChildNode->ToElement();              //Cast the ChildNode to an element object so we can grab the attributes
		const char *cVal=XMLElement->Attribute("Name");   //Grab the animation name
		if(!cVal)   //If we didn't load the animation name
		{
			MessageBox( NULL, "Sprite Viewer could not load one of the animation names. Please check your XML file.", "Sprite Viewer has encountered a problem", MB_ICONERROR );
			animation.clear();   //Remove the elements from our Animation vector
			return FALSE;
		}

		strcpy_s(animation[iAnimationCounter-1].cAnimationName,20,cVal);   //Set animation name
		iInputTest = XMLElement->QueryIntAttribute("Frames", &iNoOfFrames);             //Grab the number of frames in the animation
		if(iInputTest==TIXML_NO_ATTRIBUTE)   //If we didn't load the number of frames
		{
			MessageBox( NULL, "Sprite Viewer could not load the number of frames of one of your animations. Please check your XML file.", "Sprite Viewer has encountered a problem", MB_ICONERROR );
			animation.clear();   //Remove the elements from our Animation vector
			return FALSE;
		}

		GrandChildNode = ChildNode->FirstChild();                          //Find the first child of the ChildNode, which is the first frame node
		animation[iAnimationCounter-1].CreateFrames(iNoOfFrames);          //Create a frame struct for each frame inside the related animation object

		for(iFrameCounter=1; iFrameCounter<=iNoOfFrames; iFrameCounter++)   //For each frame node
		{
			XMLElement = GrandChildNode->ToElement();   //Cast the GrandChildNode to an element object so we can grab the attributes
			iInputTest = XMLElement->QueryIntAttribute("Number", &iVal);                                //Grab the frame number
			if(iInputTest==TIXML_NO_ATTRIBUTE)   //If we didn't load the frame number
			{
				MessageBox( NULL, "Sprite Viewer could not load the number of one of your frames. Please check your XML file.", "Sprite Viewer has encountered a problem", MB_ICONERROR );
				animation.clear();   //Remove the elements from our Animation vector
				return FALSE;
			}
			animation[iAnimationCounter-1].AnimationFrame[iFrameCounter].iFrameNo=iVal;    //Set the frame number

			iInputTest = XMLElement->QueryIntAttribute("Width", &iVal);                                 //Grab the frame width
			if(iInputTest==TIXML_NO_ATTRIBUTE)   //If we didn't load the width
			{
				MessageBox( NULL, "Sprite Viewer could not load the width of one of your frames. Please check your XML file.", "Sprite Viewer has encountered a problem", MB_ICONERROR );
				animation.clear();   //Remove the elements from our Animation vector
				return FALSE;
			}
			animation[iAnimationCounter-1].AnimationFrame[iFrameCounter].iWidth=iVal;      //Set the weight

			iInputTest = XMLElement->QueryIntAttribute("Height", &iVal);                                //Grab the frame height
			if(iInputTest==TIXML_NO_ATTRIBUTE)   //If we didn't load the frame height
			{
				MessageBox( NULL, "Sprite Viewer could not load the height of one of your frames. Please check your XML file.", "Sprite Viewer has encountered a problem", MB_ICONERROR );
				animation.clear();   //Remove the elements from our Animation vector
				return FALSE;
			}
			animation[iAnimationCounter-1].AnimationFrame[iFrameCounter].iHeight=iVal;     //Set the height

			iInputTest = XMLElement->QueryIntAttribute("TopLeftX", &iVal);                              //Grab the TopLeftX coordinate
			if(iInputTest==TIXML_NO_ATTRIBUTE)   //If we didn't load the TopLeftX
			{
				MessageBox( NULL, "Sprite Viewer could not load the TopLeftX of one of your frames. Please check your XML file.", "Sprite Viewer has encountered a problem", MB_ICONERROR );
				animation.clear();   //Remove the elements from our Animation vector
				return FALSE;
			}
			animation[iAnimationCounter-1].AnimationFrame[iFrameCounter].iTopLeftX=iVal;   //Set the top left x coordinate

			iInputTest = XMLElement->QueryIntAttribute("TopLeftY", &iVal);                              //Grab the TopLeftY coordinate
			if(iInputTest==TIXML_NO_ATTRIBUTE)   //If we didn't load the frame number
			{
				MessageBox( NULL, "Sprite Viewer could not load the TopLeftY of one of your frames. Please check your XML file.", "Sprite Viewer has encountered a problem", MB_ICONERROR );
				animation.clear();   //Remove the elements from our Animation vector
				return FALSE;
			}
			animation[iAnimationCounter-1].AnimationFrame[iFrameCounter].iTopLeftY=iVal;   //Set the top left y coordinate

			GrandChildNode = GrandChildNode->NextSibling("Frame");                         //Move to the next frame
		}
		ChildNode = ChildNode->NextSibling("Animation");   //Move to the next animation
	}
	return TRUE;
}

Share this post


Link to post
Share on other sites
Advertisement
std::bad_alloc is thrown by operator new when an allocation fails. Pretty much the only reason an allocation can fail is if you run out of memory. You probably have a memory leak.

Examine whether you have any non-terminating loops and/or recursions with calls to operator new inside.

Share this post


Link to post
Share on other sites
Quote:
Original post by fpsgamer
std::bad_alloc is thrown by operator new when an allocation fails. Pretty much the only reason an allocation can fail is if you run out of memory. You probably have a memory leak.

I've seen bad_alloc many times, and I've never, ever seen it result from actual memory exhaustion. (Exhausting the entire virtual memory space is, well, an exhausting thing to sit through.) It's usually the result of passing in an uninitialized value for the allocation size, or (less often) from heap corruption. Drill down through the stack frames and see what the debugger says about the value being passed to the operation that causes the bad_alloc.

Share this post


Link to post
Share on other sites
Quote:
Original post by Sneftel
Quote:
Original post by fpsgamer
std::bad_alloc is thrown by operator new when an allocation fails. Pretty much the only reason an allocation can fail is if you run out of memory. You probably have a memory leak.

I've seen bad_alloc many times, and I've never, ever seen it result from actual memory exhaustion. (Exhausting the entire virtual memory space is, well, an exhausting thing to sit through.) It's usually the result of passing in an uninitialized value for the allocation size, or (less often) from heap corruption. Drill down through the stack frames and see what the debugger says about the value being passed to the operation that causes the bad_alloc.


Hmmm, in that case I guess I should qualify my statement with "In my experience...". I've seen some carelessly written loops of mine quickly eat up 4gb resulting in std::bad_alloc being thrown.

I am curious how exactly one can supply an uninitialized allocation size to new when the size in inferred from the type of object you're allocating?

Share this post


Link to post
Share on other sites
Quote:
Original post by fpsgamer
I am curious how exactly one can supply an uninitialized allocation size to new when the size in inferred from the type of object you're allocating?
I've accidentally written something like this before (which caused a bad_alloc):
uint aSize;
if( ... )
aSize = 42;
//N.B. - no else
Widget* pWidgets = new Widget[aSize];

Share this post


Link to post
Share on other sites
Quote:
Original post by fpsgamer
I am curious how exactly one can supply an uninitialized allocation size to new when the size in inferred from the type of object you're allocating?

Certainly not the non-array version of new. Things like resize(), though, call the array version.

EDIT: Beaten.

Share this post


Link to post
Share on other sites
Sometimes VS will initialize your variables to 0 for you automatically in debug mode. When this doesn't happen in release mode, it can expose problems.

On that first animation.resize(iNoOfAnimations); line, iNoOfAnimations is never given a default value, and is only passed into a function by reference which makes no guarantees about ever changing the value.

Set a break on that line, and see what value that .resize() call (and all of them, really) is actually using. In general just stepping through this function call with a debugger will give you a good idea of which line is the problem.

Always, always, *always* give every variable a default value.

[Edited by - godecho on June 12, 2008 8:58:48 AM]

Share this post


Link to post
Share on other sites
After another day of searching for the problem I only have a couple more clues as to the issue.

I don't ever actually use the new operator in my code but I am sure it is used somewhere in the std library. I do use .resize as Sneftel noted. I would say this is almost definitely a memory issue somewhere as std::bad_alloc is jumping around in my program. If I static the variable that is causing the error it jumps somewhere else.

I think that this is being caused by a problem with animation.resize(iNoOfAnimations); Do vectors provide some way to ensure that the memory is being allocated correctly when .resize is called?

Share this post


Link to post
Share on other sites
Underneath, std::vector::resize(), issues an allocation of memory via the allocator the vector was specified with (typically std::allocator), now if the allocation fails, for std::allocator, an std::bad_alloc exception is thrown. Now, to see what value you are sending to resize, if for some wanky reason you cannot use the debugger under release, is to just add something like, someLogFile << "Allocate " << iNoOfAnimations << std::flush, and see what is printed to the file. I bet that since iNoOfAnimations is uninitialized you have a really, really big number there... though it does seem kind of odd since, you do check the xml's query attribute to see if the parameter was in the xml file, so you'd think that iNoOfAnimations *should* be assigned to something if your code gets to resize(), are there other error codes from the QueryAttribute method possible? If you are able to develop under other platforms, under Linux there is a great tool called valgrind. Admittedly when anything run under it is really, really slow, among other things, it checks if any uninitialized data affects program flow control, this is a great tool to use. I highly recommend if you can use to to use it.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!