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

[SDL & C++] Exception after main

Started by Mybowlcut Mar 9, 2009 at 5:36 AM 10 replies 3.9k views
Original Post
Mybowlcut
Mybowlcut
Hey.
#include "SDL.h"

int main(int argc, char* args[])
{
	return 0;
}

That throws an exception after main. The exception comes from the (**onexitend)(); call in the code below (line is commented):
static void __cdecl doexit (
        int code,
        int quick,
        int retcaller
        )
{
#ifdef _DEBUG
        static int fExit = 0;
#endif  /* _DEBUG */

#ifdef CRTDLL
        if (!retcaller && check_managed_app())
        {
            /*
               Only if the EXE is managed then we call CorExitProcess.
               Native cleanup is done in .cctor of the EXE
               If the Exe is Native then native clean up should be done
               before calling (Cor)ExitProcess.
            */
            __crtCorExitProcess(code);
        }
#endif  /* CRTDLL */

        _lockexit();        /* assure only 1 thread in exit path */
        __TRY

        if (_C_Exit_Done != TRUE) {
            _C_Termination_Done = TRUE;

            /* save callable exit flag (for use by terminators) */
            _exitflag = (char) retcaller;  /* 0 = term, !0 = callable exit */

            if (!quick) {

                /*
                 * do _onexit/atexit() terminators
                 * (if there are any)
                 *
                 * These terminators MUST be executed in reverse order (LIFO)!
                 *
                 * NOTE:
                 *  This code assumes that __onexitbegin points
                 *  to the first valid onexit() entry and that
                 *  __onexitend points past the last valid entry.
                 *  If __onexitbegin == __onexitend, the table
                 *  is empty and there are no routines to call.
                 */

                _PVFV * onexitbegin = (_PVFV *)_decode_pointer(__onexitbegin);
                _PVFV * onexitend   = (_PVFV *)_decode_pointer(__onexitend);

                if (onexitbegin) {
                    while ( --onexitend >= onexitbegin )
                    /*
                     * if current table entry is non-NULL,
                     * call thru it.
                     */
                    if ( *onexitend != NULL )
                        (**onexitend)();  // EXCEPTION THROWN HERE
                }
#ifndef CRTDLL
                /*
                 * do pre-terminators
                 */
                _initterm(__xp_a, __xp_z);
#endif  /* CRTDLL */
            }

#ifndef CRTDLL
            /*
             * do terminators
             */
            _initterm(__xt_a, __xt_z);
#endif  /* CRTDLL */

#ifdef _DEBUG
            /* Dump all memory leaks */
            if (!fExit && _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) & _CRTDBG_LEAK_CHECK_DF)
            {
                fExit = 1;
#ifndef CRTDLL
                __freeCrtMemory();
                _CrtDumpMemoryLeaks();
#endif  /* CRTDLL */
            }
#endif  /* _DEBUG */

        }
        /* return to OS or to caller */

        __FINALLY
            if (retcaller)
                _unlockexit();      /* unlock the exit code path */
        __END_TRY_FINALLY
        if (retcaller)
            return;


        _C_Exit_Done = TRUE;

        _unlockexit();      /* unlock the exit code path */

        __crtExitProcess(code);
}
Any ideas why this would be happening? Cheers.

Scourage
Scourage
Hey,

You need to include a lot more information for me/anybody else to help. Which compiler are you using? How are your libraries/application compiled (which runtime?) What compiler defines are you defining? Is this your code, or down in SDL?

Most likely what is happening is you are trying to call a function pointer on a null or uninitialized pointer, which is jumping you out into to memory somewhere causing the exception.

Cheers,

Bob

[size="3"]Halfway down the trail to Hell...
Kylotan
Kylotan
My guess is that if you include the sdl.h header, you need to go through the SDL_Init and SDL_Quit routines in your main().
Mybowlcut
Mybowlcut
Oh, yes haha sorry. The project properties (command line options) are all in the first post in this thread.

I debugged it, and the results of the debugging can be seen in the first post here.

There a couple of threads because this issue has been spread out over time. :s

My code is literally the first sample I posted, so whatever you see there is what I am doing. I'm using Visual Studio with the default compiler (whatever that is :)).

I tried initialising SDL and then calling SDL_Quit, but it still throws the same exception in the same place:
#include "SDL.h"int main(int argc, char* args[]){    if(SDL_Init(SDL_INIT_EVERYTHING) == -1)	{		return 1;	}    SDL_Quit();	return 0;}


Cheers.

Kylotan
Kylotan
Are you sure that the sdl.h that you're including is from the same version as the sdl.dll your app refers to?
Mybowlcut
Mybowlcut
Quote:
Original post by Kylotan
Are you sure that the sdl.h that you're including is from the same version as the sdl.dll your app refers to?
I wasn't sure, so I got the new version and set it up, did a full rebuild and it still does the same thing. I also got the newer versions of SDL_ttf, SDL_image and SDL_mixer just to be sure, but it still happens.

