From 3cd706b107d3a0ada15aa8728ba876fc161ac0d5 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 23 Oct 2024 14:43:32 +0200 Subject: [PATCH] MDEV-35236 Assertion `(mem_root->flags & 4) == 0' failed in safe_lexcstrdup_root Post-fix for MDEV-35144. Cannot allocate options values on the statement arena, because HA_CREATE_INFO is shallow-copied for every execution, so if the option_list was initially empty, it will be reset for every execution and any values allocated on the statement arena will be lost. Cannot allocate option values on the execution arena, because HA_CREATE_INFO is shallow-copied for every execution, so if the option_list was initially NOT empty, any values appended to the end will be preserved and if they're on the execution arena their content will be destroyed. Let's use thd->change_item_tree() to save and restore necessary pointers for every execution. followup for 3da565c41d87 --- mysql-test/suite/innodb/r/create_select.result | 10 ++++++++++ mysql-test/suite/innodb/t/create_select.test | 13 +++++++++++++ sql/create_options.cc | 13 +++++++++++-- sql/create_options.h | 2 +- sql/sql_class.h | 11 ++++++++--- sql/sql_table.cc | 9 +++------ 6 files changed, 46 insertions(+), 12 deletions(-) diff --git a/mysql-test/suite/innodb/r/create_select.result b/mysql-test/suite/innodb/r/create_select.result index f5db880816e..183705680bd 100644 --- a/mysql-test/suite/innodb/r/create_select.result +++ b/mysql-test/suite/innodb/r/create_select.result @@ -8,3 +8,13 @@ connection default; ERROR 70100: Query execution was interrupted CREATE TABLE t1 (a SERIAL) ENGINE=InnoDB; DROP TABLE t1; +# End of 10.2 tests +# +# MDEV-35236 Assertion `(mem_root->flags & 4) == 0' failed in safe_lexcstrdup_root +# +prepare stmt from 'create or replace table t engine=innodb select 1 as f'; +set innodb_compression_default=on; +execute stmt; +execute stmt; +drop table t; +# End of 10.5 tests diff --git a/mysql-test/suite/innodb/t/create_select.test b/mysql-test/suite/innodb/t/create_select.test index 8103902e5f6..053db79b8f4 100644 --- a/mysql-test/suite/innodb/t/create_select.test +++ b/mysql-test/suite/innodb/t/create_select.test @@ -26,3 +26,16 @@ reap; CREATE TABLE t1 (a SERIAL) ENGINE=InnoDB; DROP TABLE t1; --source include/wait_until_count_sessions.inc + +--echo # End of 10.2 tests + +--echo # +--echo # MDEV-35236 Assertion `(mem_root->flags & 4) == 0' failed in safe_lexcstrdup_root +--echo # +prepare stmt from 'create or replace table t engine=innodb select 1 as f'; +set innodb_compression_default=on; +execute stmt; +execute stmt; +drop table t; + +--echo # End of 10.5 tests diff --git a/sql/create_options.cc b/sql/create_options.cc index 6e1217dcdfd..c4d320f7843 100644 --- a/sql/create_options.cc +++ b/sql/create_options.cc @@ -247,9 +247,11 @@ static const size_t ha_option_type_sizeof[]= bool extend_option_list(THD* thd, handlerton *hton, bool create, engine_option_value **option_list, - ha_create_table_option *rules, MEM_ROOT *root) + ha_create_table_option *rules) { DBUG_ENTER("extend_option_list"); + MEM_ROOT *root= thd->mem_root; + bool extended= false; for (ha_create_table_option *opt= rules; rules && opt->name; opt++) { @@ -280,8 +282,16 @@ bool extend_option_list(THD* thd, handlerton *hton, bool create, if (found) found->value= value; else + { + if (!extended) + { + void *pos= *option_list ? &(last->next) : option_list; + thd->register_item_tree_change((Item**)pos); + extended= true; + } new (root) engine_option_value(name, value, opt->type != HA_OPTION_TYPE_ULL, option_list, &last); + } } } } @@ -803,4 +813,3 @@ bool is_engine_option_known(engine_option_value *opt, } return false; } - diff --git a/sql/create_options.h b/sql/create_options.h index fc208d933a0..a8eece58a22 100644 --- a/sql/create_options.h +++ b/sql/create_options.h @@ -89,7 +89,7 @@ bool parse_option_list(THD* thd, void *option_struct, bool suppress_warning, MEM_ROOT *root); bool extend_option_list(THD* thd, handlerton *hton, bool create, engine_option_value **option_list, - ha_create_table_option *rules, MEM_ROOT *root); + ha_create_table_option *rules); bool engine_table_options_frm_read(const uchar *buff, size_t length, TABLE_SHARE *share); diff --git a/sql/sql_class.h b/sql/sql_class.h index e1c6b83c448..07b225c7d06 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -4301,14 +4301,19 @@ public: return !stmt_arena->is_conventional(); } + void register_item_tree_change(Item **place) + { + /* TODO: check for OOM condition here */ + if (is_item_tree_change_register_required()) + nocheck_register_item_tree_change(place, *place, mem_root); + } + void change_item_tree(Item **place, Item *new_value) { DBUG_ENTER("THD::change_item_tree"); DBUG_PRINT("enter", ("Register: %p (%p) <- %p", *place, place, new_value)); - /* TODO: check for OOM condition here */ - if (is_item_tree_change_register_required()) - nocheck_register_item_tree_change(place, *place, mem_root); + register_item_tree_change(place); *place= new_value; DBUG_VOID_RETURN; } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 3f035defbd3..15b2cac14e9 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3769,8 +3769,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, auto_increment++; extend_option_list(thd, create_info->db_type, !sql_field->field, &sql_field->option_list, - create_info->db_type->field_options, - thd->stmt_arena->mem_root); + create_info->db_type->field_options); if (parse_option_list(thd, &sql_field->option_struct, &sql_field->option_list, create_info->db_type->field_options, FALSE, @@ -4039,8 +4038,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, key_info->algorithm= key->key_create_info.algorithm; key_info->option_list= key->option_list; extend_option_list(thd, create_info->db_type, !key->old, - &key_info->option_list, create_info->db_type->index_options, - thd->stmt_arena->mem_root); + &key_info->option_list, create_info->db_type->index_options); if (parse_option_list(thd, &key_info->option_struct, &key_info->option_list, create_info->db_type->index_options, FALSE, @@ -4633,8 +4631,7 @@ without_overlaps_err: extend_option_list(thd, file->partition_ht(), !thd->lex->create_like() && create_table_mode > C_ALTER_TABLE, - &create_info->option_list, file->partition_ht()->table_options, - thd->stmt_arena->mem_root); + &create_info->option_list, file->partition_ht()->table_options); if (parse_option_list(thd, &create_info->option_struct, &create_info->option_list, file->partition_ht()->table_options, FALSE, thd->mem_root))