prof_hook.c 4.8 KB

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