I am encountering a segmentation fault in my C++ project and using gdb to traceback the cause.
Here is a minimal example that causes the segfault:
int main() {
GameDataRef data = std::make_shared<GameData>();
//ScreenState is an enum declared in a different file
auto screenManager = new ScreenManager(ScreenState::MainMenu);
while (data->window.isOpen()) {
sf::Event event;
sf::Keyboard keyboard;
while (data->window.pollEvent(event)) {
screenManager->handleEvents(event);
}
data->window.clear();
screenManager->update();
screenManager->draw();
data->window.display();
}
delete screenManager;
return 0;
}
Here is my ScreenManager.h file and relavent methods:
class ScreenManager {
public:
ScreenManager(ScreenState initialState);
void handleEvents(sf::Event event);
void update();
void draw() const;
void pushState(ScreenState newState);
void popState();
private:
std::unique_ptr<Screens::Screen> createState(ScreenState state);
std::stack<std::unique_ptr<Screens::Screen>> stateStack;
ScreenState currentState;
Settings settings;
GameDataRef _data;
};
ScreenManager::ScreenManager(ScreenState initialState)
: currentState(initialState)
{
pushState(initialState);
}
void ScreenManager::pushState(ScreenState newState) {
stateStack.push(std::move(createState(currentState)));
stateStack.top()->init();
}
std::unique_ptr<Screens::Screen> ScreenManager::createState(ScreenState state) {
console->debug("Creating screen: " + std::to_string(static_cast<int>(state)));
switch (state) {
case ScreenState::MainMenu:
return std::make_unique<Screens::MenuScreen>(_data);
case ScreenState::Game:
return std::make_unique<Screens::GameScreen>(_data, settings);
case ScreenState::Pause:
return std::make_unique<Screens::PauseScreen>(_data);
case ScreenState::Settings:
return std::make_unique<Screens::SettingsScreen>(_data, settings);
default:
throw std::runtime_error("Unknown screen state");
}
}
The screen manager simply takes in an enum value and creates a screen unique_ptr
then pushes it onto a stack. When init()
is called it results in a segmentation fault.
Here is the trace back from gdb:
0x00007ffff7f30784 in std::_Rb_tree<unsigned int, std::pair<unsigned int const, sf::Font::Page>, std::_Select1st<std::pair<unsigned int const, sf::Font::Page> >, std::less<unsigned int>, std::allocator<std::pair<unsigned int const, sf::Font::Page> > >::_M_mbegin (this=0x470) at /usr/include/c++/12/bits/stl_tree.h:735
735 /usr/include/c++/12/bits/stl_tree.h: No such file or directory.
#0 0x00007ffff7f30784 in std::_Rb_tree<unsigned int, std::pair<unsigned int const, sf::Font::Page>, std::_Select1st<std::pair<unsigned int const, sf::Font::Page> >, std::less<unsigned int>, std::allocator<std::pair<unsigned int const, sf::Font::Page> > >::_M_mbegin (this=0x470) at /usr/include/c++/12/bits/stl_tree.h:735
#1 0x00007ffff7f2f6fe in std::_Rb_tree<unsigned int, std::pair<unsigned int const, sf::Font::Page>, std::_Select1st<std::pair<unsigned int const, sf::Font::Page> >, std::less<unsigned int>, std::allocator<std::pair<unsigned int const, sf::Font::Page> > >::_M_begin (this=0x470) at /usr/include/c++/12/bits/stl_tree.h:739
#2 0x00007ffff7f2fe66 in std::_Rb_tree<unsigned int, std::pair<unsigned int const, sf::Font::Page>, std::_Select1st<std::pair<unsigned int const, sf::Font::Page> >, std::less<unsigned int>, std::allocator<std::pair<unsigned int const, sf::Font::Page> > >::find (this=0x470, __k=@0x7fffffffd584: 60) at /usr/include/c++/12/bits/stl_tree.h:2531
#3 0x00007ffff7f2ef8b in std::map<unsigned int, sf::Font::Page, std::less<unsigned int>, std::allocator<std::pair<unsigned int const, sf::Font::Page> > >::find (this=0x470, __x=@0x7fffffffd584: 60)
at /usr/include/c++/12/bits/stl_map.h:1218
#4 0x00007ffff7f2cff0 in sf::Font::loadPage (this=0x420, characterSize=60) at /home/buildbot-worker/debian-gcc-64/build/src/SFML/Graphics/Font.cpp:574
#5 0x00007ffff7f2cc2e in sf::Font::getTexture (this=0x420, characterSize=60) at /home/buildbot-worker/debian-gcc-64/build/src/SFML/Graphics/Font.cpp:479
--Type <RET> for more, q to quit, c to continue without paging--c
#6 0x00007ffff7f83854 in sf::Text::ensureGeometryUpdate (this=0x555555aa59a8) at /home/buildbot-worker/debian-gcc-64/build/src/SFML/Graphics/Text.cpp:403
#7 0x00007ffff7f8362f in sf::Text::getLocalBounds (this=0x555555aa59a8) at /home/buildbot-worker/debian-gcc-64/build/src/SFML/Graphics/Text.cpp:360
#8 0x00005555556fb45b in Screens::MenuScreen::init (this=0x555555aa5980) at src/Screens/MenuScreen.cpp:30
#9 0x00005555556fd3d1 in ScreenManager::pushState (this=0x555555aa5680, newState=ScreenState::MainMenu) at src/ScreenManager.cpp:52
#10 0x00005555556fcc88 in ScreenManager::ScreenManager (this=0x555555aa5680, initialState=ScreenState::MainMenu) at ...
#11 0x00005555556e6b65 in main () at
The traceback says it’s occurring because of some issues in SFML but I know the init()
method works because this works fine (without ScreenManager):
int main() {
// Create the main window
GameDataRef data = std::make_shared<GameData>();
std::stack<std::unique_ptr<Screens::Screen>> states;
auto state = std::make_unique<Screens::MenuScreen>(data);
states.push(std::move(state));
states.top()->init();
// Main loop
while (data->window.isOpen()) {
// Process events
sf::Event event;
while (data->window.pollEvent(event)) {
// Close window: exit
if (event.type == sf::Event::Closed) {
data->window.close();
}
}
data->window.clear();
states.top()->draw();
data->window.display();
}
return 0;
}
I don’t think gdb is tracing the source of the segmentation fault to the right place. If I comment out the init()
method it still segfaults and traces it back instead to:
window->clear(sf::Color(206, 154, 245));
Again, these both work in the minimal example I provided. Exact same environment.
I’d really appreciate any insight on this.