From 9528b1d9c1ffe22c9bc27daffaafc97cda397da6 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Thu, 2 Apr 2026 14:37:04 +1100 Subject: [PATCH] MDEV-39241: THD::backup_commit_lock warning dangling-pointer The mechanisms of XA backup locks use a stack allocated mdl_request object. This is passed and stored in the THD object. Compilers complain about this behaviour because the lifetime of the THD->backup_commit_lock may exceed the lifetime of the stack variable mdl_request. As the complier is also free to reuse the memory of mdl_request after its last reference in the code, the lifetime of the variable isn't defined after the function call to trans_xa_get_backup_lock. As the THD has an allocation mechanism defined, and can release used memory, lets change this implementation and be explicit, and not rely on the compiler doing the right thing in the realm of undefined behaviour. Caused by MDEV-39241. --- sql/xa.cc | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/sql/xa.cc b/sql/xa.cc index 48cbf65c53a29..eb53d11f92438 100644 --- a/sql/xa.cc +++ b/sql/xa.cc @@ -524,9 +524,13 @@ static bool trans_xa_get_backup_lock(THD *thd, MDL_request *mdl_request) DBUG_ASSERT(thd->backup_commit_lock == 0); MDL_REQUEST_INIT(mdl_request, MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT, MDL_EXPLICIT); - if (thd->mdl_context.acquire_lock(mdl_request, + if (mdl_request && + thd->mdl_context.acquire_lock(mdl_request, thd->variables.lock_wait_timeout)) + { + mdl_request->~MDL_request();; return 1; + } thd->backup_commit_lock= mdl_request; return 0; } @@ -536,6 +540,7 @@ static inline void trans_xa_release_backup_lock(THD *thd) if (thd->backup_commit_lock) { thd->mdl_context.release_lock(thd->backup_commit_lock->ticket); + thd->backup_commit_lock->~MDL_request();; thd->backup_commit_lock= 0; } } @@ -563,11 +568,11 @@ bool trans_xa_prepare(THD *thd) my_error(ER_XAER_NOTA, MYF(0)); else { - MDL_request mdl_request; - if (trans_xa_get_backup_lock(thd, &mdl_request) || + MDL_request *mdl_request= new (thd->mem_root) MDL_request; + if (trans_xa_get_backup_lock(thd, mdl_request) || ha_prepare(thd)) { - if (!mdl_request.ticket) + if (!mdl_request->ticket) /* Failed to get the backup lock */ ha_rollback_trans(thd, TRUE); thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_BINLOG_THIS_TRX); @@ -652,7 +657,6 @@ bool trans_xa_commit(THD *thd) if (auto xs= xid_cache_search(thd, thd->lex->xid)) { bool xid_deleted= false; - MDL_request mdl_request; bool rw_trans= (xs->rm_error != ER_XA_RBROLLBACK); if (rw_trans && thd->is_read_only_ctx()) @@ -662,7 +666,7 @@ bool trans_xa_commit(THD *thd) goto _end_external_xid; } res= xa_trans_rolled_back(xs); - if (trans_xa_get_backup_lock(thd, &mdl_request)) + if (trans_xa_get_backup_lock(thd, new (thd->mem_root) MDL_request)) { /* We can't rollback an XA transaction on lock failure due to @@ -720,14 +724,13 @@ bool trans_xa_commit(THD *thd) else if (thd->transaction->xid_state.xid_cache_element->xa_state == XA_PREPARED) { - MDL_request mdl_request; if (thd->lex->xa_opt != XA_NONE) { my_error(ER_XAER_INVAL, MYF(0)); DBUG_RETURN(TRUE); } - if (trans_xa_get_backup_lock(thd, &mdl_request)) + if (trans_xa_get_backup_lock(thd, new (thd->mem_root) MDL_request)) { /* We can't rollback an XA transaction on lock failure due to @@ -792,7 +795,6 @@ bool trans_xa_commit(THD *thd) bool trans_xa_rollback(THD *thd) { XID_STATE &xid_state= thd->transaction->xid_state; - MDL_request mdl_request; bool error; DBUG_ENTER("trans_xa_rollback"); @@ -823,7 +825,7 @@ bool trans_xa_rollback(THD *thd) goto _end_external_xid; } - if (trans_xa_get_backup_lock(thd, &mdl_request)) + if (trans_xa_get_backup_lock(thd, new (thd->mem_root) MDL_request)) { /* We can't rollback an XA transaction on lock failure due to @@ -867,7 +869,7 @@ bool trans_xa_rollback(THD *thd) DBUG_RETURN(TRUE); } - if (trans_xa_get_backup_lock(thd, &mdl_request)) + if (trans_xa_get_backup_lock(thd, new (thd->mem_root) MDL_request)) { /* We can't rollback an XA transaction on lock failure due to