1 #include "test/jemalloc_test.h" 2 3 const char *dump_filename = "/dev/null"; 4 5 prof_backtrace_hook_t default_hook; 6 7 bool mock_bt_hook_called = false; 8 bool mock_dump_hook_called = false; 9 10 void 11 mock_bt_hook(void **vec, unsigned *len, unsigned max_len) { 12 *len = max_len; 13 for (unsigned i = 0; i < max_len; ++i) { 14 vec[i] = (void *)((uintptr_t)i); 15 } 16 mock_bt_hook_called = true; 17 } 18 19 void 20 mock_bt_augmenting_hook(void **vec, unsigned *len, unsigned max_len) { 21 default_hook(vec, len, max_len); 22 expect_u_gt(*len, 0, "Default backtrace hook returned empty backtrace"); 23 expect_u_lt(*len, max_len, 24 "Default backtrace hook returned too large backtrace"); 25 26 /* Add a separator between default frames and augmented */ 27 vec[*len] = (void *)0x030303030; 28 (*len)++; 29 30 /* Add more stack frames */ 31 for (unsigned i = 0; i < 3; ++i) { 32 if (*len == max_len) { 33 break; 34 } 35 vec[*len] = (void *)((uintptr_t)i); 36 (*len)++; 37 } 38 39 40 mock_bt_hook_called = true; 41 } 42 43 void 44 mock_dump_hook(const char *filename) { 45 mock_dump_hook_called = true; 46 expect_str_eq(filename, dump_filename, 47 "Incorrect file name passed to the dump hook"); 48 } 49 50 TEST_BEGIN(test_prof_backtrace_hook_replace) { 51 52 test_skip_if(!config_prof); 53 54 mock_bt_hook_called = false; 55 56 void *p0 = mallocx(1, 0); 57 assert_ptr_not_null(p0, "Failed to allocate"); 58 59 expect_false(mock_bt_hook_called, "Called mock hook before it's set"); 60 61 prof_backtrace_hook_t null_hook = NULL; 62 expect_d_eq(mallctl("experimental.hooks.prof_backtrace", 63 NULL, 0, (void *)&null_hook, sizeof(null_hook)), 64 EINVAL, "Incorrectly allowed NULL backtrace hook"); 65 66 size_t default_hook_sz = sizeof(prof_backtrace_hook_t); 67 prof_backtrace_hook_t hook = &mock_bt_hook; 68 expect_d_eq(mallctl("experimental.hooks.prof_backtrace", 69 (void *)&default_hook, &default_hook_sz, (void *)&hook, 70 sizeof(hook)), 0, "Unexpected mallctl failure setting hook"); 71 72 void *p1 = mallocx(1, 0); 73 assert_ptr_not_null(p1, "Failed to allocate"); 74 75 expect_true(mock_bt_hook_called, "Didn't call mock hook"); 76 77 prof_backtrace_hook_t current_hook; 78 size_t current_hook_sz = sizeof(prof_backtrace_hook_t); 79 expect_d_eq(mallctl("experimental.hooks.prof_backtrace", 80 (void *)¤t_hook, ¤t_hook_sz, (void *)&default_hook, 81 sizeof(default_hook)), 0, 82 "Unexpected mallctl failure resetting hook to default"); 83 84 expect_ptr_eq(current_hook, hook, 85 "Hook returned by mallctl is not equal to mock hook"); 86 87 dallocx(p1, 0); 88 dallocx(p0, 0); 89 } 90 TEST_END 91 92 TEST_BEGIN(test_prof_backtrace_hook_augment) { 93 94 test_skip_if(!config_prof); 95 96 mock_bt_hook_called = false; 97 98 void *p0 = mallocx(1, 0); 99 assert_ptr_not_null(p0, "Failed to allocate"); 100 101 expect_false(mock_bt_hook_called, "Called mock hook before it's set"); 102 103 size_t default_hook_sz = sizeof(prof_backtrace_hook_t); 104 prof_backtrace_hook_t hook = &mock_bt_augmenting_hook; 105 expect_d_eq(mallctl("experimental.hooks.prof_backtrace", 106 (void *)&default_hook, &default_hook_sz, (void *)&hook, 107 sizeof(hook)), 0, "Unexpected mallctl failure setting hook"); 108 109 void *p1 = mallocx(1, 0); 110 assert_ptr_not_null(p1, "Failed to allocate"); 111 112 expect_true(mock_bt_hook_called, "Didn't call mock hook"); 113 114 prof_backtrace_hook_t current_hook; 115 size_t current_hook_sz = sizeof(prof_backtrace_hook_t); 116 expect_d_eq(mallctl("experimental.hooks.prof_backtrace", 117 (void *)¤t_hook, ¤t_hook_sz, (void *)&default_hook, 118 sizeof(default_hook)), 0, 119 "Unexpected mallctl failure resetting hook to default"); 120 121 expect_ptr_eq(current_hook, hook, 122 "Hook returned by mallctl is not equal to mock hook"); 123 124 dallocx(p1, 0); 125 dallocx(p0, 0); 126 } 127 TEST_END 128 129 TEST_BEGIN(test_prof_dump_hook) { 130 131 test_skip_if(!config_prof); 132 133 mock_dump_hook_called = false; 134 135 expect_d_eq(mallctl("prof.dump", NULL, NULL, (void *)&dump_filename, 136 sizeof(dump_filename)), 0, "Failed to dump heap profile"); 137 138 expect_false(mock_dump_hook_called, "Called dump hook before it's set"); 139 140 size_t default_hook_sz = sizeof(prof_dump_hook_t); 141 prof_dump_hook_t hook = &mock_dump_hook; 142 expect_d_eq(mallctl("experimental.hooks.prof_dump", 143 (void *)&default_hook, &default_hook_sz, (void *)&hook, 144 sizeof(hook)), 0, "Unexpected mallctl failure setting hook"); 145 146 expect_d_eq(mallctl("prof.dump", NULL, NULL, (void *)&dump_filename, 147 sizeof(dump_filename)), 0, "Failed to dump heap profile"); 148 149 expect_true(mock_dump_hook_called, "Didn't call mock hook"); 150 151 prof_dump_hook_t current_hook; 152 size_t current_hook_sz = sizeof(prof_dump_hook_t); 153 expect_d_eq(mallctl("experimental.hooks.prof_dump", 154 (void *)¤t_hook, ¤t_hook_sz, (void *)&default_hook, 155 sizeof(default_hook)), 0, 156 "Unexpected mallctl failure resetting hook to default"); 157 158 expect_ptr_eq(current_hook, hook, 159 "Hook returned by mallctl is not equal to mock hook"); 160 } 161 TEST_END 162 163 int 164 main(void) { 165 return test( 166 test_prof_backtrace_hook_replace, 167 test_prof_backtrace_hook_augment, 168 test_prof_dump_hook); 169 } 170