From: Ryan Lortie Date: Thu, 4 Dec 2014 01:35:18 +0000 (-0500) Subject: finish up vector deserialiser X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;ds=sidebyside;h=4d7d5bd26f10c8bdd6ac5eae97b1c6ed559deaed;p=platform%2Fupstream%2Fglib.git finish up vector deserialiser seems to have stopped crashing now... --- diff --git a/glib/gvariant-core.c b/glib/gvariant-core.c index 62aabaa..ea0a94e 100644 --- a/glib/gvariant-core.c +++ b/glib/gvariant-core.c @@ -675,6 +675,19 @@ g_variant_vector_deserialise (GVariantTypeInfo *type_info, { g_assert (size > 0); +#if 0 + gsize tally = 0; + gint i; + + g_print ("enter as %s (size %d)\n", g_variant_type_info_get_type_string (type_info), (guint) size); + for (i = 0; first_vector + i <= last_vector; i++) + { + g_print (" %p %d\n", first_vector[i].data.pointer, (guint) first_vector[i].size); + tally += first_vector[i].size; + } + g_assert_cmpint (size, ==, tally); +#endif + if (first_vector < last_vector) { GVariantVector *vector = first_vector; @@ -691,6 +704,16 @@ g_variant_vector_deserialise (GVariantTypeInfo *type_info, { /* We are supposed to consume type_info */ g_variant_type_info_unref (type_info); + + for (i = offset; i < children->len; i++) + { + GVariantUnpacked *unpacked = &g_array_index (children, GVariantUnpacked, i); + + g_variant_type_info_unref (unpacked->type_info); + } + + g_array_set_size (children, offset); + return FALSE; } @@ -701,7 +724,8 @@ g_variant_vector_deserialise (GVariantTypeInfo *type_info, { GVariantUnpacked *unpacked; GVariantVector *fv; - gsize saved_size; + const guchar *resume_at; + gsize resume_at_size; unpacked = &g_array_index (children, GVariantUnpacked, offset + i); @@ -717,6 +741,9 @@ g_variant_vector_deserialise (GVariantTypeInfo *type_info, unpacked->skip -= vector->size; vector++; } + g_assert (vector >= first_vector); + g_assert (vector <= last_vector); + fv = vector; fv->data.pointer += unpacked->skip; fv->size -= unpacked->skip; @@ -736,14 +763,21 @@ g_variant_vector_deserialise (GVariantTypeInfo *type_info, * it is the end of our child. */ size = unpacked->size; + //g_print ("need to seek %d bytes\n", (guint) size); while (unpacked->size > vector->size) { + //g_print (" skipping %d\n", (guint) vector->size); unpacked->size -= vector->size; vector++; } + g_assert (vector >= first_vector); + g_assert (vector <= last_vector); + /* temporarily replace the size field */ - saved_size = vector->size; + //g_print ("--adj last size from %d to %d\n", (guint) vector->size, (guint) unpacked->size); + resume_at = vector->data.pointer + unpacked->size; + resume_at_size = vector->size - unpacked->size; vector->size = unpacked->size; new[i] = g_variant_vector_deserialise (unpacked->type_info, fv, vector, size, trusted, children); @@ -761,7 +795,7 @@ g_variant_vector_deserialise (GVariantTypeInfo *type_info, /* Consume the type_info for the remaining children */ for (j = i + 1; j < n; j++) - g_variant_type_info_unref (g_array_index (children, GVariantUnpacked, offset + i).type_info); + g_variant_type_info_unref (g_array_index (children, GVariantUnpacked, offset + j).type_info); /* Rewind this */ g_array_set_size (children, offset); @@ -773,8 +807,10 @@ g_variant_vector_deserialise (GVariantTypeInfo *type_info, } /* Repair the last vector and move past our data */ - vector->data.pointer += unpacked->size; - vector->size -= saved_size - unpacked->size; + //g_print ("chug %d\n", (guint) unpacked->size); + vector->data.pointer = resume_at; + vector->size = resume_at_size; + //g_print ("now have %d left\n", (guint) vector->size); } /* Rewind */ diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c index 7880c5a..d5cbd3c 100644 --- a/glib/gvariant-serialiser.c +++ b/glib/gvariant-serialiser.c @@ -864,14 +864,16 @@ gvs_variable_sized_array_unpack_all (GVariantTypeInfo *type_info, end = gvs_read_unaligned_le (offsets, offset_size); offsets += offset_size; - if (start < prev_end || end < start) { g_assert_not_reached (); - return FALSE; /* XXX free the array and type infos */ } + if (start < prev_end || end < start) + return FALSE; unpacked.type_info = g_variant_type_info_ref (element); unpacked.skip = start - prev_end; unpacked.size = end - start; g_array_append_val (results, unpacked); + + prev_end = end; } return TRUE; @@ -1155,13 +1157,82 @@ gvs_tuple_get_child (GVariantSerialised value, static gboolean gvs_tuple_unpack_all (GVariantTypeInfo *type_info, - const guchar *end, + const guchar *end_pointer, gsize end_size, gsize total_size, GArray *results) { - g_assert_not_reached (); /* FIXME */ - return FALSE; + gsize offset_size; + gsize prev_end; + gsize i, n; + + n = g_variant_type_info_n_members (type_info); + + /* An empty tuple (n = 0) is always encoded as a single byte, which + * means that we should not be attempting to unpack it from multiple + * vectors. + */ + if (n == 0) + return FALSE; + + offset_size = gvs_get_offset_size (total_size); + + prev_end = 0; + + for (i = 0; i < n; i++) + { + const GVariantMemberInfo *member_info; + GVariantUnpacked unpacked; + gsize fixed_size; + guint alignment; + gsize start; + gsize end; + + member_info = g_variant_type_info_member_info (type_info, i); + g_variant_type_info_query (member_info->type_info, &alignment, &fixed_size); + + start = prev_end + ((-prev_end) & alignment); + + switch (member_info->ending_type) + { + case G_VARIANT_MEMBER_ENDING_FIXED: + end = start + fixed_size; + break; + + case G_VARIANT_MEMBER_ENDING_LAST: + end = total_size; + break; + + case G_VARIANT_MEMBER_ENDING_OFFSET: + if (end_size < offset_size) + return FALSE; + + end_pointer -= offset_size; + total_size -= offset_size; + end_size -= offset_size; + + end = gvs_read_unaligned_le (end_pointer, offset_size); + break; + + default: + g_assert_not_reached (); + } + + if (start < prev_end || end < start) + return FALSE; + + unpacked.type_info = g_variant_type_info_ref (member_info->type_info); + unpacked.skip = start - prev_end; + unpacked.size = end - start; + + g_array_append_val (results, unpacked); + + prev_end = end; + } + + g_assert (prev_end == total_size); + + return TRUE; } static gsize @@ -1515,14 +1586,71 @@ gvs_variant_get_child (GVariantSerialised value, return child; } +static GVariantTypeInfo * +gvs_variant_find_type (const guchar *end_pointer, + gsize end_size, + gsize total_size, + gsize *child_size) +{ + gsize i; + + for (i = 1; i <= end_size; i++) + if (end_pointer[-i] == '\0') + { + const gchar *type_string = (gchar *) end_pointer - i + 1; + const gchar *limit = (gchar *) end_pointer; + const gchar *end; + + /* We may have a type string of length 'i'. Check for validity. */ + if (g_variant_type_string_scan (type_string, limit, &end) && end == limit) + { + const GVariantType *type = (GVariantType *) type_string; + + if (g_variant_type_is_definite (type)) + { + GVariantTypeInfo *type_info; + gsize fixed_size; + + type_info = g_variant_type_info_get (type); + + g_variant_type_info_query (type_info, NULL, &fixed_size); + + if (!fixed_size || fixed_size == total_size - i) + { + *child_size = total_size - i; + + return type_info; + } + + g_variant_type_info_unref (type_info); + } + } + + /* No sense in trying other lengths if we already failed */ + break; + } + + return NULL; +} + static gboolean gvs_variant_unpack_all (GVariantTypeInfo *type_info, - const guchar *end, + const guchar *end_pointer, gsize end_size, gsize total_size, GArray *results) { - g_assert_not_reached (); /* FIXME */ + GVariantUnpacked unpacked; + + if ((unpacked.type_info = gvs_variant_find_type (end_pointer, end_size, total_size, &unpacked.size))) + { + unpacked.skip = 0; + + g_array_append_val (results, unpacked); + + return TRUE; + } + return FALSE; } diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c index d42bdfb..3d38b4f 100644 --- a/glib/tests/gvariant.c +++ b/glib/tests/gvariant.c @@ -4643,9 +4643,26 @@ test_vector_serialiser (void) for (i = 0; i < 100; i++) { - value = create_random_gvariant (4); + guint j; + + value = create_random_gvariant (2); + //g_print (">>> %s\n", g_variant_print (value, TRUE)); GLIB_PRIVATE_CALL(g_variant_to_vectors) (value, &vectors); + for (j = 0; j < vectors.vectors->len; j++) + { + GVariantVector *v = &g_array_index (vectors.vectors, GVariantVector, j); + + if (!v->gbytes) + { + v->gbytes = g_bytes_new (NULL, 0); + v->data.pointer = v->data.offset + vectors.extra_bytes->data; + } + + //g_print (" V %p %p %d\n", v, v->data.pointer, (guint) v->size); + } + GLIB_PRIVATE_CALL(g_variant_from_vectors) (g_variant_get_type (value), (GVariantVector *) vectors.vectors->data, vectors.vectors->len, g_variant_get_size (value), TRUE); + continue; flattened = flatten_vectors (&vectors); g_byte_array_free (vectors.extra_bytes, TRUE); g_byte_array_free (vectors.offsets, TRUE);