Skip to content

Commit

Permalink
Bug#34043: Server loops excessively in _checkchunk() when safemalloc …
Browse files Browse the repository at this point in the history
…is enabled

Essentially, the problem is that safemalloc is excruciatingly
slow as it checks all allocated blocks for overrun at each
memory management primitive, yielding a almost exponential
slowdown for the memory management functions (malloc, realloc,
free). The overrun check basically consists of verifying some
bytes of a block for certain magic keys, which catches some
simple forms of overrun. Another minor problem is violation
of aliasing rules and that its own internal list of blocks
is prone to corruption.

Another issue with safemalloc is rather the maintenance cost
as the tool has a significant impact on the server code.
Given the magnitude of memory debuggers available nowadays,
especially those that are provided with the platform malloc
implementation, maintenance of a in-house and largely obsolete
memory debugger becomes a burden that is not worth the effort
due to its slowness and lack of support for detecting more
common forms of heap corruption.

Since there are third-party tools that can provide the same
functionality at a lower or comparable performance cost, the
solution is to simply remove safemalloc. Third-party tools
can provide the same functionality at a lower or comparable
performance cost. 

The removal of safemalloc also allows a simplification of the
malloc wrappers, removing quite a bit of kludge: redefinition
of my_malloc, my_free and the removal of the unused second
argument of my_free. Since free() always check whether the
supplied pointer is null, redudant checks are also removed.

Also, this patch adds unit testing for my_malloc and moves
my_realloc implementation into the same file as the other
memory allocation primitives.
--BZR--
revision-id: [email protected]
property-branch-nick: 34043-trunk
property-file-info: ld7:file_id64:sp1f-mysqldump.c-19700101030959-thxq2iabzu3yo5snymsubfeclf7v5rac7:message120:Pass my_free directly as its signature is compatible with the
property-file-info: callback type -- which wasn't the case for free_table_ent.4:path18:client/mysqldump.cee
testament3-sha1: de838c2bc9f5d5dfd596a0b41de6379c65703010
  • Loading branch information
