dbus-mempool.c: ensure that all alignments are aligned to max_align_t

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.
This commit is contained in:
Alex Richardson 2022-09-15 18:53:30 +00:00 committed by Simon McVittie
parent c4a8c2d920
commit 33dbeb5ebe
2 changed files with 41 additions and 6 deletions

View 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);

View 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;
}
}