Merge CVE-2021-27218, CVE-2021-27219 and CVE-2021-28153 fixes into glib-2-58

See merge requests
https://gitlab.gnome.org/GNOME/glib/-/merge_requests/2000,
https://gitlab.gnome.org/GNOME/glib/-/merge_requests/2001 and
https://gitlab.gnome.org/GNOME/glib/-/merge_requests/2002.
diff --git a/docs/reference/glib/meson.build b/docs/reference/glib/meson.build
index f14824b..f0b0cb5 100644
--- a/docs/reference/glib/meson.build
+++ b/docs/reference/glib/meson.build
@@ -20,6 +20,7 @@
     'gprintfint.h',
     'gmirroringtable.h',
     'gscripttable.h',
+    'gstrfuncsprivate.h',
     'glib-mirroring-tab',
     'gnulib',
     'pcre',
diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c
index 7270365..85ed1a3 100644
--- a/gio/gdbusconnection.c
+++ b/gio/gdbusconnection.c
@@ -110,6 +110,7 @@
 #include "gasyncinitable.h"
 #include "giostream.h"
 #include "gasyncresult.h"
+#include "gstrfuncsprivate.h"
 #include "gtask.h"
 
 #ifdef G_OS_UNIX
@@ -3961,7 +3962,7 @@
   /* Don't waste memory by copying padding - remember to update this
    * when changing struct _GDBusInterfaceVTable in gdbusconnection.h
    */
-  return g_memdup ((gconstpointer) vtable, 3 * sizeof (gpointer));
+  return g_memdup2 ((gconstpointer) vtable, 3 * sizeof (gpointer));
 }
 
 static void
@@ -3978,7 +3979,7 @@
   /* Don't waste memory by copying padding - remember to update this
    * when changing struct _GDBusSubtreeVTable in gdbusconnection.h
    */
-  return g_memdup ((gconstpointer) vtable, 3 * sizeof (gpointer));
+  return g_memdup2 ((gconstpointer) vtable, 3 * sizeof (gpointer));
 }
 
 static void
diff --git a/gio/gdbusinterfaceskeleton.c b/gio/gdbusinterfaceskeleton.c
index 96bd520..672604c 100644
--- a/gio/gdbusinterfaceskeleton.c
+++ b/gio/gdbusinterfaceskeleton.c
@@ -27,6 +27,7 @@
 #include "gdbusprivate.h"
 #include "gdbusmethodinvocation.h"
 #include "gdbusconnection.h"
+#include "gstrfuncsprivate.h"
 #include "gtask.h"
 #include "gioerror.h"
 
@@ -697,7 +698,7 @@
        * properly before building the hooked_vtable, so we create it
        * once at the last minute.
        */
-      interface_->priv->hooked_vtable = g_memdup (g_dbus_interface_skeleton_get_vtable (interface_), sizeof (GDBusInterfaceVTable));
+      interface_->priv->hooked_vtable = g_memdup2 (g_dbus_interface_skeleton_get_vtable (interface_), sizeof (GDBusInterfaceVTable));
       interface_->priv->hooked_vtable->method_call = skeleton_intercept_handle_method_call;
     }
 
diff --git a/gio/gfile.c b/gio/gfile.c
index a5709a4..d2314a4 100644
--- a/gio/gfile.c
+++ b/gio/gfile.c
@@ -60,6 +60,7 @@
 #include "gasyncresult.h"
 #include "gioerror.h"
 #include "glibintl.h"
