malcontent-control: Fix use-after-free when closing
Sometimes, when closing the application, `flush_update_blacklisted_apps()` would be called after `MctRestrictApplicationsSelector` had been destroyed, leading to a critical. This was because the `MctRestrictApplicationsDialog` was being disposed early due to its `destroy-with-parent` property being set. The dispose function of `MctUserControls` was run several times due to GTK calling `g_object_run_dispose()`, and the critical would be emitted the second time. Make the dispose function’s call to `flush_update_blacklisted_apps()` be safe for multiple dispose calls, and ensure the dialog isn’t destroyed too early. Signed-off-by: Philip Withnall <withnall@endlessm.com>
This commit is contained in:
parent
00bb439f6e
commit
695ee10235
|
@ -62,6 +62,7 @@ struct _MctUserControls
|
||||||
guint selected_age; /* @oars_disabled_age to disable OARS */
|
guint selected_age; /* @oars_disabled_age to disable OARS */
|
||||||
|
|
||||||
guint blacklist_apps_source_id;
|
guint blacklist_apps_source_id;
|
||||||
|
gboolean flushed_on_dispose;
|
||||||
};
|
};
|
||||||
|
|
||||||
static gboolean blacklist_apps_cb (gpointer data);
|
static gboolean blacklist_apps_cb (gpointer data);
|
||||||
|
@ -650,6 +651,9 @@ mct_user_controls_finalize (GObject *object)
|
||||||
g_clear_pointer (&self->filter, mct_app_filter_unref);
|
g_clear_pointer (&self->filter, mct_app_filter_unref);
|
||||||
g_clear_object (&self->manager);
|
g_clear_object (&self->manager);
|
||||||
|
|
||||||
|
/* Hopefully we don’t have data loss. */
|
||||||
|
g_assert (self->flushed_on_dispose);
|
||||||
|
|
||||||
G_OBJECT_CLASS (mct_user_controls_parent_class)->finalize (object);
|
G_OBJECT_CLASS (mct_user_controls_parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -659,7 +663,13 @@ mct_user_controls_dispose (GObject *object)
|
||||||
{
|
{
|
||||||
MctUserControls *self = (MctUserControls *)object;
|
MctUserControls *self = (MctUserControls *)object;
|
||||||
|
|
||||||
flush_update_blacklisted_apps (self);
|
/* Since GTK calls g_object_run_dispose(), dispose() may be called multiple
|
||||||
|
* times. We definitely want to save any unsaved changes, but don’t need to
|
||||||
|
* do it multiple times, and after the first g_object_run_dispose() call,
|
||||||
|
* none of our child widgets are still around to extract data from anyway. */
|
||||||
|
if (!self->flushed_on_dispose)
|
||||||
|
flush_update_blacklisted_apps (self);
|
||||||
|
self->flushed_on_dispose = TRUE;
|
||||||
|
|
||||||
G_OBJECT_CLASS (mct_user_controls_parent_class)->dispose (object);
|
G_OBJECT_CLASS (mct_user_controls_parent_class)->dispose (object);
|
||||||
}
|
}
|
||||||
|
|
|
@ -527,7 +527,7 @@
|
||||||
<object class="MctRestrictApplicationsDialog" id="restrict_applications_dialog">
|
<object class="MctRestrictApplicationsDialog" id="restrict_applications_dialog">
|
||||||
<property name="visible">False</property>
|
<property name="visible">False</property>
|
||||||
<property name="modal">True</property>
|
<property name="modal">True</property>
|
||||||
<property name="destroy-with-parent">True</property>
|
<property name="destroy-with-parent">False</property>
|
||||||
<property name="use-header-bar">1</property>
|
<property name="use-header-bar">1</property>
|
||||||
<signal name="delete-event" handler="on_restrict_applications_dialog_delete_event_cb" />
|
<signal name="delete-event" handler="on_restrict_applications_dialog_delete_event_cb" />
|
||||||
<signal name="response" handler="on_restrict_applications_dialog_response_cb" />
|
<signal name="response" handler="on_restrict_applications_dialog_response_cb" />
|
||||||
|
|
Loading…
Reference in New Issue