Segfault when re-parenting menu items

Back in the day, menu items had to be instantiated with a real menu or bad things happened. I think it was around 2.8, where they were permitted to be instantiated with None as the parent. I have a context menu for a Grid that I’m building dynamically based on where the click originated (row label, column label, which cell, etc). I had created all of the various menu items that could possible be displayed and then was adding them like (slimmed down example):

      menu = wx.Menu()

self._deleteRowItem.SetMenu(menu)
self._insertRowItem.SetMenu(menu)

menu.AppendItem(self._deleteRowItem)
menu.AppendItem(self._insertRowItem)

self.PopupMenu(menu)

for item in menu.GetMenuItems():
menu.RemoveItem(item)
print “*”, item

#These prints match exactly what’s printed in the loop
print “+”, self._deleteRowItem
print “+”, self._insertRowItem

#If I remove the loop and remove the items explicitly, this works
#menu.RemoveItem(self._deleteRowItem)
#menu.RemoveItem(self._insertRowItem)

menu.Destroy()

So the weird thing is that if I remove the items from the menu using the loop, I get a segfault the next time I try to invoke the context menu. If I remove them explicitly, there are no issues whatsoever. The backtrace varies slightly. Below are a couple of examples. I’m going to change my code to just create the menu items dynamically as well, but I am curious why my current approach is behaving this way.

#0 0x000000333ed8efc8 in main_arena () from /lib64/libc.so.6
#1 0x00007f0d5ae1cfa3 in wxMenu::GtkAppend(wxMenuItem*, int) () from /disk01/lib/libwx_gtk2u_core-2.9.so.4
#2 0x00007f0d5ae1d37e in wxMenu::DoAppend(wxMenuItem*) () from /disk01/lib/libwx_gtk2u_core-2.9.so.4
#3 0x00007f0d5bdd876d in Append (item=, this=0x1cb63f0) at /disk01/include/wx-2.9/wx/menu.h:100
#4 _wrap_Menu_AppendItem (args=, kwargs=) at src/gtk/_core_wrap.cpp:48403
#5 0x00007f0d6242fc0e in ext_do_call (nk=29878464, na=, flags=, pp_stack=0x7ffff88aa2b8, func=0xa6fdd0) at Python/ceval.c:4331
#6 PyEval_EvalFrameEx (f=, throwflag=) at Python/ceval.c:2705
#7 0x00007f0d6243170e in PyEval_EvalCodeEx (co=0x9ac030, globals=, locals=, args=, argcount=2, kws=0x1cb5e38, kwcount=0, defs=0x0, defcount=0, closure=0x0)
at Python/ceval.c:3253
#8 0x00007f0d6242fb40 in fast_function (nk=, na=2, n=, pp_stack=0x7ffff88aa4b8, func=0xb971b8) at Python/ceval.c:4117
#9 call_function (oparg=, pp_stack=0x7ffff88aa4b8) at Python/ceval.c:4042
#10 PyEval_EvalFrameEx (f=, throwflag=) at Python/ceval.c:2666
#11 0x00007f0d6243170e in PyEval_EvalCodeEx (co=0x7f0d6222bf30, globals=, locals=, args=, argcount=2, kws=0x0, kwcount=0, defs=0x0, defcount=0, closure=0x0)
at Python/ceval.c:3253
#12 0x00007f0d623b0181 in function_call (func=0x19af050, arg=0x1c7e560, kw=0x0) at Objects/funcobject.c:526
#13 0x00007f0d62381103 in PyObject_Call (func=0x19af050, arg=, kw=) at Objects/abstract.c:2529
#14 0x00007f0d6239379f in instancemethod_call (func=0x19af050, arg=0x1c7e560, kw=0x0) at Objects/classobject.c:2578
#15 0x00007f0d62381103 in PyObject_Call (func=0x1a39640, arg=, kw=) at Objects/abstract.c:2529
#16 0x00007f0d624294b3 in PyEval_CallObjectWithKeywords (func=0x1a39640, arg=0x1c81210, kw=) at Python/ceval.c:3890
#17 0x00007f0d5bd1ce0e in wxPyCallback::EventThunker (this=, event=…) at src/helpers.cpp:1788
#18 0x00007f0d5a45a89c in wxEvtHandler::ProcessEventIfMatchesId(wxEventTableEntryBase const&, wxEvtHandler*, wxEvent&) () from /disk01/lib/libwx_baseu-2.9.so.4
#19 0x00007f0d5a45b1b6 in wxEvtHandler::SearchDynamicEventTable(wxEvent&) () from /disk01/lib/libwx_baseu-2.9.so.4
#20 0x00007f0d5a45bbd8 in wxEvtHandler::TryHereOnly(wxEvent&) () from /disk01/lib/libwx_baseu-2.9.so.4
#21 0x00007f0d5a45bf83 in wxEvtHandler::ProcessEventLocally(wxEvent&) () from /disk01/lib/libwx_baseu-2.9.so.4
#22 0x00007f0d5a45bfe5 in wxEvtHandler::ProcessEvent(wxEvent&) () from /disk01/lib/libwx_baseu-2.9.so.4
#23 0x00007f0d5af9550f in wxScrollHelperEvtHandler::ProcessEvent(wxEvent&) () from /disk01/lib/libwx_gtk2u_core-2.9.so.4
#24 0x00007f0d5b42b0bc in wxGrid::SendEvent(int, int, int, wxMouseEvent const&) () from /disk01/lib/libwx_gtk2u_adv-2.9.so.4
#25 0x00007f0d5b42d011 in wxGrid::ProcessGridCellMouseEvent(wxMouseEvent&) () from /disk01/lib/libwx_gtk2u_adv-2.9.so.4
#26 0x00007f0d5a45a89c in wxEvtHandler::ProcessEventIfMatchesId(wxEventTableEntryBase const&, wxEvtHandler*, wxEvent&) () from /disk01/lib/libwx_baseu-2.9.so.4
#27 0x00007f0d5a45bb4b in wxEventHashTable::HandleEvent(wxEvent&, wxEvtHandler*) () from /disk01/lib/libwx_baseu-2.9.so.4
#28 0x00007f0d5a45bf83 in wxEvtHandler::ProcessEventLocally(wxEvent&) () from /disk01/lib/libwx_baseu-2.9.so.4
#29 0x00007f0d5a45bfe5 in wxEvtHandler::ProcessEvent(wxEvent&) () from /disk01/lib/libwx_baseu-2.9.so.4
#30 0x00007f0d5a45b3db in wxEvtHandler::SafelyProcessEvent(wxEvent&) () from /disk01/lib/libwx_baseu-2.9.so.4
#31 0x00007f0d5adc097b in gtk_window_button_press_callback () from /disk01/lib/libwx_gtk2u_core-2.9.so.4
#32 0x000000386a353f33 in ?? () from /usr/lib64/libgtk-x11-2.0.so.0
#33 0x0000003340e0bb3e in g_closure_invoke () from /lib64/libgobject-2.0.so.0
#34 0x0000003340e20e23 in ?? () from /lib64/libgobject-2.0.so.0
#35 0x0000003340e21f4a in g_signal_emit_valist () from /lib64/libgobject-2.0.so.0
#36 0x0000003340e225f3 in g_signal_emit () from /lib64/libgobject-2.0.so.0
#37 0x000000386a476a9f in ?? () from /usr/lib64/libgtk-x11-2.0.so.0
#38 0x000000386a34acaa in gtk_propagate_event () from /usr/lib64/libgtk-x11-2.0.so.0
#39 0x000000386a34be1c in gtk_main_do_event () from /usr/lib64/libgtk-x11-2.0.so.0
#40 0x000000386965ffdc in ?? () from /usr/lib64/libgdk-x11-2.0.so.0
#41 0x0000003340238f0e in g_main_context_dispatch () from /lib64/libglib-2.0.so.0
#42 0x000000334023c938 in ?? () from /lib64/libglib-2.0.so.0
#43 0x000000334023cd55 in g_main_loop_run () from /lib64/libglib-2.0.so.0
#44 0x000000386a34c307 in gtk_main () from /usr/lib64/libgtk-x11-2.0.so.0
#45 0x00007f0d5ada199a in wxGUIEventLoop::Run() () from /disk01/lib/libwx_gtk2u_core-2.9.so.4
#46 0x00007f0d5a33ab33 in wxAppConsoleBase::MainLoop() () from /disk01/lib/libwx_baseu-2.9.so.4
#47 0x00007f0d5bd190b7 in wxPyApp::MainLoop (this=0x1c50380) at src/helpers.cpp:215
#48 0x00007f0d5bda4358 in _wrap_PyApp_MainLoop (args=) at src/gtk/_core_wrap.cpp:34291

