aboutsummaryrefslogtreecommitdiffstats
path: root/libtest/alloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'libtest/alloc.c')
-rw-r--r--libtest/alloc.c505
1 files changed, 505 insertions, 0 deletions
diff --git a/libtest/alloc.c b/libtest/alloc.c
new file mode 100644
index 0000000..842f856
--- /dev/null
+++ b/libtest/alloc.c
@@ -0,0 +1,505 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+
+static void *
+common_malloc(size_t n, enum memory_origin origin)
+{
+ struct meminfo meminfo;
+
+ assert(n);
+
+ memset(&meminfo, 0, sizeof(meminfo));
+ meminfo.requested_alloc_size = n;
+ meminfo.alignment_type = DEFAULT_ALIGNMENT;
+ meminfo.initialised_on_alloc = 0;
+ meminfo.origin = origin;
+
+ return libtest_alloc(&meminfo);
+}
+
+
+static void *
+common_realloc(void *old_ptr, size_t new_n, enum memory_origin origin)
+{
+ void *new_ptr;
+ size_t old_n;
+
+ assert(new_n);
+ if (!old_ptr)
+ return common_malloc(new_n, origin);
+
+ assert(GET_MEMINFO(old_ptr)->requested_alignment <= _Alignof(max_align_t));
+
+ new_ptr = common_malloc(new_n, origin); /* always change the pointer */
+ if (!new_ptr)
+ return NULL;
+
+ new_n = GET_MEMINFO(new_ptr)->usable_alloc_size;
+ old_n = GET_MEMINFO(old_ptr)->usable_alloc_size;
+ memcpy(new_ptr, old_ptr, new_n < old_n ? new_n : old_n);
+ libtest_free(old_ptr, DO_NOT_REQUIRE_ZEROED);
+
+ return new_ptr;
+}
+
+
+static void *
+common_memalign(size_t alignment, size_t size, enum memory_origin origin)
+{
+ struct meminfo meminfo;
+
+ assert(size);
+ assert(alignment);
+ assert(!(alignment & (alignment - 1u)));
+
+ memset(&meminfo, 0, sizeof(meminfo));
+ meminfo.requested_alloc_size = size;
+ meminfo.alignment_type = CUSTOM_ALIGNMENT;
+ meminfo.requested_alignment = alignment;
+ meminfo.initialised_on_alloc = 0;
+ meminfo.origin = origin;
+
+ return libtest_alloc(&meminfo);
+}
+
+
+#if defined(__GNUC__)
+# pragma GCC diagnostic ignored "-Wmissing-prototypes"
+#endif
+
+
+void *
+(malloc)(size_t n)
+{
+ libtest_malloc_is_custom = 1;
+ assert(libtest_have_custom_free());
+
+ return common_malloc(n, FROM_MALLOC);
+}
+
+
+void *
+(calloc)(size_t n, size_t m)
+{
+ struct meminfo meminfo;
+
+ libtest_calloc_is_custom = 1;
+ assert(libtest_have_custom_free());
+
+ assert(n);
+ assert(m);
+
+ if (n > SIZE_MAX / m) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ n *= m;
+
+ memset(&meminfo, 0, sizeof(meminfo));
+ meminfo.requested_alloc_size = n;
+ meminfo.alignment_type = DEFAULT_ALIGNMENT;
+ meminfo.initialised_on_alloc = 1;
+ meminfo.origin = FROM_CALLOC;
+
+ return libtest_alloc(&meminfo);
+}
+
+
+void *
+(realloc)(void *old_ptr, size_t new_n)
+{
+ libtest_realloc_is_custom = 1;
+ assert(libtest_have_custom_free());
+
+ return common_realloc(old_ptr, new_n, FROM_REALLOC);
+}
+
+
+void *
+(reallocarray)(void *old_ptr, size_t new_n, size_t new_m)
+{
+ libtest_reallocarray_is_custom = 1;
+ assert(libtest_have_custom_free());
+
+ assert(new_n);
+ assert(new_m);
+
+ if (new_n > SIZE_MAX / new_m) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ return common_realloc(old_ptr, new_n * new_m, FROM_REALLOCARRAY);
+}
+
+
+void *
+(valloc)(size_t size)
+{
+ struct meminfo meminfo;
+
+ libtest_valloc_is_custom = 1;
+ assert(libtest_have_custom_free());
+
+ memset(&meminfo, 0, sizeof(meminfo));
+ meminfo.requested_alloc_size = size;
+ meminfo.alignment_type = PAGE_ALIGNMENT;
+ meminfo.initialised_on_alloc = 0;
+ meminfo.origin = FROM_VALLOC;
+
+ return libtest_alloc(&meminfo);
+}
+
+
+void *
+(pvalloc)(size_t size)
+{
+ struct meminfo meminfo;
+ void *ptr;
+ size_t pagesize;
+
+ libtest_pvalloc_is_custom = 1;
+ assert(libtest_have_custom_free());
+
+ pagesize = libtest_get_pagesize();
+ memset(&meminfo, 0, sizeof(meminfo));
+ meminfo.requested_alloc_size = size + (pagesize - size % pagesize) % pagesize;
+ meminfo.alignment_type = PAGE_ALIGNMENT;
+ meminfo.initialised_on_alloc = 0;
+ meminfo.origin = FROM_PVALLOC;
+
+ ptr = libtest_alloc(&meminfo);
+ if (ptr)
+ GET_MEMINFO(ptr)->requested_alloc_size = size;
+ return ptr;
+}
+
+
+void *
+(memalign)(size_t alignment, size_t size)
+{
+ libtest_memalign_is_custom = 1;
+ assert(libtest_have_custom_free());
+
+ return common_memalign(alignment, size, FROM_MEMALIGN);
+}
+
+
+void *
+(aligned_alloc)(size_t alignment, size_t size)
+{
+ libtest_aligned_alloc_is_custom = 1;
+ assert(libtest_have_custom_free());
+
+ assert(alignment);
+ assert(!(size % alignment));
+
+ return common_memalign(alignment, size, FROM_ALIGNED_ALLOC);
+}
+
+
+int
+(posix_memalign)(void **memptr, size_t alignment, size_t size)
+{
+ struct meminfo meminfo;
+ int err, saved_errno = errno;
+ void *ptr;
+
+ libtest_posix_memalign_is_custom = 1;
+ assert(libtest_have_custom_free());
+
+ assert(size);
+ assert(alignment);
+ assert(!(alignment & (alignment - 1u)));
+ assert(!(alignment & (sizeof(void *) - 1u)));
+
+ memset(&meminfo, 0, sizeof(meminfo));
+ meminfo.requested_alloc_size = size;
+ meminfo.alignment_type = CUSTOM_ALIGNMENT;
+ meminfo.requested_alignment = alignment;
+ meminfo.initialised_on_alloc = 0;
+ meminfo.origin = FROM_POSIX_MEMALIGN;
+
+ ptr = libtest_alloc(&meminfo);
+ err = ptr ? 0 : errno;
+ if (!err)
+ *memptr = ptr;
+
+ errno = saved_errno;
+ return err;
+}
+
+
+PURE
+size_t
+(malloc_usable_size)(void *ptr)
+{
+ libtest_malloc_usable_size_is_custom = 1;
+ assert(libtest_have_custom_malloc());
+
+ return ptr ? GET_MEMINFO(ptr)->usable_alloc_size : 0u;
+}
+
+
+void
+(free)(void *ptr)
+{
+ libtest_free_is_custom = 1;
+
+ if (ptr) {
+ struct meminfo *meminfo;
+ meminfo = GET_MEMINFO(ptr);
+ if (!meminfo->accept_leakage) {
+ assert(meminfo->origin != FROM_VALLOC);
+ assert(meminfo->origin != FROM_PVALLOC);
+ }
+ }
+
+ libtest_free(ptr, REQUIRE_ZEROED);
+}
+
+
+void
+(free_sized)(void *ptr, size_t size)
+{
+ libtest_free_sized_is_custom = 1;
+
+ if (ptr) {
+ struct meminfo *meminfo;
+ meminfo = GET_MEMINFO(ptr);
+ assert(meminfo->alignment_type == DEFAULT_ALIGNMENT);
+ assert(meminfo->requested_alloc_size == size);
+ }
+
+ libtest_free(ptr, REQUIRE_ZEROED);
+}
+
+
+void
+(free_aligned_sized)(void *ptr, size_t alignment, size_t size)
+{
+ libtest_free_aligned_sized_is_custom = 1;
+
+ if (ptr) {
+ struct meminfo *meminfo;
+ meminfo = GET_MEMINFO(ptr);
+ assert(meminfo->alignment_type == CUSTOM_ALIGNMENT);
+ assert(meminfo->requested_alloc_size == size);
+ assert(meminfo->requested_alignment == alignment);
+ }
+
+ libtest_free(ptr, REQUIRE_ZEROED);
+}
+
+
+#else
+
+
+#if defined(__GNUC__)
+# pragma GCC diagnostic ignored "-Wredundant-decls"
+#endif
+
+
+void *(malloc)(size_t n);
+void *(calloc)(size_t n, size_t m);
+void *(realloc)(void *old_ptr, size_t new_n);
+void *(reallocarray)(void *old_ptr, size_t new_n, size_t new_m);
+void *(valloc)(size_t size);
+void *(pvalloc)(size_t size);
+void *(memalign)(size_t alignment, size_t size);
+void *(aligned_alloc)(size_t alignment, size_t size);
+int (posix_memalign)(void **memptr, size_t alignment, size_t size);
+size_t (malloc_usable_size)(void *ptr);
+void (free)(void *ptr);
+void (free_sized)(void *ptr, size_t size);
+void (free_aligned_sized)(void *ptr, size_t alignment, size_t size);
+
+
+static void
+fill_memory(uint8_t *mem, size_t n)
+{
+ size_t i;
+ for (i = 0u; i < n; i++)
+ mem[i] = (uint8_t)i;
+}
+
+
+static int
+check_memory(uint8_t *mem, size_t filled, size_t zeroed)
+{
+ size_t i;
+ uint8_t bad = 0;
+ for (i = 0u; i < filled; i++)
+ bad |= (uint8_t)(mem[i] ^ (uint8_t)i);
+ for (i = filled; i < filled + zeroed; i++)
+ bad |= mem[i];
+ return !bad;
+}
+
+
+#define p libtest_p___
+extern void *volatile p;
+void *volatile p;
+
+
+static void
+check(int use_free)
+{
+ void *q;
+
+ p = malloc(10u);
+ assert(p);
+ assert(GET_MEMINFO(p)->requested_alignment == _Alignof(max_align_t));
+ assert((uintptr_t)p % (uintptr_t)_Alignof(max_align_t) == 0u);
+ assert(GET_MEMINFO(p)->requested_alloc_size == 10u);
+ assert(malloc_usable_size(p) >= 10u);
+ if (use_free)
+ free(p);
+ else
+ free_sized(p, 10u);
+
+ p = calloc(3u, 4u);
+ assert(p);
+ assert(GET_MEMINFO(p)->requested_alignment == _Alignof(max_align_t));
+ assert((uintptr_t)p % (uintptr_t)_Alignof(max_align_t) == 0u);
+ assert(GET_MEMINFO(p)->requested_alloc_size == 12u);
+ assert(malloc_usable_size(p) >= 12u);
+ if (use_free)
+ free(p);
+ else
+ free_sized(p, 12u);
+
+ p = realloc(NULL, 5u);
+ assert(p);
+ assert(GET_MEMINFO(p)->requested_alignment == _Alignof(max_align_t));
+ assert((uintptr_t)p % (uintptr_t)_Alignof(max_align_t) == 0u);
+ assert(GET_MEMINFO(p)->requested_alloc_size == 5u);
+ assert(malloc_usable_size(p) >= 5u);
+ fill_memory(p, 5u);
+
+ p = realloc(p, 9u);
+ assert(p);
+ assert(GET_MEMINFO(p)->requested_alignment == _Alignof(max_align_t));
+ assert((uintptr_t)p % (uintptr_t)_Alignof(max_align_t) == 0u);
+ assert(GET_MEMINFO(p)->requested_alloc_size == 9u);
+ assert(malloc_usable_size(p) >= 9u);
+ assert(check_memory(p, 5u, 4u));
+
+ p = realloc(p, 3u);
+ assert(p);
+ assert(GET_MEMINFO(p)->requested_alignment == _Alignof(max_align_t));
+ assert((uintptr_t)p % (uintptr_t)_Alignof(max_align_t) == 0u);
+ assert(GET_MEMINFO(p)->requested_alloc_size == 3u);
+ assert(malloc_usable_size(p) >= 3u);
+ assert(check_memory(p, 3u, 0u));
+ if (use_free)
+ free(p);
+ else
+ free_sized(p, 3u);
+
+ p = reallocarray(NULL, 3u, 10u);
+ assert(p);
+ assert(GET_MEMINFO(p)->requested_alignment == _Alignof(max_align_t));
+ assert((uintptr_t)p % (uintptr_t)_Alignof(max_align_t) == 0u);
+ assert(GET_MEMINFO(p)->requested_alloc_size == 30u);
+ assert(malloc_usable_size(p) >= 30u);
+ fill_memory(p, 30u);
+
+ p = reallocarray(p, 10u, 10u);
+ assert(p);
+ assert(GET_MEMINFO(p)->requested_alignment == _Alignof(max_align_t));
+ assert((uintptr_t)p % (uintptr_t)_Alignof(max_align_t) == 0u);
+ assert(GET_MEMINFO(p)->requested_alloc_size == 100u);
+ assert(malloc_usable_size(p) >= 100u);
+ assert(check_memory(p, 30u, 70u));
+
+ p = reallocarray(p, 5u, 10u);
+ assert(p);
+ assert(GET_MEMINFO(p)->requested_alignment == _Alignof(max_align_t));
+ assert((uintptr_t)p % (uintptr_t)_Alignof(max_align_t) == 0u);
+ assert(GET_MEMINFO(p)->requested_alloc_size == 50u);
+ assert(malloc_usable_size(p) >= 50u);
+ assert(check_memory(p, 30u, 20u));
+ if (use_free)
+ free(p);
+ else
+ free_sized(p, 50u);
+
+ p = memalign(2u, 7u);
+ assert(p);
+ assert(GET_MEMINFO(p)->requested_alignment == 2u);
+ assert((uintptr_t)p % 2u == 0u);
+ assert(GET_MEMINFO(p)->requested_alloc_size == 7u);
+ assert(malloc_usable_size(p) >= 7u);
+ if (use_free)
+ free(p);
+ else
+ free_aligned_sized(p, 2u, 7u);
+
+ p = aligned_alloc(2u, 4u);
+ assert(p);
+ assert(GET_MEMINFO(p)->requested_alignment == 2u);
+ assert((uintptr_t)p % 2u == 0u);
+ assert(GET_MEMINFO(p)->requested_alloc_size == 4u);
+ assert(malloc_usable_size(p) >= 4u);
+ if (use_free)
+ free(p);
+ else
+ free_aligned_sized(p, 2u, 4u);
+
+ assert(!posix_memalign(&q, sizeof(void *), 11u));
+ p = q;
+ assert(p);
+ assert(GET_MEMINFO(p)->requested_alignment == sizeof(void *));
+ assert((uintptr_t)p % 2u == 0u);
+ assert(GET_MEMINFO(p)->requested_alloc_size == 11u);
+ assert(malloc_usable_size(p) >= 11u);
+ if (use_free)
+ free(p);
+ else
+ free_aligned_sized(p, sizeof(void *), 11u);
+}
+
+
+int
+main(void)
+{
+ size_t pagesize;
+
+ SET_UP_ALARM();
+
+ libtest_start_tracking();
+
+ check(1);
+ check(0);
+
+ pagesize = libtest_get_pagesize();
+
+ libtest_stop_tracking();
+
+ p = valloc(6u);
+ assert(p);
+ assert(GET_MEMINFO(p)->requested_alignment == pagesize);
+ assert((uintptr_t)p % (uintptr_t)pagesize == 0u);
+ assert(GET_MEMINFO(p)->requested_alloc_size == 6u);
+ assert(malloc_usable_size(p) >= 6u);
+ /* cannot be free(3)ed */
+
+ p = pvalloc(8u);
+ assert(p);
+ assert(GET_MEMINFO(p)->requested_alignment == pagesize);
+ assert((uintptr_t)p % (uintptr_t)pagesize == 0u);
+ assert(GET_MEMINFO(p)->requested_alloc_size == 8u);
+ assert(malloc_usable_size(p) >= pagesize);
+ /* cannot be free(3)ed */
+
+ assert(libtest_check_no_leaks());
+ return 0;
+
+ /* TODO test failures */
+}
+
+
+#endif