diff -r 6691e007cef7 -r 473d8cb58a6c ucx/list.c --- a/ucx/list.c Wed Dec 31 12:37:09 2025 +0100 +++ b/ucx/list.c Wed Dec 31 16:40:12 2025 +0100 @@ -31,6 +31,12 @@ #include #include +// we don't want to include the full array_list.h. +// therefore, we only forward declare the one function we want to use +CX_EXPORT void cx_array_qsort_c(void *array, size_t nmemb, size_t size, + cx_compare_func2 fn, void *context); + + int cx_list_compare_wrapper(const void *l, const void *r, void *c) { CxList *list = c; const void *left; @@ -57,33 +63,33 @@ // -static void cx_emptyl_noop(cx_attr_unused CxList *list) { +static void cx_emptyl_noop(CX_UNUSED CxList *list) { // this is a noop, but MUST be implemented } static void *cx_emptyl_at( - cx_attr_unused const struct cx_list_s *list, - cx_attr_unused size_t index + CX_UNUSED const struct cx_list_s *list, + CX_UNUSED size_t index ) { return NULL; } static size_t cx_emptyl_find_remove( - cx_attr_unused struct cx_list_s *list, - cx_attr_unused const void *elem, - cx_attr_unused bool remove + CX_UNUSED struct cx_list_s *list, + CX_UNUSED const void *elem, + CX_UNUSED bool remove ) { return 0; } -static bool cx_emptyl_iter_valid(cx_attr_unused const void *iter) { +static bool cx_emptyl_iter_valid(CX_UNUSED const void *iter) { return false; } static CxIterator cx_emptyl_iterator( const struct cx_list_s *list, size_t index, - cx_attr_unused bool backwards + CX_UNUSED bool backwards ) { CxIterator iter = {0}; iter.src_handle = (void*) list; @@ -141,8 +147,7 @@ const char *src = data; size_t i = 0; for (; i < n; i++) { - if (NULL == list->cl->insert_element(list, index + i, src) - ) { + if (NULL == list->cl->insert_element(list, index + i, src)) { return i; // LCOV_EXCL_LINE } if (src != NULL) { @@ -283,12 +288,6 @@ return cx_list_default_insert_sorted_impl(list, sorted_data, n, false); } -// TODO: remove this hack once we have a solution for qsort() / qsort_s() -static _Thread_local CxList *cx_hack_for_qsort_list; -static int cx_hack_cmp_for_qsort(const void *l, const void *r) { - return cx_list_compare_wrapper(l, r, cx_hack_for_qsort_list); -} - void cx_list_default_sort(struct cx_list_s *list) { size_t elem_size = list->collection.elem_size; size_t list_size = list->collection.size; @@ -304,9 +303,7 @@ } // qsort - // TODO: qsort_s() is not as nice as we thought - cx_hack_for_qsort_list = list; - qsort(tmp, list_size, elem_size, cx_hack_cmp_for_qsort); + cx_array_qsort_c(tmp, list_size, elem_size, cx_list_compare_wrapper, list); // copy elements back loc = tmp; @@ -341,6 +338,13 @@ return 0; } +static int cx_list_cmpfunc2_safe_memcmp(const void *a, const void *b, void *c) { + // it is not safe to store a pointer to the size in the list + // because the entire list structure might get reallocated + size_t elem_size = (size_t)(uintptr_t)c; + return memcmp(a, b, elem_size); +} + void cx_list_init( struct cx_list_s *list, struct cx_list_class_s *cl, @@ -354,8 +358,8 @@ if (elem_size > 0) { list->collection.elem_size = elem_size; list->collection.simple_cmp = NULL; - list->collection.advanced_cmp = cx_acmp_memcmp; - list->collection.cmp_data = &list->collection.elem_size; + list->collection.advanced_cmp = cx_list_cmpfunc2_safe_memcmp; + list->collection.cmp_data = (void*)(uintptr_t)list->collection.elem_size; list->collection.store_pointer = false; } else { list->collection.elem_size = sizeof(void *);