aboutsummaryrefslogtreecommitdiffstats
path: root/test.c
diff options
context:
space:
mode:
Diffstat (limited to 'test.c')
-rw-r--r--test.c199
1 files changed, 199 insertions, 0 deletions
diff --git a/test.c b/test.c
new file mode 100644
index 0000000..05d74d4
--- /dev/null
+++ b/test.c
@@ -0,0 +1,199 @@
+/* See LICENSE file for copyright and license details. */
+#include "libsimple.h"
+#include "test.h"
+#include <malloc.h>
+
+
+size_t alloc_fail_in = 0;
+
+static int custom_malloc = 0;
+
+
+size_t
+get_pagesize(void)
+{
+ long r;
+ assert((r = sysconf(_SC_PAGESIZE)) >= 0);
+ return (size_t)r;
+}
+
+
+size_t
+round_up(size_t size)
+{
+ size_t ps = get_pagesize();
+ return size + (ps - size % ps) % ps;
+}
+
+
+int
+have_custom_malloc(void)
+{
+ free(malloc(1));
+ return custom_malloc;
+}
+
+
+struct allocinfo *
+get_allocinfo(void *ptr)
+{
+ assert(ptr);
+ return (void *)((char *)ptr - sizeof(struct allocinfo));
+}
+
+
+void *
+malloc(size_t size)
+{
+ size_t alignment = get_pagesize();
+ while (alignment < sizeof(long long int))
+ alignment *= 2;
+ while (alignment < sizeof(long double))
+ alignment *= 2;
+ return memalign(alignment, size);
+}
+
+
+void *
+calloc(size_t nelem, size_t elsize)
+{
+ struct allocinfo *info;
+ void *ret;
+ assert(nelem && elsize); /* unspecified behaviour otherwise */
+ if (nelem > SIZE_MAX / elsize) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ ret = malloc(nelem * elsize);
+ if (!ret)
+ return NULL;
+ memset(ret, 0, nelem * elsize);
+ info = get_allocinfo(ret);
+ info->zeroed = nelem * elsize;
+ return ret;
+}
+
+
+void *
+realloc(void *ptr, size_t size)
+{
+ struct allocinfo *info;
+ void *ret;
+ size_t n;
+ assert(size); /* unspecified behaviour otherwise */
+ if (!ptr)
+ return malloc(size);
+ ret = malloc(size);
+ if (!ret)
+ return malloc;
+ info = get_allocinfo(ret);
+ n = MIN(size, info->size);
+ info->zeroed = MIN(n, info->zeroed);
+ memcpy(ret, ptr, n);
+ free(ptr);
+ return ret;
+}
+
+
+void *
+memalign(size_t alignment, size_t size)
+{
+ struct allocinfo *info;
+ void *ptr;
+ size_t n;
+ uintptr_t off;
+
+ custom_malloc = 1;
+
+ assert(alignment);
+ assert(!(alignment & (alignment - 1UL)));
+ assert(size); /* unspecified behaviour otherwise */
+
+ if (alloc_fail_in && alloc_fail_in-- == 1)
+ goto enomem;
+
+ n = size;
+ if (n > SIZE_MAX - alignment)
+ goto enomem;
+ n += alignment;
+ if (n > SIZE_MAX - sizeof(struct allocinfo))
+ goto enomem;
+ n += sizeof(struct allocinfo);
+
+ ptr = mmap(NULL, n, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (!ptr)
+ goto enomem;
+
+ off = (uintptr_t)ptr;
+ off += sizeof(struct allocinfo);
+ off += (alignment - off % alignment) % alignment;
+ off -= (uintptr_t)ptr;
+
+ ptr = (char *)ptr + off;
+ info = get_allocinfo(ptr);
+
+ info->real_beginning = (char *)ptr - off;
+ info->real_size = n;
+ info->size = size;
+ info->extent = n - size - off;
+ info->alignment = alignment;
+ info->zeroed = 0;
+ info->refcount = 1;
+
+ return ptr;
+
+enomem:
+ errno = ENOMEM;
+ return NULL;
+}
+
+
+int
+posix_memalign(void **memptr, size_t alignment, size_t size)
+{
+ int ret, saved_errno = errno;
+ void **volatile ptrp = memptr;
+ assert(!(alignment % sizeof(void *)));
+ assert(ptrp);
+ *memptr = memalign(alignment, size);
+ ret = *memptr ? ENOMEM : 0;
+ errno = saved_errno;
+ return ret;
+}
+
+
+void *
+aligned_alloc(size_t alignment, size_t size)
+{
+ assert(alignment);
+ assert(!(size % alignment));
+ return memalign(alignment, size);
+}
+
+
+void *
+valloc(size_t size)
+{
+ return memalign(get_pagesize(), size);
+}
+
+
+void *
+pvalloc(size_t size)
+{
+ return memalign(get_pagesize(), round_up(size));
+}
+
+
+void
+free(void *ptr)
+{
+ struct allocinfo *info;
+ if (!ptr)
+ return;
+ info = get_allocinfo(ptr);
+ assert(info->refcount);
+ if (info->refcount-- > 1)
+ return;
+ assert(!munmap(info->real_beginning, info->real_size));
+}