mirror of
https://github.com/jemalloc/jemalloc.git
synced 2026-05-24 13:56:23 +03:00
Change structs use when freeing to avoid using index2size for large sizes.
1. Change the definition of emap_alloc_ctx_t 2. Change the read of both from edata_t. 3. Change the assignment and usage of emap_alloc_ctx_t. 4. Change other callsites of index2size. Note for the changes in the data structure, i.e., emap_alloc_ctx_t, will be used when the build-time config (--enable-limit-usize-gap) is enabled but they will store the same value as index2size(szind) if the runtime option (opt_limit_usize_gap) is not enabled.
This commit is contained in:
parent
96b15d5d43
commit
d01d5b8f4a
9 changed files with 167 additions and 42 deletions
|
|
@ -51,7 +51,7 @@ arena_choose_maybe_huge(tsd_t *tsd, arena_t *arena, size_t size) {
|
|||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE bool
|
||||
large_dalloc_safety_checks(edata_t *edata, const void *ptr, szind_t szind) {
|
||||
large_dalloc_safety_checks(edata_t *edata, const void *ptr, size_t input_size) {
|
||||
if (!config_opt_safety_checks) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -68,7 +68,6 @@ large_dalloc_safety_checks(edata_t *edata, const void *ptr, szind_t szind) {
|
|||
"possibly caused by double free bugs.", ptr);
|
||||
return true;
|
||||
}
|
||||
size_t input_size = sz_index2size(szind);
|
||||
if (unlikely(input_size != edata_usize_get(edata))) {
|
||||
safety_check_fail_sized_dealloc(/* current_dealloc */ true, ptr,
|
||||
/* true_size */ edata_usize_get(edata), input_size);
|
||||
|
|
@ -101,9 +100,10 @@ arena_prof_info_get(tsd_t *tsd, const void *ptr, emap_alloc_ctx_t *alloc_ctx,
|
|||
if (unlikely(!is_slab)) {
|
||||
/* edata must have been initialized at this point. */
|
||||
assert(edata != NULL);
|
||||
size_t usize = (alloc_ctx == NULL)? edata_usize_get(edata):
|
||||
emap_alloc_ctx_usize_get(alloc_ctx);
|
||||
if (reset_recent &&
|
||||
large_dalloc_safety_checks(edata, ptr,
|
||||
edata_szind_get(edata))) {
|
||||
large_dalloc_safety_checks(edata, ptr, usize)) {
|
||||
prof_info->alloc_tctx = PROF_TCTX_SENTINEL;
|
||||
return;
|
||||
}
|
||||
|
|
@ -225,7 +225,7 @@ arena_salloc(tsdn_t *tsdn, const void *ptr) {
|
|||
emap_alloc_ctx_lookup(tsdn, &arena_emap_global, ptr, &alloc_ctx);
|
||||
assert(alloc_ctx.szind != SC_NSIZES);
|
||||
|
||||
return sz_index2size(alloc_ctx.szind);
|
||||
return emap_alloc_ctx_usize_get(&alloc_ctx);
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE size_t
|
||||
|
|
@ -256,17 +256,19 @@ arena_vsalloc(tsdn_t *tsdn, const void *ptr) {
|
|||
|
||||
assert(full_alloc_ctx.szind != SC_NSIZES);
|
||||
|
||||
return sz_index2size(full_alloc_ctx.szind);
|
||||
return config_limit_usize_gap? edata_usize_get(full_alloc_ctx.edata):
|
||||
sz_index2size(full_alloc_ctx.szind);
|
||||
}
|
||||
|
||||
static inline void
|
||||
arena_dalloc_large_no_tcache(tsdn_t *tsdn, void *ptr, szind_t szind) {
|
||||
arena_dalloc_large_no_tcache(tsdn_t *tsdn, void *ptr, szind_t szind,
|
||||
size_t usize) {
|
||||
if (config_prof && unlikely(szind < SC_NBINS)) {
|
||||
arena_dalloc_promoted(tsdn, ptr, NULL, true);
|
||||
} else {
|
||||
edata_t *edata = emap_edata_lookup(tsdn, &arena_emap_global,
|
||||
ptr);
|
||||
if (large_dalloc_safety_checks(edata, ptr, szind)) {
|
||||
if (large_dalloc_safety_checks(edata, ptr, usize)) {
|
||||
/* See the comment in isfree. */
|
||||
return;
|
||||
}
|
||||
|
|
@ -287,19 +289,22 @@ arena_dalloc_no_tcache(tsdn_t *tsdn, void *ptr) {
|
|||
assert(alloc_ctx.szind == edata_szind_get(edata));
|
||||
assert(alloc_ctx.szind < SC_NSIZES);
|
||||
assert(alloc_ctx.slab == edata_slab_get(edata));
|
||||
assert(emap_alloc_ctx_usize_get(&alloc_ctx) ==
|
||||
edata_usize_get(edata));
|
||||
}
|
||||
|
||||
if (likely(alloc_ctx.slab)) {
|
||||
/* Small allocation. */
|
||||
arena_dalloc_small(tsdn, ptr);
|
||||
} else {
|
||||
arena_dalloc_large_no_tcache(tsdn, ptr, alloc_ctx.szind);
|
||||
arena_dalloc_large_no_tcache(tsdn, ptr, alloc_ctx.szind,
|
||||
emap_alloc_ctx_usize_get(&alloc_ctx));
|
||||
}
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE void
|
||||
arena_dalloc_large(tsdn_t *tsdn, void *ptr, tcache_t *tcache, szind_t szind,
|
||||
bool slow_path) {
|
||||
size_t usize, bool slow_path) {
|
||||
assert (!tsdn_null(tsdn) && tcache != NULL);
|
||||
bool is_sample_promoted = config_prof && szind < SC_NBINS;
|
||||
if (unlikely(is_sample_promoted)) {
|
||||
|
|
@ -313,7 +318,7 @@ arena_dalloc_large(tsdn_t *tsdn, void *ptr, tcache_t *tcache, szind_t szind,
|
|||
} else {
|
||||
edata_t *edata = emap_edata_lookup(tsdn,
|
||||
&arena_emap_global, ptr);
|
||||
if (large_dalloc_safety_checks(edata, ptr, szind)) {
|
||||
if (large_dalloc_safety_checks(edata, ptr, usize)) {
|
||||
/* See the comment in isfree. */
|
||||
return;
|
||||
}
|
||||
|
|
@ -396,6 +401,8 @@ arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache,
|
|||
assert(alloc_ctx.szind == edata_szind_get(edata));
|
||||
assert(alloc_ctx.szind < SC_NSIZES);
|
||||
assert(alloc_ctx.slab == edata_slab_get(edata));
|
||||
assert(emap_alloc_ctx_usize_get(&alloc_ctx) ==
|
||||
edata_usize_get(edata));
|
||||
}
|
||||
|
||||
if (likely(alloc_ctx.slab)) {
|
||||
|
|
@ -407,7 +414,7 @@ arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache,
|
|||
alloc_ctx.szind, slow_path);
|
||||
} else {
|
||||
arena_dalloc_large(tsdn, ptr, tcache, alloc_ctx.szind,
|
||||
slow_path);
|
||||
emap_alloc_ctx_usize_get(&alloc_ctx), slow_path);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -422,8 +429,9 @@ arena_sdalloc_no_tcache(tsdn_t *tsdn, void *ptr, size_t size) {
|
|||
* There is no risk of being confused by a promoted sampled
|
||||
* object, so base szind and slab on the given size.
|
||||
*/
|
||||
alloc_ctx.szind = sz_size2index(size);
|
||||
alloc_ctx.slab = (alloc_ctx.szind < SC_NBINS);
|
||||
szind_t szind = sz_size2index(size);
|
||||
emap_alloc_ctx_set(&alloc_ctx, szind, (szind < SC_NBINS),
|
||||
size);
|
||||
}
|
||||
|
||||
if ((config_prof && opt_prof) || config_debug) {
|
||||
|
|
@ -446,7 +454,8 @@ arena_sdalloc_no_tcache(tsdn_t *tsdn, void *ptr, size_t size) {
|
|||
/* Small allocation. */
|
||||
arena_dalloc_small(tsdn, ptr);
|
||||
} else {
|
||||
arena_dalloc_large_no_tcache(tsdn, ptr, alloc_ctx.szind);
|
||||
arena_dalloc_large_no_tcache(tsdn, ptr, alloc_ctx.szind,
|
||||
emap_alloc_ctx_usize_get(&alloc_ctx));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -469,6 +478,7 @@ arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache,
|
|||
emap_alloc_ctx_lookup(tsdn, &arena_emap_global, ptr,
|
||||
&alloc_ctx);
|
||||
assert(alloc_ctx.szind == sz_size2index(size));
|
||||
assert(emap_alloc_ctx_usize_get(&alloc_ctx) == size);
|
||||
} else {
|
||||
alloc_ctx = *caller_alloc_ctx;
|
||||
}
|
||||
|
|
@ -486,6 +496,11 @@ arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache,
|
|||
ptr);
|
||||
assert(alloc_ctx.szind == edata_szind_get(edata));
|
||||
assert(alloc_ctx.slab == edata_slab_get(edata));
|
||||
emap_alloc_ctx_set(&alloc_ctx, alloc_ctx.szind, alloc_ctx.slab,
|
||||
sz_s2u(size));
|
||||
assert(!config_limit_usize_gap ||
|
||||
emap_alloc_ctx_usize_get(&alloc_ctx) ==
|
||||
edata_usize_get(edata));
|
||||
}
|
||||
|
||||
if (likely(alloc_ctx.slab)) {
|
||||
|
|
@ -496,8 +511,10 @@ arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache,
|
|||
tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr,
|
||||
alloc_ctx.szind, slow_path);
|
||||
} else {
|
||||
emap_alloc_ctx_set(&alloc_ctx, alloc_ctx.szind, alloc_ctx.slab,
|
||||
sz_s2u(size));
|
||||
arena_dalloc_large(tsdn, ptr, tcache, alloc_ctx.szind,
|
||||
slow_path);
|
||||
emap_alloc_ctx_usize_get(&alloc_ctx), slow_path);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -288,10 +288,53 @@ edata_szind_get(const edata_t *edata) {
|
|||
}
|
||||
|
||||
static inline size_t
|
||||
edata_usize_get(const edata_t *edata) {
|
||||
edata_usize_get_from_ind_unsafe(const edata_t *edata) {
|
||||
return sz_index2size(edata_szind_get(edata));
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
edata_usize_get_from_ind(const edata_t *edata) {
|
||||
size_t usize = edata_usize_get_from_ind_unsafe(edata);
|
||||
assert(!sz_limit_usize_gap_enabled() || usize < SC_LARGE_MINCLASS);
|
||||
return usize;
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
edata_usize_get_from_size(const edata_t *edata) {
|
||||
size_t size = (edata->e_size_esn & EDATA_SIZE_MASK);
|
||||
assert(size > sz_large_pad);
|
||||
size_t usize = size - sz_large_pad;
|
||||
/*
|
||||
* No matter limit-usize-gap enabled or not, usize retrieved here is
|
||||
* not accurate when smaller than SC_LAGE_MINCLASS.
|
||||
*/
|
||||
assert(usize >= SC_LARGE_MINCLASS);
|
||||
return usize;
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
edata_usize_get(const edata_t *edata) {
|
||||
/*
|
||||
* When sz_limit_usize_gap_enabled() is true, two cases:
|
||||
* 1. if usize_from_ind is not smaller than SC_LARGE_MINCLASS,
|
||||
* usize_from_size is accurate;
|
||||
* 2. otherwise, usize_from_ind is accurate.
|
||||
*
|
||||
* When sz_limit_usize_gap_enabled() is not true, the two should be the
|
||||
* same when usize_from_ind is not smaller than SC_LARGE_MINCLASS.
|
||||
*/
|
||||
size_t usize_from_ind = edata_usize_get_from_ind_unsafe(edata);
|
||||
if (!sz_limit_usize_gap_enabled() ||
|
||||
usize_from_ind < SC_LARGE_MINCLASS) {
|
||||
assert(sz_limit_usize_gap_enabled() ||
|
||||
usize_from_ind < SC_LARGE_MINCLASS ||
|
||||
usize_from_ind == edata_usize_get_from_size(edata));
|
||||
return usize_from_ind;
|
||||
}
|
||||
|
||||
return edata_usize_get_from_size(edata);
|
||||
}
|
||||
|
||||
static inline unsigned
|
||||
edata_binshard_get(const edata_t *edata) {
|
||||
unsigned binshard = (unsigned)((edata->e_bits &
|
||||
|
|
|
|||
|
|
@ -20,10 +20,11 @@ struct emap_s {
|
|||
};
|
||||
|
||||
/* Used to pass rtree lookup context down the path. */
|
||||
typedef struct emap_alloc_ctx_t emap_alloc_ctx_t;
|
||||
struct emap_alloc_ctx_t {
|
||||
typedef struct emap_alloc_ctx_s emap_alloc_ctx_t;
|
||||
struct emap_alloc_ctx_s {
|
||||
szind_t szind;
|
||||
bool slab;
|
||||
size_t usize;
|
||||
};
|
||||
|
||||
typedef struct emap_full_alloc_ctx_s emap_full_alloc_ctx_t;
|
||||
|
|
@ -230,16 +231,53 @@ emap_edata_lookup(tsdn_t *tsdn, emap_t *emap, const void *ptr) {
|
|||
return rtree_read(tsdn, &emap->rtree, rtree_ctx, (uintptr_t)ptr).edata;
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE void
|
||||
emap_alloc_ctx_set(emap_alloc_ctx_t *alloc_ctx, szind_t szind, bool slab,
|
||||
size_t usize) {
|
||||
alloc_ctx->szind = szind;
|
||||
alloc_ctx->slab = slab;
|
||||
/*
|
||||
* When config_limit_usize_gap disabled, alloc_ctx->usize
|
||||
* should not be accessed.
|
||||
*/
|
||||
if (config_limit_usize_gap) {
|
||||
alloc_ctx->usize = usize;
|
||||
assert(sz_limit_usize_gap_enabled() ||
|
||||
usize == sz_index2size(szind));
|
||||
}
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE size_t
|
||||
emap_alloc_ctx_usize_get(emap_alloc_ctx_t *alloc_ctx) {
|
||||
assert(alloc_ctx->szind < SC_NSIZES);
|
||||
if (alloc_ctx->slab || !config_limit_usize_gap) {
|
||||
assert(!config_limit_usize_gap ||
|
||||
alloc_ctx->usize == sz_index2size(alloc_ctx->szind));
|
||||
return sz_index2size(alloc_ctx->szind);
|
||||
}
|
||||
assert(sz_limit_usize_gap_enabled() ||
|
||||
alloc_ctx->usize == sz_index2size(alloc_ctx->szind));
|
||||
return alloc_ctx->usize;
|
||||
}
|
||||
|
||||
/* Fills in alloc_ctx with the info in the map. */
|
||||
JEMALLOC_ALWAYS_INLINE void
|
||||
emap_alloc_ctx_lookup(tsdn_t *tsdn, emap_t *emap, const void *ptr,
|
||||
emap_alloc_ctx_t *alloc_ctx) {
|
||||
EMAP_DECLARE_RTREE_CTX;
|
||||
|
||||
rtree_metadata_t metadata = rtree_metadata_read(tsdn, &emap->rtree,
|
||||
rtree_ctx, (uintptr_t)ptr);
|
||||
alloc_ctx->szind = metadata.szind;
|
||||
alloc_ctx->slab = metadata.slab;
|
||||
if (config_limit_usize_gap) {
|
||||
rtree_contents_t contents = rtree_read(tsdn, &emap->rtree,
|
||||
rtree_ctx, (uintptr_t)ptr);
|
||||
assert(contents.edata != NULL);
|
||||
emap_alloc_ctx_set(alloc_ctx, contents.metadata.szind,
|
||||
contents.metadata.slab, edata_usize_get(contents.edata));
|
||||
} else {
|
||||
rtree_metadata_t metadata = rtree_metadata_read(tsdn,
|
||||
&emap->rtree, rtree_ctx, (uintptr_t)ptr);
|
||||
/* alloc_ctx->usize will not be read/write in this case. */
|
||||
emap_alloc_ctx_set(alloc_ctx, metadata.szind, metadata.slab, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* The pointer must be mapped. */
|
||||
|
|
@ -293,6 +331,10 @@ emap_alloc_ctx_try_lookup_fast(tsd_t *tsd, emap_t *emap, const void *ptr,
|
|||
if (err) {
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
* Small allocs using the fastpath can always use index to get the
|
||||
* usize. Therefore, do not set alloc_ctx->usize here.
|
||||
*/
|
||||
alloc_ctx->szind = metadata.szind;
|
||||
alloc_ctx->slab = metadata.slab;
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -425,8 +425,9 @@ maybe_check_alloc_ctx(tsd_t *tsd, void *ptr, emap_alloc_ctx_t *alloc_ctx) {
|
|||
if (alloc_ctx->szind != dbg_ctx.szind) {
|
||||
safety_check_fail_sized_dealloc(
|
||||
/* current_dealloc */ true, ptr,
|
||||
/* true_size */ sz_index2size(dbg_ctx.szind),
|
||||
/* input_size */ sz_index2size(alloc_ctx->szind));
|
||||
/* true_size */ emap_alloc_ctx_usize_get(&dbg_ctx),
|
||||
/* input_size */ emap_alloc_ctx_usize_get(
|
||||
alloc_ctx));
|
||||
return true;
|
||||
}
|
||||
if (alloc_ctx->slab != dbg_ctx.slab) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue