Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 | // // posix_memalign_test.c // libmalloc // // test allocating and freeing all sizes and alignments // #include <darwintest.h> #include <errno.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include "../src/platform.h" #if !MALLOC_TARGET_EXCLAVES #include <mach/mach.h> #endif // !MALLOC_TARGET_EXCLAVES #include <malloc/malloc.h> #include <malloc_private.h> T_GLOBAL_META(T_META_RUN_CONCURRENTLY(true), T_META_TAG_XZONE); #if !MALLOC_TARGET_EXCLAVES struct t_recorder_ctx { void *ptr; size_t size; bool found; }; static void pointer_recorder(task_t task, void *context, unsigned type, vm_range_t *ranges, unsigned count) { if (!(type & MALLOC_PTR_IN_USE_RANGE_TYPE)) { return; } struct t_recorder_ctx *ctx = context; vm_address_t ptr_addr = (vm_address_t)(ctx->ptr); vm_size_t ptr_size = (vm_size_t)(ctx->size); for (unsigned i = 0; i < count; i++) { vm_range_t *range = &ranges[i]; if (range->address <= ptr_addr && range->address + range->size > ptr_addr) { T_QUIET; T_EXPECT_FALSE(ctx->found, "first time"); vm_size_t offset = ptr_addr - range->address; T_QUIET; T_EXPECT_GE(range->size - offset, ctx->size, "allocation must be large enough"); ctx->found = true; } } } static void check_pointer_is_enumerated(void *ptr, size_t size) { vm_address_t *zones; unsigned zone_count; kern_return_t kr; kr = malloc_get_all_zones(mach_task_self(), /*reader=*/NULL, &zones, &zone_count); T_QUIET; T_ASSERT_EQ(kr, KERN_SUCCESS, "malloc_get_all_zones(mach_task_self(), ...)"); struct t_recorder_ctx ctx = { .ptr = ptr, .size = size, .found = false, }; for (unsigned i = 0; i < zone_count; i++) { malloc_zone_t *zone = (malloc_zone_t *)zones[i]; zone->introspect->enumerator(mach_task_self(), &ctx, MALLOC_PTR_IN_USE_RANGE_TYPE, (vm_address_t)zone, NULL, pointer_recorder); if (ctx.found) { return; } } T_QUIET; T_FAIL("pointer %p not enumerated in any zone", ptr); } #endif // !MALLOC_TARGET_EXCLAVES static inline void * t_posix_memalign(size_t alignment, size_t size, bool scribble, bool enumerate) { void *ptr = NULL; int result = posix_memalign(&ptr, alignment, size); size_t allocated_size = malloc_size(ptr); T_QUIET; T_ASSERT_NOTNULL(ptr, "allocation"); T_QUIET; T_ASSERT_EQ((intptr_t)ptr % alignment, 0ul, "pointer should be properly aligned"); T_QUIET; T_EXPECT_LE(size, allocated_size, "allocation size"); T_QUIET; T_EXPECT_TRUE(malloc_claimed_address(ptr), "should be claimed"); #if !MALLOC_TARGET_EXCLAVES if (enumerate) { check_pointer_is_enumerated(ptr, size); } #endif // !MALLOC_TARGET_EXCLAVES if (scribble) { // Scribble memory pointed to by `ptr` to make sure we're not using that // memory for control structures. This also makes sure the memory can be // written to. const uint64_t pat = 0xdeadbeefcafebabeull; memset_pattern8(ptr, &pat, size); } return ptr; } T_DECL(posix_memalign_free, "posix_memalign all power of two alignments <= 4096", T_META_TAG_VM_NOT_PREFERRED) { for (size_t alignment = sizeof(void*); alignment < 4096; alignment *= 2) { bool enumerate = true; // test several sizes for (size_t size = alignment; size <= 256*alignment; size += 8) { void* ptr = t_posix_memalign(alignment, size, true, enumerate); free(ptr); enumerate = false; } } } T_DECL(posix_memalign_alignment_not_a_power_of_2, "posix_memalign should return EINVAL if alignment is not a power of 2", T_META_TAG_VM_PREFERRED) { { void *ptr = NULL; int result = posix_memalign(&ptr, 24, 48); // alignment is even, but not a power of two T_QUIET; T_ASSERT_NULL(ptr, "ptr should be null"); T_QUIET; T_ASSERT_EQ(result, EINVAL, "posix_memalign should return EINVAL"); } { void *ptr = NULL; int result = posix_memalign(&ptr, 23, 46); // alignment is odd, and not a power of two T_QUIET; T_ASSERT_NULL(ptr, "ptr should be null"); T_QUIET; T_ASSERT_EQ(result, EINVAL, "posix_memalign should return EINVAL"); } } T_DECL(posix_memalign_alignment_not_a_multiple_of_voidstar, "posix_memalign should return EINVAL if alignment is not a multiple of sizeof(void*)", T_META_TAG_VM_PREFERRED) { void *ptr = NULL; const size_t alignment = sizeof(void*)+1; int result = posix_memalign(&ptr, alignment, alignment * 2); T_QUIET; T_ASSERT_NULL(ptr, "ptr should be null"); T_QUIET; T_ASSERT_EQ(result, EINVAL, "posix_memalign should return EINVAL"); } T_DECL(posix_memalign_allocate_size_0, "posix_memalign should return something that can be passed to free() when size is 0", T_META_TAG_VM_PREFERRED) { void *ptr = NULL; int result = posix_memalign(&ptr, 8, 0); T_QUIET; T_ASSERT_EQ(result, 0, "posix_memalign should not return an error when asked for size 0"); free(ptr); } #if defined(__LP64__) T_DECL(posix_memalign_large, "posix_memalign large power of two alignments", T_META_TAG_VM_NOT_PREFERRED) { // 64GB on macOS, 64MB on embedded uint64_t max_alignment = TARGET_OS_OSX ? UINT64_C(68719476736) : UINT64_C(67108864); for (size_t alignment = sizeof(void*); alignment <= max_alignment; alignment *= 2) { // don't scribble - we don't want to actually touch that many pages, we just // verify that the allocated pointer looks reasonable void* ptr = t_posix_memalign(alignment, alignment, false, true); free(ptr); } T_END; } #endif // __LP64__ T_DECL(posix_memalign_single_page_large, "Allocate tiny blocks with large alignment", T_META_TAG_XZONE_ONLY) { void *ptr1 = t_posix_memalign(32768, 1, false, true); T_ASSERT_NOTNULL(ptr1, "Allocated aligned ptr %p", ptr1); void *ptr2 = t_posix_memalign(16*1024, 48 * 1024, false, true); T_ASSERT_NOTNULL(ptr2, "Allocated aligned ptr %p", ptr2); void *ptr3 = t_posix_memalign(32768, 1, false, true); T_ASSERT_NOTNULL(ptr3, "Allocated aligned ptr %p", ptr3); free(ptr1); free(ptr2); free(ptr3); } |