8 #ifdef CHECK_MEMORY_LEAKS
59 #if !_FAST_MUTEX_CHECK_INITIALIZATION && !defined(_NOTHREADS)
60 #error "_FAST_MUTEX_CHECK_INITIALIZATION not set: check_leaks may not work"
69 #ifndef _DEBUG_NEW_ALIGNMENT
70 #define _DEBUG_NEW_ALIGNMENT 16
80 #ifndef _DEBUG_NEW_CALLER_ADDRESS
82 #define _DEBUG_NEW_CALLER_ADDRESS __builtin_return_address(0)
84 #define _DEBUG_NEW_CALLER_ADDRESS NULL
97 #ifndef _DEBUG_NEW_ERROR_ACTION
98 #ifndef _DEBUG_NEW_ERROR_CRASH
99 #define _DEBUG_NEW_ERROR_ACTION abort()
101 #define _DEBUG_NEW_ERROR_ACTION do { *((char*)0) = 0; abort(); } while (0)
116 #ifndef _DEBUG_NEW_FILENAME_LEN
117 #define _DEBUG_NEW_FILENAME_LEN 80
132 #ifndef _DEBUG_NEW_PROGNAME
133 #define _DEBUG_NEW_PROGNAME NULL
143 #ifndef _DEBUG_NEW_STD_OPER_NEW
144 #define _DEBUG_NEW_STD_OPER_NEW 1
154 #ifndef _DEBUG_NEW_TAILCHECK
155 #define _DEBUG_NEW_TAILCHECK 0
163 #ifndef _DEBUG_NEW_TAILCHECK_CHAR
164 #define _DEBUG_NEW_TAILCHECK_CHAR 0xCC
175 #ifndef _DEBUG_NEW_USE_ADDR2LINE
177 #define _DEBUG_NEW_USE_ADDR2LINE 1
179 #define _DEBUG_NEW_USE_ADDR2LINE 0
184 #pragma warning(disable: 4073) // #pragma init_seg(lib) used
185 #pragma warning(disable: 4290) // C++ exception specification ignored
186 #pragma init_seg(lib)
189 #undef _DEBUG_NEW_EMULATE_MALLOC
190 #undef _DEBUG_NEW_REDEFINE_NEW
195 #define _DEBUG_NEW_REDEFINE_NEW 0
202 (((s) + _DEBUG_NEW_ALIGNMENT - 1) & ~(_DEBUG_NEW_ALIGNMENT - 1))
207 struct new_ptr_list_t
209 new_ptr_list_t* next;
210 new_ptr_list_t* prev;
214 #if _DEBUG_NEW_FILENAME_LEN == 0
217 char file[_DEBUG_NEW_FILENAME_LEN];
222 unsigned is_array :1;
229 const unsigned MAGIC = 0x4442474E;
234 const int ALIGNED_LIST_ITEM_SIZE = align(
sizeof(new_ptr_list_t));
239 static new_ptr_list_t new_ptr_list = {
244 #if _DEBUG_NEW_FILENAME_LEN == 0
258 static fast_mutex new_ptr_lock;
263 static fast_mutex new_output_lock;
268 static size_t total_mem_alloc = 0;
274 bool new_autocheck_flag =
true;
279 bool new_verbose_flag =
false;
286 FILE* new_output_fp = stderr;
296 const char* new_progname = _DEBUG_NEW_PROGNAME;
298 #if _DEBUG_NEW_USE_ADDR2LINE
308 static bool print_position_from_addr(
const void* addr)
310 static const void* last_addr = NULL;
311 static char last_info[256] =
"";
312 if (addr == last_addr)
314 if (last_info[0] ==
'\0')
316 fprintf(new_output_fp,
"%s", last_info);
321 const char addr2line_cmd[] =
"addr2line -e ";
322 #if defined(__CYGWIN__) || defined(_WIN32)
323 const int exeext_len = 4;
325 const int exeext_len = 0;
327 #if !defined(__CYGWIN__) && defined(__unix__)
328 const char ignore_err[] =
" 2>/dev/null";
329 #elif defined(__CYGWIN__) || \
330 (defined(_WIN32) && defined(WINVER) && WINVER >= 0x0500)
331 const char ignore_err[] =
" 2>nul";
333 const char ignore_err[] =
"";
335 char* cmd = (
char*)alloca(strlen(new_progname)
337 +
sizeof addr2line_cmd - 1
338 +
sizeof ignore_err - 1
341 strcpy(cmd, addr2line_cmd);
342 strcpy(cmd +
sizeof addr2line_cmd - 1, new_progname);
343 size_t len = strlen(cmd);
344 #if defined(__CYGWIN__) || defined(_WIN32)
346 || (strcmp(cmd + len - 4,
".exe") != 0 &&
347 strcmp(cmd + len - 4,
".EXE") != 0))
349 strcpy(cmd + len,
".exe");
353 sprintf(cmd + len,
" %p%s", addr, ignore_err);
354 FILE* fp = popen(cmd,
"r");
357 char buffer[
sizeof last_info] =
"";
359 if (fgets(buffer,
sizeof buffer, fp))
361 len = strlen(buffer);
362 if (buffer[len - 1] ==
'\n')
363 buffer[--len] =
'\0';
365 int res = pclose(fp);
370 if (res == 0 && len > 0)
373 if (buffer[len - 1] ==
'0' && buffer[len - 2] ==
':')
377 fprintf(new_output_fp,
"%s", buffer);
378 strcpy(last_info, buffer);
393 static bool print_position_from_addr(
const void*)
397 #endif // _DEBUG_NEW_USE_ADDR2LINE
410 static void print_position(
const void* ptr,
int line)
414 fprintf(new_output_fp,
"%s:%d", (
const char*)ptr, line);
416 else if (ptr != NULL)
418 if (!print_position_from_addr(ptr))
419 fprintf(new_output_fp,
"%p", ptr);
423 fprintf(new_output_fp,
"<Unknown>");
427 #if _DEBUG_NEW_TAILCHECK
436 static bool check_tail(new_ptr_list_t* ptr)
438 const unsigned char*
const pointer = (
unsigned char*)ptr +
439 ALIGNED_LIST_ITEM_SIZE + ptr->size;
440 for (
int i = 0; i < _DEBUG_NEW_TAILCHECK; ++i)
441 if (pointer[i] != _DEBUG_NEW_TAILCHECK_CHAR)
457 static void* alloc_mem(
size_t size,
const char* file,
int line,
bool is_array)
460 STATIC_ASSERT((_DEBUG_NEW_ALIGNMENT & (_DEBUG_NEW_ALIGNMENT - 1)) == 0,
461 Alignment_must_be_power_of_two);
462 STATIC_ASSERT(_DEBUG_NEW_TAILCHECK >= 0, Invalid_tail_check_length);
463 size_t s = size + ALIGNED_LIST_ITEM_SIZE + _DEBUG_NEW_TAILCHECK;
464 new_ptr_list_t* ptr = (new_ptr_list_t*)malloc(s);
467 #if _DEBUG_NEW_STD_OPER_NEW
470 fast_mutex_autolock lock(new_output_lock);
471 fprintf(new_output_fp,
472 "Out of memory when allocating %u bytes\n",
474 fflush(new_output_fp);
475 _DEBUG_NEW_ERROR_ACTION;
478 void* pointer = (
char*)ptr + ALIGNED_LIST_ITEM_SIZE;
479 #if _DEBUG_NEW_FILENAME_LEN == 0
483 strncpy(ptr->file, file, _DEBUG_NEW_FILENAME_LEN - 1)
484 [_DEBUG_NEW_FILENAME_LEN - 1] =
'\0';
486 ptr->addr = (
void*)file;
489 ptr->is_array = is_array;
493 fast_mutex_autolock lock(new_ptr_lock);
494 ptr->prev = new_ptr_list.prev;
495 ptr->next = &new_ptr_list;
496 new_ptr_list.prev->next = ptr;
497 new_ptr_list.prev = ptr;
499 #if _DEBUG_NEW_TAILCHECK
500 memset((
char*)pointer + size, _DEBUG_NEW_TAILCHECK_CHAR,
501 _DEBUG_NEW_TAILCHECK);
503 if (new_verbose_flag)
505 fast_mutex_autolock lock(new_output_lock);
506 fprintf(new_output_fp,
507 "new%s: allocated %p (size %lu, ",
508 is_array ?
"[]" :
"",
511 print_position(ptr->file, ptr->line);
513 print_position(ptr->addr, ptr->line);
514 fprintf(new_output_fp,
")\n");
516 total_mem_alloc += size;
528 static void free_pointer(
void* pointer,
void* addr,
bool is_array)
532 new_ptr_list_t* ptr =
533 (new_ptr_list_t*)((
char*)pointer - ALIGNED_LIST_ITEM_SIZE);
534 if (ptr->magic != MAGIC)
537 fast_mutex_autolock lock(new_output_lock);
538 fprintf(new_output_fp,
"delete%s: invalid pointer %p (",
539 is_array ?
"[]" :
"", pointer);
540 print_position(addr, 0);
541 fprintf(new_output_fp,
")\n");
543 check_mem_corruption();
544 fflush(new_output_fp);
545 _DEBUG_NEW_ERROR_ACTION;
547 if (is_array != ptr->is_array)
551 msg =
"delete[] after new";
553 msg =
"delete after new[]";
554 fast_mutex_autolock lock(new_output_lock);
555 fprintf(new_output_fp,
556 "%s: pointer %p (size %lu)\n\tat ",
558 (
char*)ptr + ALIGNED_LIST_ITEM_SIZE,
560 print_position(addr, 0);
561 fprintf(new_output_fp,
"\n\toriginally allocated at ");
563 print_position(ptr->file, ptr->line);
565 print_position(ptr->addr, ptr->line);
566 fprintf(new_output_fp,
"\n");
567 fflush(new_output_fp);
568 _DEBUG_NEW_ERROR_ACTION;
570 #if _DEBUG_NEW_TAILCHECK
571 if (!check_tail(ptr))
573 check_mem_corruption();
574 fflush(new_output_fp);
575 _DEBUG_NEW_ERROR_ACTION;
579 fast_mutex_autolock lock(new_ptr_lock);
580 total_mem_alloc -= ptr->size;
582 ptr->prev->next = ptr->next;
583 ptr->next->prev = ptr->prev;
585 if (new_verbose_flag)
587 fast_mutex_autolock lock(new_output_lock);
588 fprintf(new_output_fp,
589 "delete%s: freed %p (size %lu, %lu bytes still allocated)\n",
590 is_array ?
"[]" :
"",
591 (
char*)ptr + ALIGNED_LIST_ITEM_SIZE,
592 ptr->size, total_mem_alloc);
606 fast_mutex_autolock lock_ptr(new_ptr_lock);
607 fast_mutex_autolock lock_output(new_output_lock);
608 new_ptr_list_t* ptr = new_ptr_list.next;
609 while (ptr != &new_ptr_list)
611 const char*
const pointer = (
char*)ptr + ALIGNED_LIST_ITEM_SIZE;
612 if (ptr->magic != MAGIC)
614 fprintf(new_output_fp,
615 "warning: heap data corrupt near %p\n",
618 #if _DEBUG_NEW_TAILCHECK
619 if (!check_tail(ptr))
621 fprintf(new_output_fp,
622 "warning: overwritten past end of object at %p\n",
626 fprintf(new_output_fp,
627 "Leaked object at %p (size %lu, ",
631 print_position(ptr->file, ptr->line);
633 print_position(ptr->addr, ptr->line);
634 fprintf(new_output_fp,
")\n");
638 if (new_verbose_flag || leak_cnt)
639 fprintf(new_output_fp,
"*** %d leaks found\n", leak_cnt);
649 int check_mem_corruption()
652 fast_mutex_autolock lock_ptr(new_ptr_lock);
653 fast_mutex_autolock lock_output(new_output_lock);
654 fprintf(new_output_fp,
"*** Checking for memory corruption: START\n");
655 for (new_ptr_list_t* ptr = new_ptr_list.next;
656 ptr != &new_ptr_list;
659 const char*
const pointer = (
char*)ptr + ALIGNED_LIST_ITEM_SIZE;
660 if (ptr->magic == MAGIC
661 #
if _DEBUG_NEW_TAILCHECK
666 #if _DEBUG_NEW_TAILCHECK
667 if (ptr->magic != MAGIC)
670 fprintf(new_output_fp,
671 "Heap data corrupt near %p (size %lu, ",
674 #if _DEBUG_NEW_TAILCHECK
678 fprintf(new_output_fp,
679 "Overwritten past end of object at %p (size %u, ",
685 print_position(ptr->file, ptr->line);
687 print_position(ptr->addr, ptr->line);
688 fprintf(new_output_fp,
")\n");
691 fprintf(new_output_fp,
"*** Checking for memory corruption: %d FOUND\n",
696 void __debug_new_recorder::_M_process(
void* pointer)
700 new_ptr_list_t* ptr =
701 (new_ptr_list_t*)((
char*)pointer - ALIGNED_LIST_ITEM_SIZE);
702 if (ptr->magic != MAGIC || ptr->line != 0)
704 fast_mutex_autolock lock(new_output_lock);
705 fprintf(new_output_fp,
706 "warning: debug_new used with placement new (%s:%d)\n",
710 #if _DEBUG_NEW_FILENAME_LEN == 0
713 strncpy(ptr->file, _M_file, _DEBUG_NEW_FILENAME_LEN - 1)
714 [_DEBUG_NEW_FILENAME_LEN - 1] =
'\0';
719 void*
operator new(
size_t size,
const char* file,
int line)
721 void* ptr = alloc_mem(size, file, line,
false);
722 #if _DEBUG_NEW_STD_OPER_NEW
726 throw std::bad_alloc();
732 void*
operator new[](
size_t size,
const char* file,
int line)
734 void* ptr = alloc_mem(size, file, line,
true);
735 #if _DEBUG_NEW_STD_OPER_NEW
739 throw std::bad_alloc();
745 void*
operator new(
size_t size)
throw(std::bad_alloc)
747 return operator new(size, (
char*)_DEBUG_NEW_CALLER_ADDRESS, 0);
750 void*
operator new[](
size_t size)
throw(std::bad_alloc)
752 return operator new[](size, (
char*)_DEBUG_NEW_CALLER_ADDRESS, 0);
755 #if !defined(__BORLANDC__) || __BORLANDC__ > 0x551
756 void*
operator new(
size_t size,
const std::nothrow_t&)
throw()
758 return alloc_mem(size, (
char*)_DEBUG_NEW_CALLER_ADDRESS, 0,
false);
761 void*
operator new[](
size_t size,
const std::nothrow_t&)
throw()
763 return alloc_mem(size, (
char*)_DEBUG_NEW_CALLER_ADDRESS, 0,
true);
767 void operator delete(
void* pointer)
throw()
769 free_pointer(pointer, _DEBUG_NEW_CALLER_ADDRESS,
false);
772 void operator delete[](
void* pointer)
throw()
774 free_pointer(pointer, _DEBUG_NEW_CALLER_ADDRESS,
true);
777 #if HAVE_PLACEMENT_DELETE
778 void operator delete(
void* pointer,
const char* file,
int line)
throw()
780 if (new_verbose_flag)
782 fast_mutex_autolock lock(new_output_lock);
783 fprintf(new_output_fp,
784 "info: exception thrown on initializing object at %p (",
786 print_position(file, line);
787 fprintf(new_output_fp,
")\n");
789 operator delete(pointer);
792 void operator delete[](
void* pointer,
const char* file,
int line)
throw()
794 if (new_verbose_flag)
796 fast_mutex_autolock lock(new_output_lock);
797 fprintf(new_output_fp,
798 "info: exception thrown on initializing objects at %p (",
800 print_position(file, line);
801 fprintf(new_output_fp,
")\n");
803 operator delete[](pointer);
806 void operator delete(
void* pointer,
const std::nothrow_t&)
throw()
808 operator delete(pointer, (
char*)_DEBUG_NEW_CALLER_ADDRESS, 0);
811 void operator delete[](
void* pointer,
const std::nothrow_t&)
throw()
813 operator delete[](pointer, (
char*)_DEBUG_NEW_CALLER_ADDRESS, 0);
815 #endif // HAVE_PLACEMENT_DELETE
817 int __debug_new_counter::_S_count = 0;
822 __debug_new_counter::__debug_new_counter()
831 __debug_new_counter::~__debug_new_counter()
833 if (--_S_count == 0 && new_autocheck_flag)
836 new_verbose_flag =
true;
837 #if defined(__GNUC__) && __GNUC__ >= 3
838 if (!getenv(
"GLIBCPP_FORCE_NEW") && !getenv(
"GLIBCXX_FORCE_NEW"))
839 fprintf(new_output_fp,
840 "*** WARNING: GCC 3 or later is detected, please make sure the\n"
841 " environment variable GLIBCPP_FORCE_NEW (GCC 3.2 and 3.3) or\n"
842 " GLIBCXX_FORCE_NEW (GCC 3.4 and later) is defined. Check the\n"
843 " README file for details.\n");