Merge branch 'backport-1942-bytes-byte-array-bitten-glib-2-66' into 'glib-2-66'

Backport !1942 “gbytearray: Do not accept too large byte arrays” to glib-2-66

See merge request GNOME/glib!1944
diff --git a/glib/garray.c b/glib/garray.c
index 4b6de19..d09c904 100644
--- a/glib/garray.c
+++ b/glib/garray.c
@@ -2261,6 +2261,10 @@
  * Create byte array containing the data. The data will be owned by the array
  * and will be freed with g_free(), i.e. it could be allocated using g_strdup().
  *
+ * Do not use it if @len is greater than %G_MAXUINT. #GByteArray
+ * stores the length of its data in #guint, which may be shorter than
+ * #gsize.
+ *
  * Since: 2.32
  *
  * Returns: (transfer full): a new #GByteArray
@@ -2272,6 +2276,8 @@
   GByteArray *array;
   GRealArray *real;
 
+  g_return_val_if_fail (len <= G_MAXUINT, NULL);
+
   array = g_byte_array_new ();
   real = (GRealArray *)array;
   g_assert (real->data == NULL);
diff --git a/glib/gbytes.c b/glib/gbytes.c
index 6f17d10..5293869 100644
--- a/glib/gbytes.c
+++ b/glib/gbytes.c
@@ -521,6 +521,10 @@
  * g_bytes_new(), g_bytes_new_take() or g_byte_array_free_to_bytes(). In all
  * other cases the data is copied.
  *
+ * Do not use it if @bytes contains more than %G_MAXUINT
+ * bytes. #GByteArray stores the length of its data in #guint, which
+ * may be shorter than #gsize, that @bytes is using.
+ *
  * Returns: (transfer full): a new mutable #GByteArray containing the same byte data
  *
  * Since: 2.32
diff --git a/glib/tests/bytes.c b/glib/tests/bytes.c
index a65d3a9..f6e4403 100644
--- a/glib/tests/bytes.c
+++ b/glib/tests/bytes.c
@@ -10,12 +10,12 @@
  */
 
 #undef G_DISABLE_ASSERT
-#undef G_LOG_DOMAIN
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include "glib.h"
+#include "glib/gstrfuncsprivate.h"
 
 /* Keep in sync with glib/gbytes.c */
 struct _GBytes
@@ -334,6 +334,38 @@
 }
 
 static void
+test_to_array_transferred_oversize (void)
+{
+  g_test_message ("g_bytes_unref_to_array() can only take GBytes up to "
+                  "G_MAXUINT in length; test that longer ones are rejected");
+
+  if (sizeof (guint) >= sizeof (gsize))
+    {
+      g_test_skip ("Skipping test as guint is not smaller than gsize");
+    }
+  else if (g_test_undefined ())
+    {
+      GByteArray *array = NULL;
+      GBytes *bytes = NULL;
+      gpointer data = g_memdup2 (NYAN, N_NYAN);
+      gsize len = ((gsize) G_MAXUINT) + 1;
+
+      bytes = g_bytes_new_take (data, len);
+      g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
+                             "g_byte_array_new_take: assertion 'len <= G_MAXUINT' failed");
+      array = g_bytes_unref_to_array (g_steal_pointer (&bytes));
+      g_test_assert_expected_messages ();
+      g_assert_null (array);
+
+      g_free (data);
+    }
+  else
+    {
+      g_test_skip ("Skipping test as testing undefined behaviour is disabled");
+    }
+}
+
+static void
 test_to_array_two_refs (void)
 {
   gconstpointer memory;
@@ -408,6 +440,7 @@
   g_test_add_func ("/bytes/to-data/two-refs", test_to_data_two_refs);
   g_test_add_func ("/bytes/to-data/non-malloc", test_to_data_non_malloc);
   g_test_add_func ("/bytes/to-array/transferred", test_to_array_transferred);
+  g_test_add_func ("/bytes/to-array/transferred/oversize", test_to_array_transferred_oversize);
   g_test_add_func ("/bytes/to-array/two-refs", test_to_array_two_refs);
   g_test_add_func ("/bytes/to-array/non-malloc", test_to_array_non_malloc);
   g_test_add_func ("/bytes/null", test_null);