summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Goldblatt <davidgoldblatt@fb.com>2018-04-19 20:14:22 (GMT)
committerDavid Goldblatt <davidtgoldblatt@gmail.com>2018-05-18 18:43:03 (GMT)
commit226327cf66f6e1fb1aed24ed3e2e9c291d1843b7 (patch)
tree44ff5517c1f21d21a20d4802bd6e01eec0c65544
parentfe0e39938593b5fb16dc09fcdbe29d6ad7b3cf05 (diff)
downloadjemalloc-226327cf66f6e1fb1aed24ed3e2e9c291d1843b7.zip
jemalloc-226327cf66f6e1fb1aed24ed3e2e9c291d1843b7.tar.gz
jemalloc-226327cf66f6e1fb1aed24ed3e2e9c291d1843b7.tar.bz2
Hooks: hook the pure-allocation functions.
-rw-r--r--include/jemalloc/internal/hook.h2
-rw-r--r--src/jemalloc.c66
-rw-r--r--test/unit/hook.c124
3 files changed, 184 insertions, 8 deletions
diff --git a/include/jemalloc/internal/hook.h b/include/jemalloc/internal/hook.h
index 847c91b..fbf3a07 100644
--- a/include/jemalloc/internal/hook.h
+++ b/include/jemalloc/internal/hook.h
@@ -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
diff --git a/src/jemalloc.c b/src/jemalloc.c
index f837e6b..df59f69 100644
--- a/src/jemalloc.c
+++ b/src/jemalloc.c
@@ -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,
- &alloc_ctx);
+ 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;
diff --git a/test/unit/hook.c b/test/unit/hook.c
index a959096..06d4b82 100644
--- a/test/unit/hook.c
+++ b/test/unit/hook.c
@@ -38,6 +38,12 @@ assert_args_raw(uintptr_t *args_raw_expected, int nargs) {
}
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]) {
call_count++;
@@ -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);
}