summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThirunarayanan Balathandayuthapani <thiru@mariadb.com>2022-08-04 11:58:49 +0530
committerThirunarayanan Balathandayuthapani <thiru@mariadb.com>2022-08-04 11:58:49 +0530
commit1b00eae652414d54738ce9435a7448dbe98e2d5d (patch)
tree1504b0d12f9987171d81743298ff369e478a6590
parent212994f704496d01881f377e34e04bd007e5e298 (diff)
downloadmariadb-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.cc7
-rw-r--r--storage/innobase/btr/btr0cur.cc9
-rw-r--r--storage/innobase/btr/btr0sea.cc24
-rw-r--r--storage/innobase/buf/buf0buf.cc12
-rw-r--r--storage/innobase/include/btr0sea.h7
-rw-r--r--storage/innobase/mtr/mtr0mtr.cc18
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: