Skip to content

Commit 1ea2c0a

Browse files
committed
Bug #19031370: ADD SUPPORT FOR VISUAL STUDIO CRT MEMORY LEAKS TRACKING
Added support for MS Visual Studio CRT memory leak tracing: * Made a new CMake parameter : WITH_MSCRT_DEBUG=YES/NO (default NO) * Added a code to my_init.c to initialize the CRT debugging to print to stderr * Enabled convertion all malloc to _malloc_dbg, calloc to _calloc_dbg and realloc to _realloc_dbg to get line numbers in the report * Renamed all the class methods and members named free/malloc/calloc/realloc to mem_free/mem_malloc/mem_calloc/mem_realloc to avoid conflicts with the #define * Marked the my_malloc/my_free allocations as "client" blocks and left all the others as "normal" blocks. * Made sure NDB compiles too * Addressed Magnus' comments (renamed some of the ndb mem_free to more meaningful names) * Addressed second set of Magnus' comments (renamed num_free_bytes) to num_free. * updated to the latest trunk * fixed an ndb compilation failure on windows * Addressed Jon-Olav's remarks: moved definiton out of my_global.h, some cmake cleanups.
1 parent ed391b6 commit 1ea2c0a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+249
-199
lines changed

CMakeLists.txt

+3
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,9 @@ OPTION(WITHOUT_SERVER OFF)
229229
IF(UNIX)
230230
OPTION(WITH_VALGRIND "Valgrind instrumentation" OFF)
231231
ENDIF()
232+
IF(WIN32)
233+
OPTION(WITH_MSCRT_DEBUG "MS Visual Studio Debug CRT instrumentation" OFF)
234+
ENDIF()
232235
IF(NOT WITHOUT_SERVER)
233236
OPTION (WITH_UNIT_TESTS "Compile MySQL with unit tests" ON)
234237
ENDIF()

client/mysql.cc

+8-8
Original file line numberDiff line numberDiff line change
@@ -1276,7 +1276,7 @@ int main(int argc,char *argv[])
12761276
my_end(0);
12771277
exit(1);
12781278
}
1279-
glob_buffer.realloc(512);
1279+
glob_buffer.mem_realloc(512);
12801280
completion_hash_init(&ht, 128);
12811281
init_alloc_root(PSI_NOT_INSTRUMENTED, &hash_mem_root, 16384, 0);
12821282
memset(&mysql, 0, sizeof(mysql));
@@ -1439,9 +1439,9 @@ void mysql_end(int sig)
14391439

14401440
if (sig >= 0)
14411441
put_info(sig ? "Aborted" : "Bye", INFO_RESULT);
1442-
glob_buffer.free();
1443-
old_buffer.free();
1444-
processed_prompt.free();
1442+
glob_buffer.mem_free();
1443+
old_buffer.mem_free();
1444+
processed_prompt.mem_free();
14451445
my_free(server_version);
14461446
my_free(opt_password);
14471447
my_free(opt_mysql_unix_port);
@@ -2301,8 +2301,8 @@ static int read_and_execute(bool interactive)
23012301
}
23022302

