MDEV-35510 ASAN build crashes during bootstrap

Decouple a DML result's cleanup from the destructor semantics, allowing
cleanup to occur without simultaneously deallocating memory.

The MYSQL_DML_DONE function would access the select_result_interceptor
implementation (in either the cases of UPDATE or DELETE) after that
interceptor instance's destructor had been called.  Most of the time
this works because the instance was allocated on the statement memroot
which continues to live on and no other allocations are made at this point.
The interceptor instance's destructor would be called during either
Sql_cmd_update::execute_inner or Sql_cmd_delete::execute_inner by an
explicit call to delete.  Since the result instance lives on the
memroot associated with the current command, we can avoid calling the
destructor via delete and instead invoke a cleanup method, deferring
the memory deallocation to free_root when the command's processing has
completed.
This commit is contained in:
Dave Gosselin 2025-01-08 15:18:03 -05:00
parent f014d5872b
commit 6d2391f4de
3 changed files with 21 additions and 5 deletions

View file

@ -7435,6 +7435,7 @@ public:
public:
multi_delete(THD *thd_arg, TABLE_LIST *dt, uint num_of_tables);
~multi_delete();
void cleanup();
int prepare(List<Item> &list, SELECT_LEX_UNIT *u) override;
int send_data(List<Item> &items) override;
bool initialize_tables (JOIN *join) override;
@ -7489,6 +7490,7 @@ public:
List<Item> *fields, List<Item> *values,
enum_duplicates handle_duplicates, bool ignore);
~multi_update();
void cleanup();
bool init(THD *thd);
bool init_for_single_table(THD *thd);
int prepare(List<Item> &list, SELECT_LEX_UNIT *u) override;

View file

@ -1158,6 +1158,12 @@ multi_delete::initialize_tables(JOIN *join)
multi_delete::~multi_delete()
{
cleanup();
}
void multi_delete::cleanup()
{
for (table_being_deleted= delete_tables;
table_being_deleted;
@ -1854,7 +1860,7 @@ bool Sql_cmd_delete::execute_inner(THD *thd)
if (result)
{
res= false;
delete result;
result->cleanup();
}
status_var_add(thd->status_var.rows_sent, thd->get_sent_row_count());

View file

@ -2250,6 +2250,12 @@ int multi_update::prepare2(JOIN *join)
multi_update::~multi_update()
{
cleanup();
}
void multi_update::cleanup()
{
TABLE_LIST *table;
for (table= update_tables ; table; table= table->next_local)
@ -2270,10 +2276,12 @@ multi_update::~multi_update()
}
}
}
if (copy_field)
delete [] copy_field;
if (copy_field) {
delete[] copy_field;
copy_field= nullptr;
}
thd->count_cuted_fields= CHECK_FIELD_IGNORE; // Restore this setting
DBUG_ASSERT(trans_safe || !updated ||
DBUG_ASSERT(trans_safe || !updated ||
thd->transaction->all.modified_non_trans_table);
}
@ -3127,7 +3135,7 @@ bool Sql_cmd_update::execute_inner(THD *thd)
if (result)
{
res= false;
delete result;
result->cleanup();
}
status_var_add(thd->status_var.rows_sent, thd->get_sent_row_count());