8 #ifdef CHECK_MEMORY_LEAKS
48 #if defined(__unix__) || defined(__unix) || \
49 (defined(__APPLE__) && defined(__MACH__))
60 #if !_FAST_MUTEX_CHECK_INITIALIZATION && !defined(_NOTHREADS)
61 #error "_FAST_MUTEX_CHECK_INITIALIZATION not set: check_leaks may not work"
70 #ifndef _DEBUG_NEW_ALIGNMENT
71 #define _DEBUG_NEW_ALIGNMENT 16
81 #ifndef _DEBUG_NEW_CALLER_ADDRESS
83 #define _DEBUG_NEW_CALLER_ADDRESS __builtin_return_address(0)
85 #define _DEBUG_NEW_CALLER_ADDRESS NULL
98 #ifndef _DEBUG_NEW_ERROR_ACTION
99 #ifndef _DEBUG_NEW_ERROR_CRASH
100 #define _DEBUG_NEW_ERROR_ACTION abort()
102 #define _DEBUG_NEW_ERROR_ACTION do { *((char*)0) = 0; abort(); } while (0)
118 #ifndef _DEBUG_NEW_FILENAME_LEN
120 #define _DEBUG_NEW_FILENAME_LEN 0
122 #define _DEBUG_NEW_FILENAME_LEN 44
138 #ifndef _DEBUG_NEW_PROGNAME
139 #define _DEBUG_NEW_PROGNAME NULL
149 #ifndef _DEBUG_NEW_STD_OPER_NEW
150 #define _DEBUG_NEW_STD_OPER_NEW 1
160 #ifndef _DEBUG_NEW_TAILCHECK
161 #define _DEBUG_NEW_TAILCHECK 0
169 #ifndef _DEBUG_NEW_TAILCHECK_CHAR
170 #define _DEBUG_NEW_TAILCHECK_CHAR 0xCC
181 #ifndef _DEBUG_NEW_USE_ADDR2LINE
183 #define _DEBUG_NEW_USE_ADDR2LINE 1
185 #define _DEBUG_NEW_USE_ADDR2LINE 0
190 #pragma warning(disable: 4074) // #pragma init_seg(compiler) used
191 #pragma warning(disable: 4290) // C++ exception specification ignored
192 #if _MSC_VER >= 1400 // Visual Studio 2005 or later
193 #pragma warning(disable: 4996) // Use the `unsafe' strncpy
195 #pragma init_seg(compiler)
198 #undef _DEBUG_NEW_EMULATE_MALLOC
199 #undef _DEBUG_NEW_REDEFINE_NEW
204 #define _DEBUG_NEW_REDEFINE_NEW 0
211 (((s) + _DEBUG_NEW_ALIGNMENT - 1) & ~(_DEBUG_NEW_ALIGNMENT - 1))
223 const size_t PLATFORM_MEM_ALIGNMENT =
sizeof(size_t) * 2;
228 struct new_ptr_list_t
230 new_ptr_list_t* next;
231 new_ptr_list_t* prev;
235 #if _DEBUG_NEW_FILENAME_LEN == 0
238 char file[_DEBUG_NEW_FILENAME_LEN];
250 static const unsigned DEBUG_NEW_MAGIC = 0x4442474E;
255 static const int ALIGNED_LIST_ITEM_SIZE = ALIGN(
sizeof(new_ptr_list_t));
260 static new_ptr_list_t new_ptr_list = {
265 #if _DEBUG_NEW_FILENAME_LEN == 0
289 static size_t total_mem_alloc = 0;
319 #if _DEBUG_NEW_USE_ADDR2LINE
329 static bool print_position_from_addr(
const void* addr)
331 static const void* last_addr = NULL;
332 static char last_info[256] =
"";
333 if (addr == last_addr)
335 if (last_info[0] ==
'\0')
337 fprintf(new_output_fp,
"%s", last_info);
342 #if defined(__APPLE__) && defined(__MACH__)
343 const char addr2line_cmd[] =
"atos -o ";
345 const char addr2line_cmd[] =
"addr2line -e ";
347 #if defined(__CYGWIN__) || defined(_WIN32)
348 const int exeext_len = 4;
350 const int exeext_len = 0;
352 #if !defined(__CYGWIN__) && \
353 (defined(__unix__) || defined(__unix) || \
354 (defined(__APPLE__) && defined(__MACH__)))
355 const char ignore_err[] =
" 2>/dev/null";
356 #elif defined(__CYGWIN__) || \
357 (defined(_WIN32) && defined(WINVER) && WINVER >= 0x0500)
358 const char ignore_err[] =
" 2>nul";
360 const char ignore_err[] =
"";
362 char* cmd = (
char*)alloca(strlen(new_progname)
364 +
sizeof addr2line_cmd - 1
365 +
sizeof ignore_err - 1
368 strcpy(cmd, addr2line_cmd);
369 strcpy(cmd +
sizeof addr2line_cmd - 1, new_progname);
370 size_t len = strlen(cmd);
371 #if defined(__CYGWIN__) || defined(_WIN32)
373 || (strcmp(cmd + len - 4,
".exe") != 0 &&
374 strcmp(cmd + len - 4,
".EXE") != 0))
376 strcpy(cmd + len,
".exe");
380 sprintf(cmd + len,
" %p%s", addr, ignore_err);
381 FILE* fp = popen(cmd,
"r");
384 char buffer[
sizeof last_info] =
"";
386 if (fgets(buffer,
sizeof buffer, fp))
388 len = strlen(buffer);
389 if (buffer[len - 1] ==
'\n')
390 buffer[--len] =
'\0';
392 int res = pclose(fp);
397 if (res == 0 && len > 0)
400 if (buffer[len - 1] ==
'0' && buffer[len - 2] ==
':')
404 fprintf(new_output_fp,
"%s", buffer);
405 strcpy(last_info, buffer);
420 static bool print_position_from_addr(
const void*)
424 #endif // _DEBUG_NEW_USE_ADDR2LINE
437 static void print_position(
const void* ptr,
int line)
441 fprintf(new_output_fp,
"%s:%d", (
const char*)ptr, line);
443 else if (ptr != NULL)
445 if (!print_position_from_addr(ptr))
446 fprintf(new_output_fp,
"%p", ptr);
450 fprintf(new_output_fp,
"<Unknown>");
454 #if _DEBUG_NEW_TAILCHECK
463 static bool check_tail(new_ptr_list_t* ptr)
465 const unsigned char*
const tail_ptr = (
unsigned char*)ptr +
466 ALIGNED_LIST_ITEM_SIZE + ptr->size;
467 for (
int i = 0; i < _DEBUG_NEW_TAILCHECK; ++i)
468 if (tail_ptr[i] != _DEBUG_NEW_TAILCHECK_CHAR)
484 static void* alloc_mem(
size_t size,
const char* file,
int line,
bool is_array)
487 #if _DEBUG_NEW_TYPE == 1
488 STATIC_ASSERT(_DEBUG_NEW_ALIGNMENT >= PLATFORM_MEM_ALIGNMENT,
489 Alignment_too_small);
491 STATIC_ASSERT((_DEBUG_NEW_ALIGNMENT & (_DEBUG_NEW_ALIGNMENT - 1)) == 0,
492 Alignment_must_be_power_of_two);
493 STATIC_ASSERT(_DEBUG_NEW_TAILCHECK >= 0, Invalid_tail_check_length);
494 size_t s = size + ALIGNED_LIST_ITEM_SIZE + _DEBUG_NEW_TAILCHECK;
495 new_ptr_list_t* ptr = (new_ptr_list_t*)malloc(s);
498 #if _DEBUG_NEW_STD_OPER_NEW
502 fprintf(new_output_fp,
503 "Out of memory when allocating %lu bytes\n",
504 (
unsigned long)size);
505 fflush(new_output_fp);
506 _DEBUG_NEW_ERROR_ACTION;
509 void* usr_ptr = (
char*)ptr + ALIGNED_LIST_ITEM_SIZE;
510 #if _DEBUG_NEW_FILENAME_LEN == 0
514 strncpy(ptr->file, file, _DEBUG_NEW_FILENAME_LEN - 1)
515 [_DEBUG_NEW_FILENAME_LEN - 1] =
'\0';
517 ptr->addr = (
void*)file;
520 ptr->is_array = is_array;
522 ptr->magic = DEBUG_NEW_MAGIC;
525 ptr->prev = new_ptr_list.prev;
526 ptr->next = &new_ptr_list;
527 new_ptr_list.prev->next = ptr;
528 new_ptr_list.prev = ptr;
530 #if _DEBUG_NEW_TAILCHECK
531 memset((
char*)usr_ptr + size, _DEBUG_NEW_TAILCHECK_CHAR,
532 _DEBUG_NEW_TAILCHECK);
534 if (new_verbose_flag)
537 fprintf(new_output_fp,
538 "new%s: allocated %p (size %lu, ",
539 is_array ?
"[]" :
"",
540 usr_ptr, (
unsigned long)size);
542 print_position(ptr->file, ptr->line);
544 print_position(ptr->addr, ptr->line);
545 fprintf(new_output_fp,
")\n");
547 total_mem_alloc += size;
559 static void free_pointer(
void* usr_ptr,
void* addr,
bool is_array)
563 new_ptr_list_t* ptr =
564 (new_ptr_list_t*)((
char*)usr_ptr - ALIGNED_LIST_ITEM_SIZE);
565 if (ptr->magic != DEBUG_NEW_MAGIC)
569 fprintf(new_output_fp,
"delete%s: invalid pointer %p (",
570 is_array ?
"[]" :
"", usr_ptr);
571 print_position(addr, 0);
572 fprintf(new_output_fp,
")\n");
575 fflush(new_output_fp);
576 _DEBUG_NEW_ERROR_ACTION;
578 if (is_array != ptr->is_array)
582 msg =
"delete[] after new";
584 msg =
"delete after new[]";
586 fprintf(new_output_fp,
587 "%s: pointer %p (size %lu)\n\tat ",
589 (
char*)ptr + ALIGNED_LIST_ITEM_SIZE,
590 (
unsigned long)ptr->size);
591 print_position(addr, 0);
592 fprintf(new_output_fp,
"\n\toriginally allocated at ");
594 print_position(ptr->file, ptr->line);
596 print_position(ptr->addr, ptr->line);
597 fprintf(new_output_fp,
"\n");
598 fflush(new_output_fp);
599 _DEBUG_NEW_ERROR_ACTION;
601 #if _DEBUG_NEW_TAILCHECK
602 if (!check_tail(ptr))
605 fflush(new_output_fp);
606 _DEBUG_NEW_ERROR_ACTION;
611 total_mem_alloc -= ptr->size;
613 ptr->prev->next = ptr->next;
614 ptr->next->prev = ptr->prev;
616 if (new_verbose_flag)
619 fprintf(new_output_fp,
620 "delete%s: freed %p (size %lu, %lu bytes still allocated)\n",
621 is_array ?
"[]" :
"",
622 (
char*)ptr + ALIGNED_LIST_ITEM_SIZE,
623 (
unsigned long)ptr->size, (
unsigned long)total_mem_alloc);
639 new_ptr_list_t* ptr = new_ptr_list.next;
640 while (ptr != &new_ptr_list)
642 const char*
const usr_ptr = (
char*)ptr + ALIGNED_LIST_ITEM_SIZE;
643 if (ptr->magic != DEBUG_NEW_MAGIC)
645 fprintf(new_output_fp,
646 "warning: heap data corrupt near %p\n",
649 #if _DEBUG_NEW_TAILCHECK
650 if (!check_tail(ptr))
652 fprintf(new_output_fp,
653 "warning: overwritten past end of object at %p\n",
657 fprintf(new_output_fp,
658 "Leaked object at %p (size %lu, ",
660 (
unsigned long)ptr->size);
662 print_position(ptr->file, ptr->line);
664 print_position(ptr->addr, ptr->line);
665 fprintf(new_output_fp,
")\n");
669 if (new_verbose_flag || leak_cnt)
670 fprintf(new_output_fp,
"*** %d leaks found\n", leak_cnt);
685 fprintf(new_output_fp,
"*** Checking for memory corruption: START\n");
686 for (new_ptr_list_t* ptr = new_ptr_list.next;
687 ptr != &new_ptr_list;
690 const char*
const usr_ptr = (
char*)ptr + ALIGNED_LIST_ITEM_SIZE;
691 if (ptr->magic == DEBUG_NEW_MAGIC
692 #
if _DEBUG_NEW_TAILCHECK
697 #if _DEBUG_NEW_TAILCHECK
698 if (ptr->magic != DEBUG_NEW_MAGIC)
701 fprintf(new_output_fp,
702 "Heap data corrupt near %p (size %lu, ",
704 (
unsigned long)ptr->size);
705 #if _DEBUG_NEW_TAILCHECK
709 fprintf(new_output_fp,
710 "Overwritten past end of object at %p (size %lu, ",
712 (
unsigned long)ptr->size);
716 print_position(ptr->file, ptr->line);
718 print_position(ptr->addr, ptr->line);
719 fprintf(new_output_fp,
")\n");
722 fprintf(new_output_fp,
"*** Checking for memory corruption: %d FOUND\n",
742 size_t offset = (
char*)usr_ptr - (
char*)NULL;
743 if (offset % PLATFORM_MEM_ALIGNMENT != 0) {
744 offset -=
sizeof(size_t);
745 if (offset % PLATFORM_MEM_ALIGNMENT != 0) {
747 fprintf(new_output_fp,
748 "warning: memory unaligned; skipping processing (%s:%d)\n",
752 usr_ptr = (
char*)usr_ptr -
sizeof(
size_t);
755 new_ptr_list_t* ptr =
756 (new_ptr_list_t*)((
char*)usr_ptr - ALIGNED_LIST_ITEM_SIZE);
757 if (ptr->magic != DEBUG_NEW_MAGIC || ptr->line != 0)
760 fprintf(new_output_fp,
761 "warning: debug_new used with placement new (%s:%d)\n",
765 if (new_verbose_flag) {
767 fprintf(new_output_fp,
768 "info: pointer %p allocated from %s:%d\n",
771 #if _DEBUG_NEW_FILENAME_LEN == 0
774 strncpy(ptr->file,
_M_file, _DEBUG_NEW_FILENAME_LEN - 1)
775 [_DEBUG_NEW_FILENAME_LEN - 1] =
'\0';
799 if (--
_S_count == 0 && new_autocheck_flag)
802 new_verbose_flag =
true;
803 #if defined(__GNUC__) && __GNUC__ == 3
804 if (!getenv(
"GLIBCPP_FORCE_NEW") && !getenv(
"GLIBCXX_FORCE_NEW"))
805 fprintf(new_output_fp,
806 "*** WARNING: GCC 3 is detected, please make sure the environment\n"
807 " variable GLIBCPP_FORCE_NEW (GCC 3.2 and 3.3) or GLIBCXX_FORCE_NEW\n"
808 " (GCC 3.4) is defined. Check the README file for details.\n");
815 #if NVWA_USE_NAMESPACE
816 using namespace nvwa;
817 #endif // NVWA_USE_NAMESPACE
829 void*
operator new(
size_t size,
const char* file,
int line)
831 void* ptr = alloc_mem(size, file, line,
false);
832 #if _DEBUG_NEW_STD_OPER_NEW
836 throw std::bad_alloc();
852 void*
operator new[](
size_t size,
const char* file,
int line)
854 void* ptr = alloc_mem(size, file, line,
true);
855 #if _DEBUG_NEW_STD_OPER_NEW
859 throw std::bad_alloc();
873 void*
operator new(
size_t size) _GLIBCXX_THROW (std::bad_alloc)
875 return operator new(size, (
char*)_DEBUG_NEW_CALLER_ADDRESS, 0);
886 void*
operator new[](
size_t size) _GLIBCXX_THROW (std::bad_alloc)
888 return operator new[](size, (
char*)_DEBUG_NEW_CALLER_ADDRESS, 0);
898 void*
operator new(
size_t size,
const std::nothrow_t&) _NOEXCEPT
900 return alloc_mem(size, (
char*)_DEBUG_NEW_CALLER_ADDRESS, 0,
false);
910 void*
operator new[](
size_t size,
const std::nothrow_t&) _NOEXCEPT
912 return alloc_mem(size, (
char*)_DEBUG_NEW_CALLER_ADDRESS, 0,
true);
920 void operator delete(
void* ptr) _NOEXCEPT
922 free_pointer(ptr, _DEBUG_NEW_CALLER_ADDRESS,
false);
930 void operator delete[](
void* ptr) _NOEXCEPT
932 free_pointer(ptr, _DEBUG_NEW_CALLER_ADDRESS,
true);
946 void operator delete(
void* ptr,
const char* file,
int line) _NOEXCEPT
948 if (new_verbose_flag)
951 fprintf(new_output_fp,
952 "info: exception thrown on initializing object at %p (",
954 print_position(file, line);
955 fprintf(new_output_fp,
")\n");
957 operator delete(ptr);
968 void operator delete[](
void* ptr,
const char* file,
int line) _NOEXCEPT
970 if (new_verbose_flag)
973 fprintf(new_output_fp,
974 "info: exception thrown on initializing objects at %p (",
976 print_position(file, line);
977 fprintf(new_output_fp,
")\n");
979 operator delete[](ptr);
988 void operator delete(
void* ptr,
const std::nothrow_t&) _NOEXCEPT
990 operator delete(ptr, (
char*)_DEBUG_NEW_CALLER_ADDRESS, 0);
999 void operator delete[](
void* ptr,
const std::nothrow_t&) _NOEXCEPT
1001 operator delete[](ptr, (
char*)_DEBUG_NEW_CALLER_ADDRESS, 0);
const char * new_progname
#define STATIC_ASSERT(_Expr, _Msg)
void _M_process(void *ptr)
int check_mem_corruption()