mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-07-31 22:23:39 +02:00
The pattern here is that we acquire strong references via GWeakRef. So you might think that g_object_weak_unref() is safe to call. However, it is not safe, in case where another thread might run g_object_run_dispose(). Which is clear, because GWeakRef only ensures we hold a strong reference, but g_object_run_dispose() is anyway run on an object where we already hold a reference. In weak_unbind(), we obtain strong references, but (after) that point, another thead might call g_object_run_dispose(). Then, inside unbind_internal_locked() we do: g_object_weak_unref (source, weak_unbind, context); binding_context_unref (context); Note that here weak_unbind might have already be unrefed, and g_object_weak_unref() fails an assertion. But worse, the weak_unbind callback will also be called and we issue two binding_context_unref() and crash. This is fixed by using g_object_weak_ref_full() (which handles the case that the weak notification might have already be emitted) and a separate GDestroyNotify (that is guaranteed to run exactly once). This still doesn't make it fully work. Note that we also call g_signal_handler_disconnect (source, binding->source_notify); this has exactly the same problem. A concurrent g_object_run_dispose() will already disconnect all signal handlers, and calling disconnect fails an assertion. I think the solution for that is a new API g_signal_handler_try_disconnect(), which does not assert. After all, the gulong signal ID is unique (the gulong is large enough to never wrap and there is even a g_error() check against that).