Merge branch 'upstream' into tizen 64/265664/3
authorMateusz Majewski <m.majewski2@samsung.com>
Mon, 8 Nov 2021 10:23:16 +0000 (11:23 +0100)
committerMateusz Majewski <m.majewski2@samsung.com>
Mon, 8 Nov 2021 10:23:16 +0000 (11:23 +0100)
Note: glib/gbytes.c contains a particularly nontrivial merge conflict
resolution inside the g_bytes_get_region function.

Change-Id: Ifea638440da0f0094c3c79e51559c9598d7f6a1d

44 files changed:
1  2 
NEWS
docs/reference/glib/glib-sections.txt
docs/reference/glib/gvariant-text.xml
gio/gapplicationimpl-dbus.c
gio/gdbusaddress.c
gio/gdbusconnection.c
gio/gdbusconnection.h
gio/gdbusintrospection.h
gio/gdbusmessage.c
gio/gdbusmethodinvocation.c
gio/gdbusmethodinvocation.h
gio/gdbusnamewatching.c
gio/gdbusobjectmanagerclient.c
gio/gdbusprivate.c
gio/gdbusprivate.h
gio/gdbusproxy.c
gio/gdbusutils.c
gio/gdbusutils.h
gio/gioenums.h
gio/meson.build
glib/gbytes.c
glib/gbytes.h
glib/glib-autocleanups.h
glib/glib-private.c
glib/glib-private.h
glib/glib-unix.c
glib/glib-unix.h
glib/gmessages.h
glib/gtestutils.c
glib/gtestutils.h
glib/gutils.c
glib/gvariant-core.c
glib/gvariant-core.h
glib/gvariant-parser.c
glib/gvariant-serialiser.c
glib/gvariant.c
glib/gvariant.h
glib/gvarianttype.c
glib/gvarianttypeinfo.c
glib/meson.build
glib/tests/bytes.c
glib/tests/gvariant.c
meson_options.txt
packaging/glib2.spec

diff --cc NEWS
Simple merge
@@@ -2422,8 -2571,10 +2573,11 @@@ GUnixFDSourceFun
  g_unix_fd_add
  g_unix_fd_add_full
  g_unix_fd_source_new
 +g_unix_fd_ensure_zero_copy_safe
  
+ <SUBSECTION>
+ g_unix_get_passwd_entry
  <SUBSECTION Private>
  g_unix_error_quark
  </SECTION>
@@@ -2881,8 -3037,8 +3041,9 @@@ g_bytes_new_stati
  g_bytes_new_with_free_func
  g_bytes_new_from_bytes
  g_bytes_get_data
+ g_bytes_get_region
  g_bytes_get_size
 +g_bytes_get_zero_copy_fd
  g_bytes_hash
  g_bytes_equal
  g_bytes_compare
