I’ve got a problem and the problem is me – Debugging

1-13-2018
When you are working on a program and you are the only one really working on the program, you are going to have issues.

In my excitement on trying to churn out articles as quickly as possible, I’ve been noticing bugs, here and there and a little everywhere. No mind I say, I’ll come back a little later and fix it.

I’ve said that time after time and now it’s time to pay the piper his price. I can’t really do any more coding or even test my next article until I remove some bugs that I have introduced.

It started early enough on. I was looking to figure out why a particular sequence at the end was causing some crashes. It turns out that I had been overwriting some memory at the end of the game, so I simply removed the graphics at hand that seemed to be causing the issue.

Now, in truth, it was not the images at all, it was caused by a memory leak. I had created a dynamic array and did not close out the array at the end. When the game started over, the memory was still claimed and now a new array was created. This happened over and over until the poor Speccy finally crashed. This is a classic memory leak. Claiming more and more memory until the computer runs out of memory.

Lesson 1, do not allocate dynamic arrays unless you close them after you do not need them anymore.

Lesson 2, use a tool that might help you with the process.

Now, not anything against hand debugging, but if there are automatic tools to catch obvious errors, then why not use them. There is one tool that comes to my mind CPP Check. http://cppcheck.sourceforge.net/.

Is it perfect, no, but it is an extremely handy tool and does catch a lot.

I’m not going into the setup of the program as it is intuitive to use. But, catching an error is always worth looking into.

Such as when checking out my screenutils.h file. It’s just a utility I use for testing, CPP check finds 3 errors.

%u in format string (no. 1) requires 'unsigned int' but the argument type is 'signed short'.
%u in format string (no. 1) requires 'unsigned int' but the argument type is 'signed short'.
%d in format string (no. 1) requires 'int' but the argument type is 'unsigned char *'.

So I obviously have 3 casting errors I didn’t catch. My eyes just went right past the mistake and I didn’t see them at all. No worries, minor errors.

The lines in question are.

sprintf(text, "%u:%u", info,info2);

Now this line actually has 2 errors, again Z88dk would probably compile it the same way.

Now, the problem is in the line itself, but also how I have the function set up.

The lines in question are.

sprintf(text, "%u:%u", info,info2);

Now this line actually has 2 errors, again Z88dk would probably compile it the same way.

Now, the problem is in the line itself, but also how I have the function set up.

void printtester3(short info, short info2)

Which means I am looking for short int’s, but the sprintf is looking for an int. Easily solved.

First, change the caller to

void printtester3(unsigned short info, unsigned short info2)

Then change the sprintf command slightly.

sprintf(text, "%hu:%hu", info,info2);
%d in format string (no. 1) requires 'int' but the argument type is 'unsigned char *'.
sprintf(text, "%d", info);

sprintf(text, "%s", info);

and the errors in that function are fixed.

That’s was just the screenutils.h

No real big bugs, nothing that will really crash and burn.

Back to my noticeable bug. You kill 10 enemies and you get

Which is never a good sign. In fact, it looks like a memory corruption problem. Why do I say that the game never freezes during play, this only happens when the game is over, kill 10 enemies and game over. We also know that variables are supposed to be reset along with arrays.

I’m going to try and make the game over situation, kill 1 enemy. Same situation.

Here is our game over routine

//game over check
if( killed == 1 ) //end game
{
    Sound(STOP, 0);                            
    EXIT;
    //    Bitmap(1, 0)
    //    Pause(50);
    //    Bitmap(3, 1);
    //    Pause(50);
    //    Bitmap(2, 1);//this is ok
    //    Pause(50);
    //    Bitmap(0, 0);//crashes game. why??                        
    Pause(50);
    Bitmap(2, 0);                            
    buildMap = 0;            
    isLevelRead = 0;//reset flag to re read level
    goto start;
}

Most of this was from the original FASE game demo. The only real additions are the buildMap and isLevelRead variables. All those will do is call a function that is already being used the first time around.

However, there can be an error in either one of those two functions.

And, yes I know there’s a goto function, in there, it’s part of the original FASE demo. No, I do not have a problem with it for now, but that may change in the future. For now let’s try to do a debugging tip.

Lesson 3, temporarily remove functions.

We know already that a routine or function is called when we start the game, which is why the buildMap and isLevelRead variables are set here.

Let’s remove them both for fun by commenting them out.

//buildMap = 0;            
//isLevelRead = 0;//reset flag to re read level

and it still crashes in the same way.

Let’s look closer at the functions which the variables call as they are called at least once.

Looking at things show that buildMap is not really being utilized at all, just sitting there. No harm, but it is hogging up a little bit of memory. I think I used it as a temporary variable. I’ll leave it alone for now.

The variable that is catching my interest is isLevelRead.

That is used in the routine.

if (isLevelRead == 0)
{
    FRAME;// we force update screen to be able to catch the tile-set for the attributes
    readScreenTiles(x1,y1,tileAttribute);		
    //now that we have read our tiles, we need to select our starting level
    levelPositioning[2] = ((short)level);//recast level to fit properly in array
    startingPosition((short)levelPositioning);//call the function				
    x = levelPositioning[0];
    y = levelPositioning[1];
    enemyStart(level);
    isLevelRead = 1;//level has now been read
    enemySlowDown = 0;
    enemySpeedUp --;//lower is faster
    if (enemySpeedUp < 0) enemySpeedUp = 0;
}

That calls up quite a few items. Where do we start? Let’s cast a wide net and comment out the entire block of code.

//we need to read level into array
if (isLevelRead == 0)
{
    FRAME;// we force update screen to be able to catch the tile-set for the attributes
    /*
    readScreenTiles(x1,y1,tileAttribute);
    //now that we have read our tiles, we need to select our starting level
    levelPositioning[2] = ((short)level);//recast level to fit properly in array 
    startingPosition((short)levelPositioning);
    x = levelPositioning[0];
    y = levelPositioning[1];
    enemyStart(level);
    isLevelRead = 1;//level has now been read
    enemySlowDown = 0;
    enemySpeedUp --;//lower is faster
    if (enemySpeedUp < 0) enemySpeedUp = 0;
    */
}

And that what we did here. Now a test compile and run. Shows the exact same problem.

We might be doing this awhile.

Fast forward an hour.

Well, I didn’t really debug for an hour. I looked at it, did some other stuff (perhaps played a facebook game), had some coffee, look at it again, repeat.

As it turns out, the problem seems to be in the start code.

Remember that goto start command that I said I was going to ignore. Well, time to focus on that.

The goto command, usually bad form in most C code, but in this case completely harmless, points to a block of code to determine if the machine is a 128k machine.

Here’s the block of code.

goto start;

points to

start:
Sound(LOAD, 0);
		
//is the game 128k
if( *is128 )
{
    EI;
    *intadr= IsrSound;
}

Commenting out the entire if statements and subsequent commands, the bug clears up.

//is the game 128k
/*if( *is128 )
{
    EI;
    *intadr= IsrSound;
}*/

This is the sometimes frustrating thing about debugging, it always seems to be the last thing you try.

Now to go back and slowly turn items back on and check to see if I can find any other bugs.

None others for now, but as soon as I discover another, I’ll be sure to write it up.

Advertisements

Author: andydansby

I'm a hobbyist coder working with the ZX Spectrum. Living in New York state near the Syracuse area. I grew up in Virgina. The first computer my parents bought for me was a Timex Sinclair 2068.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s