+#include "gstrfuncsprivate.h"
 
 
 /**
@@ -7738,7 +7739,7 @@
   g_main_context_invoke_full (g_task_get_context (task),
                               g_task_get_priority (task),
                               measure_disk_usage_invoke_progress,
-                              g_memdup (&progress, sizeof progress),
+                              g_memdup2 (&progress, sizeof progress),
                               g_free);
 }
 
@@ -7756,7 +7757,7 @@
                                  data->progress_callback ? measure_disk_usage_progress : NULL, task,
                                  &result.disk_usage, &result.num_dirs, &result.num_files,
                                  &error))
-    g_task_return_pointer (task, g_memdup (&result, sizeof result), g_free);
+    g_task_return_pointer (task, g_memdup2 (&result, sizeof result), g_free);
   else
     g_task_return_error (task, error);
 }
@@ -7780,7 +7781,7 @@
 
   task = g_task_new (file, cancellable, callback, user_data);
   g_task_set_source_tag (task, g_file_real_measure_disk_usage_async);
-  g_task_set_task_data (task, g_memdup (&data, sizeof data), g_free);
+  g_task_set_task_data (task, g_memdup2 (&data, sizeof data), g_free);
   g_task_set_priority (task, io_priority);
 
   g_task_run_in_thread (task, measure_disk_usage_thread);
diff --git a/gio/gsettingsschema.c b/gio/gsettingsschema.c
index 38c9d78..e23dd8c 100644
--- a/gio/gsettingsschema.c
+++ b/gio/gsettingsschema.c
@@ -20,6 +20,7 @@
 
 #include "gsettingsschema-internal.h"
 #include "gsettings.h"
+#include "gstrfuncsprivate.h"
 
 #include "gvdb/gvdb-reader.h"
 #include "strinfo.c"
@@ -1057,9 +1058,9 @@
 
       if (g_str_has_suffix (key, "/"))
         {
-          gint length = strlen (key);
+          gsize length = strlen (key);
 
-          strv[j] = g_memdup (key, length);
+          strv[j] = g_memdup2 (key, length);
           strv[j][length - 1] = '\0';
           j++;
         }
diff --git a/gio/gwin32appinfo.c b/gio/gwin32appinfo.c
index 9f335b3..2a0fe38 100644
--- a/gio/gwin32appinfo.c
+++ b/gio/gwin32appinfo.c
@@ -472,7 +472,7 @@
       str_size = wcslen (str) + 1;
       str_size *= sizeof (gunichar2);
     }
-  return g_memdup (str, str_size);
+  return g_memdup2 (str, str_size);
 }
 
 #define URL_ASSOCIATIONS L"HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\"
diff --git a/gio/gwin32registrykey.c b/gio/gwin32registrykey.c
index c19fede..1c55263 100644
--- a/gio/gwin32registrykey.c
+++ b/gio/gwin32registrykey.c
@@ -28,6 +28,8 @@
 #include <ntstatus.h>
 #include <winternl.h>
 
+#include "gstrfuncsprivate.h"
+
 #ifndef _WDMDDK_
 typedef enum _KEY_INFORMATION_CLASS {
   KeyBasicInformation,
@@ -134,7 +136,7 @@
       str_size = wcslen (str) + 1;
       str_size *= sizeof (gunichar2);
     }
-  return g_memdup (str, str_size);
+  return g_memdup2 (str, str_size);
 }
 
 /**
@@ -247,7 +249,7 @@
   new_iter->value_name_size = iter->value_name_size;
 
   if (iter->value_data != NULL)
-    new_iter->value_data = g_memdup (iter->value_data, iter->value_data_size);
+    new_iter->value_data = g_memdup2 (iter->value_data, iter->value_data_size);
 
   new_iter->value_data_size = iter->value_data_size;
 
@@ -268,8 +270,8 @@
   new_iter->value_data_expanded_charsize = iter->value_data_expanded_charsize;
 
   if (iter->value_data_expanded_u8 != NULL)
-    new_iter->value_data_expanded_u8 = g_memdup (iter->value_data_expanded_u8,
-                                                 iter->value_data_expanded_charsize);
+    new_iter->value_data_expanded_u8 = g_memdup2 (iter->value_data_expanded_u8,
+                                                  iter->value_data_expanded_charsize);
 
   new_iter->value_data_expanded_u8_size = iter->value_data_expanded_charsize;
 
diff --git a/gio/tests/async-close-output-stream.c b/gio/tests/async-close-output-stream.c
index 5f66202..d3f97a1 100644
--- a/gio/tests/async-close-output-stream.c
+++ b/gio/tests/async-close-output-stream.c
@@ -24,6 +24,8 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include "gstrfuncsprivate.h"
+
 #define DATA_TO_WRITE "Hello world\n"
 
 typedef struct
@@ -147,9 +149,9 @@
 
   data->expected_size = g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (data->data_stream));
 
-  g_assert_cmpint (data->expected_size, >, 0);
+  g_assert_cmpuint (data->expected_size, >, 0);
 
-  data->expected_output = g_memdup (written, (guint)data->expected_size);
+  data->expected_output = g_memdup2 (written, data->expected_size);
 
   /* then recreate the streams and prepare them for the asynchronous close */
   destroy_streams (data);
