printing: Avoid accessing freed printers

Print backend can be disposed together with all its printers
as a reaction to user stopping enumeration of printers.
Adding a weak pointer help us to detect that the backend
was disposed and hence the backend and its printers should not
be used anymore.

Fixes #6265
This commit is contained in:
Marek Kasik 2024-03-13 11:42:19 +01:00
parent c4dd8d0125
commit 90950b2d3d

View File

@ -3690,6 +3690,19 @@ avahi_request_printer_list (GtkPrintBackendCups *cups_backend)
g_bus_get (G_BUS_TYPE_SYSTEM, cups_backend->avahi_cancellable, avahi_create_browsers, cups_backend);
}
/*
* Print backend can be disposed together with all its printers
* as a reaction to user stopping enumeration of printers.
*/
static void
backend_finalized_cb (gpointer data,
GObject *where_the_object_was)
{
gboolean *backend_finalized = data;
*backend_finalized = TRUE;
}
static void
cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
GtkCupsResult *result,
@ -3702,6 +3715,7 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
GList *removed_printer_checklist;
gchar *remote_default_printer = NULL;
GList *iter;
gboolean backend_finalized = FALSE;
gdk_threads_enter ();
@ -3738,6 +3752,8 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
*/
removed_printer_checklist = gtk_print_backend_get_printer_list (backend);
g_object_weak_ref (G_OBJECT (backend), backend_finalized_cb, &backend_finalized);
response = gtk_cups_result_get_response (result);
for (attr = ippFirstAttribute (response); attr != NULL;
attr = ippNextAttribute (response))
@ -3848,6 +3864,9 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
{
g_signal_emit_by_name (backend, "printer-added", printer);
if (backend_finalized)
break;
gtk_printer_set_is_new (printer, FALSE);
}
@ -3884,36 +3903,44 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
break;
}
/* look at the removed printers checklist and mark any printer
as inactive if it is in the list, emitting a printer_removed signal */
if (removed_printer_checklist != NULL)
if (!backend_finalized)
{
for (iter = removed_printer_checklist; iter; iter = iter->next)
g_object_weak_unref (G_OBJECT (backend), backend_finalized_cb, &backend_finalized);
/* look at the removed printers checklist and mark any printer
as inactive if it is in the list, emitting a printer_removed signal */
if (removed_printer_checklist != NULL)
{
if (!GTK_PRINTER_CUPS (iter->data)->avahi_browsed)
for (iter = removed_printer_checklist; iter; iter = iter->next)
{
mark_printer_inactive (GTK_PRINTER (iter->data), backend);
list_has_changed = TRUE;
if (!GTK_PRINTER_CUPS (iter->data)->avahi_browsed)
{
mark_printer_inactive (GTK_PRINTER (iter->data), backend);
list_has_changed = TRUE;
}
}
}
g_list_free (removed_printer_checklist);
}
g_list_free (removed_printer_checklist);
done:
if (list_has_changed)
g_signal_emit_by_name (backend, "printer-list-changed");
gtk_print_backend_set_list_done (backend);
if (!cups_backend->got_default_printer && remote_default_printer != NULL)
if (!backend_finalized)
{
set_default_printer (cups_backend, remote_default_printer);
g_free (remote_default_printer);
}
if (list_has_changed)
g_signal_emit_by_name (backend, "printer-list-changed");
if (!cups_backend->got_default_printer && cups_backend->avahi_default_printer != NULL)
set_default_printer (cups_backend, cups_backend->avahi_default_printer);
gtk_print_backend_set_list_done (backend);
if (!cups_backend->got_default_printer && remote_default_printer != NULL)
{
set_default_printer (cups_backend, remote_default_printer);
g_free (remote_default_printer);
}
if (!cups_backend->got_default_printer && cups_backend->avahi_default_printer != NULL)
set_default_printer (cups_backend, cups_backend->avahi_default_printer);
}
gdk_threads_leave ();
}