Will the disassembly or memory window or registers window help? It's in the CodeGuru link I posted, but I can get the values of them again if you think it will help?

Cheers.

Kylotan
Kylotan
Quote:
Original post by Mybowlcut
Quote:
Original post by Kylotan
Are you sure that the sdl.h that you're including is from the same version as the sdl.dll your app refers to?
I wasn't sure, so I got the new version and set it up, did a full rebuild and it still does the same thing.

You might want to check your pc for all instances of sdl.dll. A rebuild won't make any difference here if it's finding an old version of the dll in your Windows/System directory, for example. Something like Process Monitor can be used to track down exactly which dll is getting used. Admittedly this is clutching at straws somewhat.
Mybowlcut
Mybowlcut
Wow that program is crazy... very cool. Unfortunately, I have no idea how to find where I am since it is storing events every millisecond+.

Edit: I think I found it:
Quote:
8:59:17.9251531 PM svchost.exe 1980 QueryOpen C:\Documents and Settings\Bill\My Documents\Visual Studio 2005\Projects\CHECKERS\Checkers_SDL\debug\SDL.dll SUCCESS CreationTime: 4/03/2009 2:54:57 PM, LastAccessTime: 11/03/2009 8:59:08 PM, LastWriteTime: 30/12/2007 11:07:40 PM, ChangeTime: 11/03/2009 1:34:04 PM, AllocationSize: 323,584, EndOfFile: 321,536, FileAttributes: A
8:59:17.9257093 PM svchost.exe 1980 CreateFile C:\Documents and Settings\Bill\My Documents\Visual Studio 2005\Projects\CHECKERS\Checkers_SDL\debug\SDL.dll SUCCESS Desired Access: Read EA, Read Attributes, Read Control, Disposition: Open, Options: , Attributes: n/a, ShareMode: Read, Write, Delete, AllocationSize: n/a, Impersonating: NT AUTHORITY\SYSTEM, OpenResult: Opened
8:59:17.9261925 PM svchost.exe 1980 QueryFileInternalInformationFile C:\Documents and Settings\Bill\My Documents\Visual Studio 2005\Projects\CHECKERS\Checkers_SDL\debug\SDL.dll SUCCESS IndexNumber: 0x5000000013287
8:59:17.9266390 PM svchost.exe 1980 CloseFile C:\Documents and Settings\Bill\My Documents\Visual Studio 2005\Projects\CHECKERS\Checkers_SDL\debug\SDL.dll SUCCESS
But they are the dlls I copied from the newly unzipped SDL. Is there an easier way to do this? I'm trying to use the filter but it just filters EVERYTHING. :s

Kylotan
Kylotan
If you right click on an event for a given process (eg. yours), you can have it 'include' that process, which effectively excludes all others, making it easy to see what's what.

It does look like it's using the right DLL in your case, though. Perhaps the SDL mailing list will be able to help you?
Mybowlcut
Mybowlcut
Oh, ok. That's pretty nifty haha.

Yeah, guess I'll try there.

Cheers!

Mybowlcut
Mybowlcut
Ok I have found the source of the issue... but I don't understand why it is happening. I basically went through and excluded files one by one until it stopped crashing. It turns out it was this structure in SDL_Tools.h & SDL_Tools.cpp (I have removed all other crap from these two files for clarity):

#ifndef SDL_TOOLS_H#define SDL_TOOLS_H#include "include_ticpp.h"#include "SDL.h"namespace SDL_Tools{	// A readable/writeable SDL_Rect.	struct RW_SDL_Rect : public SDL_Rect//, public ticpp::Element_RW	{		RW_SDL_Rect();		RW_SDL_Rect(Sint16 x, Sint16 y, Uint16 w, Uint16 h);		virtual void Read(ticpp::Element* element);		virtual void Write(ticpp::Element* element) const;	};}#endif

#include "SDL_Tools.h"SDL_Tools::RW_SDL_Rect::RW_SDL_Rect(){}SDL_Tools::RW_SDL_Rect::RW_SDL_Rect(Sint16 x, Sint16 y, Uint16 w, Uint16 h){	this->x = x;	this->y = y;	this->w = w;	this->h = h;}void SDL_Tools::RW_SDL_Rect::Read(ticpp::Element* element){	//ticpp::throw_on_bad_element(element, __FILE__);	x = element->GetAttribute<Sint16>("x");	y = element->GetAttribute<Sint16>("y");	w = element->GetAttribute<Uint16>("w");	h = element->GetAttribute<Uint16>("h");}void SDL_Tools::RW_SDL_Rect::Write(ticpp::Element* element) const{	//ticpp::throw_on_bad_element(element, __FILE__);	element->SetAttribute("x", x);	element->SetAttribute("y", y);	element->SetAttribute("w", w);	element->SetAttribute("h", h);}

