Commit 69ffc066 authored by Michael Widenius's avatar Michael Widenius

Fixes BUG#60976 "Crash, valgrind warning and memory leak with partitioned archive tables"

Noted that there was no memory leak, just a lot of used partitioned tables.
Fixed old bug: 'show status' now shows memory usage when compiled with safemalloc.
Added option --flush to mysqlcheck.c to run a 'flush tables' between each check to keep down memory usage.
Changed '--safemalloc' options to mysqld so that one can use --safemalloc and --skip-safemalloc.
Now skip-safemalloc is default (ie, we only do checking of memory overrun during free()) to speed up tests.


client/client_priv.h:
  Added OPT_FLUSH_TABLES
client/mysqlcheck.c:
  Added option --flush to mysqlcheck.c to run a 'flush tables' between each check to keep down memory usage.
mysql-test/mysql-test-run.pl:
  Always run tests with --loose-skip-safemysqld for higher speed
sql/mysqld.cc:
  Changed '--safemalloc' options so that one can use --safemalloc and --skip-safemalloc.
  Now skip-safemalloc is default (ie, we only do checking of memory overrun during free()) to speed up tests
sql/sql_parse.cc:
  Fixed old bug: 'show status' now shows memory usage when compiled with safemalloc.
storage/archive/archive_reader.c:
  Changed all malloc() calls to use my_malloc()/my_free()
  Added checks of malloc() calls.
storage/archive/ha_archive.cc:
  Detect failure if init_archive_reader() and return errno. This fixed assert crash in my_seek().
  Changed all malloc() calls to use my_malloc()/my_free()
