Category: bugs

Yet another curious bug

Yet another curious bug

MatchThree latest version with a bugI’m aware that C is notorious for unexpected behaviour (UB). Let me describe this bug:

My second game in C + SDL for my newest eBook is Match Three and compiled with Clang-11 on my Raspberry Pi 4B. I’m getting a weird bug that doesn’t occur when I compile it on Windows under MSVC; the only differences between the source code on the PI and Windows are the paths to SDL and the sn._s calls but there aren’t many of those. Also I compiled it with clang-14 on Ubuntu 22.04 LTS on a Hyper-VM and that behaves properly.

 

Each piece is held a struct in a 10 x 10 array. One field is  called size. It’s 0 normally but if it is set to a value, typically  64 then it counts down, one per frame and the piece is drawn rotated by 8 degrees each frame. When it reaches 0 the piece is removed. This is my “down the plughole” way of removing pieces. It takes exactly 64/60 seconds to vanish. I use the size field to draw it when size is non-zero so it shrinks as it rotates It’s a nice effect.

 

The bug though is that when it starts up, several pieces start rotating and keep rotating. The size field stays at 63. There’s no code that explains this behaviour and it only happens on the Raspberry Pi, not on Windows or on Ubuntu. Is it a compiler bug or some weird UB on the PI version. It’s an interesting bug and I’ve only wasted a week of evenings on it so far!

How to debug programs using SDL

How to debug programs using SDL

Terminal fprintf outputThere’s nothing worse than a program halting with a simple “Segmentation fault” and no idea where or why. It happened to me today working on the 2nd eBook (for Raspberry Pi) and I had to figure out where it was going wrong.

In the end it was a really silly bug, I was trying to load masks but had left the masks/ folder out of the filename.

How did I find it? I sprinkled a few fprintf(stderr,”message”); throughout the program changing “message” to something appropriate and launched it from a terminal. I’d thought it was in a function LoadTextures() so added a call before and after but you can see that worked and the segmentation fault happened after LoadTextures().

So I added it before and after LoadMasks() and my second run it happened before it reached the After LoadMasks message.

Note, I used stderr as the output path because, unlike stdout which is buffered and can be cleared, anything sent to stderr appears immediately.  More about this in this offsite article.

The using SDL part of the title is just to show that you can find bugs even in programs that use SDL.

Raspberry Pi Sound issues- trying to fix it

Raspberry Pi Sound issues- trying to fix it

Loudpeaker
Image by OpenClipart-Vectors from Pixabay

In working through my Linux/Raspberry Pi eBook(Yes – the second eBook!), I’m up to the chapter where sounds are introduced using the SDL_mixer library. And I’ve hit two sets of problems.

It sometimes refuses to initialize the sound code.  This code below hits the LogError line:

	int success=Mix_OpenAudio(22050, AUDIO_S16LSB, 2, 8192);
	if (success==-1 ) {
		LogError("InitSetup failed to init audio");
	}

The other day it was working but not today. Now I have updated the Pi’s code (sudo apt update etc) but I wouldn’t have expected that to break it. I’ve been looking on the internet and find the whole thing a bit complicated.

I’ve got my Pi running 64-bit Raspberry Pi OS. I’ve changed the output device to headphones which plug into the headphone socket. If I run the VLC media player and tell it to play into the headphones, it will happily play the .wav files I’ve got for the asteroids game.

But if I run speaker-test, a terminal application with this command line

speaker-test -c2 -twav -l7 plughw:1,0

I get

speaker-test 1.2.4

Playback device is default
Stream parameters are 48000Hz, S16_LE, 2 channels
WAV file(s)
Setting of hwparams failed: Invalid argument

By running this command:

aplay -L

I got 71 lines of output but of these these below are the most important

output
hw:CARD=Headphones,DEV=0
    bcm2835 Headphones, bcm2835 Headphones

and the speaker-test command using the device parameter –Dhw:Headphones now worked. I’ve highlighted the bits in the aplay output needed to identify the device.