diff --git a/gio/tests/gdbus-export.c b/gio/tests/gdbus-export.c
index 4d6d3a4..544b886 100644
--- a/gio/tests/gdbus-export.c
+++ b/gio/tests/gdbus-export.c
@@ -23,6 +23,7 @@
 #include <string.h>
 
 #include "gdbus-tests.h"
+#include "gstrfuncsprivate.h"
 
 /* all tests rely on a shared mainloop */
 static GMainLoop *loop = NULL;
@@ -652,7 +653,7 @@
       g_assert_not_reached ();
     }
 
-  return g_memdup (interfaces, 2 * sizeof (void *));
+  return g_memdup2 (interfaces, 2 * sizeof (void *));
 }
 
 static const GDBusInterfaceVTable *
@@ -708,7 +709,7 @@
 {
   const GDBusInterfaceInfo *interfaces[2] = { &dyna_interface_info, NULL };
 
-  return g_memdup (interfaces, 2 * sizeof (void *));
+  return g_memdup2 (interfaces, 2 * sizeof (void *));
 }
 
 static const GDBusInterfaceVTable *
diff --git a/gio/win32/gwinhttpfile.c b/gio/win32/gwinhttpfile.c
index d5df16d..e98031a 100644
--- a/gio/win32/gwinhttpfile.c
+++ b/gio/win32/gwinhttpfile.c
@@ -29,6 +29,7 @@
 #include "gio/gfile.h"
 #include "gio/gfileattribute.h"
 #include "gio/gfileinfo.h"
+#include "gstrfuncsprivate.h"
 #include "gwinhttpfile.h"
 #include "gwinhttpfileinputstream.h"
 #include "gwinhttpfileoutputstream.h"
@@ -393,10 +394,10 @@
   child = g_object_new (G_TYPE_WINHTTP_FILE, NULL);
   child->vfs = winhttp_file->vfs;
   child->url = winhttp_file->url;
-  child->url.lpszScheme = g_memdup (winhttp_file->url.lpszScheme, (winhttp_file->url.dwSchemeLength+1)*2);
-  child->url.lpszHostName = g_memdup (winhttp_file->url.lpszHostName, (winhttp_file->url.dwHostNameLength+1)*2);
-  child->url.lpszUserName = g_memdup (winhttp_file->url.lpszUserName, (winhttp_file->url.dwUserNameLength+1)*2);
-  child->url.lpszPassword = g_memdup (winhttp_file->url.lpszPassword, (winhttp_file->url.dwPasswordLength+1)*2);
+  child->url.lpszScheme = g_memdup2 (winhttp_file->url.lpszScheme, ((gsize) winhttp_file->url.dwSchemeLength + 1) * 2);
+  child->url.lpszHostName = g_memdup2 (winhttp_file->url.lpszHostName, ((gsize) winhttp_file->url.dwHostNameLength + 1) * 2);
+  child->url.lpszUserName = g_memdup2 (winhttp_file->url.lpszUserName, ((gsize) winhttp_file->url.dwUserNameLength + 1) * 2);
+  child->url.lpszPassword = g_memdup2 (winhttp_file->url.lpszPassword, ((gsize) winhttp_file->url.dwPasswordLength + 1) * 2);
   child->url.lpszUrlPath = wnew_path;
   child->url.dwUrlPathLength = wcslen (wnew_path);
   child->url.lpszExtraInfo = NULL;
