Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Debug Assertion Failure

This thread is locked; no one can reply to it. rss feed Print
 1   2 
Debug Assertion Failure
Gatleos
Member #12,534
January 2011

I'm not even sure this is worth asking, since it's such a vague yet complex problem. But here goes. My program recently started behaving... oddly. It compiles perfectly, but about 75% of the time running it immediately produces an error. It's not a run-time error, like I said it runs fine sometimes. And when my game loop is exited and the program prepares to close, I get a debug assertion failure every time.

The program is an Allegro ASCII library I'm programming, and the only guess I have is that Allegro is going crazy from all the images I'm blitting to the screen. But even that seems unlikely, the program hardly uses any CPU and even when I remove most of the draw commands from the loop I get the error just as often.

HEEEEEEELLLLLLP

Thanks in advance. :)

J-Gamer
Member #12,491
January 2011
avatar

We probably could be more of a help when you would give more details...
Did your compiler throw any warnings when building? Or do you have them turned off?
You should try and make your program into something smaller that still crashes for the same reason... You might find the problem yourself this way, otherwise you should post some code.

" There are plenty of wonderful ideas in The Bible, but God isn't one of them." - Derezo
"If your body was a business, thought would be like micro-management and emotions would be like macro-management. If you primarily live your life with emotions, then you are prone to error on the details. If you over-think things all the time you tend to lose scope of priorities." - Mark Oates

Gatleos
Member #12,534
January 2011

No warnings to speak of. My main .cpp probably wouldn't be of much help if I posted it, since most of it is just referencing functions in the library I'm building. That's almost certainly where the problem is coming from, but it's a mountain of code. Want to see it...?

Edgar Reynaldo
Member #8,592
May 2007
avatar

Gatleos said:

And when my game loop is exited and the program prepares to close, I get a debug assertion failure every time.

So run your program through a debugger and get a backtrace of the function stack when the assertion fails.

To do this, use allegro to set the assert handler.

int AssertHandler(const char* msg) {
   int zero = 0;
   int dividebyzero = 1/zero;
   return 0;
}

// in main
register_assert_handler(AssertHandler);

That way, when something fails an Allegro ASSERT, you will divide by zero. Your debugger will catch this exception, and then you can debug it properly.

Gatleos said:

No warnings to speak of.

So you compiled with -Wall, right?

Gatleos
Member #12,534
January 2011

I've run step-by-step through the program multiple times, it never encounters any kind of errors. It would help if I knew what the hell an assertion failure was.

On that note, I think you're overestimating my programming knowledge.

EDIT: I need to start specifying that I'm using Allegro 5. How would I use that nifty reality-breaking assert handler in 5.0?

gnolam
Member #2,030
March 2002
avatar

Gatleos said:

It would help if I knew what the hell an assertion failure was.

It's an assertion that fails. ;)

What assert() does is basically "if the supplied argument is not true, kill the program". It's a way of error checking.

--
Move to the Democratic People's Republic of Vivendi Universal (formerly known as Sweden) - officially democracy- and privacy-free since 2008-06-18!

Edgar Reynaldo
Member #8,592
May 2007
avatar

Gatleos said:

I need to start specifying that I'm using Allegro 5. How would I use that nifty reality-breaking assert handler in 5.0?

Sorry, I don't believe that functionality is available in Allegro 5, but it should be.

Gatleos said:

It would help if I knew what the hell an assertion failure was.

An assertion failure is when a program fails an assert call.

#include <assert.h>// C
#include <cassert>// C++

assert(1);// fine, 1 evaluates to true, assertion passed
assert(0);// %!#$%, 0 evaluates to false, assertion failed, abort called

Gatleos said:

I've run step-by-step through the program multiple times, it never encounters any kind of errors.

Are you on Windows? I think an error message pops up when assert is failed on Windows. Do you have any idea where the assertion failure is coming from?

Gatleos
Member #12,534
January 2011

Yup, windows. It comes up when I exit the game loop. The only code after that de-allocates my display, bitmaps, etc. But that code hasn't changed since long before these errors started popping up.

{"name":"R1ShD.png","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/a\/e\/ae4f3d19732d0e73f7f0e56c0dc54ee6.png","w":451,"h":333,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/a\/e\/ae4f3d19732d0e73f7f0e56c0dc54ee6"}R1ShD.png

X-G
Member #856
December 2000
avatar

Oh, that particular assertion is a CRT exception. It means that some memory function was attempted on a pointer that isn't a valid heap pointer pointing into your local heap. This usually means one of three things:

1) You attempted to use free(), realloc(), or delete on a pointer that isn't valid, for instance if you try to free() the same pointer twice. The pointer is invalid because it has already been freed.

2) You're freeing a pointer that was originally allocated in a DLL (as opposed to your main program), or vice versa. The pointer is invalid because DLLs you load have their own heap separate from your application's local heap.

3) You're mixing debug and release CRTs and allocating/freeing memory from different CRTs. The pointer is invalid because the debug and release CRTs have different internal allocation semantics.

