135 lines
5.2 KiB
Diff
135 lines
5.2 KiB
Diff
|
|
From 0f2a6c61c9c5e34d57293fb6987b21f3d1feb1cb Mon Sep 17 00:00:00 2001
|
|||
|
|
From: Philip Withnall <withnall@endlessm.com>
|
|||
|
|
Date: Tue, 13 Feb 2018 13:29:23 +0000
|
|||
|
|
Subject: [PATCH 232/682] =?UTF-8?q?gvariant:=20Realign=20data=20on=20const?=
|
|||
|
|
=?UTF-8?q?ruction=20if=20it=E2=80=99s=20not=20properly=20aligned?=
|
|||
|
|
MIME-Version: 1.0
|
|||
|
|
Content-Type: text/plain; charset=UTF-8
|
|||
|
|
Content-Transfer-Encoding: 8bit
|
|||
|
|
|
|||
|
|
Otherwise the GVariant would later fail internal alignment checks,
|
|||
|
|
aborting the program.
|
|||
|
|
|
|||
|
|
If unaligned data is provided to (for example)
|
|||
|
|
g_variant_new_from_data(), it will copy the data into a new aligned
|
|||
|
|
allocation. This is slow, but better than crashing. If callers want
|
|||
|
|
better performance, they should provide aligned data in their call, and
|
|||
|
|
it will not be copied or reallocated.
|
|||
|
|
|
|||
|
|
Includes a unit test.
|
|||
|
|
|
|||
|
|
Signed-off-by: Philip Withnall <withnall@endlessm.com>
|
|||
|
|
|
|||
|
|
https://gitlab.gnome.org/GNOME/glib/issues/1342
|
|||
|
|
---
|
|||
|
|
glib/gvariant-core.c | 46 +++++++++++++++++++++++++++++++++++++++--
|
|||
|
|
glib/gvariant.c | 10 +++++++++
|
|||
|
|
glib/tests/gvariant.c | 48 +++++++++++++++++++++++++++++++++++++++++++
|
|||
|
|
3 files changed, 102 insertions(+), 2 deletions(-)
|
|||
|
|
|
|||
|
|
diff --git a/glib/gvariant-core.c b/glib/gvariant-core.c
|
|||
|
|
index 815bdf9e0..ef59c7049 100644
|
|||
|
|
--- a/glib/gvariant-core.c
|
|||
|
|
+++ b/glib/gvariant-core.c
|
|||
|
|
@@ -506,6 +506,10 @@ g_variant_alloc (const GVariantType *type,
|
|||
|
|
*
|
|||
|
|
* A reference is taken on @bytes.
|
|||
|
|
*
|
|||
|
|
+ * The data in @bytes must be aligned appropriately for the @type being loaded.
|
|||
|
|
+ * Otherwise this function will internally create a copy of the memory (since
|
|||
|
|
+ * GLib 2.60) or (in older versions) fail and exit the process.
|
|||
|
|
+ *
|
|||
|
|
* Returns: (transfer none): a new #GVariant with a floating reference
|
|||
|
|
*
|
|||
|
|
* Since: 2.36
|
|||
|
|
@@ -518,14 +522,50 @@ g_variant_new_from_bytes (const GVariantType *type,
|
|||
|
|
GVariant *value;
|
|||
|
|
guint alignment;
|
|||
|
|
gsize size;
|
|||
|
|
+ GBytes *owned_bytes = NULL;
|
|||
|
|
|
|||
|
|
value = g_variant_alloc (type, TRUE, trusted);
|
|||
|
|
|
|||
|
|
- value->contents.serialised.bytes = g_bytes_ref (bytes);
|
|||
|
|
-
|
|||
|
|
g_variant_type_info_query (value->type_info,
|
|||
|
|
&alignment, &size);
|
|||
|
|
|
|||
|
|
+ /* Ensure the alignment is correct. This is a huge performance hit if it’s
|
|||
|
|
+ * not correct, but that’s better than aborting if a caller provides data
|
|||
|
|
+ * with the wrong alignment (which is likely to happen very occasionally, and
|
|||
|
|
+ * only cause an abort on some architectures — so is unlikely to be caught
|
|||
|
|
+ * in testing). Callers can always actively ensure they use the correct
|
|||
|
|
+ * alignment to avoid the performance hit. */
|
|||
|
|
+ if ((alignment & (gsize) g_bytes_get_data (bytes, NULL)) != 0)
|
|||
|
|
+ {
|
|||
|
|
+#ifdef HAVE_POSIX_MEMALIGN
|
|||
|
|
+ gpointer aligned_data = NULL;
|
|||
|
|
+ gsize aligned_size = g_bytes_get_size (bytes);
|
|||
|
|
+
|
|||
|
|
+ /* posix_memalign() requires the alignment to be a multiple of
|
|||
|
|
+ * sizeof(void*), and a power of 2. See g_variant_type_info_query() for
|
|||
|
|
+ * details on the alignment format. */
|
|||
|
|
+ if (posix_memalign (&aligned_data, MAX (sizeof (void *), alignment + 1),
|
|||
|
|
+ aligned_size) != 0)
|
|||
|
|
+ g_error ("posix_memalign failed");
|
|||
|
|
+
|
|||
|
|
+ memcpy (aligned_data, g_bytes_get_data (bytes, NULL), aligned_size);
|
|||
|
|
+
|
|||
|
|
+ bytes = owned_bytes = g_bytes_new_with_free_func (aligned_data,
|
|||
|
|
+ aligned_size,
|
|||
|
|
+ free, aligned_data);
|
|||
|
|
+ aligned_data = NULL;
|
|||
|
|
+#else
|
|||
|
|
+ /* NOTE: there may be platforms that lack posix_memalign() and also
|
|||
|
|
+ * have malloc() that returns non-8-aligned. if so, we need to try
|
|||
|
|
+ * harder here.
|
|||
|
|
+ */
|
|||
|
|
+ bytes = owned_bytes = g_bytes_new (g_bytes_get_data (bytes, NULL),
|
|||
|
|
+ g_bytes_get_size (bytes));
|
|||
|
|
+#endif
|
|||
|
|
+ }
|
|||
|
|
+
|
|||
|
|
+ value->contents.serialised.bytes = g_bytes_ref (bytes);
|
|||
|
|
+
|
|||
|
|
if (size && g_bytes_get_size (bytes) != size)
|
|||
|
|
{
|
|||
|
|
/* Creating a fixed-sized GVariant with a bytes of the wrong
|
|||
|
|
@@ -543,6 +583,8 @@ g_variant_new_from_bytes (const GVariantType *type,
|
|||
|
|
value->contents.serialised.data = g_bytes_get_data (bytes, &value->size);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
+ g_clear_pointer (&owned_bytes, g_bytes_unref);
|
|||
|
|
+
|
|||
|
|
return value;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
diff --git a/glib/gvariant.c b/glib/gvariant.c
|
|||
|
|
index d45b487ad..983d4704c 100644
|
|||
|
|
--- a/glib/gvariant.c
|
|||
|
|
+++ b/glib/gvariant.c
|
|||
|
|
@@ -307,6 +307,11 @@
|
|||
|
|
* Constructs a new trusted #GVariant instance from the provided data.
|
|||
|
|
* This is used to implement g_variant_new_* for all the basic types.
|
|||
|
|
*
|
|||
|
|
+ * Note: @data must be backed by memory that is aligned appropriately for the
|
|||
|
|
+ * @type being loaded. Otherwise this function will internally create a copy of
|
|||
|
|
+ * the memory (since GLib 2.60) or (in older versions) fail and exit the
|
|||
|
|
+ * process.
|
|||
|
|
+ *
|
|||
|
|
* Returns: a new floating #GVariant
|
|||
|
|
*/
|
|||
|
|
static GVariant *
|
|||
|
|
@@ -5986,6 +5991,11 @@ g_variant_byteswap (GVariant *value)
|
|||
|
|
* needed. The exact time of this call is unspecified and might even be
|
|||
|
|
* before this function returns.
|
|||
|
|
*
|
|||
|
|
+ * Note: @data must be backed by memory that is aligned appropriately for the
|
|||
|
|
+ * @type being loaded. Otherwise this function will internally create a copy of
|
|||
|
|
+ * the memory (since GLib 2.60) or (in older versions) fail and exit the
|
|||
|
|
+ * process.
|
|||
|
|
+ *
|
|||
|
|
* Returns: (transfer none): a new floating #GVariant of type @type
|
|||
|
|
*
|
|||
|
|
* Since: 2.24
|