Segfault in the destructor for wxListBox (Ubuntu & GTK+)

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
Virchanza
Experienced Solver
Experienced Solver
Posts: 78
Joined: Sun Jul 19, 2009 6:12 am

Segfault in the destructor for wxListBox (Ubuntu & GTK+)

Post by Virchanza » Wed Sep 15, 2010 12:15 pm

My program has its main dialog box, and the main dialog box displays a modeless child dialog box whose class is "Dialog_Detailed_MAC_Info".

When I display the child dialog box and play around with it, everything works fine.

However, when I close the child dialog box, my program immediately segfaults and closes.

I've got the backtrace from the core dump file. Look at #30, it's where the child dialog box begins to destroy itself. Everything goes fine until the destructor for wxListBox is reached.

Code: Select all

#0  0x00000000 in ?? ()
#1  0x00344ac8 in wxAppConsole::HandleEvent(wxEvtHandler*, void (wxEvtHandler::*)(wxEvent&), wxEvent&) const ()
   from /usr/lib/libwx_baseu-2.8.so.0
#2  0x003e3429 in wxEvtHandler::ProcessEventIfMatches(wxEventTableEntryBase const&, wxEvtHandler*, wxEvent&) ()
   from /usr/lib/libwx_baseu-2.8.so.0
#3  0x003e35b8 in wxEvtHandler::SearchDynamicEventTable(wxEvent&) () from /usr/lib/libwx_baseu-2.8.so.0
#4  0x003e45b5 in wxEvtHandler::ProcessEvent(wxEvent&) () from /usr/lib/libwx_baseu-2.8.so.0
#5  0x00bba388 in ?? () from /usr/lib/libwx_gtk2u_core-2.8.so.0
#6  0x008dbdcc in g_cclosure_marshal_VOID__VOID () from /usr/lib/libgobject-2.0.so.0
#7  0x008ce252 in g_closure_invoke () from /usr/lib/libgobject-2.0.so.0
#8  0x008e2d90 in ?? () from /usr/lib/libgobject-2.0.so.0
#9  0x008e3db4 in g_signal_emit_valist () from /usr/lib/libgobject-2.0.so.0
#10 0x008e4085 in g_signal_emit_by_name () from /usr/lib/libgobject-2.0.so.0
#11 0x066e74a3 in ?? () from /usr/lib/libgtk-x11-2.0.so.0
#12 0x008db438 in g_cclosure_marshal_VOID__BOXED () from /usr/lib/libgobject-2.0.so.0
#13 0x008ce252 in g_closure_invoke () from /usr/lib/libgobject-2.0.so.0
#14 0x008e299d in ?? () from /usr/lib/libgobject-2.0.so.0
#15 0x008e3db4 in g_signal_emit_valist () from /usr/lib/libgobject-2.0.so.0
#16 0x008e4256 in g_signal_emit () from /usr/lib/libgobject-2.0.so.0
#17 0x066d10ea in gtk_tree_model_row_deleted () from /usr/lib/libgtk-x11-2.0.so.0
#18 0x065dd834 in gtk_list_store_remove () from /usr/lib/libgtk-x11-2.0.so.0
#19 0x065dd900 in gtk_list_store_clear () from /usr/lib/libgtk-x11-2.0.so.0
#20 0x00bb87ba in wxListBox::Clear() () from /usr/lib/libwx_gtk2u_core-2.8.so.0
#21 0x00bb89cf in wxListBox::~wxListBox() () from /usr/lib/libwx_gtk2u_core-2.8.so.0
#22 0x00c64034 in wxWindowBase::DestroyChildren() () from /usr/lib/libwx_gtk2u_core-2.8.so.0
#23 0x00b5e8aa in wxWindow::~wxWindow() () from /usr/lib/libwx_gtk2u_core-2.8.so.0
#24 0x00c6044c in wxTopLevelWindowBase::~wxTopLevelWindowBase() () from /usr/lib/libwx_gtk2u_core-2.8.so.0
#25 0x00b55209 in wxTopLevelWindowGTK::~wxTopLevelWindowGTK() () from /usr/lib/libwx_gtk2u_core-2.8.so.0
#26 0x080651ec in ~wxTopLevelWindow (this=0x8d36998, __in_chrg=<value optimized out>) at /usr/include/wx-2.8/wx/toplevel.h:353
#27 0x0806521c in ~wxDialogBase (this=0x8d36998, __in_chrg=<value optimized out>) at /usr/include/wx-2.8/wx/dialog.h:42
#28 0x0806524c in ~wxDialog (this=0x8d36998, __in_chrg=<value optimized out>) at /usr/include/wx-2.8/wx/gtk/dialog.h:48
#29 0x0805fc96 in ~Dialog_Detailed_MAC_Info__Auto_Base_Class (this=0x8d36998, __in_chrg=<value optimized out>)
    at /home/virchanza/folder_for_dynamo/source_code/AUTO_GENERATED_wxformbuilder.cpp:439
