# HG changeset patch # User Mike Becker # Date 1764513675 -3600 # Node ID 313fd460d264a69aa172c285c44513790f630c30 # Parent 3ee5a5c7823ac6a270637dec71cd35c207dca924 fix missing memory alignment for linked list node extra data diff -r 3ee5a5c7823a -r 313fd460d264 src/cx/linked_list.h --- a/src/cx/linked_list.h Sun Nov 30 15:06:02 2025 +0100 +++ b/src/cx/linked_list.h Sun Nov 30 15:41:15 2025 +0100 @@ -62,7 +62,14 @@ */ off_t loc_data; /** + * Location of extra data (optional). + * Negative when no extra data is requested. + * @see cx_linked_list_extra_data() + */ + off_t loc_extra; + /** * Additional bytes to allocate @em behind the payload (e.g. for metadata). + * @see cx_linked_list_extra_data() */ size_t extra_data_len; /** @@ -112,6 +119,23 @@ cxLinkedListCreate(NULL, NULL, elem_size) /** + * Instructs the linked list to reserve extra data in each node. + * + * The extra data will be aligned and placed behind the element data. + * The exact location in the node is stored in the @c loc_extra field + * of the linked list. + * + * You should usually not use this function except when you are creating an + * own linked-list implementation that is based on the UCX linked list and + * needs to store extra data in each node. + * + * @param list the list (must be a linked list) + * @param len the length of the extra data + */ +cx_attr_nonnull +CX_EXPORT void cx_linked_list_extra_data(cx_linked_list *list, size_t len); + +/** * Finds the node at a certain index. * * This function can be used to start at an arbitrary position within the list. diff -r 3ee5a5c7823a -r 313fd460d264 src/kv_list.c --- a/src/kv_list.c Sun Nov 30 15:06:02 2025 +0100 +++ b/src/kv_list.c Sun Nov 30 15:41:15 2025 +0100 @@ -98,7 +98,7 @@ } static CxHashKey *cx_kv_list_loc_key(cx_kv_list *list, void *node_data) { - return (CxHashKey*)((char*)node_data + list->list.base.collection.elem_size); + return (CxHashKey*)((char*)node_data - list->list.loc_data + list->list.loc_extra); } static void cx_kvl_deallocate(struct cx_list_s *list) { @@ -559,7 +559,7 @@ CxList *list = cxLinkedListCreate(allocator, comparator, elem_size); if (list == NULL) return NULL; // LCOV_EXCL_LINE cx_linked_list *ll = (cx_linked_list*)list; - ll->extra_data_len = sizeof(CxHashKey); + cx_linked_list_extra_data(ll, sizeof(CxHashKey)); CxMap *map = cxHashMapCreate(allocator, CX_STORE_POINTERS, 0); if (map == NULL) { // LCOV_EXCL_START cxListFree(list); diff -r 3ee5a5c7823a -r 313fd460d264 src/linked_list.c --- a/src/linked_list.c Sun Nov 30 15:06:02 2025 +0100 +++ b/src/linked_list.c Sun Nov 30 15:41:15 2025 +0100 @@ -692,8 +692,13 @@ } static void *cx_ll_malloc_node(const cx_linked_list *list) { - return cxZalloc(list->base.collection.allocator, - list->loc_data + list->base.collection.elem_size + list->extra_data_len); + size_t n; + if (list->extra_data_len == 0) { + n = list->loc_data + list->base.collection.elem_size; + } else { + n = list->loc_extra + list->extra_data_len; + } + return cxZalloc(list->base.collection.allocator, n); } static int cx_ll_insert_at( @@ -1267,12 +1272,22 @@ cx_linked_list *list = cxCalloc(allocator, 1, sizeof(cx_linked_list)); if (list == NULL) return NULL; - list->extra_data_len = 0; list->loc_prev = 0; list->loc_next = sizeof(void*); list->loc_data = sizeof(void*)*2; + list->loc_extra = -1; + list->extra_data_len = 0; cx_list_init((CxList*)list, &cx_linked_list_class, allocator, comparator, elem_size); return (CxList *) list; } + +void cx_linked_list_extra_data(cx_linked_list *list, size_t len) { + list->extra_data_len = len; + + off_t loc_extra = list->loc_data + list->base.collection.elem_size; + size_t alignment = alignof(void*); + size_t padding = alignment - (loc_extra % alignment); + list->loc_extra = loc_extra + padding; +}