diff options
author | Vlad Lesin <vlad_lesin@mail.ru> | 2023-05-12 12:11:53 +0300 |
---|---|---|
committer | Vlad Lesin <vlad_lesin@mail.ru> | 2023-05-17 10:43:20 +0300 |
commit | 208e7528d5448237ad3246741ea98978959529f3 (patch) | |
tree | f42cce0dd7e536f94a6fe65ffe0def88578e72c2 /mysys/lf_alloc-pin.c | |
parent | 956d6c4af9e353299cce6d2ccbd7c400a1d00d70 (diff) | |
download | mariadb-git-bb-10.4-MDEV-31185-pins.tar.gz |
MDEV-31185 rw_trx_hash_t::find() unpins pins too earlybb-10.4-MDEV-31185-pins
rw_trx_hash_t::find() acquires element->mutex, then unpins pins, used for
lf_hash element search. After that the "element" can be deallocated and
reused by some other thread.
If we take a look rw_trx_hash_t::insert()->lf_hash_insert()->lf_alloc_new()
calls, we will not find any element->mutex acquisition, as it was not
initialized yet before it's allocation. rw_trx_hash_t::insert() can reuse
the chunk, unpinned in rw_trx_hash_t::find().
The scenario is the following:
1. Thread 1 have just executed lf_hash_search() in
rw_trx_hash_t::find(), but have not acquired element->mutex yet.
2. Thread 2 have removed the element from hash table with
rw_trx_hash_t::erase() call.
3. Thread 1 acquired element->mutex and unpinned pin 2 pin with
lf_hash_search_unpin(pins) call.
4. Some thread purged memory of the element.
5. Thread 3 reused the memory for the element, filled element->id,
element->trx.
6. Thread 1 crashes with failed "DBUG_ASSERT(trx_id == trx->id)"
assertion.
Note that trx_t objects are also reused, see the code around trx_pools
for details.
The fix is to invoke "lf_hash_search_unpin(pins);" after
"mutex_exit(&element->mutex);" call in rw_trx_hash_t::find().
Diffstat (limited to 'mysys/lf_alloc-pin.c')
-rw-r--r-- | mysys/lf_alloc-pin.c | 3 |
1 files changed, 3 insertions, 0 deletions
diff --git a/mysys/lf_alloc-pin.c b/mysys/lf_alloc-pin.c index f844920a664..6d80b381e5e 100644 --- a/mysys/lf_alloc-pin.c +++ b/mysys/lf_alloc-pin.c @@ -270,6 +270,9 @@ void lf_pinbox_free(LF_PINS *pins, void *addr) add_to_purgatory(pins, addr); if (pins->purgatory_count % LF_PURGATORY_SIZE == 0) lf_pinbox_real_free(pins); + DBUG_EXECUTE_IF("unconditional_pinbox_free", + if (pins->purgatory_count % LF_PURGATORY_SIZE) + lf_pinbox_real_free(pins);); } struct st_harvester { |