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 | #include <stdlib.h> #include <darwintest.h> #include <malloc_private.h> #include "../src/platform.h" T_GLOBAL_META(T_META_RUN_CONCURRENTLY(true), T_META_TAG_ALL_ALLOCATORS); #if !MALLOC_TARGET_EXCLAVES // Exclaves don't support disabling zero on free T_DECL(malloc_checkfix_zero_on_free, "Test malloc_zero_on_free_disable() SPI", T_META_ENVVAR("MallocZeroOnFree=1"), T_META_TAG_VM_PREFERRED) { // Drive some activity up front void *p1 = malloc(16); T_ASSERT_NOTNULL(p1, "malloc 1"); void *p2 = malloc(512); T_ASSERT_NOTNULL(p1, "malloc 2"); free(p2); // Call the checkfix SPI malloc_zero_on_free_disable(); // Drive some more activity void *p3 = calloc(1, 512); T_ASSERT_NOTNULL(p3, "calloc 1"); free(p3); free(p1); T_PASS("Reached the end"); } #endif // !MALLOC_TARGET_EXCLAVES static void assert_all_zero(char *allocation, size_t size) { for (size_t i = 0; i < size; i++) { T_QUIET; T_ASSERT_EQ(allocation[i], '\0', "byte %zu should be 0", i); } } #if !MALLOC_TARGET_EXCLAVES T_DECL(malloc_zone_batch_zero_on_free, "malloc_zone_batch_free must zero-on-free", T_META_ENVVAR("MallocZeroOnFree=1"), T_META_ENVVAR("MallocCheckZeroOnFreeCorruption=1"), T_META_ENVVAR("MallocNanoZone=0"), T_META_TAG_VM_PREFERRED) { const int n = 3; const size_t size = 272; void *allocations[n]; for (int i = 0; i < n; i++) { allocations[i] = malloc(size); T_QUIET; T_ASSERT_NOTNULL(allocations[i], "malloc()"); memset(allocations[i], 'a', size); } malloc_zone_batch_free(malloc_default_zone(), allocations, n); char *allocation = calloc(1, size); T_QUIET; T_ASSERT_NOTNULL(allocation, "calloc()"); assert_all_zero(allocation, size); free(allocation); T_PASS("Successful calloc after batch free"); } #endif // !MALLOC_TARGET_EXCLAVES static void check_zeroing_mode(void) { // Note: normally we would T_ASSERT that malloc returned non-NULL pointers, // but that may trigger undesired allocations that would interfere with the // intended sequence, so we'll just let them crash instead if that happens // Exercise nano support (may still be tiny if !CONFIG_NANOZONE) const size_t nano_alloc_size = 16; void *p1 = malloc(nano_alloc_size); memset(p1, 'a', nano_alloc_size); void *p2 = malloc(nano_alloc_size); memset(p2, 'b', nano_alloc_size); free(p1); p1 = malloc(nano_alloc_size); // we probably got the old p1 back // Regardless of whether or not we got the old one, we should be guaranteed // by zero-on-alloc mode that the allocation is zero-filled assert_all_zero(p1, nano_alloc_size); free(p1); free(p2); // Exercise tiny support const size_t tiny_alloc_size = 320; p1 = malloc(tiny_alloc_size); memset(p1, 'c', tiny_alloc_size); p2 = malloc(tiny_alloc_size); memset(p2, 'd', tiny_alloc_size); free(p1); p1 = malloc(tiny_alloc_size); // we probably got the old p1 back // Regardless of whether or not we got the old one, we should be guaranteed // that the allocation is zero-filled assert_all_zero(p1, tiny_alloc_size); // Also check realloc: p2 is most likely next to p1, so if we free p2 and // realloc up p1 it should coalesce. Regardless of whether or not that // happens, we should be guaranteed that it's zero-filled free(p2); void *p3 = realloc(p1, tiny_alloc_size + 64); assert_all_zero(p3, tiny_alloc_size + 64); free(p3); T_PASS("No issues for zeroing mode"); } T_DECL(malloc_zero_on_alloc, "Exercise zero-on-alloc mode", T_META_ENVVAR("MallocZeroOnAlloc=1"), T_META_ENVVAR("MallocNanoZone=1"), T_META_TAG_VM_PREFERRED) { check_zeroing_mode(); } T_DECL(malloc_zero_on_free, "Exercise zero-on-free mode", T_META_ENVVAR("MallocZeroOnFree=1"), T_META_ENVVAR("MallocNanoZone=1"), T_META_TAG_VM_PREFERRED) { check_zeroing_mode(); } |