Hooks: hook the pure-allocation functions.

This commit is contained in:
David Goldblatt 2018-04-19 13:14:22 -07:00 committed by David Goldblatt
parent fe0e399385
commit 226327cf66
3 changed files with 184 additions and 8 deletions

View File

@ -18,7 +18,7 @@
* hook is called. If it is moved, then the alloc hook is called on the new * hook is called. If it is moved, then the alloc hook is called on the new
* location, and then the free hook is called on the old location. * location, and then the free hook is called on the old location.
* *
* (We omit no-ops, like free(NULL), etc.). * If we return NULL from OOM, then usize might not be trustworthy.
* *
* Reentrancy: * Reentrancy:
* Is not protected against. If your hooks allocate, then the hooks will be * Is not protected against. If your hooks allocate, then the hooks will be

View File

@ -2038,6 +2038,14 @@ je_malloc(size_t size) {
dopts.item_size = size; dopts.item_size = size;
imalloc(&sopts, &dopts); imalloc(&sopts, &dopts);
/*
* Note that this branch gets optimized away -- it immediately follows
* the check on tsd_fast that sets sopts.slow.
*/
if (sopts.slow) {
uintptr_t args[3] = {size};
hook_invoke_alloc(hook_alloc_malloc, ret, (uintptr_t)ret, args);
}
LOG("core.malloc.exit", "result: %p", ret); LOG("core.malloc.exit", "result: %p", ret);
@ -2070,6 +2078,12 @@ je_posix_memalign(void **memptr, size_t alignment, size_t size) {
dopts.alignment = alignment; dopts.alignment = alignment;
ret = imalloc(&sopts, &dopts); ret = imalloc(&sopts, &dopts);
if (sopts.slow) {
uintptr_t args[3] = {(uintptr_t)memptr, (uintptr_t)alignment,
(uintptr_t)size};
hook_invoke_alloc(hook_alloc_posix_memalign, *memptr,
(uintptr_t)ret, args);
}
LOG("core.posix_memalign.exit", "result: %d, alloc ptr: %p", ret, LOG("core.posix_memalign.exit", "result: %d, alloc ptr: %p", ret,
*memptr); *memptr);
@ -2107,6 +2121,11 @@ je_aligned_alloc(size_t alignment, size_t size) {
dopts.alignment = alignment; dopts.alignment = alignment;
imalloc(&sopts, &dopts); imalloc(&sopts, &dopts);
if (sopts.slow) {
uintptr_t args[3] = {(uintptr_t)alignment, (uintptr_t)size};
hook_invoke_alloc(hook_alloc_aligned_alloc, ret,
(uintptr_t)ret, args);
}
LOG("core.aligned_alloc.exit", "result: %p", ret); LOG("core.aligned_alloc.exit", "result: %p", ret);
@ -2138,6 +2157,10 @@ je_calloc(size_t num, size_t size) {
dopts.zero = true; dopts.zero = true;
imalloc(&sopts, &dopts); imalloc(&sopts, &dopts);
if (sopts.slow) {
uintptr_t args[3] = {(uintptr_t)num, (uintptr_t)size};
hook_invoke_alloc(hook_alloc_calloc, ret, (uintptr_t)ret, args);
}
LOG("core.calloc.exit", "result: %p", ret); LOG("core.calloc.exit", "result: %p", ret);
@ -2307,6 +2330,7 @@ je_realloc(void *ptr, size_t size) {
} else { } else {
tcache = NULL; tcache = NULL;
} }
ifree(tsd, ptr, tcache, true); ifree(tsd, ptr, tcache, true);
LOG("core.realloc.exit", "result: %p", NULL); LOG("core.realloc.exit", "result: %p", NULL);
@ -2330,9 +2354,12 @@ je_realloc(void *ptr, size_t size) {
assert(old_usize == isalloc(tsd_tsdn(tsd), ptr)); assert(old_usize == isalloc(tsd_tsdn(tsd), ptr));
if (config_prof && opt_prof) { if (config_prof && opt_prof) {
usize = sz_s2u(size); usize = sz_s2u(size);
ret = unlikely(usize == 0 || usize > LARGE_MAXCLASS) ? if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) {
NULL : irealloc_prof(tsd, ptr, old_usize, usize, ret = NULL;
} else {
ret = irealloc_prof(tsd, ptr, old_usize, usize,
&alloc_ctx); &alloc_ctx);
}
} else { } else {
if (config_stats) { if (config_stats) {
usize = sz_s2u(size); usize = sz_s2u(size);
@ -2342,8 +2369,23 @@ je_realloc(void *ptr, size_t size) {
tsdn = tsd_tsdn(tsd); tsdn = tsd_tsdn(tsd);
} else { } else {
/* realloc(NULL, size) is equivalent to malloc(size). */ /* realloc(NULL, size) is equivalent to malloc(size). */
void *ret = je_malloc(size); static_opts_t sopts;
LOG("core.realloc.exit", "result: %p", ret); dynamic_opts_t dopts;
static_opts_init(&sopts);
dynamic_opts_init(&dopts);
sopts.bump_empty_alloc = true;
sopts.null_out_result_on_error = true;
sopts.set_errno_on_error = true;
sopts.oom_string =
"<jemalloc>: Error in realloc(): out of memory\n";
dopts.result = &ret;
dopts.num_items = 1;
dopts.item_size = size;
imalloc(&sopts, &dopts);
return ret; return ret;
} }
@ -2443,6 +2485,11 @@ je_memalign(size_t alignment, size_t size) {
dopts.alignment = alignment; dopts.alignment = alignment;
imalloc(&sopts, &dopts); imalloc(&sopts, &dopts);
if (sopts.slow) {
uintptr_t args[3] = {alignment, size};
hook_invoke_alloc(hook_alloc_memalign, ret, (uintptr_t)ret,
args);
}
LOG("core.memalign.exit", "result: %p", ret); LOG("core.memalign.exit", "result: %p", ret);
return ret; return ret;
@ -2478,6 +2525,10 @@ je_valloc(size_t size) {
dopts.alignment = PAGE; dopts.alignment = PAGE;
imalloc(&sopts, &dopts); imalloc(&sopts, &dopts);
if (sopts.slow) {
uintptr_t args[3] = {size};
hook_invoke_alloc(hook_alloc_valloc, ret, (uintptr_t)ret, args);
}
LOG("core.valloc.exit", "result: %p\n", ret); LOG("core.valloc.exit", "result: %p\n", ret);
return ret; return ret;
@ -2588,6 +2639,11 @@ je_mallocx(size_t size, int flags) {
} }
imalloc(&sopts, &dopts); imalloc(&sopts, &dopts);
if (sopts.slow) {
uintptr_t args[3] = {size, flags};
hook_invoke_alloc(hook_alloc_mallocx, ret, (uintptr_t)ret,
args);
}
LOG("core.mallocx.exit", "result: %p", ret); LOG("core.mallocx.exit", "result: %p", ret);
return ret; return ret;

View File

@ -37,6 +37,12 @@ assert_args_raw(uintptr_t *args_raw_expected, int nargs) {
assert_d_eq(cmp, 0, "Raw args mismatch"); assert_d_eq(cmp, 0, "Raw args mismatch");
} }
static void
reset() {
call_count = 0;
reset_args();
}
static void static void
test_alloc_hook(void *extra, hook_alloc_t type, void *result, test_alloc_hook(void *extra, hook_alloc_t type, void *result,
uintptr_t result_raw, uintptr_t args_raw[3]) { uintptr_t result_raw, uintptr_t args_raw[3]) {
@ -171,10 +177,124 @@ TEST_BEGIN(test_hooks_remove) {
} }
TEST_END TEST_END
TEST_BEGIN(test_hooks_alloc_simple) {
/* "Simple" in the sense that we're not in a realloc variant. */
hooks_t hooks = {&test_alloc_hook, NULL, NULL};
void *handle = hook_install(TSDN_NULL, &hooks, (void *)123);
assert_ptr_ne(handle, NULL, "Hook installation failed");
/* Stop malloc from being optimized away. */
volatile int err;
void *volatile ptr;
/* malloc */
reset();
ptr = malloc(1);
assert_d_eq(call_count, 1, "Hook not called");
assert_ptr_eq(arg_extra, (void *)123, "Wrong extra");
assert_d_eq(arg_type, (int)hook_alloc_malloc, "Wrong hook type");
assert_ptr_eq(ptr, arg_result, "Wrong result");
assert_u64_eq((uintptr_t)ptr, (uintptr_t)arg_result_raw,
"Wrong raw result");
assert_u64_eq((uintptr_t)1, arg_args_raw[0], "Wrong argument");
free(ptr);
/* posix_memalign */
reset();
err = posix_memalign((void **)&ptr, 1024, 1);
assert_d_eq(call_count, 1, "Hook not called");
assert_ptr_eq(arg_extra, (void *)123, "Wrong extra");
assert_d_eq(arg_type, (int)hook_alloc_posix_memalign,
"Wrong hook type");
assert_ptr_eq(ptr, arg_result, "Wrong result");
assert_u64_eq((uintptr_t)err, (uintptr_t)arg_result_raw,
"Wrong raw result");
assert_u64_eq((uintptr_t)&ptr, arg_args_raw[0], "Wrong argument");
assert_u64_eq((uintptr_t)1024, arg_args_raw[1], "Wrong argument");
assert_u64_eq((uintptr_t)1, arg_args_raw[2], "Wrong argument");
free(ptr);
/* aligned_alloc */
reset();
ptr = aligned_alloc(1024, 1);
assert_d_eq(call_count, 1, "Hook not called");
assert_ptr_eq(arg_extra, (void *)123, "Wrong extra");
assert_d_eq(arg_type, (int)hook_alloc_aligned_alloc,
"Wrong hook type");
assert_ptr_eq(ptr, arg_result, "Wrong result");
assert_u64_eq((uintptr_t)ptr, (uintptr_t)arg_result_raw,
"Wrong raw result");
assert_u64_eq((uintptr_t)1024, arg_args_raw[0], "Wrong argument");
assert_u64_eq((uintptr_t)1, arg_args_raw[1], "Wrong argument");
free(ptr);
/* calloc */
reset();
ptr = calloc(11, 13);
assert_d_eq(call_count, 1, "Hook not called");
assert_ptr_eq(arg_extra, (void *)123, "Wrong extra");
assert_d_eq(arg_type, (int)hook_alloc_calloc, "Wrong hook type");
assert_ptr_eq(ptr, arg_result, "Wrong result");
assert_u64_eq((uintptr_t)ptr, (uintptr_t)arg_result_raw,
"Wrong raw result");
assert_u64_eq((uintptr_t)11, arg_args_raw[0], "Wrong argument");
assert_u64_eq((uintptr_t)13, arg_args_raw[1], "Wrong argument");
free(ptr);
/* memalign */
#ifdef JEMALLOC_OVERRIDE_MEMALIGN
reset();
ptr = memalign(1024, 1);
assert_d_eq(call_count, 1, "Hook not called");
assert_ptr_eq(arg_extra, (void *)123, "Wrong extra");
assert_d_eq(arg_type, (int)hook_alloc_memalign, "Wrong hook type");
assert_ptr_eq(ptr, arg_result, "Wrong result");
assert_u64_eq((uintptr_t)ptr, (uintptr_t)arg_result_raw,
"Wrong raw result");
assert_u64_eq((uintptr_t)1024, arg_args_raw[0], "Wrong argument");
assert_u64_eq((uintptr_t)1, arg_args_raw[1], "Wrong argument");
free(ptr);
#endif /* JEMALLOC_OVERRIDE_MEMALIGN */
/* valloc */
#ifdef JEMALLOC_OVERRIDE_VALLOC
reset();
ptr = valloc(1);
assert_d_eq(call_count, 1, "Hook not called");
assert_ptr_eq(arg_extra, (void *)123, "Wrong extra");
assert_d_eq(arg_type, (int)hook_alloc_valloc, "Wrong hook type");
assert_ptr_eq(ptr, arg_result, "Wrong result");
assert_u64_eq((uintptr_t)ptr, (uintptr_t)arg_result_raw,
"Wrong raw result");
assert_u64_eq((uintptr_t)1, arg_args_raw[0], "Wrong argument");
free(ptr);
#endif /* JEMALLOC_OVERRIDE_VALLOC */
/* mallocx */
reset();
ptr = mallocx(1, MALLOCX_LG_ALIGN(10));
assert_d_eq(call_count, 1, "Hook not called");
assert_ptr_eq(arg_extra, (void *)123, "Wrong extra");
assert_d_eq(arg_type, (int)hook_alloc_mallocx, "Wrong hook type");
assert_ptr_eq(ptr, arg_result, "Wrong result");
assert_u64_eq((uintptr_t)ptr, (uintptr_t)arg_result_raw,
"Wrong raw result");
assert_u64_eq((uintptr_t)1, arg_args_raw[0], "Wrong argument");
assert_u64_eq((uintptr_t)MALLOCX_LG_ALIGN(10), arg_args_raw[1],
"Wrong flags");
free(ptr);
hook_remove(TSDN_NULL, handle);
}
TEST_END
int int
main(void) { main(void) {
return test( /* We assert on call counts. */
return test_no_reentrancy(
test_hooks_basic, test_hooks_basic,
test_hooks_null, test_hooks_null,
test_hooks_remove); test_hooks_remove,
test_hooks_alloc_simple);
} }