X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gio%2Fgdbusmessage.c;h=766609ec8a384015bd6a92b8aec473f96aa13130;hb=7fd6f07d498063470903a886b4805a13bd333908;hp=b41f6497b3da7f3091f5dcc11dfa595e06c6bef4;hpb=d108ada4b98cb50fb1517f55c4f09acdaf3de471;p=platform%2Fupstream%2Fglib.git diff --git a/gio/gdbusmessage.c b/gio/gdbusmessage.c index b41f649..766609e 100644 --- a/gio/gdbusmessage.c +++ b/gio/gdbusmessage.c @@ -204,12 +204,12 @@ g_memory_buffer_read_uint64 (GMemoryBuffer *mbuf) #define MIN_ARRAY_SIZE 128 -static gint -g_nearest_pow (gint num) +static gsize +g_nearest_pow (gsize num) { - gint n = 1; + gsize n = 1; - while (n < num) + while (n < num && n > 0) n <<= 1; return n; @@ -261,12 +261,10 @@ g_memory_buffer_write (GMemoryBuffer *mbuf, TODO: This wastes a lot of memory at large buffer sizes. Figure out a more rational allocation strategy. */ new_size = g_nearest_pow (mbuf->pos + count); - /* Check for overflow again. We have only checked if - pos + count > G_MAXSIZE, but it only catches the case of writing - more than 4GiB total on a 32-bit system. There's still the problem - of g_nearest_pow overflowing above 0x7fffffff, so we're - effectively limited to 2GiB. */ - if (new_size < mbuf->len) + /* Check for overflow again. We have checked if + pos + count > G_MAXSIZE, but now check if g_nearest_pow () has + overflowed */ + if (new_size == 0) return FALSE; new_size = MAX (new_size, MIN_ARRAY_SIZE); @@ -1205,6 +1203,27 @@ g_dbus_message_set_unix_fd_list (GDBusMessage *message, /* ---------------------------------------------------------------------------------------------------- */ +static guint +get_type_fixed_size (const GVariantType *type) +{ + /* NB: we do not treat 'b' as fixed-size here because GVariant and + * D-Bus disagree about the size. + */ + switch (*g_variant_type_peek_string (type)) + { + case 'y': + return 1; + case 'n': case 'q': + return 2; + case 'i': case 'u': case 'h': + return 4; + case 'x': case 't': case 'd': + return 8; + default: + return 0; + } +} + static gboolean validate_headers (GDBusMessage *message, GError **error) @@ -1325,7 +1344,7 @@ read_string (GMemoryBuffer *mbuf, gchar *str; const gchar *end_valid; - if (mbuf->pos + len >= mbuf->valid_len || mbuf->pos + len < mbuf->pos) + if G_UNLIKELY (mbuf->pos + len >= mbuf->valid_len || mbuf->pos + len < mbuf->pos) { mbuf->pos = mbuf->valid_len; /* G_GSIZE_FORMAT doesn't work with gettext, so we use %lu */ @@ -1341,7 +1360,7 @@ read_string (GMemoryBuffer *mbuf, return NULL; } - if (mbuf->data[mbuf->pos + len] != '\0') + if G_UNLIKELY (mbuf->data[mbuf->pos + len] != '\0') { str = g_strndup (mbuf->data + mbuf->pos, len); g_set_error (error, @@ -1357,7 +1376,7 @@ read_string (GMemoryBuffer *mbuf, str = mbuf->data + mbuf->pos; mbuf->pos += len + 1; - if (!g_utf8_validate (str, -1, &end_valid)) + if G_UNLIKELY (!g_utf8_validate (str, -1, &end_valid)) { gint offset; gchar *valid_str; @@ -1378,6 +1397,35 @@ read_string (GMemoryBuffer *mbuf, return str; } +static gconstpointer +read_bytes (GMemoryBuffer *mbuf, + gsize len, + GError **error) +{ + gconstpointer result; + + if G_UNLIKELY (mbuf->pos + len > mbuf->valid_len || mbuf->pos + len < mbuf->pos) + { + mbuf->pos = mbuf->valid_len; + /* G_GSIZE_FORMAT doesn't work with gettext, so we use %lu */ + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + g_dngettext (GETTEXT_PACKAGE, + "Wanted to read %lu byte but only got %lu", + "Wanted to read %lu bytes but only got %lu", + (gulong)len), + (gulong)len, + (gulong)(mbuf->valid_len - mbuf->pos)); + return NULL; + } + + result = mbuf->data + mbuf->pos; + mbuf->pos += len; + + return result; +} + /* if just_align==TRUE, don't read a value, just align the input stream wrt padding */ /* returns a non-floating GVariant! */ @@ -1588,10 +1636,8 @@ parse_value_from_blob (GMemoryBuffer *buf, if (!just_align) { guint32 array_len; - goffset offset; - goffset target; const GVariantType *element_type; - GVariantBuilder builder; + guint fixed_size; array_len = g_memory_buffer_read_uint32 (buf); @@ -1614,44 +1660,82 @@ parse_value_from_blob (GMemoryBuffer *buf, goto fail; } - g_variant_builder_init (&builder, type); element_type = g_variant_type_element (type); + fixed_size = get_type_fixed_size (element_type); - if (array_len == 0) + /* Fast-path the cases like 'ay', etc. */ + if (fixed_size != 0) { - GVariant *item; - item = parse_value_from_blob (buf, - element_type, - TRUE, - indent + 2, - NULL); - g_assert (item == NULL); + gconstpointer array_data; + + if (array_len % fixed_size != 0) + { + g_set_error (&local_error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + _("Encountered array of type 'a%c', expected to have a length a multiple " + "of %u bytes, but found to be %u bytes in length"), + g_variant_type_peek_string (element_type)[0], fixed_size, array_len); + goto fail; + } + + ensure_input_padding (buf, fixed_size); + array_data = read_bytes (buf, array_len, &local_error); + if (array_data == NULL) + goto fail; + + ret = g_variant_new_fixed_array (element_type, array_data, array_len / fixed_size, fixed_size); + + if (g_memory_buffer_is_byteswapped (buf)) + { + GVariant *tmp = g_variant_ref_sink (ret); + ret = g_variant_byteswap (tmp); + g_variant_unref (tmp); + } } else { - /* TODO: optimize array of primitive types */ - offset = buf->pos; - target = offset + array_len; - while (offset < target) + GVariantBuilder builder; + goffset offset; + goffset target; + + g_variant_builder_init (&builder, type); + + if (array_len == 0) { GVariant *item; item = parse_value_from_blob (buf, element_type, - FALSE, + TRUE, indent + 2, - &local_error); - if (item == NULL) + NULL); + g_assert (item == NULL); + } + else + { + offset = buf->pos; + target = offset + array_len; + while (offset < target) { - g_variant_builder_clear (&builder); - goto fail; + GVariant *item; + item = parse_value_from_blob (buf, + 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 = buf->pos; } - g_variant_builder_add_value (&builder, item); - g_variant_unref (item); - offset = buf->pos; } - } - ret = g_variant_builder_end (&builder); + ret = g_variant_builder_end (&builder); + } } break; @@ -1812,12 +1896,9 @@ parse_value_from_blob (GMemoryBuffer *buf, is_leaf = is_leaf; /* To avoid -Wunused-but-set-variable */ #endif /* DEBUG_SERIALIZER */ - /* sink the reference */ + /* sink the reference, if floating */ if (ret != NULL) - { - g_assert (g_variant_is_floating (ret)); - g_variant_ref_sink (ret); - } + g_variant_take_ref (ret); return ret; fail: @@ -2283,12 +2364,14 @@ append_value_to_blob (GVariant *value, case 'a': /* G_VARIANT_TYPE_ARRAY */ { + const GVariantType *element_type; GVariant *item; GVariantIter iter; goffset array_len_offset; goffset array_payload_begin_offset; goffset cur_offset; gsize array_len; + guint fixed_size; padding_added = ensure_output_padding (mbuf, 4); if (value != NULL) @@ -2312,17 +2395,35 @@ append_value_to_blob (GVariant *value, */ array_payload_begin_offset = mbuf->valid_len; + element_type = g_variant_type_element (type); + fixed_size = get_type_fixed_size (element_type); + if (g_variant_n_children (value) == 0) { gsize padding_added_for_item; if (!append_value_to_blob (NULL, - g_variant_type_element (type), + element_type, mbuf, &padding_added_for_item, error)) goto fail; array_payload_begin_offset += padding_added_for_item; } + else if (fixed_size != 0) + { + GVariant *use_value; + + if (g_memory_buffer_is_byteswapped (mbuf)) + use_value = g_variant_byteswap (value); + else + use_value = g_variant_ref (value); + + array_payload_begin_offset += ensure_output_padding (mbuf, fixed_size); + + array_len = g_variant_get_size (use_value); + g_memory_buffer_write (mbuf, g_variant_get_data (use_value), array_len); + g_variant_unref (use_value); + } else { guint n;