Bug killers

B5262118b588a5a420230bfbef4a2cdf
0
Stainless 151 Sep 18, 2012 at 18:53 c++

The game I am working on at the moment is almost complete, it works perfectly on PC and various other platforms, but has a horrible bug on Samsung TV’s.

So I am going through all my usual bug hunting techniques, and it made me think it might be worthwhile starting a thread about problems that are hard to find.

So here’s a couple I can think of straight away.

1) Works on {insert platform here} but not on {insert other platform here}

The first thing I look for in this case is an uninitialized member variable. On PC when you create a new instance of an object the memory allocated for it is often full of zero’s. On other platforms the memory can just be filled with random data. This can be a really tricky bug to find, but if you observe the bug closely you can often get a clue as to which variable is the problem.

This bug can also be called Works for {insert time here} then goes wrong.

In this case it can happen when the game runs out of unused memory and starts reusing memory that has been allocated before.

2) Works for {n} objects but doesn’t work for {m}

It is common for objects to be lumped together. The c++ way is to have a base class and then derive other classes off the base class. However before we had c++, it was common to use structs for objects. To make the objects adaptable, we used unions.

struct GameObject
{
     int ID;
     union
     {
         char * name;
         float fname;
         int   iname;
     }u;
}GameObjectt;

That’s fine as it is, however this can be fatal on some platforms.

Consider this variation on the above code.

struct GameObject
{
     int ID;
     char fred;
     union
     {
         char * name;
         float fname;
         int   iname;
     }u;
}GameObjectt;

Looks fine doesn’t it? Well it’s a potential disaster.

Some compilers will look at that and create a structure like this.

ID          0x0000
fred       0x0004
u           0x0005
size       0x0009

Ow dear….. if you access name, all is fine. Access fname or iname and the game crashes.

This is because a lot of platforms can only pick up a pointer from an aligned address. This does not apply to a char * as the compiler knows that a sizeof(char) can be one, so adds extra code to handle this case.

There are a lot of ways to fix this, gcc has alignment macros you can add to the end of a struct, other compilers have command line switches, but the best thing to do is rewrite the code to bring it up to date.

Well that’s two from me, one obvious, one obscure. Anybody got any more?

3 Replies

Please log in or register to post a reply.

6837d514b487de395be51432d9cdd078
0
TheNut 179 Sep 18, 2012 at 21:53

I’ve been dinged on that padding issue before, which I swore from that day on I would write my own serializers. It was about the same time I also lost trust in the STL. Nowadays I rarely encounter programming errors **angels singing**. I mostly encounter the oddball crash during debugging because I forgot to instantiate an object or some such. You know, the phone rings, talk to the boss, hang-up and then you’re like “k, what was I doing?”. Other than that, I can’t really think of anything recently. Perhaps some of the less common things to consider:

Memory Leaks
1. Don’t forget to declare your base class destructor virtual.
2. Take advantage of smart pointers.
3. Use _CrtDumpMemoryLeaks in Visual C++ to help track memory leaks if you didn’t splurge on a commercial product.
4. Never forget to release OpenGL or DirectX resources (textures, VBOs, sound buffers, etc.). I see this a lot with WebGL.

General Programming
1. Unit test
2. Unit test
3. Unit…. Okay, hopefully you get the picture :)

A8433b04cb41dd57113740b779f61acb
0
Reedbeta 167 Sep 18, 2012 at 22:31

A nasty issue one of my coworkers ran into the other day: when using multithreading and you have a function that can be called from different threads, local ‘static’ variables will not be initialized thread-safely. It’s because local statics are initialized on the first call of the function, but it could be called for the “first” time simultaneously from two or more threads. The solution: move the static outside the function; then it gets initialized before main().

Another favorite of mine is nested uses of strtok. For example, you’re parsing key-value pairs but then within one of the values you want to parse further to extract sub-values, e.g. vector components. Since strtok maintains internal state, when you return to the outer parser it will be very confused. Of course, you could say “serves you right for using strtok”. :)

B5262118b588a5a420230bfbef4a2cdf
0
Stainless 151 Sep 20, 2012 at 08:53

@TheNut

  1. Unit…. Okay, hopefully you get the picture :)

I wish!! I spend a lot of time porting other peoples code, sadly they very very rarely have unit testing built in. :(

strtok …. yes that can bite you.

Another I have been bit by is stack overflow. C is a stack based language, when you call a function the variables are pushed on the stack, etc. but people often don’t think about where variables are stored in a function, they are stored in the stack as well. I saw in one block of code that was called a lot on small images, one day a large image got added to the game and the game crashed. It was a nightmare to find as the crash left the machine in such a bad state the debugger couldn’t figure out what was wrong and just crashed itself.

void RecodeImageBGRA(int wid, int height)
{
      uint buffer[wid*height];
     ......

That was chewing up a huge chunk of stack and causing the game to crash, but only when a specific image was used in the game.

Fun to track down that one. :)