aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <maandree@operamail.com>2015-10-18 05:15:00 +0200
committerMattias Andrée <maandree@operamail.com>2015-10-18 05:15:39 +0200
commit5eb009e831808779b92c2a5605a77f2b10dfb5da (patch)
treeb111e9fd1b481ba40965a59d0d30d9504a08fb35
parentinfo: unaligned pointers (diff)
downloadslibc-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--TODO1
-rw-r--r--include/slibc-alloc.h56
-rw-r--r--src/slibc-alloc.c85
3 files changed, 130 insertions, 12 deletions
diff --git a/TODO b/TODO
index 6cc6390..df5e498 100644
--- a/TODO
+++ b/TODO
@@ -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;
}