Tcaches: Fix a subtle race condition.
Without a lock held continuously between checking tcaches_past and incrementing it, it's possible for two threads to go down manual creation path simultaneously. If the number of tcaches is one less than the maximum, it's possible for both to create a tcache and increment tcaches_past, with the second thread returning a value larger than TCACHES_MAX.
This commit is contained in:
parent
a9aa6f6d0f
commit
be9548f2be
@ -767,7 +767,7 @@ static bool
|
|||||||
tcaches_create_prep(tsd_t *tsd, base_t *base) {
|
tcaches_create_prep(tsd_t *tsd, base_t *base) {
|
||||||
bool err;
|
bool err;
|
||||||
|
|
||||||
malloc_mutex_lock(tsd_tsdn(tsd), &tcaches_mtx);
|
malloc_mutex_assert_owner(tsd_tsdn(tsd), &tcaches_mtx);
|
||||||
|
|
||||||
if (tcaches == NULL) {
|
if (tcaches == NULL) {
|
||||||
tcaches = base_alloc(tsd_tsdn(tsd), base,
|
tcaches = base_alloc(tsd_tsdn(tsd), base,
|
||||||
@ -785,7 +785,6 @@ tcaches_create_prep(tsd_t *tsd, base_t *base) {
|
|||||||
|
|
||||||
err = false;
|
err = false;
|
||||||
label_return:
|
label_return:
|
||||||
malloc_mutex_unlock(tsd_tsdn(tsd), &tcaches_mtx);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -795,6 +794,8 @@ tcaches_create(tsd_t *tsd, base_t *base, unsigned *r_ind) {
|
|||||||
|
|
||||||
bool err;
|
bool err;
|
||||||
|
|
||||||
|
malloc_mutex_lock(tsd_tsdn(tsd), &tcaches_mtx);
|
||||||
|
|
||||||
if (tcaches_create_prep(tsd, base)) {
|
if (tcaches_create_prep(tsd, base)) {
|
||||||
err = true;
|
err = true;
|
||||||
goto label_return;
|
goto label_return;
|
||||||
@ -807,7 +808,6 @@ tcaches_create(tsd_t *tsd, base_t *base, unsigned *r_ind) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tcaches_t *elm;
|
tcaches_t *elm;
|
||||||
malloc_mutex_lock(tsd_tsdn(tsd), &tcaches_mtx);
|
|
||||||
if (tcaches_avail != NULL) {
|
if (tcaches_avail != NULL) {
|
||||||
elm = tcaches_avail;
|
elm = tcaches_avail;
|
||||||
tcaches_avail = tcaches_avail->next;
|
tcaches_avail = tcaches_avail->next;
|
||||||
@ -819,10 +819,10 @@ tcaches_create(tsd_t *tsd, base_t *base, unsigned *r_ind) {
|
|||||||
*r_ind = tcaches_past;
|
*r_ind = tcaches_past;
|
||||||
tcaches_past++;
|
tcaches_past++;
|
||||||
}
|
}
|
||||||
malloc_mutex_unlock(tsd_tsdn(tsd), &tcaches_mtx);
|
|
||||||
|
|
||||||
err = false;
|
err = false;
|
||||||
label_return:
|
label_return:
|
||||||
|
malloc_mutex_unlock(tsd_tsdn(tsd), &tcaches_mtx);
|
||||||
witness_assert_depth(tsdn_witness_tsdp_get(tsd_tsdn(tsd)), 0);
|
witness_assert_depth(tsdn_witness_tsdp_get(tsd_tsdn(tsd)), 0);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user