The new command  is

speaker-test -c2 -twav -l7 -Dhw:Headphones

I can now hear a female voice saying front left then front right a few times in my headphones.

So my Pi’s sound device is working; I just have to figure why SDL_mixer isn’t always. I’ll keep looking.

And the second problem which only occurs when the mixer is working, is when you play a lot of sounds. The PlayASound() function checks the result. On Windows it never had a problem but on Raspberry Pi, when you blow up a lot of asteroids say at one time, it plays a number of explosions then returns an error for each explosion after that. I think there’s only so many channels; that’s an easy fix; just ignore the error and return as if it succeeded.

Tutorial seven on pointers and C strings published

Tutorial seven on pointers and C strings published

A different kind of sea string
Image by Steve Norris from Pixabay

The tutorials from About.com continue with the 7th one (of about 30) published. This is about C strings which are really just pointers to an array of characters.  Once you understand pointers strings are easy enough to understand.

C is not a great programming language for string handling. To do a lot of manipulation is tedious and error prone. You’ll find safe versions of many of the standard functions for things like string copying and appending. The difference between the safe functions and the non-safe functions is that the safe functions include a maximum length.

For example strcpy() is used to copy a string. It’s definition is this:

char *strcpy(char *dest, const char *src)

That is, it copies a string pointed to by src to a string pointed by dest and confusing also returns a pointer to dest.  What a waste of a function. It could have returned an int saying how many characters were copied instead. Because it relies on src pointing to a string (char *) that terminates with a null (or 0). If the null is missing it can copy a lot more characters and that’s how buffer overflow bugs happen. So you have strncpy which is defined as this:

char *strncpy(char *dest, const char *src, size_t n)

The extra parameter is how many characters are to be copied. That way if it goes wrong, it is limited to n.

The picture? That’s a different kind of sea string…<groan>

Bit of an oddity with VS Code

Bit of an oddity with VS Code

When I first started using it, the C++ extension, and configuring for C++, I got a tasks.json one which was suited for gcc, but recently when I install it, (and the C/C++ Extension for Visual Studio Code, the only choices seem to be these. What happened to the the ones for clang/gcc? The one on the right is what I’m expecting. Even with a C/C++ file open as the instructions here say, I’m getting the one on the left.

VS Code ConfigureVs Configure C++
It’s possible that I’m getting this because I’m using the headmelted and VsCodium versions on a Raspberry Pi.

There’s a bit of a question mark about using the official extension on non-official build of Visual Studio. Headmelted allows it, but VsCodium has its own marketplace.

It’s easy enough to copy tasks.json over so not really a problem but just a minor irritation.

An interesting way to find a bug

An interesting way to find a bug

Disassembly
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;
			break;
		}
	}
}

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;
			break;
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.

1566 Compile errors with just two characters!

1566 Compile errors with just two characters!

1500 compile errorsWhen programmers have to explain why it took longer to get something working,you don’t often here reasons like this. A simple syntax error error took me an hour to find and fix. Yet it does happen and it happened to me today.

Oh sure you feel silly afterwards and it was only a 131 lines of C code. The very last of the 1566 compile errors was unexpected end-of-file found on line 132. That was a red herring of sorts. The error actually occurred right at the start of the program.

Here’s the first 10 lines. It should be quite easy to spot but when you are looking through 130 lines with a hint that it’s messed up the end of the file, it’s not so obvious.

// tictactoe.c
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <time.h>

int playerIsX, computerFirst, x, y, danger, turn;
char board[3][3];  // holds X, O and space
char playerPiece, computerPiece;

In case you haven’t spotted it, it’s the missing .h; it should be string.h not string in that 3rd #include. An obvious-in-hindsight clue is the error listing. The files that are mentioned don’t have .h on them.  (cctype, cstdint etc. Those are C++ files and string is a C++ header file. Also mention of namespace in the error message is also a big hint.

Still I think that sets a record for the most errors generated in a C compile! The compiler btw was Visual Studio 2019’s C/C++ compiler.

