Description:
MySQL server crashes with SIGSEGV (signal 11) in the data dictionary cache infrastructure, specifically in `dd::cache::Shared_multi_map<dd::Routine>::Autolocker::~Autolocker()`. The crash occurs due to a race condition in the `Autolocker` destructor, which releases the mutex **before** executing deferred `delete` operations on evicted DD cache objects. This creates a window where another thread can access, evict, or re-delete the same objects, leading to use-after-free or double-free.
The root cause is in `sql/dd/impl/cache/shared_multi_map.h`, lines 160-173. The `Autolocker` destructor executes in this order:
1. `mysql_mutex_unlock(&m_map->m_lock)` — releases the lock
2. `delete` deferred objects — **executed without lock protection**
3. `delete` deferred elements — **executed without lock protection**
Between step 1 and step 2, another thread may acquire the lock and access the same `Shared_multi_map` instance (via `get()`, `put()`, `release()`, or `drop()`), potentially operating on the same cache elements that are pending deletion. This leads to use-after-free or double-free, causing SIGSEGV.
## Crash Backtrace
```
stack_bottom = 7fc81e617460 thread_stack 0x100000
/usr/local/engine/bin/mysqld(my_print_stacktrace(unsigned char const*, unsigned long)+0x3d) [0x557ebc5620bd]
/usr/local/engine/bin/mysqld(print_fatal_signal(int)+0x314) [0x557ebafa00a4]
/usr/local/engine/bin/mysqld(handle_fatal_signal+0x84) [0x557ebafa0134]
/lib64/libpthread.so.0(+0x13280) [0x7fce32ab8280]
/usr/local/engine/bin/mysqld(dd::cache::Shared_multi_map<dd::Routine>::Autolocker::~Autolocker()+0x66) [0x557ebc324b56]
/usr/local/engine/bin/mysqld(dd::cache::Shared_multi_map<dd::Routine>::release(dd::cache::Cache_element<dd::Routine>*)+0x6f) [0x557ebc33317f]
/usr/local/engine/bin/mysqld(dd::cache::Dictionary_client::Auto_releaser::~Auto_releaser()+0x16b8) [0x557ebac577d8]
/usr/local/engine/bin/mysqld(+0x184e254) [0x557ebb33d254]
/usr/local/engine/bin/mysqld(sp_cache_routine(THD*, enum_sp_type, sp_name const*, bool, sp_head**)+0xb4) [0x557ebb33ce84]
/usr/local/engine/bin/mysqld(sp_cache_routine(THD*, Sroutine_hash_entry*, bool, sp_head**)+0x61) [0x557ebb33cda1]
/usr/local/engine/bin/mysqld(+0x12e35ad) [0x557ebadd25ad]
/usr/local/engine/bin/mysqld(open_tables(THD*, TABLE_LIST**, unsigned int*, unsigned int, Prelocking_strategy*)+0xa96) [0x557ebab8c9f6]
/usr/local/engine/bin/mysqld(open_tables_for_query(THD*, TABLE_LIST*, unsigned int)+0x99) [0x557ebab91339]
/usr/local/engine/bin/mysqld(Sql_cmd_dml::prepare(THD*)+0x521) [0x557ebabc5b51]
/usr/local/engine/bin/mysqld(Sql_cmd_dml::execute(THD*)+0xff) [0x557ebabc4b2f]
/usr/local/engine/bin/mysqld(mysql_execute_command(THD*, bool)+0x3de) [0x557ebabb301e]
/usr/local/engine/bin/mysqld(dispatch_sql_command(THD*, Parser_state*)+0x4d0) [0x557ebabba2e0]
/usr/local/engine/bin/mysqld(dispatch_command(THD*, COM_DATA const*, enum_server_command)+0x558) [0x557ebabbb6a8]
/usr/local/engine/bin/mysqld(do_command(THD*)+0x11b) [0x557ebabbafab]
/usr/local/engine/bin/mysqld(threadpool_process_request(THD*)+0x98) [0x557ebad25718]
/usr/local/engine/bin/mysqld(+0x1237219) [0x557ebad26219]
/usr/local/engine/bin/mysqld(+0x3017be6) [0x557ebcb06be6]
/lib64/libpthread.so.0(+0x8f4b) [0x7fce32aadf4b]
/lib64/libc.so.6(clone+0x3f) [0x7fce3258f7ef]
```
How to repeat:
High-concurrency workload with stored routines (procedures/functions)
Suggested fix:
// Unlock the multi map when being deleted (e.g. going out of scope)
// and delete the objects and elements.
~Autolocker() {
mysql_mutex_unlock(&m_map->m_lock); // Step 1: Lock released
// Delete the objects.
for (typename Object_list_type::const_iterator it =
m_objects_to_delete.begin();
it != m_objects_to_delete.end(); ++it)
delete *it; // Step 2: Delete without lock
// Delete the elements.
for (typename Element_list_type::const_iterator it =
m_elements_to_delete.begin();
it != m_elements_to_delete.end(); ++it)
delete *it; // Step 3: Delete without lock
}
Description: MySQL server crashes with SIGSEGV (signal 11) in the data dictionary cache infrastructure, specifically in `dd::cache::Shared_multi_map<dd::Routine>::Autolocker::~Autolocker()`. The crash occurs due to a race condition in the `Autolocker` destructor, which releases the mutex **before** executing deferred `delete` operations on evicted DD cache objects. This creates a window where another thread can access, evict, or re-delete the same objects, leading to use-after-free or double-free. The root cause is in `sql/dd/impl/cache/shared_multi_map.h`, lines 160-173. The `Autolocker` destructor executes in this order: 1. `mysql_mutex_unlock(&m_map->m_lock)` — releases the lock 2. `delete` deferred objects — **executed without lock protection** 3. `delete` deferred elements — **executed without lock protection** Between step 1 and step 2, another thread may acquire the lock and access the same `Shared_multi_map` instance (via `get()`, `put()`, `release()`, or `drop()`), potentially operating on the same cache elements that are pending deletion. This leads to use-after-free or double-free, causing SIGSEGV. ## Crash Backtrace ``` stack_bottom = 7fc81e617460 thread_stack 0x100000 /usr/local/engine/bin/mysqld(my_print_stacktrace(unsigned char const*, unsigned long)+0x3d) [0x557ebc5620bd] /usr/local/engine/bin/mysqld(print_fatal_signal(int)+0x314) [0x557ebafa00a4] /usr/local/engine/bin/mysqld(handle_fatal_signal+0x84) [0x557ebafa0134] /lib64/libpthread.so.0(+0x13280) [0x7fce32ab8280] /usr/local/engine/bin/mysqld(dd::cache::Shared_multi_map<dd::Routine>::Autolocker::~Autolocker()+0x66) [0x557ebc324b56] /usr/local/engine/bin/mysqld(dd::cache::Shared_multi_map<dd::Routine>::release(dd::cache::Cache_element<dd::Routine>*)+0x6f) [0x557ebc33317f] /usr/local/engine/bin/mysqld(dd::cache::Dictionary_client::Auto_releaser::~Auto_releaser()+0x16b8) [0x557ebac577d8] /usr/local/engine/bin/mysqld(+0x184e254) [0x557ebb33d254] /usr/local/engine/bin/mysqld(sp_cache_routine(THD*, enum_sp_type, sp_name const*, bool, sp_head**)+0xb4) [0x557ebb33ce84] /usr/local/engine/bin/mysqld(sp_cache_routine(THD*, Sroutine_hash_entry*, bool, sp_head**)+0x61) [0x557ebb33cda1] /usr/local/engine/bin/mysqld(+0x12e35ad) [0x557ebadd25ad] /usr/local/engine/bin/mysqld(open_tables(THD*, TABLE_LIST**, unsigned int*, unsigned int, Prelocking_strategy*)+0xa96) [0x557ebab8c9f6] /usr/local/engine/bin/mysqld(open_tables_for_query(THD*, TABLE_LIST*, unsigned int)+0x99) [0x557ebab91339] /usr/local/engine/bin/mysqld(Sql_cmd_dml::prepare(THD*)+0x521) [0x557ebabc5b51] /usr/local/engine/bin/mysqld(Sql_cmd_dml::execute(THD*)+0xff) [0x557ebabc4b2f] /usr/local/engine/bin/mysqld(mysql_execute_command(THD*, bool)+0x3de) [0x557ebabb301e] /usr/local/engine/bin/mysqld(dispatch_sql_command(THD*, Parser_state*)+0x4d0) [0x557ebabba2e0] /usr/local/engine/bin/mysqld(dispatch_command(THD*, COM_DATA const*, enum_server_command)+0x558) [0x557ebabbb6a8] /usr/local/engine/bin/mysqld(do_command(THD*)+0x11b) [0x557ebabbafab] /usr/local/engine/bin/mysqld(threadpool_process_request(THD*)+0x98) [0x557ebad25718] /usr/local/engine/bin/mysqld(+0x1237219) [0x557ebad26219] /usr/local/engine/bin/mysqld(+0x3017be6) [0x557ebcb06be6] /lib64/libpthread.so.0(+0x8f4b) [0x7fce32aadf4b] /lib64/libc.so.6(clone+0x3f) [0x7fce3258f7ef] ``` How to repeat: High-concurrency workload with stored routines (procedures/functions) Suggested fix: // Unlock the multi map when being deleted (e.g. going out of scope) // and delete the objects and elements. ~Autolocker() { mysql_mutex_unlock(&m_map->m_lock); // Step 1: Lock released // Delete the objects. for (typename Object_list_type::const_iterator it = m_objects_to_delete.begin(); it != m_objects_to_delete.end(); ++it) delete *it; // Step 2: Delete without lock // Delete the elements. for (typename Element_list_type::const_iterator it = m_elements_to_delete.begin(); it != m_elements_to_delete.end(); ++it) delete *it; // Step 3: Delete without lock }