00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00039 #ifdef _MSC_VER
00040 #include <windows_config.h>
00041 #else
00042 #include <config.h>
00043 #endif
00044
00045 #ifdef CHECK_MEMORY_LEAKS
00046
00047 #include <new>
00048 #include <assert.h>
00049 #include <limits.h>
00050 #include <stdio.h>
00051 #include <stdlib.h>
00052 #include <string.h>
00053 #ifdef __unix__
00054 #include <alloca.h>
00055 #endif
00056 #ifdef _WIN32
00057 #include <malloc.h>
00058 #endif
00059 #include "fast_mutex.h"
00060 #include "static_assert.h"
00061
00062 #if !_FAST_MUTEX_CHECK_INITIALIZATION && !defined(_NOTHREADS)
00063 #error "_FAST_MUTEX_CHECK_INITIALIZATION not set: check_leaks may not work"
00064 #endif
00065
00072 #ifndef _DEBUG_NEW_ALIGNMENT
00073 #define _DEBUG_NEW_ALIGNMENT 16
00074 #endif
00075
00083 #ifndef _DEBUG_NEW_CALLER_ADDRESS
00084 #ifdef __GNUC__
00085 #define _DEBUG_NEW_CALLER_ADDRESS __builtin_return_address(0)
00086 #else
00087 #define _DEBUG_NEW_CALLER_ADDRESS NULL
00088 #endif
00089 #endif
00090
00100 #ifndef _DEBUG_NEW_ERROR_ACTION
00101 #ifndef _DEBUG_NEW_ERROR_CRASH
00102 #define _DEBUG_NEW_ERROR_ACTION abort()
00103 #else
00104 #define _DEBUG_NEW_ERROR_ACTION do { *((char*)0) = 0; abort(); } while (0)
00105 #endif
00106 #endif
00107
00120 #ifndef _DEBUG_NEW_FILENAME_LEN
00121 #define _DEBUG_NEW_FILENAME_LEN 80
00122 #endif
00123
00131 #ifndef _DEBUG_NEW_HASHTABLESIZE
00132 #define _DEBUG_NEW_HASHTABLESIZE 16384
00133 #endif
00134
00141 #ifndef _DEBUG_NEW_HASH
00142 #define _DEBUG_NEW_HASH(p) (((size_t)(p) >> 8) % _DEBUG_NEW_HASHTABLESIZE)
00143 #endif
00144
00157 #ifndef _DEBUG_NEW_PROGNAME
00158 #define _DEBUG_NEW_PROGNAME NULL
00159 #endif
00160
00169 #ifndef _DEBUG_NEW_USE_ADDR2LINE
00170 #ifdef __GNUC__
00171 #define _DEBUG_NEW_USE_ADDR2LINE 1
00172 #else
00173 #define _DEBUG_NEW_USE_ADDR2LINE 0
00174 #endif
00175 #endif
00176
00177 #ifdef _MSC_VER
00178 #pragma warning(disable: 4073) // #pragma init_seg(lib) used
00179 #pragma warning(disable: 4290) // C++ exception specification ignored
00180 #pragma init_seg(lib)
00181 #endif
00182
00183 #undef _DEBUG_NEW_EMULATE_MALLOC
00184 #undef _DEBUG_NEW_REDEFINE_NEW
00185
00189 #define _DEBUG_NEW_REDEFINE_NEW 0
00190 #include "debug_new.h"
00191
00195 #define align(s) \
00196 (((s) + _DEBUG_NEW_ALIGNMENT - 1) & ~(_DEBUG_NEW_ALIGNMENT - 1))
00197
00201 struct new_ptr_list_t
00202 {
00203 new_ptr_list_t* next;
00204 union
00205 {
00206 #if _DEBUG_NEW_FILENAME_LEN == 0
00207 const char* file;
00208 #else
00209 char file[_DEBUG_NEW_FILENAME_LEN];
00210 #endif
00211 void* addr;
00212 };
00213 int line;
00214 size_t size;
00215 };
00216
00220 const int aligned_list_item_size = align(sizeof(new_ptr_list_t));
00221
00225 static new_ptr_list_t* new_ptr_list[_DEBUG_NEW_HASHTABLESIZE];
00226
00231 static fast_mutex new_ptr_lock[_DEBUG_NEW_HASHTABLESIZE];
00232
00236 static fast_mutex new_output_lock;
00237
00241 static size_t total_mem_alloc = 0;
00242
00247 bool new_autocheck_flag = true;
00248
00252 bool new_verbose_flag = false;
00253
00259 FILE* new_output_fp = stderr;
00260
00269 const char* new_progname = _DEBUG_NEW_PROGNAME;
00270
00271 #if _DEBUG_NEW_USE_ADDR2LINE
00272
00281 static bool print_position_from_addr(const void* addr)
00282 {
00283 static const void* last_addr = NULL;
00284 static char last_info[256] = "";
00285 if (addr == last_addr)
00286 {
00287 if (last_info[0] == '\0')
00288 return false;
00289 fprintf(new_output_fp, "%s", last_info);
00290 return true;
00291 }
00292 if (new_progname)
00293 {
00294 const char addr2line_cmd[] = "addr2line -e ";
00295 #if defined(__CYGWIN__) || defined(_WIN32)
00296 const int exeext_len = 4;
00297 #else
00298 const int exeext_len = 0;
00299 #endif
00300 #if !defined(__CYGWIN__) && defined(__unix__)
00301 const char ignore_err[] = " 2>/dev/null";
00302 #elif defined(__CYGWIN__) || \
00303 (defined(_WIN32) && defined(WINVER) && WINVER >= 0x0500)
00304 const char ignore_err[] = " 2>nul";
00305 #else
00306 const char ignore_err[] = "";
00307 #endif
00308 char* cmd = (char*)alloca(strlen(new_progname)
00309 + exeext_len
00310 + sizeof addr2line_cmd - 1
00311 + sizeof ignore_err - 1
00312 + sizeof(void*) * 2
00313 + 4 );
00314 strcpy(cmd, addr2line_cmd);
00315 strcpy(cmd + sizeof addr2line_cmd - 1, new_progname);
00316 size_t len = strlen(cmd);
00317 #if defined(__CYGWIN__) || defined(_WIN32)
00318 if (len <= 4
00319 || (strcmp(cmd + len - 4, ".exe") != 0 &&
00320 strcmp(cmd + len - 4, ".EXE") != 0))
00321 {
00322 strcpy(cmd + len, ".exe");
00323 len += 4;
00324 }
00325 #endif
00326 sprintf(cmd + len, " %p%s", addr, ignore_err);
00327 FILE* fp = popen(cmd, "r");
00328 if (fp)
00329 {
00330 char buffer[sizeof last_info] = "";
00331 len = 0;
00332 if (fgets(buffer, sizeof buffer, fp))
00333 {
00334 len = strlen(buffer);
00335 if (buffer[len - 1] == '\n')
00336 buffer[--len] = '\0';
00337 }
00338 int res = pclose(fp);
00339
00340
00341
00342
00343 if (res == 0 && len > 0)
00344 {
00345 last_addr = addr;
00346 if (buffer[len - 1] == '0' && buffer[len - 2] == ':')
00347 last_info[0] = '\0';
00348 else
00349 {
00350 fprintf(new_output_fp, "%s", buffer);
00351 strcpy(last_info, buffer);
00352 return true;
00353 }
00354 }
00355 }
00356 }
00357 return false;
00358 }
00359 #else
00360
00366 static bool print_position_from_addr(const void*)
00367 {
00368 return false;
00369 }
00370 #endif // _DEBUG_NEW_USE_ADDR2LINE
00371
00383 static void print_position(const void* ptr, int line)
00384 {
00385 line &= ~INT_MIN;
00386 if (line != 0)
00387 {
00388 fprintf(new_output_fp, "%s:%d", (const char*)ptr, line);
00389 }
00390 else if (ptr != NULL)
00391 {
00392 if (!print_position_from_addr(ptr))
00393 fprintf(new_output_fp, "%p", ptr);
00394 }
00395 else
00396 {
00397 fprintf(new_output_fp, "<Unknown>");
00398 }
00399 }
00400
00411 static new_ptr_list_t** search_pointer(void* pointer, size_t hash_index)
00412 {
00413 new_ptr_list_t** raw_ptr = &new_ptr_list[hash_index];
00414 while (*raw_ptr)
00415 {
00416 if ((char*)*raw_ptr + aligned_list_item_size == pointer)
00417 {
00418 return raw_ptr;
00419 }
00420 raw_ptr = &(*raw_ptr)->next;
00421 }
00422 return NULL;
00423 }
00424
00436 static void free_pointer(new_ptr_list_t** raw_ptr, void* addr, bool array_mode)
00437 {
00438 new_ptr_list_t* ptr = *raw_ptr;
00439 int array_mode_mismatch = array_mode ^ ((ptr->line & INT_MIN) != 0);
00440 if (array_mode_mismatch)
00441 {
00442 const char* msg;
00443 if (array_mode)
00444 msg = "delete[] after new";
00445 else
00446 msg = "delete after new[]";
00447 fast_mutex_autolock lock(new_output_lock);
00448 fprintf(new_output_fp,
00449 "%s: pointer %p (size %u)\n\tat ",
00450 msg,
00451 (char*)ptr + aligned_list_item_size,
00452 ptr->size);
00453 print_position(addr, 0);
00454 fprintf(new_output_fp, "\n\toriginally allocated at ");
00455 if ((ptr->line & ~INT_MIN) != 0)
00456 print_position(ptr->file, ptr->line);
00457 else
00458 print_position(ptr->addr, ptr->line);
00459 fprintf(new_output_fp, "\n");
00460 fflush(new_output_fp);
00461 _DEBUG_NEW_ERROR_ACTION;
00462 }
00463 total_mem_alloc -= ptr->size;
00464 if (new_verbose_flag)
00465 {
00466 fast_mutex_autolock lock(new_output_lock);
00467 fprintf(new_output_fp,
00468 "delete: freeing %p (size %u, %u bytes still allocated)\n",
00469 (char*)ptr + aligned_list_item_size,
00470 ptr->size, total_mem_alloc);
00471 }
00472 *raw_ptr = ptr->next;
00473 free(ptr);
00474 return;
00475 }
00476
00482 int check_leaks()
00483 {
00484 int leak_cnt = 0;
00485 for (int i = 0; i < _DEBUG_NEW_HASHTABLESIZE; ++i)
00486 {
00487 fast_mutex_autolock lock(new_ptr_lock[i]);
00488 new_ptr_list_t* ptr = new_ptr_list[i];
00489 if (ptr == NULL)
00490 continue;
00491 while (ptr)
00492 {
00493 fast_mutex_autolock lock(new_output_lock);
00494 fprintf(new_output_fp,
00495 "Leaked object at %p (size %u, ",
00496 (char*)ptr + aligned_list_item_size,
00497 ptr->size);
00498 if ((ptr->line & ~INT_MIN) != 0)
00499 print_position(ptr->file, ptr->line);
00500 else
00501 print_position(ptr->addr, ptr->line);
00502 fprintf(new_output_fp, ")\n");
00503 ptr = ptr->next;
00504 ++leak_cnt;
00505 }
00506 }
00507 return leak_cnt;
00508 }
00509
00510 void* operator new(size_t size, const char* file, int line)
00511 {
00512 assert((line & INT_MIN) == 0);
00513 STATIC_ASSERT((_DEBUG_NEW_ALIGNMENT & (_DEBUG_NEW_ALIGNMENT - 1)) == 0,
00514 Alignment_must_be_power_of_two);
00515 size_t s = size + aligned_list_item_size;
00516 new_ptr_list_t* ptr = (new_ptr_list_t*)malloc(s);
00517 if (ptr == NULL)
00518 {
00519 fast_mutex_autolock lock(new_output_lock);
00520 fprintf(new_output_fp,
00521 "new: out of memory when allocating %u bytes\n",
00522 size);
00523 fflush(new_output_fp);
00524 _DEBUG_NEW_ERROR_ACTION;
00525 }
00526 void* pointer = (char*)ptr + aligned_list_item_size;
00527 size_t hash_index = _DEBUG_NEW_HASH(pointer);
00528 #if _DEBUG_NEW_FILENAME_LEN == 0
00529 ptr->file = file;
00530 #else
00531 if (line)
00532 strncpy(ptr->file, file, _DEBUG_NEW_FILENAME_LEN - 1)
00533 [_DEBUG_NEW_FILENAME_LEN - 1] = '\0';
00534 else
00535 ptr->addr = (void*)file;
00536 #endif
00537 ptr->line = line;
00538 ptr->size = size;
00539 {
00540 fast_mutex_autolock lock(new_ptr_lock[hash_index]);
00541 ptr->next = new_ptr_list[hash_index];
00542 new_ptr_list[hash_index] = ptr;
00543 }
00544 if (new_verbose_flag)
00545 {
00546 fast_mutex_autolock lock(new_output_lock);
00547 fprintf(new_output_fp,
00548 "new: allocated %p (size %u, ",
00549 pointer, size);
00550 if (line != 0)
00551 print_position(ptr->file, ptr->line);
00552 else
00553 print_position(ptr->addr, ptr->line);
00554 fprintf(new_output_fp, ")\n");
00555 }
00556 total_mem_alloc += size;
00557 return pointer;
00558 }
00559
00560 void* operator new[](size_t size, const char* file, int line)
00561 {
00562 void* pointer = operator new(size, file, line);
00563 new_ptr_list_t* ptr =
00564 (new_ptr_list_t*)((char*)pointer - aligned_list_item_size);
00565 assert((ptr->line & INT_MIN) == 0);
00566 ptr->line |= INT_MIN;
00567 return pointer;
00568 }
00569
00570 void* operator new(size_t size) throw(std::bad_alloc)
00571 {
00572 return operator new(size, (char*)_DEBUG_NEW_CALLER_ADDRESS, 0);
00573 }
00574
00575 void* operator new[](size_t size) throw(std::bad_alloc)
00576 {
00577 return operator new[](size, (char*)_DEBUG_NEW_CALLER_ADDRESS, 0);
00578 }
00579
00580 #if !defined(__BORLANDC__) || __BORLANDC__ > 0x551
00581 void* operator new(size_t size, const std::nothrow_t&) throw()
00582 {
00583 return operator new(size, (char*)_DEBUG_NEW_CALLER_ADDRESS, 0);
00584 }
00585
00586 void* operator new[](size_t size, const std::nothrow_t&) throw()
00587 {
00588 return operator new[](size, (char*)_DEBUG_NEW_CALLER_ADDRESS, 0);
00589 }
00590 #endif
00591
00592 void operator delete(void* pointer) throw()
00593 {
00594 if (pointer == NULL)
00595 return;
00596 size_t hash_index = _DEBUG_NEW_HASH(pointer);
00597 fast_mutex_autolock lock(new_ptr_lock[hash_index]);
00598 new_ptr_list_t** raw_ptr = search_pointer(pointer, hash_index);
00599 if (raw_ptr == NULL)
00600 {
00601 fast_mutex_autolock lock(new_output_lock);
00602 fprintf(new_output_fp, "delete: invalid pointer %p at ", pointer);
00603 print_position(_DEBUG_NEW_CALLER_ADDRESS, 0);
00604 fprintf(new_output_fp, "\n");
00605 fflush(new_output_fp);
00606 _DEBUG_NEW_ERROR_ACTION;
00607 }
00608 free_pointer(raw_ptr, _DEBUG_NEW_CALLER_ADDRESS, false);
00609 }
00610
00611 void operator delete[](void* pointer) throw()
00612 {
00613 if (pointer == NULL)
00614 return;
00615 size_t hash_index = _DEBUG_NEW_HASH(pointer);
00616 fast_mutex_autolock lock(new_ptr_lock[hash_index]);
00617 new_ptr_list_t** raw_ptr = search_pointer(pointer, hash_index);
00618 if (raw_ptr == NULL)
00619 {
00620 fast_mutex_autolock lock(new_output_lock);
00621 fprintf(new_output_fp, "delete[]: invalid pointer %p at ", pointer);
00622 print_position(_DEBUG_NEW_CALLER_ADDRESS, 0);
00623 fprintf(new_output_fp, "\n");
00624 fflush(new_output_fp);
00625 _DEBUG_NEW_ERROR_ACTION;
00626 }
00627 free_pointer(raw_ptr, _DEBUG_NEW_CALLER_ADDRESS, true);
00628 }
00629
00630 #if HAS_PLACEMENT_DELETE
00631 void operator delete(void* pointer, const char* file, int line) throw()
00632 {
00633 if (new_verbose_flag)
00634 {
00635 fast_mutex_autolock lock(new_output_lock);
00636 fprintf(new_output_fp,
00637 "info: exception thrown on initializing object at %p (",
00638 pointer);
00639 print_position(file, line);
00640 fprintf(new_output_fp, ")\n");
00641 }
00642 operator delete(pointer);
00643 }
00644
00645 void operator delete[](void* pointer, const char* file, int line) throw()
00646 {
00647 if (new_verbose_flag)
00648 {
00649 fast_mutex_autolock lock(new_output_lock);
00650 fprintf(new_output_fp,
00651 "info: exception thrown on initializing objects at %p (",
00652 pointer);
00653 print_position(file, line);
00654 fprintf(new_output_fp, ")\n");
00655 }
00656 operator delete[](pointer);
00657 }
00658
00659 void operator delete(void* pointer, const std::nothrow_t&) throw()
00660 {
00661 operator delete(pointer, (char*)_DEBUG_NEW_CALLER_ADDRESS, 0);
00662 }
00663
00664 void operator delete[](void* pointer, const std::nothrow_t&) throw()
00665 {
00666 operator delete[](pointer, (char*)_DEBUG_NEW_CALLER_ADDRESS, 0);
00667 }
00668 #endif // HAS_PLACEMENT_DELETE
00669
00670 int __debug_new_counter::_count = 0;
00671
00675 __debug_new_counter::__debug_new_counter()
00676 {
00677 ++_count;
00678 }
00679
00684 __debug_new_counter::~__debug_new_counter()
00685 {
00686 if (--_count == 0 && new_autocheck_flag)
00687 if (check_leaks())
00688 {
00689 new_verbose_flag = true;
00690 #if defined(__GNUC__) && __GNUC__ >= 3
00691 if (!getenv("GLIBCPP_FORCE_NEW") && !getenv("GLIBCXX_FORCE_NEW"))
00692 fprintf(new_output_fp,
00693 "*** WARNING: GCC 3 or later is detected, please make sure the\n"
00694 " environment variable GLIBCPP_FORCE_NEW (GCC 3.2 and 3.3) or\n"
00695 " GLIBCXX_FORCE_NEW (GCC 3.4 and later) is defined. Check the\n"
00696 " README file for details.\n");
00697 #endif
00698 }
00699 }
00700
00701 #endif // CHECK_MEMORY_LEAKS