summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorAlex Lapenkou <lapenkov@fb.com>2021-09-01 13:00:01 -0700
committerAlexander Lapenkov <lapenkov.a@yandex.ru>2021-09-22 15:04:01 -0700
commita9031a0970df9c999873617423f789bd46bfe619 (patch)
tree3ad66313811401baad2e4048b985c9d3c5740b0d /test
parentf7d46b81197b9879e1f572f9a4d3bfe3b8f850b9 (diff)
downloadjemalloc-a9031a0970df9c999873617423f789bd46bfe619.tar.gz
Allow setting a dump hook
If users want to be notified when a heap dump occurs, they can set this hook.
Diffstat (limited to 'test')
-rw-r--r--test/unit/prof_hook.c114
1 files changed, 111 insertions, 3 deletions
diff --git a/test/unit/prof_hook.c b/test/unit/prof_hook.c
index 32d0e9ea..6480d930 100644
--- a/test/unit/prof_hook.c
+++ b/test/unit/prof_hook.c
@@ -1,6 +1,11 @@
#include "test/jemalloc_test.h"
+const char *dump_filename = "/dev/null";
+
+prof_backtrace_hook_t default_hook;
+
bool mock_bt_hook_called = false;
+bool mock_dump_hook_called = false;
void
mock_bt_hook(void **vec, unsigned *len, unsigned max_len) {
@@ -11,7 +16,38 @@ mock_bt_hook(void **vec, unsigned *len, unsigned max_len) {
mock_bt_hook_called = true;
}
-TEST_BEGIN(test_prof_backtrace_hook) {
+void
+mock_bt_augmenting_hook(void **vec, unsigned *len, unsigned max_len) {
+ default_hook(vec, len, max_len);
+ expect_u_gt(*len, 0, "Default backtrace hook returned empty backtrace");
+ expect_u_lt(*len, max_len,
+ "Default backtrace hook returned too large backtrace");
+
+ /* Add a separator between default frames and augmented */
+ vec[*len] = (void *)0x030303030;
+ (*len)++;
+
+ /* Add more stack frames */
+ for (unsigned i = 0; i < 3; ++i) {
+ if (*len == max_len) {
+ break;
+ }
+ vec[*len] = (void *)((uintptr_t)i);
+ (*len)++;
+ }
+
+
+ mock_bt_hook_called = true;
+}
+
+void
+mock_dump_hook(const char *filename) {
+ mock_dump_hook_called = true;
+ expect_str_eq(filename, dump_filename,
+ "Incorrect file name passed to the dump hook");
+}
+
+TEST_BEGIN(test_prof_backtrace_hook_replace) {
test_skip_if(!config_prof);
@@ -27,7 +63,6 @@ TEST_BEGIN(test_prof_backtrace_hook) {
NULL, 0, (void *)&null_hook, sizeof(null_hook)),
EINVAL, "Incorrectly allowed NULL backtrace hook");
- prof_backtrace_hook_t default_hook;
size_t default_hook_sz = sizeof(prof_backtrace_hook_t);
prof_backtrace_hook_t hook = &mock_bt_hook;
expect_d_eq(mallctl("experimental.hooks.prof_backtrace",
@@ -54,8 +89,81 @@ TEST_BEGIN(test_prof_backtrace_hook) {
}
TEST_END
+TEST_BEGIN(test_prof_backtrace_hook_augment) {
+
+ test_skip_if(!config_prof);
+
+ mock_bt_hook_called = false;
+
+ void *p0 = mallocx(1, 0);
+ assert_ptr_not_null(p0, "Failed to allocate");
+
+ expect_false(mock_bt_hook_called, "Called mock hook before it's set");
+
+ size_t default_hook_sz = sizeof(prof_backtrace_hook_t);
+ prof_backtrace_hook_t hook = &mock_bt_augmenting_hook;
+ expect_d_eq(mallctl("experimental.hooks.prof_backtrace",
+ (void *)&default_hook, &default_hook_sz, (void *)&hook,
+ sizeof(hook)), 0, "Unexpected mallctl failure setting hook");
+
+ void *p1 = mallocx(1, 0);
+ assert_ptr_not_null(p1, "Failed to allocate");
+
+ expect_true(mock_bt_hook_called, "Didn't call mock hook");
+
+ prof_backtrace_hook_t current_hook;
+ size_t current_hook_sz = sizeof(prof_backtrace_hook_t);
+ expect_d_eq(mallctl("experimental.hooks.prof_backtrace",
+ (void *)&current_hook, &current_hook_sz, (void *)&default_hook,
+ sizeof(default_hook)), 0,
+ "Unexpected mallctl failure resetting hook to default");
+
+ expect_ptr_eq(current_hook, hook,
+ "Hook returned by mallctl is not equal to mock hook");
+
+ dallocx(p1, 0);
+ dallocx(p0, 0);
+}
+TEST_END
+
+TEST_BEGIN(test_prof_dump_hook) {
+
+ test_skip_if(!config_prof);
+
+ mock_dump_hook_called = false;
+
+ expect_d_eq(mallctl("prof.dump", NULL, NULL, (void *)&dump_filename,
+ sizeof(dump_filename)), 0, "Failed to dump heap profile");
+
+ expect_false(mock_dump_hook_called, "Called dump hook before it's set");
+
+ size_t default_hook_sz = sizeof(prof_dump_hook_t);
+ prof_dump_hook_t hook = &mock_dump_hook;
+ expect_d_eq(mallctl("experimental.hooks.prof_dump",
+ (void *)&default_hook, &default_hook_sz, (void *)&hook,
+ sizeof(hook)), 0, "Unexpected mallctl failure setting hook");
+
+ expect_d_eq(mallctl("prof.dump", NULL, NULL, (void *)&dump_filename,
+ sizeof(dump_filename)), 0, "Failed to dump heap profile");
+
+ expect_true(mock_dump_hook_called, "Didn't call mock hook");
+
+ prof_dump_hook_t current_hook;
+ size_t current_hook_sz = sizeof(prof_dump_hook_t);
+ expect_d_eq(mallctl("experimental.hooks.prof_dump",
+ (void *)&current_hook, &current_hook_sz, (void *)&default_hook,
+ sizeof(default_hook)), 0,
+ "Unexpected mallctl failure resetting hook to default");
+
+ expect_ptr_eq(current_hook, hook,
+ "Hook returned by mallctl is not equal to mock hook");
+}
+TEST_END
+
int
main(void) {
return test(
- test_prof_backtrace_hook);
+ test_prof_backtrace_hook_replace,
+ test_prof_backtrace_hook_augment,
+ test_prof_dump_hook);
}