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
|
* 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
|
||||||
|
@ -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;
|
||||||
|
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");
|
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);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user