#30 0x08066726 in ~Dialog_Detailed_MAC_Info (this=0x8d36998, __in_chrg=<value optimized out>)
    at /home/virchanza/folder_for_dynamo/source_code/GUI_Dialog_Detailed_MAC_Info.hpp:9
#31 0x00bdbaa8 in wxAppBase::DeletePendingObjects() () from /usr/lib/libwx_gtk2u_core-2.8.so.0
#32 0x00bdbb74 in wxAppBase::ProcessIdle() () from /usr/lib/libwx_gtk2u_core-2.8.so.0
#33 0x00b2f565 in ?? () from /usr/lib/libwx_gtk2u_core-2.8.so.0
#34 0x06ef4661 in ?? () from /lib/libglib-2.0.so.0
#35 0x06ef65e5 in g_main_context_dispatch () from /lib/libglib-2.0.so.0
#36 0x06efa2d8 in ?? () from /lib/libglib-2.0.so.0
#37 0x06efa817 in g_main_loop_run () from /lib/libglib-2.0.so.0
#38 0x065e13c9 in gtk_main () from /usr/lib/libgtk-x11-2.0.so.0
#39 0x00b48928 in wxEventLoop::Run() () from /usr/lib/libwx_gtk2u_core-2.8.so.0
#40 0x00bdb95e in wxAppBase::MainLoop() () from /usr/lib/libwx_gtk2u_core-2.8.so.0
#41 0x00bdb551 in wxAppBase::OnRun() () from /usr/lib/libwx_gtk2u_core-2.8.so.0
#42 0x0037e7f3 in wxEntry(int&, wchar_t**) () from /usr/lib/libwx_baseu-2.8.so.0
#43 0x0037e9d7 in wxEntry(int&, char**) () from /usr/lib/libwx_baseu-2.8.so.0
#44 0x0806afd3 in main (argc=1, argv=0xbfc76204) at /home/virchanza/folder_for_dynamo/source_code/main.cpp:27
(gdb) 
Has anyone ever seen anything like this before?

Here's the source code for the child dialog box. There's two wxListBox's on the child dialog box, one is called m_list_ips and the other one is called m_list_ports (I'm actually not sure which one is causing the segfault when it destroys itself).

Code: Select all

#include "GUI_Dialog_Detailed_MAC_Info.hpp"

#include "parser.hpp"

#include "specs.hpp" /* Qty_IP */

#include "globals.hpp" /* CriticalSectionLocker_MAC_Database */

Dialog_Detailed_MAC_Info::Dialog_Detailed_MAC_Info(wxWindow* parent,MAC_Data const *const arg_p)
 : Dialog_Detailed_MAC_Info__Auto_Base_Class( parent ), p_mac_data(arg_p)
{
    CriticalSectionLocker_MAC_Database locker;  /* <--- Safety First! */

    assert(p_mac_data != 0);

    assert(p_mac_data->num != 0);

    m_txt_MAC->ChangeValue( MakeStringFromMAC(p_mac_data->num) );

    this->Populate_IP_List();
}

void Dialog_Detailed_MAC_Info::Populate_IP_List()
{
    /* CRITICAL SECTION MUST BE ENTERED BEFORE
       THIS FUNCTION IS CALLED! */

    for (IP_Data const *p = p_mac_data->ip_data_array; p->num; ++p)
    {
        m_list_ips->Append( MakeStringFromIP(p->num) );

        /* The string returned from MakeStringFromIP is not
           destroyed until the end of the statement */
    }
}

void Dialog_Detailed_MAC_Info::OnButtonClick_Refresh( wxCommandEvent& event )
{
    m_list_ips->Clear();
    m_list_ports->Clear();

    CriticalSectionLocker_MAC_Database locker;  /* <--- Safety First! */

    this->Populate_IP_List();
}

