See https://bugzilla.gnome.org/show_bug.cgi?id=621838 for the whole
story. The problem was that we ended up reading data from arrays of
arrays when we were just supposed to be aligning the buffers.
Also add a host of debug infrastructure that was needed to find the
root cause. For now it can be turned on only via defining
DEBUG_SERIALIZER. In the future we might want to make it work via
G_DBUS_DEBUG. In a nutshell, the added debug info looks like this
Parsing blob (blob_len = 0x0084 bytes)
0000: 6c 01 00 01 3c 00 00 00 41 00 00 00 37 00 00 00 l...<...A...7...
0010: 08 01 67 00 08 61 61 79 61 7b 73 76 7d 00 00 00 ..g..aaya{sv}...
0020: 01 01 6f 00 08 00 00 00 2f 66 6f 6f 2f 62 61 72 ..o...../foo/bar
0030: 00 00 00 00 00 00 00 00 03 01 73 00 06 00 00 00 ..........s.....
0040: 4d 65 6d 62 65 72 00 00 00 00 00 00 34 00 00 00 Member......4...
0050: 03 00 00 00 63 77 64 00 01 73 00 00 23 00 00 00 ....cwd..s..#...
0060: 2f 68 6f 6d 65 2f 64 61 76 69 64 7a 2f 48 61 63 /home/davidz/Hac
0070: 6b 69 6e 67 2f 67 6c 69 62 2f 67 69 6f 2f 74 65 king/glib/gio/te
0080: 73 74 73 00 sts.
Parsing headers (blob_len = 0x0084 bytes)
Reading type a{yv} from offset 0x000c: array spans 0x0037 bytes
Reading type {yv} from offset 0x0010
Reading type y from offset 0x0010: 0x08 '
Reading type v from offset 0x0011
Reading type g from offset 0x0014: 'aaya{sv}'
Reading type {yv} from offset 0x001e
Reading type y from offset 0x0020: 0x01 '\ 1'
Reading type v from offset 0x0021
Reading type o from offset 0x0024: '/foo/bar'
Reading type {yv} from offset 0x0031
Reading type y from offset 0x0038: 0x03 '\ 3'
Reading type v from offset 0x0039
Reading type s from offset 0x003c: 'Member'
Parsing body (blob_len = 0x0084 bytes)
Reading type (aaya{sv}) from offset 0x0047
Reading type aay from offset 0x0048: array spans 0x0000 bytes
Reading type a{sv} from offset 0x004c: array spans 0x0034 bytes
Reading type {sv} from offset 0x0050
Reading type s from offset 0x0050: 'cwd'
Reading type v from offset 0x0058
Reading type s from offset 0x005b: '/home/davidz/Hacking/glib/gio/tests'
OK
Signed-off-by: David Zeuthen <davidz@redhat.com>
* Author: David Zeuthen <davidz@redhat.com>
*/
* Author: David Zeuthen <davidz@redhat.com>
*/
+/* Uncomment to debug serializer code */
+/* #define DEBUG_SERIALIZER */
+
#include "config.h"
#include <string.h>
#include "config.h"
#include <string.h>
#include "gmemoryoutputstream.h"
#include "gseekable.h"
#include "gioerror.h"
#include "gmemoryoutputstream.h"
#include "gseekable.h"
#include "gioerror.h"
+#include "gdbusprivate.h"
#ifdef G_OS_UNIX
#include "gunixfdlist.h"
#ifdef G_OS_UNIX
#include "gunixfdlist.h"
offset = g_seekable_tell (G_SEEKABLE (mis));
wanted_offset = ((offset + padding_size - 1) / padding_size) * padding_size;
offset = g_seekable_tell (G_SEEKABLE (mis));
wanted_offset = ((offset + padding_size - 1) / padding_size) * padding_size;
- /*g_debug ("ensure_input_padding(%d) pushed offset 0x%04x to 0x%04x", (gint) padding_size, (gint) offset, (gint) wanted_offset);*/
-
- return g_seekable_seek (G_SEEKABLE (mis), wanted_offset, G_SEEK_SET, NULL, error);
+ if (offset != wanted_offset)
+ {
+ return g_seekable_seek (G_SEEKABLE (mis), wanted_offset, G_SEEK_SET, NULL, error);
+ }
+ else
+ {
+ return TRUE;
+ }
GDataInputStream *dis,
const GVariantType *type,
gboolean just_align,
GDataInputStream *dis,
const GVariantType *type,
gboolean just_align,
GError **error)
{
GVariant *ret;
GError *local_error;
GError **error)
{
GVariant *ret;
GError *local_error;
- /*g_debug ("Reading type %s from offset 0x%04x", g_variant_type_dup_string (type), (gint) g_seekable_tell (G_SEEKABLE (mis)));*/
+#ifdef DEBUG_SERIALIZER
+ if (!just_align)
+ {
+ gchar *s;
+ s = g_variant_type_dup_string (type);
+ g_print ("%*sReading type %s from offset 0x%04x",
+ indent, "",
+ s,
+ (gint) g_seekable_tell (G_SEEKABLE (mis)));
+ g_free (s);
+ }
+#endif /* DEBUG_SERIALIZER */
local_error = NULL;
if (g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN))
{
local_error = NULL;
if (g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN))
{
if (!ensure_input_padding (mis, 4, &local_error))
goto fail;
if (!ensure_input_padding (mis, 4, &local_error))
goto fail;
- array_len = g_data_input_stream_read_uint32 (dis, NULL, &local_error);
- if (local_error != NULL)
- goto fail;
- if (array_len > (2<<26))
- g_set_error (&local_error,
- G_IO_ERROR,
- G_IO_ERROR_INVALID_ARGUMENT,
- _("Encountered array of length %" G_GUINT32_FORMAT " bytes. Maximum length is 2<<26 bytes."),
- array_len);
- goto fail;
+ array_len = 0;
+ }
+ else
+ {
+ array_len = g_data_input_stream_read_uint32 (dis, NULL, &local_error);
+ if (local_error != NULL)
+ goto fail;
+
+ is_leaf = FALSE;
+#ifdef DEBUG_SERIALIZER
+ g_print (": array spans 0x%04x bytes\n", array_len);
+#endif /* DEBUG_SERIALIZER */
+
+ if (array_len > (2<<26))
+ {
+ g_set_error (&local_error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Encountered array of length %" G_GUINT32_FORMAT " bytes. Maximum length is 2<<26 bytes."),
+ array_len);
+ goto fail;
+ }
}
g_variant_builder_init (&builder, type);
}
g_variant_builder_init (&builder, type);
&local_error);
g_assert (item == NULL);
}
&local_error);
g_assert (item == NULL);
}
dis,
element_type,
FALSE,
dis,
element_type,
FALSE,
&local_error);
if (item == NULL)
{
&local_error);
if (item == NULL)
{
if (!ensure_input_padding (mis, 8, &local_error))
goto fail;
if (!ensure_input_padding (mis, 8, &local_error))
goto fail;
+ is_leaf = FALSE;
+#ifdef DEBUG_SERIALIZER
+ g_print ("\n");
+#endif /* DEBUG_SERIALIZER */
+
if (!just_align)
{
key_type = g_variant_type_key (type);
if (!just_align)
{
key_type = g_variant_type_key (type);
&local_error);
if (key == NULL)
goto fail;
&local_error);
if (key == NULL)
goto fail;
&local_error);
if (value == NULL)
{
&local_error);
if (value == NULL)
{
if (!ensure_input_padding (mis, 8, &local_error))
goto fail;
if (!ensure_input_padding (mis, 8, &local_error))
goto fail;
+ is_leaf = FALSE;
+#ifdef DEBUG_SERIALIZER
+ g_print ("\n");
+#endif /* DEBUG_SERIALIZER */
+
if (!just_align)
{
const GVariantType *element_type;
if (!just_align)
{
const GVariantType *element_type;
dis,
element_type,
FALSE,
dis,
element_type,
FALSE,
&local_error);
if (item == NULL)
{
&local_error);
if (item == NULL)
{
}
else if (g_variant_type_is_variant (type))
{
}
else if (g_variant_type_is_variant (type))
{
+ is_leaf = FALSE;
+#ifdef DEBUG_SERIALIZER
+ g_print ("\n");
+#endif /* DEBUG_SERIALIZER */
+
if (!just_align)
{
guchar siglen;
if (!just_align)
{
guchar siglen;
dis,
variant_type,
FALSE,
dis,
variant_type,
FALSE,
&local_error);
g_variant_type_free (variant_type);
if (value == NULL)
&local_error);
g_variant_type_free (variant_type);
if (value == NULL)
}
g_assert ((just_align && ret == NULL) || (!just_align && ret != NULL));
}
g_assert ((just_align && ret == NULL) || (!just_align && ret != NULL));
+
+#ifdef DEBUG_SERIALIZER
+ if (ret != NULL)
+ {
+ if (is_leaf)
+ {
+ gchar *s;
+ if (g_variant_type_equal (type, G_VARIANT_TYPE_BYTE))
+ {
+ s = g_strdup_printf ("0x%02x '%c'", g_variant_get_byte (ret), g_variant_get_byte (ret));
+ }
+ else
+ {
+ s = g_variant_print (ret, FALSE);
+ }
+ g_print (": %s\n", s);
+ g_free (s);
+ }
+ }
+#endif /* DEBUG_SERIALIZER */
+
+#ifdef DEBUG_SERIALIZER
+ g_print ("\n"
+ "%*sFAILURE: %s (%s, %d)\n",
+ indent, "",
+ local_error->message,
+ g_quark_to_string (local_error->domain),
+ local_error->code);
+#endif /* DEBUG_SERIALIZER */
g_propagate_error (error, local_error);
return NULL;
}
g_propagate_error (error, local_error);
return NULL;
}
message_body_len = g_data_input_stream_read_uint32 (dis, NULL, NULL);
message->priv->serial = g_data_input_stream_read_uint32 (dis, NULL, NULL);
message_body_len = g_data_input_stream_read_uint32 (dis, NULL, NULL);
message->priv->serial = g_data_input_stream_read_uint32 (dis, NULL, NULL);
+#ifdef DEBUG_SERIALIZER
+ g_print ("Parsing blob (blob_len = 0x%04x bytes)\n", (gint) blob_len);
+ {
+ gchar *s;
+ s = _g_dbus_hexdump ((const gchar *) blob, blob_len, 2);
+ g_print ("%s\n", s);
+ g_free (s);
+ }
+#endif /* DEBUG_SERIALIZER */
+
+#ifdef DEBUG_SERIALIZER
+ g_print ("Parsing headers (blob_len = 0x%04x bytes)\n", (gint) blob_len);
+#endif /* DEBUG_SERIALIZER */
headers = parse_value_from_blob (mis,
dis,
G_VARIANT_TYPE ("a{yv}"),
FALSE,
headers = parse_value_from_blob (mis,
dis,
G_VARIANT_TYPE ("a{yv}"),
FALSE,
error);
if (headers == NULL)
goto out;
error);
if (headers == NULL)
goto out;
tupled_signature_str = g_strdup_printf ("(%s)", signature_str);
variant_type = g_variant_type_new (tupled_signature_str);
g_free (tupled_signature_str);
tupled_signature_str = g_strdup_printf ("(%s)", signature_str);
variant_type = g_variant_type_new (tupled_signature_str);
g_free (tupled_signature_str);
+#ifdef DEBUG_SERIALIZER
+ g_print ("Parsing body (blob_len = 0x%04x bytes)\n", (gint) blob_len);
+#endif /* DEBUG_SERIALIZER */
message->priv->body = parse_value_from_blob (mis,
dis,
variant_type,
FALSE,
message->priv->body = parse_value_from_blob (mis,
dis,
variant_type,
FALSE,
error);
if (message->priv->body == NULL)
{
error);
if (message->priv->body == NULL)
{
/* ---------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------- */
-static gchar *
-hexdump (const gchar *data, gsize len, guint indent)
+gchar *
+_g_dbus_hexdump (const gchar *data, gsize len, guint indent)
{
guint n, m;
GString *ret;
{
guint n, m;
GString *ret;
if (message == NULL)
{
gchar *s;
if (message == NULL)
{
gchar *s;
- s = hexdump (worker->read_buffer, worker->read_buffer_cur_size, 2);
+ s = _g_dbus_hexdump (worker->read_buffer, worker->read_buffer_cur_size, 2);
g_warning ("Error decoding D-Bus message of %" G_GSIZE_FORMAT " bytes\n"
"The error is: %s\n"
"The payload is as follows:\n"
g_warning ("Error decoding D-Bus message of %" G_GSIZE_FORMAT " bytes\n"
"The error is: %s\n"
"The payload is as follows:\n"
s = g_dbus_message_print (message, 2);
g_print ("%s", s);
g_free (s);
s = g_dbus_message_print (message, 2);
g_print ("%s", s);
g_free (s);
- s = hexdump (worker->read_buffer, worker->read_buffer_cur_size, 2);
+ s = _g_dbus_hexdump (worker->read_buffer, worker->read_buffer_cur_size, 2);
g_print ("%s\n", s);
g_free (s);
}
g_print ("%s\n", s);
g_free (s);
}
s = g_dbus_message_print (data->message, 2);
g_print ("%s", s);
g_free (s);
s = g_dbus_message_print (data->message, 2);
g_print ("%s", s);
g_free (s);
- s = hexdump (data->blob, data->blob_size, 2);
+ s = _g_dbus_hexdump (data->blob, data->blob_size, 2);
g_print ("%s\n", s);
g_free (s);
}
g_print ("%s\n", s);
g_free (s);
}
GVariantType * _g_dbus_compute_complete_signature (GDBusArgInfo **args);
GVariantType * _g_dbus_compute_complete_signature (GDBusArgInfo **args);
+gchar *_g_dbus_hexdump (const gchar *data, gsize len, guint indent);
+
/* ---------------------------------------------------------------------------------------------------- */
#ifdef G_OS_WIN32
/* ---------------------------------------------------------------------------------------------------- */
#ifdef G_OS_WIN32
"value 1: array:\n"
"value 2: array:\n"
" string: `Something'\n");
"value 1: array:\n"
"value 2: array:\n"
" string: `Something'\n");
+
+ /* https://bugzilla.gnome.org/show_bug.cgi?id=621838 */
+ check_serialization (g_variant_new_parsed ("(@aay [], {'cwd': <'/home/davidz/Hacking/glib/gio/tests'>})"),
+ "value 0: array:\n"
+ "value 1: array:\n"
+ " dict_entry:\n"
+ " string: `cwd'\n"
+ " variant:\n"
+ " string: `/home/davidz/Hacking/glib/gio/tests'\n");