SFML community forums
Help => General => Topic started by: kiswa on May 05, 2015, 02:12:48 am
-
I have been working on a basic starter setup for an SFML game. When I run it, it works fine, states transition as expected, updates are are at 30 per second, FPS is unbound. Going well.
However, when I transition from the game state to the pause state and back, I get a segfault when closing the window. This does not happen when exiting directly from the game (initial) state, or from the pause state. It only happens when exiting after returning from the pause state to the game state.
I have no idea what I'm missing. Take a look at the code and let me know if you have any ideas. https://github.com/kiswa/SFML_Starter/
-
When things crash you should always use your debugger to find out where and possibly why.
You have a stack of unique_ptr. When you call exitState from the event handling in the pause state, the statemachine will pop the pause state from the stack and since it doesn't get further use, the unique_ptr gets destroyed and the play state with it. BUT your code execution is still in the pause state object, which is now deleted, which causes a crash.
For as long as you're rynning code in a state, you can't delete the state object.
-
I did use a debugger, and I still couldn't figure out exactly where it was blowing up.
I figured it was related to the stack, and I'm assuming you meant "pause state" when you wrote "unique_ptr gets destroyed and the play state with it." If I'm understanding correctly, I can't pop the pause state because the running code is still in the pause state? Then why does it successfully return to the game state? I can enter and exit the pause state multiple times without a problem, but it throws a segfault when closing the window from the game state. (EDIT: But only if the pause state was entered and exited at least once.)
I'm still not sure what I'm missing, but thanks for the help so far.
-
I've continued to dig into this and am getting nowhere. I changed a significant amount of code today, and I still get the same result.
Apparently, I'm doing something wrong when leaving a state. When the segfault is thrown, the call stack looks like this:
#0 sf::Window::pollEvent(sf::Event&)() at :0
#1 kg::PauseState::handleInput(this = 0xef64d0) at src/pause_state.cpp:36
#2 kg::PauseState::mainLoop(this = 0xef64d0) at src/pause_state.cpp:28
#3 kg::PauseState::start(this = 0xef64d0) at src/pause_state.cpp:9
#4 kg::StateMachine::startState(this = 0x610150, newState = std::unique_ptr<kg::State> containing 0x0, isReplacing = false) at src/state_machine.cpp:15
#5 kg::GameState::handleInput(this = 0x10a62d0) at src/game_state.cpp:83
#6 kg::GameState::mainLoop(this = 0x10a62d0) at src/game_state.cpp:63
#7 kg::GameState::start(this = 0x10a62d0) at src/game_state.cpp:11
#8 kg::StateMachine::startState(this = 0x610150, newState = std::unique_ptr<kg::State> containing 0x0, isReplacing = true) at src/state_machine.cpp:15
#9 kg::Game::Game(this = 0x7fffffffe7a0, width = 800, height = 600, title = "(\a\?\?\?\?\?\?$@\?\?\?\?\?\?\?\?\?\?\\?\?\?\?\?\?\?\?\?\?\?\?@\?\?\?\?\?\?\\?\?\?\\?\?\\?\?\?\?\?\?\?\?\?\?\?\?\\?\?\?\?\?\?\\?\?\?\?\?@", '\?' <repeats 13 times>, "/TwQ\???\?\?$@\?\?\?\?\?\?\?\?\?\?\", '\?' <repeats 18 times>, "/T\?\?\?\5Tv/Tg=r'Tv", '\?' <repeats 24 times>, "\?\?@\?\?\?\?\?\?\?\?\?\?\\?\?\", '\?' <repeats 15 times>...) at src/game.cpp:8
#10 main(argc = 1, argv = 0x7fffffffe8b8) at src/main.cpp:4
I don't understand why PauseState code is still running at this point! It should not exist once it has been popped off the state machine stack. What am I doing wrong?
Latest code is at https://github.com/kiswa/SFML_Starter/
-
Debug further. You can track the creation and destruction of the PauseState by placing breakpoints or cout statements. Step through from beginning to end if necessary. You'll see quickly if and when these operations occur as expected.
Don't expect the community to debug your project for you... Your current problem isn't even related to SFML ;)
-
I'm still going through it, but you're probably right.
If anyone wants to spend some time figuring it out though, I'd appreciate it. I've stepped through it several times, and everything goes in the order I expect. It only segfaults in one particular case, and I've gone through it step-by-step several times.
I thought it was related to SFML because the segfault was always thrown from the RenderWindow::pollEVent method
-
eXpl0it3r already told you what happens.
You have a stack of unique_ptr. When you call exitState from the event handling in the pause state, the statemachine will pop the pause state from the stack and since it doesn't get further use, the unique_ptr gets destroyed and the play state with it. BUT your code execution is still in the pause state object, which is now deleted, which causes a crash.
For as long as you're rynning code in a state, you can't delete the state object.
_states.pop();
As soon as this is called your state is destroyed, but yet the code that is currently executing is contained within the destroyed state. The crash happening inside pollEvent most likely comes from the fact that the sf::Event memory is already cleaned up, but you pass is back into the pollEvent function. No matter what exactly causes the crash, its because you destroy the state object while still executing code inside it.
-
I know that's what's causing the problem, I'm just having a hard time figuring out what needs to be done to solve it. I tried adding an additional check to the loop and calling a method before popping the state from the stack, but it had the same results.
I'm obviously missing something (it's been a while since I did any serious C++) and I was just hoping someone would see it and go "Oh, you just need to do X." Optimistic, I know.
-
There is no 'simple' solution, you need to ensure that when popping the state that the execution stack calling pop does not originate from within the state being destroyed (or keep the state alive while calling pop).
The way the SFML Game Development book does it is that it queues changes and then executes them at a later time.
https://github.com/SFML/SFML-Game-Development-Book/blob/master/05_States/Source/StateStack.cpp#L53
https://github.com/SFML/SFML-Game-Development-Book/blob/master/05_States/Source/StateStack.cpp#L74
-
Maybe not 'simple', but your response just got my brain to think about it the right way and I have some ideas now.
Thank you!
-
Another solution is to store the returned state when calling pop and then discard it in the next iteration.
-
I've actually got it working now (with one text-related bug I'm still messing with). Once I realized what you guys meant I came at it from the other side of things.
The game class now runs the loop, calling the methods on the active state. When a state transitions, it sets a flag in the state machine and at the start of each loop the machine checks that flag to see if it should pop the state (or add a new state).
I just checked it in, so you can see what I did if you're interested. https://github.com/kiswa/SFML_Starter/