]> git.ipfire.org Git - thirdparty/dbus.git/commitdiff
dbus-mempool.c: ensure that all alignments are aligned to max_align_t
authorAlex Richardson <arichardson@FreeBSD.org>
Thu, 15 Sep 2022 18:53:30 +0000 (18:53 +0000)
committerSimon McVittie <smcv@collabora.com>
Wed, 21 Sep 2022 11:35:05 +0000 (11:35 +0000)
This is required e.g. for CHERI-enabled targets such as Arm Morello where
aligning to sizeof(long) is not sufficient to load/store pointers (which
need 16 byte alignment instead of 8 bytes).

As we can't depend on C11 yet, this commit adds a max_align_t emulation
to dbus-internals.h.

dbus/dbus-internals.h
dbus/dbus-mempool.c

index deee366f576c03f9bf38122d6828908a51031ee5..4643053b9713ba72adbdf87c66be2e7baa8755f2 100644 (file)
@@ -283,6 +283,21 @@ _dbus_assert_error_xor_bool (const DBusError *error,
 #define _DBUS_ALIGN_ADDRESS(this, boundary) \
   ((void*)_DBUS_ALIGN_VALUE(this, boundary))
 
+#define _DBUS_IS_ALIGNED(this, boundary) \
+  ((((size_t) (uintptr_t) (this)) & ((size_t) (boundary) - 1)) == 0)
+
+/**
+ * Aligning a pointer to _DBUS_ALIGNOF(dbus_max_align_t) guarantees that all
+ * scalar types can be loaded/stored from/to such an address without incurring
+ * an alignment fault (or a slow misaligned access).
+ * This is based on C11 max_align_t, but falls back to DBusBasicValue for
+ * older C standards.
+ */
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
+typedef max_align_t dbus_max_align_t;
+#else
+typedef DBusBasicValue dbus_max_align_t;
+#endif
 
 DBUS_PRIVATE_EXPORT
 char*       _dbus_strdup                (const char  *str);
index c6565351b52ca8e874feee3bd3297e2311fd7130..dc0b44673ca7fca54df63d6c36d76bd7aa916ff7 100644 (file)
@@ -82,12 +82,24 @@ struct DBusMemBlock
                         *   when we free the mem pool.
                         */
 
-  /* this is a size_t so that "elements" is aligned */
   size_t used_so_far;       /**< bytes of this block already allocated as elements. */
-
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
+  /*
+   * Ensure that elements is aligned correctly. For all supported pre-C11
+   * targets, the size_t above should ensure that the elements array is
+   * sufficiently aligned (this is checked in the static assert below).
+   */
+  _Alignas (dbus_max_align_t)
+#endif
   unsigned char elements[]; /**< the block data, actually allocated to required size */
 };
 
+_DBUS_STATIC_ASSERT (_DBUS_IS_ALIGNED (sizeof (struct DBusMemBlock),
+                                       _DBUS_ALIGNOF (dbus_max_align_t)));
+_DBUS_STATIC_ASSERT (_DBUS_IS_ALIGNED (offsetof (struct DBusMemBlock,
+                                                 elements),
+                                       _DBUS_ALIGNOF (dbus_max_align_t)));
+
 /**
  * Internals fields of DBusMemPool
  */
@@ -152,10 +164,11 @@ _dbus_mem_pool_new (int element_size,
   _dbus_assert (element_size >= (int) sizeof (void*));
   _dbus_assert (element_size >= (int) sizeof (DBusFreedElement));
 
-  /* align the element size to a pointer boundary so we won't get bus
-   * errors under other architectures.
+  /* align the element size to be suitable for the most-aligned type
+   * that we care about (in practice usually a pointer).
    */
-  pool->element_size = _DBUS_ALIGN_VALUE (element_size, sizeof (void *));
+  pool->element_size =
+      _DBUS_ALIGN_VALUE (element_size, _DBUS_ALIGNOF (dbus_max_align_t));
 
   pool->zero_elements = zero_elements != FALSE;
 
@@ -239,6 +252,8 @@ _dbus_mem_pool_alloc (DBusMemPool *pool)
 
           VALGRIND_MEMPOOL_ALLOC (pool, (void *) &block->elements[0],
               pool->element_size);
+          _dbus_assert (_DBUS_IS_ALIGNED (&block->elements[0],
+                                          _DBUS_ALIGNOF (dbus_max_align_t)));
           return (void*) &block->elements[0];
         }
       else
@@ -264,7 +279,8 @@ _dbus_mem_pool_alloc (DBusMemPool *pool)
             memset (element, '\0', pool->element_size);
 
           pool->allocated_elements += 1;
-
+          _dbus_assert (
+              _DBUS_IS_ALIGNED (element, _DBUS_ALIGNOF (dbus_max_align_t)));
           return element;
         }
       else
@@ -306,6 +322,8 @@ _dbus_mem_pool_alloc (DBusMemPool *pool)
                 block = dbus_malloc0 (alloc_size);
               else
                 block = dbus_malloc (alloc_size);
+              _dbus_assert (
+                  _DBUS_IS_ALIGNED (block, _DBUS_ALIGNOF (dbus_max_align_t)));
 
 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
               _dbus_set_fail_alloc_counter (saved_counter);
@@ -327,6 +345,8 @@ _dbus_mem_pool_alloc (DBusMemPool *pool)
           pool->allocated_elements += 1;
 
           VALGRIND_MEMPOOL_ALLOC (pool, element, pool->element_size);
+          _dbus_assert (
+              _DBUS_IS_ALIGNED (element, _DBUS_ALIGNOF (dbus_max_align_t)));
           return element;
         }
     }