a11y: Plug reference leaks
authorEmmanuele Bassi <ebassi@gnome.org>
Fri, 3 Mar 2023 19:07:16 +0000 (19:07 +0000)
committerEmmanuele Bassi <ebassi@gnome.org>
Fri, 3 Mar 2023 22:07:09 +0000 (22:07 +0000)
The gtk_accessible_get_at_context() getter is now transfer full, which
means we need to drop the reference when getting the GtkATContext.

gtk/gtkaccessible.c
gtk/gtkatcontext.c
gtk/gtkmodelbutton.c
gtk/gtktestatcontext.c
gtk/gtkwidget.c
gtk/inspector/a11y.c
testsuite/a11y/accessible.c

index 3d3839cb6865767b85fb4a3c0a5121c914a389b2..873094a4745f5a5066f5aaa0ff38036c8fa21e21 100644 (file)
@@ -127,7 +127,10 @@ gtk_accessible_get_accessible_parent (GtkAccessible *self)
 
   context = gtk_accessible_get_at_context (self);
   if (context != NULL)
-    parent = gtk_at_context_get_accessible_parent (context);
+    {
+      parent = gtk_at_context_get_accessible_parent (context);
+      g_object_unref (context);
+    }
 
   if (parent != NULL)
     return g_object_ref (parent);
