Avoid O(n²) walking of string arrays
authorEmmanuele Bassi <ebassi@gnome.org>
Thu, 16 Jul 2015 15:12:35 +0000 (16:12 +0100)
committerEmmanuele Bassi <ebassi@gnome.org>
Thu, 16 Jul 2015 15:19:55 +0000 (16:19 +0100)
"Yo, we heard you like traversing NULL-terminated arrays to operate on
them, so we called g_strv_length() as the for condition, so you can
iterate the array while iterating the array."

Instead of making famed rapper and television producer Xzibit proud, we
should avoid calling g_strv_length() on an array while looping on the
array, to avoid quadratic complexity.

We do this in various places that deal with arrays of strings that we
cannot really guess are short enough not to matter — e.g. the list of
CSS selectors in the inspector, or the required authentication
information for printing.

gtk/gtkprintbackend.c
gtk/inspector/selector.c
modules/printbackends/cups/gtkcupssecretsutils.c
testsuite/a11y/state/state-record.c

index cda9376007ef9a989f20d0af9a13f429406023a2..8ec6dbc99b88991ec25708f77e3a5c52d187ce18 100644 (file)
@@ -706,24 +706,27 @@ password_dialog_response (GtkWidget       *dialog,
                           GtkPrintBackend *backend)
 {
   GtkPrintBackendPrivate *priv = backend->priv;
-  gint i;
+  gint i, auth_info_len;
 
   if (response_id == GTK_RESPONSE_OK)
     gtk_print_backend_set_password (backend, priv->auth_info_required, priv->auth_info, priv->store_auth_info);
   else
     gtk_print_backend_set_password (backend, priv->auth_info_required, NULL, FALSE);
 
-  for (i = 0; i < g_strv_length (priv->auth_info_required); i++)
-    if (priv->auth_info[i] != NULL)
-      {
-        memset (priv->auth_info[i], 0, strlen (priv->auth_info[i]));
-        g_free (priv->auth_info[i]);
-        priv->auth_info[i] = NULL;
-      }
-  g_free (priv->auth_info);
-  priv->auth_info = NULL;
+  /* We want to clear the data before freeing it */
+  auth_info_len = g_strv_length (priv->auth_info_required);
+  for (i = 0; i < auth_info_len; i++)
+    {
+      if (priv->auth_info[i] != NULL)
+        {
+          memset (priv->auth_info[i], 0, strlen (priv->auth_info[i]));
+          g_free (priv->auth_info[i]);
+          priv->auth_info[i] = NULL;
+        }
+    }
 
-  g_strfreev (priv->auth_info_required);
+  g_clear_pointer (&priv->auth_info, g_free);
+  g_clear_pointer (&priv->auth_info_required, g_strfreev);
 
   gtk_widget_destroy (dialog);
 
index e19f74ca9c15507ecd78ddc99ca672d24698b5b8..c820d3b70afbd048dafcf41ca4e7ee4158b945c3 100644 (file)
@@ -64,7 +64,7 @@ gtk_inspector_selector_set_object (GtkInspectorSelector *oh,
                                    GObject              *object)
 {
   GtkTreeIter iter, parent;
-  gint i;
+  gint i, words_len;
   GtkWidget *widget;
   gchar *path, **words;
   const gchar *title;
@@ -85,7 +85,8 @@ gtk_inspector_selector_set_object (GtkInspectorSelector *oh,
   path = gtk_widget_path_to_string (gtk_widget_get_path (widget));
   words = g_strsplit (path, " ", 0);
 
-  for (i = 0; i < g_strv_length (words); i++)
+  words_len = g_strv_length (words);
+  for (i = 0; i < words_len; i++)
     {
       gtk_tree_store_append (oh->priv->model, &iter, i ? &parent : NULL);
       gtk_tree_store_set (oh->priv->model, &iter,
index d5df4a73268b66cb490b41fa410023fd8295eed8..925f7d561c05d5147997b68fa70f8173ce4038b9 100644 (file)
@@ -109,7 +109,7 @@ get_secret_cb (GObject      *source_object,
                      *key = NULL,
                      *value = NULL;
   GVariantIter       *iter = NULL;
-  guint               i;
+  guint               i, required_len;
   gint                pw_field = -1;
 
   task = user_data;
@@ -228,7 +228,8 @@ get_secret_cb (GObject      *source_object,
 fail:
   /* Error out */
   GTK_NOTE (PRINTING, g_print ("Failed to lookup secret.\n"));
-  for (i = 0; i < g_strv_length (task_data->auth_info_required); i++)
+  required_len = g_strv_length (task_data->auth_info_required);
+  for (i = 0; i < required_len; i++)
     {
       /* Not all fields of auth_info are neccessarily written so we can not
          use strfreev here */
index cf9313b1b03b6189fdfbd1e405c646934db26a87..dd37c6233ca81a3b1c0d09eb68c59a2e11d5c0f4 100644 (file)
@@ -142,7 +142,7 @@ record_events (const gchar *ui_file,
   GError *error;
   gchar *contents;
   gchar **actions;
-  gint i;
+  gint i, len;
 
   builder = gtk_builder_new ();
   error = NULL;
@@ -152,8 +152,9 @@ record_events (const gchar *ui_file,
   g_file_get_contents (in_file, &contents, NULL, &error);
   g_assert_no_error (error);
   actions = g_strsplit (contents, "\n", 0);
-  for (i = 0; i < g_strv_length (actions); i++)
+
+  len = g_strv_length (actions);
+  for (i = 0; i < len; i++)
     do_action (builder, actions[i], string);
 
   g_object_unref (builder);