diff --git a/glib/garray.c b/glib/garray.c
index a6cbd57..b00033a 100644
--- a/glib/garray.c
+++ b/glib/garray.c
@@ -1755,6 +1755,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
@@ -1766,6 +1770,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 7b72886..dee4948 100644
--- a/glib/gbytes.c
+++ b/glib/gbytes.c
@@ -34,6 +34,8 @@
 
 #include <string.h>
 
+#include "gstrfuncsprivate.h"
+
 /**
  * GBytes:
  *
@@ -95,7 +97,7 @@
 {
   g_return_val_if_fail (data != NULL || size == 0, NULL);
 
-  return g_bytes_new_take (g_memdup (data, size), size);
+  return g_bytes_new_take (g_memdup2 (data, size), size);
 }
 
 /**
@@ -499,7 +501,7 @@
        * Copy: Non g_malloc (or compatible) allocator, or static memory,
        * so we have to copy, and then unref.
        */
-      result = g_memdup (bytes->data, bytes->size);
+      result = g_memdup2 (bytes->data, bytes->size);
       *size = bytes->size;
       g_bytes_unref (bytes);
     }
@@ -519,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/gdir.c b/glib/gdir.c
index cb4ad0b..9d955d5 100644
--- a/glib/gdir.c
+++ b/glib/gdir.c
@@ -37,6 +37,7 @@
 #include "gconvert.h"
 #include "gfileutils.h"
 #include "gstrfuncs.h"
+#include "gstrfuncsprivate.h"
 #include "gtestutils.h"
 #include "glibintl.h"
 
@@ -113,7 +114,7 @@
     return NULL;
 #endif
 
-  return g_memdup (&dir, sizeof dir);
+  return g_memdup2 (&dir, sizeof dir);
 }
 
 /**
diff --git a/glib/ghash.c b/glib/ghash.c
index 433004c..e36a7a8 100644
--- a/glib/ghash.c
+++ b/glib/ghash.c
@@ -34,6 +34,7 @@
 
 #include "glib-private.h"
 #include "gstrfuncs.h"
+#include "gstrfuncsprivate.h"
 #include "gatomic.h"
 #include "gtestutils.h"
 #include "gslice.h"
@@ -967,7 +968,7 @@
    * split the table.
    */
   if (G_UNLIKELY (hash_table->keys == hash_table->values && hash_table->keys[node_index] != new_value))
-    hash_table->values = g_memdup (hash_table->keys, sizeof (gpointer) * hash_table->size);
+    hash_table->values = g_memdup2 (hash_table->keys, sizeof (gpointer) * hash_table->size);
 
   /* Step 3: Actually do the write */
   hash_table->values[node_index] = new_value;
diff --git a/glib/gslice.c b/glib/gslice.c
index d1b1fc6..db3331b 100644
--- a/glib/gslice.c
+++ b/glib/gslice.c
@@ -41,6 +41,7 @@
 #include "gmain.h"
 #include "gmem.h"               /* gslice.h */
 #include "gstrfuncs.h"
+#include "gstrfuncsprivate.h"
 #include "gutils.h"
 #include "gtrashstack.h"
 #include "gtestutils.h"
@@ -349,7 +350,7 @@
       array[i++] = allocator->contention_counters[address];
       array[i++] = allocator_get_magazine_threshold (allocator, address);
       *n_values = i;
-      return g_memdup (array, sizeof (array[0]) * *n_values);
+      return g_memdup2 (array, sizeof (array[0]) * *n_values);
     default:
       return NULL;
     }
