1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

MDEV-30805 SIGSEGV in my_convert and UBSAN: member access within null pointer of type 'const struct MY_CHARSET_HANDLER' in my_convert

Type_handler::partition_field_append_value() erroneously
passed the address of my_collation_contextually_typed_binary
to conversion functions copy_and_convert() and my_convert().

This happened because generate_partition_syntax_for_frm()
was called from mysql_create_frm_image() in the stage when
the fields in List<Create_field> can still contain unresolved
contextual collations, like "binary" in the reported crash scenario:

  ALTER TABLE t CHANGE COLUMN a a CHAR BINARY;

Fix:

1. Splitting mysql_prepare_create_table() into two parts:
   - mysql_prepare_create_table_stage1() interates through
     List<Create_field> and calls Create_field::prepare_stage1(),
     which performs basic attribute initialization, including
     context collation resolution.
   - mysql_prepare_create_table_finalize() - the rest of the
     old mysql_prepare_create_table() code.

2. Changing mysql_create_frm_image():
   It now calls:
   - mysql_prepare_create_table_stage1() in the very
     beginning, before the partition related code.
   - mysql_prepare_create_table_finalize() in the end,
    instead of the old mysql_prepare_create_table() call

3. Adding mysql_prepare_create_table() as a wrapper
   for two calls:
     mysql_prepare_create_table_stage1() ||
     mysql_prepare_create_table_finalize()
   so the code stays unchanged in the other places
   where mysql_prepare_create_table() was used.

4. Changing prototype for Type_handler::Column_definition_prepare_stage1()
   Removing arguments:
   - handler *file
   - ulonglong table_flags
   Adding a new argument instead:
   - column_definition_type_t type
   This allows to call Column_definition_prepare_stage1() and
   therefore to call mysql_prepare_create_table_stage1()
   before instantiation of a handler.
   This simplifies the code, because in case of a partitioned table,
   mysql_create_frm_image() creates a handler of the underlying
   partition first, the frees it and created a ha_partition
   instance instead.
   mysql_prepare_create_table() before the fix was called with the final
   (ha_partition) handler.

5. Moving parts of Column_definition_prepare_stage1() which
   need a pointer to handler and table_flags to
   Column_definition_prepare_stage2().
This commit is contained in:
Alexander Barkov
2023-03-14 05:29:04 +04:00
parent 46a7603813
commit 4703638775
11 changed files with 221 additions and 137 deletions

View File

@ -3008,8 +3008,7 @@ bool Type_handler::
Column_definition_prepare_stage1(THD *thd,
MEM_ROOT *mem_root,
Column_definition *def,
handler *file,
ulonglong table_flags,
column_definition_type_t type,
const Column_derived_attributes
*derived_attr)
const
@ -3022,8 +3021,7 @@ bool Type_handler_null::
Column_definition_prepare_stage1(THD *thd,
MEM_ROOT *mem_root,
Column_definition *def,
handler *file,
ulonglong table_flags,
column_definition_type_t type,
const Column_derived_attributes
*derived_attr)
const
@ -3037,8 +3035,7 @@ bool Type_handler_row::
Column_definition_prepare_stage1(THD *thd,
MEM_ROOT *mem_root,
Column_definition *def,
handler *file,
ulonglong table_flags,
column_definition_type_t type,
const Column_derived_attributes
*derived_attr)
const
@ -3052,8 +3049,7 @@ bool Type_handler_temporal_result::
Column_definition_prepare_stage1(THD *thd,
MEM_ROOT *mem_root,
Column_definition *def,
handler *file,
ulonglong table_flags,
column_definition_type_t type,
const Column_derived_attributes
*derived_attr)
const
@ -3067,8 +3063,7 @@ bool Type_handler_numeric::
Column_definition_prepare_stage1(THD *thd,
MEM_ROOT *mem_root,
Column_definition *def,
handler *file,
ulonglong table_flags,
column_definition_type_t type,
const Column_derived_attributes
*derived_attr)
const
@ -3081,8 +3076,7 @@ bool Type_handler_newdecimal::
Column_definition_prepare_stage1(THD *thd,
MEM_ROOT *mem_root,
Column_definition *def,
handler *file,
ulonglong table_flags,
column_definition_type_t type,
const Column_derived_attributes
*derived_attr)
const
@ -3096,28 +3090,26 @@ bool Type_handler_bit::
Column_definition_prepare_stage1(THD *thd,
MEM_ROOT *mem_root,
Column_definition *def,
handler *file,
ulonglong table_flags,
column_definition_type_t type,
const Column_derived_attributes
*derived_attr)
const
{
def->charset= &my_charset_numeric;
return def->prepare_stage1_bit(thd, mem_root, file, table_flags);
return def->prepare_stage1_bit(thd, mem_root);
}
bool Type_handler_typelib::
Column_definition_prepare_stage1(THD *thd,
MEM_ROOT *mem_root,
Column_definition *def,
handler *file,
ulonglong table_flags,
column_definition_type_t type,
const Column_derived_attributes
*derived_attr)
const
{
return def->prepare_charset_for_string(derived_attr) ||
def->prepare_stage1_typelib(thd, mem_root, file, table_flags);
def->prepare_stage1_typelib(thd, mem_root, type);
}
@ -3125,14 +3117,13 @@ bool Type_handler_string_result::
Column_definition_prepare_stage1(THD *thd,
MEM_ROOT *mem_root,
Column_definition *def,
handler *file,
ulonglong table_flags,
column_definition_type_t type,
const Column_derived_attributes
*derived_attr)
const
{
return def->prepare_charset_for_string(derived_attr) ||
def->prepare_stage1_string(thd, mem_root, file, table_flags);
def->prepare_stage1_string(thd, mem_root);
}
@ -3343,10 +3334,11 @@ bool Type_handler_bit::
handler *file,
ulonglong table_flags) const
{
/*
We have sql_field->pack_flag already set here, see
mysql_prepare_create_table().
*/
if (!(table_flags & HA_CAN_BIT_FIELD))
{
def->pack_flag|= FIELDFLAG_TREAT_BIT_AS_CHAR;
def->create_length_to_internal_length_bit();
}
return false;
}