gvariant: handle immediate iteration with empty body 41/175941/1 accepted/tizen/4.0/unified/20180418.143508 submit/tizen_4.0/20180418.024055
authorAdrian Szyndela <adrian.s@samsung.com>
Fri, 13 Apr 2018 14:07:53 +0000 (16:07 +0200)
committerAdrian Szyndela <adrian.s@samsung.com>
Fri, 13 Apr 2018 14:14:55 +0000 (16:14 +0200)
With GVariant, we had to do a trade-off. libdbus API does not provide
any function that would state that a message is "finished".
While creating dbus-1 messages, they are always complete.
On additions header fields can change, and all the data is simply
appended. With GVariant it is different. The format does not have
signature field anymore in the header, but it is at the end
of a message, as a part of body variant. After a body variant,
there is also a body offset appended. These values are added to a body
when a message is considered "finished". We have chosen function
dbus_message_lock() as a signal that a message is finished.
This function is always called when a message is added to output queue.

Now, what does actually happen in case of immediate iteration after
creating a message with empty body? The length of the body is zero.
This is not possible for valid GVariant as it has at least one NUL byte,
signature (minimal is '()') and a body offset. It breaks
_dbus_message_gvariant_get_body_length(). However, it can be done with
public interface, therefore this patch:

1. fixes _dbus_message_gvariant_get_body_length() to return 0 in case
of empty body, instead of computing "negative" value.
2. warns users when they try to iterate over a GVariant message
that is not locked.

Change-Id: I2938289d1fc394d214935b173b417c7e38d4ad68

dbus/dbus-marshal-gvariant.c

index 9f3ff3e..2adee4d 100644 (file)
@@ -844,8 +844,14 @@ _dbus_message_gvariant_get_body_length (DBusMessage *message)
 {
   size_t body_len = _dbus_string_get_length (&message->body);
   size_t message_len = body_len + _dbus_string_get_length (&message->header.data);
-  body_len -= bus_gvariant_determine_word_size (message_len , 0);
+  size_t offset_size = bus_gvariant_determine_word_size (message_len, 0);
 
+  if (body_len <= offset_size)
+         return 0;
+
+  body_len -= offset_size;
+
+  /* searching for variant's NULL byte */
   while (body_len > 0 && _dbus_string_get_byte (&message->body, body_len) != 0)
     body_len--;
 
@@ -1448,6 +1454,10 @@ void
 _dbus_type_reader_gvariant_init (DBusTypeReader *reader,
                                  DBusMessage    *message)
 {
+#ifndef DBUS_DISABLE_CHECKS
+  if (!message->locked)
+    _dbus_warn ("Warning: do not use dbus_message_iter_init() on an unlocked message; lock it first with dbus_message_lock()\n");
+#endif
   reader->gvariant = TRUE;
   /* GVariant wraps contents into struct, but in this place type is already
    * stripped off the parentheses (see get_const_signature()).