diff --git a/glib/gstrfuncsprivate.h b/glib/gstrfuncsprivate.h
new file mode 100644
index 0000000..85c8832
--- /dev/null
+++ b/glib/gstrfuncsprivate.h
@@ -0,0 +1,55 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <string.h>
+
+/*
+ * g_memdup2:
+ * @mem: (nullable): the memory to copy.
+ * @byte_size: the number of bytes to copy.
+ *
+ * Allocates @byte_size bytes of memory, and copies @byte_size bytes into it
+ * from @mem. If @mem is %NULL it returns %NULL.
+ *
+ * This replaces g_memdup(), which was prone to integer overflows when
+ * converting the argument from a #gsize to a #guint.
+ *
+ * This static inline version is a backport of the new public API from
+ * GLib 2.68, kept internal to GLib for backport to older stable releases.
+ * See https://gitlab.gnome.org/GNOME/glib/-/issues/2319.
+ *
+ * Returns: (nullable): a pointer to the newly-allocated copy of the memory,
+ *    or %NULL if @mem is %NULL.
+ * Since: 2.68
+ */
+static inline gpointer
+g_memdup2 (gconstpointer mem,
+           gsize         byte_size)
+{
+  gpointer new_mem;
+
+  if (mem && byte_size != 0)
+    {
+      new_mem = g_malloc (byte_size);
+      memcpy (new_mem, mem, byte_size);
+    }
+  else
+    new_mem = NULL;
+
+  return new_mem;
+}
diff --git a/glib/gtestutils.c b/glib/gtestutils.c
index 7b29c27..f484fd3 100644
--- a/glib/gtestutils.c
+++ b/glib/gtestutils.c
@@ -49,6 +49,7 @@
 #include "gpattern.h"
 #include "grand.h"
 #include "gstrfuncs.h"
+#include "gstrfuncsprivate.h"
 #include "gtimer.h"
 #include "gslice.h"
 #include "gspawn.h"
@@ -3461,7 +3462,7 @@
       if (p <= tbuffer->data->str + mlength)
         {
           g_string_erase (tbuffer->data, 0, mlength);
-          tbuffer->msgs = g_slist_prepend (tbuffer->msgs, g_memdup (&msg, sizeof (msg)));
+          tbuffer->msgs = g_slist_prepend (tbuffer->msgs, g_memdup2 (&msg, sizeof (msg)));
           return TRUE;
         }
 
diff --git a/glib/gvariant.c b/glib/gvariant.c
index d45b487..de35c3e 100644
--- a/glib/gvariant.c
+++ b/glib/gvariant.c
@@ -33,6 +33,7 @@
 
 #include <string.h>
 
+#include "gstrfuncsprivate.h"
 
 /**
  * SECTION:gvariant
@@ -720,7 +721,7 @@
   g_variant_ref_sink (value);
 
   return g_variant_new_from_children (G_VARIANT_TYPE_VARIANT,
-                                      g_memdup (&value, sizeof value),
+                                      g_memdup2 (&value, sizeof value),
                                       1, g_variant_is_trusted (value));
 }
 
@@ -1224,7 +1225,7 @@
       return NULL;
     }
 
-  data = g_memdup (elements, n_elements * element_size);
+  data = g_memdup2 (elements, n_elements * element_size);
   value = g_variant_new_from_data (array_type, data,
                                    n_elements * element_size,
                                    FALSE, g_free, data);
@@ -1901,7 +1902,7 @@
   if (length)
     *length = size;
 
-  return g_memdup (original, size + 1);
+  return g_memdup2 (original, size + 1);
 }
 
 /**
diff --git a/glib/gvarianttype.c b/glib/gvarianttype.c
index f64be97..59ae6aa 100644
--- a/glib/gvarianttype.c
+++ b/glib/gvarianttype.c
@@ -28,6 +28,7 @@
 
 #include <string.h>
 
+#include "gstrfuncsprivate.h"
 
 /**
  * SECTION:gvarianttype
@@ -1177,7 +1178,7 @@
   g_assert (offset < sizeof buffer);
   buffer[offset++] = ')';
 
-  return (GVariantType *) g_memdup (buffer, offset);
+  return (GVariantType *) g_memdup2 (buffer, offset);
 }
 
 /**
diff --git a/glib/meson.build b/glib/meson.build
index 6fc56da..dcbd20e 100644
--- a/glib/meson.build
+++ b/glib/meson.build
@@ -182,6 +182,7 @@
   'gslist.c',
   'gstdio.c',
   'gstrfuncs.c',
+  'gstrfuncsprivate.h',
   'gstring.c',
   'gstringchunk.c',
   'gtestutils.c',
diff --git a/glib/tests/array-test.c b/glib/tests/array-test.c
index e0a6109..faa6061 100644
--- a/glib/tests/array-test.c
+++ b/glib/tests/array-test.c
@@ -30,6 +30,8 @@
 #include <string.h>
 #include "glib.h"
 
+#include "gstrfuncsprivate.h"
+
 /* Test data to be passed to any function which calls g_array_new(), providing
  * the parameters for that call. Most #GArray tests should be repeated for all
  * possible values of #ArrayTestData. */
