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 | #include <darwintest.h> #include <sys/mman.h> #include "../src/internal.h" // MALLOC_TARGET_EXCLAVES #if CONFIG_XZONE_MALLOC #if MALLOC_TARGET_EXCLAVES #include <vas/vas.h> #else #include <mach/mach_init.h> #include <mach/vm_map.h> #endif // MALLOC_TARGET_EXCLAVES static void * test_mvm_allocate_plat(uintptr_t addr, size_t size, int flags, uint32_t debug_flags, int vm_page_label, plat_map_t *map_out) { #if MALLOC_TARGET_EXCLAVES const _liblibc_map_type_t type = LIBLIBC_MAP_TYPE_PRIVATE | ((flags & VM_FLAGS_ANYWHERE) ? 0 : LIBLIBC_MAP_TYPE_FIXED) | ((debug_flags & MALLOC_NO_POPULATE) ? LIBLIBC_MAP_TYPE_NOCOMMIT : 0); return mmap_plat(map_out, addr, size, LIBLIBC_MAP_PERM_READ | LIBLIBC_MAP_PERM_WRITE, type, 0, (unsigned)vm_page_label); #else vm_address_t vm_addr; kern_return_t kr; kr = vm_allocate(mach_task_self(), &vm_addr, size, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(vm_page_label)); return kr == KERN_SUCCESS ? (void *)vm_addr : NULL; #endif // MALLOC_TARGET_EXCLAVES } #define mvm_allocate_plat(addr, size, align, flags, debug_flags, vm_page_label, plat) \ test_mvm_allocate_plat(addr, size, flags, debug_flags, vm_page_label, plat) static int test_mvm_madvise(void *addr, size_t size, int advice, plat_map_t *map) { #if MALLOC_TARGET_EXCLAVES return !madvise_plat(map, addr, size, LIBLIBC_MAP_HINT_UNUSED); #else kern_return_t kr = madvise(addr, size, advice); return kr != - 1; #endif // MALLOC_TARGET_EXCLAVES } #define mvm_madvise_plat(addr, size, advice, debug_flags, plat) \ test_mvm_madvise(addr, size, advice, plat) static void test_malloc_lock_lock(_malloc_lock_s *lock) { #if MALLOC_HAS_OS_LOCK os_unfair_lock_lock(lock); #else T_QUIET; T_ASSERT_EQ(pthread_mutex_lock(lock), 0, "Lock lock"); #endif // MALLOC_HAS_OS_LOCK } #define _malloc_lock_lock(lock) test_malloc_lock_lock(lock); static void test_malloc_lock_unlock(_malloc_lock_s *lock) { #if MALLOC_HAS_OS_LOCK os_unfair_lock_unlock(lock); #else T_QUIET; T_ASSERT_EQ(pthread_mutex_unlock(lock), 0, "Unlock lock"); #endif // MALLOC_HAS_OS_LOCK } #define _malloc_lock_unlock(lock) test_malloc_lock_unlock(lock); #include "../src/xzone/xzone_metapool.c" #if !MALLOC_TARGET_EXCLAVES bool check_page_is_dirty(void *page) { int disposition = 0; mach_vm_size_t disp_count = 1; kern_return_t kr = mach_vm_page_range_query(mach_task_self(), (mach_vm_address_t)page, KiB(16), (mach_vm_address_t)&disposition, &disp_count); T_QUIET; T_ASSERT_EQ(kr, KERN_SUCCESS, "Query page disposition"); return disposition & VM_PAGE_QUERY_PAGE_DIRTY; } #endif // !MALLOC_TARGET_EXCLAVES T_DECL(xzone_metapool_metadata, "Check that metapools with metadata allocator madvise blocks") { struct xzm_metapool_s metadata_pool = { 0 }; struct xzm_metapool_s data_pool = { 0 }; // Constants const size_t metadata_size = MAX(sizeof(struct xzm_metapool_block_s), sizeof(struct xzm_metapool_slab_s)); const size_t metadata_slab_size = KiB(16); const size_t data_size = KiB(16); const size_t data_slab_size = KiB(512); const size_t num_data_blocks = data_slab_size / data_size; xzm_metapool_init(&metadata_pool, 1, metadata_slab_size, metadata_size, metadata_size, NULL); xzm_metapool_init(&data_pool, 1, data_slab_size, data_size, data_size, &metadata_pool); // Allocate a full slab of data blocks, ensure that they all came from the // same slab, dirty all of their pages, and then free them all. After // freeing, the pages should be madvised void *data[num_data_blocks]; for (int i = 0; i < num_data_blocks; i++) { data[i] = xzm_metapool_alloc(&data_pool); T_ASSERT_NOTNULL(data[i], "Allocate data block"); if (i != 0) { T_ASSERT_EQ((uintptr_t)data[i] - (uintptr_t)data[i-1], data_size, "All data blocks are from the same slab"); } } for (int i = 0; i < num_data_blocks; i++) { memset(data[i], 'A', data_size); #if !MALLOC_TARGET_EXCLAVES T_EXPECT_TRUE(check_page_is_dirty(data[i]), "Page is dirty after memset"); #endif // !MALLOC_TARGET_EXCLAVES } for (int i = 0; i < num_data_blocks; i++) { xzm_metapool_free(&data_pool, data[i]); #if !MALLOC_TARGET_EXCLAVES T_EXPECT_FALSE(check_page_is_dirty(data[i]), "Freed page is not dirty"); #endif // !MALLOC_TARGET_EXCLAVES } } #else // CONFIG_XZONE_MALLOC T_DECL(xzm_metapool_not_supported, "xzone metapool not supported") { T_SKIP("xzone metapool not supported on this platform"); } #endif // CONFIG_XZONE_MALLOC |