Davi Arnaut authored and Davi Arnaut committed Jul 8, 2010
1 parent 8735c71 commit d4a0c69
Show file tree
Hide file tree
Showing 218 changed files with 1,012 additions and 1,821 deletions.
Binary file modified .bzrfileids
Binary file not shown.
4 changes: 2 additions & 2 deletions BUILD/SETUP.sh
Original file line number Diff line number Diff line change
Expand Up @@ -122,13 +122,13 @@ fi
# Override -DFORCE_INIT_OF_VARS from debug_cflags. It enables the macro
# LINT_INIT(), which is only useful for silencing spurious warnings
# of static analysis tools. We want LINT_INIT() to be a no-op in Valgrind.
valgrind_flags="-USAFEMALLOC -UFORCE_INIT_OF_VARS -DHAVE_purify "
valgrind_flags="-UFORCE_INIT_OF_VARS -DHAVE_purify "
valgrind_flags="$valgrind_flags -DMYSQL_SERVER_SUFFIX=-valgrind-max"
valgrind_configs="--with-valgrind"
#
# Used in -debug builds
debug_cflags="-DUNIV_MUST_NOT_INLINE -DEXTRA_DEBUG -DFORCE_INIT_OF_VARS "
debug_cflags="$debug_cflags -DSAFEMALLOC -DPEDANTIC_SAFEMALLOC -DSAFE_MUTEX"
debug_cflags="$debug_cflags -DSAFE_MUTEX"
error_inject="--with-error-inject "
#
# Base C++ flags for all builds
Expand Down
4 changes: 2 additions & 2 deletions BUILD/build_mccge.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1010,7 +1010,7 @@ set_ccache_usage()
set_valgrind_flags()
{
if test "x$valgrind_flag" = "xyes" ; then
loc_valgrind_flags="-USAFEMALLOC -UFORCE_INIT_OF_VARS -DHAVE_purify "
loc_valgrind_flags="-UFORCE_INIT_OF_VARS -DHAVE_purify "
loc_valgrind_flags="$loc_valgrind_flags -DMYSQL_SERVER_SUFFIX=-valgrind-max"
compiler_flags="$compiler_flags $loc_valgrind_flags"
with_flags="$with_flags --with-valgrind"
Expand Down Expand Up @@ -1066,7 +1066,7 @@ set_with_debug_flags()
if test "x$with_debug_flag" = "xyes" ; then
if test "x$developer_flag" = "xyes" ; then
loc_debug_flags="-DUNIV_MUST_NOT_INLINE -DEXTRA_DEBUG -DFORCE_INIT_OF_VARS "
loc_debug_flags="$loc_debug_flags -DSAFEMALLOC -DPEDANTIC_SAFEMALLOC"
loc_debug_flags="$loc_debug_flags"
compiler_flags="$compiler_flags $loc_debug_flags"
fi
fi
Expand Down
2 changes: 1 addition & 1 deletion BUILD/compile-ia64-debug-max
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ gmake -k maintainer-clean || true
path=`dirname $0`
. "$path/autorun.sh"

CC=ecc CFLAGS="-w1 -DEXTRA_DEBUG -DSAFEMALLOC -DSAFE_MUTEX -O2" CXX=ecc CXXFLAGS="-w1 -DEXTRA_DEBUG -DSAFEMALLOC -DSAFE_MUTEX -O2" ./configure --prefix=/usr/local/mysql --with-extra-charsets=complex --enable-thread-safe-client --with-mysqld-ldflags=-all-static --with-client-ldflags=-all-static --with-debug --with-innodb --with-embedded-server --with-archive-storage-engine
CC=ecc CFLAGS="-w1 -DEXTRA_DEBUG -DSAFE_MUTEX -O2" CXX=ecc CXXFLAGS="-w1 -DEXTRA_DEBUG -DSAFE_MUTEX -O2" ./configure --prefix=/usr/local/mysql --with-extra-charsets=complex --enable-thread-safe-client --with-mysqld-ldflags=-all-static --with-client-ldflags=-all-static --with-debug --with-innodb --with-embedded-server --with-archive-storage-engine
gmake
9 changes: 4 additions & 5 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ ENDIF()
SET(CUSTOM_C_FLAGS $ENV{CFLAGS})

OPTION(WITH_DEBUG "Use dbug/safemutex" OFF)
OPTION(WITH_DEBUG_FULL "Use dbug and safemalloc/safemutex. Slow" OFF)
OPTION(WITH_DEBUG_FULL "Use dbug and safemutex. Slow." OFF)

# Distinguish between community and non-community builds, with the
# default being a community build. This does not impact the feature
Expand Down Expand Up @@ -175,14 +175,13 @@ IF(NOT CMAKE_BUILD_TYPE
ENDIF()
ENDIF()

# Add safemalloc and safemutex for debug condifurations, except on Windows
# (C runtime library provides safemalloc functionality and safemutex has never
# worked there)
# Add safemutex for debug configurations, except on Windows
# (safemutex has never worked on Windows)
IF(WITH_DEBUG OR WITH_DEBUG_FULL AND NOT WIN32)
FOREACH(LANG C CXX)
IF(WITH_DEBUG_FULL)
SET(CMAKE_${LANG}_FLAGS_DEBUG
"${CMAKE_${LANG}_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
"${CMAKE_${LANG}_FLAGS_DEBUG} -DSAFE_MUTEX")
ELSE()
SET(CMAKE_${LANG}_FLAGS_DEBUG
"${CMAKE_${LANG}_FLAGS_DEBUG} -DSAFE_MUTEX")
Expand Down
3 changes: 1 addition & 2 deletions client/completion_hash.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@

#include <my_global.h>
#include <m_string.h>
#undef SAFEMALLOC // Speed things up
#include <my_sys.h>
#include "completion_hash.h"

Expand Down Expand Up @@ -213,7 +212,7 @@ void completion_hash_clean(HashTable *ht)
void completion_hash_free(HashTable *ht)
{
completion_hash_clean(ht);
my_free(ht->arBuckets, MYF(0));
my_free(ht->arBuckets);
}


Expand Down
48 changes: 24 additions & 24 deletions client/mysql.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1205,7 +1205,7 @@ int main(int argc,char *argv[])
strncmp(link_name, "/dev/null", 10) == 0)
{
/* The .mysql_history file is a symlink to /dev/null, don't use it */
my_free(histfile, MYF(MY_ALLOW_ZERO_PTR));
my_free(histfile);
histfile= 0;
}
}
Expand Down Expand Up @@ -1266,23 +1266,23 @@ sig_handler mysql_end(int sig)
glob_buffer.free();
old_buffer.free();
processed_prompt.free();
my_free(server_version,MYF(MY_ALLOW_ZERO_PTR));
my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR));
my_free(opt_mysql_unix_port,MYF(MY_ALLOW_ZERO_PTR));
my_free(histfile,MYF(MY_ALLOW_ZERO_PTR));
my_free(histfile_tmp,MYF(MY_ALLOW_ZERO_PTR));
my_free(current_db,MYF(MY_ALLOW_ZERO_PTR));
my_free(current_host,MYF(MY_ALLOW_ZERO_PTR));
my_free(current_user,MYF(MY_ALLOW_ZERO_PTR));
my_free(full_username,MYF(MY_ALLOW_ZERO_PTR));
my_free(part_username,MYF(MY_ALLOW_ZERO_PTR));
my_free(default_prompt,MYF(MY_ALLOW_ZERO_PTR));
my_free(server_version);
my_free(opt_password);
my_free(opt_mysql_unix_port);
my_free(histfile);
my_free(histfile_tmp);
my_free(current_db);
my_free(current_host);
my_free(current_user);
my_free(full_username);
my_free(part_username);
my_free(default_prompt);
#ifdef HAVE_SMEM
my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR));
my_free(shared_memory_base_name);
#endif
my_free(current_prompt,MYF(MY_ALLOW_ZERO_PTR));
my_free(current_prompt);
while (embedded_server_arg_count > 1)
my_free(embedded_server_args[--embedded_server_arg_count],MYF(0));
my_free(embedded_server_args[--embedded_server_arg_count]);
mysql_server_end();
free_defaults(defaults_argv);
my_end(my_end_arg);
Expand Down Expand Up @@ -1736,7 +1736,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
if (argument)
{
char *start= argument;
my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR));
my_free(opt_password);
opt_password= my_strdup(argument, MYF(MY_FAE));
while (*argument) *argument++= 'x'; // Destroy argument
if (*start)
Expand Down Expand Up @@ -1833,7 +1833,7 @@ static int get_options(int argc, char **argv)
if (argc == 1)
{
skip_updates= 0;
my_free(current_db, MYF(MY_ALLOW_ZERO_PTR));
my_free(current_db);
current_db= my_strdup(*argv, MYF(MY_WME));
}
if (tty_password)
Expand Down Expand Up @@ -2731,7 +2731,7 @@ static void get_current_db()
{
MYSQL_RES *res;

my_free(current_db, MYF(MY_ALLOW_ZERO_PTR));
my_free(current_db);
current_db= NULL;
/* In case of error below current_db will be NULL */
if (!mysql_query(&mysql, "SELECT DATABASE()") &&
Expand Down Expand Up @@ -4023,12 +4023,12 @@ com_connect(String *buffer, char *line)
tmp= get_arg(buff, 0);
if (tmp && *tmp)
{
my_free(current_db, MYF(MY_ALLOW_ZERO_PTR));
my_free(current_db);
current_db= my_strdup(tmp, MYF(MY_WME));
tmp= get_arg(buff, 1);
if (tmp)
{
my_free(current_host,MYF(MY_ALLOW_ZERO_PTR));
my_free(current_host);
current_host=my_strdup(tmp,MYF(MY_WME));
}
}
Expand Down Expand Up @@ -4200,7 +4200,7 @@ com_use(String *buffer __attribute__((unused)), char *line)
if (mysql_select_db(&mysql,tmp))
return put_error(&mysql);
}
my_free(current_db,MYF(MY_ALLOW_ZERO_PTR));
my_free(current_db);
current_db=my_strdup(tmp,MYF(MY_WME));
#ifdef HAVE_READLINE
if (select_db > 1)
Expand Down Expand Up @@ -4952,8 +4952,8 @@ static void add_int_to_prompt(int toadd)

static void init_username()
{
my_free(full_username,MYF(MY_ALLOW_ZERO_PTR));
my_free(part_username,MYF(MY_ALLOW_ZERO_PTR));
my_free(full_username);
my_free(part_username);

MYSQL_RES *result;
LINT_INIT(result);
Expand All @@ -4971,7 +4971,7 @@ static int com_prompt(String *buffer, char *line)
{
char *ptr=strchr(line, ' ');
prompt_counter = 0;
my_free(current_prompt,MYF(MY_ALLOW_ZERO_PTR));
my_free(current_prompt);
current_prompt=my_strdup(ptr ? ptr+1 : default_prompt,MYF(MY_WME));
if (!ptr)
tee_fprintf(stdout, "Returning to default PROMPT of %s\n", default_prompt);
Expand Down
12 changes: 6 additions & 6 deletions client/mysqladmin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
if (argument)
{
char *start=argument;
my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR));
my_free(opt_password);
opt_password=my_strdup(argument,MYF(MY_FAE));
while (*argument) *argument++= 'x'; /* Destroy argument */
if (*start)
Expand Down Expand Up @@ -448,10 +448,10 @@ int main(int argc,char *argv[])
} /* got connection */

mysql_close(&mysql);
my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR));
my_free(user,MYF(MY_ALLOW_ZERO_PTR));
my_free(opt_password);
my_free(user);
#ifdef HAVE_SMEM
my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR));
my_free(shared_memory_base_name);
#endif
free_defaults(save_argv);
my_end(my_end_arg);
Expand Down Expand Up @@ -1008,8 +1008,8 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv)
/* free up memory from prompted password */
if (typed_password != argv[1])
{
my_free(typed_password,MYF(MY_ALLOW_ZERO_PTR));
my_free(verified,MYF(MY_ALLOW_ZERO_PTR));
my_free(typed_password);
my_free(verified);
}
argc--; argv++;
break;
Expand Down
34 changes: 17 additions & 17 deletions client/mysqlbinlog.cc
Original file line number Diff line number Diff line change
Expand Up @@ -68,20 +68,20 @@ TYPELIB base64_output_mode_typelib=
{ array_elements(base64_output_mode_names) - 1, "",
base64_output_mode_names, NULL };
static enum_base64_output_mode opt_base64_output_mode= BASE64_OUTPUT_UNSPEC;
static const char *opt_base64_output_mode_str= NullS;
static const char* database= 0;
static char *opt_base64_output_mode_str= NullS;
static char* database= 0;
static my_bool force_opt= 0, short_form= 0, remote_opt= 0;
static my_bool debug_info_flag, debug_check_flag;
static my_bool force_if_open_opt= 1;
static ulonglong offset = 0;
static const char* host = 0;
static char* host = 0;
static int port= 0;
static uint my_end_arg;
static const char* sock= 0;
#ifdef HAVE_SMEM
static char *shared_memory_base_name= 0;
#endif
static const char* user = 0;
static char* user = 0;
static char* pass = 0;
static char *charset= 0;

Expand All @@ -96,7 +96,7 @@ static my_time_t start_datetime= 0, stop_datetime= MY_TIME_T_MAX;
static ulonglong rec_count= 0;
static short binlog_flags = 0;
static MYSQL* mysql = NULL;
static const char* dirname_for_local_load= 0;
static char* dirname_for_local_load= 0;

/**
Pointer to the Format_description_log_event of the currently active binlog.
Expand Down Expand Up @@ -191,7 +191,7 @@ class Load_log_processor
int init()
{
return init_dynamic_array(&file_names, sizeof(File_name_record),
100,100 CALLER_INFO);
100, 100);
}

void init_by_dir_name(const char *dir)
Expand All @@ -213,7 +213,7 @@ class Load_log_processor
{
if (ptr->fname)
{
my_free(ptr->fname, MYF(MY_WME));
my_free(ptr->fname);
delete ptr->event;
bzero((char *)ptr, sizeof(File_name_record));
}
Expand Down Expand Up @@ -442,7 +442,7 @@ Exit_status Load_log_processor::process_first_event(const char *bname,
{
error("Could not construct local filename %s%s.",
target_dir_name,bname);
my_free(fname, MYF(0));
my_free(fname);
delete ce;
DBUG_RETURN(ERROR_STOP);
}
Expand All @@ -458,7 +458,7 @@ Exit_status Load_log_processor::process_first_event(const char *bname,
if (set_dynamic(&file_names, (uchar*)&rec, file_id))
{
error("Out of memory.");
my_free(fname, MYF(0));
my_free(fname);
delete ce;
DBUG_RETURN(ERROR_STOP);
}
Expand Down Expand Up @@ -822,7 +822,7 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
*/
convert_path_to_forward_slashes((char*) ce->fname);
ce->print(result_file, print_event_info, TRUE);
my_free((char*)ce->fname,MYF(MY_WME));
my_free((void*)ce->fname);
delete ce;
}
else
Expand Down Expand Up @@ -887,7 +887,7 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
}

