San: Unguard guarded slabs during arena destruction
When opt_retain is on, slab extents remain guarded in all states, even retained. This works well if arena is never destroyed, because we anticipate those slabs will be eventually reused. But if the arena is destroyed, the slabs must be unguarded to prevent leaking guard pages.
This commit is contained in:
parent
b6a7a535b3
commit
6cb585b13a
@ -14,7 +14,14 @@ extern size_t opt_san_guard_large;
|
|||||||
extern size_t opt_san_guard_small;
|
extern size_t opt_san_guard_small;
|
||||||
|
|
||||||
void guard_pages(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata, emap_t *emap);
|
void guard_pages(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata, emap_t *emap);
|
||||||
void unguard_pages(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata, emap_t *emap);
|
void unguard_pages(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata,
|
||||||
|
emap_t *emap);
|
||||||
|
/*
|
||||||
|
* Unguard the extent, but don't modify emap boundaries. Must be called on an
|
||||||
|
* extent that has been erased from emap and shouldn't be placed back.
|
||||||
|
*/
|
||||||
|
void unguard_pages_pre_destroy(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata,
|
||||||
|
emap_t *emap);
|
||||||
void tsd_san_init(tsd_t *tsd);
|
void tsd_san_init(tsd_t *tsd);
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
|
@ -1057,12 +1057,14 @@ extent_destroy_wrapper(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
|
|||||||
edata_t *edata) {
|
edata_t *edata) {
|
||||||
assert(edata_base_get(edata) != NULL);
|
assert(edata_base_get(edata) != NULL);
|
||||||
assert(edata_size_get(edata) != 0);
|
assert(edata_size_get(edata) != 0);
|
||||||
|
assert(edata_state_get(edata) == extent_state_retained);
|
||||||
|
assert(emap_edata_is_acquired(tsdn, pac->emap, edata));
|
||||||
witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
|
witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
|
||||||
WITNESS_RANK_CORE, 0);
|
WITNESS_RANK_CORE, 0);
|
||||||
|
|
||||||
/* Deregister first to avoid a race with other allocating threads. */
|
if (edata_guarded_get(edata)) {
|
||||||
extent_deregister(tsdn, pac, edata);
|
unguard_pages_pre_destroy(tsdn, ehooks, edata, pac->emap);
|
||||||
|
}
|
||||||
edata_addr_set(edata, edata_base_get(edata));
|
edata_addr_set(edata, edata_base_get(edata));
|
||||||
|
|
||||||
/* Try to destroy; silently fail otherwise. */
|
/* Try to destroy; silently fail otherwise. */
|
||||||
|
33
src/guard.c
33
src/guard.c
@ -32,10 +32,16 @@ guard_pages(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata, emap_t *emap) {
|
|||||||
/* The new boundary will be registered on the pa_alloc path. */
|
/* The new boundary will be registered on the pa_alloc path. */
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
unguard_pages(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata, emap_t *emap) {
|
unguard_pages_impl(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata, emap_t *emap,
|
||||||
|
bool reg_emap) {
|
||||||
/* Remove the inner boundary which no longer exists. */
|
/* Remove the inner boundary which no longer exists. */
|
||||||
|
if (reg_emap) {
|
||||||
|
assert(edata_state_get(edata) == extent_state_active);
|
||||||
emap_deregister_boundary(tsdn, emap, edata);
|
emap_deregister_boundary(tsdn, emap, edata);
|
||||||
|
} else {
|
||||||
|
assert(edata_state_get(edata) == extent_state_retained);
|
||||||
|
}
|
||||||
|
|
||||||
size_t size = edata_size_get(edata);
|
size_t size = edata_size_get(edata);
|
||||||
size_t size_with_guards = size + PAGE_GUARDS_SIZE;
|
size_t size_with_guards = size + PAGE_GUARDS_SIZE;
|
||||||
@ -44,7 +50,6 @@ unguard_pages(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata, emap_t *emap) {
|
|||||||
uintptr_t guard1 = addr - PAGE;
|
uintptr_t guard1 = addr - PAGE;
|
||||||
uintptr_t guard2 = addr + size;
|
uintptr_t guard2 = addr + size;
|
||||||
|
|
||||||
assert(edata_state_get(edata) == extent_state_active);
|
|
||||||
ehooks_unguard(tsdn, ehooks, (void *)guard1, (void *)guard2);
|
ehooks_unguard(tsdn, ehooks, (void *)guard1, (void *)guard2);
|
||||||
|
|
||||||
/* Update the true addr and usable size of the edata. */
|
/* Update the true addr and usable size of the edata. */
|
||||||
@ -52,8 +57,26 @@ unguard_pages(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata, emap_t *emap) {
|
|||||||
edata_addr_set(edata, (void *)guard1);
|
edata_addr_set(edata, (void *)guard1);
|
||||||
edata_guarded_set(edata, false);
|
edata_guarded_set(edata, false);
|
||||||
|
|
||||||
/* Then re-register the outer boundary including the guards. */
|
/*
|
||||||
emap_register_boundary(tsdn, emap, edata, SC_NSIZES, /* slab */ false);
|
* Then re-register the outer boundary including the guards, if
|
||||||
|
* requested.
|
||||||
|
*/
|
||||||
|
if (reg_emap) {
|
||||||
|
emap_register_boundary(tsdn, emap, edata, SC_NSIZES,
|
||||||
|
/* slab */ false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
unguard_pages(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata, emap_t *emap) {
|
||||||
|
unguard_pages_impl(tsdn, ehooks, edata, emap, /* reg_emap */ true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
unguard_pages_pre_destroy(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata,
|
||||||
|
emap_t *emap) {
|
||||||
|
emap_assert_not_mapped(tsdn, emap, edata);
|
||||||
|
unguard_pages_impl(tsdn, ehooks, edata, emap, /* reg_emap */ false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
Loading…
Reference in New Issue
Block a user