mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
move safemalloc out of dbug.
remeber a real backtrace for every allocation. make safemalloc to tract C++ new/delete too. collateral fixes to make the test suite pass.
This commit is contained in:
@@ -1786,11 +1786,13 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
|
||||
break;
|
||||
case 'V':
|
||||
usage(1);
|
||||
exit(0);
|
||||
status.exit_status= 0;
|
||||
mysql_end(-1);
|
||||
case 'I':
|
||||
case '?':
|
||||
usage(0);
|
||||
exit(0);
|
||||
status.exit_status= 0;
|
||||
mysql_end(-1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@@ -301,20 +301,17 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
int error= 0, ho_error;
|
||||
int error= 0;
|
||||
MYSQL mysql;
|
||||
char **commands, **save_argv;
|
||||
|
||||
MY_INIT(argv[0]);
|
||||
mysql_init(&mysql);
|
||||
if (load_defaults("my",load_default_groups,&argc,&argv))
|
||||
exit(1);
|
||||
if ((error= load_defaults("my",load_default_groups,&argc,&argv)))
|
||||
goto err1;
|
||||
save_argv = argv; /* Save for free_defaults */
|
||||
if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option)))
|
||||
{
|
||||
free_defaults(save_argv);
|
||||
exit(ho_error);
|
||||
}
|
||||
if ((error=handle_options(&argc, &argv, my_long_options, get_one_option)))
|
||||
goto err2;
|
||||
if (debug_info_flag)
|
||||
my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO;
|
||||
if (debug_check_flag)
|
||||
@@ -463,6 +460,7 @@ int main(int argc,char *argv[])
|
||||
} /* got connection */
|
||||
|
||||
mysql_close(&mysql);
|
||||
err2:
|
||||
mysql_library_end();
|
||||
my_free(opt_password);
|
||||
my_free(user);
|
||||
@@ -470,8 +468,9 @@ int main(int argc,char *argv[])
|
||||
my_free(shared_memory_base_name);
|
||||
#endif
|
||||
free_defaults(save_argv);
|
||||
err1:
|
||||
my_end(my_end_arg);
|
||||
exit(error ? 1 : 0);
|
||||
exit(error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -45,7 +45,7 @@
|
||||
|
||||
#include "mysqld.h"
|
||||
|
||||
Rpl_filter *binlog_filter;
|
||||
Rpl_filter *binlog_filter= 0;
|
||||
|
||||
#define BIN_LOG_HEADER_SIZE 4
|
||||
#define PROBE_HEADER_LEN (EVENT_LEN_OFFSET+4)
|
||||
@@ -77,7 +77,7 @@ static void error(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2);
|
||||
static void warning(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2);
|
||||
|
||||
static bool one_database=0, to_last_remote_log= 0, disable_log_bin= 0;
|
||||
static bool opt_hexdump= 0;
|
||||
static bool opt_hexdump= 0, opt_version= 0;
|
||||
const char *base64_output_mode_names[]=
|
||||
{"NEVER", "AUTO", "ALWAYS", "UNSPEC", "DECODE-ROWS", NullS};
|
||||
TYPELIB base64_output_mode_typelib=
|
||||
@@ -1430,6 +1430,7 @@ static void cleanup()
|
||||
my_free(user);
|
||||
my_free(const_cast<char*>(dirname_for_local_load));
|
||||
|
||||
delete binlog_filter;
|
||||
delete glob_description_event;
|
||||
if (mysql)
|
||||
mysql_close(mysql);
|
||||
@@ -1588,10 +1589,12 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
|
||||
break;
|
||||
case 'V':
|
||||
print_version();
|
||||
exit(0);
|
||||
opt_version= 1;
|
||||
break;
|
||||
case '?':
|
||||
usage();
|
||||
exit(0);
|
||||
opt_version= 1;
|
||||
break;
|
||||
}
|
||||
if (tty_password)
|
||||
pass= get_tty_password(NullS);
|
||||
@@ -2303,24 +2306,26 @@ int main(int argc, char** argv)
|
||||
my_init_time(); // for time functions
|
||||
|
||||
init_alloc_root(&s_mem_root, 16384, 0);
|
||||
if (load_defaults("my", load_groups, &argc, &argv))
|
||||
exit(1);
|
||||
|
||||
if (!(binlog_filter= new Rpl_filter))
|
||||
{
|
||||
error("Failed to create Rpl_filter");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (load_defaults("my", load_groups, &argc, &argv))
|
||||
exit(1);
|
||||
|
||||
defaults_argv= argv;
|
||||
parse_args(&argc, (char***)&argv);
|
||||
|
||||
if (!argc)
|
||||
if (!argc || opt_version)
|
||||
{
|
||||
if (!argc)
|
||||
usage();
|
||||
cleanup();
|
||||
free_defaults(defaults_argv);
|
||||
my_end(my_end_arg);
|
||||
exit(1);
|
||||
exit(!opt_version);
|
||||
}
|
||||
|
||||
if (opt_base64_output_mode == BASE64_OUTPUT_UNSPEC)
|
||||
@@ -2407,7 +2412,6 @@ int main(int argc, char** argv)
|
||||
my_fclose(result_file, MYF(0));
|
||||
cleanup();
|
||||
free_annotate_event();
|
||||
delete binlog_filter;
|
||||
free_root(&s_mem_root, MYF(0));
|
||||
free_defaults(defaults_argv);
|
||||
my_free_open_file_info();
|
||||
|
@@ -961,6 +961,7 @@ static void safe_exit(int error)
|
||||
DBUG_VOID_RETURN;
|
||||
if (sock)
|
||||
mysql_close(sock);
|
||||
sf_leaking_memory= 1; /* don't check for memory leaks */
|
||||
exit(error);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
@@ -972,7 +973,6 @@ int main(int argc, char **argv)
|
||||
char **defaults_argv;
|
||||
|
||||
MY_INIT(argv[0]);
|
||||
mysql_library_init(-1, 0, 0);
|
||||
/*
|
||||
** Check out the args
|
||||
*/
|
||||
|
@@ -62,6 +62,8 @@ static char *opt_plugin_dir= 0, *opt_default_auth= 0;
|
||||
static longlong opt_ignore_lines= -1;
|
||||
#include <sslopt-vars.h>
|
||||
|
||||
static char **argv_to_free;
|
||||
|
||||
#ifdef HAVE_SMEM
|
||||
static char *shared_memory_base_name=0;
|
||||
#endif
|
||||
@@ -475,10 +477,18 @@ static void db_disconnect(char *host, MYSQL *mysql)
|
||||
|
||||
static void safe_exit(int error, MYSQL *mysql)
|
||||
{
|
||||
if (ignore_errors)
|
||||
if (error && ignore_errors)
|
||||
return;
|
||||
if (mysql)
|
||||
mysql_close(mysql);
|
||||
|
||||
#ifdef HAVE_SMEM
|
||||
my_free(shared_memory_base_name);
|
||||
#endif
|
||||
free_defaults(argv_to_free);
|
||||
mysql_library_end();
|
||||
my_free(opt_password);
|
||||
my_end(my_end_arg);
|
||||
exit(error);
|
||||
}
|
||||
|
||||
@@ -597,7 +607,6 @@ error:
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int error=0;
|
||||
char **argv_to_free;
|
||||
MY_INIT(argv[0]);
|
||||
|
||||
if (load_defaults("my",load_default_groups,&argc,&argv))
|
||||
@@ -687,11 +696,6 @@ int main(int argc, char **argv)
|
||||
exitcode= error;
|
||||
db_disconnect(current_host, mysql);
|
||||
}
|
||||
my_free(opt_password);
|
||||
#ifdef HAVE_SMEM
|
||||
my_free(shared_memory_base_name);
|
||||
#endif
|
||||
free_defaults(argv_to_free);
|
||||
my_end(my_end_arg);
|
||||
safe_exit(0, 0);
|
||||
return(exitcode);
|
||||
}
|
||||
|
@@ -1394,6 +1394,7 @@ static void cleanup_and_exit(int exit_code)
|
||||
}
|
||||
}
|
||||
|
||||
sf_leaking_memory= 0; /* all memory should be freed by now */
|
||||
exit(exit_code);
|
||||
}
|
||||
|
||||
@@ -8462,6 +8463,9 @@ int main(int argc, char **argv)
|
||||
MY_INIT(argv[0]);
|
||||
DBUG_ENTER("main");
|
||||
|
||||
/* mysqltest has no way to free all its memory correctly */
|
||||
sf_leaking_memory= 1;
|
||||
|
||||
save_file[0]= 0;
|
||||
TMPDIR[0]= 0;
|
||||
|
||||
|
@@ -17,17 +17,6 @@ INCLUDE_DIRECTORIES(
|
||||
${CMAKE_SOURCE_DIR}/dbug
|
||||
${CMAKE_SOURCE_DIR}/include
|
||||
)
|
||||
IF(WIN32)
|
||||
SET(DEFAULT_SAFEMALLOC OFF)
|
||||
ELSE()
|
||||
SET(DEFAULT_SAFEMALLOC ON)
|
||||
ENDIF()
|
||||
OPTION(WITH_SAFEMALLOC ${DEFAULT_SAFEMALLOC} "Use safemalloc for debug builds. Will result in slower execution.")
|
||||
|
||||
IF(WITH_SAFEMALLOC)
|
||||
ADD_DEFINITIONS( -DSAFEMALLOC)
|
||||
ENDIF()
|
||||
|
||||
SET(DBUG_SOURCES dbug.c)
|
||||
ADD_CONVENIENCE_LIBRARY(dbug ${DBUG_SOURCES})
|
||||
TARGET_LINK_LIBRARIES(dbug mysys)
|
||||
|
362
dbug/dbug.c
362
dbug/dbug.c
@@ -98,9 +98,6 @@
|
||||
#include <process.h>
|
||||
#endif
|
||||
|
||||
#include <my_valgrind.h> /* TRASH */
|
||||
#include <my_stacktrace.h> /* my_safe_print_str */
|
||||
|
||||
/*
|
||||
* Manifest constants which may be "tuned" if desired.
|
||||
*/
|
||||
@@ -131,6 +128,7 @@
|
||||
#define SANITY_CHECK_ON (1 << 12) /* Check memory on every DBUG_ENTER/RETURN */
|
||||
#define TRACE_ON ((uint)1 << 31) /* Trace enabled. MUST be the highest bit!*/
|
||||
|
||||
#define sf_sanity() (0)
|
||||
#define TRACING (cs->stack->flags & TRACE_ON)
|
||||
#define DEBUGGING (cs->stack->flags & DEBUG_ON)
|
||||
|
||||
@@ -207,8 +205,6 @@ static BOOLEAN init_done= FALSE; /* Set to TRUE when initialization done */
|
||||
static struct settings init_settings;
|
||||
static const char *db_process= 0;/* Pointer to process name; argv[0] */
|
||||
my_bool _dbug_on_= TRUE; /* FALSE if no debugging at all */
|
||||
static const char *unknown_func= "?func";
|
||||
static const char *unknown_file= "?file";
|
||||
|
||||
typedef struct _db_code_state_ {
|
||||
const char *process; /* Pointer to process name; usually argv[0] */
|
||||
@@ -289,8 +285,6 @@ static void DbugExit(const char *why);
|
||||
static const char *DbugStrTok(const char *s);
|
||||
static void DbugVfprintf(FILE *stream, const char* format, va_list args);
|
||||
|
||||
static void DbugErr(CODE_STATE *, uint, const char* format, ...);
|
||||
|
||||
/*
|
||||
* Miscellaneous printf format strings.
|
||||
*/
|
||||
@@ -313,9 +307,6 @@ static void DbugErr(CODE_STATE *, uint, const char* format, ...);
|
||||
#define WRITABLE(pathname) (access(pathname, W_OK) == 0)
|
||||
#endif
|
||||
|
||||
static int sf_sanity();
|
||||
static void sf_terminate();
|
||||
|
||||
/*
|
||||
** Macros to allow dbugging with threads
|
||||
*/
|
||||
@@ -323,9 +314,6 @@ static void sf_terminate();
|
||||
#include <my_pthread.h>
|
||||
static pthread_mutex_t THR_LOCK_dbug;
|
||||
|
||||
/* this mutex protects all sf_* variables, and nothing else*/
|
||||
static pthread_mutex_t sf_mutex;
|
||||
|
||||
static CODE_STATE *code_state(void)
|
||||
{
|
||||
CODE_STATE *cs, **cs_ptr;
|
||||
@@ -341,7 +329,6 @@ static CODE_STATE *code_state(void)
|
||||
{
|
||||
init_done=TRUE;
|
||||
pthread_mutex_init(&THR_LOCK_dbug, NULL);
|
||||
pthread_mutex_init(&sf_mutex, NULL);
|
||||
bzero(&init_settings, sizeof(init_settings));
|
||||
init_settings.out_file=stderr;
|
||||
init_settings.flags=OPEN_APPEND;
|
||||
@@ -354,8 +341,8 @@ static CODE_STATE *code_state(void)
|
||||
cs=(CODE_STATE*) DbugMalloc(sizeof(*cs));
|
||||
bzero((uchar*) cs,sizeof(*cs));
|
||||
cs->process= db_process ? db_process : "dbug";
|
||||
cs->func= unknown_func;
|
||||
cs->file= unknown_file;
|
||||
cs->func= "?func";
|
||||
cs->file= "?file";
|
||||
cs->stack=&init_settings;
|
||||
*cs_ptr= cs;
|
||||
}
|
||||
@@ -1637,7 +1624,6 @@ void _db_end_()
|
||||
init_settings.keywords= 0;
|
||||
init_settings.processes= 0;
|
||||
FreeState(cs, &tmp, 0);
|
||||
sf_terminate();
|
||||
}
|
||||
|
||||
|
||||
@@ -2161,346 +2147,4 @@ const char* _db_get_func_(void)
|
||||
return cs->func;
|
||||
}
|
||||
|
||||
/*
|
||||
prints the error message, followed by a stack trace
|
||||
of the specified depth
|
||||
*/
|
||||
static void DbugErr(CODE_STATE *cs, uint depth, const char* format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args,format);
|
||||
vfprintf(stderr, format, args);
|
||||
va_end(args);
|
||||
|
||||
if (cs || ((cs= code_state())))
|
||||
{
|
||||
uint i= depth;
|
||||
struct _db_stack_frame_ *frame= cs->framep;
|
||||
while (i-- && frame)
|
||||
{
|
||||
fprintf(stderr, ", at %s", frame->func);
|
||||
frame= frame->prev;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
memory debugger
|
||||
based on safemalloc, memory sub-system, written by Bjorn Benson
|
||||
********************************************************************/
|
||||
|
||||
#ifndef SF_REMEMBER_FRAMES
|
||||
#define SF_REMEMBER_FRAMES 16
|
||||
#endif
|
||||
|
||||
/*
|
||||
Structure that stores information of an allocated memory block
|
||||
The data is at &struct_adr+sizeof(struct irem)
|
||||
Note that sizeof(struct st_irem) % sizeof(double) == 0
|
||||
*/
|
||||
struct st_irem
|
||||
{
|
||||
struct st_irem *next; /* Linked list of structures */
|
||||
struct st_irem *prev; /* Other link */
|
||||
size_t datasize; /* Size requested */
|
||||
const char *frame[SF_REMEMBER_FRAMES]; /* call stack */
|
||||
uint32 marker; /* Underrun marker value */
|
||||
};
|
||||
|
||||
/*
|
||||
DBUG_MALLOC/DBUG_REALLOC/DBUG_FREE can be called even
|
||||
before dbug is initialized. We cannot properly take into account
|
||||
these calls, but we can at least wrap allocated memory
|
||||
in st_irem's and check for overrun/underruns.
|
||||
These special irem's - that are not linked into a global list -
|
||||
are distinguished by a special value in the 'next' pointer.
|
||||
*/
|
||||
#define NOT_LINKED ((struct st_irem *)1)
|
||||
|
||||
size_t sf_malloc_mem_limit= (intptr)~0ULL;
|
||||
static size_t sf_malloc_cur_memory= 0L; /* Current memory usage */
|
||||
static size_t sf_malloc_max_memory= 0L; /* Maximum memory usage */
|
||||
|
||||
static int sf_malloc_count= 0; /* Number of allocated chunks */
|
||||
|
||||
static void *sf_min_adress= (void*) (intptr)~0ULL,
|
||||
*sf_max_adress= 0;
|
||||
|
||||
static struct st_irem *sf_malloc_root = 0;
|
||||
|
||||
#define MAGICSTART 0x14235296 /* A magic value for underrun key */
|
||||
|
||||
#define MAGICEND0 0x68 /* Magic values for overrun keys */
|
||||
#define MAGICEND1 0x34 /* " */
|
||||
#define MAGICEND2 0x7A /* " */
|
||||
#define MAGICEND3 0x15 /* " */
|
||||
|
||||
static int bad_ptr(const char *where, void *ptr);
|
||||
static void free_memory(void *ptr);
|
||||
|
||||
/*
|
||||
* FUNCTION
|
||||
*
|
||||
* _db_malloc_ allocates memory
|
||||
*
|
||||
* SYNOPSIS
|
||||
*
|
||||
* void *_db_malloc_(size_t size)
|
||||
* size_t size; Bytes to allocate
|
||||
*/
|
||||
|
||||
void *_db_malloc_(size_t size)
|
||||
{
|
||||
#ifndef SAFEMALLOC
|
||||
return malloc(size);
|
||||
#else
|
||||
CODE_STATE *cs= code_state();
|
||||
struct st_irem *irem;
|
||||
uchar *data;
|
||||
struct _db_stack_frame_ *frame;
|
||||
int i= 0;
|
||||
|
||||
if (size + sf_malloc_cur_memory > sf_malloc_mem_limit)
|
||||
irem= 0;
|
||||
else
|
||||
irem= (struct st_irem *) malloc (sizeof(struct st_irem) + size + 4);
|
||||
|
||||
if (!irem)
|
||||
return 0;
|
||||
|
||||
compile_time_assert(sizeof(struct st_irem) % sizeof(double) == 0);
|
||||
|
||||
/* Fill up the structure */
|
||||
data= (uchar*) (irem + 1);
|
||||
irem->datasize= size;
|
||||
irem->prev= 0;
|
||||
irem->marker= MAGICSTART;
|
||||
data[size + 0]= MAGICEND0;
|
||||
data[size + 1]= MAGICEND1;
|
||||
data[size + 2]= MAGICEND2;
|
||||
data[size + 3]= MAGICEND3;
|
||||
|
||||
if (cs && cs->framep)
|
||||
{
|
||||
for (frame= cs->framep;
|
||||
i < SF_REMEMBER_FRAMES && frame->func != unknown_func;
|
||||
i++, frame= frame->prev)
|
||||
irem->frame[i]= frame->func;
|
||||
}
|
||||
|
||||
if (i < SF_REMEMBER_FRAMES)
|
||||
irem->frame[i]= unknown_func;
|
||||
if (i==0)
|
||||
irem->frame[0]= (char*)1;
|
||||
|
||||
if (init_done)
|
||||
{
|
||||
pthread_mutex_lock(&sf_mutex);
|
||||
/* Add this structure to the linked list */
|
||||
if ((irem->next= sf_malloc_root))
|
||||
sf_malloc_root->prev= irem;
|
||||
sf_malloc_root= irem;
|
||||
|
||||
/* Keep the statistics */
|
||||
sf_malloc_count++;
|
||||
sf_malloc_cur_memory+= size;
|
||||
set_if_bigger(sf_malloc_max_memory, sf_malloc_cur_memory);
|
||||
set_if_smaller(sf_min_adress, (void*)data);
|
||||
set_if_bigger(sf_max_adress, (void*)data);
|
||||
pthread_mutex_unlock(&sf_mutex);
|
||||
}
|
||||
else
|
||||
{
|
||||
set_if_bigger(sf_malloc_max_memory, sf_malloc_cur_memory);
|
||||
set_if_smaller(sf_min_adress, (void*)data);
|
||||
set_if_bigger(sf_max_adress, (void*)data);
|
||||
irem->next= NOT_LINKED;
|
||||
}
|
||||
|
||||
TRASH_ALLOC(data, size);
|
||||
return data;
|
||||
#endif
|
||||
}
|
||||
|
||||
void *_db_realloc_(void *ptr, size_t size)
|
||||
{
|
||||
#ifndef SAFEMALLOC
|
||||
return realloc(ptr, size);
|
||||
#else
|
||||
char *data;
|
||||
|
||||
if (!ptr)
|
||||
return _db_malloc_(size);
|
||||
|
||||
if (bad_ptr("Reallocating", ptr))
|
||||
return 0;
|
||||
|
||||
if ((data= _db_malloc_(size)))
|
||||
{
|
||||
struct st_irem *irem= (struct st_irem *)ptr - 1;
|
||||
set_if_smaller(size, irem->datasize);
|
||||
memcpy(data, ptr, size);
|
||||
free_memory(ptr);
|
||||
}
|
||||
return data;
|
||||
#endif
|
||||
}
|
||||
|
||||
void _db_free_(void *ptr)
|
||||
{
|
||||
#ifndef SAFEMALLOC
|
||||
free(ptr);
|
||||
#else
|
||||
if (!ptr || bad_ptr("Freeing", ptr))
|
||||
return;
|
||||
|
||||
free_memory(ptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void free_memory(void *ptr)
|
||||
{
|
||||
struct st_irem *irem= (struct st_irem *)ptr - 1;
|
||||
|
||||
if (irem->next != NOT_LINKED)
|
||||
{
|
||||
pthread_mutex_lock(&sf_mutex);
|
||||
/* Remove this structure from the linked list */
|
||||
if (irem->prev)
|
||||
irem->prev->next= irem->next;
|
||||
else
|
||||
sf_malloc_root= irem->next;
|
||||
|
||||
if (irem->next)
|
||||
irem->next->prev= irem->prev;
|
||||
|
||||
/* Handle the statistics */
|
||||
sf_malloc_cur_memory-= irem->datasize;
|
||||
sf_malloc_count--;
|
||||
pthread_mutex_unlock(&sf_mutex);
|
||||
}
|
||||
|
||||
/* only trash the data and magic values, but keep the stack trace */
|
||||
TRASH_FREE((uchar*)(irem + 1) - 4, irem->datasize + 8);
|
||||
free(irem);
|
||||
return;
|
||||
}
|
||||
|
||||
#define SF_ADD_NL 1
|
||||
#define SF_USE_SAFE_PRINT 2
|
||||
static void print_allocated_at(struct st_irem *irem, int flags)
|
||||
{
|
||||
int i;
|
||||
const char *allocated= flags & SF_ADD_NL ? "Allocated" : ", allocated";
|
||||
|
||||
for (i=0;
|
||||
i < SF_REMEMBER_FRAMES && irem->frame[i] != unknown_func;
|
||||
i++)
|
||||
{
|
||||
fprintf(stderr, "%s at ", i ? "," : allocated);
|
||||
if (flags & SF_USE_SAFE_PRINT)
|
||||
my_safe_print_str(irem->frame[i], 80);
|
||||
else
|
||||
fputs(irem->frame[i], stderr);
|
||||
}
|
||||
if (i && (flags & SF_ADD_NL))
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
static int bad_ptr(const char *where, void *ptr)
|
||||
{
|
||||
struct st_irem *irem= (struct st_irem *)ptr - 1;
|
||||
const uchar *magicend;
|
||||
|
||||
if (((intptr) ptr) % sizeof(double))
|
||||
{
|
||||
DbugErr(0, SF_REMEMBER_FRAMES, "Error: %s wrong aligned pointer", where);
|
||||
return 1;
|
||||
}
|
||||
if (ptr < sf_min_adress || ptr > sf_max_adress)
|
||||
{
|
||||
DbugErr(0, SF_REMEMBER_FRAMES, "Error: %s pointer out of range", where);
|
||||
return 1;
|
||||
}
|
||||
if (irem->marker != MAGICSTART)
|
||||
{
|
||||
DbugErr(0, SF_REMEMBER_FRAMES,
|
||||
"Error: %s unallocated data or underrun buffer", where);
|
||||
/*
|
||||
we cannot use print_allocated_at here:
|
||||
if the memory was not allocated, there's nothing to print,
|
||||
if it was allocated and underrun, call stack may be corrupted
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
magicend= (uchar*)ptr + irem->datasize;
|
||||
if (magicend[0] != MAGICEND0 ||
|
||||
magicend[1] != MAGICEND1 ||
|
||||
magicend[2] != MAGICEND2 ||
|
||||
magicend[3] != MAGICEND3)
|
||||
{
|
||||
DbugErr(0, SF_REMEMBER_FRAMES, "Error: %s overrun buffer", where);
|
||||
print_allocated_at(irem, SF_ADD_NL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* check all allocated memory list for consistency */
|
||||
static int sf_sanity()
|
||||
{
|
||||
struct st_irem *irem;
|
||||
int flag= 0;
|
||||
int count= 0;
|
||||
|
||||
pthread_mutex_lock(&sf_mutex);
|
||||
count= sf_malloc_count;
|
||||
for (irem= sf_malloc_root; irem && count > 0; count--, irem= irem->next)
|
||||
flag+= bad_ptr("Safemalloc", irem + 1);
|
||||
pthread_mutex_unlock(&sf_mutex);
|
||||
if (count || irem)
|
||||
{
|
||||
DbugErr(0, SF_REMEMBER_FRAMES, "Error: Safemalloc link list destroyed");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* FUNCTION
|
||||
*
|
||||
* sf_terminate Report on all the memory pieces that have not been free'd
|
||||
*
|
||||
* SYNOPSIS
|
||||
*
|
||||
* void sf_terminate()
|
||||
*/
|
||||
|
||||
static void sf_terminate()
|
||||
{
|
||||
struct st_irem *irem;
|
||||
|
||||
sf_sanity();
|
||||
|
||||
/* Report on all the memory that was allocated but not free'd */
|
||||
if ((irem= sf_malloc_root))
|
||||
{
|
||||
while (irem)
|
||||
{
|
||||
fprintf(stderr, "Warning: %6lu bytes at %p are not freed", (ulong) irem->datasize, irem + 1);
|
||||
print_allocated_at(irem, SF_USE_SAFE_PRINT);
|
||||
fprintf(stderr, "\n");
|
||||
irem= irem->next;
|
||||
}
|
||||
fprintf(stderr, "Memory lost: %lu bytes in %d chunks\n",
|
||||
(ulong) sf_malloc_cur_memory, sf_malloc_count);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#endif /* DBUG_OFF */
|
||||
|
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
#include <my_global.h> /* This includes dbug.h */
|
||||
#include <my_sys.h>
|
||||
#include <my_pthread.h>
|
||||
|
||||
int main (argc, argv)
|
||||
@@ -12,7 +13,7 @@ char *argv[];
|
||||
{
|
||||
register int result, ix;
|
||||
extern int factorial(int);
|
||||
my_thread_global_init();
|
||||
MY_INIT(argv[0]);
|
||||
|
||||
{
|
||||
DBUG_ENTER ("main");
|
||||
@@ -29,6 +30,8 @@ char *argv[];
|
||||
result = factorial (atoi(argv[ix]));
|
||||
printf ("%d\n", result);
|
||||
}
|
||||
DBUG_RETURN (0);
|
||||
DBUG_LEAVE;
|
||||
}
|
||||
my_end(0);
|
||||
exit(0);
|
||||
}
|
||||
|
@@ -201,7 +201,7 @@ func2: info: s=ko
|
||||
| | <func3
|
||||
<main
|
||||
% ./tests t:d:-d,ret3:f:-f,func2 +d,dump,explain:P
|
||||
dbug: >main
|
||||
dbug-tests: >main
|
||||
dbug-tests: | >func1
|
||||
dbug-tests: | | | >func3
|
||||
dbug-tests: | | | <func3
|
||||
@@ -216,7 +216,7 @@ dbug-tests: | | >func3
|
||||
dbug-tests: | | <func3
|
||||
dbug-tests: <main
|
||||
% ./tests t:d:-d,ret3:f:-f,func2 +d,dump,explain:P:F
|
||||
dbug: tests.c: >main
|
||||
dbug-tests: tests.c: >main
|
||||
dbug-tests: tests.c: | >func1
|
||||
dbug-tests: tests.c: | | | >func3
|
||||
dbug-tests: tests.c: | | | <func3
|
||||
|
@@ -5,6 +5,7 @@
|
||||
char *push1=0;
|
||||
|
||||
#include <my_global.h> /* This includes dbug.h */
|
||||
#include <my_sys.h>
|
||||
#include <my_pthread.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -44,7 +45,7 @@ int main (int argc, char *argv[])
|
||||
if (argc == 1)
|
||||
return 0;
|
||||
|
||||
my_thread_global_init();
|
||||
MY_INIT("dbug-tests");
|
||||
|
||||
dup2(1, 2);
|
||||
for (i = 1; i < argc; i++)
|
||||
@@ -56,7 +57,6 @@ int main (int argc, char *argv[])
|
||||
}
|
||||
{
|
||||
DBUG_ENTER ("main");
|
||||
DBUG_PROCESS ("dbug-tests");
|
||||
func1();
|
||||
DBUG_EXECUTE_IF("dump",
|
||||
{
|
||||
@@ -78,6 +78,9 @@ int main (int argc, char *argv[])
|
||||
DBUG_PRINT("explain", ("dbug explained: %s", s));
|
||||
}
|
||||
func2();
|
||||
DBUG_RETURN (0);
|
||||
DBUG_LEAVE;
|
||||
}
|
||||
DBUG_SET(""); /* to not have my_end() in the traces */
|
||||
my_end(0);
|
||||
return 0;
|
||||
}
|
||||
|
22
dbug/user.r
22
dbug/user.r
@@ -881,20 +881,6 @@ Modifying
|
||||
.I initial
|
||||
value does not affect threads that are already running. Obviously,
|
||||
these macros are only useful in the multi-threaded environment.
|
||||
.SP 1
|
||||
.LI DBUG_MALLOC\
|
||||
.LI DBUG_REALLOC\
|
||||
.LI DBUG_FREE\
|
||||
When these macros are used instead of system malloc(), realloc(), and free(),
|
||||
.I dbug
|
||||
built-in memory debugger performs checks for memory overwrites, underwrites,
|
||||
memory leaks, and accesses to uninitialized or freed memory. Memory leaks are
|
||||
found as memory not deallocated at shutdown. Memory overwrites and underwrites
|
||||
are detected when this memory is about to be freed (by
|
||||
.B DBUG_FREE
|
||||
macro), unless
|
||||
.B S
|
||||
flag is present in the debug control string (see below).
|
||||
.LE
|
||||
|
||||
.SK
|
||||
@@ -1003,11 +989,9 @@ Most useful with
|
||||
macros used to temporarily alter the
|
||||
debugger state.
|
||||
.LI S
|
||||
Check the memory allocated with
|
||||
.B DBUG_MALLOC
|
||||
and
|
||||
.B DBUG_REALLOC
|
||||
for overwrites/underwrites
|
||||
When compiled with
|
||||
.I safemalloc
|
||||
this flag invokes "sanity" memory checks (for overwrites/underwrites)
|
||||
on each
|
||||
.B DBUG_ENTER
|
||||
and
|
||||
|
@@ -419,6 +419,8 @@ int main(int argc,char *argv[])
|
||||
if (unknown_error)
|
||||
free(unknown_error);
|
||||
|
||||
my_handler_error_unregister();
|
||||
my_end(0);
|
||||
exit(error);
|
||||
return error;
|
||||
}
|
||||
|
@@ -60,9 +60,6 @@ extern void _db_unlock_file_(void);
|
||||
extern FILE *_db_fp_(void);
|
||||
extern void _db_flush_();
|
||||
extern const char* _db_get_func_(void);
|
||||
extern void *_db_malloc_(size_t size);
|
||||
extern void *_db_realloc_(void *ptr, size_t size);
|
||||
extern void _db_free_(void *ptr);
|
||||
|
||||
#define DBUG_ENTER(a) struct _db_stack_frame_ _db_stack_frame_; \
|
||||
_db_enter_ (a,__FILE__,__LINE__,&_db_stack_frame_)
|
||||
@@ -95,9 +92,6 @@ extern void _db_free_(void *ptr);
|
||||
#define DBUG_EXPLAIN_INITIAL(buf,len) _db_explain_init_((buf),(len))
|
||||
#define DEBUGGER_OFF do { _dbug_on_= 0; } while(0)
|
||||
#define DEBUGGER_ON do { _dbug_on_= 1; } while(0)
|
||||
#define DBUG_MALLOC(SIZE) _db_malloc_(SIZE)
|
||||
#define DBUG_REALLOC(PTR,SIZE) _db_realloc_(PTR,SIZE)
|
||||
#define DBUG_FREE(PTR) _db_free_(PTR)
|
||||
#define IF_DBUG(A,B) A
|
||||
|
||||
#ifndef __WIN__
|
||||
@@ -156,9 +150,6 @@ extern void _db_suicide_();
|
||||
#define DBUG_EXPLAIN_INITIAL(buf,len)
|
||||
#define DEBUGGER_OFF do { } while(0)
|
||||
#define DEBUGGER_ON do { } while(0)
|
||||
#define DBUG_MALLOC(SIZE) malloc(SIZE)
|
||||
#define DBUG_REALLOC(PTR,SIZE) realloc(PTR,SIZE)
|
||||
#define DBUG_FREE(PTR) free(PTR)
|
||||
#define IF_DBUG(A,B) B
|
||||
#define DBUG_ABORT() do { } while(0)
|
||||
#define DBUG_CRASH_ENTER(func)
|
||||
|
@@ -55,6 +55,7 @@ void my_set_exception_pointers(EXCEPTION_POINTERS *ep);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* at the moment, safemalloc is the main user of libbfd */
|
||||
#ifndef SAFEMALLOC
|
||||
#undef HAVE_BFD_H
|
||||
#endif
|
||||
|
@@ -153,8 +153,10 @@ extern void *my_realloc(void *oldpoint, size_t Size, myf MyFlags);
|
||||
extern void my_free(void *ptr);
|
||||
extern void *my_memdup(const void *from,size_t length,myf MyFlags);
|
||||
extern char *my_strdup(const char *from,myf MyFlags);
|
||||
extern char *my_strndup(const char *from, size_t length,
|
||||
myf MyFlags);
|
||||
extern char *my_strndup(const char *from, size_t length, myf MyFlags);
|
||||
|
||||
extern int sf_leaking_memory; /* set to 1 to disable memleak detection */
|
||||
|
||||
#if defined(ENABLED_DEBUG_SYNC)
|
||||
extern void (*debug_sync_C_callback_ptr)(const char *, size_t);
|
||||
#define DEBUG_SYNC_C(_sync_point_name_) do { \
|
||||
|
@@ -15,6 +15,7 @@
|
||||
|
||||
|
||||
/* Some defines to make it easier to use valgrind */
|
||||
#include <m_string.h> /* bfill */
|
||||
|
||||
#ifdef HAVE_valgrind
|
||||
#define IF_VALGRIND(A,B) A
|
||||
|
@@ -4292,7 +4292,7 @@ Abernathy
|
||||
aberrant
|
||||
aberration
|
||||
drop table words;
|
||||
mysql-import: Error: 1146, Table 'test.words' doesn't exist, when using table: words
|
||||
mysqlimport: Error: 1146, Table 'test.words' doesn't exist, when using table: words
|
||||
drop table t1;
|
||||
drop table t2;
|
||||
drop table words2;
|
||||
|
@@ -1747,7 +1747,7 @@ select * from words2;
|
||||
|
||||
# Drop table "words" and run with threads, should fail
|
||||
drop table words;
|
||||
--replace_regex /.*mysqlimport(\.exe)*/mysql-import/
|
||||
--replace_regex /.*mysqlimport(\.exe)*/mysqlimport/
|
||||
--error 1
|
||||
--exec $MYSQL_IMPORT --silent --use-threads=2 test $MYSQLTEST_VARDIR/tmp/t1.txt $MYSQLTEST_VARDIR/tmp/t2.txt $MYSQLTEST_VARDIR/std_data/words.dat $MYSQLTEST_VARDIR/std_data/words2.dat 2>&1
|
||||
|
||||
|
@@ -33,7 +33,7 @@ SET(MYSYS_SOURCES array.c charset-def.c charset.c checksum.c default.c
|
||||
rijndael.c sha1.c string.c thr_alarm.c thr_lock.c thr_mutex.c
|
||||
thr_rwlock.c tree.c typelib.c base64.c my_memmem.c my_getpagesize.c
|
||||
lf_alloc-pin.c lf_dynarray.c lf_hash.c
|
||||
my_addr_resolve.c
|
||||
my_addr_resolve.c safemalloc.c
|
||||
my_atomic.c my_getncpus.c my_safehash.c my_chmod.c my_rnd.c
|
||||
my_uuid.c wqueue.c waiting_threads.c ma_dyncol.c
|
||||
my_rdtsc.c)
|
||||
@@ -46,8 +46,18 @@ IF(HAVE_ALARM)
|
||||
SET(MYSYS_SOURCES ${MYSYS_SOURCES} my_alarm.c)
|
||||
ENDIF()
|
||||
|
||||
IF(NOT HAVE_CXX_NEW)
|
||||
# gcc as C++ compiler does not have new/delete
|
||||
IF(WIN32)
|
||||
SET(DEFAULT_SAFEMALLOC OFF)
|
||||
ELSE()
|
||||
SET(DEFAULT_SAFEMALLOC ON)
|
||||
ENDIF()
|
||||
OPTION(WITH_SAFEMALLOC "Use safemalloc for debug builds. Will result in slower execution." ${DEFAULT_SAFEMALLOC})
|
||||
|
||||
IF(WITH_SAFEMALLOC)
|
||||
ADD_DEFINITIONS( -DSAFEMALLOC)
|
||||
ENDIF()
|
||||
|
||||
IF(NOT HAVE_CXX_NEW OR WITH_SAFEMALLOC)
|
||||
SET(MYSYS_SOURCES ${MYSYS_SOURCES} my_new.cc)
|
||||
ADD_DEFINITIONS( -DUSE_MYSYS_NEW)
|
||||
ENDIF()
|
||||
|
@@ -37,7 +37,7 @@ void *my_malloc(size_t size, myf my_flags)
|
||||
if (!size)
|
||||
size=1;
|
||||
|
||||
point= DBUG_MALLOC(size);
|
||||
point= sf_malloc(size);
|
||||
DBUG_EXECUTE_IF("simulate_out_of_memory",
|
||||
{
|
||||
my_free(point);
|
||||
@@ -85,7 +85,7 @@ void *my_realloc(void *oldpoint, size_t size, myf my_flags)
|
||||
DBUG_ASSERT(size > 0);
|
||||
if (!oldpoint && (my_flags & MY_ALLOW_ZERO_PTR))
|
||||
DBUG_RETURN(my_malloc(size, my_flags));
|
||||
if ((point= DBUG_REALLOC(oldpoint, size)) == NULL)
|
||||
if ((point= sf_realloc(oldpoint, size)) == NULL)
|
||||
{
|
||||
if (my_flags & MY_FREE_ON_ERROR)
|
||||
my_free(oldpoint);
|
||||
@@ -111,7 +111,7 @@ void my_free(void *ptr)
|
||||
{
|
||||
DBUG_ENTER("my_free");
|
||||
DBUG_PRINT("my",("ptr: %p", ptr));
|
||||
DBUG_FREE(ptr);
|
||||
sf_free(ptr);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
@@ -17,6 +17,9 @@
|
||||
/*
|
||||
This is a replacement of new/delete operators to be used when compiling
|
||||
with gcc 3.0.x to avoid including libstdc++
|
||||
|
||||
It is also used to make all memory allocations to go through
|
||||
my_malloc/my_free wrappers (for debugging/safemalloc and accounting)
|
||||
*/
|
||||
|
||||
#include "mysys_priv.h"
|
||||
@@ -25,24 +28,22 @@
|
||||
|
||||
void *operator new (size_t sz)
|
||||
{
|
||||
return (void *) malloc (sz ? sz : 1);
|
||||
return (void *) my_malloc (sz ? sz : 1, MYF(0));
|
||||
}
|
||||
|
||||
void *operator new[] (size_t sz)
|
||||
{
|
||||
return (void *) malloc (sz ? sz : 1);
|
||||
return (void *) my_malloc (sz ? sz : 1, MYF(0));
|
||||
}
|
||||
|
||||
void operator delete (void *ptr)
|
||||
{
|
||||
if (ptr)
|
||||
free(ptr);
|
||||
my_free(ptr);
|
||||
}
|
||||
|
||||
void operator delete[] (void *ptr) throw ()
|
||||
{
|
||||
if (ptr)
|
||||
free(ptr);
|
||||
my_free(ptr);
|
||||
}
|
||||
|
||||
C_MODE_START
|
||||
|
@@ -69,6 +69,15 @@ extern PSI_file_key key_file_proc_meminfo;
|
||||
extern PSI_file_key key_file_charset, key_file_cnf;
|
||||
#endif /* HAVE_PSI_INTERFACE */
|
||||
|
||||
#ifdef SAFEMALLOC
|
||||
void *sf_malloc(size_t size);
|
||||
void *sf_realloc(void *ptr, size_t size);
|
||||
void sf_free(void *ptr);
|
||||
#else
|
||||
#define sf_malloc(X) malloc(X)
|
||||
#define sf_realloc(X,Y) realloc(X,Y)
|
||||
#define sf_free(X) free(X)
|
||||
#endif
|
||||
|
||||
/*
|
||||
EDQUOT is used only in 3 C files only in mysys/. If it does not exist on
|
||||
|
341
mysys/safemalloc.c
Normal file
341
mysys/safemalloc.c
Normal file
@@ -0,0 +1,341 @@
|
||||
/* Copyright (C) 2000 MySQL AB, 2011 Monty Program Ab
|
||||
|
||||
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 Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
/********************************************************************
|
||||
memory debugger
|
||||
based on safemalloc, memory sub-system, written by Bjorn Benson
|
||||
********************************************************************/
|
||||
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <my_stacktrace.h> /* my_addr_resolve */
|
||||
|
||||
#if HAVE_EXECINFO_H
|
||||
#include <execinfo.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
this can be set to 1 if we leak memory and know it
|
||||
(to disable memory leak tests on exit)
|
||||
*/
|
||||
int sf_leaking_memory= 0;
|
||||
|
||||
#ifdef SAFEMALLOC
|
||||
|
||||
/* this mutex protects all sf_* variables, and nothing else*/
|
||||
static pthread_mutex_t sf_mutex;
|
||||
static int init_done= 0;
|
||||
|
||||
#ifndef SF_REMEMBER_FRAMES
|
||||
#define SF_REMEMBER_FRAMES 8
|
||||
#endif
|
||||
|
||||
/* ignore the first two frames (sf_malloc itself, and my_malloc) */
|
||||
#define SF_FRAMES_SKIP 2
|
||||
|
||||
/*
|
||||
Structure that stores information of an allocated memory block
|
||||
The data is at &struct_adr+sizeof(struct irem)
|
||||
Note that sizeof(struct st_irem) % sizeof(double) == 0
|
||||
*/
|
||||
struct st_irem
|
||||
{
|
||||
struct st_irem *next; /* Linked list of structures */
|
||||
struct st_irem *prev; /* Other link */
|
||||
size_t datasize; /* Size requested */
|
||||
#ifdef HAVE_BACKTRACE
|
||||
void *frame[SF_REMEMBER_FRAMES]; /* call stack */
|
||||
#endif
|
||||
uint32 marker; /* Underrun marker value */
|
||||
};
|
||||
|
||||
static int sf_malloc_count= 0; /* Number of allocated chunks */
|
||||
|
||||
static void *sf_min_adress= (void*) (intptr)~0ULL,
|
||||
*sf_max_adress= 0;
|
||||
|
||||
static struct st_irem *sf_malloc_root = 0;
|
||||
|
||||
#define MAGICSTART 0x14235296 /* A magic value for underrun key */
|
||||
|
||||
#define MAGICEND0 0x68 /* Magic values for overrun keys */
|
||||
#define MAGICEND1 0x34 /* " */
|
||||
#define MAGICEND2 0x7A /* " */
|
||||
#define MAGICEND3 0x15 /* " */
|
||||
|
||||
static int bad_ptr(const char *where, void *ptr);
|
||||
static void free_memory(void *ptr);
|
||||
static void sf_terminate();
|
||||
|
||||
/**
|
||||
allocates memory
|
||||
*/
|
||||
|
||||
void *sf_malloc(size_t size)
|
||||
{
|
||||
struct st_irem *irem;
|
||||
uchar *data;
|
||||
|
||||
/*
|
||||
this style of initialization looks like race conditon prone,
|
||||
but it is safe under the assumption that a program does
|
||||
at least one malloc() while still being single threaded.
|
||||
*/
|
||||
if (!init_done)
|
||||
{
|
||||
pthread_mutex_init(&sf_mutex, NULL);
|
||||
/* disable deadlock detector, because it calls my_malloc() */
|
||||
safe_mutex_setflags(&sf_mutex, MYF_NO_DEADLOCK_DETECTION);
|
||||
atexit(sf_terminate);
|
||||
init_done= 1;
|
||||
}
|
||||
|
||||
irem= (struct st_irem *) malloc (sizeof(struct st_irem) + size + 4);
|
||||
|
||||
if (!irem)
|
||||
return 0;
|
||||
|
||||
/* we guarantee the alignment */
|
||||
compile_time_assert(sizeof(struct st_irem) % sizeof(double) == 0);
|
||||
|
||||
/* Fill up the structure */
|
||||
data= (uchar*) (irem + 1);
|
||||
irem->datasize= size;
|
||||
irem->prev= 0;
|
||||
irem->marker= MAGICSTART;
|
||||
data[size + 0]= MAGICEND0;
|
||||
data[size + 1]= MAGICEND1;
|
||||
data[size + 2]= MAGICEND2;
|
||||
data[size + 3]= MAGICEND3;
|
||||
|
||||
#ifdef HAVE_BACKTRACE
|
||||
{
|
||||
void *frame[SF_REMEMBER_FRAMES + SF_FRAMES_SKIP];
|
||||
int frames= backtrace(frame, array_elements(frame));
|
||||
if (frames < SF_FRAMES_SKIP)
|
||||
frames= 0;
|
||||
else
|
||||
{
|
||||
frames-= SF_FRAMES_SKIP;
|
||||
memcpy(irem->frame, frame + SF_FRAMES_SKIP, sizeof(void*)*frames);
|
||||
}
|
||||
if (frames < SF_REMEMBER_FRAMES)
|
||||
irem->frame[frames]= 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
pthread_mutex_lock(&sf_mutex);
|
||||
|
||||
/* Add this structure to the linked list */
|
||||
if ((irem->next= sf_malloc_root))
|
||||
sf_malloc_root->prev= irem;
|
||||
sf_malloc_root= irem;
|
||||
|
||||
/* Keep the statistics */
|
||||
sf_malloc_count++;
|
||||
set_if_smaller(sf_min_adress, (void*)data);
|
||||
set_if_bigger(sf_max_adress, (void*)data);
|
||||
|
||||
pthread_mutex_unlock(&sf_mutex);
|
||||
|
||||
TRASH_ALLOC(data, size);
|
||||
return data;
|
||||
}
|
||||
|
||||
void *sf_realloc(void *ptr, size_t size)
|
||||
{
|
||||
char *data;
|
||||
|
||||
if (!ptr)
|
||||
return sf_malloc(size);
|
||||
|
||||
if (bad_ptr("Reallocating", ptr))
|
||||
return 0;
|
||||
|
||||
if ((data= sf_malloc(size)))
|
||||
{
|
||||
struct st_irem *irem= (struct st_irem *)ptr - 1;
|
||||
set_if_smaller(size, irem->datasize);
|
||||
memcpy(data, ptr, size);
|
||||
free_memory(ptr);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
void sf_free(void *ptr)
|
||||
{
|
||||
if (!ptr || bad_ptr("Freeing", ptr))
|
||||
return;
|
||||
|
||||
free_memory(ptr);
|
||||
}
|
||||
|
||||
static void free_memory(void *ptr)
|
||||
{
|
||||
struct st_irem *irem= (struct st_irem *)ptr - 1;
|
||||
|
||||
pthread_mutex_lock(&sf_mutex);
|
||||
/* Remove this structure from the linked list */
|
||||
if (irem->prev)
|
||||
irem->prev->next= irem->next;
|
||||
else
|
||||
sf_malloc_root= irem->next;
|
||||
|
||||
if (irem->next)
|
||||
irem->next->prev= irem->prev;
|
||||
|
||||
/* Handle the statistics */
|
||||
sf_malloc_count--;
|
||||
pthread_mutex_unlock(&sf_mutex);
|
||||
|
||||
/* only trash the data and magic values, but keep the stack trace */
|
||||
TRASH_FREE((uchar*)(irem + 1) - 4, irem->datasize + 8);
|
||||
free(irem);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef HAVE_BACKTRACE
|
||||
static void print_stack(void **frame)
|
||||
{
|
||||
const char *err;
|
||||
int i;
|
||||
|
||||
if ((err= my_addr_resolve_init()))
|
||||
{
|
||||
fprintf(stderr, "(my_addr_resolve failure: %s)\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i=0; i < SF_REMEMBER_FRAMES && frame[i]; i++)
|
||||
{
|
||||
my_addr_loc loc;
|
||||
if (i)
|
||||
fprintf(stderr, ", ");
|
||||
|
||||
if (my_addr_resolve(frame[i], &loc))
|
||||
fprintf(stderr, "...");
|
||||
else
|
||||
fprintf(stderr, "%s:%u", loc.file, loc.line);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
#else
|
||||
#define print_stack(X) fprintf(stderr, "???\n")
|
||||
#endif
|
||||
|
||||
static void warn(const char *format,...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args,format);
|
||||
vfprintf(stderr, format, args);
|
||||
va_end(args);
|
||||
|
||||
#ifdef HAVE_BACKTRACE
|
||||
{
|
||||
void *frame[SF_REMEMBER_FRAMES + SF_FRAMES_SKIP];
|
||||
int frames= backtrace(frame, array_elements(frame));
|
||||
if (frames < SF_REMEMBER_FRAMES + SF_FRAMES_SKIP)
|
||||
frame[frames]= 0;
|
||||
print_stack(frame + SF_FRAMES_SKIP);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static int bad_ptr(const char *where, void *ptr)
|
||||
{
|
||||
struct st_irem *irem= (struct st_irem *)ptr - 1;
|
||||
const uchar *magicend;
|
||||
|
||||
if (((intptr) ptr) % sizeof(double))
|
||||
{
|
||||
warn("Error: %s wrong aligned pointer", where);
|
||||
return 1;
|
||||
}
|
||||
if (ptr < sf_min_adress || ptr > sf_max_adress)
|
||||
{
|
||||
warn("Error: %s pointer out of range", where);
|
||||
return 1;
|
||||
}
|
||||
if (irem->marker != MAGICSTART)
|
||||
{
|
||||
warn("Error: %s unallocated data or underrun buffer", where);
|
||||
return 1;
|
||||
}
|
||||
|
||||
magicend= (uchar*)ptr + irem->datasize;
|
||||
if (magicend[0] != MAGICEND0 ||
|
||||
magicend[1] != MAGICEND1 ||
|
||||
magicend[2] != MAGICEND2 ||
|
||||
magicend[3] != MAGICEND3)
|
||||
{
|
||||
warn("Error: %s overrun buffer", where);
|
||||
fprintf(stderr, ", allocated at ");
|
||||
print_stack(irem->frame);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* check all allocated memory list for consistency */
|
||||
static int sf_sanity()
|
||||
{
|
||||
struct st_irem *irem;
|
||||
int flag= 0;
|
||||
int count= 0;
|
||||
|
||||
pthread_mutex_lock(&sf_mutex);
|
||||
count= sf_malloc_count;
|
||||
for (irem= sf_malloc_root; irem && count > 0; count--, irem= irem->next)
|
||||
flag+= bad_ptr("Safemalloc", irem + 1);
|
||||
pthread_mutex_unlock(&sf_mutex);
|
||||
if (count || irem)
|
||||
{
|
||||
warn("Error: Safemalloc link list destroyed");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
report on all the memory pieces that have not been free'd
|
||||
*/
|
||||
|
||||
static void sf_terminate()
|
||||
{
|
||||
size_t total= 0;
|
||||
struct st_irem *irem;
|
||||
|
||||
sf_sanity();
|
||||
|
||||
/* Report on all the memory that was allocated but not free'd */
|
||||
if (!sf_leaking_memory && sf_malloc_root)
|
||||
{
|
||||
for (irem= sf_malloc_root; irem; irem= irem->next)
|
||||
{
|
||||
fprintf(stderr, "Warning: %4lu bytes lost, allocated at ",
|
||||
(ulong) irem->datasize);
|
||||
print_stack(irem->frame);
|
||||
total+= irem->datasize;
|
||||
}
|
||||
fprintf(stderr, "Memory lost: %lu bytes in %d chunks\n",
|
||||
(ulong) total, sf_malloc_count);
|
||||
}
|
||||
|
||||
pthread_mutex_destroy(&sf_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
@@ -47,7 +47,10 @@ int find_type_or_exit(const char *x, TYPELIB *typelib, const char *option)
|
||||
{
|
||||
int res;
|
||||
if ((res= find_type_with_warning(x, typelib, option)) <= 0)
|
||||
{
|
||||
sf_leaking_memory= 1; /* no memory leak reports here */
|
||||
exit(1);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@@ -6782,6 +6782,7 @@ int ha_partition::final_add_index(handler_add_index *add, bool commit)
|
||||
if (table_arg->key_info == add->key_info)
|
||||
table_arg->key_info= NULL;
|
||||
}
|
||||
delete add;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
@@ -333,8 +333,6 @@ static PSI_rwlock_key key_rwlock_openssl;
|
||||
#endif
|
||||
#endif /* HAVE_PSI_INTERFACE */
|
||||
|
||||
#undef SAFEMALLOC
|
||||
|
||||
/* the default log output is log tables */
|
||||
static bool lower_case_table_names_used= 0;
|
||||
static bool max_long_data_size_used= false;
|
||||
@@ -3509,6 +3507,8 @@ static int init_common_variables()
|
||||
|
||||
tzset(); // Set tzname
|
||||
|
||||
sf_leaking_memory= 0; // no memory leaks from now on
|
||||
|
||||
max_system_variables.pseudo_thread_id= (ulong)~0;
|
||||
server_start_time= flush_status_time= my_time(0);
|
||||
|
||||
@@ -4709,6 +4709,7 @@ int mysqld_main(int argc, char **argv)
|
||||
to be able to read defaults files and parse options.
|
||||
*/
|
||||
my_progname= argv[0];
|
||||
sf_leaking_memory= 1; // no safemalloc memory leak reports if we exit early
|
||||
#ifndef _WIN32
|
||||
// For windows, my_init() is called from the win specific mysqld_main
|
||||
if (my_init()) // init my_sys library & pthreads
|
||||
|
@@ -5732,6 +5732,7 @@ int ha_pbxt::create(const char *table_path, TABLE *table_arg, HA_CREATE_INFO *cr
|
||||
catch_(a) {
|
||||
if (tab_def)
|
||||
tab_def->finalize(self);
|
||||
delete tab_def;
|
||||
dic.dic_table = NULL;
|
||||
err = xt_ha_pbxt_thread_error_for_mysql(thd, self, FALSE);
|
||||
}
|
||||
|
Reference in New Issue
Block a user