@@ -161,6 +164,7 @@ gtk_accessible_set_accessible_parent (GtkAccessible *self,
   g_return_if_fail (GTK_IS_ACCESSIBLE (self));
   g_return_if_fail (parent == NULL || GTK_IS_ACCESSIBLE (parent));
   g_return_if_fail (next_sibling == NULL || GTK_IS_ACCESSIBLE (parent));
+
   GtkATContext *context;
 
   context = gtk_accessible_get_at_context (self);
@@ -168,6 +172,7 @@ gtk_accessible_set_accessible_parent (GtkAccessible *self,
     {
       gtk_at_context_set_accessible_parent (context, parent);
       gtk_at_context_set_next_accessible_sibling (context, next_sibling);
+      g_object_unref (context);
     }
 }
 
@@ -188,20 +193,26 @@ gtk_accessible_update_next_accessible_sibling (GtkAccessible *self,
                                                GtkAccessible *new_sibling)
 {
   GtkATContext *context;
+  GtkAccessible *parent;
 
   g_return_if_fail (GTK_IS_ACCESSIBLE (self));
 
   context = gtk_accessible_get_at_context (self);
-  if (!context)
+  if (context == NULL)
     return;
 
-  if (gtk_at_context_get_accessible_parent (context) == NULL)
-  {
-    g_critical ("Failed to update next accessible sibling: no parent accessible set for this accessible");
-    return;
-  }
+  parent = gtk_at_context_get_accessible_parent (context);
+  if (parent == NULL)
+    {
+      g_object_unref (context);
+      g_critical ("Failed to update next accessible sibling: no parent accessible set for this accessible");
+      return;
+    }
 
   gtk_at_context_set_next_accessible_sibling (context, new_sibling);
+
+  g_object_unref (parent);
+  g_object_unref (context);
 }
 
 /**
@@ -240,14 +251,20 @@ gtk_accessible_get_next_accessible_sibling (GtkAccessible *self)
   GtkATContext *context;
 
   context = gtk_accessible_get_at_context (self);
-  if (context != NULL && gtk_at_context_get_accessible_parent (context) != NULL)
+  if (context != NULL)
     {
-      GtkAccessible *sibling = gtk_at_context_get_next_accessible_sibling (context);
+      GtkAccessible *sibling = NULL;
+
+      if (gtk_at_context_get_accessible_parent (context) != NULL)
+        {
+          sibling = gtk_at_context_get_next_accessible_sibling (context);
+          if (sibling != NULL)
+            sibling = g_object_ref (sibling);
+        }
 
-      if (sibling != NULL)
-        return g_object_ref (sibling);
+      g_object_unref (context);
 
-      return NULL;
+      return sibling;
     }
   else
     return GTK_ACCESSIBLE_GET_IFACE (self)->get_next_accessible_sibling (self);
@@ -264,13 +281,21 @@ gtk_accessible_get_next_accessible_sibling (GtkAccessible *self)
 GtkAccessibleRole
 gtk_accessible_get_accessible_role (GtkAccessible *self)
 {
-  GtkAccessibleRole role;
+  GtkAccessibleRole role = GTK_ACCESSIBLE_ROLE_NONE;
 
   g_return_val_if_fail (GTK_IS_ACCESSIBLE (self), GTK_ACCESSIBLE_ROLE_NONE);
 
   GtkATContext *context = gtk_accessible_get_at_context (self);
-  if (context != NULL && gtk_at_context_is_realized (context))
-    return gtk_at_context_get_accessible_role (context);
+  if (context != NULL)
+    {
+      if (gtk_at_context_is_realized (context))
+        role = gtk_at_context_get_accessible_role (context);
+
+      g_object_unref (context);
+
+      if (role != GTK_ACCESSIBLE_ROLE_NONE)
+        return role;
+    }
 
   g_object_get (G_OBJECT (self), "accessible-role", &role, NULL);
 
@@ -344,6 +369,8 @@ gtk_accessible_update_state (GtkAccessible      *self,
 
 out:
   va_end (args);
+
+  g_object_unref (context);
 }
 
 /**
@@ -397,6 +424,7 @@ gtk_accessible_update_state_value (GtkAccessible      *self,
     }
 
   gtk_at_context_update (context);
+  g_object_unref (context);
 }
 
 /**
@@ -420,6 +448,7 @@ gtk_accessible_reset_state (GtkAccessible      *self,
 
   gtk_at_context_set_accessible_state (context, state, NULL);
   gtk_at_context_update (context);
+  g_object_unref (context);
 }
 
 /**
@@ -491,6 +520,8 @@ gtk_accessible_update_property (GtkAccessible         *self,
 
 out:
   va_end (args);
+
+  g_object_unref (context);
 }
 
 /**
@@ -544,6 +575,7 @@ gtk_accessible_update_property_value (GtkAccessible         *self,
     }
 
   gtk_at_context_update (context);
+  g_object_unref (context);
 }
 
 /**
@@ -567,6 +599,7 @@ gtk_accessible_reset_property (GtkAccessible         *self,
 
   gtk_at_context_set_accessible_property (context, property, NULL);
   gtk_at_context_update (context);
+  g_object_unref (context);
 }
 
 /**
@@ -638,6 +671,8 @@ gtk_accessible_update_relation (GtkAccessible         *self,
 
 out:
   va_end (args);
+
+  g_object_unref (context);
 }
 
 /**
@@ -666,6 +701,8 @@ gtk_accessible_update_relation_value (GtkAccessible         *self,
   g_return_if_fail (n_relations > 0);
 
   context = gtk_accessible_get_at_context (self);
+  if (context == NULL)
+    return;
 
   for (int i = 0; i < n_relations; i++)
     {
@@ -684,15 +721,14 @@ gtk_accessible_update_relation_value (GtkAccessible         *self,
           break;
         }
 
-      if (context)
-        gtk_at_context_set_accessible_relation (context, relation, real_value);
+      gtk_at_context_set_accessible_relation (context, relation, real_value);
 
       if (real_value != NULL)
         gtk_accessible_value_unref (real_value);
     }
 
-  if (context)
-    gtk_at_context_update (context);
+  gtk_at_context_update (context);
+  g_object_unref (context);
 }
 
 /**
@@ -716,6 +752,7 @@ gtk_accessible_reset_relation (GtkAccessible         *self,
 
   gtk_at_context_set_accessible_relation (context, relation, NULL);
   gtk_at_context_update (context);
+  g_object_unref (context);
 }
 
 static const char *role_names[] = {
@@ -876,13 +913,22 @@ gtk_accessible_platform_changed (GtkAccessible               *self,
 
   /* propagate changes up from ignored widgets */
   if (gtk_accessible_get_accessible_role (self) == GTK_ACCESSIBLE_ROLE_NONE)
-    context = gtk_accessible_get_at_context (gtk_accessible_get_accessible_parent (self));
+    {
+      GtkAccessible *parent = gtk_accessible_get_accessible_parent (self);
+
+      if (parent != NULL)
+        {
+          context = gtk_accessible_get_at_context (parent);
+          g_object_unref (parent);
+        }
+    }
 
   if (context == NULL)
     return;
 
   gtk_at_context_platform_changed (context, change);
   gtk_at_context_update (context);
+  g_object_unref (context);
 }
 
 /**
@@ -936,6 +982,7 @@ gtk_accessible_bounds_changed (GtkAccessible *self)
     return;
 
   gtk_at_context_bounds_changed (context);
+  g_object_unref (context);
 }
 
 /**
@@ -988,6 +1035,7 @@ gtk_accessible_should_present (GtkAccessible *self)
 {
   GtkAccessibleRole role;
   GtkATContext *context;
+  gboolean res = TRUE;
 
   if (GTK_IS_WIDGET (self) &&
       !gtk_widget_get_visible (GTK_WIDGET (self)))
@@ -1008,10 +1056,12 @@ gtk_accessible_should_present (GtkAccessible *self)
 
       value = gtk_at_context_get_accessible_state (context, GTK_ACCESSIBLE_STATE_HIDDEN);
       if (gtk_boolean_accessible_value_get (value))
-        return FALSE;
+        res = FALSE;
     }
 
-  return TRUE;
+  g_object_unref (context);
+
+  return res;
 }
 
 void
@@ -1025,15 +1075,24 @@ gtk_accessible_update_children (GtkAccessible           *self,
       gtk_widget_get_root (GTK_WIDGET (self)) == NULL)
     return;
 
-  context = gtk_accessible_get_at_context (self);
-
   /* propagate changes up from ignored widgets */
   if (gtk_accessible_get_accessible_role (self) == GTK_ACCESSIBLE_ROLE_NONE)
