diff options
author | Jan Lindström <jan.lindstrom@mariadb.com> | 2021-03-04 14:28:50 +0200 |
---|---|---|
committer | Jan Lindström <jan.lindstrom@mariadb.com> | 2021-03-15 11:56:42 +0200 |
commit | 30dea4599e44e3008fb9bc5fe79ab5747841f21f (patch) | |
tree | cb6b479b5bcc8e82126d5e6f0e35e260666d809c /storage | |
parent | ba7d86a65989eeebd5310c5e5a953805dc513572 (diff) | |
download | mariadb-git-30dea4599e44e3008fb9bc5fe79ab5747841f21f.tar.gz |
MDEV-24978 : SIGABRT in __libc_message
Keyvalue can be longer than REC_VERSION_56_MAX_INDEX_COL_LEN
and this leads out-of-array reference. Use dynamic memory
allocation using actual max length of key value.
Diffstat (limited to 'storage')
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 63 |
1 files changed, 42 insertions, 21 deletions
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 423996c7fb1..56602c68187 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -6730,8 +6730,8 @@ wsrep_innobase_mysql_sort( case MYSQL_TYPE_LONG_BLOB: case MYSQL_TYPE_VARCHAR: { - uchar tmp_str[REC_VERSION_56_MAX_INDEX_COL_LEN] = {'\0'}; - uint tmp_length = REC_VERSION_56_MAX_INDEX_COL_LEN; + uchar *tmp_str; + uint tmp_length; /* Use the charset number to pick the right charset struct for the comparison. Since the MySQL function get_charset may be @@ -6754,7 +6754,11 @@ wsrep_innobase_mysql_sort( } } - ut_a(str_length <= tmp_length); + // Note that strnxfrm may change length of string + tmp_length= charset->coll->strnxfrmlen(charset, str_length); + tmp_length= ut_max(str_length, tmp_length) + 1; + tmp_str= static_cast<uchar *>(ut_malloc_nokey(tmp_length)); + ut_ad(str_length <= tmp_length); memcpy(tmp_str, str, str_length); tmp_length = charset->coll->strnxfrm(charset, str, str_length, @@ -6778,6 +6782,7 @@ wsrep_innobase_mysql_sort( ret_length = tmp_length; } + ut_free(tmp_str); break; } case MYSQL_TYPE_DECIMAL : @@ -7129,7 +7134,7 @@ wsrep_store_key_val_for_row( THD* thd, TABLE* table, uint keynr, /*!< in: key number */ - char* buff, /*!< in/out: buffer for the key value (in MySQL + uchar* buff, /*!< in/out: buffer for the key value (in MySQL format) */ uint buff_len,/*!< in: buffer length */ const uchar* record, @@ -7138,7 +7143,7 @@ wsrep_store_key_val_for_row( KEY* key_info = table->key_info + keynr; KEY_PART_INFO* key_part = key_info->key_part; KEY_PART_INFO* end = key_part + key_info->user_defined_key_parts; - char* buff_start = buff; + uchar* buff_start = buff; enum_field_types mysql_type; Field* field; uint buff_space = buff_len; @@ -7150,7 +7155,8 @@ wsrep_store_key_val_for_row( for (; key_part != end; key_part++) { - uchar sorted[REC_VERSION_56_MAX_INDEX_COL_LEN] = {'\0'}; + uchar *sorted=NULL; + uint max_len=0; ibool part_is_null = FALSE; if (key_part->null_bit) { @@ -7229,10 +7235,14 @@ wsrep_store_key_val_for_row( true_len = key_len; } + max_len= true_len; + sorted= static_cast<uchar *>(ut_malloc_nokey(max_len+1)); memcpy(sorted, data, true_len); true_len = wsrep_innobase_mysql_sort( mysql_type, cs->number, sorted, true_len, - REC_VERSION_56_MAX_INDEX_COL_LEN); + max_len); + ut_ad(true_len <= max_len); + if (wsrep_protocol_version > 1) { /* Note that we always reserve the maximum possible length of the true VARCHAR in the key value, though @@ -7317,11 +7327,13 @@ wsrep_store_key_val_for_row( true_len = key_len; } + max_len= true_len; + sorted= static_cast<uchar *>(ut_malloc_nokey(max_len+1)); memcpy(sorted, blob_data, true_len); true_len = wsrep_innobase_mysql_sort( mysql_type, cs->number, sorted, true_len, - REC_VERSION_56_MAX_INDEX_COL_LEN); - + max_len); + ut_ad(true_len <= max_len); /* Note that we always reserve the maximum possible length of the BLOB prefix in the key value. */ @@ -7397,10 +7409,14 @@ wsrep_store_key_val_for_row( cs->mbmaxlen), &error); } + + max_len= true_len; + sorted= static_cast<uchar *>(ut_malloc_nokey(max_len+1)); memcpy(sorted, src_start, true_len); true_len = wsrep_innobase_mysql_sort( mysql_type, cs->number, sorted, true_len, - REC_VERSION_56_MAX_INDEX_COL_LEN); + max_len); + ut_ad(true_len <= max_len); if (true_len > buff_space) { fprintf (stderr, @@ -7415,6 +7431,11 @@ wsrep_store_key_val_for_row( buff += true_len; buff_space -= true_len; } + + if (sorted) { + ut_free(sorted); + sorted= NULL; + } } ut_a(buff <= buff_start + buff_len); @@ -10492,7 +10513,7 @@ wsrep_append_key( trx_t *trx, TABLE_SHARE *table_share, TABLE *table, - const char* key, + const uchar* key, uint16_t key_len, wsrep_key_type key_type /*!< in: access type of this key (shared, exclusive, semi...) */ @@ -10596,8 +10617,8 @@ ha_innobase::wsrep_append_keys( if (wsrep_protocol_version == 0) { uint len; - char keyval[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'}; - char *key = &keyval[0]; + uchar keyval[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'}; + uchar *key = &keyval[0]; ibool is_null; len = wsrep_store_key_val_for_row( @@ -10629,18 +10650,18 @@ ha_innobase::wsrep_append_keys( for (i=0; i<table->s->keys; ++i) { uint len; - char keyval0[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'}; - char keyval1[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'}; - char* key0 = &keyval0[1]; - char* key1 = &keyval1[1]; + uchar keyval0[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'}; + uchar keyval1[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'}; + uchar* key0 = &keyval0[1]; + uchar* key1 = &keyval1[1]; KEY* key_info = table->key_info + i; ibool is_null; dict_index_t* idx = innobase_get_index(i); dict_table_t* tab = (idx) ? idx->table : NULL; - keyval0[0] = (char)i; - keyval1[0] = (char)i; + keyval0[0] = (uchar)i; + keyval1[0] = (uchar)i; if (!tab) { WSREP_WARN("MariaDB-InnoDB key mismatch %s %s", @@ -10698,7 +10719,7 @@ ha_innobase::wsrep_append_keys( wsrep_calc_row_hash(digest, record0, table, m_prebuilt, thd); if ((rcode = wsrep_append_key(thd, trx, table_share, table, - (const char*) digest, 16, + (const uchar*) digest, 16, key_type))) { DBUG_RETURN(rcode); } @@ -10708,7 +10729,7 @@ ha_innobase::wsrep_append_keys( digest, record1, table, m_prebuilt, thd); if ((rcode = wsrep_append_key(thd, trx, table_share, table, - (const char*) digest, + (const uchar*) digest, 16, key_type))) { DBUG_RETURN(rcode); } |