Commit 6cc9d0ff authored by Sergei Golubchik's avatar Sergei Golubchik

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.
parent 37c81d81
......@@ -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)
{
usage();
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 @@ pthread_handler_t worker_thread(void *arg)
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)
......
......@@ -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;
}
......@@ -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;
}
......
......@@ -16,7 +16,10 @@
/*
This is a replacement of new/delete operators to be used when compiling
with gcc 3.0.x to avoid including libstdc++
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
......
/* 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);
}
......
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