crash with "vector subscript out of range" during handleEvent()

Started by TheNess, 31 March 2015, 01:23:42

TheNess

Hi there :)

First let me say that tgui is excellent and I really love its simplicity!

with that said, I have a voodoo exception that happens at rare occasions. basically I get "vector subscript out of range" when I call handleEvent(), from this code in Container.cpp:


void Container::focusWidget(Widget *const widget)
    {
        // Loop all the widgets
        for (unsigned int i = 0; i < m_Widgets.size(); ++i)
        {
            // Search for the widget that has to be focused
            if (m_Widgets[i].get() == widget)
            {
                // Only continue when the widget wasn't already focused
                if (m_FocusedWidget != i+1)
                {
                    // Unfocus the currently focused widget
                    if (m_FocusedWidget)
                    {
                        m_Widgets[m_FocusedWidget-1]->m_Focused = false; // <- EXCEPTION HERE.
                        m_Widgets[m_FocusedWidget-1]->widgetUnfocused();
                    }

                    // Focus the new widget
                    m_FocusedWidget = i+1;
                    widget->m_Focused = true;
                    widget->widgetFocused();
                }

                break;
            }
        }
    }


it comes from bool handleEvent(sf::Event event, bool resetView) (the last line of "return m_Container.handleEvent(event);"), and it usually happens when I call handleEvent() of the tgui manager and in the same frame I do some "show()" and "hide()" to windows (I have a level editor with tgui and it happens when I switch between tools and hide some windows and show others).

that's all I have on this bug at this moment. I'm trying to look deeper into it, so if you have any ideas or things I can try to narrow it down that will be great.


thanks,




texus

If you can get a minimal code that reproduce this then that would be nice.

Do you have a callback bound to the focus events on widgets? Do you run these show and hide calls inside a function callback from a tgui widget? Do you remove widgets somewhere or do you only hide and show them?

TheNess

QuoteIf you can get a minimal code that reproduce this then that would be nice.
I will try, but know it's a very rare but (took me a while to finally catch it in debug mode lol)

QuoteDo you have a callback bound to the focus events on widgets?
no.
QuoteDo you run these show and hide calls inside a function callback from a tgui widget?
yes. this happens when the user select an item from a top bar and "switch" edit mode for say from editing tiles to editing objects, then I hide all the tiles-related windows and show all the objects-related windows.
QuoteDo you remove widgets somewhere or do you only hide and show them?
no remove, I only create them once and I player with the visibility of the windows via hide() and show().


texus

Quoteyes. this happens when the user select an item from a top bar and "switch" edit mode for say from editing tiles to editing objects, then I hide all the tiles-related windows and show all the objects-related windows.
Could you give me a bit more information about this? What type of widget do they click on and on which callback do you react (e.g. LeftMouseClicked)?

TheNess

It's a MenuBar, and I listen to tgui::MenuBar::MenuItemClicked(). then what happens is that I do the switch (eg, hide() / show() some windows), then I render gui and end frame (window.display()), and then on the next frame when I call gui.handleEvent() it happens.

I'm trying to find a way to reproduce it consistently.

TheNess

Yes I found when exactly it happens! I should have noticed it before.
It goes like this:
In the tiles toolbox window I have a combo-box to select tiletype. I click on the combobox once to open it, and when its still opened I go to the top menu and click on edit objects, which will hide() the tiles window.
note that there are two clicks here: Tools --> Objects. the first click on "Tools" menu closes the combobox, as it should, but apparently its not the same as actually selecting item from the combobox and closing it properly.

I checked and this happens with any combobox and window - if I don't close the combobox by selecting an item but by clicking elsewhere and then hide the window it will happen.


EDIT:

here's a minimal code to reproduce:



int main()
{
// create graphics manager
sf::RenderWindow m_window;
sf::VideoMode DesktopMode = sf::VideoMode::getDesktopMode();
m_window.create(DesktopMode, "My window");

// create gui manager
tgui::Gui gui(m_window);
gui.setGlobalFont(RESOURCES_PATH "gfx/courier.ttf");

// create top menu (relevant to all editing modes)
const unsigned int TOP_BAR_ID = 1;
tgui::MenuBar::Ptr menu(gui);
menu->load(gui_theme);
    menu->setSize((float)m_window.getSize().x, TOP_BAR_HEIGHT);
    menu->addMenu("Do Bug");
    menu->addMenuItem("Do Bug", "DO IT!");
menu->bindCallback(tgui::MenuBar::MenuItemClicked);
menu->bindCallback(tgui::MenuBar::MouseEntered);
    menu->setCallbackId(TOP_BAR_ID);

// the window that will contain the combobox
tgui::ChildWindow::Ptr bug_window(gui);
bug_window->load(gui_theme);
    bug_window->setSize(230, 340);
bug_window->setPosition(100, 100);
bug_window->show();
tgui::ComboBox::Ptr combo;
combo->load(gui_theme);
combo->addItem("click");
combo->addItem("me");
bug_window->add(combo);

    // run the program as long as the window is open
    while (m_window.isOpen())
    {
        // start rendering frame
m_window.clear(sf::Color::Black);

        // poll window events
        sf::Event event;
while (m_window.pollEvent(event))
        {
gui.handleEvent(event);
        }


// poll gui events
tgui::Callback callback;
        while (gui.pollCallback(callback))
        {
if (callback.id == TOP_BAR_ID)
{
menu->moveToFront();
if (callback.trigger == tgui::MenuBar::MenuItemClicked)
{
bug_window->hide();
}
}
}

gui.draw();
m_window.display();
    }

    return 0;
}



please note that it only happens with the "menu->moveToFront();", which was my attempt to make sure the top menu bar is always on-top of everything.

to reproduce click on the combobox once (it will open and you will see items "Click" and "Me"), then without closing it click on the top menu bar "Do Bug" -> "Do It!" and it should happen.

hope it was helpful.
good luck  ;D

texus

I'll have a look at this later today.

Quoteplease note that it only happens with the "menu->moveToFront();", which was my attempt to make sure the top menu bar is always on-top of everything.
The list of the combo box is actually a separate widget which is always in front of all other widgets. So the combination with the open combo box and the moveToFront call probably mess some internal things up.

texus

The problem should be fixed now. I can't test it myself since even your code works here (even though it is clear that it accessed the 3th element from an array containing only 2 elements), it just won't crash on linux.

Thanks for taking the time to debug the issue and find the exact cause.

In order to use the new version, download it and build the libraries with cmake.