-    context = gtk_accessible_get_at_context (gtk_accessible_get_accessible_parent (self));
+    {
+      GtkAccessible *parent = gtk_accessible_get_accessible_parent (self);
+
+      context = gtk_accessible_get_at_context (parent);
+
+      g_object_unref (parent);
+    }
+  else
+    {
+      context = gtk_accessible_get_at_context (self);
+    }
 
   if (context == NULL)
     return;
 
   gtk_at_context_child_changed (context, 1 << state, child);
   gtk_at_context_update (context);
+  g_object_unref (context);
 }
index e4ca7217d44411c4bea5daf34591a9a6b6c11933..e4e66e82aa86067d8ac1f89a3562bd45f93c048f 100644 (file)
@@ -996,6 +996,8 @@ gtk_at_context_get_name_accumulate (GtkATContext *self,
           GtkATContext *rel_context = gtk_accessible_get_at_context (rel);
 
           gtk_at_context_get_name_accumulate (rel_context, names, FALSE);
+
+          g_object_unref (rel_context);
         }
     }
 
@@ -1068,6 +1070,8 @@ gtk_at_context_get_description_accumulate (GtkATContext *self,
           GtkATContext *rel_context = gtk_accessible_get_at_context (rel);
 
           gtk_at_context_get_description_accumulate (rel_context, labels, FALSE);
+
+          g_object_unref (rel_context);
         }
     }
 
index a7ce33796820a410eea24a29f3d013aae7354d79..064583623abad5aef2df6c26fa0efe2fa949382e 100644 (file)
@@ -329,6 +329,8 @@ update_at_context (GtkModelButton *button)
 
   if (was_realized)
     gtk_at_context_realize (context);
+
+  g_object_unref (context);
 }
 
 static void
@@ -1199,7 +1201,7 @@ gtk_model_button_class_init (GtkModelButtonClass *class)
    * A GIcon that will be used if iconic appearance for the button is
    * desired.
    */
