GVariant: deal with non-8-aligned malloc()

Closes bug #619585.
This commit is contained in:
Ryan Lortie 2010-05-25 11:25:34 -04:00
parent 9e25ec592b
commit a81c2f2c7a
2 changed files with 64 additions and 26 deletions

View File

@ -139,6 +139,24 @@ g_variant_serialised_check (GVariantSerialised serialised)
else else
g_assert (serialised.size == 0 || serialised.data != NULL); g_assert (serialised.size == 0 || serialised.data != NULL);
/* Depending on the native alignment requirements of the machine, the
* compiler will insert either 3 or 7 padding bytes after the char.
* This will result in the sizeof() the struct being 12 or 16.
* Subtract 9 to get 3 or 7 which is a nice bitmask to apply to get
* the alignment bits that we "care about" being zero: in the
* 4-aligned case, we care about 2 bits, and in the 8-aligned case, we
* care about 3 bits.
*/
alignment &= sizeof (struct {
char a;
union {
guint64 x;
void *y;
gdouble z;
} b;
}
) - 9;
g_assert_cmpint (alignment & (gsize) serialised.data, ==, 0); g_assert_cmpint (alignment & (gsize) serialised.data, ==, 0);
} }

View File

@ -22,6 +22,17 @@
#define INVALIDS "cefjklpwz&@^$" #define INVALIDS "cefjklpwz&@^$"
#define N_INVALIDS (G_N_ELEMENTS (INVALIDS) - 1) #define N_INVALIDS (G_N_ELEMENTS (INVALIDS) - 1)
/* see comment in gvariant-serialiser.c about this madness.
*
* we use this to get testing of non-strictly-aligned GVariant instances
* on machines that can tolerate it. it is necessary to support this
* because some systems have malloc() that returns non-8-aligned
* pointers. it is necessary to have special support in the tests
* because on most machines malloc() is 8-aligned.
*/
#define ALIGN_BITS (sizeof (struct { char a; union { \
guint64 x; void *y; gdouble z; } b; }) - 9)
static gboolean static gboolean
randomly (gdouble prob) randomly (gdouble prob)
{ {
@ -1138,7 +1149,7 @@ random_instance_write (RandomInstance *instance,
GRand *rand; GRand *rand;
gint i; gint i;
g_assert_cmpint ((gsize) buffer & instance->alignment, ==, 0); g_assert_cmpint ((gsize) buffer & ALIGN_BITS & instance->alignment, ==, 0);
rand = g_rand_new_with_seed (instance->seed); rand = g_rand_new_with_seed (instance->seed);
for (i = 0; i < instance->size; i++) for (i = 0; i < instance->size; i++)
@ -1165,7 +1176,7 @@ random_instance_assert (RandomInstance *instance,
GRand *rand; GRand *rand;
gint i; gint i;
g_assert_cmpint ((gsize) buffer & instance->alignment, ==, 0); g_assert_cmpint ((gsize) buffer & ALIGN_BITS & instance->alignment, ==, 0);
g_assert_cmpint (size, ==, instance->size); g_assert_cmpint (size, ==, instance->size);
rand = g_rand_new_with_seed (instance->seed); rand = g_rand_new_with_seed (instance->seed);
@ -1188,7 +1199,7 @@ random_instance_check (RandomInstance *instance,
GRand *rand; GRand *rand;
gint i; gint i;
g_assert_cmpint ((gsize) buffer & instance->alignment, ==, 0); g_assert_cmpint ((gsize) buffer & ALIGN_BITS & instance->alignment, ==, 0);
if (size != instance->size) if (size != instance->size)
return FALSE; return FALSE;
@ -1255,9 +1266,10 @@ flavoured_malloc (gsize size, gsize flavour)
} }
static void static void
flavoured_free (gpointer data) flavoured_free (gpointer data,
gsize flavour)
{ {
g_free ((gpointer) (((gsize) data) & ~7)); g_free (((gchar *) data) - flavour);
} }
static void static void
@ -1342,7 +1354,7 @@ test_maybe (void)
guint alignment; guint alignment;
guint flavour; guint flavour;
alignment = instance->alignment + 1; alignment = (instance->alignment & ALIGN_BITS) + 1;
for (flavour = 0; flavour < 8; flavour += alignment) for (flavour = 0; flavour < 8; flavour += alignment)
{ {
@ -1360,7 +1372,7 @@ test_maybe (void)
g_assert (child.type_info == instance->type_info); g_assert (child.type_info == instance->type_info);
random_instance_assert (instance, child.data, child.size); random_instance_assert (instance, child.data, child.size);
g_variant_type_info_unref (child.type_info); g_variant_type_info_unref (child.type_info);
flavoured_free (serialised.data); flavoured_free (serialised.data, flavour);
} }
} }
@ -1465,7 +1477,7 @@ test_array (void)
guint i; guint i;
g_variant_type_info_query (array_info, &alignment, NULL); g_variant_type_info_query (array_info, &alignment, NULL);
alignment++; alignment = (alignment & ALIGN_BITS) + 1;
for (flavour = 0; flavour < 8; flavour += alignment) for (flavour = 0; flavour < 8; flavour += alignment)
{ {
@ -1491,7 +1503,7 @@ test_array (void)
g_variant_type_info_unref (child.type_info); g_variant_type_info_unref (child.type_info);
} }
flavoured_free (serialised.data); flavoured_free (serialised.data, flavour);
} }
} }
@ -1626,7 +1638,7 @@ test_tuple (void)
gsize flavour; gsize flavour;
guint i; guint i;
alignment++; alignment = (alignment & ALIGN_BITS) + 1;
for (flavour = 0; flavour < 8; flavour += alignment) for (flavour = 0; flavour < 8; flavour += alignment)
{ {
@ -1652,7 +1664,7 @@ test_tuple (void)
g_variant_type_info_unref (child.type_info); g_variant_type_info_unref (child.type_info);
} }
flavoured_free (serialised.data); flavoured_free (serialised.data, flavour);
} }
} }
@ -1714,26 +1726,34 @@ test_variant (void)
} }
{ {
/* variants are 8-aligned, so no extra flavouring */ gsize alignment;
GVariantSerialised serialised; gsize flavour;
GVariantSerialised child;
serialised.type_info = type_info; /* variants are always 8-aligned */
serialised.data = flavoured_malloc (needed_size, 0); alignment = ALIGN_BITS + 1;
serialised.size = needed_size;
g_variant_serialiser_serialise (serialised, random_instance_filler, for (flavour = 0; flavour < 8; flavour += alignment)
(gpointer *) &instance, 1); {
GVariantSerialised serialised;
GVariantSerialised child;
g_assert (memcmp (serialised.data, data, serialised.size) == 0); serialised.type_info = type_info;
g_assert (g_variant_serialised_n_children (serialised) == 1); serialised.data = flavoured_malloc (needed_size, flavour);
serialised.size = needed_size;
child = g_variant_serialised_get_child (serialised, 0); g_variant_serialiser_serialise (serialised, random_instance_filler,
g_assert (child.type_info == instance->type_info); (gpointer *) &instance, 1);
random_instance_check (instance, child.data, child.size);
g_variant_type_info_unref (child.type_info); g_assert (memcmp (serialised.data, data, serialised.size) == 0);
flavoured_free (serialised.data); g_assert (g_variant_serialised_n_children (serialised) == 1);
child = g_variant_serialised_get_child (serialised, 0);
g_assert (child.type_info == instance->type_info);
random_instance_check (instance, child.data, child.size);
g_variant_type_info_unref (child.type_info);
flavoured_free (serialised.data, flavour);
}
} }
g_variant_type_info_unref (type_info); g_variant_type_info_unref (type_info);