properly abort instead of looping infinitely
authorSven Herzberg <herzi@gnome-de.org>
Wed, 13 Jan 2010 13:47:58 +0000 (14:47 +0100)
committerSven Herzberg <herzi@gnome-de.org>
Wed, 13 Jan 2010 14:01:00 +0000 (15:01 +0100)
Fixes: Bug 568760 - nautilus freezes due to a bug in garray.c:322

* glib/garray.c: increase the size of potential return values by
  using an unsigned result; properly check if we still handle valid size
  proposals, return the original request if there's no usable size left
* tests/array-test.c: reproduce the error condition of the bug report

glib/garray.c
glib/tests/array-test.c

index b439000..d4eae12 100644 (file)
@@ -67,9 +67,9 @@ struct _GRealArray
     g_array_elt_zero ((array), (array)->len, 1);                       \
 }G_STMT_END
 
-static gint g_nearest_pow        (gint        num) G_GNUC_CONST;
-static void g_array_maybe_expand (GRealArray *array,
-                                 gint        len);
+static guint g_nearest_pow        (gint        num) G_GNUC_CONST;
+static void  g_array_maybe_expand (GRealArray *array,
+                                  gint        len);
 
 GArray*
 g_array_new (gboolean zero_terminated,
@@ -387,16 +387,18 @@ g_array_sort_with_data (GArray           *farray,
                     user_data);
 }
 
-
-static gint
+/* Returns the smallest power of 2 greater than n, or n if
+ * such power does not fit in a guint
+ */
+static guint
 g_nearest_pow (gint num)
 {
-  gint n = 1;
+  guint n = 1;
 
-  while (n < num)
+  while (n < num && n > 0)
     n <<= 1;
 
-  return n;
+  return n ? n : num;
 }
 
 static void
index 86308e0..949120b 100644 (file)
@@ -28,6 +28,7 @@
 #undef G_LOG_DOMAIN
 
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include "glib.h"
 
@@ -100,6 +101,26 @@ array_ref_count (void)
 }
 
 static void
+array_large_size (void)
+{
+  GArray* array;
+
+  g_test_bug ("568760");
+
+  array = g_array_new (TRUE, TRUE, sizeof (char));
+
+  /* it might take really long until the allocation happens */
+  if (g_test_trap_fork (10 /* s */ * 1000 /* ms */ * 1000 /* µs */, 0))
+    {
+      g_array_set_size (array, 1073750016);
+      exit (0); /* success */
+    }
+  g_test_trap_assert_passed ();
+
+  g_array_free (array, TRUE);
+}
+
+static void
 pointer_array_add (void)
 {
   GPtrArray *gparray;
@@ -288,10 +309,13 @@ main (int argc, char *argv[])
 {
   g_test_init (&argc, &argv, NULL);
 
+  g_test_bug_base ("http://bugs.gnome.org/%s");
+
   /* array tests */
   g_test_add_func ("/array/append", array_append);
   g_test_add_func ("/array/prepend", array_prepend);
   g_test_add_func ("/array/ref-count", array_ref_count);
+  g_test_add_func ("/array/large-size", array_large_size);
 
   /* pointer arrays */
   g_test_add_func ("/pointerarray/add", pointer_array_add);