[glib/glib-2-30] GDBusMessage: do not align for grandchildren of empty arrays.



commit 7cfb6070032f909fb9651ba80899b1eb556cb6ab
Author: Will Thompson <will thompson collabora co uk>
Date:   Tue Apr 10 13:20:09 2012 +0100

    GDBusMessage: do not align for grandchildren of empty arrays.
    
    D-Bus arrays are serialized as follows:
    
    1. align to a 4-byte boundary (for the length)
    2. uint32: the length of the serialized body in bytes
    3. padding for the alignment of the body type (not included in the length)
    4. the body.
    
    Note that 3. is a no-op unless the body type is an 8-byte aligned type
    (uint64, int64, double, struct, dict_entry), since you are always on a
    4-byte boundary from aligning and writing the length.
    
    So, an empty aax (that is, an array containing zero arrays of int64)
    is serialized as follows:
    
    1. align to a 4-byte boundary
    2. length of the contents of this (empty) array, in bytes (0)
    3. align to a 4-byte boundary (the child array's alignment requirement)
    4. there is no body.
    
    But previously, GDBus would recurse in step three to align not just for
    the type of the child array, but for the nonexistent child array's
    contents. This only affects the algorithm when the grandchild type has
    8-byte alignment and the reader happened to not already be on an 8-byte
    boundary, in which case 4 bytes were spuriously skipped.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=673612
    
    Signed-off-by: David Zeuthen <davidz redhat com>

 gio/gdbusmessage.c |  159 +++++++++++++++++++++++++---------------------------
 1 files changed, 76 insertions(+), 83 deletions(-)
---
diff --git a/gio/gdbusmessage.c b/gio/gdbusmessage.c
index 95ff709..e0d138a 100644
--- a/gio/gdbusmessage.c
+++ b/gio/gdbusmessage.c
@@ -1289,94 +1289,87 @@ parse_value_from_blob (GMemoryInputStream    *mis,
       break;
 
     case 'a': /* G_VARIANT_TYPE_ARRAY */
-      {
-        guint32 array_len;
-        goffset offset;
-        goffset target;
-        const GVariantType *element_type;
-        GVariantBuilder builder;
+      if (!ensure_input_padding (mis, 4, &local_error))
+        goto fail;
 
-        if (!ensure_input_padding (mis, 4, &local_error))
-          goto fail;
+      /* If we are only aligning for this array type, it is the child type of
+       * another array, which is empty. So, we do not need to add padding for
+       * this nonexistent array's elements: we only need to align for this
+       * array itself (4 bytes). See
+       * <https://bugzilla.gnome.org/show_bug.cgi?id=673612>.
+       */
+      if (!just_align)
+        {
+          guint32 array_len;
+          goffset offset;
+          goffset target;
+          const GVariantType *element_type;
+          GVariantBuilder builder;
 
-        if (just_align)
-          {
-            array_len = 0;
-          }
-        else
-          {
-            array_len = g_data_input_stream_read_uint32 (dis, NULL, &local_error);
-            if (local_error != NULL)
-              goto fail;
+          array_len = g_data_input_stream_read_uint32 (dis, NULL, &local_error);
+          if (local_error != NULL)
+            goto fail;
 
-            is_leaf = FALSE;
+          is_leaf = FALSE;
 #ifdef DEBUG_SERIALIZER
-            g_print (": array spans 0x%04x bytes\n", array_len);
+          g_print (": array spans 0x%04x bytes\n", array_len);
 #endif /* DEBUG_SERIALIZER */
 
-            if (array_len > (2<<26))
-              {
-                /* G_GUINT32_FORMAT doesn't work with gettext, so use u */
-                g_set_error (&local_error,
-                             G_IO_ERROR,
-                             G_IO_ERROR_INVALID_ARGUMENT,
-                             g_dngettext (GETTEXT_PACKAGE,
-                                          "Encountered array of length %u byte. Maximum length is 2<<26 bytes (64 MiB).",
-                                          "Encountered array of length %u bytes. Maximum length is 2<<26 bytes (64 MiB).",
-                                          array_len),
-                             array_len);
-                goto fail;
-              }
-          }
+          if (array_len > (2<<26))
+            {
+              /* G_GUINT32_FORMAT doesn't work with gettext, so use u */
+              g_set_error (&local_error,
+                           G_IO_ERROR,
+                           G_IO_ERROR_INVALID_ARGUMENT,
+                           g_dngettext (GETTEXT_PACKAGE,
+                                        "Encountered array of length %u byte. Maximum length is 2<<26 bytes (64 MiB).",
+                                        "Encountered array of length %u bytes. Maximum length is 2<<26 bytes (64 MiB).",
+                                        array_len),
+                           array_len);
+              goto fail;
+            }
 
-        g_variant_builder_init (&builder, type);
-        element_type = g_variant_type_element (type);
+          g_variant_builder_init (&builder, type);
+          element_type = g_variant_type_element (type);
 
-        if (array_len == 0)
-          {
-            GVariant *item;
-            item = parse_value_from_blob (mis,
-                                          dis,
-                                          element_type,
-                                          TRUE,
-                                          indent + 2,
-                                          NULL);
-            g_assert (item == NULL);
-          }
-        else
-          {
-            /* TODO: optimize array of primitive types */
-            offset = g_seekable_tell (G_SEEKABLE (mis));
-            target = offset + array_len;
-            while (offset < target)
-              {
-                GVariant *item;
-                item = parse_value_from_blob (mis,
-                                              dis,
-                                              element_type,
-                                              FALSE,
-                                              indent + 2,
-                                              &local_error);
-                if (item == NULL)
-                  {
-                    g_variant_builder_clear (&builder);
-                    goto fail;
-                  }
-                g_variant_builder_add_value (&builder, item);
-                g_variant_unref (item);
-                offset = g_seekable_tell (G_SEEKABLE (mis));
-              }
-          }
+          if (array_len == 0)
+            {
+              GVariant *item;
+              item = parse_value_from_blob (mis,
+                                            dis,
+                                            element_type,
+                                            TRUE,
+                                            indent + 2,
+                                            NULL);
+              g_assert (item == NULL);
+            }
+          else
+            {
+              /* TODO: optimize array of primitive types */
+              offset = g_seekable_tell (G_SEEKABLE (mis));
+              target = offset + array_len;
+              while (offset < target)
+                {
+                  GVariant *item;
+                  item = parse_value_from_blob (mis,
+                                                dis,
+                                                element_type,
+                                                FALSE,
+                                                indent + 2,
+                                                &local_error);
+                  if (item == NULL)
+                    {
+                      g_variant_builder_clear (&builder);
+                      goto fail;
+                    }
+                  g_variant_builder_add_value (&builder, item);
+                  g_variant_unref (item);
+                  offset = g_seekable_tell (G_SEEKABLE (mis));
+                }
+            }
 
-        if (!just_align)
-          {
-            ret = g_variant_builder_end (&builder);
-          }
-        else
-          {
-            g_variant_builder_clear (&builder);
-          }
-      }
+          ret = g_variant_builder_end (&builder);
+        }
       break;
 
     default:



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]