TTF_Quit segmentation fault

Started by
6 comments, last by GBGames 7 years, 3 months ago

I'm writing a framework for my games which can be found at https://github.com/Nyapp/Builder

It works well until the program has to exit, and then it gets a segfault. It has something to do with TTF_Quit() because I removed it from Builder::deinit() (which quits all 4 SDL libraries) and then it disappears. Help?

Advertisement

I'm writing a framework for my games which can be found at https://github.com/Nyapp/Builder

It works well until the program has to exit, and then it gets a segfault. It has something to do with TTF_Quit() because I removed it from Builder::deinit() (which quits all 4 SDL libraries) and then it disappears. Help?

Have you been able to run your program in gdb or another debugger? I find that it sometimes shows me exactly where things went wrong, although in this case I wonder if the crash is separated from the introduced problem. Valgrind is also a good option if this is a memory issue, as it can tell you if you have issues with memory management.

Looking at font.cpp, I see that you do TTF_CloseFont on your pointer before you assign a new font to it, so that seems correct. Your destructor runs TTF_CloseFont(). Is it possible that the mFont is already closed by this point? The docs don't say what happens if you call CloseFont on an already closed font, so I am not sure what may happen. Sounds like a good experiment to try.

Oh, I just saw that your Builder::deinit() is calling SDL_Quit() before TTF_Quit(). SDL_Quit() should be called last. See https://wiki.libsdl.org/SDL_Quit "If you start a subsystem using a call to that subsystem's init function (for example SDL_VideoInit()) instead of SDL_Init() or SDL_InitSubSystem(), then you must use that subsystem's quit function (SDL_VideoQuit()) to shut it down before calling SDL_Quit()."

I hope this helps!

-------------------------GBGames' Blog: An Indie Game Developer's Somewhat Interesting ThoughtsStaff Reviewer for Game Tunnel

I'm writing a framework for my games which can be found at https://github.com/Nyapp/Builder

It works well until the program has to exit, and then it gets a segfault. It has something to do with TTF_Quit() because I removed it from Builder::deinit() (which quits all 4 SDL libraries) and then it disappears. Help?

Have you been able to run your program in gdb or another debugger? I find that it sometimes shows me exactly where things went wrong, although in this case I wonder if the crash is separated from the introduced problem. Valgrind is also a good option if this is a memory issue, as it can tell you if you have issues with memory management.

Looking at font.cpp, I see that you do TTF_CloseFont on your pointer before you assign a new font to it, so that seems correct. Your destructor runs TTF_CloseFont(). Is it possible that the mFont is already closed by this point? The docs don't say what happens if you call CloseFont on an already closed font, so I am not sure what may happen. Sounds like a good experiment to try.

Oh, I just saw that your Builder::deinit() is calling SDL_Quit() before TTF_Quit(). SDL_Quit() should be called last. See https://wiki.libsdl.org/SDL_Quit "If you start a subsystem using a call to that subsystem's init function (for example SDL_VideoInit()) instead of SDL_Init() or SDL_InitSubSystem(), then you must use that subsystem's quit function (SDL_VideoQuit()) to shut it down before calling SDL_Quit()."

I hope this helps!

I added a check in ~Font() and re-ordered the quit functions so SDL_Quit() is last, but it didn't work. gdb says this:

GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from a.out...(no debugging symbols found)...done.
(gdb) run
Starting program: /media/stackmasher/cfca4fc1-f4ef-4ffd-a2d3-cf6fc050941e/Programming/Projects/Builder-master/demo/a.out
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7fffe35d9700 (LWP 5113)]
[New Thread 0x7fffe2dd8700 (LWP 5114)]
[Thread 0x7fffe2dd8700 (LWP 5114) exited]
[Thread 0x7fffe35d9700 (LWP 5113) exited]

Thread 1 "a.out" received signal SIGSEGV, Segmentation fault.
0x00007ffff2ef0248 in FT_Done_Face ()
from /usr/lib/x86_64-linux-gnu/libfreetype.so.6
(gdb)

In gdb after it crashes, can you type "bt", hit Enter, and show us the stack trace it prints out?