23032303
#if defined(_WIN32)
2304-
buffer.free();
2305-
tmpbuf.free();
2304+
buffer.mem_free();
2305+
tmpbuf.mem_free();
23062306
#else
23072307
if (interactive)
23082308
/*
@@ -2706,7 +2706,7 @@ static bool add_line(String &buffer, char *line, size_t line_length,
27062706
length++;
27072707
}
27082708
if (buffer.length() + length >= buffer.alloced_length())
2709-
buffer.realloc(buffer.length()+length+IO_SIZE);
2709+
buffer.mem_realloc(buffer.length()+length+IO_SIZE);
27102710
if ((!*ml_comment || preserve_comments) && buffer.append(line, length))
27112711
DBUG_RETURN(1);
27122712
}
@@ -5497,7 +5497,7 @@ static void mysql_end_timer(ulong start_time,char *buff)
54975497

54985498
static const char* construct_prompt()
54995499
{
5500-
processed_prompt.free(); // Erase the old prompt
5500+
processed_prompt.mem_free(); // Erase the old prompt
55015501
time_t lclock = time(NULL); // Get the date struct
55025502
struct tm *t = localtime(&lclock);
55035503

cmake/os/Windows.cmake

+5
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,11 @@ ADD_DEFINITIONS(-DWIN32_LEAN_AND_MEAN -DNOGDI)
5858

5959
# We want to use std::min/std::max, not the windows.h macros
6060
ADD_DEFINITIONS(-DNOMINMAX)
61+
62+
IF(WITH_MSCRT_DEBUG)
63+
ADD_DEFINITIONS(-DMY_MSCRT_DEBUG)
64+
ADD_DEFINITIONS(-D_CRTDBG_MAP_ALLOC)
65+
ENDIF()
6166

6267
IF(MSVC)
6368
# Enable debug info also in Release build,

include/m_ctype.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -254,9 +254,9 @@ typedef struct my_charset_loader_st
254254
{
255255
char error[128];
256256
void *(*once_alloc)(size_t);
257-
void *(*malloc)(size_t);
258-
void *(*realloc)(void *, size_t);
259-
void (*free)(void *);
257+
void *(*mem_malloc)(size_t);
258+
void *(*mem_realloc)(void *, size_t);
259+
void (*mem_free)(void *);
260260
void (*reporter)(enum loglevel, const char *format, ...);
261261
int (*add_collation)(struct charset_info_st *cs);
262262
} MY_CHARSET_LOADER;

include/my_global.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
#endif
3333

3434
#include <stdio.h>
35-
#include <stdarg.h>
3635
#include <stdlib.h>
3736
#include <stddef.h>
3837
#include <math.h>
@@ -49,6 +48,9 @@
4948
#if !defined(_WIN32)
5049
#include <netdb.h>
5150
#endif
51+
#ifdef MY_MSCRT_DEBUG
52+
#include <crtdbg.h>
53+
#endif
5254

5355
/*
5456
A lot of our programs uses asserts, so better to always include it

include/sql_string.h

+14-14
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ class String
186186
}
187187
static void operator delete(void *, MEM_ROOT *)
188188
{ /* never called */ }
189-
~String() { free(); }
189+
~String() { mem_free(); }
190190

191191
void set_charset(const CHARSET_INFO *charset_arg)
192192
{ m_charset= charset_arg; }
@@ -204,7 +204,7 @@ class String
204204
(m_alloced_length >= (m_length + 1)));
205205

