Description:
Sys_var_struct expects default value to be a pointer to pointer, however,
default_collation_for_utf8mb4 is constructed with a pointer to
my_charset_utf8mb4_0900_ai_ci, which is dereferenced to be a bad pointer in the
temporary storage save_result.ptr when
"SET GLOBAL default_collation_for_utf8mb4 = default" is processed.
There was a dirty fix to crash.
Bug #27594468: PROBLEM WHEN SETTING DEFAULT_COLLATION_FOR_UTF8MB4 TO
DEFAULT...
However, it leaves option.def_value of Sys_var_struct in a broken state: it can
be a pointer or a pointer to pointer, and there is no reliable way to tell.
For the SET GLOBAL statement, it is fine, because the check function pulls the
correct default back before update. It might have unexpected consequences
elsewhere, since saved_value_to_string() use the same saved_result.ptr as well.
I was bitten when trying to list sysvar definitions in a running server.
How to repeat:
The default value of global system variable Sys_var_struct<CHARSET_INFO, Get_name>
default_collation_for_utf8mb4 is saved in option.def_value as longlong. It is
actually a pointer to global variable CHARSET_INFO my_charset_utf8mb4_0900_ai_ci.
static Sys_var_struct<CHARSET_INFO, Get_name> Sys_default_collation_for_utf8mb4(
"default_collation_for_utf8mb4",
"Controls default collation for utf8mb4 while replicating implicit "
"utf8mb4 collations.",
SESSION_VAR(default_collation_for_utf8mb4), NO_CMD_LINE,
DEFAULT(&my_charset_utf8mb4_0900_ai_ci), NO_MUTEX_GUARD, IN_BINLOG,
ON_CHECK(check_default_collation_for_utf8mb4),
ON_UPDATE(update_deprecated));
However, for "SET GLOBAL default_collation_for_utf8mb4 = default", Sys_var_struct
treats it as a pointer to pointer when saving to the temporary storage:
void global_save_default(THD *, set_var *var) override {
void **default_value = reinterpret_cast<void **>(option.def_value);
var->save_result.ptr = *default_value;
}
(gdb) p option.def_value
$19 = 294478752
(gdb) p (CHARSET_INFO*)option.def_value
$20 = (CHARSET_INFO *) 0x118d63a0 <my_charset_utf8mb4_0900_ai_ci>
(gdb) p var->save_result.ptr
$21 = (const void *) 0xff
Bug #27594468 fixed a crash due to this bad pointer, however, it did not fix the
broken state.
Bug #27594468: PROBLEM WHEN SETTING DEFAULT_COLLATION_FOR_UTF8MB4 TO
DEFAULT...
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index eee5370d2de..fd67bd83510 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -6099,6 +6099,9 @@ static bool check_default_collation_for_utf8mb4(sys_var *self, THD *thd,
return true;
}
+ if (!var->value)
+ var->save_result.ptr = reinterpret_cast<void *>(self->get_default());
+
(gdb) p var->save_result.ptr
$22 = (const void *) 0xff
(gdb) p var->value
$23 = (Item *) 0x0
(gdb) p var->save_result.ptr
$26 = (const void *) 0x118d63a0 <my_charset_utf8mb4_0900_ai_ci>
Suggested fix:
Add an pointer to my_charset_utf8mb4_0900_ai_ci, and use it to construct
default_collation_for_utf8mb4. With a fix in this way, the dirty fix to
Bug #27594468 can also be reverted.
Description: Sys_var_struct expects default value to be a pointer to pointer, however, default_collation_for_utf8mb4 is constructed with a pointer to my_charset_utf8mb4_0900_ai_ci, which is dereferenced to be a bad pointer in the temporary storage save_result.ptr when "SET GLOBAL default_collation_for_utf8mb4 = default" is processed. There was a dirty fix to crash. Bug #27594468: PROBLEM WHEN SETTING DEFAULT_COLLATION_FOR_UTF8MB4 TO DEFAULT... However, it leaves option.def_value of Sys_var_struct in a broken state: it can be a pointer or a pointer to pointer, and there is no reliable way to tell. For the SET GLOBAL statement, it is fine, because the check function pulls the correct default back before update. It might have unexpected consequences elsewhere, since saved_value_to_string() use the same saved_result.ptr as well. I was bitten when trying to list sysvar definitions in a running server. How to repeat: The default value of global system variable Sys_var_struct<CHARSET_INFO, Get_name> default_collation_for_utf8mb4 is saved in option.def_value as longlong. It is actually a pointer to global variable CHARSET_INFO my_charset_utf8mb4_0900_ai_ci. static Sys_var_struct<CHARSET_INFO, Get_name> Sys_default_collation_for_utf8mb4( "default_collation_for_utf8mb4", "Controls default collation for utf8mb4 while replicating implicit " "utf8mb4 collations.", SESSION_VAR(default_collation_for_utf8mb4), NO_CMD_LINE, DEFAULT(&my_charset_utf8mb4_0900_ai_ci), NO_MUTEX_GUARD, IN_BINLOG, ON_CHECK(check_default_collation_for_utf8mb4), ON_UPDATE(update_deprecated)); However, for "SET GLOBAL default_collation_for_utf8mb4 = default", Sys_var_struct treats it as a pointer to pointer when saving to the temporary storage: void global_save_default(THD *, set_var *var) override { void **default_value = reinterpret_cast<void **>(option.def_value); var->save_result.ptr = *default_value; } (gdb) p option.def_value $19 = 294478752 (gdb) p (CHARSET_INFO*)option.def_value $20 = (CHARSET_INFO *) 0x118d63a0 <my_charset_utf8mb4_0900_ai_ci> (gdb) p var->save_result.ptr $21 = (const void *) 0xff Bug #27594468 fixed a crash due to this bad pointer, however, it did not fix the broken state. Bug #27594468: PROBLEM WHEN SETTING DEFAULT_COLLATION_FOR_UTF8MB4 TO DEFAULT... diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index eee5370d2de..fd67bd83510 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -6099,6 +6099,9 @@ static bool check_default_collation_for_utf8mb4(sys_var *self, THD *thd, return true; } + if (!var->value) + var->save_result.ptr = reinterpret_cast<void *>(self->get_default()); + (gdb) p var->save_result.ptr $22 = (const void *) 0xff (gdb) p var->value $23 = (Item *) 0x0 (gdb) p var->save_result.ptr $26 = (const void *) 0x118d63a0 <my_charset_utf8mb4_0900_ai_ci> Suggested fix: Add an pointer to my_charset_utf8mb4_0900_ai_ci, and use it to construct default_collation_for_utf8mb4. With a fix in this way, the dirty fix to Bug #27594468 can also be reverted.