diff options
author | Thirunarayanan Balathandayuthapani <thiru@mariadb.com> | 2022-08-04 11:58:49 +0530 |
---|---|---|
committer | Thirunarayanan Balathandayuthapani <thiru@mariadb.com> | 2022-08-04 11:58:49 +0530 |
commit | 1b00eae652414d54738ce9435a7448dbe98e2d5d (patch) | |
tree | 1504b0d12f9987171d81743298ff369e478a6590 | |
parent | 212994f704496d01881f377e34e04bd007e5e298 (diff) | |
download | mariadb-git-10.6-MDEV-27700.tar.gz |
MDEV-27700 ASAN: heap-use-after-free in btr_search_drop_page_hash_index(buf_block_t*)10.6-MDEV-27700
- Race condition happens between btr_search_lazy_free() and
btr_search_drop_page_hash_index(). btr_search_lazy_free() frees
the index heap and btr_search_drop_page_hash_index() does
index->freed() after freeing the heap.
-rw-r--r-- | storage/innobase/btr/btr0btr.cc | 7 | ||||
-rw-r--r-- | storage/innobase/btr/btr0cur.cc | 9 | ||||
-rw-r--r-- | storage/innobase/btr/btr0sea.cc | 24 | ||||
-rw-r--r-- | storage/innobase/buf/buf0buf.cc | 12 | ||||
-rw-r--r-- | storage/innobase/include/btr0sea.h | 7 | ||||
-rw-r--r-- | storage/innobase/mtr/mtr0mtr.cc | 18 |
6 files changed, 33 insertions, 44 deletions
diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc index 7334a2e1757..05912483c8a 100644 --- a/storage/innobase/btr/btr0btr.cc +++ b/storage/innobase/btr/btr0btr.cc @@ -584,13 +584,6 @@ dberr_t btr_page_free(dict_index_t* index, buf_block_t* block, mtr_t* mtr, bool blob, bool space_latched) { ut_ad(mtr->memo_contains_flagged(block, MTR_MEMO_PAGE_X_FIX)); -#ifdef BTR_CUR_HASH_ADAPT - if (block->index && !block->index->freed()) - { - ut_ad(!blob); - ut_ad(page_is_leaf(block->page.frame)); - } -#endif const uint32_t page{block->page.id().page_no()}; ut_ad(index->table->space_id == block->page.id().space()); /* The root page is freed by btr_free_root(). */ diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index 7a9480cdf4e..1aaf697f7fc 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -282,9 +282,6 @@ latch_block: block->page.fix(); block->page.lock.x_lock(); -#ifdef BTR_CUR_HASH_ADAPT - ut_ad(!block->index || !block->index->freed()); -#endif if (UNIV_LIKELY_NULL(rtr_info)) { rtr_info->tree_savepoints[RTR_MAX_LEVELS + 1] = save; @@ -7023,9 +7020,6 @@ btr_store_big_rec_extern_fields( rec_block->page.fix(); rec_block->page.lock.x_lock(); -#ifdef BTR_CUR_HASH_ADAPT - ut_ad(!rec_block->index || !rec_block->index->freed()); -#endif uint32_t hint_prev = prev_page_no; if (hint_prev == FIL_NULL) { @@ -7400,9 +7394,6 @@ skip_free: mtr.memo_push(block, MTR_MEMO_PAGE_X_FIX); block->fix(); block->page.lock.x_lock(); -#ifdef BTR_CUR_HASH_ADAPT - ut_ad(!block->index || !block->index->freed()); -#endif const page_t* page = buf_block_get_frame(ext_block); diff --git a/storage/innobase/btr/btr0sea.cc b/storage/innobase/btr/btr0sea.cc index 137a8b10d9f..208444454fb 100644 --- a/storage/innobase/btr/btr0sea.cc +++ b/storage/innobase/btr/btr0sea.cc @@ -1279,8 +1279,11 @@ fail_and_release_page: index page for which we know that block->buf_fix_count == 0 or it is an index page which has already been removed from the buf_pool.page_hash - i.e.: it is in state BUF_BLOCK_REMOVE_HASH */ -void btr_search_drop_page_hash_index(buf_block_t* block) + i.e.: it is in state BUF_BLOCK_REMOVE_HASH +@param[in] drop_ahi_freed drop the ahi entries only if the index + is freed */ +void btr_search_drop_page_hash_index(buf_block_t* block, + bool drop_ahi_freed) { ulint n_fields; ulint n_bytes; @@ -1316,13 +1319,21 @@ retry: auto part = btr_search_sys.get_part(index_id, block->page.id().space()); + part->latch.rd_lock(SRW_LOCK_CALL); + dict_index_t* index = block->index; bool is_freed = index && index->freed(); if (is_freed) { + part->latch.rd_unlock(); part->latch.wr_lock(SRW_LOCK_CALL); - } else { - part->latch.rd_lock(SRW_LOCK_CALL); + if (block->index != index) { + part->latch.wr_unlock(); + goto retry; + } + } else if (drop_ahi_freed) { + part->latch.rd_unlock(); + return; } assert_block_ahi_valid(block); @@ -1797,12 +1808,13 @@ drop_exit: return; } + ahi_latch->rd_lock(SRW_LOCK_CALL); + if (index->freed()) { + ahi_latch->rd_unlock(); goto drop_exit; } - ahi_latch->rd_lock(SRW_LOCK_CALL); - if (block->index) { uint16_t n_fields = block->curr_n_fields; uint16_t n_bytes = block->curr_n_bytes; diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index c53997086bb..085355533f4 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -2760,10 +2760,8 @@ re_evict: && state < buf_page_t::WRITE_FIX)); #ifdef BTR_CUR_HASH_ADAPT - if (dict_index_t* index = block->index) { - if (index->freed()) { - btr_search_drop_page_hash_index(block); - } + if (block->index) { + btr_search_drop_page_hash_index(block, true); } #endif /* BTR_CUR_HASH_ADAPT */ @@ -2822,10 +2820,8 @@ get_latch: } get_latch_valid: #ifdef BTR_CUR_HASH_ADAPT - if (dict_index_t* index = block->index) { - if (index->freed()) { - mtr_t::defer_drop_ahi(block, fix_type); - } + if (block->index) { + mtr_t::defer_drop_ahi(block, fix_type); } #endif /* BTR_CUR_HASH_ADAPT */ mtr->memo_push(block, fix_type); diff --git a/storage/innobase/include/btr0sea.h b/storage/innobase/include/btr0sea.h index 106582286a9..95103168147 100644 --- a/storage/innobase/include/btr0sea.h +++ b/storage/innobase/include/btr0sea.h @@ -100,8 +100,11 @@ btr_search_move_or_delete_hash_entries( index page for which we know that block->buf_fix_count == 0 or it is an index page which has already been removed from the buf_pool.page_hash - i.e.: it is in state BUF_BLOCK_REMOVE_HASH */ -void btr_search_drop_page_hash_index(buf_block_t* block); + i.e.: it is in state BUF_BLOCK_REMOVE_HASH +@param[in] drop_ahi_freed drop the ahi entries only if the index + is freed */ +void btr_search_drop_page_hash_index(buf_block_t* block, + bool drop_ahi_freed=false); /** Drop possible adaptive hash index entries when a page is evicted from the buffer pool or freed in a file, or the index is being dropped. diff --git a/storage/innobase/mtr/mtr0mtr.cc b/storage/innobase/mtr/mtr0mtr.cc index 5718daeda0b..a12e9bbd5b7 100644 --- a/storage/innobase/mtr/mtr0mtr.cc +++ b/storage/innobase/mtr/mtr0mtr.cc @@ -1278,18 +1278,16 @@ void mtr_t::defer_drop_ahi(buf_block_t *block, mtr_memo_type_t fix_type) /* Temporarily release our S-latch. */ block->page.lock.s_unlock(); block->page.lock.x_lock(); - if (dict_index_t *index= block->index) - if (index->freed()) - btr_search_drop_page_hash_index(block); + if (block->index) + btr_search_drop_page_hash_index(block, true); block->page.lock.x_unlock(); block->page.lock.s_lock(); ut_ad(!block->page.is_read_fixed()); break; case MTR_MEMO_PAGE_SX_FIX: block->page.lock.u_x_upgrade(); - if (dict_index_t *index= block->index) - if (index->freed()) - btr_search_drop_page_hash_index(block); + if (block->index) + btr_search_drop_page_hash_index(block, true); block->page.lock.x_u_downgrade(); break; case MTR_MEMO_PAGE_X_FIX: @@ -1317,9 +1315,6 @@ void mtr_t::page_lock_upgrade(const buf_block_t &block) { ut_ad(block.page.lock.have_x()); m_memo.for_each_block(CIterate<UpgradeX>((UpgradeX(block)))); -#ifdef BTR_CUR_HASH_ADAPT - ut_ad(!block.index || !block.index->freed()); -#endif /* BTR_CUR_HASH_ADAPT */ } /** Upgrade U locks to X */ @@ -1379,9 +1374,8 @@ void mtr_t::page_lock(buf_block_t *block, ulint rw_latch) } #ifdef BTR_CUR_HASH_ADAPT - if (dict_index_t *index= block->index) - if (index->freed()) - defer_drop_ahi(block, fix_type); + if (block->index) + defer_drop_ahi(block, fix_type); #endif /* BTR_CUR_HASH_ADAPT */ done: |