@@ -1177,7 +1179,7 @@
   GByteArray *gbarray;
   guint8 *data;
 
-  data = g_memdup ("woooweeewow", 11);
+  data = g_memdup2 ("woooweeewow", 11);
   gbarray = g_byte_array_new_take (data, 11);
   g_assert (gbarray->data == data);
   g_assert_cmpuint (gbarray->len, ==, 11);
diff --git a/glib/tests/bytes.c b/glib/tests/bytes.c
index 5ea5c2b..9e26382 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;
@@ -407,7 +439,8 @@
   g_test_add_func ("/bytes/to-data/transfered", test_to_data_transferred);
   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/transfered", test_to_array_transferred);
+  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);
diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c
index 18800f9..e6ac324 100644
--- a/glib/tests/gvariant.c
+++ b/glib/tests/gvariant.c
@@ -17,6 +17,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include <glib.h>
+#include "gstrfuncsprivate.h"
 
 #define BASIC "bynqiuxthdsog?"
 #define N_BASIC (G_N_ELEMENTS (BASIC) - 1)
@@ -4779,7 +4780,7 @@
   GVariant *variant = NULL;
   GVariant *normal_variant = NULL;
 
-  aligned_data = g_memdup (data, size); /* guarantee alignment */
+  aligned_data = g_memdup2 (data, size); /* guarantee alignment */
   variant = g_variant_new_from_data (G_VARIANT_TYPE_VARIANT, aligned_data, size,
                                      FALSE, NULL, NULL);
   g_assert_nonnull (variant);
@@ -4908,7 +4909,7 @@
   GVariant *variant = NULL;
   GVariant *normal_variant = NULL;
 
-  aligned_data = g_memdup (data, size); /* guarantee alignment */
+  aligned_data = g_memdup2 (data, size); /* guarantee alignment */
   variant = g_variant_new_from_data (G_VARIANT_TYPE_VARIANT, aligned_data, size,
                                      FALSE, NULL, NULL);
   g_assert_nonnull (variant);
@@ -4935,7 +4936,7 @@
   GVariant *variant = NULL;
   GVariant *normal_variant = NULL;
 
-  aligned_data = g_memdup (data, size); /* guarantee alignment */
+  aligned_data = g_memdup2 (data, size); /* guarantee alignment */
   variant = g_variant_new_from_data (G_VARIANT_TYPE_VARIANT, aligned_data,
                                      size, FALSE, NULL, NULL);
   g_assert_nonnull (variant);
@@ -4962,7 +4963,7 @@
   GVariant *variant = NULL;
   GVariant *normal_variant = NULL;
 
-  aligned_data = g_memdup (data, size); /* guarantee alignment */
+  aligned_data = g_memdup2 (data, size); /* guarantee alignment */
   variant = g_variant_new_from_data (G_VARIANT_TYPE_VARIANT, aligned_data, size,
                                      FALSE, NULL, NULL);
   g_assert_nonnull (variant);
