diff options
author | Mattias Andrée <maandree@operamail.com> | 2015-10-18 05:15:00 +0200 |
---|---|---|
committer | Mattias Andrée <maandree@operamail.com> | 2015-10-18 05:15:39 +0200 |
commit | 5eb009e831808779b92c2a5605a77f2b10dfb5da (patch) | |
tree | b111e9fd1b481ba40965a59d0d30d9504a08fb35 | |
parent | info: unaligned pointers (diff) | |
download | slibc-5eb009e831808779b92c2a5605a77f2b10dfb5da.tar.gz slibc-5eb009e831808779b92c2a5605a77f2b10dfb5da.tar.bz2 slibc-5eb009e831808779b92c2a5605a77f2b10dfb5da.tar.xz |
add rememalign: realloc with configurable alignment
Signed-off-by: Mattias Andrée <maandree@operamail.com>
-rw-r--r-- | TODO | 1 | ||||
-rw-r--r-- | include/slibc-alloc.h | 56 | ||||
-rw-r--r-- | src/slibc-alloc.c | 85 |
3 files changed, 130 insertions, 12 deletions
@@ -27,7 +27,6 @@ LOW PRIORITY: _GNU_SOURCE, system-dependant -realloc &c with alignment alloc functions without bookkeeping crt0 with cpu cycle count printing diff --git a/include/slibc-alloc.h b/include/slibc-alloc.h index a36c024..f19982a 100644 --- a/include/slibc-alloc.h +++ b/include/slibc-alloc.h @@ -44,6 +44,34 @@ enum extalloc_mode * Create new allocation with `malloc` if necessary. */ EXTALLOC_MALLOC = 2, + + }; + + +/** + * Configurations for `rememalign`. + * There are independent of each other, and + * multiple can be selected by using bitwise or + * between them. + */ +enum rememalign_mode + { + /** + * Clear disowned memory. + */ + REMEMALIGN_CLEAR = 1, + + /** + * Initialise new memory. + */ + REMEMALIGN_INIT = 2, + + /** + * If a new allocation is created, copy the data + * from the old allocation over to the new allocation. + */ + REMEMALIGN_MEMCPY = 4, + }; @@ -180,19 +208,39 @@ void* extalloc(void*, size_t, enum extalloc_mode) __GCC_ONLY(__attribute__((__nonnull__, __warn_unused_result__))); /** + * This function is similar to `realloc`, however its + * behaviour and pointer alignment can be tuned. + * + * @param ptr The old allocation, see `realloc` for more details. + * @param boundary The alignment. + * @param size The new allocation size, see `realloc` for more details. + * @param mode `REMEMALIGN_CLEAR`, `REMEMALIGN_INIT` or + * `REMEMALIGN_MEMCPY`, or both or neither. + * @return The new allocation, see `realloc` for more details. + * + * @throws 0 `errno` is set to zero success if `NULL` is returned. + * @throws EINVAL `mode` is invalid, or `boundary` is not a power of two. + * @throws ENOMEM The process cannot allocate more memory. + */ +void* rememalign(void*, size_t, size_t, enum rememalign_mode) + __GCC_ONLY(__attribute__((__warn_unused_result__))); + +/** * This function behaves exactly like `fast_realloc`, except: * - Its behaviour is undefined if `ptr` is `NULL`. * - Its behaviour is undefined if `size` equals the old allocation size. * - Its behaviour is undefined if `size` is zero. * - It will never free `ptr`. + * - The alignment of new pointers can be specified. * - * @param ptr The old allocation, see `realloc` for more details. - * @param size The new allocation size, see `realloc` for more details. - * @return The new allocation, see `realloc` for more details. + * @param ptr The old allocation, see `realloc` for more details. + * @param boundary The alignment. + * @param size The new allocation size, see `realloc` for more details. + * @return The new allocation, see `realloc` for more details. * * @throws ENOMEM The process cannot allocate more memory. */ -void* naive_realloc(void*, size_t) /* sic! we limit ourself to ASCII */ +void* naive_realloc(void*, size_t, size_t) /* sic! we limit ourself to ASCII */ __GCC_ONLY(__attribute__((__nonnull__, __warn_unused_result__))); /** diff --git a/src/slibc-alloc.c b/src/slibc-alloc.c index cad55b0..91478c6 100644 --- a/src/slibc-alloc.c +++ b/src/slibc-alloc.c @@ -17,6 +17,7 @@ */ #include <slibc-alloc.h> #include <stdlib.h> +#include <stddef.h> #include <strings.h> #include <errno.h> /* TODO #include <sys/mman.h> */ @@ -117,7 +118,7 @@ size_t allocsize(void* segment) if (CLEAR_OLD ? (old_size > size) : 0) \ explicit_bzero(((char*)ptr) + size, old_size - size); \ \ - new_ptr = naive_realloc(ptr, size); \ + new_ptr = naive_realloc(ptr, sizeof(max_align_t), size); \ if (new_ptr != ptr) \ { \ if (new_ptr == NULL) \ @@ -243,7 +244,9 @@ void* extalloc(void* ptr, size_t size, enum extalloc_mode mode) if (clear ? (old_size > size) : 0) explicit_bzero(((char*)ptr) + size, old_size - size); - new_ptr = ((mode & EXTALLOC_MALLOC) ? naive_realloc : naive_extalloc)(ptr, size); + new_ptr = (mode & EXTALLOC_MALLOC) + ? naive_realloc(ptr, sizeof(max_align_t), size) + : naive_extalloc(ptr, size); if ((new_ptr != ptr) && (new_ptr != NULL)) { if (clear) @@ -256,22 +259,90 @@ void* extalloc(void* ptr, size_t size, enum extalloc_mode mode) /** + * This function is similar to `realloc`, however its + * behaviour and pointer alignment can be tuned. + * + * @param ptr The old allocation, see `realloc` for more details. + * @param boundary The alignment. + * @param size The new allocation size, see `realloc` for more details. + * @param mode `REMEMALIGN_CLEAR`, `REMEMALIGN_INIT` or + * `REMEMALIGN_MEMCPY`, or both or neither. + * @return The new allocation, see `realloc` for more details. + * + * @throws 0 `errno` is set to zero success if `NULL` is returned. + * @throws EINVAL `mode` is invalid, or `boundary` is not a power of two. + * @throws ENOMEM The process cannot allocate more memory. + */ +void* rememalign(void* ptr, size_t boundary, size_t size, enum rememalign_mode mode) +{ + int conf_clear = mode & REMEMALIGN_CLEAR; + int conf_init = mode & REMEMALIGN_INIT; + int conf_memcpy = mode & REMEMALIGN_MEMCPY; + size_t old_size; + void* new_ptr; + + if (size == 0) + return secure_free(ptr), NULL; + + if (ptr == NULL) + { + new_ptr = memalign(boundary, size); + if ((new_ptr != NULL) && conf_init) + bzero(new_ptr, size); + return new_ptr; + } + + old_size = allocsize(ptr); + if (old_size == size) + return ptr; + + if (conf_clear ? (old_size > size) : 0) + explicit_bzero(((char*)ptr) + size, old_size - size); + + if (conf_memcpy) + new_ptr = naive_realloc(ptr, boundary, size); + else + { + new_ptr = naive_extalloc(ptr, size); + if ((new_ptr == NULL) && (errno == 0)) + new_ptr = memalign(boundary, size); + } + if (new_ptr != ptr) + { + if (new_ptr == NULL) + return NULL; + if (conf_clear) + explicit_bzero(PURE_ALLOC(ptr), PURE_SIZE(ptr)); + fast_free(ptr); + } + + if (conf_init ? (old_size < size) : 0) + explicit_bzero(((char*)new_ptr) + old_size, size - old_size); + + return new_ptr; +} + + +/** * This function behaves exactly like `fast_realloc`, except: * - Its behaviour is undefined if `ptr` is `NULL`. * - Its behaviour is undefined if `size` equals the old allocation size. * - Its behaviour is undefined if `size` is zero. * - It will never free `ptr`. + * - The alignment of new pointers can be specified. * - * @param ptr The old allocation, see `realloc` for more details. - * @param size The new allocation size, see `realloc` for more details. - * @return The new allocation, see `realloc` for more details. + * @param ptr The old allocation, see `realloc` for more details. + * @param boundary The alignment. + * @param size The new allocation size, see `realloc` for more details. + * @return The new allocation, see `realloc` for more details. * + * @throws EINVAL `boundary` is not a power of two. * @throws ENOMEM The process cannot allocate more memory. */ -void* naive_realloc(void* ptr, size_t size) +void* naive_realloc(void* ptr, size_t boundary, size_t size) { /* TODO implementation of naive_realloc with reallocation */ - return malloc(size); + return memalign(boundary, size); (void) ptr; } |