Description:
Race condition between xa recover and xa start on Transaction_ctx object.
Because there are two locations that point to the same Transaction_ctx *transaction,
one is in THD named m_transaction, another is in m_transaction_cache.
T69: xa start insert a new std::shared_ptr<Transaction_ctx> into m_transaction_cache.
T70: xa recover call get_cached_transactions, get a list of std::shared_ptr<Transaction_ctx> from m_transaction_cache.
Then, T69 disconnect, release thd->m_transaction.
T70 go to traverse the list and visit Transaction_ctx* which is released by T69.
==287860==ERROR: AddressSanitizer: heap-use-after-free on address 0x61600040ff80 at pc 0x00000300cf7b bp 0x2ae1f0602e30 sp 0x2ae1f0602e28
READ of size 4 at 0x61600040ff80 thread T70 (connection)
#0 0x300cf7a in XID_STATE::has_state(XID_STATE::xa_states) const /data3/caizj/source/mysql-8.0.32/sql/xa.h:346
#1 0x3ed1d2e in Sql_cmd_xa_recover::trans_xa_recover(THD*) /data3/caizj/source/mysql-8.0.32/sql/xa/sql_xa_recover.cc:69
#2 0x3ed1fe7 in Sql_cmd_xa_recover::execute(THD*) /data3/caizj/source/mysql-8.0.32/sql/xa/sql_xa_recover.cc:40
#3 0x3231371 in mysql_execute_command(THD*, bool) /data3/caizj/source/mysql-8.0.32/sql/sql_parse.cc:4688
#4 0x3234971 in dispatch_sql_command(THD*, Parser_state*) /data3/caizj/source/mysql-8.0.32/sql/sql_parse.cc:5322
#5 0x3237344 in dispatch_command(THD*, COM_DATA const*, enum_server_command) /data3/caizj/source/mysql-8.0.32/sql/sql_parse.cc:2036
#6 0x323aac4 in do_command(THD*) /data3/caizj/source/mysql-8.0.32/sql/sql_parse.cc:1439
#7 0x35dd1af in handle_connection /data3/caizj/source/mysql-8.0.32/sql/conn_handler/connection_handler_per_thread.cc:302
#8 0x67b42c1 in pfs_spawn_thread /data3/caizj/source/mysql-8.0.32/storage/perfschema/pfs.cc:2986
#9 0x2adf1341fea4 in start_thread (/lib64/libpthread.so.0+0x7ea4)
#10 0x2adf150c4b0c in clone (/lib64/libc.so.6+0xfeb0c)
0x61600040ff80 is located 256 bytes inside of 544-byte region [0x61600040fe80,0x6160004100a0)
freed by thread T69 (connection) here:
#0 0x2adf128f9f05 in operator delete(void*, unsigned long) ../../../../libsanitizer/asan/asan_new_delete.cc:177
#1 0x352eb8b in Transaction_ctx::~Transaction_ctx() (/data3/caizj/ob_rel/mysql-8.0.32/bin/mysqld+0x352eb8b)
#2 0x30c3ebb in std::default_delete<Transaction_ctx>::operator()(Transaction_ctx*) const (/data3/caizj/ob_rel/mysql-8.0.32/bin/mysqld+0x30c3ebb)
#3 0x30c8b54 in std::unique_ptr<Transaction_ctx, std::default_delete<Transaction_ctx> >::~unique_ptr() /data3/local/gcc-9.2.0/include/c++/9.2.0/bits/unique_ptr.h:284
#4 0x30bf519 in THD::~THD() /data3/caizj/source/mysql-8.0.32/sql/sql_class.cc:1408
#5 0x30bf756 in THD::~THD() /data3/caizj/source/mysql-8.0.32/sql/sql_class.cc:1468
#6 0x35dd0f1 in handle_connection /data3/caizj/source/mysql-8.0.32/sql/conn_handler/connection_handler_per_thread.cc:324
#7 0x67b42c1 in pfs_spawn_thread /data3/caizj/source/mysql-8.0.32/storage/perfschema/pfs.cc:2986
#8 0x2adf1341fea4 in start_thread (/lib64/libpthread.so.0+0x7ea4)
previously allocated by thread T69 (connection) here:
#0 0x2adf128f8a7f in operator new(unsigned long) ../../../../libsanitizer/asan/asan_new_delete.cc:104
#1 0x30bc7be in THD::THD(bool) /data3/caizj/source/mysql-8.0.32/sql/sql_class.cc:661
#2 0x3ee4d09 in Channel_info::create_thd() /data3/caizj/source/mysql-8.0.32/sql/conn_handler/channel_info.cc:45
#3 0x35e4d2d in Channel_info_local_socket::create_thd() /data3/caizj/source/mysql-8.0.32/sql/conn_handler/socket_connection.cc:173
#4 0x35dc546 in init_new_thd /data3/caizj/source/mysql-8.0.32/sql/conn_handler/connection_handler_per_thread.cc:194
#5 0x35dd13f in handle_connection /data3/caizj/source/mysql-8.0.32/sql/conn_handler/connection_handler_per_thread.cc:263
#6 0x67b42c1 in pfs_spawn_thread /data3/caizj/source/mysql-8.0.32/storage/perfschema/pfs.cc:2986
#7 0x2adf1341fea4 in start_thread (/lib64/libpthread.so.0+0x7ea4)
Thread T70 (connection) created by T0 here:
#0 0x2adf12829332 in __interceptor_pthread_create ../../../../libsanitizer/asan/asan_interceptors.cc:208
#1 0x58f2fb3 in my_thread_create(my_thread_handle*, pthread_attr_t const*, void* (*)(void*), void*) /data3/caizj/source/mysql-8.0.32/mysys/my_thread.cc:80
#2 0x67b4154 in pfs_spawn_thread_vc(unsigned int, unsigned int, my_thread_handle*, pthread_attr_t const*, void* (*)(void*), void*) /data3/caizj/source/mysql-8.0.32/storage/perfschema/pfs.cc:3032
#3 0x35dc0fc in inline_mysql_thread_create /data3/caizj/source/mysql-8.0.32/include/mysql/psi/mysql_thread.h:139
#4 0x35dd5a8 in Per_thread_connection_handler::add_connection(Channel_info*) /data3/caizj/source/mysql-8.0.32/sql/conn_handler/connection_handler_per_thread.cc:414
#5 0x37ef932 in Connection_handler_manager::process_new_connection(Channel_info*) /data3/caizj/source/mysql-8.0.32/sql/conn_handler/connection_handler_manager.cc:260
#6 0x2f664c6 in Connection_acceptor<Mysqld_socket_listener>::connection_event_loop() (/data3/caizj/ob_rel/mysql-8.0.32/bin/mysqld+0x2f664c6)
#7 0x2f60403 in mysqld_main(int, char**) /data3/caizj/source/mysql-8.0.32/sql/mysqld.cc:8207
#8 0x2f395da in main /data3/caizj/source/mysql-8.0.32/sql/main.cc:25
#9 0x2adf14fe8554 in __libc_start_main (/lib64/libc.so.6+0x22554)
Thread T69 (connection) created by T0 here:
#0 0x2adf12829332 in __interceptor_pthread_create ../../../../libsanitizer/asan/asan_interceptors.cc:208
#1 0x58f2fb3 in my_thread_create(my_thread_handle*, pthread_attr_t const*, void* (*)(void*), void*) /data3/caizj/source/mysql-8.0.32/mysys/my_thread.cc:80
#2 0x67b4154 in pfs_spawn_thread_vc(unsigned int, unsigned int, my_thread_handle*, pthread_attr_t const*, void* (*)(void*), void*) /data3/caizj/source/mysql-8.0.32/storage/perfschema/pfs.cc:3032
#3 0x35dc0fc in inline_mysql_thread_create /data3/caizj/source/mysql-8.0.32/include/mysql/psi/mysql_thread.h:139
#4 0x35dd5a8 in Per_thread_connection_handler::add_connection(Channel_info*) /data3/caizj/source/mysql-8.0.32/sql/conn_handler/connection_handler_per_thread.cc:414
#5 0x37ef932 in Connection_handler_manager::process_new_connection(Channel_info*) /data3/caizj/source/mysql-8.0.32/sql/conn_handler/connection_handler_manager.cc:260
#6 0x2f664c6 in Connection_acceptor<Mysqld_socket_listener>::connection_event_loop() (/data3/caizj/ob_rel/mysql-8.0.32/bin/mysqld+0x2f664c6)
#7 0x2f60403 in mysqld_main(int, char**) /data3/caizj/source/mysql-8.0.32/sql/mysqld.cc:8207
#8 0x2f395da in main /data3/caizj/source/mysql-8.0.32/sql/main.cc:25
#9 0x2adf14fe8554 in __libc_start_main (/lib64/libc.so.6+0x22554)
How to repeat:
(1) add a DBUG_EXECUTE_IF in function Sql_cmd_xa_recover::trans_xa_recover, after get_cached_transactions , before for loop to traverse:
auto list = xa::Transaction_cache::get_cached_transactions();
DBUG_EXECUTE_IF("simulate_delay_after_xa_start_disconnect", sleep(10););
for (const auto &transaction : list) {
(2) build mysql with ASAN and debug type
-DCMAKE_BUILD_TYPE=Debug -DWITH_ASAN=ON
(3) run the test case(my_xa_recover.test) uploaded.