Commit a298dfb8 authored by Marko Mäkelä's avatar Marko Mäkelä

MDEV-35053 Crash in purge_sys_t::iterator::free_history_rseg()

purge_sys_t::get_page(): Avoid accessing a freed reference to pages[id]
after pages.erase(id).  This heap-use-after-free would sometimes be
caught by AddressSanitizer.

purge_sys_t::iterator::free_history_rseg(): Do not crash if undo=nullptr
(the database is corrupted).

Reviewed by: Debarun Banerjee
parent 2d031f4a
...@@ -493,16 +493,18 @@ inline dberr_t purge_sys_t::iterator::free_history_rseg(trx_rseg_t &rseg) const ...@@ -493,16 +493,18 @@ inline dberr_t purge_sys_t::iterator::free_history_rseg(trx_rseg_t &rseg) const
if (undo->hdr_page_no == hdr_addr.page) if (undo->hdr_page_no == hdr_addr.page)
goto found_cached; goto found_cached;
ut_ad("inconsistent undo logs" == 0); ut_ad("inconsistent undo logs" == 0);
if (false) found_cached:
found_cached:
UT_LIST_REMOVE(rseg.undo_cached, undo);
static_assert(FIL_NULL == 0xffffffff, ""); static_assert(FIL_NULL == 0xffffffff, "");
if (UNIV_UNLIKELY(mach_read_from_4(TRX_RSEG + TRX_RSEG_FORMAT + if (UNIV_UNLIKELY(mach_read_from_4(TRX_RSEG + TRX_RSEG_FORMAT +
rseg_hdr->page.frame))) rseg_hdr->page.frame)))
trx_rseg_format_upgrade(rseg_hdr, &mtr); trx_rseg_format_upgrade(rseg_hdr, &mtr);
mtr.memset(rseg_hdr, TRX_RSEG + TRX_RSEG_UNDO_SLOTS + if (UNIV_LIKELY(undo != nullptr))
undo->id * TRX_RSEG_SLOT_SIZE, 4, 0xff); {
ut_free(undo); UT_LIST_REMOVE(rseg.undo_cached, undo);
mtr.memset(rseg_hdr, TRX_RSEG + TRX_RSEG_UNDO_SLOTS +
undo->id * TRX_RSEG_SLOT_SIZE, 4, 0xff);
ut_free(undo);
}
mtr.write<8,mtr_t::MAYBE_NOP>(*rseg_hdr, TRX_RSEG + TRX_RSEG_MAX_TRX_ID + mtr.write<8,mtr_t::MAYBE_NOP>(*rseg_hdr, TRX_RSEG + TRX_RSEG_MAX_TRX_ID +
rseg_hdr->page.frame, rseg_hdr->page.frame,
trx_sys.get_max_trx_id() - 1); trx_sys.get_max_trx_id() - 1);
...@@ -778,13 +780,16 @@ buf_block_t *purge_sys_t::get_page(page_id_t id) ...@@ -778,13 +780,16 @@ buf_block_t *purge_sys_t::get_page(page_id_t id)
{ {
ut_ad(!recv_sys.recovery_on); ut_ad(!recv_sys.recovery_on);
buf_block_t*& undo_page= pages[id]; buf_block_t *&h= pages[id];
buf_block_t *undo_page= h;
if (!undo_page) if (!undo_page)
{ {
undo_page= buf_pool.page_fix(id); // batch_cleanup() will unfix() undo_page= buf_pool.page_fix(id); // batch_cleanup() will unfix()
if (!undo_page) if (!undo_page)
pages.erase(id); pages.erase(id);
else
h= undo_page;
} }
return undo_page; return undo_page;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment