GNOME Bugzilla – Bug 315874
Container::signal_remove handler not called sometimes.
Last modified: 2013-02-27 16:11:07 UTC
Compile and run the attached test case. (It is a modified child_widget2 testcase). This bug emerged in testing view::VisibilityBox which attaches add/remove handlers to all containers inside it (to a first approximation). If a child of one of those containers is deleted before it is removed, then gtk+ emits the "remove" signal as usual but the c++ handler is still attached because trackable's destructor hasn't been reached yet. However, the child's wrapper reports itself as deleted so the signal proxy tries to recreate it but this is refused because the gtk+ object is being destroyed, causing a warning to be shown and the signal not to be emitted. In contrast, a C handler will be notified as normal. So, it would seem that the wrapper must be changed to consider itself existing until gtk_widget_dispose returns at the very least; it's perfectly valid to listen for the remove signal and to be notified at delete time. I'm not sure what the implications of this lifetime extension would be. I've filed the bug under glibmm because I consider this a bug in the base wrapping code rather than in how gtkcontainer is specifically wrapped.
Created attachment 52040 [details] Test case
Sorry for the lack of response. I hope I have time to investigate in January.
Confirmed. When closing the window, I get: (a.out:29961): glibmm-WARNING **: Glib::create_new_wrapper: Attempted to create a 2nd C++ wrapper for a C instance whose C++ wrapper has been deleted. (a.out:29961): glibmm-WARNING **: failed to wrap type of 'gtkmm__GtkVBox' Child removed
The backtrace with --g-fatal-warnings:
+ Trace 64393
Here's one of my (usually wrong) ideas: Maybe Container_signal_remove_callback() (the C callbacks that call the connected handler slots when a signal is emitted) should do the same clever things that Container_Class::remove_callback_custom() (The default signal handler) does. I guess that the signal handlers are called before the default signal handler, and this cleverness should happen as soon as possible. This could stop the warning, at least, though I don't think the handler would be called.
And I guess that you connected to the signal because you noticed that an on_remove() override was being not called. > it's perfectly valid to listen for the remove signal and to be notified at delete time If possible, I'd like to make that work, though preventing crashes would be a priority if I have to choose.
Created attachment 56204 [details] [review] remove.patch This patch should fix the warning. I haven't committed it yet because the test case is currently segfaulting on close even without the patch. Investigating.
Using vmware (woot!), I used Ubuntu Breezy to check that this extra crash was just a problem with glib/GTK+ HEAD. I have applied this patch to both branches, which fixes the warning/crash. But the problem remains that the "remove" signal handler won't be called sometimes, as shown by the test case.
Thanks for looking in to this Murray. The reason why we didn't try using an on_remove override is that the specific widget in question (the ContentBox) recursively listens for remove events on all containers under it in the hierarchy - obviously, we can't override methods on those objects; so as you observe, we still have a problem (at least we have a workaround in using the underlying gsignal).
I think this bug is closely related to gtkmm bug 605728. When I apply the patch in bug 605728, comment 2, MyWindow::OnChildRemoved() is called when the window is closed. The following backtrace shows how OnChildRemoved() is called.
+ Trace 231286
When the patch has been applied, Gtk::Object::_release_c_instance() calls disconnect_cpp_wrapper() _after_ it calls g_object_run_dispose(). Container_signal_remove_callback() finds that gtkmm_child_already_deleted is false. It calls Container_signal_remove_callback_normal() which calls OnChildRemoved(). This backtrace is slightly different from the one in bug 605728, comment 1. That backtrace shows the call of an overridden default signal handler. This kind of call of a 'remove' signal handler is not always safe. MyWindow::OnChildRemoved() is called while MyWindow and MyWindow::vbox is being deleted. If MyWindow had contained member data declared after vbox, and OnChildRemoved() had accessed that data, then it had accessed deleted data. I have not yet pushed the patch in bug 605728, comment 2. I hope that someone with very good knowledge of gtkmm will have time to comment on it. I have not found any problem with it, apart from the just mentioned risk with some 'remove' signal handlers, a risk which I would say is acceptable.
I've now pushed the patch in bug 605728. It also fixes this bug. I've also moved this bug from glibmm to gtkmm. It only affects the removal of Gtk::Widgets, and the fix is a modification in gtkmm.