diff --git a/glib/tests/option-context.c b/glib/tests/option-context.c
index 34ebfaa..7125e22 100644
--- a/glib/tests/option-context.c
+++ b/glib/tests/option-context.c
@@ -27,6 +27,8 @@
 #include <string.h>
 #include <locale.h>
 
+#include "gstrfuncsprivate.h"
+
 static GOptionEntry main_entries[] = {
   { "main-switch", 0, 0,
     G_OPTION_ARG_NONE, NULL,
@@ -256,7 +258,7 @@
 static char **
 copy_stringv (char **argv, int argc)
 {
-  return g_memdup (argv, sizeof (char *) * (argc + 1));
+  return g_memdup2 (argv, sizeof (char *) * (argc + 1));
 }
 
 static void
@@ -2318,7 +2320,7 @@
   g_option_context_add_group (context, group);
 
   argv = split_string ("program --test arg1 -f arg2 --group-test arg3 --frob arg4 -z arg5", &argc);
-  orig_argv = g_memdup (argv, (argc + 1) * sizeof (char *));
+  orig_argv = g_memdup2 (argv, (argc + 1) * sizeof (char *));
 
   retval = g_option_context_parse (context, &argc, &argv, &error);
 
diff --git a/glib/tests/strfuncs.c b/glib/tests/strfuncs.c
index d974ad4..1111226 100644
--- a/glib/tests/strfuncs.c
+++ b/glib/tests/strfuncs.c
@@ -32,6 +32,8 @@
 #include <string.h>
 #include "glib.h"
 
+#include "gstrfuncsprivate.h"
+
 #if defined (_MSC_VER) && (_MSC_VER <= 1800)
 #define isnan(x) _isnan(x)
 
@@ -199,6 +201,26 @@
   #undef TEST_DIGIT
 }
 
+/* Testing g_memdup2() function with various positive and negative cases */
+static void
+test_memdup2 (void)
+{
+  gchar *str_dup = NULL;
+  const gchar *str = "The quick brown fox jumps over the lazy dog";
+
+  /* Testing negative cases */
+  g_assert_null (g_memdup2 (NULL, 1024));
+  g_assert_null (g_memdup2 (str, 0));
+  g_assert_null (g_memdup2 (NULL, 0));
+
+  /* Testing normal usage cases */
+  str_dup = g_memdup2 (str, strlen (str) + 1);
+  g_assert_nonnull (str_dup);
+  g_assert_cmpstr (str, ==, str_dup);
+
+  g_free (str_dup);
+}
+
 static void
 test_strdup (void)
 {
@@ -1731,6 +1753,7 @@
   g_test_init (&argc, &argv, NULL);
 
   g_test_add_func ("/strfuncs/test-is-to-digit", test_is_to_digit);
+  g_test_add_func ("/strfuncs/memdup2", test_memdup2);
   g_test_add_func ("/strfuncs/strdup", test_strdup);
   g_test_add_func ("/strfuncs/strndup", test_strndup);
   g_test_add_func ("/strfuncs/strdup-printf", test_strdup_printf);
diff --git a/gobject/gsignal.c b/gobject/gsignal.c
index 76f1dc9..4296eb2 100644
--- a/gobject/gsignal.c
+++ b/gobject/gsignal.c
@@ -28,6 +28,7 @@
 #include <signal.h>
 
 #include "gsignal.h"
+#include "gstrfuncsprivate.h"
 #include "gtype-private.h"
 #include "gbsearcharray.h"
 #include "gvaluecollector.h"
@@ -1724,7 +1725,7 @@
   node->single_va_closure_is_valid = FALSE;
   node->flags = signal_flags & G_SIGNAL_FLAGS_MASK;
   node->n_params = n_params;
-  node->param_types = g_memdup (param_types, sizeof (GType) * n_params);
+  node->param_types = g_memdup2 (param_types, sizeof (GType) * n_params);
   node->return_type = return_type;
   node->class_closure_bsa = NULL;
   if (accumulator)
diff --git a/gobject/gtype.c b/gobject/gtype.c
index 1acc0a0..bee83bd 100644
--- a/gobject/gtype.c
+++ b/gobject/gtype.c
@@ -33,6 +33,7 @@
 
 #include "glib-private.h"
 #include "gconstructor.h"
+#include "gstrfuncsprivate.h"
 
 #ifdef G_OS_WIN32
 #include <windows.h>
@@ -1467,7 +1468,7 @@
   iholder->next = iface_node_get_holders_L (iface);
   iface_node_set_holders_W (iface, iholder);
   iholder->instance_type = NODE_TYPE (node);
-  iholder->info = info ? g_memdup (info, sizeof (*info)) : NULL;
+  iholder->info = info ? g_memdup2 (info, sizeof (*info)) : NULL;
   iholder->plugin = plugin;
 
   /* create an iface entry for this type */
@@ -1728,7 +1729,7 @@
         INVALID_RECURSION ("g_type_plugin_*", iholder->plugin, NODE_NAME (iface));
       
       check_interface_info_I (iface, instance_type, &tmp_info);
-      iholder->info = g_memdup (&tmp_info, sizeof (tmp_info));
+      iholder->info = g_memdup2 (&tmp_info, sizeof (tmp_info));
     }
   
   return iholder;	/* we don't modify write lock upon returning NULL */
@@ -2013,10 +2014,10 @@
       IFaceEntry *pentry = type_lookup_iface_entry_L (pnode, iface);
       
       if (pentry)
-	vtable = g_memdup (pentry->vtable, iface->data->iface.vtable_size);
+	vtable = g_memdup2 (pentry->vtable, iface->data->iface.vtable_size);
     }
   if (!vtable)