#0 0x000000333ed8efc8 in main_arena () from /lib64/libc.so.6
#1 0x00007f76484a1fa3 in wxMenu::GtkAppend(wxMenuItem*, int) () from /disk01/lib/libwx_gtk2u_core-2.9.so.4
#2 0x00007f76484a237e in wxMenu::DoAppend(wxMenuItem*) () from /disk01/lib/libwx_gtk2u_core-2.9.so.4
#3 0x00007f764945d76d in Append (item=, this=0x1fedc80) at /disk01/include/wx-2.9/wx/menu.h:100
#4 _wrap_Menu_AppendItem (args=, kwargs=) at src/gtk/_core_wrap.cpp:48403
#5 0x00007f764f971c0e in ext_do_call (nk=31919424, na=, flags=, pp_stack=0x7fff524b8e68, func=0xc93fc8) at Python/ceval.c:4331
#6 PyEval_EvalFrameEx (f=, throwflag=) at Python/ceval.c:2705
#7 0x00007f764f97370e in PyEval_EvalCodeEx (co=0xb62a30, globals=, locals=, args=, argcount=2, kws=0x1fed6c8, kwcount=0, defs=0x0, defcount=0, closure=0x0)
at Python/ceval.c:3253
#8 0x00007f764f971b40 in fast_function (nk=, na=2, n=, pp_stack=0x7fff524b9068, func=0xd7cc08) at Python/ceval.c:4117
#9 call_function (oparg=, pp_stack=0x7fff524b9068) at Python/ceval.c:4042
#10 PyEval_EvalFrameEx (f=, throwflag=) at Python/ceval.c:2666
#11 0x00007f764f97370e in PyEval_EvalCodeEx (co=0x7f764f777a30, globals=, locals=, args=, argcount=2, kws=0x0, kwcount=0, defs=0x0, defcount=0, closure=0x0)
at Python/ceval.c:3253
#12 0x00007f764f8f2181 in function_call (func=0x1bc29b0, arg=0x1e709e0, kw=0x0) at Objects/funcobject.c:526
#13 0x00007f764f8c3103 in PyObject_Call (func=0x1bc29b0, arg=, kw=) at Objects/abstract.c:2529
#14 0x00007f764f8d579f in instancemethod_call (func=0x1bc29b0, arg=0x1e709e0, kw=0x0) at Objects/classobject.c:2578
#15 0x00007f764f8c3103 in PyObject_Call (func=0x1c3a870, arg=, kw=) at Objects/abstract.c:2529
#16 0x00007f764f96b4b3 in PyEval_CallObjectWithKeywords (func=0x1c3a870, arg=0x1e7a090, kw=) at Python/ceval.c:3890
#17 0x00007f76493a1e0e in wxPyCallback::EventThunker (this=, event=…) at src/helpers.cpp:1788
#18 0x00007f7647adf89c in wxEvtHandler::ProcessEventIfMatchesId(wxEventTableEntryBase const&, wxEvtHandler*, wxEvent&) () from /disk01/lib/libwx_baseu-2.9.so.4
#19 0x00007f7647ae01b6 in wxEvtHandler::SearchDynamicEventTable(wxEvent&) () from /disk01/lib/libwx_baseu-2.9.so.4
#20 0x00007f7647ae0bd8 in wxEvtHandler::TryHereOnly(wxEvent&) () from /disk01/lib/libwx_baseu-2.9.so.4
#21 0x00007f7647ae0f83 in wxEvtHandler::ProcessEventLocally(wxEvent&) () from /disk01/lib/libwx_baseu-2.9.so.4
#22 0x00007f7647ae0fe5 in wxEvtHandler::ProcessEvent(wxEvent&) () from /disk01/lib/libwx_baseu-2.9.so.4
#23 0x00007f764861a50f in wxScrollHelperEvtHandler::ProcessEvent(wxEvent&) () from /disk01/lib/libwx_gtk2u_core-2.9.so.4
#24 0x00007f7648ab00bc in wxGrid::SendEvent(int, int, int, wxMouseEvent const&) () from /disk01/lib/libwx_gtk2u_adv-2.9.so.4
#25 0x00007f7648ab2011 in wxGrid::ProcessGridCellMouseEvent(wxMouseEvent&) () from /disk01/lib/libwx_gtk2u_adv-2.9.so.4
#26 0x00007f7647adf89c in wxEvtHandler::ProcessEventIfMatchesId(wxEventTableEntryBase const&, wxEvtHandler*, wxEvent&) () from /disk01/lib/libwx_baseu-2.9.so.4
#27 0x00007f7647ae0b4b in wxEventHashTable::HandleEvent(wxEvent&, wxEvtHandler*) () from /disk01/lib/libwx_baseu-2.9.so.4
#28 0x00007f7647ae0f83 in wxEvtHandler::ProcessEventLocally(wxEvent&) () from /disk01/lib/libwx_baseu-2.9.so.4
#29 0x00007f7647ae0fe5 in wxEvtHandler::ProcessEvent(wxEvent&) () from /disk01/lib/libwx_baseu-2.9.so.4
#30 0x00007f7647ae03db in wxEvtHandler::SafelyProcessEvent(wxEvent&) () from /disk01/lib/libwx_baseu-2.9.so.4
#31 0x00007f764844597b in gtk_window_button_press_callback () from /disk01/lib/libwx_gtk2u_core-2.9.so.4
#32 0x000000386a353f33 in ?? () from /usr/lib64/libgtk-x11-2.0.so.0
#33 0x0000003340e0bb3e in g_closure_invoke () from /lib64/libgobject-2.0.so.0
#34 0x0000003340e20e23 in ?? () from /lib64/libgobject-2.0.so.0
#35 0x0000003340e21f4a in g_signal_emit_valist () from /lib64/libgobject-2.0.so.0
#36 0x0000003340e225f3 in g_signal_emit () from /lib64/libgobject-2.0.so.0
#37 0x000000386a476a9f in ?? () from /usr/lib64/libgtk-x11-2.0.so.0
#38 0x000000386a34acaa in gtk_propagate_event () from /usr/lib64/libgtk-x11-2.0.so.0
#39 0x000000386a34be1c in gtk_main_do_event () from /usr/lib64/libgtk-x11-2.0.so.0
#40 0x000000386965ffdc in ?? () from /usr/lib64/libgdk-x11-2.0.so.0
#41 0x0000003340238f0e in g_main_context_dispatch () from /lib64/libglib-2.0.so.0
#42 0x000000334023c938 in ?? () from /lib64/libglib-2.0.so.0
#43 0x000000334023cd55 in g_main_loop_run () from /lib64/libglib-2.0.so.0
#44 0x000000386a34c307 in gtk_main () from /usr/lib64/libgtk-x11-2.0.so.0
#45 0x00007f764842699a in wxGUIEventLoop::Run() () from /disk01/lib/libwx_gtk2u_core-2.9.so.4
#46 0x00007f76479bfb33 in wxAppConsoleBase::MainLoop() () from /disk01/lib/libwx_baseu-2.9.so.4
#47 0x00007f764939e0b7 in wxPyApp::MainLoop (this=0x1eac3c0) at src/helpers.cpp:215
#48 0x00007f7649429358 in _wrap_PyApp_MainLoop (args=) at src/gtk/_core_wrap.cpp:34291
—Type to continue, or q to quit—
#49 0x00007f764f971c0e in ext_do_call (nk=31923728, na=, flags=, pp_stack=0x7fff524ba228, func=0xc8cb00) at Python/ceval.c:4331
#50 PyEval_EvalFrameEx (f=, throwflag=) at Python/ceval.c:2705
#51 0x00007f764f97370e in PyEval_EvalCodeEx (co=0xaeb030, globals=, locals=, args=, argcount=1, kws=0x0, kwcount=0, defs=0x0, defcount=0, closure=0x0)
at Python/ceval.c:3253
#52 0x00007f764f8f2181 in function_call (func=0xd68050, arg=0x1bbf790, kw=0x0) at Objects/funcobject.c:526
#53 0x00007f764f8c3103 in PyObject_Call (func=0xd68050, arg=, kw=) at Objects/abstract.c:2529
#54 0x00007f764f8d579f in instancemethod_call (func=0xd68050, arg=0x1bbf790, kw=0x0) at Objects/classobject.c:2578
#55 0x00007f764f8c3103 in PyObject_Call (func=0x1afd410, arg=, kw=) at Objects/abstract.c:2529
#56 0x00007f764f971282 in do_call (nk=, na=, pp_stack=0x7fff524ba798, func=0x1afd410) at Python/ceval.c:4239
#57 call_function (oparg=, pp_stack=0x7fff524ba798) at Python/ceval.c:4044
#58 PyEval_EvalFrameEx (f=, throwflag=) at Python/ceval.c:2666
#59 0x00007f764f972d15 in fast_function (nk=, na=, n=, pp_stack=0x7fff524ba8e8, func=0xd6a410) at Python/ceval.c:4107
#60 call_function (oparg=, pp_stack=0x7fff524ba8e8) at Python/ceval.c:4042
#61 PyEval_EvalFrameEx (f=, throwflag=) at Python/ceval.c:2666
#62 0x00007f764f97370e in PyEval_EvalCodeEx (co=0x7f764f77a730, globals=, locals=, args=, argcount=0, kws=0x0, kwcount=0, defs=0x0, defcount=0, closure=0x0)
at Python/ceval.c:3253
#63 0x00007f764f973822 in PyEval_EvalCode (co=, globals=, locals=) at Python/ceval.c:667
#64 0x00007f764f9935b0 in run_mod (arena=0x9fa690, flags=0x7fff524babf0, locals=0x997160, globals=0x997160, filename=, mod=0xa5aec8) at Python/pythonrun.c:1353
#65 PyRun_FileExFlags (fp=0xa1e740, filename=, start=, globals=0x997160, locals=0x997160, closeit=1, flags=0x7fff524babf0) at Python/pythonrun.c:1339
#66 0x00007f764f99377c in PyRun_SimpleFileExFlags (fp=0xa1e740, filename=0x7fff524bb6b3 “table.py”, closeit=1, flags=0x7fff524babf0) at Python/pythonrun.c:943
#67 0x00007f764f9a7a7e in Py_Main (argc=, argv=) at Modules/main.c:639
#68 0x000000333ea1ecdd in __libc_start_main () from /lib64/libc.so.6
#69 0x0000000000400649 in _start ()