-  properties[PROP_ICON] = 
+  properties[PROP_ICON] =
     g_param_spec_object ("icon", NULL, NULL,
                          G_TYPE_ICON,
                          G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
index 3e30b27d10ebd2d2652e5a06886d0348af4474dd..fc8f84b191938b0731e68da6f779fd8e9f61b018 100644 (file)
@@ -172,6 +172,7 @@ gtk_test_accessible_has_property (GtkAccessible         *accessible,
                                   GtkAccessibleProperty  property)
 {
   GtkATContext *context;
+  gboolean res;
 
   g_return_val_if_fail (GTK_IS_ACCESSIBLE (accessible), FALSE);
 
@@ -179,7 +180,11 @@ gtk_test_accessible_has_property (GtkAccessible         *accessible,
   if (context == NULL)
     return FALSE;
 
-  return gtk_at_context_has_accessible_property (context, property);
+  res = gtk_at_context_has_accessible_property (context, property);
+
+  g_object_unref (context);
+
+  return res;
 }
 
 /**
@@ -230,6 +235,7 @@ gtk_test_accessible_check_property (GtkAccessible         *accessible,
 
 out:
   gtk_accessible_value_unref (check_value);
+  g_object_unref (context);
 
   return res;
 }
@@ -248,6 +254,7 @@ gtk_test_accessible_has_state (GtkAccessible      *accessible,
                                GtkAccessibleState  state)
 {
   GtkATContext *context;
+  gboolean res;
 
   g_return_val_if_fail (GTK_IS_ACCESSIBLE (accessible), FALSE);
 
@@ -255,7 +262,11 @@ gtk_test_accessible_has_state (GtkAccessible      *accessible,
   if (context == NULL)
     return FALSE;
 
-  return gtk_at_context_has_accessible_state (context, state);
+  res = gtk_at_context_has_accessible_state (context, state);
+
+  g_object_unref (context);
+
+  return res;
 }
 
 /**
@@ -306,6 +317,7 @@ gtk_test_accessible_check_state (GtkAccessible      *accessible,
 
 out:
   gtk_accessible_value_unref (check_value);
+  g_object_unref (context);
 
   return res;
 }
@@ -324,6 +336,7 @@ gtk_test_accessible_has_relation (GtkAccessible         *accessible,
                                   GtkAccessibleRelation  relation)
 {
   GtkATContext *context;
+  gboolean res;
 
   g_return_val_if_fail (GTK_IS_ACCESSIBLE (accessible), FALSE);
 
@@ -331,7 +344,11 @@ gtk_test_accessible_has_relation (GtkAccessible         *accessible,
   if (context == NULL)
     return FALSE;
 
-  return gtk_at_context_has_accessible_relation (context, relation);
+  res = gtk_at_context_has_accessible_relation (context, relation);
+
+  g_object_unref (context);
+
+  return res;
 }
 
 /**
@@ -382,6 +399,7 @@ gtk_test_accessible_check_relation (GtkAccessible         *accessible,
 
 out:
   gtk_accessible_value_unref (check_value);
+  g_object_unref (context);
 
   return res;
 }
index f67893837f6d9c2a639923c8274510d4b74a7310..3c9537e985ac3d5a5c577feb38857efebb53eba5 100644 (file)
@@ -633,6 +633,7 @@ static void     remove_parent_surface_transform_changed_listener (GtkWidget *wid
 static void     add_parent_surface_transform_changed_listener    (GtkWidget *widget);
 static void     gtk_widget_queue_compute_expand                  (GtkWidget *widget);
 
+static GtkATContext *create_at_context (GtkWidget *self);
 
 
 static int              GtkWidget_private_offset = 0;
@@ -904,8 +905,18 @@ gtk_widget_get_accessible_role (GtkWidget *self)
   GtkATContext *context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (self));
   GtkWidgetClassPrivate *class_priv;
 
-  if (context != NULL && gtk_at_context_is_realized (context))
-    return gtk_at_context_get_accessible_role (context);
+  if (context != NULL)
+    {
+      GtkAccessibleRole role = GTK_ACCESSIBLE_ROLE_NONE;
+
+      if (gtk_at_context_is_realized (context))
+        role = gtk_at_context_get_accessible_role (context);
+
+      g_object_unref (context);
+
+      if (role != GTK_ACCESSIBLE_ROLE_NONE)
+        return role;
+    }
 
   if (priv->accessible_role != GTK_ACCESSIBLE_ROLE_WIDGET)
     return priv->accessible_role;
@@ -2361,7 +2372,7 @@ gtk_widget_init (GTypeInstance *instance, gpointer g_class)
       gtk_widget_add_controller (widget, controller);
     }
 
-  priv->at_context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (widget));
+  priv->at_context = create_at_context (widget);
 }
 
 static void
@@ -7353,7 +7364,6 @@ gtk_widget_dispose (GObject *object)
   GtkWidget *widget = GTK_WIDGET (object);
   GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
   GSList *sizegroups;
-  GtkATContext *at_context;
 
   if (priv->muxer != NULL)
     g_object_run_dispose (G_OBJECT (priv->muxer));
@@ -7403,9 +7413,11 @@ gtk_widget_dispose (GObject *object)
       gtk_size_group_remove_widget (size_group, widget);
     }
 
-  at_context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (widget));
-  if (at_context != NULL)
-    gtk_at_context_unrealize (at_context);
+  if (priv->at_context != NULL)
+    {
+      gtk_at_context_unrealize (priv->at_context);
+      g_clear_object (&priv->at_context);
+    }
 
   g_clear_object (&priv->muxer);
 
@@ -8428,9 +8440,8 @@ gtk_widget_set_vexpand_set (GtkWidget      *widget,
  */
 
 static GtkATContext *
-gtk_widget_accessible_get_at_context (GtkAccessible *accessible)
+create_at_context (GtkWidget *self)
 {
-  GtkWidget *self = GTK_WIDGET (accessible);
   GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self);
   GtkWidgetClass *widget_class = GTK_WIDGET_GET_CLASS (self);
   GtkWidgetClassPrivate *class_priv = widget_class->priv;
@@ -8444,9 +8455,6 @@ gtk_widget_accessible_get_at_context (GtkAccessible *accessible)
       return NULL;
     }
 
-  if (priv->at_context != NULL)
-    return priv->at_context;
-
   /* Widgets have two options to set the accessible role: either they
    * define it in their class_init() function, and the role applies to
    * all instances; or an instance is created with the :accessible-role
@@ -8461,9 +8469,35 @@ gtk_widget_accessible_get_at_context (GtkAccessible *accessible)
     role = class_priv->accessible_role;
 
   priv->accessible_role = role;
-  priv->at_context = gtk_at_context_create (role, accessible, gdk_display_get_default ());
+  priv->at_context = gtk_at_context_create (role, GTK_ACCESSIBLE (self), gdk_display_get_default ());
+  if (priv->at_context != NULL)
+    return g_object_ref (priv->at_context);
 
-  return priv->at_context;
+  return NULL;
+}
+
+static GtkATContext *
+gtk_widget_accessible_get_at_context (GtkAccessible *accessible)
+{
+  GtkWidget *self = GTK_WIDGET (accessible);
+  GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self);
+
+  if (priv->in_destruction)
+    {
+      GTK_DEBUG (A11Y, "ATContext for widget ā€œ%sā€ [%p] accessed during destruction",
+                       G_OBJECT_TYPE_NAME (self),
+                       self);
+      return NULL;
+    }
+
+  if (priv->at_context != NULL)
+    return g_object_ref (priv->at_context);
+
+  priv->at_context = create_at_context (self);
+  if (priv->at_context != NULL)
+    return g_object_ref (priv->at_context);
+
+  return NULL;
 }
 
 static gboolean
@@ -9300,6 +9334,8 @@ gtk_widget_buildable_finish_accessibility_properties (GtkWidget *widget,
     }
 
   g_slist_free_full (attributes, accessibility_attribute_info_free);
+
+  g_object_unref (context);
 }
 
 static void
index f1844892046f9a680dcc640e3d4fdb7d3d97ade5..7fbaec0c924c886cd199b5b7ef1f7e8f3d868079 100644 (file)
@@ -244,6 +244,8 @@ update_path (GtkInspectorA11y *sl)
     }
   else
     path = "not on bus";
+
+  g_clear_object (&context);
 #endif
 
   gtk_label_set_label (GTK_LABEL (sl->path), path);
@@ -270,7 +272,7 @@ update_attributes (GtkInspectorA11y *sl)
   gboolean has_value;
 
   context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (sl->object));
-  if (!context)
+  if (context == NULL)
     return;
 
   store = g_list_store_new (G_TYPE_OBJECT);
@@ -347,6 +349,8 @@ update_attributes (GtkInspectorA11y *sl)
   g_object_unref (selection);
 
   gtk_widget_set_visible (sl->attributes, g_list_model_get_n_items (G_LIST_MODEL (filter_model)) > 0);
+
+  g_object_unref (context);
 }
 
 static void
@@ -420,8 +424,11 @@ gtk_inspector_a11y_set_object (GtkInspectorA11y *sl,
   if (sl->object && GTK_IS_ACCESSIBLE (sl->object))
     {
       context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (sl->object));
-      if (context)
-        g_signal_handlers_disconnect_by_func (context, refresh_all, sl);
+      if (context != NULL)
+        {
+          g_signal_handlers_disconnect_by_func (context, refresh_all, sl);
+          g_object_unref (context);
+        }
     }
 
   g_set_object (&sl->object, object);
@@ -432,8 +439,12 @@ gtk_inspector_a11y_set_object (GtkInspectorA11y *sl,
   if (GTK_IS_ACCESSIBLE (sl->object))
     {
       context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (sl->object));
-      if (context)
-        g_signal_connect_swapped (context, "state-change", G_CALLBACK (refresh_all), sl);
+      if (context != NULL)
+        {
+          g_signal_connect_swapped (context, "state-change", G_CALLBACK (refresh_all), sl);
+          g_object_unref (context);
+        }
+
       gtk_stack_page_set_visible (page, TRUE);
       update_role (sl);
       update_path (sl);
@@ -461,7 +472,11 @@ dispose (GObject *o)
       GtkATContext *context;
 
       context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (sl->object));
-      g_signal_handlers_disconnect_by_func (context, refresh_all, sl);
+      if (context != NULL)
+        {
+          g_signal_handlers_disconnect_by_func (context, refresh_all, sl);
+          g_object_unref (context);
+        }
     }
 
   g_clear_object (&sl->object);
index 2ea857ac3ea4bb650e7b5da3420490d6b1958f89..695221d565a2d2777d1dd0aee6a7bd4a2d4121cf 100644 (file)
@@ -33,7 +33,7 @@ test_object_accessible_get_at_context (GtkAccessible *accessible)
                                               accessible,
                                               gdk_display_get_default ());
 
-  return self->at_context;
+  return g_object_ref (self->at_context);
 }
 
 static void