Fix a prof-related race condition.

Fix prof_lookup() to artificially raise curobjs for all paths through
the code that creates a new entry in the per thread bt2cnt hash table.
This fixes a race condition that could corrupt memory if prof_accum were
false, and a non-default lg_prof_tcmax were used and/or threads were
destroyed.
This commit is contained in:
Jason Evans 2011-08-30 23:40:11 -07:00
parent 46405e670f
commit a9076c9483

View File

@ -474,11 +474,23 @@ prof_lookup(prof_bt_t *bt)
/* /*
* Artificially raise curobjs, in order to avoid a race * Artificially raise curobjs, in order to avoid a race
* condition with prof_ctx_merge()/prof_ctx_destroy(). * condition with prof_ctx_merge()/prof_ctx_destroy().
*
* No locking is necessary for ctx here because no other
* threads have had the opportunity to fetch it from
* bt2ctx yet.
*/ */
ctx.p->cnt_merged.curobjs++; ctx.p->cnt_merged.curobjs++;
new_ctx = true; new_ctx = true;
} else } else {
/*
* Artificially raise curobjs, in order to avoid a race
* condition with prof_ctx_merge()/prof_ctx_destroy().
*/
malloc_mutex_lock(&ctx.p->lock);
ctx.p->cnt_merged.curobjs++;
malloc_mutex_unlock(&ctx.p->lock);
new_ctx = false; new_ctx = false;
}
prof_leave(); prof_leave();
/* Link a prof_thd_cnt_t into ctx for this thread. */ /* Link a prof_thd_cnt_t into ctx for this thread. */
@ -491,8 +503,9 @@ prof_lookup(prof_bt_t *bt)
*/ */
ret.p = ql_last(&prof_tdata->lru_ql, lru_link); ret.p = ql_last(&prof_tdata->lru_ql, lru_link);
assert(ret.v != NULL); assert(ret.v != NULL);
ckh_remove(&prof_tdata->bt2cnt, ret.p->ctx->bt, NULL, if (ckh_remove(&prof_tdata->bt2cnt, ret.p->ctx->bt,
NULL); NULL, NULL))
assert(false);
ql_remove(&prof_tdata->lru_ql, ret.p, lru_link); ql_remove(&prof_tdata->lru_ql, ret.p, lru_link);
prof_ctx_merge(ret.p->ctx, ret.p); prof_ctx_merge(ret.p->ctx, ret.p);
/* ret can now be re-used. */ /* ret can now be re-used. */
@ -523,7 +536,6 @@ prof_lookup(prof_bt_t *bt)
ql_head_insert(&prof_tdata->lru_ql, ret.p, lru_link); ql_head_insert(&prof_tdata->lru_ql, ret.p, lru_link);
malloc_mutex_lock(&ctx.p->lock); malloc_mutex_lock(&ctx.p->lock);
ql_tail_insert(&ctx.p->cnts_ql, ret.p, cnts_link); ql_tail_insert(&ctx.p->cnts_ql, ret.p, cnts_link);
if (new_ctx)
ctx.p->cnt_merged.curobjs--; ctx.p->cnt_merged.curobjs--;
malloc_mutex_unlock(&ctx.p->lock); malloc_mutex_unlock(&ctx.p->lock);
} else { } else {
@ -650,7 +662,8 @@ prof_ctx_destroy(prof_ctx_t *ctx)
assert(ctx->cnt_merged.accumobjs == 0); assert(ctx->cnt_merged.accumobjs == 0);
assert(ctx->cnt_merged.accumbytes == 0); assert(ctx->cnt_merged.accumbytes == 0);
/* Remove ctx from bt2ctx. */ /* Remove ctx from bt2ctx. */
ckh_remove(&bt2ctx, ctx->bt, NULL, NULL); if (ckh_remove(&bt2ctx, ctx->bt, NULL, NULL))
assert(false);
prof_leave(); prof_leave();
/* Destroy ctx. */ /* Destroy ctx. */
malloc_mutex_unlock(&ctx->lock); malloc_mutex_unlock(&ctx->lock);