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:
guangli-dai 2024-04-01 16:49:34 -07:00 committed by Guangli Dai
parent 96b15d5d43
commit d01d5b8f4a
9 changed files with 167 additions and 42 deletions

View file

@ -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);
}
}

View file

@ -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 &

View file

@ -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;

View file

@ -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) {