if (fname)
my_free(fname, MYF(MY_WME));
my_free(fname);
break;
}
case TABLE_MAP_EVENT:
Expand Down Expand Up @@ -1222,11 +1222,11 @@ static void warning(const char *format,...)
*/
static void cleanup()
{
my_free(pass,MYF(MY_ALLOW_ZERO_PTR));
my_free((char*) database, MYF(MY_ALLOW_ZERO_PTR));
my_free((char*) host, MYF(MY_ALLOW_ZERO_PTR));
my_free((char*) user, MYF(MY_ALLOW_ZERO_PTR));
my_free((char*) dirname_for_local_load, MYF(MY_ALLOW_ZERO_PTR));
my_free(pass);
my_free(database);
my_free(host);
my_free(user);
my_free(dirname_for_local_load);

delete glob_description_event;
if (mysql)
Expand Down Expand Up @@ -1306,7 +1306,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
argument= (char*) ""; // Don't require password
if (argument)
{
my_free(pass,MYF(MY_ALLOW_ZERO_PTR));
my_free(pass);
char *start=argument;
pass= my_strdup(argument,MYF(MY_FAE));
while (*argument) *argument++= 'x'; /* Destroy argument */
Expand Down
12 changes: 6 additions & 6 deletions client/mysqlcheck.c
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
if (argument)
{
char *start = argument;
my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR));
my_free(opt_password);
opt_password = my_strdup(argument, MYF(MY_FAE));
while (*argument) *argument++= 'x'; /* Destroy argument */
if (*start)
Expand Down Expand Up @@ -470,7 +470,7 @@ static int process_selected_tables(char *db, char **table_names, int tables)
}
*--end = 0;
handle_request_for_tables(table_names_comma_sep + 1, (uint) (tot_length - 1));
my_free(table_names_comma_sep, MYF(0));
my_free(table_names_comma_sep);
}
else
for (; tables > 0; tables--, table_names++)
Expand Down Expand Up @@ -569,7 +569,7 @@ static int process_all_tables_in_db(char *database)
*--end = 0;
if (tot_length)
handle_request_for_tables(tables + 1, tot_length - 1);
my_free(tables, MYF(0));
my_free(tables);
}
else
{
Expand Down Expand Up @@ -727,7 +727,7 @@ static int handle_request_for_tables(char *tables, uint length)
return 1;
}
print_result();
my_free(query, MYF(0));
my_free(query);
return 0;
}

Expand Down Expand Up @@ -899,9 +899,9 @@ int main(int argc, char **argv)
dbDisconnect(current_host);
if (opt_auto_repair)
delete_dynamic(&tables4repair);
my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR));
my_free(opt_password);
#ifdef HAVE_SMEM
my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR));
my_free(shared_memory_base_name);
#endif
my_end(my_end_arg);
return(first_error!=0);
Expand Down
Loading

0 comments on commit d4a0c69

Please sign in to comment.