--
Since 2008-Jun-18, democracy in Sweden is dead. | 悪霊退散!悪霊退散!怨霊、物の怪、困った時は ドーマン!セーマン!ドーマン!セーマン! 直ぐに呼びましょう陰陽師レッツゴー!

Gatleos
Member #12,534
January 2011

Well, that seems to be on the right track. It's not a .dll, but in my header, there's a class constructor that dynamically allocates a 2d array, and a destructor that frees it:

#SelectExpand
1struct Tile 2{ 3int symbol; 4const char *color; 5const char *backcolor; 6}; 7 8class Window 9{ 10public: 11int x;//Window x offset 12int y;//Window y offset 13int w;//Window width 14int h;//Window height 15Tile **tile;//2d array of contents of window 16Window(int xpos,int ypos,int width,int height) 17{ 18tile = new Tile*[width+1]; 19for(int i=0;i<=width+1;i++) 20{ 21tile[i] = new Tile[height+1]; 22} 23for(int i=0;i<=width+1;i++) 24for(int j=0;j<=height+1;j++) 25{ 26tile[i][j].symbol=0; 27tile[i][j].color="white"; 28tile[i][j].backcolor="black"; 29} 30x=xpos; 31y=ypos; 32w=width; 33h=height; 34} 35~Window() 36{ 37delete tile; 38} 39};

And this function is called after the main game loop is done:

void EndAllegro()
{
al_destroy_bitmap(ascii);
al_destroy_timer(timer);
al_destroy_display(display);
al_destroy_event_queue(event_queue);
}

X-G
Member #856
December 2000
avatar

EDIT: Nevermind, I see your error. You're using the wrong kind of delete. You allocated the tile array with new[], so you have to delete it with delete[].

--
Since 2008-Jun-18, democracy in Sweden is dead. | 悪霊退散!悪霊退散!怨霊、物の怪、困った時は ドーマン!セーマン!ドーマン!セーマン! 直ぐに呼びましょう陰陽師レッツゴー!

Gatleos
Member #12,534
January 2011

So:
delete[] tile;
like that?

Doesn't seem to get rid of the assertion failure. There must be something else in addition to that.

X-G
Member #856
December 2000
avatar

Yes, that's right. By the way, you never free the pointers inside the array. Also make sure you're not making any accidental copies of that class anywhere (doing so is a sure way to crash -- your class does not have full copy semantics).

It's entirely plausible for there to be more errors like this around. Check around for suspicious deletes, and paste if you have more details for us.

--
Since 2008-Jun-18, democracy in Sweden is dead. | 悪霊退散!悪霊退散!怨霊、物の怪、困った時は ドーマン!セーマン!ドーマン!セーマン! 直ぐに呼びましょう陰陽師レッツゴー!

Edgar Reynaldo
Member #8,592
May 2007
avatar

Gatleos, where are your indents? :o

Also, you're not deleting your Tile** properly. You need to loop over the contents and delete [] those before you delete [] the Tile**.

tile = new Tile*[width + 1];
for (int i = 0 ; i < width + 1 ; ++i) {
   tile[i] = new Tile[height + 1];
}

for (int i = 0  ; < width + 1 ; ++i) {
   delete [] tile[i];
}
delete [] tile;

Gatleos
Member #12,534
January 2011

I thought I needed to delete the "rows" of the array first, I was trying to think of a way to gauge the size of the array to make sure I got all of them. Then I remembered I had a perfectly good variable called window.w as part of the class that I made for exactly that purpose. SIGH

If you think my lack of indents here is bad, you should see the atrocious ocean of poorly-formatted code that constitutes that library I'm building. Speaking of which, part of that library is probably where the error is originating. Thanks for the help so far, I'll post more if I find anything suspicious.

But first: the bitmap called ascii is declared and defined in the object library but freed at the end of my main program by the EndAllegro function. Could that have to do with the assertion failure?

Edgar Reynaldo
Member #8,592
May 2007
avatar

Ehhh, directly destroying a library resource from a client application seems like a bad practice to me. Just give your library a CleanUp function and call that from EndAllegro. If you're not destroying it twice, then I don't see why that would cause the assertion failure though.

X-G
Member #856
December 2000
avatar

All that matters if whether they are part of the same heap or not. But you know, when that debug assertion is hit, you should be able to get a stack trace out of windows that will show you exactly what caused it. What compiler do you use?

--
Since 2008-Jun-18, democracy in Sweden is dead. | 悪霊退散!悪霊退散!怨霊、物の怪、困った時は ドーマン!セーマン!ドーマン!セーマン! 直ぐに呼びましょう陰陽師レッツゴー!

Gatleos
Member #12,534
January 2011

VC++ 2010. Euugghh.

How can I get the stack trace then?

X-G
Member #856
December 2000
avatar

Run your program from inside the IDE, with F5 (not Ctrl+F5). When the assertion hits, press "Retry".

--
Since 2008-Jun-18, democracy in Sweden is dead. | 悪霊退散!悪霊退散!怨霊、物の怪、困った時は ドーマン!セーマン!ドーマン!セーマン! 直ぐに呼びましょう陰陽師レッツゴー!

Gatleos
Member #12,534
January 2011

Done. I got a message from the compiler instead:

{"name":"ABLKi.png","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/8\/d\/8d13af5fac5e3afd59c27cdc5e220511.png","w":528,"h":237,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/8\/d\/8d13af5fac5e3afd59c27cdc5e220511"}ABLKi.png

X-G
Member #856
December 2000
avatar

Yes, now Break. You will get the debugging view in MSVC, which has all the goodies including a stack trace.

--
Since 2008-Jun-18, democracy in Sweden is dead. | 悪霊退散!悪霊退散!怨霊、物の怪、困った時は ドーマン!セーマン!ドーマン!セーマン! 直ぐに呼びましょう陰陽師レッツゴー!

Gatleos
Member #12,534
January 2011

AAAAAHHHHHAAAAAA!!!

I isolated the problem to this function call:
Window Game(1,1,25,20);
the errors stop when I comment it out.

The Window object is part of a class that recreates the newwin() function from pdcurses. The function call above is declaring a Window called Game and calling the class constructor that allocates a 2d array to store the ascii symbol and color data of every "tile" in that window. Something in that constructor must be causing a run-time error 75% of the time when the program starts and a debug assertion failure 100% of the time when the program terminates.

Phew. Here's the Window class again:

#SelectExpand
1class Window 2 { 3 public: 4 int x;//Window x offset 5 int y;//Window y offset 6 int w;//Window width 7 int h;//Window height 8 Tile **tile;//2d array of contents of window 9 Window(int xpos,int ypos,int width,int height) 10 { 11 tile = new Tile*[width+1]; 12 for(int i=0;i<=width+1;i++) 13 { 14 tile[i] = new Tile[height+1]; 15 } 16 for(int i=0;i<=width+1;i++) 17 for(int j=0;j<=height+1;j++) 18 { 19 tile[i][j].symbol=0; 20 tile[i][j].color="white"; 21 tile[i][j].backcolor="black"; 22 } 23 x=xpos; 24 y=ypos; 25 w=width; 26 h=height; 27 } 28 ~Window() 29 { 30 for(int i=0;i<w;++i) 31 delete[] tile[i]; 32 delete[] tile; 33 } 34 };

And here is the Tile struct (an array of these is allocated in the class constructor):

struct Tile
  {
  int symbol;
  const char *color;
  const char *backcolor;
  };

The call to the tile ID in a window looks like this:
Game.tile[i][j].symbol

What could be causing all this trouble in this code?

X-G
Member #856
December 2000
avatar

Well for one thing you're overrunning all your buffers:

Quote:

for(int i=0;i <= width+1;i++)

--
Since 2008-Jun-18, democracy in Sweden is dead. | 悪霊退散!悪霊退散!怨霊、物の怪、困った時は ドーマン!セーマン!ドーマン!セーマン! 直ぐに呼びましょう陰陽師レッツゴー!

Gatleos
Member #12,534
January 2011

Okay, I solved the assertion failure and isolated the run-time error. Now that I can get at it, it turns out it is a memory write error. It's a very strange one, though, in this function:

#SelectExpand
1void Draw_Char(int code,Window window,int x,int y) 2{ 3ALLEGRO_COLOR backcolor=al_map_rgba(0,0,0,255); 4if(code<0 || code>255) 5code=63; 6int backcode=219; 7int row = code / colnum; 8int backrow = backcode / colnum; 9if(x<window.w && y<window.h) 10{ 11window.tile[x][y].symbol=code; 12window.tile[x][y].color="white"; 13window.tile[x][y].backcolor="black"; 14} 15while(code>=colnum) 16code-=colnum; 17while(backcode>=colnum) 18backcode-=colnum; 19if(x<=window.w && y<=window.h) 20{ 21al_draw_tinted_bitmap_region(ascii, backcolor, tilewidth*backcode, tileheight*backrow, tilewidth, tileheight, (tilewidth*x)+(tilewidth*window.x), (tileheight*y)+(tileheight*window.y), 0); 22al_draw_bitmap_region(ascii, tilewidth*code, tileheight*row, tilewidth, tileheight, (tilewidth*x)+(tilewidth*window.x), (tileheight*y)+(tileheight*window.y), 0); 23} 24}

This function is overloaded; the first one takes an ascii code and coordinates and prints it at that location. The second one (shown above), takes a Window variable as an additional argument. At line 11 through 13, the function saves the tile data to the Window object. Line 11 is where the error occurs.

Like I said, it's a memory write error. What's strange, though, is that it only produces the error the second time it cycles through. This function is called each frame of the game loop, but the first time it works perfectly. No variables change, the function is just run twice with the same parameters and only crashes the second time. I'm stumped. :-/

Edgar Reynaldo
Member #8,592
May 2007
avatar

Gatleos said:

if(x<=window.w && y<=window.h)

You're checking the wrong bounds again.

Quote:

void Draw_Char(int code,Window window,int x,int y)

You're passing window by value, and not by reference. That means whatever you do to modify window will be done to a local copy and not to the Window you're passing to the function. It works in this case because the local copy of window has the same Tile** tile that the one passed to the function does.

I don't know why line 11 is failing though, sorry.

 1   2 


Go to: