Description:
See innobase_commit_by_xid in storage/innobase/handler/ha_innodb.cc
1. TrxInInnoDB::enter
save trx into TrxInInnoDB::m_trx
access and modify TrxInInnoDB::m_trx
2. trx_free_for_background(trx);
reinit trx and free to trx_pools
3. TrxInInnoDB::exit
access and modify TrxInInnoDB::m_trx which has already free to trx_pools
After step-2 and before step-3, the trx_t object might be allocated and used by other thread, which is really dangerous.
In our test, finally we crash in:
storage/innobase/include/trx0trx.h:1504
ut_ad((trx->in_innodb & TRX_FORCE_ROLLBACK_MASK) == 0);
How to repeat:
Run XA transactions in parallel for a long time.
Suggested fix:
An immature fix:
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 4aeacf071b7..4591845ad5d 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -20076,13 +20076,15 @@ static xa_status_code innobase_commit_by_xid(
trx_t *trx = trx_get_trx_by_xid(xid);
if (trx != nullptr) {
- TrxInInnoDB trx_in_innodb(trx);
+ {
+ TrxInInnoDB trx_in_innodb(trx);
- innobase_commit_low(trx);
- ut_ad(trx->mysql_thd == nullptr);
- /* use cases are: disconnected xa, slave xa, recovery */
- trx_deregister_from_2pc(trx);
- ut_ad(!trx->will_lock); /* trx cache requirement */
+ innobase_commit_low(trx);
+ ut_ad(trx->mysql_thd == nullptr);
+ /* use cases are: disconnected xa, slave xa, recovery */
+ trx_deregister_from_2pc(trx);
+ ut_ad(!trx->will_lock); /* trx cache requirement */
+ }
trx_free_for_background(trx);
return (XA_OK);
@@ -20104,12 +20106,15 @@ static xa_status_code innobase_rollback_by_xid(
trx_t *trx = trx_get_trx_by_xid(xid);
if (trx != nullptr) {
- TrxInInnoDB trx_in_innodb(trx);
+ int ret;
+ {
+ TrxInInnoDB trx_in_innodb(trx);
- int ret = innobase_rollback_trx(trx);
+ ret = innobase_rollback_trx(trx);
- trx_deregister_from_2pc(trx);
- ut_ad(!trx->will_lock);
+ trx_deregister_from_2pc(trx);
+ ut_ad(!trx->will_lock);
+ }
trx_free_for_background(trx);
return (ret != 0 ? XAER_RMERR : XA_OK);