Simple merge
@@@ -361,15 -361,18 +361,17 @@@ g_application_impl_attempt_primary (GAp
                                      GCancellable      *cancellable,
                                      GError           **error)
  {
-   const static GDBusInterfaceVTable vtable = {
+   static const GDBusInterfaceVTable vtable = {
      g_application_impl_method_call,
      g_application_impl_get_property,
-     NULL /* set_property */
+     NULL, /* set_property */
+     { 0 }
    };
    GApplicationClass *app_class = G_APPLICATION_GET_CLASS (impl->app);
 +  GBusRequestNameReplyFlags rval;
    GBusNameOwnerFlags name_owner_flags;
    GApplicationFlags app_flags;
 -  GVariant *reply;
 -  guint32 rval;
+   GError *local_error = NULL;
  
    if (org_gtk_Application == NULL)
      {
@@@ -1386,22 -1330,26 +1404,30 @@@ g_dbus_address_get_for_bus_sync (GBusTy
    switch (bus_type)
      {
      case G_BUS_TYPE_SYSTEM:
-       ret = g_strdup (g_getenv ("DBUS_SYSTEM_BUS_ADDRESS"));
+       if (has_elevated_privileges)
+         ret = NULL;
+       else
+         ret = g_strdup (g_getenv ("DBUS_SYSTEM_BUS_ADDRESS"));
        if (ret == NULL)
          {
 -          ret = g_strdup ("unix:path=/var/run/dbus/system_bus_socket");
 +          ret = g_strdup ("kernel:path=/sys/fs/kdbus/0-system/bus;unix:path=/var/run/dbus/system_bus_socket");
          }
        break;
  
      case G_BUS_TYPE_SESSION:
-       ret = g_strdup (g_getenv ("DBUS_SESSION_BUS_ADDRESS"));
+       if (has_elevated_privileges)
+         ret = NULL;
+       else
+         ret = g_strdup (g_getenv ("DBUS_SESSION_BUS_ADDRESS"));
        if (ret == NULL)
          {
 -          ret = get_session_address_platform_specific (&local_error);
 +          ret = get_session_address_kdbus ();
 +          if (ret == NULL)
 +            ret = get_session_address_platform_specific (&local_error);
 +          if (ret == NULL)
 +            goto out;
          }
        break;
  
index d653ad9,d730111..339a198
mode 100755,100644..100755
@@@ -2313,9 -1613,8 +2321,9 @@@ static gboolea
  g_dbus_connection_send_message_unlocked (GDBusConnection   *connection,
                                           GDBusMessage      *message,
                                           GDBusSendMessageFlags flags,
-                                          volatile guint32  *out_serial,
+                                          guint32           *out_serial,
 -                                         GError           **error)
 +                                         GError           **error,
 +                                         gint timeout_msec)
  {
    guchar *blob;
    gsize blob_size;
@@@ -2477,7 -1751,7 +2487,7 @@@ g_dbus_connection_send_message (GDBusCo
    g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
  
    CONNECTION_LOCK (connection);
-   ret = g_dbus_connection_send_message_unlocked (connection, message, flags, out_serial, error, -1);
 -  ret = g_dbus_connection_send_message_unlocked (connection, message, flags, (guint32 *) out_serial, error);
++  ret = g_dbus_connection_send_message_unlocked (connection, message, flags, (guint32 *) out_serial, error, -1);
    CONNECTION_UNLOCK (connection);
    return ret;
  }
@@@ -8092,12 -7194,23 +8173,23 @@@ distribute_method_call (GDBusConnectio
      goto out;
  
    /* if we end up here, the message has not been not handled - so return an error saying this */
-   reply = g_dbus_message_new_method_error (message,
+   if (object_found == TRUE)
+     {
+       reply = g_dbus_message_new_method_error (message,
+                                                "org.freedesktop.DBus.Error.UnknownMethod",
+                                                _("No such interface “%s” on object at path %s"),
+                                                interface_name,
+                                                object_path);
+     }
+   else
+     {
+       reply = g_dbus_message_new_method_error (message,
                                             "org.freedesktop.DBus.Error.UnknownMethod",
-                                            _("No such interface “%s” on object at path %s"),
-                                            interface_name,
+                                            _("Object does not exist at path “%s”"),
                                             object_path);
 -  g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
+     }
 +  g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL, -1);
    g_object_unref (reply);
  
   out:
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -34,33 -33,63 +34,68 @@@ G_BEGIN_DECL
  #define G_DBUS_METHOD_INVOCATION(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_DBUS_METHOD_INVOCATION, GDBusMethodInvocation))
  #define G_IS_DBUS_METHOD_INVOCATION(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_DBUS_METHOD_INVOCATION))
  
+ /**
+  * G_DBUS_METHOD_INVOCATION_HANDLED:
+  *
+  * The value returned by handlers of the signals generated by
+  * the `gdbus-codegen` tool to indicate that a method call has been
+  * handled by an implementation. It is equal to %TRUE, but using
+  * this macro is sometimes more readable.
+  *
+  * In code that needs to be backwards-compatible with older GLib,
+  * use %TRUE instead, often written like this:
+  *
+  * |[
+  *   g_dbus_method_invocation_return_error (invocation, ...);
+  *   return TRUE;    // handled
+  * ]|
+  *
+  * Since: 2.68
+  */
+ #define G_DBUS_METHOD_INVOCATION_HANDLED TRUE GLIB_AVAILABLE_MACRO_IN_2_68
+ /**
+  * G_DBUS_METHOD_INVOCATION_UNHANDLED:
+  *
+  * The value returned by handlers of the signals generated by
+  * the `gdbus-codegen` tool to indicate that a method call has not been
+  * handled by an implementation. It is equal to %FALSE, but using
+  * this macro is sometimes more readable.
+  *
+  * In code that needs to be backwards-compatible with older GLib,
+  * use %FALSE instead.
+  *
+  * Since: 2.68
+  */
+ #define G_DBUS_METHOD_INVOCATION_UNHANDLED FALSE GLIB_AVAILABLE_MACRO_IN_2_68
  GLIB_AVAILABLE_IN_ALL
 -GType                  g_dbus_method_invocation_get_type             (void) G_GNUC_CONST;
 +GType                  g_dbus_method_invocation_get_type             (void) G_GNUC_CONST TIZEN_PUBLIC_DEPRECATED_API;
  GLIB_AVAILABLE_IN_ALL
 -const gchar           *g_dbus_method_invocation_get_sender           (GDBusMethodInvocation *invocation);
 +const gchar           *g_dbus_method_invocation_get_sender           (GDBusMethodInvocation *invocation) TIZEN_PUBLIC_DEPRECATED_API;
  GLIB_AVAILABLE_IN_ALL
 -const gchar           *g_dbus_method_invocation_get_object_path      (GDBusMethodInvocation *invocation);
 +const gchar           *g_dbus_method_invocation_get_object_path      (GDBusMethodInvocation *invocation) TIZEN_PUBLIC_DEPRECATED_API;
  GLIB_AVAILABLE_IN_ALL
 -const gchar           *g_dbus_method_invocation_get_interface_name   (GDBusMethodInvocation *invocation);
 +const gchar           *g_dbus_method_invocation_get_interface_name   (GDBusMethodInvocation *invocation) TIZEN_PUBLIC_DEPRECATED_API;
  GLIB_AVAILABLE_IN_ALL
 -const gchar           *g_dbus_method_invocation_get_method_name      (GDBusMethodInvocation *invocation);
 +const gchar           *g_dbus_method_invocation_get_method_name      (GDBusMethodInvocation *invocation) TIZEN_PUBLIC_DEPRECATED_API;
  GLIB_AVAILABLE_IN_ALL
 -const GDBusMethodInfo *g_dbus_method_invocation_get_method_info      (GDBusMethodInvocation *invocation);
 +const GDBusMethodInfo *g_dbus_method_invocation_get_method_info      (GDBusMethodInvocation *invocation) TIZEN_PUBLIC_DEPRECATED_API;
  GLIB_AVAILABLE_IN_2_38
 -const GDBusPropertyInfo *g_dbus_method_invocation_get_property_info  (GDBusMethodInvocation *invocation);
 +const GDBusPropertyInfo *g_dbus_method_invocation_get_property_info  (GDBusMethodInvocation *invocation) TIZEN_PUBLIC_DEPRECATED_API;
  GLIB_AVAILABLE_IN_ALL
 -GDBusConnection       *g_dbus_method_invocation_get_connection       (GDBusMethodInvocation *invocation);
 +GDBusConnection       *g_dbus_method_invocation_get_connection       (GDBusMethodInvocation *invocation) TIZEN_PUBLIC_DEPRECATED_API;
  GLIB_AVAILABLE_IN_ALL
 -GDBusMessage          *g_dbus_method_invocation_get_message          (GDBusMethodInvocation *invocation);
 +GDBusMessage          *g_dbus_method_invocation_get_message          (GDBusMethodInvocation *invocation) TIZEN_PUBLIC_DEPRECATED_API;
  GLIB_AVAILABLE_IN_ALL
 -GVariant              *g_dbus_method_invocation_get_parameters       (GDBusMethodInvocation *invocation);
 +GVariant              *g_dbus_method_invocation_get_parameters       (GDBusMethodInvocation *invocation) TIZEN_PUBLIC_DEPRECATED_API;
 +#ifdef G_OS_UNIX
 +GLIB_AVAILABLE_IN_2_44
 +gint                   g_dbus_method_invocation_peek_unix_fd         (GDBusMethodInvocation *invocation,
 +                                                                      guint                  index_) TIZEN_PUBLIC_DEPRECATED_API;
 +#endif
  GLIB_AVAILABLE_IN_ALL
 -gpointer               g_dbus_method_invocation_get_user_data        (GDBusMethodInvocation *invocation);
 +gpointer               g_dbus_method_invocation_get_user_data        (GDBusMethodInvocation *invocation) TIZEN_PUBLIC_DEPRECATED_API;
  
  GLIB_AVAILABLE_IN_ALL
  void                   g_dbus_method_invocation_return_value         (GDBusMethodInvocation *invocation,
index 7ca294d,d4272e4..ef6481f
mode 100755,100644..100755
@@@ -400,13 -418,13 +428,13 @@@ get_name_owner_cb (GObject      *source
      }
    else
      {
-       call_vanished_handler (client, FALSE);
+       call_vanished_handler (client);
      }
  
 -  client->initialized = TRUE;
 -
 + out:
    if (result != NULL)
      g_variant_unref (result);
 +
    client_unref (client);
  }
  
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
  G_BEGIN_DECLS
  
  GLIB_AVAILABLE_IN_ALL
 -gboolean g_dbus_is_guid (const gchar *string);
 +gboolean g_dbus_is_guid (const gchar *string) TIZEN_PUBLIC_DEPRECATED_API;
  GLIB_AVAILABLE_IN_ALL
 -gchar *g_dbus_generate_guid (void);
 +gchar *g_dbus_generate_guid (void) TIZEN_PUBLIC_DEPRECATED_API;
  
  GLIB_AVAILABLE_IN_ALL
 -gboolean g_dbus_is_name (const gchar *string);
 +gboolean g_dbus_is_name (const gchar *string) TIZEN_PUBLIC_DEPRECATED_API;
  GLIB_AVAILABLE_IN_ALL
 -gboolean g_dbus_is_unique_name (const gchar *string);
 +gboolean g_dbus_is_unique_name (const gchar *string) TIZEN_PUBLIC_DEPRECATED_API;
  GLIB_AVAILABLE_IN_ALL
 -gboolean g_dbus_is_member_name (const gchar *string);
 +gboolean g_dbus_is_member_name (const gchar *string) TIZEN_PUBLIC_DEPRECATED_API;
  GLIB_AVAILABLE_IN_ALL
 -gboolean g_dbus_is_interface_name (const gchar *string);
 +gboolean g_dbus_is_interface_name (const gchar *string) TIZEN_PUBLIC_DEPRECATED_API;
+ GLIB_AVAILABLE_IN_2_70
+ gboolean g_dbus_is_error_name (const gchar *string);
  
  GLIB_AVAILABLE_IN_ALL
  void g_dbus_gvariant_to_gvalue (GVariant  *value,
 -                                GValue    *out_gvalue);
 +                                GValue    *out_gvalue) TIZEN_PUBLIC_DEPRECATED_API;
  GLIB_AVAILABLE_IN_ALL
  GVariant *g_dbus_gvalue_to_gvariant (const GValue         *gvalue,
 -                                     const GVariantType   *type);
 +                                     const GVariantType   *type) TIZEN_PUBLIC_DEPRECATED_API;
+ GLIB_AVAILABLE_IN_2_68
+ gchar *g_dbus_escape_object_path_bytestring (const guint8 *bytes);
+ GLIB_AVAILABLE_IN_2_68
+ gchar *g_dbus_escape_object_path (const gchar *s);
+ GLIB_AVAILABLE_IN_2_68
+ guint8 *g_dbus_unescape_object_path (const gchar *s);
  
  G_END_DECLS
  
diff --cc gio/gioenums.h
Simple merge
diff --cc gio/meson.build
@@@ -828,7 -816,7 +834,7 @@@ libgio = library('gio-2.0'
    #  '$(gio_win32_res_ldflag)',
    dependencies : [libz_dep, libdl_dep, libmount_dep, libglib_dep,
                    libgobject_dep, libgmodule_dep, selinux_dep, xattr_dep,
-                   platform_deps, network_libs, libdbuspolicy_dep],
 -                  platform_deps, network_libs, libsysprof_capture_dep],
++                  platform_deps, network_libs, libdbuspolicy_dep, libsysprof_capture_dep],
    c_args : gio_c_args,
    objc_args : gio_c_args,
    # intl.lib is not compatible with SAFESEH
diff --cc glib/gbytes.c
@@@ -765,3 -538,75 +769,78 @@@ g_bytes_unref_to_array (GBytes *bytes
    data = g_bytes_unref_to_data (bytes, &size);
    return g_byte_array_new_take (data, size);
  }
 -  return ((guchar *) bytes->data) + offset;
 -}
+ /**
+  * g_bytes_get_region:
+  * @bytes: a #GBytes
+  * @element_size: a non-zero element size
+  * @offset: an offset to the start of the region within the @bytes
+  * @n_elements: the number of elements in the region
+  *
+  * Gets a pointer to a region in @bytes.
+  *
+  * The region starts at @offset many bytes from the start of the data
+  * and contains @n_elements many elements of @element_size size.
+  *
+  * @n_elements may be zero, but @element_size must always be non-zero.
+  * Ideally, @element_size is a static constant (eg: sizeof a struct).
+  *
+  * This function does careful bounds checking (including checking for
+  * arithmetic overflows) and returns a non-%NULL pointer if the
+  * specified region lies entirely within the @bytes. If the region is
+  * in some way out of range, or if an overflow has occurred, then %NULL
+  * is returned.
+  *
+  * Note: it is possible to have a valid zero-size region. In this case,
+  * the returned pointer will be equal to the base pointer of the data of
+  * @bytes, plus @offset.  This will be non-%NULL except for the case
+  * where @bytes itself was a zero-sized region.  Since it is unlikely
+  * that you will be using this function to check for a zero-sized region
+  * in a zero-sized @bytes, %NULL effectively always means "error".
+  *
+  * Returns: (nullable): the requested region, or %NULL in case of an error
+  *
+  * Since: 2.70
+  */
+ gconstpointer
+ g_bytes_get_region (GBytes *bytes,
+                     gsize   element_size,
+                     gsize   offset,
+                     gsize   n_elements)
+ {
+   gsize total_size;
+   gsize end_offset;
+   g_return_val_if_fail (element_size > 0, NULL);
+   /* No other assertion checks here.  If something is wrong then we will
+    * simply crash (via NULL dereference or divide-by-zero).
+    */
+   if (!g_size_checked_mul (&total_size, element_size, n_elements))
+     return NULL;
+   if (!g_size_checked_add (&end_offset, offset, total_size))
+     return NULL;
+   /* We now have:
+    *
+    *   0 <= offset <= end_offset
+    *
+    * So we need only check that end_offset is within the range of the
+    * size of @bytes and we're good to go.
+    */
+   if (end_offset > bytes->size)
+     return NULL;
+   /* We now have:
+    *
+    *   0 <= offset <= end_offset <= bytes->size
+    */
++  /* NB: The following line has been adapted to the kdbus rework by Mateusz
++   * and not by a competent programmer. Tread with caution!
++   */
++  return ((guchar *) g_bytes_get_data (bytes, NULL)) + offset;
++}
diff --cc glib/gbytes.h
Simple merge
@@@ -29,12 -29,16 +29,16 @@@ g_autoptr_cleanup_generic_gfree (void *
  }
  
  static inline void
 -g_autoptr_cleanup_gstring_free (GString *string)
 +g_autoptr_cleanup_gstring_free (GString *__string__)
  {
 -  if (string)
 -    g_string_free (string, TRUE);
 +  if (__string__)
 +    g_string_free (__string__, TRUE);
  }
  
+ /* Ignore deprecations in case we refer to a type which was added in a more
+  * recent GLib version than the user’s #GLIB_VERSION_MAX_ALLOWED definition. */
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
  /* If adding a cleanup here, please also add a test case to
   * glib/tests/autoptr.c
   */
Simple merge
  
  #include <glib.h>
  #include "gwakeup.h"
 +#include "gvariant-vectors.h"
  #include "gstdioprivate.h"
  
+ /* gcc defines __SANITIZE_ADDRESS__, clang sets the address_sanitizer
+  * feature flag */
+ #if defined(__SANITIZE_ADDRESS__) || g_macro__has_feature(address_sanitizer)
+ /*
+  * %_GLIB_ADDRESS_SANITIZER:
+  *
+  * Private macro defined if the AddressSanitizer is in use.
+  */
+ #define _GLIB_ADDRESS_SANITIZER
+ #include <sanitizer/lsan_interface.h>
+ #endif
+ /*
+  * g_ignore_leak:
+  * @p: any pointer
+  *
+  * Tell AddressSanitizer and similar tools that if the object pointed to
+  * by @p is leaked, it is not a problem. Use this to suppress memory leak
+  * reports when a potentially unreachable pointer is deliberately not
+  * going to be deallocated.
+  */
+ static inline void
+ g_ignore_leak (gconstpointer p)
+ {
+ #ifdef _GLIB_ADDRESS_SANITIZER
+   if (p != NULL)
+     __lsan_ignore_object (p);
+ #endif
+ }
+ /*
+  * g_ignore_strv_leak:
+  * @strv: (nullable) (array zero-terminated=1): an array of strings
+  *
+  * The same as g_ignore_leak(), but for the memory pointed to by @strv,
+  * and for each element of @strv.
+  */
+ static inline void
+ g_ignore_strv_leak (GStrv strv)
+ {
+ #ifdef _GLIB_ADDRESS_SANITIZER
+   gchar **item;
+   if (strv)
+     {
+       g_ignore_leak (strv);
+       for (item = strv; *item != NULL; item++)
+         g_ignore_leak (*item);
+     }
+ #endif
+ }
  GMainContext *          g_get_worker_context            (void);
  gboolean                g_check_setuid                  (void);
  GMainContext *          g_main_context_new_with_next_id (guint next_id);
  #include "gmain-internal.h"
  
  #include <string.h>
+ #include <sys/types.h>
+ #include <pwd.h>
+ G_STATIC_ASSERT (sizeof (ssize_t) == GLIB_SIZEOF_SSIZE_T);
+ G_STATIC_ASSERT (G_ALIGNOF (gssize) == G_ALIGNOF (ssize_t));
+ G_STATIC_ASSERT (sizeof (GPid) == sizeof (pid_t));
+ G_STATIC_ASSERT (G_ALIGNOF (GPid) == G_ALIGNOF (pid_t));
  
 +#include <fcntl.h>
 +#include <sys/syscall.h>
 +#include <unistd.h>
 +
 +#ifdef __linux__
 +
 +/* We want to support these features of Linux even when building GLib
 + * against older versions of system headers.  This will allow us to
 + * 'automatically' start supporting a particular feature when GLib is
 + * used with a newer kernel, without recompile.
 + *
 + * This means that we're not changing functionality of GLib simply based
 + * on the set of headers we happen to compile against...
 + */
 +
 +#ifndef F_LINUX_SPECIFIC_BASE
 +#define F_LINUX_SPECIFIC_BASE 1024
 +#endif
 +
 +#ifndef F_ADD_SEALS
 +#define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9)
 +#define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10)
 +
 +#define F_SEAL_SEAL     0x0001  /* prevent further seals from being set */
 +#define F_SEAL_SHRINK   0x0002  /* prevent file from shrinking */
 +#define F_SEAL_GROW     0x0004  /* prevent file from growing */
 +#define F_SEAL_WRITE    0x0008  /* prevent writes */
 +#endif
 +
 +#endif
 +
  /**
   * SECTION:gunix
   * @title: UNIX-specific utilities and integration
@@@ -454,60 -431,120 +462,179 @@@ g_unix_fd_add (gint              fd
  }
  
  /**
 + * g_unix_fd_ensure_zero_copy_safe:
 + * @fd: a file descriptor
 + *
 + * Checks whether @fd can be use in zero-copy mode. On Linux, this checks that
 + * the descriptor is a memfd, created with memfd_create(), and tries to apply
 + * seals to it so that it can be safely consumed by another process. On other
 + * Unix systems, this function will fail.
 + *
 + * Returns: whether the fd is safe to use in zero-copy mode. Sealing of memfds
 + *          is required for the @fd to be considered safe. If sealing fails, or
 + *          memfds are not available, or the @fd is not a memfd, returns %FALSE
 + *
 + * Since: 2.44
 + **/
 +gboolean
 +g_unix_fd_ensure_zero_copy_safe (gint fd)
 +{
 +#ifdef F_GET_SEALS
 +  gint seals;
 +  const gint IMMUTABLE_SEALS = F_SEAL_WRITE |
 +                               F_SEAL_SHRINK |
 +                               F_SEAL_GROW |
 +                               F_SEAL_SEAL;
 +
 +  g_return_val_if_fail (fd >= 0, FALSE);
 +
 +  /* Seal the fd if possible (only on Linux 3.17+, and if the fd was created
 +   * with memfd_create()). */
 +  seals = fcntl (fd, F_GET_SEALS);
 +  if (seals == -1)
 +    {
 +      g_debug ("Retrieving fd seals failed: %s", g_strerror (errno));
 +      return FALSE;
 +    }
 +
 +  /* Seal the fd, if it is not already. */
 +  if ((seals & (IMMUTABLE_SEALS)) >= IMMUTABLE_SEALS)
 +    {
 +      g_debug ("%s", "fd already sealed");
 +    }
 +  else
 +    {
 +      gint error;
 +
 +      error = fcntl (fd, F_ADD_SEALS, IMMUTABLE_SEALS);
 +      if (error == -1)
 +        {
 +          g_debug ("fd sealing failed: %s", g_strerror (errno));
 +          return FALSE;
 +        }
 +    }
 +
 +  return TRUE;
 +#else
 +  return FALSE;
 +#endif
 +}
++
++/**
+  * g_unix_get_passwd_entry:
+  * @user_name: the username to get the passwd file entry for
+  * @error: return location for a #GError, or %NULL
+  *
+  * Get the `passwd` file entry for the given @user_name using `getpwnam_r()`.
+  * This can fail if the given @user_name doesn’t exist.
+  *
+  * The returned `struct passwd` has been allocated using g_malloc() and should
+  * be freed using g_free(). The strings referenced by the returned struct are
+  * included in the same allocation, so are valid until the `struct passwd` is
+  * freed.
+  *
+  * This function is safe to call from multiple threads concurrently.
+  *
+  * You will need to include `pwd.h` to get the definition of `struct passwd`.
+  *
+  * Returns: (transfer full): passwd entry, or %NULL on error; free the returned
+  *    value with g_free()
+  * Since: 2.64
+  */
+ struct passwd *
+ g_unix_get_passwd_entry (const gchar  *user_name,
+                          GError      **error)
+ {
+   struct passwd *passwd_file_entry;
+   struct
+     {
+       struct passwd pwd;
+       char string_buffer[];
+     } *buffer = NULL;
+   gsize string_buffer_size = 0;
+   GError *local_error = NULL;
+   int errsv = 0;
+   g_return_val_if_fail (user_name != NULL, NULL);
+   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+ #ifdef _SC_GETPW_R_SIZE_MAX
+     {
+       /* Get the recommended buffer size */
+       glong string_buffer_size_long = sysconf (_SC_GETPW_R_SIZE_MAX);
+       if (string_buffer_size_long > 0)
+         string_buffer_size = string_buffer_size_long;
+     }
+ #endif /* _SC_GETPW_R_SIZE_MAX */
+   /* Default starting size. */
+   if (string_buffer_size == 0)
+     string_buffer_size = 64;
+   do
+     {
+       int retval;
+       g_free (buffer);
+       /* Allocate space for the `struct passwd`, and then a buffer for all its
+        * strings (whose size is @string_buffer_size, which increases in this
+        * loop until it’s big enough). Add 6 extra bytes to work around a bug in
+        * macOS < 10.3. See #156446.
+        */
+       buffer = g_malloc0 (sizeof (*buffer) + string_buffer_size + 6);
+       errno = 0;
+       retval = getpwnam_r (user_name, &buffer->pwd, buffer->string_buffer,
+                            string_buffer_size, &passwd_file_entry);
+       errsv = errno;
+       /* Bail out if: the lookup was successful, or if the user id can't be
+        * found (should be pretty rare case actually), or if the buffer should be
+        * big enough and yet lookups are still not successful.
+        */
+       if (passwd_file_entry != NULL)
+         {
+           /* Success. */
+           break;
+         }
+       else if (retval == 0 ||
+           errsv == ENOENT || errsv == ESRCH ||
+           errsv == EBADF || errsv == EPERM)
+         {
+           /* Username not found. */
+           g_unix_set_error_from_errno (&local_error, errsv);
+           break;
+         }
+       else if (errsv == ERANGE)
+         {
+           /* Can’t allocate enough string buffer space. */
+           if (string_buffer_size > 32 * 1024)
+             {
+               g_unix_set_error_from_errno (&local_error, errsv);
+               break;
+             }
+           string_buffer_size *= 2;
+           continue;
+         }
+       else
+         {
+           g_unix_set_error_from_errno (&local_error, errsv);
+           break;
+         }
+     }
+   while (passwd_file_entry == NULL);
+   g_assert (passwd_file_entry == NULL ||
+             (gpointer) passwd_file_entry == (gpointer) buffer);
+   /* Success or error. */
+   if (local_error != NULL)
+     {
+       g_clear_pointer (&buffer, g_free);
+       g_propagate_error (error, g_steal_pointer (&local_error));
+       errno = errsv;
+     }
+   return (struct passwd *) g_steal_pointer (&buffer);
+ }
@@@ -114,9 -114,10 +114,13 @@@ guint    g_unix_fd_add             (gin
                                      GUnixFDSourceFunc function,
                                      gpointer          user_data);
  
 +GLIB_AVAILABLE_IN_2_44
 +gboolean g_unix_fd_ensure_zero_copy_safe (gint fd);
 +
+ GLIB_AVAILABLE_IN_2_64
+ struct passwd *g_unix_get_passwd_entry (const gchar  *user_name,
+                                         GError      **error);
  G_END_DECLS
  
  #endif  /* __G_UNIX_H__ */
Simple merge
Simple merge
Simple merge
diff --cc glib/gutils.c
Simple merge
@@@ -110,20 -109,30 +110,20 @@@ struct _GVarian
   *            The type_info field never changes during the life of the
   *            instance, so it can be accessed without a lock.
   *
 - * size: this is the size of the serialized form for the instance, if it
 - *       is known.  If the instance is in serialized form then it is, by
 - *       definition, known.  If the instance is in tree form then it may
 - *       be unknown (in which case it is -1).  It is possible for the
 - *       size to be known when in tree form if, for example, the user
 - *       has called g_variant_get_size() without calling
 - *       g_variant_get_data().  Additionally, even when the user calls
 - *       g_variant_get_data() the size of the data must first be
 - *       determined so that a large enough buffer can be allocated for
 - *       the data.
 - *
 - *       Once the size is known, it can never become unknown again.
 - *       g_variant_ensure_size() is used to ensure that the size is in
 - *       the known state -- it calculates the size if needed.  After
 - *       that, the size field can be accessed without a lock.
 + * size: this is the size of the serialised form for the instance.  It
 + *       is known for serialised instances and also tree-form instances
 + *       (for which it is calculated at construction time, from the
 + *       known sizes of the children used).  After construction, it
 + *       never changes and therefore can be accessed without a lock.
   *
   * contents: a union containing either the information associated with
-  *           holding a value in serialised form or holding a value in
+  *           holding a value in serialized form or holding a value in
   *           tree form.
   *
-  *   .serialised: Only valid when the instance is in serialised form.
+  *   .serialised: Only valid when the instance is in serialized form.
   *
   *                Since an instance can never transition away from
-  *                serialised form, once these fields are set, they will
+  *                serialized form, once these fields are set, they will
   *                never be changed.  It is therefore valid to access
   *                them without holding a lock.
   *
@@@ -258,65 -267,52 +258,65 @@@ g_variant_release_children (GVariant *v
    g_free (value->contents.tree.children);
  }
  
 -/* This begins the main body of the recursive serializer.
 +/* < private >
 + * g_variant_lock_in_tree_form:
 + * @value: a #GVariant
 + *
 + * Locks @value if it is in tree form.
 + *
 + * Returns: %TRUE if @value is now in tree form with the lock acquired
 + */
 +static gboolean
 +g_variant_lock_in_tree_form (GVariant *value)
 +{
 +  if (g_atomic_int_get (&value->state) & STATE_SERIALISED)
 +    return FALSE;
 +
 +  g_variant_lock (value);
 +
 +  if (value->state & STATE_SERIALISED)
 +    {
 +      g_variant_unlock (value);
 +      return FALSE;
 +    }
 +
 +  return TRUE;
 +}
 +
 +/* This begins the main body of the recursive serialiser.
   *
-  * There are 3 functions here that work as a team with the serialiser to
+  * There are 3 functions here that work as a team with the serializer to
   * get things done.  g_variant_store() has a trivial role, but as a
   * public API function, it has its definition elsewhere.
   *
-  * Note that "serialisation" of an instance does not mean that the
-  * instance is converted to serialised form -- it means that the
-  * serialised form of an instance is written to an external buffer.
+  * Note that "serialization" of an instance does not mean that the
+  * instance is converted to serialized form -- it means that the
+  * serialized form of an instance is written to an external buffer.
   * g_variant_ensure_serialised() (which is not part of this set of
   * functions) is the function that is responsible for converting an
-  * instance to serialised form.
+  * instance to serialized form.
   *
   * We are only concerned here with container types since non-container
-  * instances are always in serialised form.  For these instances,
-  * storing their serialised form merely involves a memcpy().
+  * instances are always in serialized form.  For these instances,
+  * storing their serialized form merely involves a memcpy().
   *
 - * Serialization is a two-step process.  First, the size of the
 - * serialized data must be calculated so that an appropriately-sized
 - * buffer can be allocated.  Second, the data is written into the
 - * buffer.
 + * Converting to serialised form:
   *
 - * Determining the size:
 - *   The process of determining the size is triggered by a call to
 - *   g_variant_ensure_size() on a container.  This invokes the
 - *   serializer code to determine the size.  The serializer is passed
 - *   g_variant_fill_gvs() as a callback.
 - *
 - *   g_variant_fill_gvs() is called by the serializer on each child of
 - *   the container which, in turn, calls g_variant_ensure_size() on
 - *   itself and fills in the result of its own size calculation.
 + *   The first step in the process of converting a GVariant to
 + *   serialised form is to allocate a buffer.  The size of the buffer is
 + *   always known because we computed at construction time of the
 + *   GVariant.
   *
 - *   The serializer uses the size information from the children to
 - *   calculate the size needed for the entire container.
 - *
 - * Writing the data:
   *   After the buffer has been allocated, g_variant_serialise() is
 - *   called on the container.  This invokes the serializer code to write
 - *   the bytes to the container.  The serializer is, again, passed
 + *   called on the container.  This invokes the serialiser code to write
 + *   the bytes to the container.  The serialiser is passed
   *   g_variant_fill_gvs() as a callback.
   *
 - *   This time, when g_variant_fill_gvs() is called for each child, the
 + *   At the time that g_variant_fill_gvs() is called for each child, the
   *   child is given a pointer to a sub-region of the allocated buffer
   *   where it should write its data.  This is done by calling
-  *   g_variant_store().  In the event that the instance is in serialised
-  *   form this means a memcpy() of the serialised data into the
+  *   g_variant_store().  In the event that the instance is in serialized
+  *   form this means a memcpy() of the serialized data into the
   *   allocated buffer.  In the event that the instance is in tree form
   *   this means a recursive call back into g_variant_serialise().
   *
@@@ -406,12 -431,15 +406,12 @@@ g_variant_fill_gvs (GVariantSerialised 
   * g_variant_ensure_serialised:
   * @value: a #GVariant
   *
-  * Ensures that @value is in serialised form.
+  * Ensures that @value is in serialized form.
   *
 - * If @value is in tree form then this function ensures that the
 - * serialized size is known and then allocates a buffer of that size and
 - * serializes the instance into the buffer.  The 'children' array is
 - * then released and the instance is set to serialized form based on the
 - * contents of the buffer.
 - *
 - * The current thread must hold the lock on @value.
 + * If @value is in tree form then this function allocates a buffer of
 + * that size and serialises the instance into the buffer.  The
 + * 'children' array is then released and the instance is set to
 + * serialised form based on the contents of the buffer.
   */
  static void
  g_variant_ensure_serialised (GVariant *value)
@@@ -613,11 -554,12 +613,12 @@@ g_variant_new_serialised (GVariantTypeI
                            aligned_size) != 0)
          g_error ("posix_memalign failed");
  
-       memcpy (aligned_data, g_bytes_get_data (bytes, NULL), aligned_size);
+       if (aligned_size != 0)
+         memcpy (aligned_data, g_bytes_get_data (bytes, NULL), aligned_size);
  
 -      bytes = owned_bytes = g_bytes_new_with_free_func (aligned_data,
 -                                                        aligned_size,
 -                                                        free, aligned_data);
 +      owned_bytes = g_bytes_new_with_free_func (aligned_data,
 +                                                aligned_size,
 +                                                free, aligned_data);
        aligned_data = NULL;
  #else
        /* NOTE: there may be platforms that lack posix_memalign() and also
@@@ -698,190 -667,20 +699,205 @@@ g_variant_is_trusted (GVariant *value
  }
  
  /* < internal >
 + * g_variant_get_serialised:
 + * @value: a #GVariant
 + * @bytes: (out) (transfer none): a location to store the #GBytes
 + * @size: (out): a location to store the size of the returned data
 + *
 + * Ensures that @value is in serialised form and returns information
 + * about it.  This is called from various APIs in gvariant.c
 + *
 + * Returns: data, of length @size
 + */
 +gconstpointer
 +g_variant_get_serialised (GVariant  *value,
 +                          GBytes   **bytes,
 +                          gsize     *size)
 +{
 +  g_variant_ensure_serialised (value);
 +
 +  if (bytes)
 +    *bytes = value->contents.serialised.bytes;
 +
 +  *size = value->size;
 +
 +  return value->contents.serialised.data;
 +}
 +
 +static GVariant *
 +g_variant_vector_deserialise (GVariantTypeInfo *type_info,
 +                              GVariantVector   *first_vector,
 +                              GVariantVector   *last_vector,
 +                              gsize             size,
 +                              gboolean          trusted,
 +                              GArray           *unpacked_children)
 +{
 +  g_assert (size > 0);
 +
 +  if (first_vector < last_vector)
 +    {
 +      GVariantVector *vector = first_vector;
 +      const guchar *end_pointer;
 +      GVariant **children;
 +      guint save_point;
 +      guint n_children;
 +      gboolean failed;
 +      guint i;
 +
 +      end_pointer = last_vector->data.pointer + last_vector->size;
 +      save_point = unpacked_children->len;
 +
 +      if (!g_variant_serialiser_unpack_all (type_info, end_pointer, last_vector->size, size, unpacked_children))
 +        {
 +          for (i = save_point; i < unpacked_children->len; i++)
 +            g_variant_type_info_unref (g_array_index (unpacked_children, GVariantUnpacked, i).type_info);
 +          g_array_set_size (unpacked_children, save_point);
 +
 +          g_variant_type_info_unref (type_info);
 +
 +          return NULL;
 +        }
 +
 +      n_children = unpacked_children->len - save_point;
 +      children = g_new (GVariant *, n_children);
 +      failed = FALSE;
 +
 +      for (i = 0; i < n_children; i++)
 +        {
 +          GVariantUnpacked *unpacked = &g_array_index (unpacked_children, GVariantUnpacked, save_point + i);
 +          const guchar *resume_at_data;
 +          gsize resume_at_size;
 +          GVariantVector *fv;
 +
 +          /* Skip the alignment.
 +           *
 +           * We can destroy vectors because we won't be going back.
 +           *
 +           * We do a >= compare because we want to go to the next vector
 +           * if it is the start of our child.
 +           */
 +          while (unpacked->skip >= vector->size)
 +            {
 +              unpacked->skip -= vector->size;
 +              vector++;
 +            }
 +          g_assert (vector <= last_vector);
 +
 +          fv = vector;
 +          fv->data.pointer += unpacked->skip;
 +          fv->size -= unpacked->skip;
 +
 +          if (unpacked->size == 0)
 +            {
 +              children[i] = g_variant_new_serialised (unpacked->type_info, g_bytes_new (NULL, 0), NULL, 0, trusted);
 +              g_variant_ref_sink (children[i]);
 +              continue;
 +            }
 +
 +          /* Now skip to the end, according to 'size'.
 +           *
 +           * We cannot destroy everything here because we will probably
 +           * end up reusing the last one.
 +           *
 +           * We do a > compare because we want to stay on this vector if
 +           * it is the end of our child.
 +           */
 +          size = unpacked->size;
 +          while (unpacked->size > vector->size)
 +            {
 +              unpacked->size -= vector->size;
 +              vector++;
 +            }
 +          g_assert (vector <= last_vector);
 +
 +          /* We have to modify the vectors for the benefit of the
 +           * recursive step.  We also have to remember where we left
 +           * off, keeping in mind that the recursive step may itself
 +           * modify the vectors.
 +           */
 +          resume_at_data = vector->data.pointer + unpacked->size;
 +          resume_at_size = vector->size - unpacked->size;
 +          vector->size = unpacked->size;
 +
 +          children[i] = g_variant_vector_deserialise (unpacked->type_info, fv, vector,
 +                                                      size, trusted, unpacked_children);
 +
 +          vector->data.pointer = resume_at_data;
 +          vector->size = resume_at_size;
 +
 +          if (children[i])
 +            g_variant_ref_sink (children[i]);
 +          else
 +            failed = TRUE;
 +        }
 +
 +      /* We consumed all the type infos */
 +      g_array_set_size (unpacked_children, save_point);
 +
 +      if G_UNLIKELY (failed)
 +        {
 +          for (i = 0; i < n_children; i++)
 +            if (children[i])
 +              g_variant_unref (children[i]);
 +
 +          g_variant_type_info_unref (type_info);
 +          g_free (children);
 +
 +          return NULL;
 +        }
 +
 +      return g_variant_new_from_children (type_info, children, n_children, trusted);
 +    }
 +  else
 +    {
 +      g_assert (first_vector == last_vector);
 +      g_assert (size == first_vector->size);
 +
 +      return g_variant_new_serialised (type_info, g_bytes_ref (first_vector->gbytes),
 +                                       first_vector->data.pointer, size, trusted);
 +    }
 +}
 +
 +GVariant *
 +g_variant_from_vectors (const GVariantType *type,
 +                        GVariantVector     *vectors,
 +                        gsize               n_vectors,
 +                        gsize               size,
 +                        gboolean            trusted)
 +{
 +  GVariant *result;
 +  GArray *tmp;
 +
 +  g_return_val_if_fail (vectors != NULL || n_vectors == 0, NULL);
 +
 +  if (size == 0)
 +    return g_variant_new_serialised (g_variant_type_info_get (type), g_bytes_new (NULL, 0), NULL, 0, trusted);
 +
 +  tmp = g_array_new (FALSE, FALSE, sizeof (GVariantUnpacked));
 +  result = g_variant_vector_deserialise (g_variant_type_info_get (type),
 +                                         vectors, vectors + n_vectors - 1, size, trusted, tmp);
 +  if (result)
 +    g_variant_ref_sink (result);
 +  g_array_free (tmp, TRUE);
 +
 +  return result;
 +}
 +
++/* < internal >
+  * g_variant_get_depth:
+  * @value: a #GVariant
+  *
+  * Gets the nesting depth of a #GVariant. This is 0 for a #GVariant with no
+  * children.
+  *
+  * Returns: nesting depth of @value
+  */
+ gsize
+ g_variant_get_depth (GVariant *value)
+ {
+   return value->depth;
+ }
  /* -- public -- */
  
  /**
@@@ -40,8 -34,6 +40,10 @@@ gboolean                g_variant_is_tr
  
  GVariantTypeInfo *      g_variant_get_type_info                         (GVariant            *value);
  
 +gconstpointer           g_variant_get_serialised                        (GVariant            *value,
 +                                                                         GBytes             **bytes,
 +                                                                         gsize               *size);
 +
+ gsize                   g_variant_get_depth                             (GVariant            *value);
  #endif /* __G_VARIANT_CORE_H__ */
Simple merge
Simple merge
diff --cc glib/gvariant.c
@@@ -69,7 -69,7 +69,7 @@@
   *
   * The range of possible values is determined by the type.
   *
-- * The type system used by #GVariant is #GVariantType. 
++ * The type system used by #GVariant is #GVariantType.
   *
   * #GVariant instances always have a type and a value (which are given
   * at construction time).  The type and value of a #GVariant instance
   *
   * This means that in total, for our "a{sv}" example, 91 bytes of
   * type information would be allocated.
