summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Goldblatt <davidgoldblatt@fb.com>2018-04-19 23:44:25 (GMT)
committerDavid Goldblatt <davidtgoldblatt@gmail.com>2018-05-18 18:43:03 (GMT)
commit67270040a56d8658ce6aec81b15d78571e0e9198 (patch)
tree5ef84de38d19245572e5039740315fad50adf161
parent83e516154cfacfc1e010a03f2f420bf79913944a (diff)
downloadjemalloc-67270040a56d8658ce6aec81b15d78571e0e9198.zip
jemalloc-67270040a56d8658ce6aec81b15d78571e0e9198.tar.gz
jemalloc-67270040a56d8658ce6aec81b15d78571e0e9198.tar.bz2
Hooks: hook the realloc paths that act as pure malloc/free.
-rw-r--r--include/jemalloc/internal/hook.h8
-rw-r--r--src/jemalloc.c12
-rw-r--r--test/unit/hook.c52
3 files changed, 67 insertions, 5 deletions
diff --git a/include/jemalloc/internal/hook.h b/include/jemalloc/internal/hook.h
index fbf3a07..ac1bcdb 100644
--- a/include/jemalloc/internal/hook.h
+++ b/include/jemalloc/internal/hook.h
@@ -16,9 +16,13 @@
*
* 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
- * 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:
* Is not protected against. If your hooks allocate, then the hooks will be
diff --git a/src/jemalloc.c b/src/jemalloc.c
index 1a62180..57c2019 100644
--- a/src/jemalloc.c
+++ b/src/jemalloc.c
@@ -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
void JEMALLOC_NOTHROW *
JEMALLOC_ALLOC_SIZE(2)
-je_realloc(void *ptr, size_t size) {
+je_realloc(void *ptr, size_t arg_size) {
void *ret;
tsdn_t *tsdn JEMALLOC_CC_SILENCE_INIT(NULL);
size_t usize JEMALLOC_CC_SILENCE_INIT(0);
size_t old_usize = 0;
+ size_t size = arg_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;
}
+ uintptr_t args[3] = {(uintptr_t)ptr, size};
+ hook_invoke_dalloc(hook_dalloc_realloc, ptr, args);
+
ifree(tsd, ptr, tcache, true);
LOG("core.realloc.exit", "result: %p", NULL);
@@ -2386,6 +2390,12 @@ je_realloc(void *ptr, size_t size) {
dopts.item_size = size;
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;
}
diff --git a/test/unit/hook.c b/test/unit/hook.c
index f923f72..8c9d680 100644
--- a/test/unit/hook.c
+++ b/test/unit/hook.c
@@ -179,7 +179,6 @@ 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");
@@ -364,6 +363,54 @@ TEST_BEGIN(test_hooks_expand_simple) {
}
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
main(void) {
@@ -374,5 +421,6 @@ main(void) {
test_hooks_remove,
test_hooks_alloc_simple,
test_hooks_dalloc_simple,
- test_hooks_expand_simple);
+ test_hooks_expand_simple,
+ test_hooks_realloc_as_malloc_or_free);
}