Hooks: hook the realloc pathways that move/expand.
This commit is contained in:
parent
67270040a5
commit
cb0707c0fc
@ -3,6 +3,7 @@
|
||||
|
||||
#include "jemalloc/internal/bin.h"
|
||||
#include "jemalloc/internal/extent_dss.h"
|
||||
#include "jemalloc/internal/hook.h"
|
||||
#include "jemalloc/internal/pages.h"
|
||||
#include "jemalloc/internal/size_classes.h"
|
||||
#include "jemalloc/internal/stats.h"
|
||||
@ -65,7 +66,8 @@ void arena_dalloc_small(tsdn_t *tsdn, void *ptr);
|
||||
bool arena_ralloc_no_move(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size,
|
||||
size_t extra, bool zero);
|
||||
void *arena_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t oldsize,
|
||||
size_t size, size_t alignment, bool zero, tcache_t *tcache);
|
||||
size_t size, size_t alignment, bool zero, tcache_t *tcache,
|
||||
hook_ralloc_args_t *hook_args);
|
||||
dss_prec_t arena_dss_prec_get(arena_t *arena);
|
||||
bool arena_dss_prec_set(arena_t *arena, dss_prec_t dss_prec);
|
||||
ssize_t arena_dirty_decay_ms_default_get(void);
|
||||
|
@ -105,6 +105,37 @@ struct hooks_s {
|
||||
hook_expand expand_hook;
|
||||
};
|
||||
|
||||
/*
|
||||
* Begin implementation details; everything above this point might one day live
|
||||
* in a public API. Everything below this point never will.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The realloc pathways haven't gotten any refactoring love in a while, and it's
|
||||
* fairly difficult to pass information from the entry point to the hooks. We
|
||||
* put the informaiton the hooks will need into a struct to encapsulate
|
||||
* everything.
|
||||
*
|
||||
* Much of these pathways are force-inlined, so that the compiler can avoid
|
||||
* materializing this struct until we hit an extern arena function. For fairly
|
||||
* goofy reasons, *many* of the realloc paths hit an extern arena function.
|
||||
* These paths are cold enough that it doesn't matter; eventually, we should
|
||||
* rewrite the realloc code to make the expand-in-place and the
|
||||
* free-then-realloc paths more orthogonal, at which point we don't need to
|
||||
* spread the hook logic all over the place.
|
||||
*/
|
||||
typedef struct hook_ralloc_args_s hook_ralloc_args_t;
|
||||
struct hook_ralloc_args_s {
|
||||
/* I.e. as opposed to rallocx. */
|
||||
bool is_realloc;
|
||||
/*
|
||||
* The expand hook takes 4 arguments, even if only 3 are actually used;
|
||||
* we add an extra one in case the user decides to memcpy without
|
||||
* looking too closely at the hooked function.
|
||||
*/
|
||||
uintptr_t args[4];
|
||||
};
|
||||
|
||||
/*
|
||||
* Returns an opaque handle to be used when removing the hook. NULL means that
|
||||
* we couldn't install the hook.
|
||||
|
@ -1,6 +1,7 @@
|
||||
#ifndef JEMALLOC_INTERNAL_INLINES_C_H
|
||||
#define JEMALLOC_INTERNAL_INLINES_C_H
|
||||
|
||||
#include "jemalloc/internal/hook.h"
|
||||
#include "jemalloc/internal/jemalloc_internal_types.h"
|
||||
#include "jemalloc/internal/sz.h"
|
||||
#include "jemalloc/internal/witness.h"
|
||||
@ -133,31 +134,20 @@ isdalloct(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache,
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE void *
|
||||
iralloct_realign(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size,
|
||||
size_t extra, size_t alignment, bool zero, tcache_t *tcache,
|
||||
arena_t *arena) {
|
||||
size_t alignment, bool zero, tcache_t *tcache, arena_t *arena,
|
||||
hook_ralloc_args_t *hook_args) {
|
||||
witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
|
||||
WITNESS_RANK_CORE, 0);
|
||||
void *p;
|
||||
size_t usize, copysize;
|
||||
|
||||
usize = sz_sa2u(size + extra, alignment);
|
||||
usize = sz_sa2u(size, alignment);
|
||||
if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) {
|
||||
return NULL;
|
||||
}
|
||||
p = ipalloct(tsdn, usize, alignment, zero, tcache, arena);
|
||||
if (p == NULL) {
|
||||
if (extra == 0) {
|
||||
return NULL;
|
||||
}
|
||||
/* Try again, without extra this time. */
|
||||
usize = sz_sa2u(size, alignment);
|
||||
if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) {
|
||||
return NULL;
|
||||
}
|
||||
p = ipalloct(tsdn, usize, alignment, zero, tcache, arena);
|
||||
if (p == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
* Copy at most size bytes (not size+extra), since the caller has no
|
||||
@ -165,13 +155,26 @@ iralloct_realign(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size,
|
||||
*/
|
||||
copysize = (size < oldsize) ? size : oldsize;
|
||||
memcpy(p, ptr, copysize);
|
||||
hook_invoke_alloc(hook_args->is_realloc
|
||||
? hook_alloc_realloc : hook_alloc_rallocx, p, (uintptr_t)p,
|
||||
hook_args->args);
|
||||
hook_invoke_dalloc(hook_args->is_realloc
|
||||
? hook_dalloc_realloc : hook_dalloc_rallocx, ptr, hook_args->args);
|
||||
isdalloct(tsdn, ptr, oldsize, tcache, NULL, true);
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* is_realloc threads through the knowledge of whether or not this call comes
|
||||
* from je_realloc (as opposed to je_rallocx); this ensures that we pass the
|
||||
* correct entry point into any hooks.
|
||||
* Note that these functions are all force-inlined, so no actual bool gets
|
||||
* passed-around anywhere.
|
||||
*/
|
||||
JEMALLOC_ALWAYS_INLINE void *
|
||||
iralloct(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t alignment,
|
||||
bool zero, tcache_t *tcache, arena_t *arena) {
|
||||
bool zero, tcache_t *tcache, arena_t *arena, hook_ralloc_args_t *hook_args)
|
||||
{
|
||||
assert(ptr != NULL);
|
||||
assert(size != 0);
|
||||
witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
|
||||
@ -183,19 +186,19 @@ iralloct(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t alignment,
|
||||
* Existing object alignment is inadequate; allocate new space
|
||||
* and copy.
|
||||
*/
|
||||
return iralloct_realign(tsdn, ptr, oldsize, size, 0, alignment,
|
||||
zero, tcache, arena);
|
||||
return iralloct_realign(tsdn, ptr, oldsize, size, alignment,
|
||||
zero, tcache, arena, hook_args);
|
||||
}
|
||||
|
||||
return arena_ralloc(tsdn, arena, ptr, oldsize, size, alignment, zero,
|
||||
tcache);
|
||||
tcache, hook_args);
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE void *
|
||||
iralloc(tsd_t *tsd, void *ptr, size_t oldsize, size_t size, size_t alignment,
|
||||
bool zero) {
|
||||
bool zero, hook_ralloc_args_t *hook_args) {
|
||||
return iralloct(tsd_tsdn(tsd), ptr, oldsize, size, alignment, zero,
|
||||
tcache_get(tsd), NULL);
|
||||
tcache_get(tsd), NULL, hook_args);
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE bool
|
||||
|
@ -1,13 +1,16 @@
|
||||
#ifndef JEMALLOC_INTERNAL_LARGE_EXTERNS_H
|
||||
#define JEMALLOC_INTERNAL_LARGE_EXTERNS_H
|
||||
|
||||
#include "jemalloc/internal/hook.h"
|
||||
|
||||
void *large_malloc(tsdn_t *tsdn, arena_t *arena, size_t usize, bool zero);
|
||||
void *large_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment,
|
||||
bool zero);
|
||||
bool large_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, size_t usize_min,
|
||||
size_t usize_max, bool zero);
|
||||
void *large_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t usize,
|
||||
size_t alignment, bool zero, tcache_t *tcache);
|
||||
void *large_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t usize,
|
||||
size_t alignment, bool zero, tcache_t *tcache,
|
||||
hook_ralloc_args_t *hook_args);
|
||||
|
||||
typedef void (large_dalloc_junk_t)(void *, size_t);
|
||||
extern large_dalloc_junk_t *JET_MUTABLE large_dalloc_junk;
|
||||
|
18
src/arena.c
18
src/arena.c
@ -1630,7 +1630,8 @@ arena_ralloc_move_helper(tsdn_t *tsdn, arena_t *arena, size_t usize,
|
||||
|
||||
void *
|
||||
arena_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t oldsize,
|
||||
size_t size, size_t alignment, bool zero, tcache_t *tcache) {
|
||||
size_t size, size_t alignment, bool zero, tcache_t *tcache,
|
||||
hook_ralloc_args_t *hook_args) {
|
||||
size_t usize = sz_s2u(size);
|
||||
if (unlikely(usize == 0 || size > LARGE_MAXCLASS)) {
|
||||
return NULL;
|
||||
@ -1639,13 +1640,17 @@ arena_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t oldsize,
|
||||
if (likely(usize <= SMALL_MAXCLASS)) {
|
||||
/* Try to avoid moving the allocation. */
|
||||
if (!arena_ralloc_no_move(tsdn, ptr, oldsize, usize, 0, zero)) {
|
||||
hook_invoke_expand(hook_args->is_realloc
|
||||
? hook_expand_realloc : hook_expand_rallocx,
|
||||
ptr, oldsize, usize, (uintptr_t)ptr,
|
||||
hook_args->args);
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (oldsize >= LARGE_MINCLASS && usize >= LARGE_MINCLASS) {
|
||||
return large_ralloc(tsdn, arena, iealloc(tsdn, ptr), usize,
|
||||
alignment, zero, tcache);
|
||||
return large_ralloc(tsdn, arena, ptr, usize,
|
||||
alignment, zero, tcache, hook_args);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1658,11 +1663,16 @@ arena_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t oldsize,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hook_invoke_alloc(hook_args->is_realloc
|
||||
? hook_alloc_realloc : hook_alloc_rallocx, ret, (uintptr_t)ret,
|
||||
hook_args->args);
|
||||
hook_invoke_dalloc(hook_args->is_realloc
|
||||
? hook_dalloc_realloc : hook_dalloc_rallocx, ptr, hook_args->args);
|
||||
|
||||
/*
|
||||
* Junk/zero-filling were already done by
|
||||
* ipalloc()/arena_malloc().
|
||||
*/
|
||||
|
||||
size_t copysize = (usize < oldsize) ? usize : oldsize;
|
||||
memcpy(ret, ptr, copysize);
|
||||
isdalloct(tsdn, ptr, oldsize, tcache, NULL, true);
|
||||
|
@ -2169,20 +2169,22 @@ je_calloc(size_t num, size_t size) {
|
||||
|
||||
static void *
|
||||
irealloc_prof_sample(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t usize,
|
||||
prof_tctx_t *tctx) {
|
||||
prof_tctx_t *tctx, hook_ralloc_args_t *hook_args) {
|
||||
void *p;
|
||||
|
||||
if (tctx == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (usize <= SMALL_MAXCLASS) {
|
||||
p = iralloc(tsd, old_ptr, old_usize, LARGE_MINCLASS, 0, false);
|
||||
p = iralloc(tsd, old_ptr, old_usize, LARGE_MINCLASS, 0, false,
|
||||
hook_args);
|
||||
if (p == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
arena_prof_promote(tsd_tsdn(tsd), p, usize);
|
||||
} else {
|
||||
p = iralloc(tsd, old_ptr, old_usize, usize, 0, false);
|
||||
p = iralloc(tsd, old_ptr, old_usize, usize, 0, false,
|
||||
hook_args);
|
||||
}
|
||||
|
||||
return p;
|
||||
@ -2190,7 +2192,7 @@ irealloc_prof_sample(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t usize,
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE void *
|
||||
irealloc_prof(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t usize,
|
||||
alloc_ctx_t *alloc_ctx) {
|
||||
alloc_ctx_t *alloc_ctx, hook_ralloc_args_t *hook_args) {
|
||||
void *p;
|
||||
bool prof_active;
|
||||
prof_tctx_t *old_tctx, *tctx;
|
||||
@ -2199,9 +2201,11 @@ irealloc_prof(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t usize,
|
||||
old_tctx = prof_tctx_get(tsd_tsdn(tsd), old_ptr, alloc_ctx);
|
||||
tctx = prof_alloc_prep(tsd, usize, prof_active, true);
|
||||
if (unlikely((uintptr_t)tctx != (uintptr_t)1U)) {
|
||||
p = irealloc_prof_sample(tsd, old_ptr, old_usize, usize, tctx);
|
||||
p = irealloc_prof_sample(tsd, old_ptr, old_usize, usize, tctx,
|
||||
hook_args);
|
||||
} else {
|
||||
p = iralloc(tsd, old_ptr, old_usize, usize, 0, false);
|
||||
p = iralloc(tsd, old_ptr, old_usize, usize, 0, false,
|
||||
hook_args);
|
||||
}
|
||||
if (unlikely(p == NULL)) {
|
||||
prof_alloc_rollback(tsd, tctx, true);
|
||||
@ -2349,6 +2353,10 @@ je_realloc(void *ptr, size_t arg_size) {
|
||||
|
||||
check_entry_exit_locking(tsd_tsdn(tsd));
|
||||
|
||||
|
||||
hook_ralloc_args_t hook_args = {true, {(uintptr_t)ptr,
|
||||
(uintptr_t)arg_size, 0, 0}};
|
||||
|
||||
alloc_ctx_t alloc_ctx;
|
||||
rtree_ctx_t *rtree_ctx = tsd_rtree_ctx(tsd);
|
||||
rtree_szind_slab_read(tsd_tsdn(tsd), &extents_rtree, rtree_ctx,
|
||||
@ -2362,13 +2370,14 @@ je_realloc(void *ptr, size_t arg_size) {
|
||||
ret = NULL;
|
||||
} else {
|
||||
ret = irealloc_prof(tsd, ptr, old_usize, usize,
|
||||
&alloc_ctx);
|
||||
&alloc_ctx, &hook_args);
|
||||
}
|
||||
} else {
|
||||
if (config_stats) {
|
||||
usize = sz_s2u(size);
|
||||
}
|
||||
ret = iralloc(tsd, ptr, old_usize, size, 0, false);
|
||||
ret = iralloc(tsd, ptr, old_usize, size, 0, false,
|
||||
&hook_args);
|
||||
}
|
||||
tsdn = tsd_tsdn(tsd);
|
||||
} else {
|
||||
@ -2664,7 +2673,7 @@ je_mallocx(size_t size, int flags) {
|
||||
static void *
|
||||
irallocx_prof_sample(tsdn_t *tsdn, void *old_ptr, size_t old_usize,
|
||||
size_t usize, size_t alignment, bool zero, tcache_t *tcache, arena_t *arena,
|
||||
prof_tctx_t *tctx) {
|
||||
prof_tctx_t *tctx, hook_ralloc_args_t *hook_args) {
|
||||
void *p;
|
||||
|
||||
if (tctx == NULL) {
|
||||
@ -2672,14 +2681,14 @@ irallocx_prof_sample(tsdn_t *tsdn, void *old_ptr, size_t old_usize,
|
||||
}
|
||||
if (usize <= SMALL_MAXCLASS) {
|
||||
p = iralloct(tsdn, old_ptr, old_usize, LARGE_MINCLASS,
|
||||
alignment, zero, tcache, arena);
|
||||
alignment, zero, tcache, arena, hook_args);
|
||||
if (p == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
arena_prof_promote(tsdn, p, usize);
|
||||
} else {
|
||||
p = iralloct(tsdn, old_ptr, old_usize, usize, alignment, zero,
|
||||
tcache, arena);
|
||||
tcache, arena, hook_args);
|
||||
}
|
||||
|
||||
return p;
|
||||
@ -2688,7 +2697,7 @@ irallocx_prof_sample(tsdn_t *tsdn, void *old_ptr, size_t old_usize,
|
||||
JEMALLOC_ALWAYS_INLINE void *
|
||||
irallocx_prof(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t size,
|
||||
size_t alignment, size_t *usize, bool zero, tcache_t *tcache,
|
||||
arena_t *arena, alloc_ctx_t *alloc_ctx) {
|
||||
arena_t *arena, alloc_ctx_t *alloc_ctx, hook_ralloc_args_t *hook_args) {
|
||||
void *p;
|
||||
bool prof_active;
|
||||
prof_tctx_t *old_tctx, *tctx;
|
||||
@ -2698,10 +2707,10 @@ irallocx_prof(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t size,
|
||||
tctx = prof_alloc_prep(tsd, *usize, prof_active, false);
|
||||
if (unlikely((uintptr_t)tctx != (uintptr_t)1U)) {
|
||||
p = irallocx_prof_sample(tsd_tsdn(tsd), old_ptr, old_usize,
|
||||
*usize, alignment, zero, tcache, arena, tctx);
|
||||
*usize, alignment, zero, tcache, arena, tctx, hook_args);
|
||||
} else {
|
||||
p = iralloct(tsd_tsdn(tsd), old_ptr, old_usize, size, alignment,
|
||||
zero, tcache, arena);
|
||||
zero, tcache, arena, hook_args);
|
||||
}
|
||||
if (unlikely(p == NULL)) {
|
||||
prof_alloc_rollback(tsd, tctx, false);
|
||||
@ -2775,6 +2784,9 @@ je_rallocx(void *ptr, size_t size, int flags) {
|
||||
assert(alloc_ctx.szind != NSIZES);
|
||||
old_usize = sz_index2size(alloc_ctx.szind);
|
||||
assert(old_usize == isalloc(tsd_tsdn(tsd), ptr));
|
||||
|
||||
hook_ralloc_args_t hook_args = {false, {(uintptr_t)ptr, size, flags,
|
||||
0}};
|
||||
if (config_prof && opt_prof) {
|
||||
usize = (alignment == 0) ?
|
||||
sz_s2u(size) : sz_sa2u(size, alignment);
|
||||
@ -2782,13 +2794,13 @@ je_rallocx(void *ptr, size_t size, int flags) {
|
||||
goto label_oom;
|
||||
}
|
||||
p = irallocx_prof(tsd, ptr, old_usize, size, alignment, &usize,
|
||||
zero, tcache, arena, &alloc_ctx);
|
||||
zero, tcache, arena, &alloc_ctx, &hook_args);
|
||||
if (unlikely(p == NULL)) {
|
||||
goto label_oom;
|
||||
}
|
||||
} else {
|
||||
p = iralloct(tsd_tsdn(tsd), ptr, old_usize, size, alignment,
|
||||
zero, tcache, arena);
|
||||
zero, tcache, arena, &hook_args);
|
||||
if (unlikely(p == NULL)) {
|
||||
goto label_oom;
|
||||
}
|
||||
|
17
src/large.c
17
src/large.c
@ -270,10 +270,12 @@ large_ralloc_move_helper(tsdn_t *tsdn, arena_t *arena, size_t usize,
|
||||
}
|
||||
|
||||
void *
|
||||
large_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t usize,
|
||||
size_t alignment, bool zero, tcache_t *tcache) {
|
||||
size_t oldusize = extent_usize_get(extent);
|
||||
large_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t usize,
|
||||
size_t alignment, bool zero, tcache_t *tcache,
|
||||
hook_ralloc_args_t *hook_args) {
|
||||
extent_t *extent = iealloc(tsdn, ptr);
|
||||
|
||||
size_t oldusize = extent_usize_get(extent);
|
||||
/* The following should have been caught by callers. */
|
||||
assert(usize > 0 && usize <= LARGE_MAXCLASS);
|
||||
/* Both allocation sizes must be large to avoid a move. */
|
||||
@ -281,6 +283,9 @@ large_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t usize,
|
||||
|
||||
/* Try to avoid moving the allocation. */
|
||||
if (!large_ralloc_no_move(tsdn, extent, usize, usize, zero)) {
|
||||
hook_invoke_expand(hook_args->is_realloc
|
||||
? hook_expand_realloc : hook_expand_rallocx, ptr, oldusize,
|
||||
usize, (uintptr_t)ptr, hook_args->args);
|
||||
return extent_addr_get(extent);
|
||||
}
|
||||
|
||||
@ -295,6 +300,12 @@ large_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t usize,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hook_invoke_alloc(hook_args->is_realloc
|
||||
? hook_alloc_realloc : hook_alloc_rallocx, ret, (uintptr_t)ret,
|
||||
hook_args->args);
|
||||
hook_invoke_dalloc(hook_args->is_realloc
|
||||
? hook_dalloc_realloc : hook_dalloc_rallocx, ptr, hook_args->args);
|
||||
|
||||
size_t copysize = (usize < oldusize) ? usize : oldusize;
|
||||
memcpy(ret, extent_addr_get(extent), copysize);
|
||||
isdalloct(tsdn, extent_addr_get(extent), oldusize, tcache, NULL, true);
|
||||
|
113
test/unit/hook.c
113
test/unit/hook.c
@ -412,6 +412,115 @@ TEST_BEGIN(test_hooks_realloc_as_malloc_or_free) {
|
||||
}
|
||||
TEST_END
|
||||
|
||||
static void
|
||||
do_realloc_test(void *(*ralloc)(void *, size_t, int), int flags,
|
||||
int expand_type, int dalloc_type) {
|
||||
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;
|
||||
void *volatile ptr2;
|
||||
|
||||
/* Realloc in-place, small. */
|
||||
ptr = malloc(129);
|
||||
reset();
|
||||
ptr2 = ralloc(ptr, 130, flags);
|
||||
assert_ptr_eq(ptr, ptr2, "Small realloc moved");
|
||||
|
||||
assert_d_eq(call_count, 1, "Hook not called");
|
||||
assert_ptr_eq(arg_extra, (void *)123, "Wrong extra");
|
||||
assert_d_eq(arg_type, expand_type, "Wrong hook type");
|
||||
assert_ptr_eq(ptr, arg_address, "Wrong address");
|
||||
assert_u64_eq((uintptr_t)ptr, (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)130, arg_args_raw[1], "Wrong argument");
|
||||
free(ptr);
|
||||
|
||||
/*
|
||||
* Realloc in-place, large. Since we can't guarantee the large case
|
||||
* across all platforms, we stay resilient to moving results.
|
||||
*/
|
||||
ptr = malloc(2 * 1024 * 1024);
|
||||
free(ptr);
|
||||
ptr2 = malloc(1 * 1024 * 1024);
|
||||
reset();
|
||||
ptr = ralloc(ptr2, 2 * 1024 * 1024, flags);
|
||||
/* ptr is the new address, ptr2 is the old address. */
|
||||
if (ptr == ptr2) {
|
||||
assert_d_eq(call_count, 1, "Hook not called");
|
||||
assert_d_eq(arg_type, expand_type, "Wrong hook type");
|
||||
} else {
|
||||
assert_d_eq(call_count, 2, "Wrong hooks called");
|
||||
assert_ptr_eq(ptr, arg_result, "Wrong address");
|
||||
assert_d_eq(arg_type, dalloc_type, "Wrong hook type");
|
||||
}
|
||||
assert_ptr_eq(arg_extra, (void *)123, "Wrong extra");
|
||||
assert_ptr_eq(ptr2, arg_address, "Wrong address");
|
||||
assert_u64_eq((uintptr_t)ptr, (uintptr_t)arg_result_raw,
|
||||
"Wrong raw result");
|
||||
assert_u64_eq((uintptr_t)ptr2, arg_args_raw[0], "Wrong argument");
|
||||
assert_u64_eq((uintptr_t)2 * 1024 * 1024, arg_args_raw[1],
|
||||
"Wrong argument");
|
||||
free(ptr);
|
||||
|
||||
/* Realloc with move, small. */
|
||||
ptr = malloc(8);
|
||||
reset();
|
||||
ptr2 = ralloc(ptr, 128, flags);
|
||||
assert_ptr_ne(ptr, ptr2, "Small realloc didn't move");
|
||||
|
||||
assert_d_eq(call_count, 2, "Hook not called");
|
||||
assert_ptr_eq(arg_extra, (void *)123, "Wrong extra");
|
||||
assert_d_eq(arg_type, dalloc_type, "Wrong hook type");
|
||||
assert_ptr_eq(ptr, arg_address, "Wrong address");
|
||||
assert_ptr_eq(ptr2, arg_result, "Wrong address");
|
||||
assert_u64_eq((uintptr_t)ptr2, (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)128, arg_args_raw[1], "Wrong argument");
|
||||
free(ptr2);
|
||||
|
||||
/* Realloc with move, large. */
|
||||
ptr = malloc(1);
|
||||
reset();
|
||||
ptr2 = ralloc(ptr, 2 * 1024 * 1024, flags);
|
||||
assert_ptr_ne(ptr, ptr2, "Large realloc didn't move");
|
||||
|
||||
assert_d_eq(call_count, 2, "Hook not called");
|
||||
assert_ptr_eq(arg_extra, (void *)123, "Wrong extra");
|
||||
assert_d_eq(arg_type, dalloc_type, "Wrong hook type");
|
||||
assert_ptr_eq(ptr, arg_address, "Wrong address");
|
||||
assert_ptr_eq(ptr2, arg_result, "Wrong address");
|
||||
assert_u64_eq((uintptr_t)ptr2, (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)2 * 1024 * 1024, arg_args_raw[1],
|
||||
"Wrong argument");
|
||||
free(ptr2);
|
||||
|
||||
hook_remove(TSDN_NULL, handle);
|
||||
}
|
||||
|
||||
static void *
|
||||
realloc_wrapper(void *ptr, size_t size, UNUSED int flags) {
|
||||
return realloc(ptr, size);
|
||||
}
|
||||
|
||||
TEST_BEGIN(test_hooks_realloc) {
|
||||
do_realloc_test(&realloc_wrapper, 0, hook_expand_realloc,
|
||||
hook_dalloc_realloc);
|
||||
}
|
||||
TEST_END
|
||||
|
||||
TEST_BEGIN(test_hooks_rallocx) {
|
||||
do_realloc_test(&rallocx, MALLOCX_TCACHE_NONE, hook_expand_rallocx,
|
||||
hook_dalloc_rallocx);
|
||||
}
|
||||
TEST_END
|
||||
|
||||
int
|
||||
main(void) {
|
||||
/* We assert on call counts. */
|
||||
@ -422,5 +531,7 @@ main(void) {
|
||||
test_hooks_alloc_simple,
|
||||
test_hooks_dalloc_simple,
|
||||
test_hooks_expand_simple,
|
||||
test_hooks_realloc_as_malloc_or_free);
|
||||
test_hooks_realloc_as_malloc_or_free,
|
||||
test_hooks_realloc,
|
||||
test_hooks_rallocx);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user