An interesting way to find a bug

Image by Free-Photos from Pixabay

Here’s a bit of code with a very subtle bug. It wasn’t ever setting the size file (an int field in a struct). So I took a look at the assembly generated and spotted it. In retrospect it was a bit obvious!

void DoRotateAndDie() {
	for (int i = 0; i < 10; i++) {
		while(1) {
			int x = Random(MAXBOARDWIDTH) - 1;
			int y = Random(MAXBOARDHEIGHT) - 1;
			pBoardPiece ppiece = board[y][x].ppiece;
			if (!ppiece) continue;
			if (ppiece->size != 0) continue; // Not this one
			ppiece->size == 64;

It’s somewhat stupid. The line just before the break is meant to be an assignment but there’s double ==. Stranbgely enough the C compiler In Visual Studio didn’t generate a warning or error. When I put a break point on the line, it hit the break instead.

I was curious to see what code was generated. Here’s the disassembly.

			if (ppiece->size != 0) continue; // Not this one
00124892  mov         eax,dword ptr [ebp-2Ch]  
00124895  cmp         dword ptr [eax+30h],0  
00124899  je          DoRotateAndDie+8Dh (012489Dh)  
0012489B  jmp         DoRotateAndDie+40h (0124850h)  
			ppiece->size == 64;
0012489D  jmp         DoRotateAndDie+91h (01248A1h) 

So it doesn’t generate any code at all for that assignment of 64, it’s just two jmps with no assignment! But fixing it and checking the code this time produces this:

			if (ppiece->size != 0) continue; // Not this one
00144895  cmp         dword ptr [eax+30h],0  
00144899  je          DoRotateAndDie+8Dh (014489Dh)  
0014489B  jmp         DoRotateAndDie+40h (0144850h)  
			ppiece->size = 64;
0014489D  mov         eax,dword ptr [ebp-2Ch]  
001448A0  mov         dword ptr [eax+30h],40h  

Those last two lines assign 64 (40h in assembly).

Normally I pick up these type of bugs just by visual inspection. If it isn’t obvious then there are two other techniques to try. The first is get a colleague, or if one isn’t handy a teddy bear or toy duck will do. Now explain to the colleague/teddy bear/duck how the code works. Explicitly say it out loud, do not just think it. It’s amazing how often that works. The process of explaining it forces your brain to do a bit more work then if you just mentally walked the code.

The other method is to disassemble the code and look at it from a different point of view. If the compiler sees the code differently than how you think it should be, it might provide a clue. Here I found out that putting an expression in code instead of a statement, generates no code. Normally with =/== it’s the opposite, putting in an assignment instead of a comparison.