I tried to pull down your code and compile it myself, but my gcc is older. I need to update my system, and I won't be doing so anytime soon.

-------------------------GBGames' Blog: An Indie Game Developer's Somewhat Interesting ThoughtsStaff Reviewer for Game Tunnel

In gdb after it crashes, can you type "bt", hit Enter, and show us the stack trace it prints out?

I tried to pull down your code and compile it myself, but my gcc is older. I need to update my system, and I won't be doing so anytime soon.

That's a useful command tongue.png I'll have to remember it (I still don't understand the cause of the error though)

#0 0x00007ffff2eee248 in FT_Done_Face ()
from /usr/lib/x86_64-linux-gnu/libfreetype.so.6
#1 0x00007ffff7461a6f in TTF_CloseFont ()
from /usr/lib/x86_64-linux-gnu/libSDL2_ttf-2.0.so.0
#2 0x00007ffff7bd1739 in Builder::Font::~Font() () from /usr/lib/libbuilder.so
#3 0x0000000000401951 in main ()

If you compile your program with the debug flags (-g) (oh, and use -O0 to make sure no optimizations are made), you might see more information that could be useful.

Obviously we can see that the crash is happening when your font is being deleted. With debug output, we might be able to see which line is being called at each point in the stack trace, which will help us narrow down what is happening.

Although now that I am looking at your main function, here's my educated guess at what is happening: you are calling deinit() before your font is getting destroyed.

You call init(), which initializes all of your subsystems for SDL, then you create your Window, Player, Font, and Text objects on the stack.

But then you call deinit(), which shuts down all the SDL functionality, and when your main function exits, it calls the destructors on your objects in reverse order of when they were created. The Text object has an uninteresting destructor, so it's fine, but then your Font object calls TTF_CloseFont(), yet you've already called TTF_Quit().

You should probably ensure that deinit() is called after your resources are finished using SDL functionality. The two ways to do it would be to enclose everything in main after init() and before deinit() in curly braces so that it has its own scope (my preference), or use pointers and make sure to delete the objects before calling deinit().

With the enclosing scope, you can guarantee that objects created within that scope, like your Font object, will get destroyed when that scope is exited automatically, and then your deinit() should be safe to use.

Let me know if this information helps!

-------------------------GBGames' Blog: An Indie Game Developer's Somewhat Interesting ThoughtsStaff Reviewer for Game Tunnel

If you compile your program with the debug flags (-g) (oh, and use -O0 to make sure no optimizations are made), you might see more information that could be useful.

Obviously we can see that the crash is happening when your font is being deleted. With debug output, we might be able to see which line is being called at each point in the stack trace, which will help us narrow down what is happening.

Although now that I am looking at your main function, here's my educated guess at what is happening: you are calling deinit() before your font is getting destroyed.

You call init(), which initializes all of your subsystems for SDL, then you create your Window, Player, Font, and Text objects on the stack.

But then you call deinit(), which shuts down all the SDL functionality, and when your main function exits, it calls the destructors on your objects in reverse order of when they were created. The Text object has an uninteresting destructor, so it's fine, but then your Font object calls TTF_CloseFont(), yet you've already called TTF_Quit().

You should probably ensure that deinit() is called after your resources are finished using SDL functionality. The two ways to do it would be to enclose everything in main after init() and before deinit() in curly braces so that it has its own scope (my preference), or use pointers and make sure to delete the objects before calling deinit().

With the enclosing scope, you can guarantee that objects created within that scope, like your Font object, will get destroyed when that scope is exited automatically, and then your deinit() should be safe to use.

Let me know if this information helps!

I came up with the cleaner solution of defining main as part of the framework like so:

int game(int argc, char** argv);
int main(int argc, char** argv)
{
    Builder::init();
    int returnValue = game(argc,argv);
    Builder::deinit();
    return returnValue;
}

And then obviously in the game you use game() instead of main()

Perfect! I'm glad it worked out!

-------------------------GBGames' Blog: An Indie Game Developer's Somewhat Interesting ThoughtsStaff Reviewer for Game Tunnel

This topic is closed to new replies.

Advertisement