parent 13f55aac
...@@ -60,6 +60,7 @@ enum options_client ...@@ -60,6 +60,7 @@ enum options_client
OPT_OPEN_FILES_LIMIT, OPT_SET_CHARSET, OPT_SERVER_ARG, OPT_OPEN_FILES_LIMIT, OPT_SET_CHARSET, OPT_SERVER_ARG,
OPT_POSITION, OPT_STOP_POSITION, OPT_START_DATETIME, OPT_STOP_DATETIME, OPT_POSITION, OPT_STOP_POSITION, OPT_START_DATETIME, OPT_STOP_DATETIME,
OPT_SIGINT_IGNORE, OPT_HEXBLOB, OPT_ORDER_BY_PRIMARY, OPT_COUNT, OPT_SIGINT_IGNORE, OPT_HEXBLOB, OPT_ORDER_BY_PRIMARY, OPT_COUNT,
OPT_FLUSH_TABLES,
#ifdef HAVE_NDBCLUSTER_DB #ifdef HAVE_NDBCLUSTER_DB
OPT_NDBCLUSTER, OPT_NDB_CONNECTSTRING, OPT_NDBCLUSTER, OPT_NDB_CONNECTSTRING,
#endif #endif
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
/* By Jani Tolonen, 2001-04-20, MySQL Development Team */ /* By Jani Tolonen, 2001-04-20, MySQL Development Team */
#define CHECK_VERSION "2.6.0" #define CHECK_VERSION "2.7.0"
#include "client_priv.h" #include "client_priv.h"
#include <m_ctype.h> #include <m_ctype.h>
...@@ -35,8 +35,8 @@ static my_bool opt_alldbs = 0, opt_check_only_changed = 0, opt_extended = 0, ...@@ -35,8 +35,8 @@ static my_bool opt_alldbs = 0, opt_check_only_changed = 0, opt_extended = 0,
opt_medium_check = 0, opt_quick = 0, opt_all_in_1 = 0, opt_medium_check = 0, opt_quick = 0, opt_all_in_1 = 0,
opt_silent = 0, opt_auto_repair = 0, ignore_errors = 0, opt_silent = 0, opt_auto_repair = 0, ignore_errors = 0,
tty_password= 0, opt_frm= 0, debug_info_flag= 0, debug_check_flag= 0, tty_password= 0, opt_frm= 0, debug_info_flag= 0, debug_check_flag= 0,
opt_fix_table_names= 0, opt_fix_db_names= 0, opt_upgrade= 0, opt_fix_table_names= 0, opt_fix_db_names= 0, opt_upgrade= 0;
opt_write_binlog= 1; static my_bool opt_write_binlog= 1, opt_flush_tables= 0;
static uint verbose = 0, opt_mysql_port=0; static uint verbose = 0, opt_mysql_port=0;
static int my_end_arg; static int my_end_arg;
static char * opt_mysql_unix_port = 0; static char * opt_mysql_unix_port = 0;
...@@ -121,6 +121,9 @@ static struct my_option my_long_options[] = ...@@ -121,6 +121,9 @@ static struct my_option my_long_options[] =
"If you are using this option with CHECK TABLE, it will ensure that the table is 100 percent consistent, but will take a long time. If you are using this option with REPAIR TABLE, it will force using old slow repair with keycache method, instead of much faster repair by sorting.", "If you are using this option with CHECK TABLE, it will ensure that the table is 100 percent consistent, but will take a long time. If you are using this option with REPAIR TABLE, it will force using old slow repair with keycache method, instead of much faster repair by sorting.",
&opt_extended, &opt_extended, 0, GET_BOOL, NO_ARG, 0, 0, 0, &opt_extended, &opt_extended, 0, GET_BOOL, NO_ARG, 0, 0, 0,
0, 0, 0}, 0, 0, 0},
{"flush", OPT_FLUSH_TABLES, "Flush each table after check. This is useful if you don't want to have the checked tables take up space in the caches after the check",
&opt_flush_tables, &opt_flush_tables, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
0, 0 },
{"help", '?', "Display this help message and exit.", 0, 0, 0, GET_NO_ARG, {"help", '?', "Display this help message and exit.", 0, 0, 0, GET_NO_ARG,
NO_ARG, 0, 0, 0, 0, 0, 0}, NO_ARG, 0, 0, 0, 0, 0, 0},
{"host",'h', "Connect to host.", &current_host, {"host",'h', "Connect to host.", &current_host,
...@@ -685,6 +688,7 @@ static int disable_binlog() ...@@ -685,6 +688,7 @@ static int disable_binlog()
static int handle_request_for_tables(char *tables, uint length) static int handle_request_for_tables(char *tables, uint length)
{ {
char *query, *end, options[100], message[100]; char *query, *end, options[100], message[100];
char table_name_buff[NAME_CHAR_LEN*2*2+1], *table_name;
uint query_length= 0; uint query_length= 0;
const char *op = 0; const char *op = 0;
...@@ -723,13 +727,17 @@ static int handle_request_for_tables(char *tables, uint length) ...@@ -723,13 +727,17 @@ static int handle_request_for_tables(char *tables, uint length)
/* No backticks here as we added them before */ /* No backticks here as we added them before */
query_length= my_sprintf(query, query_length= my_sprintf(query,
(query, "%s TABLE %s %s", op, tables, options)); (query, "%s TABLE %s %s", op, tables, options));
table_name= tables;
} }
else else
{ {
char *ptr; char *ptr, *org;
ptr= strmov(strmov(query, op), " TABLE "); org= ptr= strmov(strmov(query, op), " TABLE ");
ptr= fix_table_name(ptr, tables); ptr= fix_table_name(ptr, tables);
strmake(table_name_buff, org, min((int) sizeof(table_name_buff)-1,
(int) (ptr - org)));
table_name= table_name_buff;
ptr= strxmov(ptr, " ", options, NullS); ptr= strxmov(ptr, " ", options, NullS);
query_length= (uint) (ptr - query); query_length= (uint) (ptr - query);
} }
...@@ -737,9 +745,21 @@ static int handle_request_for_tables(char *tables, uint length) ...@@ -737,9 +745,21 @@ static int handle_request_for_tables(char *tables, uint length)
{ {
sprintf(message, "when executing '%s TABLE ... %s'", op, options); sprintf(message, "when executing '%s TABLE ... %s'", op, options);
DBerror(sock, message); DBerror(sock, message);
my_free(query, MYF(0));
return 1; return 1;
} }
print_result(); print_result();
if (opt_flush_tables)
{
query_length= my_sprintf(query,
(query, "FLUSH TABLES %s", table_name));
if (mysql_real_query(sock, query, query_length))
{
DBerror(sock, query);
my_free(query, MYF(0));
return 1;
}
}
my_free(query, MYF(0)); my_free(query, MYF(0));
return 0; return 0;
} }
......
...@@ -4943,14 +4943,13 @@ sub mysqld_arguments ($$$) { ...@@ -4943,14 +4943,13 @@ sub mysqld_arguments ($$$) {
if ( $opt_valgrind_mysqld ) if ( $opt_valgrind_mysqld )
{ {
mtr_add_arg($args, "--skip-safemalloc");
if ( $mysql_version_id < 50100 ) if ( $mysql_version_id < 50100 )
{ {
mtr_add_arg($args, "--skip-bdb"); mtr_add_arg($args, "--skip-bdb");
} }
} }
mtr_add_arg($args, "--loose-skip-safemalloc");
mtr_add_arg($args, "%s--disable-sync-frm"); mtr_add_arg($args, "%s--disable-sync-frm");
if (!using_extern() and $mysql_version_id >= 50106 && !$opt_user_args) if (!using_extern() and $mysql_version_id >= 50106 && !$opt_user_args)
......
...@@ -2456,7 +2456,7 @@ bool ha_partition::read_par_file(const char *name) ...@@ -2456,7 +2456,7 @@ bool ha_partition::read_par_file(const char *name)
fn_format(buff, name, "", ha_par_ext, MY_APPEND_EXT); fn_format(buff, name, "", ha_par_ext, MY_APPEND_EXT);
/* Following could be done with my_stat to read in whole file */ /* Following could be done with my_stat to read in whole file */
if ((file= my_open(buff, O_RDONLY | O_SHARE, MYF(0))) < 0) if ((file= my_open(buff, O_RDONLY | O_SHARE, MYF(MY_WME))) < 0)
DBUG_RETURN(true); DBUG_RETURN(true);
if (my_read(file, (uchar *) & buff[0], PAR_WORD_SIZE, MYF(MY_NABP))) if (my_read(file, (uchar *) & buff[0], PAR_WORD_SIZE, MYF(MY_NABP)))
goto err1; goto err1;
......
...@@ -427,7 +427,7 @@ static bool volatile ready_to_exit; ...@@ -427,7 +427,7 @@ static bool volatile ready_to_exit;
static my_bool opt_debugging= 0, opt_external_locking= 0, opt_console= 0; static my_bool opt_debugging= 0, opt_external_locking= 0, opt_console= 0;
static my_bool opt_short_log_format= 0; static my_bool opt_short_log_format= 0;
static my_bool opt_ignore_wrong_options= 0, opt_expect_abort= 0; static my_bool opt_ignore_wrong_options= 0, opt_expect_abort= 0;
static my_bool opt_sync= 0; static my_bool opt_sync= 0, sf_malloc_trough_check= 0;
static uint kill_cached_threads, wake_thread; static uint kill_cached_threads, wake_thread;
ulong thread_created; ulong thread_created;
uint thread_handling; uint thread_handling;
...@@ -5944,7 +5944,7 @@ enum options_mysqld ...@@ -5944,7 +5944,7 @@ enum options_mysqld
OPT_NDB_REPORT_THRESH_BINLOG_EPOCH_SLIP, OPT_NDB_REPORT_THRESH_BINLOG_EPOCH_SLIP,
OPT_NDB_REPORT_THRESH_BINLOG_MEM_USAGE, OPT_NDB_REPORT_THRESH_BINLOG_MEM_USAGE,
OPT_NDB_USE_COPYING_ALTER_TABLE, OPT_NDB_USE_COPYING_ALTER_TABLE,
OPT_SKIP_SAFEMALLOC, OPT_MUTEX_DEADLOCK_DETECTOR, OPT_SAFEMALLOC, OPT_MUTEX_DEADLOCK_DETECTOR,
OPT_TEMP_POOL, OPT_TX_ISOLATION, OPT_COMPLETION_TYPE, OPT_TEMP_POOL, OPT_TX_ISOLATION, OPT_COMPLETION_TYPE,
OPT_SKIP_SYMLINKS, OPT_SKIP_SYMLINKS,
OPT_MAX_BINLOG_DUMP_EVENTS, OPT_SPORADIC_BINLOG_DUMP_FAIL, OPT_MAX_BINLOG_DUMP_EVENTS, OPT_SPORADIC_BINLOG_DUMP_FAIL,
...@@ -6898,12 +6898,11 @@ each time the SQL thread starts.", ...@@ -6898,12 +6898,11 @@ each time the SQL thread starts.",
{"skip-networking", OPT_SKIP_NETWORKING, {"skip-networking", OPT_SKIP_NETWORKING,
"Don't allow connection with TCP/IP.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, "Don't allow connection with TCP/IP.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0,
0, 0, 0}, 0, 0, 0},
#ifndef DBUG_OFF #if !defined(DBUG_OFF) && defined(SAFEMALLOC)
#ifdef SAFEMALLOC {"safemalloc", OPT_SAFEMALLOC,
{"skip-safemalloc", OPT_SKIP_SAFEMALLOC, "Check all memory allocation for every malloc/free call.",
"Don't use the memory allocation checking.", 0, 0, 0, GET_NO_ARG, NO_ARG, &sf_malloc_trough_check, &sf_malloc_trough_check, 0,
0, 0, 0, 0, 0, 0}, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
#endif
#endif #endif
{"skip-show-database", OPT_SKIP_SHOW_DB, {"skip-show-database", OPT_SKIP_SHOW_DB,
"Don't allow 'SHOW DATABASE' commands.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, "Don't allow 'SHOW DATABASE' commands.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0,
...@@ -9238,11 +9237,6 @@ mysqld_get_one_option(int optid, ...@@ -9238,11 +9237,6 @@ mysqld_get_one_option(int optid,
} }
strmake(ft_boolean_syntax, argument, sizeof(ft_boolean_syntax)-1); strmake(ft_boolean_syntax, argument, sizeof(ft_boolean_syntax)-1);
break; break;
case OPT_SKIP_SAFEMALLOC:
#ifdef SAFEMALLOC
sf_malloc_quick=1;
#endif
break;
case OPT_LOWER_CASE_TABLE_NAMES: case OPT_LOWER_CASE_TABLE_NAMES:
lower_case_table_names= argument ? atoi(argument) : 1; lower_case_table_names= argument ? atoi(argument) : 1;
lower_case_table_names_used= 1; lower_case_table_names_used= 1;
...@@ -9436,6 +9430,9 @@ static int get_options(int *argc,char **argv) ...@@ -9436,6 +9430,9 @@ static int get_options(int *argc,char **argv)
&global_system_variables.datetime_format)) &global_system_variables.datetime_format))
return 1; return 1;
#ifdef SAFEMALLOC
sf_malloc_quick= !sf_malloc_trough_check;
#endif
#ifdef EMBEDDED_LIBRARY #ifdef EMBEDDED_LIBRARY
one_thread_scheduler(&thread_scheduler); one_thread_scheduler(&thread_scheduler);
one_thread_scheduler(&extra_thread_scheduler); one_thread_scheduler(&extra_thread_scheduler);
......
...@@ -1540,7 +1540,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, ...@@ -1540,7 +1540,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
{ {
char *end= buff + length; char *end= buff + length;
length+= my_snprintf(end, buff_len - length - 1, length+= my_snprintf(end, buff_len - length - 1,
end," Memory in use: %ldK Max memory used: %ldK", " Memory in use: %ldK Max memory used: %ldK",
(sf_malloc_cur_memory+1023L)/1024L, (sf_malloc_cur_memory+1023L)/1024L,
(sf_malloc_max_memory+1023L)/1024L); (sf_malloc_max_memory+1023L)/1024L);
} }
......
...@@ -93,12 +93,16 @@ int main(int argc, char *argv[]) ...@@ -93,12 +93,16 @@ int main(int argc, char *argv[])
printf("\tFRM length %u\n", reader_handle.frm_length); printf("\tFRM length %u\n", reader_handle.frm_length);
if (reader_handle.comment_start_pos) if (reader_handle.comment_start_pos)
{ {
char *comment = char *comment = (char *) my_malloc(reader_handle.comment_length,
(char *) malloc(sizeof(char) * reader_handle.comment_length); MYF(MY_WME));
azread_comment(&reader_handle, comment); if (comment)
printf("\tComment length %u\n\t\t%.*s\n", reader_handle.comment_length, {
reader_handle.comment_length, comment); azread_comment(&reader_handle, comment);
free(comment); printf("\tComment length %u\n\t\t%.*s\n",
reader_handle.comment_length,
reader_handle.comment_length, comment);
my_free(comment,MYF(0));
}
} }
} }
else else
...@@ -180,7 +184,7 @@ int main(int argc, char *argv[]) ...@@ -180,7 +184,7 @@ int main(int argc, char *argv[])
azio_stream writer_handle; azio_stream writer_handle;
buffer= (char *)malloc(reader_handle.longest_row); buffer= (char *) my_malloc(reader_handle.longest_row, MYF(0));
if (buffer == NULL) if (buffer == NULL)
{ {
printf("Could not allocate memory for row %llu\n", row_count); printf("Could not allocate memory for row %llu\n", row_count);
...@@ -251,7 +255,7 @@ int main(int argc, char *argv[]) ...@@ -251,7 +255,7 @@ int main(int argc, char *argv[])
break; break;
} }
free(buffer); my_free(buffer, MYF(0));
azclose(&writer_handle); azclose(&writer_handle);
} }
......
...@@ -835,7 +835,7 @@ int ha_archive::write_row(uchar *buf) ...@@ -835,7 +835,7 @@ int ha_archive::write_row(uchar *buf)
if (!share->archive_write_open) if (!share->archive_write_open)
if (init_archive_writer()) if (init_archive_writer())
DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE); DBUG_RETURN(errno);
if (table->next_number_field && record == table->record[0]) if (table->next_number_field && record == table->record[0])
...@@ -1020,7 +1020,8 @@ int ha_archive::rnd_init(bool scan) ...@@ -1020,7 +1020,8 @@ int ha_archive::rnd_init(bool scan)
if (share->crashed) if (share->crashed)
DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE); DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
init_archive_reader(); if (init_archive_reader())
DBUG_RETURN(errno);
/* We rewind the file so that we can read from the beginning if scan */ /* We rewind the file so that we can read from the beginning if scan */
if (scan) if (scan)
...@@ -1317,7 +1318,8 @@ int ha_archive::optimize(THD* thd, HA_CHECK_OPT* check_opt) ...@@ -1317,7 +1318,8 @@ int ha_archive::optimize(THD* thd, HA_CHECK_OPT* check_opt)
char* frm_string; char* frm_string;
DBUG_ENTER("ha_archive::optimize"); DBUG_ENTER("ha_archive::optimize");
init_archive_reader(); if (init_archive_reader())
DBUG_RETURN(errno);
// now we close both our writer and our reader for the rename // now we close both our writer and our reader for the rename
if (share->archive_write_open) if (share->archive_write_open)
...@@ -1326,7 +1328,7 @@ int ha_archive::optimize(THD* thd, HA_CHECK_OPT* check_opt) ...@@ -1326,7 +1328,7 @@ int ha_archive::optimize(THD* thd, HA_CHECK_OPT* check_opt)
share->archive_write_open= FALSE; share->archive_write_open= FALSE;
} }
if (!(frm_string= (char*) malloc(archive.frm_length))) if (!(frm_string= (char*) my_malloc(archive.frm_length, MYF(0))))
return ENOMEM; return ENOMEM;
azread_frm(&archive, frm_string); azread_frm(&archive, frm_string);
...@@ -1337,12 +1339,12 @@ int ha_archive::optimize(THD* thd, HA_CHECK_OPT* check_opt) ...@@ -1337,12 +1339,12 @@ int ha_archive::optimize(THD* thd, HA_CHECK_OPT* check_opt)
if (!(azopen(&writer, writer_filename, O_CREAT|O_RDWR|O_BINARY))) if (!(azopen(&writer, writer_filename, O_CREAT|O_RDWR|O_BINARY)))
{ {
free(frm_string); my_free(frm_string, MYF(0));
DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE); DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
} }
rc= azwrite_frm(&writer, frm_string, archive.frm_length); rc= azwrite_frm(&writer, frm_string, archive.frm_length);
free(frm_string); my_free(frm_string, MYF(0));
if (rc) if (rc)
{ {
rc= HA_ERR_CRASHED_ON_USAGE; rc= HA_ERR_CRASHED_ON_USAGE;
...@@ -1547,7 +1549,9 @@ int ha_archive::info(uint flag) ...@@ -1547,7 +1549,9 @@ int ha_archive::info(uint flag)
if (flag & HA_STATUS_AUTO) if (flag & HA_STATUS_AUTO)
{ {
init_archive_reader(); if (init_archive_reader())
DBUG_RETURN(errno);
pthread_mutex_lock(&share->mutex); pthread_mutex_lock(&share->mutex);
azflush(&archive, Z_SYNC_FLUSH); azflush(&archive, Z_SYNC_FLUSH);
pthread_mutex_unlock(&share->mutex); pthread_mutex_unlock(&share->mutex);
...@@ -1626,7 +1630,9 @@ int ha_archive::check(THD* thd, HA_CHECK_OPT* check_opt) ...@@ -1626,7 +1630,9 @@ int ha_archive::check(THD* thd, HA_CHECK_OPT* check_opt)
Now we will rewind the archive file so that we are positioned at the Now we will rewind the archive file so that we are positioned at the
start of the file. start of the file.
*/ */
init_archive_reader(); if (init_archive_reader())
DBUG_RETURN(errno);
read_data_header(&archive); read_data_header(&archive);
while (!(rc= get_row(&archive, table->record[0]))) while (!(rc= get_row(&archive, table->record[0])))
count--; count--;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment