You’re using Ubuntu, right? Then I suggest you start by installing valgrind:
sudo apt-get install valgrind
Then add -g
to your compiler flags (for better debug messages):
g++ main.cpp -lSDL2 -lSDL2_image -lSDL2_mixer -Wall -g -o "Butter Game"
(Don’t forget to fix any warnings that the compiler shows)
Then run your program through valgrind:
valgrind "./Butter Game"
Since this is the first time I will walk you through the rest but I suggest you try it on your own so that you learn how to do it by yourself in the future. Note that you might not get the exact same messages as I do due to “random chance” and because we use different versions of g++ and SDL.
When I click on the play button the program crashes and the following message is outputted in the terminal:
==3018== Process terminating with default action of signal 11 (SIGSEGV)
==3018== Access not within mapped region at address 0x0
==3018== at 0x109FC6: createHitbox(int, int, int, int) (loadImage.h:483)
==3018== by 0x10CE67: queueVisualEvents() (main.cpp:286)
==3018== by 0x10D0FD: main (main.cpp:338)
This says the segfault happened on line 483 in loadImage.h. It also mentions address 0x0, which is just the hex notation for zero, so this most likely happens when you dereferencing a null pointer.
The offending line 483 in loadImage.h looks like this:
hitbox1->x = posX;
Based on the valgrind output it looks like hitbox1
is a null pointer.
Question is, why is it a pointer? If you make it a pointer you need to make sure it points to a SDL_Rect object before using it like this.
When I run the program through valgrind again and instead press the wimp button then I get a different message:
==3130== Invalid read of size 8
==3130== at 0x4EEB0DE: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.4.1)
==3130== by 0x4E94BEA: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.4.1)
==3130== by 0x10C7C5: quit() (main.cpp:104)
==3130== by 0x10CD54: queueVisualEvents() (main.cpp:256)
==3130== by 0x10D0FD: main (main.cpp:338)
==3130== Address 0x270ea6d0 is 0 bytes inside a block of size 216 free'd
==3130== at 0x4C2CDDB: free (vg_replace_malloc.c:530)
==3130== by 0x10C7B6: quit() (main.cpp:103)
==3130== by 0x10CD54: queueVisualEvents() (main.cpp:256)
==3130== by 0x10D0FD: main (main.cpp:338)
==3130== Block was alloc'd at
==3130== at 0x4C2DBC5: calloc (vg_replace_malloc.c:711)
==3130== by 0x4EEF479: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.4.1)
==3130== by 0x10C6DE: createHDWindow() (main.cpp:84)
==3130== by 0x10D0C0: main (main.cpp:331)
The first part is the most important. It says “an invalid read of size 8” happened on line 104 of main.cpp, inside the quit() function, which is this line:
SDL_DestroyRenderer(renderer);
I think this is happening because you destroyed the window on the line above, which also destroys the renderer, so you end up passing a dangling pointer to SDL_DestroyRenderer
.
Note that you can get error messages from valgrind without the program crashing. This does not mean you should ignore them. It’s quite common that valgrind is able to find the root cause of an issue while the crash/bug doesn’t show up until much later (this is what “memory corruption” can do).
You might get messages such as “Conditional jump or move depends on uninitialised value(s)” from within SDL during startup but these are usually nothing to worry about.
Note that segfaults are not the same as memory leaks, although valgrind can help you find both.
You might also want to read The Valgrind Quick Start Guide.