From ef1400dea95a9ec538b645396ced0657d180fdd9 Mon Sep 17 00:00:00 2001 From: Alan Wu Date: Tue, 16 Feb 2021 20:48:14 -0500 Subject: [PATCH 1/4] darray: fix buffer size calculation for element with strict alignment --- darray.h | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/darray.h b/darray.h index c7e352cded975f..5f270e0ca36847 100644 --- a/darray.h +++ b/darray.h @@ -42,13 +42,13 @@ // // bool rb_darray_append(rb_darray(T) *ptr_to_ary, T element); // -#define rb_darray_append(ptr_to_ary, element) ( \ - rb_darray_ensure_space((ptr_to_ary)) ? ( \ - rb_darray_set(*(ptr_to_ary), \ - (*(ptr_to_ary))->meta.size, \ - (element)), \ - ++((*(ptr_to_ary))->meta.size), \ - 1 \ +#define rb_darray_append(ptr_to_ary, element) ( \ + rb_darray_ensure_space((ptr_to_ary), sizeof(**(ptr_to_ary)), sizeof((*(ptr_to_ary))->data[0])) ? ( \ + rb_darray_set(*(ptr_to_ary), \ + (*(ptr_to_ary))->meta.size, \ + (element)), \ + ++((*(ptr_to_ary))->meta.size), \ + 1 \ ) : 0) // Iterate over items of the array in a for loop @@ -91,21 +91,25 @@ rb_darray_free(void *ary) // #define rb_darray_pop_back(ary) ((ary)->meta.size--) -// Internal macro -// Ensure there is space for one more element. Return 1 on success and 0 on failure. -// `ptr_to_ary` is evaluated multiple times. -#define rb_darray_ensure_space(ptr_to_ary) ( \ - (rb_darray_capa(*(ptr_to_ary)) > rb_darray_size(*(ptr_to_ary))) ? \ - 1 : \ - rb_darray_double(ptr_to_ary, sizeof((*(ptr_to_ary))->data[0]))) +// Internal function. Calculate buffer size on malloc heap. +static inline size_t +rb_darray_buffer_size(int32_t capacity, size_t header_size, size_t element_size) +{ + if (capacity == 0) return 0; + return header_size + (size_t)capacity * element_size; +} // Internal function +// Ensure there is space for one more element. Return 1 on success and 0 on failure. +// Note: header_size can be bigger than sizeof(rb_darray_meta_t) for example when T is __int128_t. +// for example. static inline int -rb_darray_double(void *ptr_to_ary, size_t element_size) +rb_darray_ensure_space(void *ptr_to_ary, size_t header_size, size_t element_size) { rb_darray_meta_t **ptr_to_ptr_to_meta = ptr_to_ary; - const rb_darray_meta_t *meta = *ptr_to_ptr_to_meta; + rb_darray_meta_t *meta = *ptr_to_ptr_to_meta; int32_t current_capa = rb_darray_capa(meta); + if (rb_darray_size(meta) < current_capa) return 1; int32_t new_capa; // Calculate new capacity @@ -119,11 +123,11 @@ rb_darray_double(void *ptr_to_ary, size_t element_size) } // Calculate new buffer size - size_t current_buffer_size = element_size * (size_t)current_capa + (meta ? sizeof(*meta) : 0); - size_t new_buffer_size = element_size * (size_t)new_capa + sizeof(*meta); + size_t current_buffer_size = rb_darray_buffer_size(current_capa, header_size, element_size); + size_t new_buffer_size = rb_darray_buffer_size(new_capa, header_size, element_size); if (new_buffer_size <= current_buffer_size) return 0; - rb_darray_meta_t *doubled_ary = realloc(*ptr_to_ptr_to_meta, new_buffer_size); + rb_darray_meta_t *doubled_ary = realloc(meta, new_buffer_size); if (!doubled_ary) return 0; if (meta == NULL) { From 3680131c8b05edfa1ef32795840458e4acb6b5b5 Mon Sep 17 00:00:00 2001 From: Alan Wu Date: Tue, 16 Feb 2021 20:49:28 -0500 Subject: [PATCH 2/4] Add rb_darray_make --- darray.h | 41 +++++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/darray.h b/darray.h index 5f270e0ca36847..db69b715072ceb 100644 --- a/darray.h +++ b/darray.h @@ -51,11 +51,24 @@ 1 \ ) : 0) +// Remove the last element of the array. +// +#define rb_darray_pop_back(ary) ((ary)->meta.size--) + // Iterate over items of the array in a for loop // #define rb_darray_foreach(ary, idx_name, elem_ptr_var) \ for (int idx_name = 0; idx_name < rb_darray_size(ary) && ((elem_ptr_var) = rb_darray_ref(ary, idx_name)); ++idx_name) +// Make a dynamic array of a certain size. All bytes backing the elements are set to zero. +// Return 1 on success and 0 on failure. +// +// Note that NULL is a valid empty dynamic array. +// +// bool rb_darray_make(rb_darray(T) *ptr_to_ary, int32_t size); +// +#define rb_darray_make(ptr_to_ary, size) rb_darray_make_impl((ptr_to_ary), size, sizeof(**(ptr_to_ary)), sizeof((*(ptr_to_ary))->data[0])) + typedef struct rb_darray_meta { int32_t size; int32_t capa; @@ -87,10 +100,6 @@ rb_darray_free(void *ary) free(ary); } -// Remove the last element of the array. -// -#define rb_darray_pop_back(ary) ((ary)->meta.size--) - // Internal function. Calculate buffer size on malloc heap. static inline size_t rb_darray_buffer_size(int32_t capacity, size_t header_size, size_t element_size) @@ -101,8 +110,7 @@ rb_darray_buffer_size(int32_t capacity, size_t header_size, size_t element_size) // Internal function // Ensure there is space for one more element. Return 1 on success and 0 on failure. -// Note: header_size can be bigger than sizeof(rb_darray_meta_t) for example when T is __int128_t. -// for example. +// Note: header_size can be bigger than sizeof(rb_darray_meta_t) when T is __int128_t, for example. static inline int rb_darray_ensure_space(void *ptr_to_ary, size_t header_size, size_t element_size) { @@ -142,4 +150,25 @@ rb_darray_ensure_space(void *ptr_to_ary, size_t header_size, size_t element_size return 1; } +static inline int +rb_darray_make_impl(void *ptr_to_ary, int32_t array_size, size_t header_size, size_t element_size) +{ + rb_darray_meta_t **ptr_to_ptr_to_meta = ptr_to_ary; + if (array_size < 0) return 0; + if (array_size == 0) { + *ptr_to_ptr_to_meta = NULL; + return 1; + } + + size_t buffer_size = rb_darray_buffer_size(array_size, header_size, element_size); + rb_darray_meta_t *meta = calloc(buffer_size, 1); + if (!meta) return 0; + + meta->size = array_size; + meta->capa = array_size; + + *ptr_to_ptr_to_meta = meta; + return 1; +} + #endif /* RUBY_DARRAY_H */ From 7d2ea80ba5212a6491da0cba0635da3b977f857c Mon Sep 17 00:00:00 2001 From: Alan Wu Date: Tue, 16 Feb 2021 21:03:20 -0500 Subject: [PATCH 3/4] Use rb_darray_make in ujit --- ujit_core.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ujit_core.c b/ujit_core.c index c3ab44c792b1e3..f6240d2a9cc885 100644 --- a/ujit_core.c +++ b/ujit_core.c @@ -167,9 +167,12 @@ add_block_version(blockid_t blockid, block_t* block) // Ensure ujit_blocks is initialized for this iseq if (rb_darray_size(body->ujit_blocks) == 0) { // Initialize ujit_blocks to be as wide as body->iseq_encoded - // TODO: add resize API for dary - while ((unsigned)rb_darray_size(body->ujit_blocks) < body->iseq_size) { - (void)rb_darray_append(&body->ujit_blocks, NULL); + int32_t casted = (int32_t)body->iseq_size; + if ((unsigned)casted != body->iseq_size) { + rb_bug("iseq too large"); + } + if (!rb_darray_make(&body->ujit_blocks, casted)) { + rb_bug("allocation failed"); } // First block compiled for this iseq From c544c3a7692d68dde14a678287a3107a169e7878 Mon Sep 17 00:00:00 2001 From: Alan Wu Date: Fri, 19 Feb 2021 11:02:09 -0500 Subject: [PATCH 4/4] darray: fix strict aliasing issue --- darray.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/darray.h b/darray.h index db69b715072ceb..d3ffc88131e09d 100644 --- a/darray.h +++ b/darray.h @@ -146,7 +146,9 @@ rb_darray_ensure_space(void *ptr_to_ary, size_t header_size, size_t element_size doubled_ary->capa = new_capa; - *ptr_to_ptr_to_meta = doubled_ary; + // We don't have access to the type of the dynamic array in function context. + // Write out result with memcpy to avoid strict aliasing issue. + memcpy(ptr_to_ary, &doubled_ary, sizeof(doubled_ary)); return 1; } @@ -167,7 +169,9 @@ rb_darray_make_impl(void *ptr_to_ary, int32_t array_size, size_t header_size, si meta->size = array_size; meta->capa = array_size; - *ptr_to_ptr_to_meta = meta; + // We don't have access to the type of the dynamic array in function context. + // Write out result with memcpy to avoid strict aliasing issue. + memcpy(ptr_to_ary, &meta, sizeof(meta)); return 1; }