Mears wrote:

Back in the day, menu items had to be instantiated with a real menu or
bad things happened. I think it was around 2.8, where they were
permitted to be instantiated with None as the parent. I have a context
menu for a Grid that I'm building dynamically based on where the click
originated (row label, column label, which cell, etc). I had created all
of the various menu items that could possible be displayed and then was
adding them like (slimmed down example):

menu = wx.Menu()
self._deleteRowItem.SetMenu(menu)
self._insertRowItem.SetMenu(menu)

menu.AppendItem(self._deleteRowItem)
menu.AppendItem(self._insertRowItem)

self.PopupMenu(menu)

for item in menu.GetMenuItems():
menu.RemoveItem(item)
print "*", item

#These prints match exactly what's printed in the loop
print "+", self._deleteRowItem
print "+", self._insertRowItem

#If I remove the loop and remove the items explicitly, this works
#menu.RemoveItem(self._deleteRowItem)
#menu.RemoveItem(self._insertRowItem)

menu.Destroy()

So the weird thing is that if I remove the items from the menu using the
loop, I get a segfault the next time I try to invoke the context menu.
If I remove them explicitly, there are no issues whatsoever. The
backtrace varies slightly. Below are a couple of examples. I'm going to
change my code to just create the menu items dynamically as well, but I
am curious why my current approach is behaving this way.

There is probably an object ownership issue, causing the Python proxy object to delete the C++ object when it shouldn't be. I'll take a look and see if anything jumps out at me.

···

--
Robin Dunn
Software Craftsman