diff options
| -rw-r--r-- | include/slibc-alloc.h | 81 | ||||
| -rw-r--r-- | src/slibc-alloc.c | 129 | 
2 files changed, 208 insertions, 2 deletions
| diff --git a/include/slibc-alloc.h b/include/slibc-alloc.h index 3fe31e0..d745dee 100644 --- a/include/slibc-alloc.h +++ b/include/slibc-alloc.h @@ -29,7 +29,7 @@  /**   * Configurations for `extalloc`. - * There are independent of each other, and + * They are independent of each other, and   * multiple can be selected by using bitwise or   * between them.   */ @@ -50,7 +50,7 @@ enum extalloc_mode  /**   * Configurations for `rememalign`. - * There are independent of each other, and + * They are independent of each other, and   * multiple can be selected by using bitwise or   * between them.   */ @@ -76,6 +76,33 @@ enum rememalign_mode  /** + * Configurations for `falloc`. + * They are independent of each other, and + * multiple can be selected by using bitwise or + * between them. + */ +enum falloc_mode +  { +    /** +     * Clear disowned memory. +     */ +    FALLOC_CLEAR = 1, +     +    /** +     * Initialise new memory. +     */ +    FALLOC_INIT = 2, +     +    /** +     * If a new allocation is created, copy the data +     * from the old allocation over to the new allocation. +     */ +    FALLOC_MEMCPY = 4, +     +  }; + + +/**   * This function is identical to `free`, except it is guaranteed not to   * override the memory segment with zeroes before freeing the allocation.   *  @@ -263,6 +290,56 @@ void* naive_realloc(void*, size_t, size_t) /* sic! we limit ourself to ASCII */  void* naive_extalloc(void*, size_t) /* sic! we limit ourself to ASCII */    __GCC_ONLY(__attribute__((__nonnull__, __warn_unused_result__))); +/** + * Allocates, deallocates, or reallocates memory without + * bookkeeping. The created allocation may not be inspecifed, + * deallocated or reallocated with any other function than + * this function. + *  + * If `new_size` is zero and `ptr` is `NULL`, + *   nothing happens, but errno is set zero and `NULL` is returned. + * If `new_size` is zero and `ptr` is not `NULL`, + *   `ptr` is deallocated, errno is set zero, and `NULL` is returned. + *   `ptr`'s content will be clear if `old_size` is not zero + *   and `mode & FALLOC_CLEAR`, but if `old_size` is zero and + *   and `mode & FALLOC_CLEAR`, `errno` is set to `EINVAL`. + * If `new_size` is not zero, and `ptr` is not `NULL`, + *   `ptr` is reallocated. If `mode & FALLOC_CLEAR` the old allocation + *   is cleared if a new allocation is created, or if the allocation + *   is shrinked, the disowned area is cleared. However, if `old_size` + *   is zero an `mode & FALLOC_CLEAR` errno is set to `EINVAL` and + *   `NULL` is returned. If a new allocation is created, the first + *   `old_size` bytes is copied from the old allocation into the new + *   allocation. If `mode & FALLOC_INIT`, all newly available space + *   will be initialised with zeroes. + * If neither `new_size` nor `new_size` is zero, and `ptr` is `NULL`, + *   `errno` is set to `EINVAL` and `NULL` is returned. + * Otherwise (if `new_size` is non-zero, `old_size` is zero, and + *   `ptr` is `NULL ), a new allocation is created. + *  + * @param   ptr        The old pointer, `NULL` if a new shall be created. + * @param   ptrshift   Pointer that is used to keep track of the pointers + *                     shift for alignment. `NULL` if the shift shall not + *                     be tracked. If this is the case, `falloc` cannot + *                     be used to reallocate or deallocate an allocation, + *                     unless the pointer is unaligned (`alignment <= 0`). + * @param   alignment  The aligment of both the new and old pointer, zero + *                     or one if it should not be aligned. + * @param   old_size   The old allocation size, zero if a new shall be created. + * @param   new_size   The new allocation size, zero if it shall be freed. + * @param   mode       `FALLOC_CLEAR`, `FALLOC_INIT` or `FALLOC_MEMCPY`, or + *                     both or neither. + * @return             The new pointer, or the old pointer if it was reallocated + *                     without creating a new allocation. `NULL` is returned + *                     if `new_size` (errno is set to zero) is zero, or on error + *                     (errno is set to describe the error.) + *  + * @throws  0       `new_size` is zero. + * @throws  EINVAL  The arguments are invalid. + * @throws  ENOMEM  The process cannot allocate more memory. + */ +void* falloc(void*, size_t*, size_t, size_t, size_t, enum falloc_mode); +  /**   * This macro calls `fast_free` and then sets the pointer to `NULL`, diff --git a/src/slibc-alloc.c b/src/slibc-alloc.c index 2ec324a..4d2d0a6 100644 --- a/src/slibc-alloc.c +++ b/src/slibc-alloc.c @@ -18,6 +18,7 @@  #include <slibc-alloc.h>  #include <stdlib.h>  #include <stddef.h> +#include <string.h>  #include <strings.h>  #include <errno.h>  /* TODO #include <sys/mman.h> */ @@ -378,3 +379,131 @@ void* naive_extalloc(void* ptr, size_t size)    (void) ptr, (void) size;  } + + +/** + * Allocates, deallocates, or reallocates memory without + * bookkeeping. The created allocation may not be inspecifed, + * deallocated or reallocated with any other function than + * this function. + *  + * If `new_size` is zero and `ptr` is `NULL`, + *   nothing happens, but `errno` is set to zero and `NULL` + *   is returned. + * If `new_size` is non-zero, `old_size` is zero, and `ptr` + *   is not `NULL` or if `new_size` and `old_size` is non-zero, + *   and `ptr` is `NULL`, `errno` is set to `EINVAL` and `NULL` + *   is returned. + * If `new_size` and `old_size` is zero and `ptr` is not `NULL`, + *   `errno` is set to `EINVAL` and `NULL` is returned. + * If `new_size` is zero, `old_size` is non-zero, and `ptr` + *   is not `NULL`, `ptr` is deallocated, and `NULL` is returned + *   with `errno` set to zero. The memory cleared before it is + *   deallocated if `mode & FALLOC_CLEAR`. + * If `new_size` is non-zero, `old_size` is zero, and `ptr` is + *   `NULL`, a new allocation is created of `new_size` bytes. + *   It will be zero-initialised if `mode & FALLOC_INIT`. + * If `new_size` and `old_size` is non-zero and `ptr` is not + *   `NULL`, `ptr` is reallocated. if the allocation is shrunk, + *   the disowned area is cleared if `mode & FALLOC_CLEAR`. + *   Newly available memory is zero-initialised if + *   `mode & FALLOC_INIT`. If a new allocation is required, + *   the data from the old allocation is only copied over to + *   the new allocation if `mode & FALLOC_MEMCPY`. If + *   `(mode & FALLOC_INIT) && !(mode & FALLOC_MEMCPY)`, the + *   entire allocation will be cleared. + *  + * @param   ptr        The old pointer, `NULL` if a new shall be created. + * @param   ptrshift   Pointer that is used to keep track of the pointers + *                     shift for alignment. `NULL` if the shift shall not + *                     be tracked. If this is the case, `falloc` cannot + *                     be used to reallocate or deallocate an allocation, + *                     unless the pointer is unaligned (`alignment <= 0`). + * @param   alignment  The aligment of both the new and old pointer, zero + *                     or one if it should not be aligned. + * @param   old_size   The old allocation size, zero if a new shall be created. + * @param   new_size   The new allocation size, zero if it shall be freed. + * @param   mode       `FALLOC_CLEAR`, `FALLOC_INIT` or `FALLOC_MEMCPY`, or + *                     both or neither. + * @return             The new pointer, or the old pointer if it was reallocated + *                     without creating a new allocation. `NULL` is returned + *                     if `new_size` (errno is set to zero) is zero, or on error + *                     (errno is set to describe the error.) + *  + * @throws  0       `new_size` is zero. + * @throws  EINVAL  The arguments are invalid. + * @throws  ENOMEM  The process cannot allocate more memory. + */ +void* falloc(void* ptr, size_t* ptrshift, size_t alignment, +	     size_t old_size, size_t new_size, enum falloc_mode mode) +{ +  void* new_ptr = NULL; +  size_t shift = 0; +   +  if (mode & (enum falloc_mode)~(FALLOC_CLEAR | FALLOC_INIT | FALLOC_MEMCPY)) +    return errno = EINVAL, NULL; +   +  alignment = alignment ? alignment : 1; +   +  if (new_size && old_size && ptr) +    { +      shift = ptrshift == NULL ? *ptrshift : 0; +      if ((alignment > 1) && (ptrshift == NULL)) +	return errno = EINVAL, NULL; +      if ((mode & FALLOC_CLEAR) && (old_size > new_size)) +	explicit_bzero(ptr + new_size, old_size - new_size); +      new_ptr = falloc_extalloc(ptr - shift, old_size + shift, new_size + shift); +      if ((new_ptr == NULL) && (errno == 0)) +	{ +	  new_ptr = falloc_malloc(new_size + alignment - 1); +	  if (new_ptr != NULL) +	    { +	      if ((size_t)new_ptr % alignment) +		shift = alignment - ((size_t)new_ptr % alignment); +	      if (ptrshift != NULL) +		*ptrshift = shift; +	      new_ptr = (void*)((char*)new_ptr + shift); +	      if (mode & FALLOC_MEMCPY) +		memcpy(new_ptr, ptr, old_size); +	    } +	} +    } +  else if (new_size && (old_size || ptr)) +    return errno = EINVAL, NULL; +  else if (new_size) +    new_ptr = falloc_malloc(new_size); +  else if (old_size && ptr) +    { +      shift = ptrshift == NULL ? *ptrshift : 0; +      if ((alignment > 1) && (ptrshift == NULL)) +	return errno = EINVAL, NULL; +      if (mode & FALLOC_CLEAR) +	explicit_bzero(ptr, old_size); +      falloc_free(ptr - shift); +      return errno = 0, NULL; +    } +  else if (old_size || !ptr) +    return errno = 0, NULL; +  else +    return errno = EINVAL, NULL; +   +  if (new_ptr != NULL) +    { +      if ((new_ptr != ptr) && (ptr != NULL)) +	{ +	  if (mode & FALLOC_CLEAR) +	    explicit_bzero(ptr, old_size); +	  falloc_free(ptr - shift); +	} +      if (mode & FALLOC_INIT) +	{ +	  if (!(mode & FALLOC_MEMCPY)) +	    old_size = 0; +	  if (new_size > old_size) +	    bzero(new_ptr + old_size, new_size - old_size); +	} +    } +   +  return errno = 0, new_ptr; +} + | 