The Joys of C++

The Joys of C++

Maze
Image by Arek Socha from Pixabay

My progress on the C++ asteroids game took a little detour down a one way street. The problem I hit was until then I thought I was being clever by passing in a reference to another class in the constructor. That worked fine until I started implementing array classes.

The issue I got was using my constructor meant that the default constructor was deleted. This happens in any class where you add your own constructor as all the special functions are deleted. You then have to add your own Move or Copy assignments if you are doing things that invoke them. Like iterating through an array (or vector in my case). Although I use Bullet and Asteroid classes, I manage  collections of them through an Asteroids and a Bullets class.

Plus I’d decided that vector class wasn’t perhaps the best class to use. This thing runs at 60 fps, so adding and deleting elements from a vector seems a bit wasteful. Instead by using a std::array, and constructing all elements in it when the managing class is instantiated, all I have to do is scan for the first element with an active flag set false. (all are set false when constructed), set a few fields for velocity and position and there it is on screen.

Is this premature optimisation? I don’t think so. One of the things that programmers are told NOT to do!

So I have cleaned up my constructors now. They are parameterless and no special functions are deleted. It’s this kind of stuff that can do your head in and one of the reasons why I think C++ is considered a harder language to master.  I’m certainly a long long way from that.

The maze? Just a metaphor for C++ programming!

Asteroids now runs on a Pi 4

Asteroids now runs on a Pi 4

Asteroids with built in temperature for Raspberry PiI was interested in seeing what frame rate I got out of it and how much it warmed the PI.

The change to get the texture loaded was to split the five image files (four x asteroid + player ship) into two rows each.

I added this code into the DrawPlayerShip function.

    if (Player.dir >= 12) {
	  	spriterect.y = SHIPHEIGHT;
		spriterect.x -= SHIPWIDTH*12;
	}

So for directions 0-11, it uses the top row and 12-23 the 2nd row. There’s similar code in the DrawAsteroids function.

I’m getting about 55 fps, twice the frame rate of the 3B+.  Sustained play over five minutes got the temperature up to 51C, but if I start the game and let asteroids drift about for a while it settles somewhere around 48-50C.

I have a fan fitted plugged into the 3.3V that runs all the time but is almost inaudible. There’s also a 5V setting that can be used for extra cooling but you only need that when temperatures get up to the 80C mark. There’s also 3 copper heat sinks stuck on three chips on the motherboard.

It’s very playable at 55 fps. This isn’t full screen BTW but on a 1024 x 768 playing area. There’s just one last change I’ve added. I combined the uname code to detect if it is running on a Pi and in that case display the temperature  on the Window caption. If you look closely at the image above you’ll see it says 43.82 C. I use a counter and check against so it only reads the temperature once a second and caches the result.

Two bugs on Raspi – one fixed

Two bugs on Raspi – one fixed

asteroids screenshotAs always bugs are the fault of the creator and mea culpa (my bad!). I can trace this back to my conversion from the Windows source to the Ubuntu version. This line in LoadMask

int numread = fread_s(mask, sizeofmask, sizeofmask, 1, fmask);

Became this line in the Ubuntu version.

int numread = fread(mask, sizeofmask, sizeofmask, fmask);

But should have been this instead.

int numread = fread(mask, sizeofmask, 1, fmask);

It affected numread and failed just on the masks/am2.msk load.
The other bug only applies on Raspberry Pi 4 and is a limitation of the implementation of SDL2 texture size.
One of the asteroids graphics is 6720 x 280 and the error it returns is Textures can’t be bigger than 4096×4096.

What is odd that it works on a Raspberry Pi 3B+ but not on the 4 which has 4 GB of RAM. Anyway I’m writing a program to transform the graphics from 24 x 1 shapes to 12 x 2. So the 280 x 280 shape file will be 3360 x 560. This will affect the player ship and all asteroids and need a slight change to the DrawPlayerShip() and DrawAsteroids() functions.