206206
if (!m_ptr || m_ptr[m_length]) /* Should be safe */
207-
(void) realloc(m_length);
207+
(void) mem_realloc(m_length);
208208
return m_ptr;
209209
}
210210
char *c_ptr_quick()
@@ -218,7 +218,7 @@ class String
218218
if (m_ptr && m_length < m_alloced_length)
219219
m_ptr[m_length]= 0;
220220
else
221-
(void) realloc(m_length);
221+
(void) mem_realloc(m_length);
222222
return m_ptr;
223223
}
224224
LEX_STRING lex_string() const
@@ -236,7 +236,7 @@ class String
236236
void set(String &str,size_t offset, size_t arg_length)
237237
{
238238
DBUG_ASSERT(&str != this);
239-
free();
239+
mem_free();
240240
m_ptr= const_cast<char*>(str.ptr()) + offset;
241241
m_length= arg_length;
242242
m_is_alloced= false;
@@ -258,15 +258,15 @@ class String
258258
*/
259259
void set(char *str, size_t arg_length, const CHARSET_INFO *cs)
260260
{
261-
free();
261+
mem_free();
262262
m_ptr= str;
263263
m_length= m_alloced_length= static_cast<uint32>(arg_length);
264264
m_is_alloced= false;
265265
m_charset= cs;
266266
}
267267
void set(const char *str, size_t arg_length, const CHARSET_INFO *cs)
268268
{
269-
free();
269+
mem_free();
270270
m_ptr= const_cast<char*>(str);
271271
m_length= arg_length;
272272
m_alloced_length= 0;
@@ -320,7 +320,7 @@ class String
320320
DBUG_ASSERT(strlen(m_ptr) == m_length);
321321
}
322322

323-
void free()
323+
void mem_free()
324324
{
325325
if (m_is_alloced)
326326
{
@@ -338,7 +338,7 @@ class String
338338
return real_alloc(arg_length);
339339
}
340340
bool real_alloc(size_t arg_length); // Empties old string
341-
bool realloc(size_t arg_length);
341+
bool mem_realloc(size_t arg_length);
342342

343343
// Shrink the buffer, but only if it is allocated on the heap.
344344
void shrink(size_t arg_length)
@@ -371,7 +371,7 @@ class String
371371
some_string = substring_of_that_string
372372
*/
373373
DBUG_ASSERT(!s.uses_buffer_owned_by(this));
374-
free();
374+
mem_free();
375375
m_ptr= s.m_ptr;
376376
m_length= s.m_length;
377377
m_alloced_length= s.m_alloced_length;
@@ -393,7 +393,7 @@ class String
393393
DBUG_ASSERT(this != &s);
394394
// Make sure buffers of the two Strings do not overlap
395395
DBUG_ASSERT(!s.uses_buffer_owned_by(this));
396-
free();
396+
mem_free();
397397
m_ptr= s.m_ptr;
398398
m_length= s.m_length;
399399
m_alloced_length= s.m_alloced_length;
@@ -456,7 +456,7 @@ class String
456456
}
457457
else
458458
{
459-
if (realloc(m_length+1))
459+
if (mem_realloc(m_length+1))
460460
return 1;
461461
m_ptr[m_length++]= chr;
462462
}
@@ -472,7 +472,7 @@ class String
472472

473473
int reserve(size_t space_needed)
474474
{
475-
return realloc(m_length + space_needed);
475+
return mem_realloc(m_length + space_needed);
476476
}
477477
int reserve(size_t space_needed, size_t grow_by);
478478
/*
@@ -528,7 +528,7 @@ class String
528528
size_t new_length= arg_length + m_length;
529529
if (new_length > m_alloced_length)
530530
{
531-
if (realloc(new_length + step_alloc))
531+
if (mem_realloc(new_length + step_alloc))
532532
return NULL;
533533
}
534534
size_t old_length= m_length;
@@ -539,7 +539,7 @@ class String
539539
bool append(const char *s, size_t arg_length, size_t step_alloc)
540540
{
541541
size_t new_length= arg_length + m_length;
542-
if (new_length > m_alloced_length && realloc(new_length + step_alloc))
542+
if (new_length > m_alloced_length && mem_realloc(new_length + step_alloc))
543543
return true;
544544
memcpy(m_ptr+m_length, s, arg_length);
545545
m_length+= arg_length;

libmysql/authentication_win/handshake.cc

+2-2
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ Handshake::~Handshake()
6666
FreeCredentialsHandle(&m_cred);
6767
if (m_have_sec_context)
6868
DeleteSecurityContext(&m_sctx);
69-
m_output.free();
69+
m_output.mem_free();
7070

7171
#ifndef DBUG_OFF
7272
if (m_ssp_info)
@@ -278,7 +278,7 @@ Security_buffer::Security_buffer(): m_allocated(true)
278278
}
279279

280280

281-
void Security_buffer::free(void)
281+
void Security_buffer::mem_free(void)
282282
{
283283
if (m_allocated && NULL != ptr())
284284
{

libmysql/authentication_win/handshake.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ class Security_buffer: public SecBufferDesc
6767

6868
~Security_buffer()
6969
{
70-
free();
70+
mem_free();
7171
}
7272

7373
byte* ptr() const
@@ -85,7 +85,7 @@ class Security_buffer: public SecBufferDesc
8585
return Blob(ptr(), len());
8686
}
8787

88-
void free(void);
88+
void mem_free(void);
8989
};
9090

9191

libmysql/authentication_win/handshake_client.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ Blob Handshake_client::process_data(const Blob &data)
278278
Security_buffer input(data);
279279
SECURITY_STATUS ret;
280280

281-
m_output.free();
281+
m_output.mem_free();
282282

283283
ret= InitializeSecurityContextW(
284284
&m_cred,

mysys/charset.c

+3-3
Original file line numberDiff line numberDiff line change
@@ -395,9 +395,9 @@ my_charset_loader_init_mysys(MY_CHARSET_LOADER *loader)
395395
{
396396
loader->error[0]= '\0';
397397
loader->once_alloc= my_once_alloc_c;
398-
loader->malloc= my_malloc_c;
399-
loader->realloc= my_realloc_c;
400-
loader->free= my_free_c;
398+
loader->mem_malloc= my_malloc_c;
399+
loader->mem_realloc= my_realloc_c;
400+
loader->mem_free= my_free_c;
401401
loader->reporter= my_charset_error_reporter;
402402
loader->add_collation= add_collation;
403403
}

mysys/my_init.c

+25
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,27 @@ static ulong atoi_octal(const char *str)
5555
MYSQL_FILE *mysql_stdin= NULL;
5656
static MYSQL_FILE instrumented_stdin;
5757

58+
#if defined(MY_MSCRT_DEBUG)
59+
int set_crt_report_leaks()
60+
{
61+
HANDLE hLogFile;
62+
63+
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF // debug allocation on
64+
| _CRTDBG_LEAK_CHECK_DF // leak checks on exit
65+
| _CRTDBG_CHECK_ALWAYS_DF // memory check (slow)
66+
);
67+
68+
return ((
69+
NULL == (hLogFile= GetStdHandle(STD_ERROR_HANDLE)) ||
70+
-1 == _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE) ||
71+
_CRTDBG_HFILE_ERROR == _CrtSetReportFile(_CRT_WARN, hLogFile) ||
72+
-1 == _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE) ||
73+
_CRTDBG_HFILE_ERROR == _CrtSetReportFile(_CRT_ERROR, hLogFile) ||
74+
-1 == _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE) ||
75+
_CRTDBG_HFILE_ERROR == _CrtSetReportFile(_CRT_ASSERT, hLogFile)) ? 1 : 0);
76+
}
77+
#endif
78+
5879

5980
/**
6081
Initialize my_sys functions, resources and variables
@@ -72,6 +93,10 @@ my_bool my_init(void)
7293

7394
my_init_done= 1;
7495

96+
#if defined(MY_MSCRT_DEBUG)
97+
set_crt_report_leaks();
98+
#endif
99+
75100
my_umask= 0660; /* Default umask for new files */
76101
my_umask_dir= 0700; /* Default umask for new directories */
77102

mysys/my_malloc.c

+15
Original file line numberDiff line numberDiff line change
@@ -159,10 +159,17 @@ static void *my_raw_malloc(size_t size, myf my_flags)
159159
if (!size)
160160
size=1;
161161

162+
#if defined(MY_MSCRT_DEBUG)
163+
if (my_flags & MY_ZEROFILL)
164+
point= _calloc_dbg(size, 1, _CLIENT_BLOCK, __FILE__, __LINE__);
165+
else
166+
point= _malloc_dbg(size, _CLIENT_BLOCK, __FILE__, __LINE__);
167+
#else
162168
if (my_flags & MY_ZEROFILL)
163169
point= calloc(size, 1);
164170
else
165171
point= malloc(size);
172+
#endif
166173

167174
DBUG_EXECUTE_IF("simulate_out_of_memory",
168175
{
@@ -221,7 +228,11 @@ static void *my_raw_realloc(void *oldpoint, size_t size, myf my_flags)
221228
goto end;);
222229
if (!oldpoint && (my_flags & MY_ALLOW_ZERO_PTR))
223230
DBUG_RETURN(my_raw_malloc(size, my_flags));
231+
#if defined(MY_MSCRT_DEBUG)
232+
point= _realloc_dbg(oldpoint, size, _CLIENT_BLOCK, __FILE__, __LINE__);
233+
#else
224234
point= realloc(oldpoint, size);
235+
#endif
225236
#ifndef DBUG_OFF
226237
end:
227238
#endif
@@ -254,7 +265,11 @@ static void my_raw_free(void *ptr)
254265
{
255266
DBUG_ENTER("my_free");
256267
DBUG_PRINT("my",("ptr: %p", ptr));
268+
#if defined(MY_MSCRT_DEBUG)
269+
_free_dbg(ptr, _CLIENT_BLOCK);
270+
#else
257271
free(ptr);
272+
#endif
258273
DBUG_VOID_RETURN;
259274
}
260275

0 commit comments

Comments
 (0)