-    vtable = g_memdup (iface->data->iface.dflt_vtable, iface->data->iface.vtable_size);
+    vtable = g_memdup2 (iface->data->iface.dflt_vtable, iface->data->iface.vtable_size);
   entry->vtable = vtable;
   vtable->g_type = NODE_TYPE (iface);
   vtable->g_instance_type = NODE_TYPE (node);
diff --git a/gobject/gtypemodule.c b/gobject/gtypemodule.c
index 4ecaf8c..20911fa 100644
--- a/gobject/gtypemodule.c
+++ b/gobject/gtypemodule.c
@@ -19,6 +19,7 @@
 
 #include <stdlib.h>
 
+#include "gstrfuncsprivate.h"
 #include "gtypeplugin.h"
 #include "gtypemodule.h"
 
@@ -436,7 +437,7 @@
   module_type_info->loaded = TRUE;
   module_type_info->info = *type_info;
   if (type_info->value_table)
-    module_type_info->info.value_table = g_memdup (type_info->value_table,
+    module_type_info->info.value_table = g_memdup2 (type_info->value_table,
 						   sizeof (GTypeValueTable));
 
   return module_type_info->type;
diff --git a/gobject/tests/param.c b/gobject/tests/param.c
index 758289b..971cff1 100644
--- a/gobject/tests/param.c
+++ b/gobject/tests/param.c
@@ -2,6 +2,8 @@
 #include <glib-object.h>
 #include <stdlib.h>
 
+#include "gstrfuncsprivate.h"
+
 static void
 test_param_value (void)
 {
@@ -851,7 +853,7 @@
             test_path = g_strdup_printf ("/param/implement/subprocess/%d-%d-%d-%d",
                                          data.change_this_flag, data.change_this_type,
                                          data.use_this_flag, data.use_this_type);
-            test_data = g_memdup (&data, sizeof (TestParamImplementData));
+            test_data = g_memdup2 (&data, sizeof (TestParamImplementData));
             g_test_add_data_func_full (test_path, test_data, test_param_implement_child, g_free);
             g_free (test_path);
           }