Those two files are excluded from the build (via right clicking and excluding from build) but still exist in the project and the phsyical folder.

Main still looks like this:
#include "sdl.h"int main(int argc, char* argv[]){	return 0;}


I have Random.h and Random.cpp included because SDL_Tools.h/.cpp needed them:
#ifndef RANDOM_H#define RANDOM_H#include <stdlib.h>#include <time.h>namespace Random{	typedef unsigned int uint;	void seed(uint seed);	void time_seed();	uint get_random();	uint get_random_between(uint min, uint max); }#endif

#include "Random.h"void Random::seed(unsigned int seed){	srand(seed);}void Random::time_seed(){	srand(static_cast<unsigned int>(time(NULL)));}Random::uint Random::get_random(){	return rand();}Random::uint Random::get_random_between(uint min, uint max){	return min + (rand() % max);}

And Point.h and Point.cpp:
#ifndef POINT_H#define POINT_H#include <iostream>// A class for representing x, y values.class Point{public:	Point();	Point(int x, int y);	~Point();    friend std::istream& operator>>(std::istream& stream, Point& point);    friend std::ostream& operator<<(std::ostream& stream, const Point& point);	Point& operator=(const Point& rhs);	friend const Point operator+(const Point& lhs, const Point& rhs);	friend const Point operator-(const Point& lhs, const Point& rhs);	Point& operator+=(const Point& rhs);	Point& operator-=(const Point& rhs);	friend const Point operator*(const Point& lhs, int multiplier);	friend const Point operator/(const Point& lhs, int divider);	Point& operator*=(int multiplier);	Point& operator/=(int divider);	friend bool operator==(const Point& lhs, const Point& rhs);	friend bool operator!=(const Point& lhs, const Point& rhs);	friend bool operator>(const Point& lhs, const Point& rhs);	friend bool operator<(const Point& lhs, const Point& rhs);	friend bool operator>=(const Point& lhs, const Point& rhs);	friend bool operator<=(const Point& lhs, const Point& rhs);	int x, y;};#endif

#include "Point.h"Point::Point(): x(0), y(0){}Point::Point(int x, int y): x(x), y(y){}Point::~Point(){}std::istream& operator>>(std::istream& stream, Point& point){    stream >> point.x >> point.y;    return stream;}std::ostream& operator<<(std::ostream& stream, const Point& point){    stream << point.x << ' ' << point.y;    return stream;}Point& Point::operator=(const Point& rhs){	this->x = rhs.x;	this->y = rhs.y;	return *this;}const Point operator+(const Point& lhs, const Point& rhs){	return Point(lhs.x + rhs.x, lhs.y + rhs.y);}const Point operator-(const Point& lhs, const Point& rhs){	return Point(lhs.x - rhs.x, lhs.y - rhs.y);}Point& Point::operator+=(const Point& rhs){	*this = *this + rhs;	return *this;}Point& Point::operator-=(const Point& rhs){	*this = *this - rhs;	return *this;}const Point operator*(const Point& lhs, int multiplier){	return Point(lhs.x * multiplier, lhs.y * multiplier);}const Point operator/(const Point& lhs, int divider){	return Point(lhs.x / divider, lhs.y / divider);}Point& Point::operator*=(int multiplier){	*this = *this * multiplier;	return *this;}Point& Point::operator/=(int divider){	*this = *this / divider;	return *this;}bool operator==(const Point& lhs, const Point& rhs){	return &lhs == &rhs || (lhs.x == rhs.x && lhs.y == rhs.y);}bool operator!=(const Point& lhs, const Point& rhs){	return !(lhs == rhs);}bool operator>(const Point& lhs, const Point& rhs){	return lhs.x > rhs.x || lhs.y > rhs.y;}bool operator<(const Point& lhs, const Point& rhs){	return lhs.x < rhs.x || lhs.y < rhs.y;}bool operator>=(const Point& lhs, const Point& rhs){	return lhs > rhs || lhs == rhs;}bool operator<=(const Point& lhs, const Point& rhs){	return lhs < rhs || lhs == rhs;}


Now, the project compiles and runs (without crashing) with the SDL_RW_Rect structure even though the file that it is in (SDL_Tools.h) includes a file that is excluded from the build (include_ticpp.h) and has no .obj file, etc. The program works fine like this (except all my files are excluded so there is no game to play).

When I uncomment the calls to throw_on_bad_element, I get a linker error.

I have no idea what is going on...

Mybowlcut
Mybowlcut
Just because this is the most annoying problem I've come across, I'm going to dig up this thread to let anyone who ever has the same problem know that it is solved... turns out it was some linker input settings... now I can distribute it! Keep an eye out for my game in Your Announcements if you enjoy checkers haha. ;)

Topic Locked

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

Sign in to reply to this topic.