aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--include/slibc-alloc.h81
-rw-r--r--src/slibc-alloc.c129
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;
+}
+