Hooks: hook the pure-allocation functions.
This commit is contained in:
parent
fe0e399385
commit
226327cf66
@ -18,7 +18,7 @@
|
||||
* 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.
|
||||
*
|
||||
* (We omit no-ops, like free(NULL), etc.).
|
||||
* If we return NULL from OOM, then usize might not be trustworthy.
|
||||
*
|
||||
* Reentrancy:
|
||||
* Is not protected against. If your hooks allocate, then the hooks will be
|
||||
|
@ -2038,6 +2038,14 @@ je_malloc(size_t size) {
|
||||
dopts.item_size = size;
|
||||
|
||||
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);
|
||||
|
||||
@ -2070,6 +2078,12 @@ je_posix_memalign(void **memptr, size_t alignment, size_t size) {
|
||||
dopts.alignment = alignment;
|
||||
|
||||
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,
|
||||
*memptr);
|
||||
@ -2107,6 +2121,11 @@ je_aligned_alloc(size_t alignment, size_t size) {
|
||||
dopts.alignment = alignment;
|
||||
|
||||
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);
|
||||
|
||||
@ -2138,6 +2157,10 @@ je_calloc(size_t num, size_t size) {
|
||||
dopts.zero = true;
|
||||
|
||||
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);
|
||||
|
||||
@ -2307,6 +2330,7 @@ je_realloc(void *ptr, size_t size) {
|
||||
} else {
|
||||
tcache = NULL;
|
||||
}
|
||||
|
||||
ifree(tsd, ptr, tcache, true);
|
||||
|
||||
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));
|
||||
if (config_prof && opt_prof) {
|
||||
usize = sz_s2u(size);
|
||||
ret = unlikely(usize == 0 || usize > LARGE_MAXCLASS) ?
|
||||
NULL : irealloc_prof(tsd, ptr, old_usize, usize,
|
||||
if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) {
|
||||
ret = NULL;
|
||||
} else {
|
||||
ret = irealloc_prof(tsd, ptr, old_usize, usize,
|
||||
&alloc_ctx);
|
||||
}
|
||||
} else {
|
||||
if (config_stats) {
|
||||
usize = sz_s2u(size);
|
||||
@ -2342,8 +2369,23 @@ je_realloc(void *ptr, size_t size) {
|
||||
tsdn = tsd_tsdn(tsd);
|
||||
} else {
|
||||
/* realloc(NULL, size) is equivalent to malloc(size). */
|
||||
void *ret = je_malloc(size);
|
||||
LOG("core.realloc.exit", "result: %p", ret);
|
||||
static_opts_t sopts;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -2443,6 +2485,11 @@ je_memalign(size_t alignment, size_t size) {
|
||||
dopts.alignment = alignment;
|
||||
|
||||
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);
|
||||
return ret;
|
||||
@ -2478,6 +2525,10 @@ je_valloc(size_t size) {
|
||||
dopts.alignment = PAGE;
|
||||
|
||||
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);
|
||||
return ret;
|
||||
@ -2588,6 +2639,11 @@ je_mallocx(size_t size, int flags) {
|
||||
}
|
||||
|
||||
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);
|
||||
return ret;
|
||||
|
124
test/unit/hook.c
124
test/unit/hook.c
@ -37,6 +37,12 @@ assert_args_raw(uintptr_t *args_raw_expected, int nargs) {
|
||||
assert_d_eq(cmp, 0, "Raw args mismatch");
|
||||
}
|
||||
|
||||
static void
|
||||
reset() {
|
||||
call_count = 0;
|
||||
reset_args();
|
||||
}
|
||||
|
||||
static void
|
||||
test_alloc_hook(void *extra, hook_alloc_t type, void *result,
|
||||
uintptr_t result_raw, uintptr_t args_raw[3]) {
|
||||
@ -171,10 +177,124 @@ TEST_BEGIN(test_hooks_remove) {
|
||||
}
|
||||
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
|
||||
main(void) {
|
||||
return test(
|
||||
/* We assert on call counts. */
|
||||
return test_no_reentrancy(
|
||||
test_hooks_basic,
|
||||
test_hooks_null,
|
||||
test_hooks_remove);
|
||||
test_hooks_remove,
|
||||
test_hooks_alloc_simple);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user