From b21930fb0fc1a1986adac0e2a911005ad709bfe7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 6 Mar 2019 10:37:43 +0200 Subject: [PATCH 1/5] MDEV-18749: Uninitialized value upon ADD FULLTEXT INDEX row_merge_create_fts_sort_index(): Initialize dict_col_t. This fixes an access to uninitialized dict_col_t::ind when a debug assertion in MariaDB 10.4 invokes is_dropped() in rec_get_converted_size_comp_prefix_low(). Older MariaDB versions seem to be unaffected by the uninitialized values, but it should not hurt to initialize everything. --- storage/innobase/row/row0ftsort.cc | 17 ++++++----------- storage/xtradb/row/row0ftsort.cc | 17 ++++++----------- 2 files changed, 12 insertions(+), 22 deletions(-) diff --git a/storage/innobase/row/row0ftsort.cc b/storage/innobase/row/row0ftsort.cc index 7e6e92ed849fc..6167fdc63d639 100644 --- a/storage/innobase/row/row0ftsort.cc +++ b/storage/innobase/row/row0ftsort.cc @@ -98,8 +98,8 @@ row_merge_create_fts_sort_index( field = dict_index_get_nth_field(new_index, 0); field->name = NULL; field->prefix_len = 0; - field->col = static_cast( - mem_heap_alloc(new_index->heap, sizeof(dict_col_t))); + field->col = new(mem_heap_zalloc(new_index->heap, sizeof(dict_col_t))) + dict_col_t(); field->col->prtype = idx_field->col->prtype | DATA_NOT_NULL; field->col->mtype = charset == &my_charset_latin1 ? DATA_VARCHAR : DATA_VARMYSQL; @@ -113,8 +113,8 @@ row_merge_create_fts_sort_index( field = dict_index_get_nth_field(new_index, 1); field->name = NULL; field->prefix_len = 0; - field->col = static_cast( - mem_heap_alloc(new_index->heap, sizeof(dict_col_t))); + field->col = new(mem_heap_zalloc(new_index->heap, sizeof(dict_col_t))) + dict_col_t(); field->col->mtype = DATA_INT; *opt_doc_id_size = FALSE; @@ -148,21 +148,16 @@ row_merge_create_fts_sort_index( field->col->prtype = DATA_NOT_NULL | DATA_BINARY_TYPE; - field->col->mbminlen = 0; - field->col->mbmaxlen = 0; - /* The third field is on the word's position in the original doc */ field = dict_index_get_nth_field(new_index, 2); field->name = NULL; field->prefix_len = 0; - field->col = static_cast( - mem_heap_alloc(new_index->heap, sizeof(dict_col_t))); + field->col = new(mem_heap_zalloc(new_index->heap, sizeof(dict_col_t))) + dict_col_t(); field->col->mtype = DATA_INT; field->col->len = 4 ; field->fixed_len = 4; field->col->prtype = DATA_NOT_NULL; - field->col->mbminlen = 0; - field->col->mbmaxlen = 0; return(new_index); } diff --git a/storage/xtradb/row/row0ftsort.cc b/storage/xtradb/row/row0ftsort.cc index deae270f7166e..1798f99703350 100644 --- a/storage/xtradb/row/row0ftsort.cc +++ b/storage/xtradb/row/row0ftsort.cc @@ -101,8 +101,8 @@ row_merge_create_fts_sort_index( field = dict_index_get_nth_field(new_index, 0); field->name = NULL; field->prefix_len = 0; - field->col = static_cast( - mem_heap_alloc(new_index->heap, sizeof(dict_col_t))); + field->col = new(mem_heap_zalloc(new_index->heap, sizeof(dict_col_t))) + dict_col_t(); field->col->prtype = idx_field->col->prtype | DATA_NOT_NULL; field->col->mtype = charset == &my_charset_latin1 ? DATA_VARCHAR : DATA_VARMYSQL; @@ -116,8 +116,8 @@ row_merge_create_fts_sort_index( field = dict_index_get_nth_field(new_index, 1); field->name = NULL; field->prefix_len = 0; - field->col = static_cast( - mem_heap_alloc(new_index->heap, sizeof(dict_col_t))); + field->col = new(mem_heap_zalloc(new_index->heap, sizeof(dict_col_t))) + dict_col_t(); field->col->mtype = DATA_INT; *opt_doc_id_size = FALSE; @@ -151,21 +151,16 @@ row_merge_create_fts_sort_index( field->col->prtype = DATA_NOT_NULL | DATA_BINARY_TYPE; - field->col->mbminlen = 0; - field->col->mbmaxlen = 0; - /* The third field is on the word's position in the original doc */ field = dict_index_get_nth_field(new_index, 2); field->name = NULL; field->prefix_len = 0; - field->col = static_cast( - mem_heap_alloc(new_index->heap, sizeof(dict_col_t))); + field->col = new(mem_heap_zalloc(new_index->heap, sizeof(dict_col_t))) + dict_col_t(); field->col->mtype = DATA_INT; field->col->len = 4 ; field->fixed_len = 4; field->col->prtype = DATA_NOT_NULL; - field->col->mbminlen = 0; - field->col->mbmaxlen = 0; return(new_index); } From b7612116850d1968dc34d5a2d7b812ebfecf67f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 6 Mar 2019 11:22:27 +0200 Subject: [PATCH 2/5] MDEV-18659: Fix string truncation/overflow in InnoDB and XtraDB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the warnings issued by GCC 8 -Wstringop-truncation and -Wstringop-overflow in InnoDB and XtraDB. This work is motivated by Jan Lindström. The patch mainly differs from his original one as follows: (1) We remove explicit initialization of stack-allocated string buffers. The minimum amount of initialization that is needed is a terminating NUL character. (2) GCC issues a warning for invoking strncpy(dest, src, sizeof dest) because if strlen(src) >= sizeof dest, there would be no terminating NUL byte in dest. We avoid this problem by invoking strncpy() with a limit that is 1 less than the buffer size, and by always writing NUL to the last byte of the buffer. (3) We replace strncpy() with memcpy() or strcpy() in those cases when the result is functionally equivalent. Note: fts_fetch_index_words() never deals with len==UNIV_SQL_NULL. This was enforced by an assertion that limits the maximum length to FTS_MAX_WORD_LEN. Also, the encoding that InnoDB uses for the compressed fulltext index is not byte-order agnostic, that is, InnoDB data files that use FULLTEXT INDEX are not portable between big-endian and little-endian systems. --- extra/mariabackup/backup_copy.cc | 6 +++--- extra/mariabackup/encryption_plugin.cc | 8 ++++++-- extra/mariabackup/fil_cur.cc | 6 ++++-- extra/mariabackup/xtrabackup.cc | 15 ++++++++------- storage/innobase/dict/dict0dict.cc | 26 ++++++++++++-------------- storage/innobase/fts/fts0opt.cc | 17 +++++++++-------- storage/innobase/include/dict0crea.ic | 10 ++++++---- storage/innobase/row/row0mysql.cc | 8 ++++++-- storage/innobase/srv/srv0start.cc | 7 +++---- storage/xtradb/dict/dict0dict.cc | 26 ++++++++++++-------------- storage/xtradb/fts/fts0opt.cc | 17 +++++++++-------- storage/xtradb/include/dict0crea.ic | 10 ++++++---- storage/xtradb/include/log0online.h | 3 ++- storage/xtradb/log/log0online.cc | 7 ++++--- storage/xtradb/row/row0mysql.cc | 8 ++++++-- storage/xtradb/srv/srv0start.cc | 7 +++---- 16 files changed, 99 insertions(+), 82 deletions(-) diff --git a/extra/mariabackup/backup_copy.cc b/extra/mariabackup/backup_copy.cc index 895ef744ea1c3..a998ebecd41f2 100644 --- a/extra/mariabackup/backup_copy.cc +++ b/extra/mariabackup/backup_copy.cc @@ -501,7 +501,8 @@ datafile_open(const char *file, datafile_cur_t *cursor, uint thread_n) 5.6+. We want to make "local" copies for the backup. */ strncpy(cursor->rel_path, xb_get_relative_path(cursor->abs_path, FALSE), - sizeof(cursor->rel_path)); + (sizeof cursor->rel_path) - 1); + cursor->rel_path[(sizeof cursor->rel_path) - 1] = '\0'; cursor->file = os_file_create_simple_no_error_handling(0, cursor->abs_path, @@ -642,8 +643,7 @@ mkdirp(const char *pathname, int Flags, myf MyFlags) /* make a parent directory path */ if (!(parent= (char *)malloc(len))) return(-1); - strncpy(parent, pathname, len); - parent[len-1]= 0; + memcpy(parent, pathname, len); for (p = parent + strlen(parent); !is_path_separator(*p) && p != parent; p--); diff --git a/extra/mariabackup/encryption_plugin.cc b/extra/mariabackup/encryption_plugin.cc index 8f7741b057a87..b5acd385d0a83 100644 --- a/extra/mariabackup/encryption_plugin.cc +++ b/extra/mariabackup/encryption_plugin.cc @@ -67,7 +67,8 @@ void encryption_plugin_backup_init(MYSQL *mysql) /* Required to load the plugin later.*/ add_to_plugin_load_list(plugin_load.c_str()); - strncpy(opt_plugin_dir, dir, FN_REFLEN); + strncpy(opt_plugin_dir, dir, FN_REFLEN - 1); + opt_plugin_dir[FN_REFLEN - 1] = '\0'; oss << "plugin_dir=" << '"' << dir << '"' << endl; @@ -133,7 +134,10 @@ void encryption_plugin_prepare_init(int argc, char **argv) add_to_plugin_load_list(xb_plugin_load); if (xb_plugin_dir) - strncpy(opt_plugin_dir, xb_plugin_dir, FN_REFLEN); + { + strncpy(opt_plugin_dir, xb_plugin_dir, FN_REFLEN - 1); + opt_plugin_dir[FN_REFLEN - 1] = '\0'; + } char **new_argv = new char *[argc + 1]; new_argv[0] = XTRABACKUP_EXE; diff --git a/extra/mariabackup/fil_cur.cc b/extra/mariabackup/fil_cur.cc index 46465575a4877..ce9aaecfc9cfa 100644 --- a/extra/mariabackup/fil_cur.cc +++ b/extra/mariabackup/fil_cur.cc @@ -152,7 +152,8 @@ xb_fil_cur_open( cursor->space_id = node->space->id; cursor->is_system = !fil_is_user_tablespace_id(node->space->id); - strncpy(cursor->abs_path, node->name, sizeof(cursor->abs_path)); + strncpy(cursor->abs_path, node->name, (sizeof cursor->abs_path) - 1); + cursor->abs_path[(sizeof cursor->abs_path) - 1] = '\0'; /* Get the relative path for the destination tablespace name, i.e. the one that can be appended to the backup root directory. Non-system @@ -160,7 +161,8 @@ xb_fil_cur_open( 5.6+. We want to make "local" copies for the backup. */ strncpy(cursor->rel_path, xb_get_relative_path(cursor->abs_path, cursor->is_system), - sizeof(cursor->rel_path)); + (sizeof cursor->rel_path) - 1); + cursor->rel_path[(sizeof cursor->rel_path) - 1] = '\0'; /* In the backup mode we should already have a tablespace handle created by fil_load_single_table_tablespace() unless it is a system diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index 2d28a6caa84f1..fb897e407e2c7 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -2251,8 +2251,9 @@ check_if_skip_table( return(FALSE); } - strncpy(buf, dbname, FN_REFLEN); - buf[tbname - 1 - dbname] = 0; + strncpy(buf, dbname, FN_REFLEN - 1); + buf[FN_REFLEN - 1] = '\0'; + buf[tbname - 1 - dbname] = '\0'; const skip_database_check_result skip_database = check_if_skip_database(buf); @@ -2260,7 +2261,6 @@ check_if_skip_table( return (TRUE); } - buf[FN_REFLEN - 1] = '\0'; buf[tbname - 1 - dbname] = '.'; /* Check if there's a suffix in the table name. If so, truncate it. We @@ -4990,7 +4990,8 @@ xtrabackup_apply_delta( } dst_path[strlen(dst_path) - 6] = '\0'; - strncpy(space_name, filename, FN_REFLEN); + strncpy(space_name, filename, FN_REFLEN - 1); + space_name[FN_REFLEN - 1] = '\0'; space_name[strlen(space_name) - 6] = 0; if (!get_meta_path(src_path, meta_path)) { @@ -6036,7 +6037,8 @@ xtrabackup_prepare_func(int argc, char ** argv) p = next + 1; } info_file_path[len - 4] = 0; - strncpy(table_name, prev, FN_REFLEN); + strncpy(table_name, prev, FN_REFLEN - 1); + table_name[FN_REFLEN - 1] = '\0'; info_file_path[len - 4] = '.'; @@ -6072,8 +6074,7 @@ xtrabackup_prepare_func(int argc, char ** argv) mach_write_to_4(page , 0x78706f72UL); mach_write_to_4(page + 4, 0x74696e66UL);/*"xportinf"*/ mach_write_to_4(page + 8, n_index); - strncpy((char *) page + 12, - table_name, 500); + strncpy((char *) page + 12, table_name, FN_REFLEN); msg("mariabackup: export metadata of " "table '%s' to file `%s` " diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index 06c6c3effab67..69762bd02ff33 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -1626,15 +1626,8 @@ dict_table_rename_in_cache( ut_ad(mutex_own(&(dict_sys->mutex))); /* store the old/current name to an automatic variable */ - if (strlen(table->name) + 1 <= sizeof(old_name)) { - memcpy(old_name, table->name, strlen(table->name) + 1); - } else { - ut_print_timestamp(stderr); - fprintf(stderr, "InnoDB: too long table name: '%s', " - "max length is %d\n", table->name, - MAX_FULL_NAME_LEN); - ut_error; - } + ut_a(strlen(table->name) < sizeof old_name); + strcpy(old_name, table->name); fold = ut_fold_string(new_name); @@ -1845,7 +1838,7 @@ dict_table_rename_in_cache( ulint db_len; char* old_id; - char old_name_cs_filename[MAX_TABLE_NAME_LEN+20]; + char old_name_cs_filename[MAX_FULL_NAME_LEN+1]; uint errors = 0; /* All table names are internally stored in charset @@ -1862,7 +1855,8 @@ dict_table_rename_in_cache( in old_name_cs_filename */ strncpy(old_name_cs_filename, old_name, - MAX_TABLE_NAME_LEN); + MAX_FULL_NAME_LEN); + old_name_cs_filename[MAX_FULL_NAME_LEN] = '\0'; if (strstr(old_name, TEMP_TABLE_PATH_PREFIX) == NULL) { innobase_convert_to_system_charset( @@ -1884,7 +1878,9 @@ dict_table_rename_in_cache( /* Old name already in my_charset_filename */ strncpy(old_name_cs_filename, old_name, - MAX_TABLE_NAME_LEN); + MAX_FULL_NAME_LEN); + old_name_cs_filename[MAX_FULL_NAME_LEN] + = '\0'; } } @@ -1910,7 +1906,7 @@ dict_table_rename_in_cache( /* This is a generated >= 4.0.18 format id */ - char table_name[MAX_TABLE_NAME_LEN] = ""; + char table_name[MAX_TABLE_NAME_LEN + 1]; uint errors = 0; if (strlen(table->name) > strlen(old_name)) { @@ -1924,6 +1920,7 @@ dict_table_rename_in_cache( /* Convert the table name to UTF-8 */ strncpy(table_name, table->name, MAX_TABLE_NAME_LEN); + table_name[MAX_TABLE_NAME_LEN] = '\0'; innobase_convert_to_system_charset( strchr(table_name, '/') + 1, strchr(table->name, '/') + 1, @@ -1933,9 +1930,10 @@ dict_table_rename_in_cache( /* Table name could not be converted from charset my_charset_filename to UTF-8. This means that the table name - is already in UTF-8 (#mysql#50). */ + is already in UTF-8 (#mysql50#). */ strncpy(table_name, table->name, MAX_TABLE_NAME_LEN); + table_name[MAX_TABLE_NAME_LEN] = '\0'; } /* Replace the prefix 'databasename/tablename' diff --git a/storage/innobase/fts/fts0opt.cc b/storage/innobase/fts/fts0opt.cc index 77293bc867a02..4ef83aefef695 100644 --- a/storage/innobase/fts/fts0opt.cc +++ b/storage/innobase/fts/fts0opt.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2007, 2018, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2016, MariaDB Corporation. All Rights reserved. +Copyright (c) 2016, 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -673,18 +673,17 @@ fts_fetch_index_words( fts_zip_t* zip = static_cast(user_arg); que_node_t* exp = sel_node->select_list; dfield_t* dfield = que_node_get_val(exp); - short len = static_cast(dfield_get_len(dfield)); + + ut_a(dfield_get_len(dfield) <= FTS_MAX_WORD_LEN); + + uint16 len = uint16(dfield_get_len(dfield)); void* data = dfield_get_data(dfield); /* Skip the duplicate words. */ - if (zip->word.f_len == static_cast(len) - && !memcmp(zip->word.f_str, data, len)) { - + if (zip->word.f_len == len && !memcmp(zip->word.f_str, data, len)) { return(TRUE); } - ut_a(len <= FTS_MAX_WORD_LEN); - memcpy(zip->word.f_str, data, len); zip->word.f_len = len; @@ -692,6 +691,9 @@ fts_fetch_index_words( ut_a(zip->zp->next_in == NULL); /* The string is prefixed by len. */ + /* FIXME: This is not byte order agnostic (InnoDB data files + with FULLTEXT INDEX are not portable between little-endian and + big-endian systems!) */ zip->zp->next_in = reinterpret_cast(&len); zip->zp->avail_in = sizeof(len); @@ -715,7 +717,6 @@ fts_fetch_index_words( zip->zp->next_in = static_cast(data); zip->zp->avail_in = len; ut_a(len <= FTS_MAX_WORD_LEN); - len = 0; } break; diff --git a/storage/innobase/include/dict0crea.ic b/storage/innobase/include/dict0crea.ic index 1cbaa47032b55..3eb3ddfa84efe 100644 --- a/storage/innobase/include/dict0crea.ic +++ b/storage/innobase/include/dict0crea.ic @@ -1,6 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -65,11 +66,11 @@ dict_create_add_foreign_id( sprintf(id, "%s_ibfk_%lu", name, (ulong) (*id_nr)++); } else { - char table_name[MAX_TABLE_NAME_LEN + 20] = ""; + char table_name[MAX_TABLE_NAME_LEN + 21]; uint errors = 0; - strncpy(table_name, name, - MAX_TABLE_NAME_LEN + 20); + strncpy(table_name, name, (sizeof table_name) - 1); + table_name[(sizeof table_name) - 1] = '\0'; innobase_convert_to_system_charset( strchr(table_name, '/') + 1, @@ -78,7 +79,8 @@ dict_create_add_foreign_id( if (errors) { strncpy(table_name, name, - MAX_TABLE_NAME_LEN + 20); + (sizeof table_name) - 1); + table_name[(sizeof table_name) - 1] = '\0'; } /* no overflow if number < 1e13 */ diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 2a9ade1da2cfd..a8195b604f2b4 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -5173,11 +5173,12 @@ row_rename_table_for_mysql( if (!new_is_tmp) { /* Rename all constraints. */ - char new_table_name[MAX_TABLE_NAME_LEN] = ""; - char old_table_utf8[MAX_TABLE_NAME_LEN] = ""; + char new_table_name[MAX_TABLE_NAME_LEN + 1]; + char old_table_utf8[MAX_TABLE_NAME_LEN + 1]; uint errors = 0; strncpy(old_table_utf8, old_name, MAX_TABLE_NAME_LEN); + old_table_utf8[MAX_TABLE_NAME_LEN] = '\0'; innobase_convert_to_system_charset( strchr(old_table_utf8, '/') + 1, strchr(old_name, '/') +1, @@ -5188,6 +5189,7 @@ row_rename_table_for_mysql( my_charset_filename to UTF-8. This means that the table name is already in UTF-8 (#mysql#50). */ strncpy(old_table_utf8, old_name, MAX_TABLE_NAME_LEN); + old_table_utf8[MAX_TABLE_NAME_LEN] = '\0'; } info = pars_info_create(); @@ -5198,6 +5200,7 @@ row_rename_table_for_mysql( old_table_utf8); strncpy(new_table_name, new_name, MAX_TABLE_NAME_LEN); + new_table_name[MAX_TABLE_NAME_LEN] = '\0'; innobase_convert_to_system_charset( strchr(new_table_name, '/') + 1, strchr(new_name, '/') +1, @@ -5208,6 +5211,7 @@ row_rename_table_for_mysql( my_charset_filename to UTF-8. This means that the table name is already in UTF-8 (#mysql#50). */ strncpy(new_table_name, new_name, MAX_TABLE_NAME_LEN); + new_table_name[MAX_TABLE_NAME_LEN] = '\0'; } pars_info_add_str_literal(info, "new_table_utf8", new_table_name); diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index 4ce3ea6672d32..b300724e2a90d 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -3,7 +3,7 @@ Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2008, Google Inc. Copyright (c) 2009, Percona Inc. -Copyright (c) 2013, 2017, MariaDB Corporation. +Copyright (c) 2013, 2019, MariaDB Corporation. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -3354,9 +3354,8 @@ srv_get_meta_data_filename( if (strncmp(suffix, ".cfg", suffix_len) == 0) { strcpy(filename, path); } else { - ut_ad(strncmp(suffix, ".ibd", suffix_len) == 0); - - strncpy(filename, path, len - suffix_len); + ut_ad(!strcmp(suffix, ".ibd")); + memcpy(filename, path, len - suffix_len); suffix = filename + (len - suffix_len); strcpy(suffix, ".cfg"); } diff --git a/storage/xtradb/dict/dict0dict.cc b/storage/xtradb/dict/dict0dict.cc index 1c489d13f1a50..4c5117f987e70 100644 --- a/storage/xtradb/dict/dict0dict.cc +++ b/storage/xtradb/dict/dict0dict.cc @@ -1632,15 +1632,8 @@ dict_table_rename_in_cache( ut_ad(mutex_own(&(dict_sys->mutex))); /* store the old/current name to an automatic variable */ - if (strlen(table->name) + 1 <= sizeof(old_name)) { - memcpy(old_name, table->name, strlen(table->name) + 1); - } else { - ut_print_timestamp(stderr); - fprintf(stderr, "InnoDB: too long table name: '%s', " - "max length is %d\n", table->name, - MAX_FULL_NAME_LEN); - ut_error; - } + ut_a(strlen(table->name) < sizeof old_name); + strcpy(old_name, table->name); fold = ut_fold_string(new_name); @@ -1851,7 +1844,7 @@ dict_table_rename_in_cache( ulint db_len; char* old_id; - char old_name_cs_filename[MAX_TABLE_NAME_LEN+20]; + char old_name_cs_filename[MAX_FULL_NAME_LEN+1]; uint errors = 0; /* All table names are internally stored in charset @@ -1868,7 +1861,8 @@ dict_table_rename_in_cache( in old_name_cs_filename */ strncpy(old_name_cs_filename, old_name, - MAX_TABLE_NAME_LEN); + MAX_FULL_NAME_LEN); + old_name_cs_filename[MAX_FULL_NAME_LEN] = '\0'; if (strstr(old_name, TEMP_TABLE_PATH_PREFIX) == NULL) { innobase_convert_to_system_charset( @@ -1890,7 +1884,9 @@ dict_table_rename_in_cache( /* Old name already in my_charset_filename */ strncpy(old_name_cs_filename, old_name, - MAX_TABLE_NAME_LEN); + MAX_FULL_NAME_LEN); + old_name_cs_filename[MAX_FULL_NAME_LEN] + = '\0'; } } @@ -1916,7 +1912,7 @@ dict_table_rename_in_cache( /* This is a generated >= 4.0.18 format id */ - char table_name[MAX_TABLE_NAME_LEN] = ""; + char table_name[MAX_TABLE_NAME_LEN + 1]; uint errors = 0; if (strlen(table->name) > strlen(old_name)) { @@ -1930,6 +1926,7 @@ dict_table_rename_in_cache( /* Convert the table name to UTF-8 */ strncpy(table_name, table->name, MAX_TABLE_NAME_LEN); + table_name[MAX_TABLE_NAME_LEN] = '\0'; innobase_convert_to_system_charset( strchr(table_name, '/') + 1, strchr(table->name, '/') + 1, @@ -1939,9 +1936,10 @@ dict_table_rename_in_cache( /* Table name could not be converted from charset my_charset_filename to UTF-8. This means that the table name - is already in UTF-8 (#mysql#50). */ + is already in UTF-8 (#mysql50#). */ strncpy(table_name, table->name, MAX_TABLE_NAME_LEN); + table_name[MAX_TABLE_NAME_LEN] = '\0'; } /* Replace the prefix 'databasename/tablename' diff --git a/storage/xtradb/fts/fts0opt.cc b/storage/xtradb/fts/fts0opt.cc index 77293bc867a02..4ef83aefef695 100644 --- a/storage/xtradb/fts/fts0opt.cc +++ b/storage/xtradb/fts/fts0opt.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2007, 2018, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2016, MariaDB Corporation. All Rights reserved. +Copyright (c) 2016, 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -673,18 +673,17 @@ fts_fetch_index_words( fts_zip_t* zip = static_cast(user_arg); que_node_t* exp = sel_node->select_list; dfield_t* dfield = que_node_get_val(exp); - short len = static_cast(dfield_get_len(dfield)); + + ut_a(dfield_get_len(dfield) <= FTS_MAX_WORD_LEN); + + uint16 len = uint16(dfield_get_len(dfield)); void* data = dfield_get_data(dfield); /* Skip the duplicate words. */ - if (zip->word.f_len == static_cast(len) - && !memcmp(zip->word.f_str, data, len)) { - + if (zip->word.f_len == len && !memcmp(zip->word.f_str, data, len)) { return(TRUE); } - ut_a(len <= FTS_MAX_WORD_LEN); - memcpy(zip->word.f_str, data, len); zip->word.f_len = len; @@ -692,6 +691,9 @@ fts_fetch_index_words( ut_a(zip->zp->next_in == NULL); /* The string is prefixed by len. */ + /* FIXME: This is not byte order agnostic (InnoDB data files + with FULLTEXT INDEX are not portable between little-endian and + big-endian systems!) */ zip->zp->next_in = reinterpret_cast(&len); zip->zp->avail_in = sizeof(len); @@ -715,7 +717,6 @@ fts_fetch_index_words( zip->zp->next_in = static_cast(data); zip->zp->avail_in = len; ut_a(len <= FTS_MAX_WORD_LEN); - len = 0; } break; diff --git a/storage/xtradb/include/dict0crea.ic b/storage/xtradb/include/dict0crea.ic index 1cbaa47032b55..3eb3ddfa84efe 100644 --- a/storage/xtradb/include/dict0crea.ic +++ b/storage/xtradb/include/dict0crea.ic @@ -1,6 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -65,11 +66,11 @@ dict_create_add_foreign_id( sprintf(id, "%s_ibfk_%lu", name, (ulong) (*id_nr)++); } else { - char table_name[MAX_TABLE_NAME_LEN + 20] = ""; + char table_name[MAX_TABLE_NAME_LEN + 21]; uint errors = 0; - strncpy(table_name, name, - MAX_TABLE_NAME_LEN + 20); + strncpy(table_name, name, (sizeof table_name) - 1); + table_name[(sizeof table_name) - 1] = '\0'; innobase_convert_to_system_charset( strchr(table_name, '/') + 1, @@ -78,7 +79,8 @@ dict_create_add_foreign_id( if (errors) { strncpy(table_name, name, - MAX_TABLE_NAME_LEN + 20); + (sizeof table_name) - 1); + table_name[(sizeof table_name) - 1] = '\0'; } /* no overflow if number < 1e13 */ diff --git a/storage/xtradb/include/log0online.h b/storage/xtradb/include/log0online.h index 2d1febe9b9fc8..1a53b9efa9cd1 100644 --- a/storage/xtradb/include/log0online.h +++ b/storage/xtradb/include/log0online.h @@ -1,6 +1,7 @@ /***************************************************************************** Copyright (c) 2011-2012, Percona Inc. All Rights Reserved. +Copyright (c) 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -146,7 +147,7 @@ struct log_online_bitmap_file_range_struct { size_t count; /*!< Number of files */ /*!< Dynamically-allocated array of info about individual files */ struct files_t { - char name[FN_REFLEN]; /*!< Name of a file */ + char name[OS_FILE_MAX_PATH+1];/*!< Name of a file */ lsn_t start_lsn; /*!< Starting LSN of data in this file */ ulong seq_num; /*!< Sequence number of this diff --git a/storage/xtradb/log/log0online.cc b/storage/xtradb/log/log0online.cc index bc1667e1c2048..b25e2bca71107 100644 --- a/storage/xtradb/log/log0online.cc +++ b/storage/xtradb/log/log0online.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2011-2012 Percona Inc. All Rights Reserved. -Copyright (C) 2016, MariaDB Corporation. +Copyright (C) 2016, 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -1453,8 +1453,9 @@ log_online_setup_bitmap_file_range( bitmap_files->files[array_pos].seq_num = file_seq_num; strncpy(bitmap_files->files[array_pos].name, - bitmap_dir_file_info.name, FN_REFLEN); - bitmap_files->files[array_pos].name[FN_REFLEN - 1] + bitmap_dir_file_info.name, + OS_FILE_MAX_PATH); + bitmap_files->files[array_pos].name[OS_FILE_MAX_PATH] = '\0'; bitmap_files->files[array_pos].start_lsn = file_start_lsn; diff --git a/storage/xtradb/row/row0mysql.cc b/storage/xtradb/row/row0mysql.cc index 93a4db98e7bf8..498a35a86ce28 100644 --- a/storage/xtradb/row/row0mysql.cc +++ b/storage/xtradb/row/row0mysql.cc @@ -5183,11 +5183,12 @@ row_rename_table_for_mysql( if (!new_is_tmp) { /* Rename all constraints. */ - char new_table_name[MAX_TABLE_NAME_LEN] = ""; - char old_table_utf8[MAX_TABLE_NAME_LEN] = ""; + char new_table_name[MAX_TABLE_NAME_LEN + 1]; + char old_table_utf8[MAX_TABLE_NAME_LEN + 1]; uint errors = 0; strncpy(old_table_utf8, old_name, MAX_TABLE_NAME_LEN); + old_table_utf8[MAX_TABLE_NAME_LEN] = '\0'; innobase_convert_to_system_charset( strchr(old_table_utf8, '/') + 1, strchr(old_name, '/') +1, @@ -5198,6 +5199,7 @@ row_rename_table_for_mysql( my_charset_filename to UTF-8. This means that the table name is already in UTF-8 (#mysql#50). */ strncpy(old_table_utf8, old_name, MAX_TABLE_NAME_LEN); + old_table_utf8[MAX_TABLE_NAME_LEN] = '\0'; } info = pars_info_create(); @@ -5208,6 +5210,7 @@ row_rename_table_for_mysql( old_table_utf8); strncpy(new_table_name, new_name, MAX_TABLE_NAME_LEN); + new_table_name[MAX_TABLE_NAME_LEN] = '\0'; innobase_convert_to_system_charset( strchr(new_table_name, '/') + 1, strchr(new_name, '/') +1, @@ -5218,6 +5221,7 @@ row_rename_table_for_mysql( my_charset_filename to UTF-8. This means that the table name is already in UTF-8 (#mysql#50). */ strncpy(new_table_name, new_name, MAX_TABLE_NAME_LEN); + new_table_name[MAX_TABLE_NAME_LEN] = '\0'; } pars_info_add_str_literal(info, "new_table_utf8", new_table_name); diff --git a/storage/xtradb/srv/srv0start.cc b/storage/xtradb/srv/srv0start.cc index 2553d405a19eb..941feeb70c7bb 100644 --- a/storage/xtradb/srv/srv0start.cc +++ b/storage/xtradb/srv/srv0start.cc @@ -3,7 +3,7 @@ Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2008, Google Inc. Copyright (c) 2009, Percona Inc. -Copyright (c) 2013, 2017, MariaDB Corporation +Copyright (c) 2013, 2019, MariaDB Corporation. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -3476,9 +3476,8 @@ srv_get_meta_data_filename( if (strncmp(suffix, ".cfg", suffix_len) == 0) { strcpy(filename, path); } else { - ut_ad(strncmp(suffix, ".ibd", suffix_len) == 0); - - strncpy(filename, path, len - suffix_len); + ut_ad(!strcmp(suffix, ".ibd")); + memcpy(filename, path, len - suffix_len); suffix = filename + (len - suffix_len); strcpy(suffix, ".cfg"); } From 4b5dc47f569f766287bd8f4801ab6b865868d01a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 6 Mar 2019 12:45:54 +0200 Subject: [PATCH 3/5] MDEV-18659: Revert a non-functional change fts_fetch_index_words(): Restore the initialization len=0. The test innodb_fts.create in 10.2 would end up in an infinite loop if this assignment is removed, because a following iteration of the while() loop would assign zip->zp->avail_in=len with the original value instead of the 0 that was reset in the previous iteration. --- storage/innobase/fts/fts0opt.cc | 4 ++-- storage/xtradb/fts/fts0opt.cc | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/storage/innobase/fts/fts0opt.cc b/storage/innobase/fts/fts0opt.cc index 4ef83aefef695..28e704eb9a585 100644 --- a/storage/innobase/fts/fts0opt.cc +++ b/storage/innobase/fts/fts0opt.cc @@ -717,15 +717,15 @@ fts_fetch_index_words( zip->zp->next_in = static_cast(data); zip->zp->avail_in = len; ut_a(len <= FTS_MAX_WORD_LEN); + len = 0; } - break; + continue; case Z_STREAM_END: case Z_BUF_ERROR: case Z_STREAM_ERROR: default: ut_error; - break; } } diff --git a/storage/xtradb/fts/fts0opt.cc b/storage/xtradb/fts/fts0opt.cc index 4ef83aefef695..28e704eb9a585 100644 --- a/storage/xtradb/fts/fts0opt.cc +++ b/storage/xtradb/fts/fts0opt.cc @@ -717,15 +717,15 @@ fts_fetch_index_words( zip->zp->next_in = static_cast(data); zip->zp->avail_in = len; ut_a(len <= FTS_MAX_WORD_LEN); + len = 0; } - break; + continue; case Z_STREAM_END: case Z_BUF_ERROR: case Z_STREAM_ERROR: default: ut_error; - break; } } From 485dcb07d12db2309e21b06d46b3156a765495cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 6 Mar 2019 14:46:58 +0200 Subject: [PATCH 4/5] MDEV-18637 Assertion `cache' failed in fts_init_recover_doc I know no test case for this bug in 10.1. So a test case will be committed separately in 10.2 fts_reset_get_doc(): properly initialize fts_get_doc_t::cache --- storage/innobase/fts/fts0fts.cc | 8 +++++--- storage/xtradb/fts/fts0fts.cc | 13 ++++++++----- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/storage/innobase/fts/fts0fts.cc b/storage/innobase/fts/fts0fts.cc index 75258bb861096..1ea3a8d2c6002 100644 --- a/storage/innobase/fts/fts0fts.cc +++ b/storage/innobase/fts/fts0fts.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2011, 2018, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2016, 2018, MariaDB Corporation. +Copyright (c) 2016, 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -736,6 +736,7 @@ fts_reset_get_doc( memset(get_doc, 0x0, sizeof(*get_doc)); get_doc->index_cache = ind_cache; + get_doc->cache = cache; } ut_ad(ib_vector_size(cache->get_docs) @@ -4801,8 +4802,9 @@ fts_tokenize_document( ut_a(!doc->tokens); ut_a(doc->charset); - doc->tokens = rbt_create_arg_cmp( - sizeof(fts_token_t), innobase_fts_text_cmp, (void*) doc->charset); + doc->tokens = rbt_create_arg_cmp(sizeof(fts_token_t), + innobase_fts_text_cmp, + (void*) doc->charset); for (ulint i = 0; i < doc->text.f_len; i += inc) { inc = fts_process_token(doc, result, i, 0); diff --git a/storage/xtradb/fts/fts0fts.cc b/storage/xtradb/fts/fts0fts.cc index 02d81551e755d..1ea3a8d2c6002 100644 --- a/storage/xtradb/fts/fts0fts.cc +++ b/storage/xtradb/fts/fts0fts.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2011, 2018, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2016, 2018, MariaDB Corporation. +Copyright (c) 2016, 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -567,7 +567,7 @@ fts_index_cache_init( index_cache->words = rbt_create_arg_cmp( sizeof(fts_tokenizer_word_t), innobase_fts_text_cmp, - (void*)index_cache->charset); + (void*) index_cache->charset); ut_a(index_cache->doc_stats == NULL); @@ -736,6 +736,7 @@ fts_reset_get_doc( memset(get_doc, 0x0, sizeof(*get_doc)); get_doc->index_cache = ind_cache; + get_doc->cache = cache; } ut_ad(ib_vector_size(cache->get_docs) @@ -2004,7 +2005,8 @@ fts_create_one_index_table( dict_mem_table_add_col(new_table, heap, "ilist", DATA_BLOB, 4130048, 0); - error = row_create_table_for_mysql(new_table, trx, false, FIL_ENCRYPTION_DEFAULT, FIL_DEFAULT_ENCRYPTION_KEY); + error = row_create_table_for_mysql(new_table, trx, false, + FIL_ENCRYPTION_DEFAULT, FIL_DEFAULT_ENCRYPTION_KEY); if (error != DB_SUCCESS) { trx->error_state = error; @@ -4800,8 +4802,9 @@ fts_tokenize_document( ut_a(!doc->tokens); ut_a(doc->charset); - doc->tokens = rbt_create_arg_cmp( - sizeof(fts_token_t), innobase_fts_text_cmp, (void*) doc->charset); + doc->tokens = rbt_create_arg_cmp(sizeof(fts_token_t), + innobase_fts_text_cmp, + (void*) doc->charset); for (ulint i = 0; i < doc->text.f_len; i += inc) { inc = fts_process_token(doc, result, i, 0); From 26f0d72a3f9b92574b16fc0348f79f16ed8021d0 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Wed, 6 Mar 2019 17:08:03 +0400 Subject: [PATCH 5/5] A cleanup for MDEV-18333 Slow_queries count doesn't increase when slow_query_log is turned off thd->lex->m_sql_cmd was not cleared between queries. log_slow_query() could crash (when running mtr --ps) because of this. --- sql/sql_parse.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index b6ad9fa2be3bc..8da2a257df7e4 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1989,6 +1989,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd, dec_thread_running(); thd->packet.shrink(thd->variables.net_buffer_length); // Reclaim some memory thd->reset_kill_query(); /* Ensure that killed_errmsg is released */ + /* + LEX::m_sql_cmd can point to Sql_cmd allocated on thd->mem_root. + Unlink it now, before freeing the root. + */ + thd->lex->m_sql_cmd= NULL; free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC)); #if defined(ENABLED_PROFILING)