Imported Upstream version 2.66.7 upstream/2.66.7
authorDongHun Kwak <dh0128.kwak@samsung.com>
Fri, 29 Oct 2021 01:28:40 +0000 (10:28 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Fri, 29 Oct 2021 01:28:40 +0000 (10:28 +0900)
14 files changed:
NEWS
gio/gdbusconnection.c
gio/gdbusserver.c
gio/gkeyfilesettingsbackend.c
gio/gtlspassword.c
gio/tests/gdbus-peer.c
gio/tests/gsettings.c
gio/tests/tls-interaction.c
glib/garray.c
glib/gbytes.c
glib/giochannel.c
glib/tests/bytes.c
glib/tests/io-channel.c
meson.build

diff --git a/NEWS b/NEWS
index 520df7a..0f0a6a2 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,23 @@
+Overview of changes in GLib 2.66.7
+==================================
+
+* Fix various regressions caused by rushed security fixes in 2.66.6
+  (work by Simon McVittie and Jan Alexander Steffens) (!1933, !1943)
+
+* Fix a silent integer truncation when calling `g_byte_array_new_take()` for
+  byte arrays bigger than `G_MAXUINT` (work by Krzesimir Nowak) (!1944)
+
+* Disallow using currently-undefined D-Bus connection or server flags to prevent
+  forward-compatibility problems with new security-sensitive flags likely to be
+  released in GLib 2.68 (work by Simon McVittie) (!1945)
+
+* Bugs fixed:
+ - !1933 [2.66] Fix regressions in 2.66.6 where negative gssize indicates strlen()
+ - !1943 Backport !1941 “gkeyfilesettingsbackend: Fix basename handling when group is unset” to glib-2-66
+ - !1944 Backport !1942 “gbytearray: Do not accept too large byte arrays” to glib-2-66
+ - !1945 Backport !1934 “gdbus: Reject attempts to set future connection or server flags” to glib-2-66
+
+
 Overview of changes in GLib 2.66.6
 ==================================
 
index 633198b..75b8180 100644 (file)
 
 #include "glibintl.h"
 
+#define G_DBUS_CONNECTION_FLAGS_ALL \
+  (G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT | \
+   G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER | \
+   G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS | \
+   G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION | \
+   G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING)
+
 /**
  * SECTION:gdbusconnection
  * @short_description: D-Bus Connections
@@ -2706,6 +2713,7 @@ g_dbus_connection_new (GIOStream            *stream,
   _g_dbus_initialize ();
 
   g_return_if_fail (G_IS_IO_STREAM (stream));
+  g_return_if_fail ((flags & ~G_DBUS_CONNECTION_FLAGS_ALL) == 0);
 
   g_async_initable_new_async (G_TYPE_DBUS_CONNECTION,
                               G_PRIORITY_DEFAULT,
@@ -2793,6 +2801,7 @@ g_dbus_connection_new_sync (GIOStream             *stream,
 {
   _g_dbus_initialize ();
   g_return_val_if_fail (G_IS_IO_STREAM (stream), NULL);
+  g_return_val_if_fail ((flags & ~G_DBUS_CONNECTION_FLAGS_ALL) == 0, NULL);
   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
   return g_initable_new (G_TYPE_DBUS_CONNECTION,
                          cancellable,
@@ -2850,6 +2859,7 @@ g_dbus_connection_new_for_address (const gchar          *address,
   _g_dbus_initialize ();
 
   g_return_if_fail (address != NULL);
+  g_return_if_fail ((flags & ~G_DBUS_CONNECTION_FLAGS_ALL) == 0);
 
   g_async_initable_new_async (G_TYPE_DBUS_CONNECTION,
                               G_PRIORITY_DEFAULT,
@@ -2937,6 +2947,7 @@ g_dbus_connection_new_for_address_sync (const gchar           *address,
   _g_dbus_initialize ();
 
   g_return_val_if_fail (address != NULL, NULL);
+  g_return_val_if_fail ((flags & ~G_DBUS_CONNECTION_FLAGS_ALL) == 0, NULL);
   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
   return g_initable_new (G_TYPE_DBUS_CONNECTION,
                          cancellable,
index 4a8dab0..64bac73 100644 (file)
 
 #include "glibintl.h"
 
+#define G_DBUS_SERVER_FLAGS_ALL \
+  (G_DBUS_SERVER_FLAGS_RUN_IN_THREAD | \
+   G_DBUS_SERVER_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS)
+
 /**
  * SECTION:gdbusserver
  * @short_description: Helper for accepting connections
@@ -512,6 +516,7 @@ g_dbus_server_new_sync (const gchar        *address,
 
   g_return_val_if_fail (address != NULL, NULL);
   g_return_val_if_fail (g_dbus_is_guid (guid), NULL);
+  g_return_val_if_fail ((flags & ~G_DBUS_SERVER_FLAGS_ALL) == 0, NULL);
   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
 
   server = g_initable_new (G_TYPE_DBUS_SERVER,
index 25b0576..de216e6 100644 (file)
@@ -158,6 +158,13 @@ convert_path (GKeyfileSettingsBackend  *kfsb,
 
   last_slash = strrchr (key, '/');
 
+  /* Disallow empty group names or key names */
+  if (key_len == 0 ||
+      (last_slash != NULL &&
+       (*(last_slash + 1) == '\0' ||
+        last_slash == key)))
+    return FALSE;
+
   if (kfsb->root_group)
     {
       /* if a root_group was specified, make sure the user hasn't given
@@ -185,7 +192,12 @@ convert_path (GKeyfileSettingsBackend  *kfsb,
     }
 
   if (basename)
-    *basename = g_memdup2 (last_slash + 1, key_len - (last_slash - key));
+    {
+      if (last_slash != NULL)
+        *basename = g_memdup2 (last_slash + 1, key_len - (last_slash - key));
+      else
+        *basename = g_strdup (key);
+    }
 
   return TRUE;
 }
index dbcec41..bd86a6d 100644 (file)
@@ -291,7 +291,7 @@ g_tls_password_set_value (GTlsPassword  *password,
     {
       /* FIXME: g_tls_password_set_value_full() doesn’t support unsigned gsize */
       gsize length_unsigned = strlen ((gchar *) value);
-      g_return_if_fail (length_unsigned > G_MAXSSIZE);
+      g_return_if_fail (length_unsigned <= G_MAXSSIZE);
       length = (gssize) length_unsigned;
     }
 
index 8450a3b..a03ebbb 100644 (file)
@@ -1139,6 +1139,183 @@ test_peer (void)
 
 /* ---------------------------------------------------------------------------------------------------- */
 
+#define VALID_GUID "0123456789abcdef0123456789abcdef"
+
+static void
+test_peer_invalid_server (void)
+{
+  GDBusServer *server;
+
+  if (!g_test_undefined ())
+    {
+      g_test_skip ("Not exercising programming errors");
+      return;
+    }
+
+  if (g_test_subprocess ())
+    {
+      /* This assumes we are not going to run out of GDBusServerFlags
+       * any time soon */
+      server = g_dbus_server_new_sync ("tcp:", (GDBusServerFlags) (1 << 30),
+                                       VALID_GUID,
+                                       NULL, NULL, NULL);
+      g_assert_null (server);
+    }
+  else
+    {
+      g_test_trap_subprocess (NULL, 0, 0);
+      g_test_trap_assert_failed ();
+      g_test_trap_assert_stderr ("*CRITICAL*G_DBUS_SERVER_FLAGS_ALL*");
+    }
+}
+
+static void
+test_peer_invalid_conn_stream_sync (void)
+{
+  GSocket *sock;
+  GSocketConnection *socket_conn;
+  GIOStream *iostream;
+  GDBusConnection *conn;
+
+  if (!g_test_undefined ())
+    {
+      g_test_skip ("Not exercising programming errors");
+      return;
+    }
+
+  sock = g_socket_new (G_SOCKET_FAMILY_IPV4,
+                       G_SOCKET_TYPE_STREAM,
+                       G_SOCKET_PROTOCOL_TCP,
+                       NULL);
+
+  if (sock == NULL)
+    {
+      g_test_skip ("TCP not available?");
+      return;
+    }
+
+  socket_conn = g_socket_connection_factory_create_connection (sock);
+  g_assert_nonnull (socket_conn);
+  iostream = G_IO_STREAM (socket_conn);
+  g_assert_nonnull (iostream);
+
+  if (g_test_subprocess ())
+    {
+      /* This assumes we are not going to run out of GDBusConnectionFlags
+       * any time soon */
+      conn = g_dbus_connection_new_sync (iostream, VALID_GUID,
+                                         (GDBusConnectionFlags) (1 << 30),
+                                         NULL, NULL, NULL);
+      g_assert_null (conn);
+    }
+  else
+    {
+      g_test_trap_subprocess (NULL, 0, 0);
+      g_test_trap_assert_failed ();
+      g_test_trap_assert_stderr ("*CRITICAL*G_DBUS_CONNECTION_FLAGS_ALL*");
+    }
+
+  g_clear_object (&sock);
+  g_clear_object (&socket_conn);
+}
+
+static void
+test_peer_invalid_conn_stream_async (void)
+{
+  GSocket *sock;
+  GSocketConnection *socket_conn;
+  GIOStream *iostream;
+
+  if (!g_test_undefined ())
+    {
+      g_test_skip ("Not exercising programming errors");
+      return;
+    }
+
+  sock = g_socket_new (G_SOCKET_FAMILY_IPV4,
+                       G_SOCKET_TYPE_STREAM,
+                       G_SOCKET_PROTOCOL_TCP,
+                       NULL);
+
+  if (sock == NULL)
+    {
+      g_test_skip ("TCP not available?");
+      return;
+    }
+
+  socket_conn = g_socket_connection_factory_create_connection (sock);
+  g_assert_nonnull (socket_conn);
+  iostream = G_IO_STREAM (socket_conn);
+  g_assert_nonnull (iostream);
+
+  if (g_test_subprocess ())
+    {
+      g_dbus_connection_new (iostream, VALID_GUID,
+                             (GDBusConnectionFlags) (1 << 30),
+                             NULL, NULL, NULL, NULL);
+    }
+  else
+    {
+      g_test_trap_subprocess (NULL, 0, 0);
+      g_test_trap_assert_failed ();
+      g_test_trap_assert_stderr ("*CRITICAL*G_DBUS_CONNECTION_FLAGS_ALL*");
+    }
+
+  g_clear_object (&sock);
+  g_clear_object (&socket_conn);
+}
+
+static void
+test_peer_invalid_conn_addr_sync (void)
+{
+  GDBusConnection *conn;
+
+  if (!g_test_undefined ())
+    {
+      g_test_skip ("Not exercising programming errors");
+      return;
+    }
+
+  if (g_test_subprocess ())
+    {
+      conn = g_dbus_connection_new_for_address_sync ("tcp:",
+                                                     (GDBusConnectionFlags) (1 << 30),
+                                                     NULL, NULL, NULL);
+      g_assert_null (conn);
+    }
+  else
+    {
+      g_test_trap_subprocess (NULL, 0, 0);
+      g_test_trap_assert_failed ();
+      g_test_trap_assert_stderr ("*CRITICAL*G_DBUS_CONNECTION_FLAGS_ALL*");
+    }
+}
+
+static void
+test_peer_invalid_conn_addr_async (void)
+{
+  if (!g_test_undefined ())
+    {
+      g_test_skip ("Not exercising programming errors");
+      return;
+    }
+
+  if (g_test_subprocess ())
+    {
+      g_dbus_connection_new_for_address ("tcp:",
+                                         (GDBusConnectionFlags) (1 << 30),
+                                         NULL, NULL, NULL, NULL);
+    }
+  else
+    {
+      g_test_trap_subprocess (NULL, 0, 0);
+      g_test_trap_assert_failed ();
+      g_test_trap_assert_stderr ("*CRITICAL*G_DBUS_CONNECTION_FLAGS_ALL*");
+    }
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
 static void
 test_peer_signals (void)
 {
@@ -2010,6 +2187,16 @@ main (int   argc,
   test_interface_introspection_data = introspection_data->interfaces[0];
 
   g_test_add_func ("/gdbus/peer-to-peer", test_peer);
+  g_test_add_func ("/gdbus/peer-to-peer/invalid/server",
+                   test_peer_invalid_server);
+  g_test_add_func ("/gdbus/peer-to-peer/invalid/conn/stream/async",
+                   test_peer_invalid_conn_stream_async);
+  g_test_add_func ("/gdbus/peer-to-peer/invalid/conn/stream/sync",
+                   test_peer_invalid_conn_stream_sync);
+  g_test_add_func ("/gdbus/peer-to-peer/invalid/conn/addr/async",
+                   test_peer_invalid_conn_addr_async);
+  g_test_add_func ("/gdbus/peer-to-peer/invalid/conn/addr/sync",
+                   test_peer_invalid_conn_addr_sync);
   g_test_add_func ("/gdbus/peer-to-peer/signals", test_peer_signals);
   g_test_add_func ("/gdbus/delayed-message-processing", delayed_message_processing);
   g_test_add_func ("/gdbus/nonce-tcp", test_nonce_tcp);
index baadca8..6e5a6d3 100644 (file)
@@ -1740,6 +1740,14 @@ key_changed_cb (GSettings *settings, const gchar *key, gpointer data)
   (*b) = TRUE;
 }
 
+typedef struct
+{
+  const gchar *path;
+  const gchar *root_group;
+  const gchar *keyfile_group;
+  const gchar *root_path;
+} KeyfileTestData;
+
 /*
  * Test that using a keyfile works
  */
@@ -1834,7 +1842,11 @@ test_keyfile (Fixture       *fixture,
   g_free (str);
 
   g_settings_set (settings, "farewell", "s", "cheerio");
-  
+
+  /* Check that empty keys/groups are not allowed. */
+  g_assert_false (g_settings_is_writable (settings, ""));
+  g_assert_false (g_settings_is_writable (settings, "/"));
+
   /* When executing as root, changing the mode of the keyfile will have
    * no effect on the writability of the settings.
    */
@@ -1866,6 +1878,149 @@ test_keyfile (Fixture       *fixture,
   g_free (keyfile_path);
 }
 
+/*
+ * Test that using a keyfile works with a schema with no path set.
+ */
+static void
+test_keyfile_no_path (Fixture       *fixture,
+                      gconstpointer  user_data)
+{
+  const KeyfileTestData *test_data = user_data;
+  GSettingsBackend *kf_backend;
+  GSettings *settings;
+  GKeyFile *keyfile;
+  gboolean writable;
+  gchar *key = NULL;
+  GError *error = NULL;
+  gchar *keyfile_path = NULL, *store_path = NULL;
+
+  keyfile_path = g_build_filename (fixture->tmp_dir, "keyfile", NULL);
+  store_path = g_build_filename (keyfile_path, "gsettings.store", NULL);
+  kf_backend = g_keyfile_settings_backend_new (store_path, test_data->root_path, test_data->root_group);
+  settings = g_settings_new_with_backend_and_path ("org.gtk.test.no-path", kf_backend, test_data->path);
+  g_object_unref (kf_backend);
+
+  g_settings_reset (settings, "test-boolean");
+  g_assert_true (g_settings_get_boolean (settings, "test-boolean"));
+
+  writable = g_settings_is_writable (settings, "test-boolean");
+  g_assert_true (writable);
+  g_settings_set (settings, "test-boolean", "b", FALSE);
+
+  g_assert_false (g_settings_get_boolean (settings, "test-boolean"));
+
+  g_settings_delay (settings);
+  g_settings_set (settings, "test-boolean", "b", TRUE);
+  g_settings_apply (settings);
+
+  keyfile = g_key_file_new ();
+  g_assert_true (g_key_file_load_from_file (keyfile, store_path, 0, NULL));
+
+  g_assert_true (g_key_file_get_boolean (keyfile, test_data->keyfile_group, "test-boolean", NULL));
+
+  g_key_file_free (keyfile);
+
+  g_settings_reset (settings, "test-boolean");
+  g_settings_apply (settings);
+  keyfile = g_key_file_new ();
+  g_assert_true (g_key_file_load_from_file (keyfile, store_path, 0, NULL));
+
+  g_assert_false (g_key_file_get_string (keyfile, test_data->keyfile_group, "test-boolean", &error));
+  g_assert_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_KEY_NOT_FOUND);
+  g_clear_error (&error);
+
+  /* Check that empty keys/groups are not allowed. */
+  g_assert_false (g_settings_is_writable (settings, ""));
+  g_assert_false (g_settings_is_writable (settings, "/"));
+
+  /* Keys which ghost the root group name are not allowed. This can only be
+   * tested when the path is `/` as otherwise it acts as a prefix and prevents
+   * any ghosting. */
+  if (g_str_equal (test_data->path, "/"))
+    {
+      key = g_strdup_printf ("%s/%s", test_data->root_group, "");
+      g_assert_false (g_settings_is_writable (settings, key));
+      g_free (key);
+
+      key = g_strdup_printf ("%s/%s", test_data->root_group, "/");
+      g_assert_false (g_settings_is_writable (settings, key));
+      g_free (key);
+
+      key = g_strdup_printf ("%s/%s", test_data->root_group, "test-boolean");
+      g_assert_false (g_settings_is_writable (settings, key));
+      g_free (key);
+    }
+
+  g_key_file_free (keyfile);
+  g_object_unref (settings);
+
+  /* Clean up the temporary directory. */
+  g_assert_no_errno (g_chmod (keyfile_path, 0777));
+  g_assert_no_errno (g_remove (store_path));
+  g_assert_no_errno (g_rmdir (keyfile_path));
+  g_free (store_path);
+  g_free (keyfile_path);
+}
+
+/*
+ * Test that a keyfile rejects writes to keys outside its root path.
+ */
+static void
+test_keyfile_outside_root_path (Fixture       *fixture,
+                                gconstpointer  user_data)
+{
+  GSettingsBackend *kf_backend;
+  GSettings *settings;
+  gchar *keyfile_path = NULL, *store_path = NULL;
+
+  keyfile_path = g_build_filename (fixture->tmp_dir, "keyfile", NULL);
+  store_path = g_build_filename (keyfile_path, "gsettings.store", NULL);
+  kf_backend = g_keyfile_settings_backend_new (store_path, "/tests/basic-types/", "root");
+  settings = g_settings_new_with_backend_and_path ("org.gtk.test.no-path", kf_backend, "/tests/");
+  g_object_unref (kf_backend);
+
+  g_assert_false (g_settings_is_writable (settings, "test-boolean"));
+
+  g_object_unref (settings);
+
+  /* Clean up the temporary directory. The keyfile probably doesn’t exist, so
+   * don’t error on failure. */
+  g_remove (store_path);
+  g_assert_no_errno (g_rmdir (keyfile_path));
+  g_free (store_path);
+  g_free (keyfile_path);
+}
+
+/*
+ * Test that a keyfile rejects writes to keys in the root if no root group is set.
+ */
+static void
+test_keyfile_no_root_group (Fixture       *fixture,
+                            gconstpointer  user_data)
+{
+  GSettingsBackend *kf_backend;
+  GSettings *settings;
+  gchar *keyfile_path = NULL, *store_path = NULL;
+
+  keyfile_path = g_build_filename (fixture->tmp_dir, "keyfile", NULL);
+  store_path = g_build_filename (keyfile_path, "gsettings.store", NULL);
+  kf_backend = g_keyfile_settings_backend_new (store_path, "/", NULL);
+  settings = g_settings_new_with_backend_and_path ("org.gtk.test.no-path", kf_backend, "/");
+  g_object_unref (kf_backend);
+
+  g_assert_false (g_settings_is_writable (settings, "test-boolean"));
+  g_assert_true (g_settings_is_writable (settings, "child/test-boolean"));
+
+  g_object_unref (settings);
+
+  /* Clean up the temporary directory. The keyfile probably doesn’t exist, so
+   * don’t error on failure. */
+  g_remove (store_path);
+  g_assert_no_errno (g_rmdir (keyfile_path));
+  g_free (store_path);
+  g_free (keyfile_path);
+}
+
 /* Test that getting child schemas works
  */
 static void
@@ -2844,6 +2999,14 @@ main (int argc, char *argv[])
   gchar *override_text;
   gchar *enums;
   gint result;
+  const KeyfileTestData keyfile_test_data_explicit_path = { "/tests/", "root", "tests", "/" };
+  const KeyfileTestData keyfile_test_data_empty_path = { "/", "root", "root", "/" };
+  const KeyfileTestData keyfile_test_data_long_path = {
+    "/tests/path/is/very/long/and/this/makes/some/comparisons/take/a/different/branch/",
+    "root",
+    "tests/path/is/very/long/and/this/makes/some/comparisons/take/a/different/branch",
+    "/"
+  };
 
 /* Meson build sets this */
 #ifdef TEST_LOCALE_PATH
@@ -2967,6 +3130,11 @@ main (int argc, char *argv[])
     }
 
   g_test_add ("/gsettings/keyfile", Fixture, NULL, setup, test_keyfile, teardown);
+  g_test_add ("/gsettings/keyfile/explicit-path", Fixture, &keyfile_test_data_explicit_path, setup, test_keyfile_no_path, teardown);
+  g_test_add ("/gsettings/keyfile/empty-path", Fixture, &keyfile_test_data_empty_path, setup, test_keyfile_no_path, teardown);
+  g_test_add ("/gsettings/keyfile/long-path", Fixture, &keyfile_test_data_long_path, setup, test_keyfile_no_path, teardown);
+  g_test_add ("/gsettings/keyfile/outside-root-path", Fixture, NULL, setup, test_keyfile_outside_root_path, teardown);
+  g_test_add ("/gsettings/keyfile/no-root-group", Fixture, NULL, setup, test_keyfile_no_root_group, teardown);
   g_test_add_func ("/gsettings/child-schema", test_child_schema);
   g_test_add_func ("/gsettings/strinfo", test_strinfo);
   g_test_add_func ("/gsettings/enums", test_enums);
index 4f0737d..5661e8e 100644 (file)
@@ -174,6 +174,38 @@ test_interaction_ask_password_finish_failure (GTlsInteraction    *interaction,
 }
 
 
+/* Return a copy of @str that is allocated in a silly way, to exercise
+ * custom free-functions. The returned pointer points to a copy of @str
+ * in a buffer of the form "BEFORE \0 str \0 AFTER". */
+static guchar *
+special_dup (const char *str)
+{
+  GString *buf = g_string_new ("BEFORE");
+  guchar *ret;
+
+  g_string_append_c (buf, '\0');
+  g_string_append (buf, str);
+  g_string_append_c (buf, '\0');
+  g_string_append (buf, "AFTER");
+  ret = (guchar *) g_string_free (buf, FALSE);
+  return ret + strlen ("BEFORE") + 1;
+}
+
+
+/* Free a copy of @str that was made with special_dup(), after asserting
+ * that it has not been corrupted. */
+static void
+special_free (gpointer p)
+{
+  gchar *s = p;
+  gchar *buf = s - strlen ("BEFORE") - 1;
+
+  g_assert_cmpstr (buf, ==, "BEFORE");
+  g_assert_cmpstr (s + strlen (s) + 1, ==, "AFTER");
+  g_free (buf);
+}
+
+
 static GTlsInteractionResult
 test_interaction_ask_password_sync_success (GTlsInteraction    *interaction,
                                             GTlsPassword       *password,
@@ -181,6 +213,8 @@ test_interaction_ask_password_sync_success (GTlsInteraction    *interaction,
                                             GError            **error)
 {
   TestInteraction *self;
+  const guchar *value;
+  gsize len;
 
   g_assert (TEST_IS_INTERACTION (interaction));
   self = TEST_INTERACTION (interaction);
@@ -192,6 +226,27 @@ test_interaction_ask_password_sync_success (GTlsInteraction    *interaction,
   g_assert (error != NULL);
   g_assert (*error == NULL);
 
+  /* Exercise different ways to set the value */
+  g_tls_password_set_value (password, (const guchar *) "foo", 4);
+  len = 0;
+  value = g_tls_password_get_value (password, &len);
+  g_assert_cmpmem (value, len, "foo", 4);
+
+  g_tls_password_set_value (password, (const guchar *) "bar", -1);
+  len = 0;
+  value = g_tls_password_get_value (password, &len);
+  g_assert_cmpmem (value, len, "bar", 3);
+
+  g_tls_password_set_value_full (password, special_dup ("baa"), 4, special_free);
+  len = 0;
+  value = g_tls_password_get_value (password, &len);
+  g_assert_cmpmem (value, len, "baa", 4);
+
+  g_tls_password_set_value_full (password, special_dup ("baz"), -1, special_free);
+  len = 0;
+  value = g_tls_password_get_value (password, &len);
+  g_assert_cmpmem (value, len, "baz", 3);
+
   /* Don't do this in real life. Include a null terminator for testing */
   g_tls_password_set_value (password, (const guchar *)"the password", 13);
   return G_TLS_INTERACTION_HANDLED;
index 4b6de19..d09c904 100644 (file)
@@ -2261,6 +2261,10 @@ g_byte_array_steal (GByteArray *array,
  * 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 @@ g_byte_array_new_take (guint8 *data,
   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);
index 6f17d10..5293869 100644 (file)
@@ -521,6 +521,10 @@ g_bytes_unref_to_data (GBytes *bytes,
  * 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
index 4dec20f..19bb06b 100644 (file)
@@ -900,13 +900,13 @@ g_io_channel_set_line_term (GIOChannel    *channel,
     {
       /* FIXME: We’re constrained by line_term_len being a guint here */
       gsize length_size = strlen (line_term);
-      g_return_if_fail (length_size > G_MAXUINT);
+      g_return_if_fail (length_size <= G_MAXUINT);
       length_unsigned = (guint) length_size;
     }
 
   g_free (channel->line_term);
   channel->line_term = line_term ? g_memdup2 (line_term, length_unsigned) : NULL;
-  channel->line_term_len = length;
+  channel->line_term_len = length_unsigned;
 }
 
 /**
index a65d3a9..f6e4403 100644 (file)
  */
 
 #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 @@ test_to_array_transferred (void)
 }
 
 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 @@ main (int argc, char *argv[])
   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);
index ff53fce..4a1b108 100644 (file)
@@ -49,8 +49,10 @@ test_read_line_embedded_nuls (void)
   channel = g_io_channel_new_file (filename, "r", &local_error);
   g_assert_no_error (local_error);
 
-  /* Only break on newline characters, not nuls. */
-  g_io_channel_set_line_term (channel, "\n", 1);
+  /* Only break on newline characters, not nuls.
+   * Use length -1 here to exercise glib#2323; the case where length > 0
+   * is covered in glib/tests/protocol.c. */
+  g_io_channel_set_line_term (channel, "\n", -1);
   g_io_channel_set_encoding (channel, NULL, &local_error);
   g_assert_no_error (local_error);
 
index ac9f739..aee9656 100644 (file)
@@ -1,5 +1,5 @@
 project('glib', 'c', 'cpp',
-  version : '2.66.6',
+  version : '2.66.7',
   # NOTE: We keep this pinned at 0.49 because that's what Debian 10 ships
   meson_version : '>= 0.49.2',
   default_options : [