• Vlad Lesin's avatar
    MDEV-31185 rw_trx_hash_t::find() unpins pins too early · b54e7b0c
    Vlad Lesin authored
    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 element->trx is
    stored in local variable in rw_trx_hash_t::find().
    
    Reviewed by: Nikita Malyavin, Marko Mäkelä.
    b54e7b0c
xa.cc 23.5 KB