Skip to content

Commit c51237c

Browse files
BUG#31360522 : >=5.6.36 SOME RANGE QUERIES STILL CRASH...
DESCRIPTION: ============ Certain range queries on a table with index prefixed BLOB/TEXT columns could lead to a server exit. ANALYSIS: ========= While opening the table based on its table share, in open_table_from_share(), we create a copy of the key_info from TABLE_SHARE object to TABLE object. If the key is prefixed, we allocate a new Field object, having its field_length set to the prefix key length, and point the table's matching key_part->field to this new Field object. We skip creating the new Field object for prefixed BLOB columns. A secondary key is extended by adding primary key parts to it if the primary key part does not exist in the secondary key or the key part in the secondary key is a prefix of the key field (add_pk_parts_to_sk()). The consequence of skipping the creation of new Field object for prefixed BLOB columns is that the key parts from the secondary key and primary key will be pointing to the same Field object. Later, while performing end-range scan, we check if the key is within range (compare_key_in_buffer()). We change the offsets of all the fields in the key range to make the fields point to the record buffer (move_key_field_offsets()). In case of BLOBs, we end up moving the same field twice in move_key_field_offsets(). This leads to accessing out of bound memory while performing key comparison. FIX: ==== We allow creating new Field object even for BLOB columns in open_table_from_share(). When a table with index prefixed BLOB columns is evicted from Table cache, Field_blob objects are free'd by clearing the Table's mem_root in closefrm(). However, since Field_blob::value is allocated on the heap, a specific cleanup to free the Field_blob objects has been added in closefrm(). Note: ===== This issue is not a regression but rather was exposed in 5.6.36 by the patch for Bug#23481444: OPTIMISER CALL ROW_SEARCH_MVCC() AND READ THE INDEX APPLIED BY UNCOMMITTED ROWS. Change-Id: Ie0ecdb801b6cf81783c0cbd9a52d709fd3abdb30
1 parent 3d680eb commit c51237c

File tree

2 files changed

+45
-1
lines changed

2 files changed

+45
-1
lines changed

sql/sql_partition.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -834,6 +834,12 @@ static bool handle_list_of_fields(List_iterator<char> it,
834834
for (i= 0; i < num_key_parts; i++)
835835
{
836836
Field *field= table->key_info[primary_key].key_part[i].field;
837+
// BLOB/TEXT columns are not allowed in partitioning keys.
838+
if (field->flags & BLOB_FLAG)
839+
{
840+
my_error(ER_BLOB_FIELD_IN_PART_FUNC_ERROR, MYF(0));
841+
DBUG_RETURN(TRUE);
842+
}
837843
field->flags|= GET_FIXED_FIELDS_FLAG;
838844
}
839845
}

sql/table.cc

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3241,8 +3241,15 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias,
32413241
{
32423242
Field *field= key_part->field= outparam->field[key_part->fieldnr-1];
32433243

3244+
/*
3245+
For spatial indexes, the key parts are assigned the length (4 *
3246+
sizeof(double)) in mysql_prepare_create_table() and the
3247+
field->key_length() is set to 0. This makes it appear like a prefixed
3248+
index. However, prefixed indexes are not allowed on Geometric columns.
3249+
Hence skipping new field creation for Geometric columns.
3250+
*/
32443251
if (field->key_length() != key_part->length &&
3245-
!(field->flags & BLOB_FLAG))
3252+
field->type() != MYSQL_TYPE_GEOMETRY)
32463253
{
32473254
/*
32483255
We are using only a prefix of the column as a key:
@@ -3512,6 +3519,37 @@ int closefrm(TABLE *table, bool free_share)
35123519
error=table->file->ha_close();
35133520
my_free((void *) table->alias);
35143521
table->alias= 0;
3522+
3523+
/*
3524+
Iterate through the Table's Key_info and free its key_part->field if the
3525+
field is of BLOB type.
3526+
3527+
When a prefixed key is present, a new Field object is created in
3528+
open_table_from_share(). These field objects get destroyed when the Table's
3529+
mem_root is cleared here later. In case of Field_blob objects,
3530+
Field_blob::value is allocated on the heap. Thus Field_blob objects are
3531+
freed here in order to destruct the Field_blob::value object.
3532+
*/
3533+
KEY *key_info= table->key_info;
3534+
if (key_info)
3535+
{
3536+
KEY_PART_INFO *key_part= key_info->key_part;
3537+
for (KEY *key_info_end= key_info + table->s->keys; key_info < key_info_end;
3538+
key_info++)
3539+
{
3540+
for (KEY_PART_INFO *key_part_end= key_part + key_info->actual_key_parts;
3541+
key_part < key_part_end; key_part++)
3542+
{
3543+
if (key_part->field && (key_part->field->flags & BLOB_FLAG) &&
3544+
key_part->field->type() != MYSQL_TYPE_GEOMETRY)
3545+
{
3546+
delete key_part->field;
3547+
key_part->field= 0;
3548+
}
3549+
}
3550+
}
3551+
}
3552+
35153553
if (table->field)
35163554
{
35173555
for (Field **ptr=table->field ; *ptr ; ptr++)

0 commit comments

Comments
 (0)