-- * 
++ *
   * The type information cache, additionally, uses a #GHashTable to
   * store and look up the cached items and stores a pointer to this
   * hash table in static storage.  The hash table is freed when there
@@@ -743,8 -724,8 +743,8 @@@ g_variant_new_variant (GVariant *value
  
    g_variant_ref_sink (value);
  
 -  return g_variant_new_from_children (G_VARIANT_TYPE_VARIANT,
 +  return g_variant_new_from_children (g_variant_type_info_get (G_VARIANT_TYPE_VARIANT),
-                                       g_memdup (&value, sizeof value),
+                                       g_memdup2 (&value, sizeof value),
                                        1, g_variant_is_trusted (value));
  }
  
@@@ -2170,12 -2156,10 +2174,12 @@@ g_variant_is_container (GVariant *value
   * @G_VARIANT_CLASS_INT64: The #GVariant is a signed 64 bit integer.
   * @G_VARIANT_CLASS_UINT64: The #GVariant is an unsigned 64 bit integer.
   * @G_VARIANT_CLASS_HANDLE: The #GVariant is a file handle index.
 - * @G_VARIANT_CLASS_DOUBLE: The #GVariant is a double precision floating 
 + * @G_VARIANT_CLASS_FLOAT: The #GVariant is a single precision floating
 + *                         point value.
-  * @G_VARIANT_CLASS_DOUBLE: The #GVariant is a double precision floating 
++ * @G_VARIANT_CLASS_DOUBLE: The #GVariant is a double precision floating
   *                          point value.
   * @G_VARIANT_CLASS_STRING: The #GVariant is a normal string.
-- * @G_VARIANT_CLASS_OBJECT_PATH: The #GVariant is a D-Bus object path 
++ * @G_VARIANT_CLASS_OBJECT_PATH: The #GVariant is a D-Bus object path
   *                               string.
   * @G_VARIANT_CLASS_SIGNATURE: The #GVariant is a D-Bus signature string.
   * @G_VARIANT_CLASS_VARIANT: The #GVariant is a variant.
@@@ -3129,7 -3081,7 +3136,7 @@@ g_variant_iter_free (GVariantIter *iter
   * you no longer need it.
   *
   * Here is an example for iterating with g_variant_iter_next_value():
-- * |[<!-- language="C" --> 
++ * |[<!-- language="C" -->
   *   // recursively iterate a container
   *   void
   *   iterate_container_recursive (GVariant *container)
@@@ -5581,7 -5524,7 +5589,7 @@@ g_variant_get_va (GVariant     *value
   *
   * This function might be used as follows:
   *
-- * |[<!-- language="C" --> 
++ * |[<!-- language="C" -->
   * GVariant *
   * make_pointless_dictionary (void)
   * {
@@@ -5677,7 -5620,7 +5685,7 @@@ g_variant_get_child (GVariant    *value
   * the unpacking process.
   *
   * Here is an example for memory management with g_variant_iter_next():
-- * |[<!-- language="C" --> 
++ * |[<!-- language="C" -->
   *   // Iterates a dictionary of type 'a{sv}'
   *   void
   *   iterate_dictionary (GVariant *dictionary)
@@@ -5769,7 -5712,7 +5777,7 @@@ g_variant_iter_next (GVariantIter *iter
   * g_variant_get(). Failure to do so will cause a memory leak.
   *
   * Here is an example for memory management with g_variant_iter_loop():
-- * |[<!-- language="C" --> 
++ * |[<!-- language="C" -->
   *   // Iterates a dictionary of type 'a{sv}'
   *   void
   *   iterate_dictionary (GVariant *dictionary)
diff --cc glib/gvariant.h
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -275,10 -269,10 +274,10 @@@ test_to_data_transferred (void
    GBytes *bytes;
  
    /* Memory transferred: one reference, and allocated with g_malloc */
 -  bytes = g_bytes_new (NYAN, N_NYAN);
 +  bytes = g_bytes_new_take (g_memdup (NYAN, N_NYAN), N_NYAN);
    memory = g_bytes_get_data (bytes, NULL);
    data = g_bytes_unref_to_data (bytes, &size);
-   g_assert (data == memory);
+   g_assert_true (data == memory);
    g_assert_cmpmem (data, size, NYAN, N_NYAN);
    g_free (data);
  }
@@@ -329,11 -347,11 +352,11 @@@ test_to_array_transferred (void
    GBytes *bytes;
  
    /* Memory transferred: one reference, and allocated with g_malloc */
 -  bytes = g_bytes_new (NYAN, N_NYAN);
 +  bytes = g_bytes_new_take (g_memdup (NYAN, N_NYAN), N_NYAN);
    memory = g_bytes_get_data (bytes, NULL);
    array = g_bytes_unref_to_array (bytes);
-   g_assert (array != NULL);
-   g_assert (array->data == memory);
+   g_assert_nonnull (array);
+   g_assert_true (array->data == memory);
    g_assert_cmpmem (array->data, array->len, NYAN, N_NYAN);
    g_byte_array_unref (array);
  }
@@@ -388,50 -438,49 +443,89 @@@ test_null (void
  
    data = g_bytes_unref_to_data (bytes, &size);
  
-   g_assert (data == NULL);
-   g_assert (size == 0);
+   g_assert_null (data);
+   g_assert_cmpuint (size, ==, 0);
+ }
+ static void
+ test_get_region (void)
+ {
+   GBytes *bytes;
+   bytes = g_bytes_new_static (NYAN, N_NYAN);
+   /* simple valid gets at the start */
+   g_assert_true (g_bytes_get_region (bytes, 1, 0, 1) == NYAN);
+   g_assert_true (g_bytes_get_region (bytes, 1, 0, N_NYAN) == NYAN);
+   /* an invalid get because the range is too wide */
+   g_assert_true (g_bytes_get_region (bytes, 1, 0, N_NYAN + 1) == NULL);
+   /* an valid get, but of a zero-byte range at the end */
+   g_assert_true (g_bytes_get_region (bytes, 1, N_NYAN, 0) == NYAN + N_NYAN);
+   /* not a valid get because it overlap ones byte */
+   g_assert_true (g_bytes_get_region (bytes, 1, N_NYAN, 1) == NULL);
+   /* let's try some multiplication overflow now */
+   g_assert_true (g_bytes_get_region (bytes, 32, 0, G_MAXSIZE / 32 + 1) == NULL);
+   g_assert_true (g_bytes_get_region (bytes, G_MAXSIZE / 32 + 1, 0, 32) == NULL);
+   /* and some addition overflow */
+   g_assert_true (g_bytes_get_region (bytes, 1, G_MAXSIZE, -G_MAXSIZE) == NULL);
+   g_assert_true (g_bytes_get_region (bytes, 1, G_MAXSSIZE, ((gsize) G_MAXSSIZE) + 1) == NULL);
+   g_assert_true (g_bytes_get_region (bytes, 1, G_MAXSIZE, 1) == NULL);
+   g_bytes_unref (bytes);
+ }
+ static void
+ test_unref_null (void)
+ {
+   g_test_summary ("Test that calling g_bytes_unref() on NULL is a no-op");
+   g_bytes_unref (NULL);
  }
  
 +#ifdef GLIB_LINUX
 +static void
 +test_memfd (void)
 +{
 +  GBytes *bytes;
 +  gint fd;
 +
 +  fd = glib_linux_memfd_create ("", MFD_CLOEXEC);
 +  if (fd == -1 && errno == EINVAL)
 +    {
 +      g_test_skip ("missing kernel memfd support");
 +      return;
 +    }
 +
 +  /* We should not be able to seal this one */
 +  g_assert (!g_unix_fd_ensure_zero_copy_safe (fd));
 +  close (fd);
 +
 +  /* but this one will work */
 +  fd = glib_linux_memfd_create ("", MFD_CLOEXEC | MFD_ALLOW_SEALING);
 +  bytes = g_bytes_new_take_zero_copy_fd (fd);
 +  g_assert_cmpint (g_bytes_get_size (bytes), ==, 0);
 +  g_bytes_unref (bytes);
 +
 +  /* try with real data */
 +  fd = glib_linux_memfd_create ("", MFD_CLOEXEC | MFD_ALLOW_SEALING);
 +  g_assert_se (write (fd, NYAN, N_NYAN) == N_NYAN);
 +  bytes = g_bytes_new_take_zero_copy_fd (fd);
 +  g_assert_cmpint (g_bytes_get_size (bytes), ==, N_NYAN);
 +  g_assert (memcmp (g_bytes_get_data (bytes, NULL), NYAN, N_NYAN) == 0);
 +  g_assert (g_bytes_get_zero_copy_fd (bytes) == fd);
 +
 +  /* ensure that we cannot modify the fd further */
 +  g_assert_se (write (fd, NYAN, N_NYAN) == -1);
 +
 +  /* that's enough for now */
 +  g_bytes_unref (bytes);
 +}
 +#endif
 +
  int
  main (int argc, char *argv[])
  {
    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);
 +#ifdef GLIB_LINUX
 +  g_test_add_func ("/bytes/memfd", test_memfd);
 +#endif
+   g_test_add_func ("/bytes/get-region", test_get_region);
+   g_test_add_func ("/bytes/unref-null", test_unref_null);
  
    return g_test_run ();
  }
Simple merge
Simple merge
index 023fe78,0000000..8342951
mode 100644,000000..100644
--- /dev/null
@@@ -1,457 -1,0 +1,456 @@@
- %{_bindir}/gio-launch-desktop
 +# Do not create provides from extension .so files because the main package
 +# should anchor any reverse-dependencies
 +%global __provides_exclude_from ^(.*\\.extension-kdbus)$
 +
 +%define baseline 2.62
 +%define with_systemtap 0
 +%define keepstatic 1
 +%define build_dir _build
 +%define build_dir_kdbus _build_kdbus
 +
 +# The 'meson' macro is defined in rpm macros, but it uses features from rpm 4.15 ({shrink, set_build_flags)
 +# Below is a version suitable for our purposes
 +%define meson \
 +  CFLAGS="${CFLAGS:-%optflags}" \
 +  export CFLAGS \
 +  %{__meson} \\\
 +        --buildtype=plain \\\
 +        --prefix=%{_prefix} \\\
 +        --libdir=%{_libdir} \\\
 +        --libexecdir=%{_libexecdir} \\\
 +        --bindir=%{_bindir} \\\
 +        --sbindir=%{_sbindir} \\\
 +        --includedir=%{_includedir} \\\
 +        --datadir=%{_datadir} \\\
 +        --mandir=%{_mandir} \\\
 +        --infodir=%{_infodir} \\\
 +        --localedir=%{_datadir}/locale \\\
 +        --sysconfdir=%{_sysconfdir} \\\
 +        --localstatedir=%{_localstatedir} \\\
 +        --sharedstatedir=%{_sharedstatedir} \\\
 +        --wrap-mode=%{__meson_wrap_mode} \\\
 +              %{_vpath_builddir}
 +# Ninja macros below are defined for ninja in e.g. fedora distro, but
 +# so far they are not provided by Tizen's ninja package.
 +%define __ninja %{_bindir}/ninja
 +%define __ninja_common_opts -v %{?_smp_flags}
 +%define ninja_build \
 +              %{__ninja} %{__ninja_common_opts}
 +%define ninja_install \
 +              DESTDIR=%{buildroot} %{__ninja} install %{__ninja_common_opts}
 +
 +Name:           glib2
 +Version:        2.62.3
 +Release:        0
 +# FIXME: find out if tapsets should really be in devel package or in main package
 +Summary:        General-Purpose Utility Library
 +License:        LGPL-2.1+
 +Group:          Base/Libraries
 +Url:            http://www.gtk.org/
 +Source:         http://download.gnome.org/sources/glib/%{baseline}/%{name}-%{version}.tar.xz
 +Source1:        glib2.sh
 +Source2:        glib2.csh
 +Source3:        test-runner.c
 +# Not upstream file. Only proposes upstream packages:
 +Source4:        glib2-upstream-gnome_defaults.conf
 +Source6:        macros.glib2
 +# Not depending on gtk-doc shortens bootstrap compilation path.
 +# Please update this file from the latest gtk-doc package:
 +Source7:        gtk-doc.m4
 +Source98:       q_quark_block_size.patch
 +Source99:       baselibs.conf
 +Source1001:   glib2.manifest
 +BuildRequires:  automake
 +BuildRequires:  fdupes
 +BuildRequires:  gcc-c++
 +BuildRequires:  m4
 +BuildRequires:  meson >= 0.49.2
 +BuildRequires:  pkg-config
 +BuildRequires:  python3
 +BuildRequires:  gettext-tools
 +# gdbus-codegen is run during the build, so we need python-xml
 +BuildRequires:  python3-xml
 +%if 0%{?with_systemtap}
 +BuildRequires:  systemtap-sdt-devel
 +%endif
 +# Needed for gresource
 +BuildRequires:  pkgconfig(libelf) >= 0.8.12
 +BuildRequires:  pkgconfig(libffi)
 +BuildRequires:  pkgconfig(libpcre) >= 8.31
 +BuildRequires:  pkgconfig(mount) >= 2.28
 +BuildRequires:  pkgconfig(zlib)
 +# Enable support for libdbuspolicy (only for kdbus transport)
 +BuildRequires:  pkgconfig(libdbuspolicy1)
 +
 +%description
 +GLib is a general-purpose utility library, which provides many useful
 +data types, macros, type conversions, string utilities, file utilities,
 +a main loop abstraction, and so on.
 +
 +%package tools
 +Summary:        General-Purpose Utility Library -- Tools
 +
 +%description tools
 +GLib is a general-purpose utility library, which provides many useful
 +data types, macros, type conversions, string utilities, file utilities,
 +a main loop abstraction, and so on.
 +
 +%package -n gio-branding-upstream
 +Summary:        Upstream definitions of default settings and applications
 +Requires:       libgio = %{version}
 +Provides:       %{name}-branding-upstream = %{version}
 +Obsoletes:      %{name}-branding-upstream < %{version}
 +Provides:       gio-branding = %{version}
 +Conflicts:      otherproviders(gio-branding)
 +Supplements:    packageand(libgio:branding-upstream)
 +BuildArch:      noarch
 +#BRAND: The /etc/gnome_defaults.conf allows to define arbitrary
 +#BRAND: applications as preferred defaults.
 +#BRAND: A /usr/share/glib-2.0/schemas/$NAME.gschema.override file can
 +#BRAND: be used to override the default value for GSettings keys. See
 +#BRAND: README.Gsettings-overrides for more details. The branding
 +#BRAND: package should then have proper Requires for features changed
 +#BRAND: with such an override file.
 +# NOTE: gnome_defaults is not an upstream feature, but a SuSE
 +# enhancement, but to conform branding conventions, the package is named
 +# as gio-branding-upstream.
 +
 +%description -n gio-branding-upstream
 +This package provides upstream defaults for settings stored with
 +GSettings and applications used by the MIME system.
 +
 +%package devel
 +#'
 +Requires:       %{name} = %{version}
 +Requires:       glibc-devel
 +Requires:       pkg-config
 +# Now require the subpackages too
 +Requires:       glib2-tools = %{version}
 +Requires:       libgio = %{version}
 +Requires:       libglib = %{version}
 +Requires:       libgmodule = %{version}
 +Requires:       libgobject = %{version}
 +Requires:       libgthread = %{version}
 +# Required by gdbus-codegen
 +Requires:       python3-xml
 +Requires:       python3
 +Provides:       glib2-doc = 2.19.6
 +Obsoletes:      glib2-doc < 2.19.6
 +Summary:        General-Purpose Utility Library -- Development Files
 +
 +%description devel
 +GLib is a general-purpose utility library, which provides many useful
 +data types, macros, type conversions, string utilities, file utilities,
 +a main loop abstraction, and so on.
 +
 +This package contains the development files for GLib.
 +
 +%package devel-static
 +Summary:        Static libraries for glib, a general-purpose utility library
 +Group:          Development/Libraries/C and C++
 +Requires:       %{name}-devel = %{version}
 +
 +%description devel-static
 +GLib is a general-purpose utility library, which provides many useful
 +data types, macros, type conversions, string utilities, file utilities,
 +a main loop abstraction, and so on.
 +
 +This package contains static versions of the GLib libraries.
 +
 +%package -n libglib
 +Summary:        General-Purpose Utility Library
 +Provides:       %{name} = %{version}
 +Obsoletes:      %{name} < %{version}
 +
 +%description -n libglib
 +GLib is a general-purpose utility library, which provides many useful
 +data types, macros, type conversions, string utilities, file utilities,
 +a main loop abstraction, and so on.
 +
 +%package -n libgmodule
 +Summary:        General-Purpose Utility Library -- Library for Modules
 +
 +%description -n libgmodule
 +GLib is a general-purpose utility library, which provides many useful
 +data types, macros, type conversions, string utilities, file utilities,
 +a main loop abstraction, and so on.
 +
 +The libgmodule library provides a portable way to dynamically load
 +object files (commonly known as 'plug-ins').
 +
 +%package -n libgio
 +Summary:        General-Purpose Utility Library -- Library for VFS
 +Requires:       gio-branding = %{version}
 +# bnc#555605: shared-mime-info is required by libgio to properly detect mime types.
 +Requires:       shared-mime-info
 +# bnc#678518: libgio interacts with others by means of dbus-launch
 +#Requires:       dbus-1-x11
 +Provides:       gio = %{version}
 +
 +%description -n libgio
 +GLib is a general-purpose utility library, which provides many useful
 +data types, macros, type conversions, string utilities, file utilities,
 +a main loop abstraction, and so on.
 +
 +GIO provides a modern, easy-to-use VFS API.
 +
 +%package -n libgio-extension-kdbus
 +Summary:      Extension for libgio to support KDBUS in Tizen
 +Requires:     libgio = %{version}-%{release}
 +
 +%description -n libgio-extension-kdbus
 +This modifies libgio to support KDBUS in Tizen.
 +
 +
 +%package -n libgthread
 +Summary:        General-Purpose Utility Library -- Library for Threads
 +
 +%description -n libgthread
 +GLib is a general-purpose utility library, which provides many useful
 +data types, macros, type conversions, string utilities, file utilities,
 +a main loop abstraction, and so on.
 +
 +The libgthread library provides a portable way to write multi-threaded
 +software.
 +
 +%package -n libgobject
 +Summary:        General-Purpose Utility Library -- Object-Oriented Framework for C
 +
 +%description -n libgobject
 +GLib is a general-purpose utility library, which provides many useful
 +data types, macros, type conversions, string utilities, file utilities,
 +a main loop abstraction, and so on.
 +
 +The GObject library provides an object-oriented framework for C.
 +
 +%package tests
 +License:        LGPL-2.0+ and MIT
 +Summary:        Set of tests for gdbus component
 +Requires:       %{name} = %{version}
 +
 +%description tests
 +This package is part of 'dbus-integration-tests' framework and contains set of tests
 +for gdbus component.
 +
 +%prep
 +%setup -q -n %{name}-%{version}
 +%{__patch} -p1 < %{SOURCE98}
 +
 +%build
 +cp %{SOURCE3} .
 +cp %{SOURCE1001} .
 +cp -a %{S:1} %{S:2} .
 +cp -a %{S:4} gnome_defaults.conf
 +if ! test -f %{_datadir}/aclocal/gtk-doc.m4 ; then
 +    cp -a %{S:7} m4macros/
 +fi
 +
 +%define _vpath_srcdir .
 +
 +# Normal build
 +%define _vpath_builddir %{build_dir}
 +%meson \
 +      --default-library=both \
 +      -Dinstalled_tests=true \
 +      -Db_pie=true
 +%meson_build
 +
 +# Configure kdbus extension build
 +%define _vpath_builddir %{build_dir_kdbus}
 +%meson \
 +      --default-library=both \
 +      -Dkdbus=true \
 +      -Dlibdbuspolicy=true \
 +      -Db_pie=true
 +%meson_build
 +
 +# compile test-runner for 'dbus-integration-test' framework
 +%__cc %{_builddir}/%{name}-%{version}/test-runner.c -fPIC -pie -o %{_builddir}/%{name}-%{version}/glib-tests
 +
 +%install
 +# kdbus extension install and gather required files
 +%define _vpath_builddir %{build_dir_kdbus}
 +%meson_install
 +for FILE in %{buildroot}%{_libdir}/libgio*; do mv "$FILE" "$FILE.extension-kdbus"; done
 +
 +# normal install overwriting kdbus extension install
 +%define _vpath_builddir %{build_dir}
 +%meson_install
 +%find_lang glib20 %{?no_lang_C}
 +
 +mkdir -p %{buildroot}%{_sysconfdir}/profile.d
 +install -D -m0644 glib2.sh %{buildroot}%{_sysconfdir}/profile.d/zzz-glib2.sh
 +install -D -m0644 glib2.csh %{buildroot}%{_sysconfdir}/profile.d/zzz-glib2.csh
 +install -D -m0644 gnome_defaults.conf %{buildroot}%{_sysconfdir}/gnome_defaults.conf
 +
 +# gio-querymodules magic
 +%if "%{_lib}" == "lib64"
 +mv %{buildroot}%{_bindir}/gio-querymodules %{buildroot}%{_bindir}/gio-querymodules-64
 +%endif
 +
 +# prepare tests for 'dbus-integration-test' framework
 +%define relative_dbus_tests_base_dir %{_prefix}/lib/dbus-tests
 +%define dbus_tests_base_dir %{buildroot}%{relative_dbus_tests_base_dir}
 +
 +install -D -m 755 %{_builddir}/%{name}-%{version}/glib-tests %{dbus_tests_base_dir}/runner/glib-tests
 +mkdir -p %{dbus_tests_base_dir}/test-suites/glib-tests/
 +mv %{buildroot}%{_prefix}/libexec/installed-tests/glib/*gdbus-* %{dbus_tests_base_dir}/test-suites/glib-tests/
 +# workaround for UNIX fd passing test (gdbus-peer)
 +echo "Testfile - check for UNIX fd passing" > %{dbus_tests_base_dir}/test-suites/glib-tests/file.c
 +rm %{dbus_tests_base_dir}/test-suites/glib-tests/gdbus-testserver
 +rm -Rf %{buildroot}%{_prefix}/libexec/installed-tests/glib/
 +rm -Rf %{buildroot}%{_prefix}/share/installed-tests/glib/
 +
 +# Install rpm macros
 +mkdir -p %{buildroot}%{_sysconfdir}/rpm
 +cp %{SOURCE6} %{buildroot}%{_sysconfdir}/rpm
 +
 +mkdir -p %{buildroot}%{_libdir}/gio/modules
 +mkdir -p %{buildroot}%{_datadir}/glib-2.0/schemas/
 +
 +chmod 755 %{buildroot}%{_bindir}/*
 +
 +%post -n libglib -p /sbin/ldconfig
 +%post -n libgobject -p /sbin/ldconfig
 +%post -n libgthread -p /sbin/ldconfig
 +%post -n libgio -p /sbin/ldconfig
 +%post -n libgmodule -p /sbin/ldconfig
 +
 +%postun -n libglib -p /sbin/ldconfig
 +%postun -n libgobject -p /sbin/ldconfig
 +%postun -n libgthread -p /sbin/ldconfig
 +%postun -n libgio -p /sbin/ldconfig
 +%postun -n libgmodule -p /sbin/ldconfig
 +
 +%files tools
 +%manifest %{name}.manifest
 +%defattr(-,root,root)
 +%license COPYING
 +%dir %{_datadir}/bash-completion
 +%dir %{_datadir}/bash-completion/completions
 +%{_datadir}/bash-completion/completions/gresource
 +%{_datadir}/bash-completion/completions/gsettings
 +%{_bindir}/gdbus
 +%{_bindir}/gio
 +%{_bindir}/gio-querymodules*
 +%{_bindir}/glib-compile-schemas
 +%{_bindir}/gresource
 +%{_bindir}/gsettings
 +%{_bindir}/gapplication
 +
 +# We put those files here, but they don't really belong here. They just don't
 +# have a better home... The zzz-glib2 scripts could arguably be in
 +# libglib but that would break the shared library policy.
 +%{_sysconfdir}/profile.d/zzz-glib2.*
 +
 +%files -n gio-branding-upstream
 +%manifest %{name}.manifest
 +%defattr(-,root,root)
 +%license COPYING
 +%config (noreplace) %{_sysconfdir}/gnome_defaults.conf
 +
 +%files -n libglib
 +%manifest %{name}.manifest
 +%defattr(-, root, root)
 +%license COPYING
 +%{_libdir}/libglib*.so.*
 +
 +%files -n libgmodule
 +%manifest %{name}.manifest
 +%defattr(-, root, root)
 +%license COPYING
 +%{_libdir}/libgmodule*.so.*
 +
 +%files -n libgobject
 +%manifest %{name}.manifest
 +%defattr(-, root, root)
 +%license COPYING
 +%{_libdir}/libgobject*.so.*
 +
 +%files -n libgthread
 +%manifest %{name}.manifest
 +%defattr(-, root, root)
 +%license COPYING
 +%{_libdir}/libgthread*.so.*
 +
 +%files -n libgio
 +%manifest %{name}.manifest
 +%defattr(-, root, root)
 +%license COPYING
 +%exclude %{_libdir}/libgio*.so.*.extension-kdbus
 +%{_libdir}/libgio*.so.*
 +%dir %{_libdir}/gio
 +%dir %{_libdir}/gio/modules
 +%ghost %{_libdir}/gio/modules/giomodule.cache
 +%dir %{_datadir}/glib-2.0/
 +%dir %{_datadir}/glib-2.0/schemas/
 +
 +%lang_package -f glib20
 +
 +%post -n libgio-extension-kdbus
 +pushd %{_libdir}
 +for FILE in libgio*.so.*.extension-kdbus; do mv "$FILE" "${FILE%.extension-kdbus}"; done
 +popd
 +
 +%files -n libgio-extension-kdbus
 +%manifest %{name}.manifest
 +%license COPYING
 +%{_libdir}/libgio*.so.*.extension-kdbus
 +
 +%files devel
 +%manifest %{name}.manifest
 +%defattr(-,root,root)
 +%license COPYING
 +
 +%{_bindir}/gdbus-codegen
 +%{_datadir}/bash-completion/completions/*
 +%_datadir/glib-2.0/codegen
 +
 +%{_bindir}/glib-compile-resources
 +%{_bindir}/glib-genmarshal
 +%{_bindir}/glib-gettextize
 +%{_bindir}/glib-mkenums
 +%{_bindir}/gobject-query
 +%{_bindir}/gtester
 +%{_bindir}/gtester-report
 +%dir %{_datadir}/aclocal
 +%{_datadir}/aclocal/glib-2.0.m4
 +%{_datadir}/aclocal/glib-gettext.m4
 +%{_datadir}/aclocal/gsettings.m4
 +%dir %{_datadir}/glib-2.0/
 +%{_datadir}/glib-2.0/gdb/
 +%{_datadir}/glib-2.0/gettext/
 +%{_datadir}/glib-2.0/schemas/gschema.dtd
 +%{_datadir}/glib-2.0/valgrind/glib.supp
 +%{_includedir}/glib-2.0
 +%{_includedir}/gio-unix-2.0
 +%{_libdir}/lib*.so
 +%dir %{_libdir}/glib-2.0/
 +%{_libdir}/glib-2.0/include/
 +%{_libdir}/pkgconfig/*.pc
 +%{_datadir}/gdb/auto-load/%{_libdir}/*-gdb.py
 +%{_datadir}/gettext/its/gschema.*
 +%if 0%{?with_systemtap}
 +%{_datadir}/systemtap/tapset/*.stp
 +%endif
 +%{_sysconfdir}/rpm/macros.glib2
 +# Own these directories to not depend on gdb
 +%dir %{_datadir}/gdb
 +%dir %{_datadir}/gdb/auto-load
 +%dir %{_datadir}/gdb/auto-load%{_prefix}
 +%dir %{_datadir}/gdb/auto-load%{_libdir}
 +
 +%files devel-static
 +%manifest %{name}.manifest
 +%defattr(-,root,root)
 +%license COPYING
 +%{_libdir}/lib*.a
 +%{_libdir}/lib*.a.extension-kdbus
 +
 +%files tests
 +%manifest %{name}.manifest
 +%license COPYING LICENSE.MIT
 +%{relative_dbus_tests_base_dir}/test-suites/glib-tests/
 +%{relative_dbus_tests_base_dir}/runner/glib-tests
 +
 +%changelog