Hooks: hook the realloc paths that act as pure malloc/free.

This commit is contained in:
David Goldblatt 2018-04-19 16:44:25 -07:00 committed by David Goldblatt
parent 83e516154c
commit 67270040a5
3 changed files with 67 additions and 5 deletions

View File

@ -16,9 +16,13 @@
* *
* For realloc and rallocx, if the expansion happens in place, the expansion * For realloc and rallocx, if the expansion happens in place, the expansion
* 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 (i.e. both
* hooks are invoked in between the alloc and the dalloc).
* *
* If we return NULL from OOM, then usize might not be trustworthy. * If we return NULL from OOM, then usize might not be trustworthy. Calling
* realloc(NULL, size) only calls the alloc hook, and calling realloc(ptr, 0)
* only calls the free hook. (Calling realloc(NULL, 0) is treated as malloc(0),
* and only calls the alloc hook).
* *
* 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

@ -2311,11 +2311,12 @@ isfree(tsd_t *tsd, void *ptr, size_t usize, tcache_t *tcache, bool slow_path) {
JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
void JEMALLOC_NOTHROW * void JEMALLOC_NOTHROW *
JEMALLOC_ALLOC_SIZE(2) JEMALLOC_ALLOC_SIZE(2)
je_realloc(void *ptr, size_t size) { je_realloc(void *ptr, size_t arg_size) {
void *ret; void *ret;
tsdn_t *tsdn JEMALLOC_CC_SILENCE_INIT(NULL); tsdn_t *tsdn JEMALLOC_CC_SILENCE_INIT(NULL);
size_t usize JEMALLOC_CC_SILENCE_INIT(0); size_t usize JEMALLOC_CC_SILENCE_INIT(0);
size_t old_usize = 0; size_t old_usize = 0;
size_t size = arg_size;
LOG("core.realloc.entry", "ptr: %p, size: %zu\n", ptr, size); LOG("core.realloc.entry", "ptr: %p, size: %zu\n", ptr, size);
@ -2331,6 +2332,9 @@ je_realloc(void *ptr, size_t size) {
tcache = NULL; tcache = NULL;
} }
uintptr_t args[3] = {(uintptr_t)ptr, size};
hook_invoke_dalloc(hook_dalloc_realloc, ptr, args);
ifree(tsd, ptr, tcache, true); ifree(tsd, ptr, tcache, true);
LOG("core.realloc.exit", "result: %p", NULL); LOG("core.realloc.exit", "result: %p", NULL);
@ -2386,6 +2390,12 @@ je_realloc(void *ptr, size_t size) {
dopts.item_size = size; dopts.item_size = size;
imalloc(&sopts, &dopts); imalloc(&sopts, &dopts);
if (sopts.slow) {
uintptr_t args[3] = {(uintptr_t)ptr, arg_size};
hook_invoke_alloc(hook_alloc_realloc, ret,
(uintptr_t)ret, args);
}
return ret; return ret;
} }

View File

@ -179,7 +179,6 @@ TEST_END
TEST_BEGIN(test_hooks_alloc_simple) { TEST_BEGIN(test_hooks_alloc_simple) {
/* "Simple" in the sense that we're not in a realloc variant. */ /* "Simple" in the sense that we're not in a realloc variant. */
hooks_t hooks = {&test_alloc_hook, NULL, NULL}; hooks_t hooks = {&test_alloc_hook, NULL, NULL};
void *handle = hook_install(TSDN_NULL, &hooks, (void *)123); void *handle = hook_install(TSDN_NULL, &hooks, (void *)123);
assert_ptr_ne(handle, NULL, "Hook installation failed"); assert_ptr_ne(handle, NULL, "Hook installation failed");
@ -364,6 +363,54 @@ TEST_BEGIN(test_hooks_expand_simple) {
} }
TEST_END TEST_END
TEST_BEGIN(test_hooks_realloc_as_malloc_or_free) {
hooks_t hooks = {&test_alloc_hook, &test_dalloc_hook,
&test_expand_hook};
void *handle = hook_install(TSDN_NULL, &hooks, (void *)123);
assert_ptr_ne(handle, NULL, "Hook installation failed");
void *volatile ptr;
/* realloc(NULL, size) as malloc */
reset();
ptr = realloc(NULL, 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_realloc, "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)NULL, arg_args_raw[0], "Wrong argument");
assert_u64_eq((uintptr_t)1, arg_args_raw[1], "Wrong argument");
free(ptr);
/* realloc(ptr, 0) as free */
ptr = malloc(1);
reset();
realloc(ptr, 0);
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_dalloc_realloc, "Wrong hook type");
assert_ptr_eq(ptr, arg_address, "Wrong pointer freed");
assert_u64_eq((uintptr_t)ptr, arg_args_raw[0], "Wrong raw arg");
assert_u64_eq((uintptr_t)0, arg_args_raw[1], "Wrong raw arg");
/* realloc(NULL, 0) as malloc(0) */
reset();
ptr = realloc(NULL, 0);
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_realloc, "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)NULL, arg_args_raw[0], "Wrong argument");
assert_u64_eq((uintptr_t)0, arg_args_raw[1], "Wrong argument");
free(ptr);
hook_remove(TSDN_NULL, handle);
}
TEST_END
int int
main(void) { main(void) {
@ -374,5 +421,6 @@ main(void) {
test_hooks_remove, test_hooks_remove,
test_hooks_alloc_simple, test_hooks_alloc_simple,
test_hooks_dalloc_simple, test_hooks_dalloc_simple,
test_hooks_expand_simple); test_hooks_expand_simple,
test_hooks_realloc_as_malloc_or_free);
} }