void Dialog_Detailed_MAC_Info::OnListBox_ItemSelected_IP( wxCommandEvent& event )
{
    m_list_ports->Clear();  /* Wipe out all the ports */

    if (m_list_ips->GetSelection() == wxNOT_FOUND)
    {
        /* This can happen when the list box
           is cleared */

        return;
    }

    CriticalSectionLocker_MAC_Database locker;  /* <--- Safety First! */

    IP_Data const *const p_ip_data = p_mac_data->ip_data_array + (m_list_ips->GetSelection());

    for (Port_Data const *p = p_ip_data->port_data_array; p->num; ++p)
    {
        wxString str;

        str << p->num;

        m_list_ports->Append(str);
    }
}

void Dialog_Detailed_MAC_Info::OnButtonClick_Close( wxCommandEvent& event )
{
    this->Destroy();
}
Can anybody see a problem?

The first thing I'm going to try is using InsertItems instead of Append. I'll let you know how I get on.

Virchanza
Experienced Solver
Experienced Solver
Posts: 78
Joined: Sun Jul 19, 2009 6:12 am

Post by Virchanza » Wed Sep 15, 2010 12:26 pm

I did two things:

1) I commented out the code for the function OnListBox_ItemSelected_IP, so that's not what's causing the crash.

2) I replaced all calls to ->Append with calls to ->InsertItems, but it had no effect, the program still crashes when I close the child dialog box.

Any ideas, anyone?

Virchanza
Experienced Solver
Experienced Solver
Posts: 78
Joined: Sun Jul 19, 2009 6:12 am

Post by Virchanza » Wed Sep 15, 2010 12:48 pm

I found a way to prevent the crash.

I changed the destructor from:

Code: Select all

void Dialog_Detailed_MAC_Info::OnButtonClick_Close( wxCommandEvent& event )
{
    this->Destroy();
}
to:

Code: Select all

void Dialog_Detailed_MAC_Info::OnButtonClick_Close( wxCommandEvent& event )
{
    m_list_ips->Clear();    /* These calls are needed to avoid a crash  */
    m_list_ports->Clear();  /* in the destructor for wxListBox. */

    this->Destroy();
}
...and now it doesn't crash anymore.

DavidHart
Site Admin
Site Admin
Posts: 4006
Joined: Thu Jan 12, 2006 6:23 pm
Location: IoW, UK

Post by DavidHart » Wed Sep 15, 2010 12:54 pm

Hi,

Try changing MakeStringFromIP(p->num) to:
MakeStringFromIP(p->num).c_str()
(and similarly MakeStringFromMAC(p_mac_data->num)). This should prevent ref-counting of the wxString, which might be the underlying cause of the crash.

Regards,

David

Virchanza
Experienced Solver
Experienced Solver
Posts: 78
Joined: Sun Jul 19, 2009 6:12 am

Post by Virchanza » Thu Sep 16, 2010 3:33 am

Thanks for the reply David.

I tried what you said, and also tried stuff like:

Code: Select all

    wxString str;
    str = MakeStringFromIP(p->num);

    m_list_ips->Append(str);
but it still crashes.

I need to Clear() the list boxes before I destroy the dialog box, otherwise the program crashes.

Any thoughts?

eranif
Moderator
Moderator
Posts: 607
Joined: Tue Nov 29, 2005 7:10 pm
Location: Israel

Post by eranif » Thu Sep 16, 2010 5:48 am

Why do you need lockers? is this a multi threaded application involved?

If so, like David mentioned, you should use wxString().c_str() when passing wxString object between threads.

to disable the ref counting and force wxWidgets to create a new instance of wxString. Since wxString is not thread safe and the destructor may be called twice.

The content of 'MakeStringFromIP' could be very interesting, can you paste it as well?
IDE: CodeLite + wxCrafter
OS: All
https://wxcrafter.codelite.org
https://codelite.org

Virchanza
Experienced Solver
Experienced Solver
Posts: 78
Joined: Sun Jul 19, 2009 6:12 am

Post by Virchanza » Fri Sep 17, 2010 1:24 am

eranif wrote:Why do you need lockers? is this a multi threaded application involved?
Yes it's a multi-threaded program.

It's a program that does Ethernet networking. At any time, it can have between 1 to 3 threads running (1 thread for the GUI, 1 thread for reading frames in from the network, 1 thread for sending frames out on the network).

The content of 'MakeStringFromIP' could be very interesting, can you paste it as well?
It's nothing to do with MakeStringFromIP. I edited my code to:

Code: Select all

->Append(wxT("Hello"));
and it still crashes.

At some stage today I will post minimalistic code that demonstrates the problem.

Post Reply