SUMO - Simulation of Urban MObility
|
00001 // -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- 00002 // vim:tabstop=4:shiftwidth=4:expandtab: 00003 #ifdef _MSC_VER 00004 #include <windows_config.h> 00005 #else 00006 #include <config.h> 00007 #endif 00008 #ifdef CHECK_MEMORY_LEAKS 00009 /* 00010 * Copyright (C) 2004-2008 Wu Yongwei <adah at users dot sourceforge dot net> 00011 * 00012 * This software is provided 'as-is', without any express or implied 00013 * warranty. In no event will the authors be held liable for any 00014 * damages arising from the use of this software. 00015 * 00016 * Permission is granted to anyone to use this software for any purpose, 00017 * including commercial applications, and to alter it and redistribute 00018 * it freely, subject to the following restrictions: 00019 * 00020 * 1. The origin of this software must not be misrepresented; you must 00021 * not claim that you wrote the original software. If you use this 00022 * software in a product, an acknowledgement in the product 00023 * documentation would be appreciated but is not required. 00024 * 2. Altered source versions must be plainly marked as such, and must 00025 * not be misrepresented as being the original software. 00026 * 3. This notice may not be removed or altered from any source 00027 * distribution. 00028 * 00029 * This file is part of Stones of Nvwa: 00030 * http://sourceforge.net/projects/nvwa 00031 * 00032 */ 00033 00044 #include <new> 00045 #include <assert.h> 00046 #include <limits.h> 00047 #include <stdio.h> 00048 #include <stdlib.h> 00049 #include <string.h> 00050 #ifdef __unix__ 00051 #include <alloca.h> 00052 #endif 00053 #ifdef _WIN32 00054 #include <malloc.h> 00055 #endif 00056 #include "fast_mutex.h" 00057 #include "static_assert.h" 00058 00059 #if !_FAST_MUTEX_CHECK_INITIALIZATION && !defined(_NOTHREADS) 00060 #error "_FAST_MUTEX_CHECK_INITIALIZATION not set: check_leaks may not work" 00061 #endif 00062 00069 #ifndef _DEBUG_NEW_ALIGNMENT 00070 #define _DEBUG_NEW_ALIGNMENT 16 00071 #endif 00072 00080 #ifndef _DEBUG_NEW_CALLER_ADDRESS 00081 #ifdef __GNUC__ 00082 #define _DEBUG_NEW_CALLER_ADDRESS __builtin_return_address(0) 00083 #else 00084 #define _DEBUG_NEW_CALLER_ADDRESS NULL 00085 #endif 00086 #endif 00087 00097 #ifndef _DEBUG_NEW_ERROR_ACTION 00098 #ifndef _DEBUG_NEW_ERROR_CRASH 00099 #define _DEBUG_NEW_ERROR_ACTION abort() 00100 #else 00101 #define _DEBUG_NEW_ERROR_ACTION do { *((char*)0) = 0; abort(); } while (0) 00102 #endif 00103 #endif 00104 00116 #ifndef _DEBUG_NEW_FILENAME_LEN 00117 #define _DEBUG_NEW_FILENAME_LEN 80 00118 #endif 00119 00132 #ifndef _DEBUG_NEW_PROGNAME 00133 #define _DEBUG_NEW_PROGNAME NULL 00134 #endif 00135 00143 #ifndef _DEBUG_NEW_STD_OPER_NEW 00144 #define _DEBUG_NEW_STD_OPER_NEW 1 00145 #endif 00146 00154 #ifndef _DEBUG_NEW_TAILCHECK 00155 #define _DEBUG_NEW_TAILCHECK 0 00156 #endif 00157 00163 #ifndef _DEBUG_NEW_TAILCHECK_CHAR 00164 #define _DEBUG_NEW_TAILCHECK_CHAR 0xCC 00165 #endif 00166 00175 #ifndef _DEBUG_NEW_USE_ADDR2LINE 00176 #ifdef __GNUC__ 00177 #define _DEBUG_NEW_USE_ADDR2LINE 1 00178 #else 00179 #define _DEBUG_NEW_USE_ADDR2LINE 0 00180 #endif 00181 #endif 00182 00183 #ifdef _MSC_VER 00184 #pragma warning(disable: 4073) // #pragma init_seg(lib) used 00185 #pragma warning(disable: 4290) // C++ exception specification ignored 00186 #pragma init_seg(lib) 00187 #endif 00188 00189 #undef _DEBUG_NEW_EMULATE_MALLOC 00190 #undef _DEBUG_NEW_REDEFINE_NEW 00191 00195 #define _DEBUG_NEW_REDEFINE_NEW 0 00196 #include "debug_new.h" 00197 00201 #define align(s) \ 00202 (((s) + _DEBUG_NEW_ALIGNMENT - 1) & ~(_DEBUG_NEW_ALIGNMENT - 1)) 00203 00207 struct new_ptr_list_t 00208 { 00209 new_ptr_list_t* next; 00210 new_ptr_list_t* prev; 00211 size_t size; 00212 union 00213 { 00214 #if _DEBUG_NEW_FILENAME_LEN == 0 00215 const char* file; 00216 #else 00217 char file[_DEBUG_NEW_FILENAME_LEN]; 00218 #endif 00219 void* addr; 00220 }; 00221 unsigned line :31; 00222 unsigned is_array :1; 00223 unsigned magic; 00224 }; 00225 00229 const unsigned MAGIC = 0x4442474E; 00230 00234 const int ALIGNED_LIST_ITEM_SIZE = align(sizeof(new_ptr_list_t)); 00235 00239 static new_ptr_list_t new_ptr_list = { 00240 &new_ptr_list, 00241 &new_ptr_list, 00242 0, 00243 { 00244 #if _DEBUG_NEW_FILENAME_LEN == 0 00245 NULL 00246 #else 00247 "" 00248 #endif 00249 }, 00250 0, 00251 0, 00252 MAGIC 00253 }; 00254 00258 static fast_mutex new_ptr_lock; 00259 00263 static fast_mutex new_output_lock; 00264 00268 static size_t total_mem_alloc = 0; 00269 00274 bool new_autocheck_flag = true; 00275 00279 bool new_verbose_flag = false; 00280 00286 FILE* new_output_fp = stderr; 00287 00296 const char* new_progname = _DEBUG_NEW_PROGNAME; 00297 00298 #if _DEBUG_NEW_USE_ADDR2LINE 00299 00308 static bool print_position_from_addr(const void* addr) 00309 { 00310 static const void* last_addr = NULL; 00311 static char last_info[256] = ""; 00312 if (addr == last_addr) 00313 { 00314 if (last_info[0] == '\0') 00315 return false; 00316 fprintf(new_output_fp, "%s", last_info); 00317 return true; 00318 } 00319 if (new_progname) 00320 { 00321 const char addr2line_cmd[] = "addr2line -e "; 00322 #if defined(__CYGWIN__) || defined(_WIN32) 00323 const int exeext_len = 4; 00324 #else 00325 const int exeext_len = 0; 00326 #endif 00327 #if !defined(__CYGWIN__) && defined(__unix__) 00328 const char ignore_err[] = " 2>/dev/null"; 00329 #elif defined(__CYGWIN__) || \ 00330 (defined(_WIN32) && defined(WINVER) && WINVER >= 0x0500) 00331 const char ignore_err[] = " 2>nul"; 00332 #else 00333 const char ignore_err[] = ""; 00334 #endif 00335 char* cmd = (char*)alloca(strlen(new_progname) 00336 + exeext_len 00337 + sizeof addr2line_cmd - 1 00338 + sizeof ignore_err - 1 00339 + sizeof(void*) * 2 00340 + 4 /* SP + "0x" + null */); 00341 strcpy(cmd, addr2line_cmd); 00342 strcpy(cmd + sizeof addr2line_cmd - 1, new_progname); 00343 size_t len = strlen(cmd); 00344 #if defined(__CYGWIN__) || defined(_WIN32) 00345 if (len <= 4 00346 || (strcmp(cmd + len - 4, ".exe") != 0 && 00347 strcmp(cmd + len - 4, ".EXE") != 0)) 00348 { 00349 strcpy(cmd + len, ".exe"); 00350 len += 4; 00351 } 00352 #endif 00353 sprintf(cmd + len, " %p%s", addr, ignore_err); 00354 FILE* fp = popen(cmd, "r"); 00355 if (fp) 00356 { 00357 char buffer[sizeof last_info] = ""; 00358 len = 0; 00359 if (fgets(buffer, sizeof buffer, fp)) 00360 { 00361 len = strlen(buffer); 00362 if (buffer[len - 1] == '\n') 00363 buffer[--len] = '\0'; 00364 } 00365 int res = pclose(fp); 00366 // Display the file/line information only if the command 00367 // is executed successfully and the output points to a 00368 // valid position, but the result will be cached if only 00369 // the command is executed successfully. 00370 if (res == 0 && len > 0) 00371 { 00372 last_addr = addr; 00373 if (buffer[len - 1] == '0' && buffer[len - 2] == ':') 00374 last_info[0] = '\0'; 00375 else 00376 { 00377 fprintf(new_output_fp, "%s", buffer); 00378 strcpy(last_info, buffer); 00379 return true; 00380 } 00381 } 00382 } 00383 } 00384 return false; 00385 } 00386 #else 00387 00393 static bool print_position_from_addr(const void*) 00394 { 00395 return false; 00396 } 00397 #endif // _DEBUG_NEW_USE_ADDR2LINE 00398 00410 static void print_position(const void* ptr, int line) 00411 { 00412 if (line != 0) // Is file/line information present? 00413 { 00414 fprintf(new_output_fp, "%s:%d", (const char*)ptr, line); 00415 } 00416 else if (ptr != NULL) // Is caller address present? 00417 { 00418 if (!print_position_from_addr(ptr)) // Fail to get source position? 00419 fprintf(new_output_fp, "%p", ptr); 00420 } 00421 else // No information is present 00422 { 00423 fprintf(new_output_fp, "<Unknown>"); 00424 } 00425 } 00426 00427 #if _DEBUG_NEW_TAILCHECK 00428 00436 static bool check_tail(new_ptr_list_t* ptr) 00437 { 00438 const unsigned char* const pointer = (unsigned char*)ptr + 00439 ALIGNED_LIST_ITEM_SIZE + ptr->size; 00440 for (int i = 0; i < _DEBUG_NEW_TAILCHECK; ++i) 00441 if (pointer[i] != _DEBUG_NEW_TAILCHECK_CHAR) 00442 return false; 00443 return true; 00444 } 00445 #endif 00446 00457 static void* alloc_mem(size_t size, const char* file, int line, bool is_array) 00458 { 00459 assert(line >= 0); 00460 STATIC_ASSERT((_DEBUG_NEW_ALIGNMENT & (_DEBUG_NEW_ALIGNMENT - 1)) == 0, 00461 Alignment_must_be_power_of_two); 00462 STATIC_ASSERT(_DEBUG_NEW_TAILCHECK >= 0, Invalid_tail_check_length); 00463 size_t s = size + ALIGNED_LIST_ITEM_SIZE + _DEBUG_NEW_TAILCHECK; 00464 new_ptr_list_t* ptr = (new_ptr_list_t*)malloc(s); 00465 if (ptr == NULL) 00466 { 00467 #if _DEBUG_NEW_STD_OPER_NEW 00468 return NULL; 00469 #else 00470 fast_mutex_autolock lock(new_output_lock); 00471 fprintf(new_output_fp, 00472 "Out of memory when allocating %u bytes\n", 00473 size); 00474 fflush(new_output_fp); 00475 _DEBUG_NEW_ERROR_ACTION; 00476 #endif 00477 } 00478 void* pointer = (char*)ptr + ALIGNED_LIST_ITEM_SIZE; 00479 #if _DEBUG_NEW_FILENAME_LEN == 0 00480 ptr->file = file; 00481 #else 00482 if (line) 00483 strncpy(ptr->file, file, _DEBUG_NEW_FILENAME_LEN - 1) 00484 [_DEBUG_NEW_FILENAME_LEN - 1] = '\0'; 00485 else 00486 ptr->addr = (void*)file; 00487 #endif 00488 ptr->line = line; 00489 ptr->is_array = is_array; 00490 ptr->size = size; 00491 ptr->magic = MAGIC; 00492 { 00493 fast_mutex_autolock lock(new_ptr_lock); 00494 ptr->prev = new_ptr_list.prev; 00495 ptr->next = &new_ptr_list; 00496 new_ptr_list.prev->next = ptr; 00497 new_ptr_list.prev = ptr; 00498 } 00499 #if _DEBUG_NEW_TAILCHECK 00500 memset((char*)pointer + size, _DEBUG_NEW_TAILCHECK_CHAR, 00501 _DEBUG_NEW_TAILCHECK); 00502 #endif 00503 if (new_verbose_flag) 00504 { 00505 fast_mutex_autolock lock(new_output_lock); 00506 fprintf(new_output_fp, 00507 "new%s: allocated %p (size %u, ", 00508 is_array ? "[]" : "", 00509 pointer, size); 00510 if (line != 0) 00511 print_position(ptr->file, ptr->line); 00512 else 00513 print_position(ptr->addr, ptr->line); 00514 fprintf(new_output_fp, ")\n"); 00515 } 00516 total_mem_alloc += size; 00517 return pointer; 00518 } 00519 00528 static void free_pointer(void* pointer, void* addr, bool is_array) 00529 { 00530 if (pointer == NULL) 00531 return; 00532 new_ptr_list_t* ptr = 00533 (new_ptr_list_t*)((char*)pointer - ALIGNED_LIST_ITEM_SIZE); 00534 if (ptr->magic != MAGIC) 00535 { 00536 { 00537 fast_mutex_autolock lock(new_output_lock); 00538 fprintf(new_output_fp, "delete%s: invalid pointer %p (", 00539 is_array ? "[]" : "", pointer); 00540 print_position(addr, 0); 00541 fprintf(new_output_fp, ")\n"); 00542 } 00543 check_mem_corruption(); 00544 fflush(new_output_fp); 00545 _DEBUG_NEW_ERROR_ACTION; 00546 } 00547 if (is_array != ptr->is_array) 00548 { 00549 const char* msg; 00550 if (is_array) 00551 msg = "delete[] after new"; 00552 else 00553 msg = "delete after new[]"; 00554 fast_mutex_autolock lock(new_output_lock); 00555 fprintf(new_output_fp, 00556 "%s: pointer %p (size %u)\n\tat ", 00557 msg, 00558 (char*)ptr + ALIGNED_LIST_ITEM_SIZE, 00559 ptr->size); 00560 print_position(addr, 0); 00561 fprintf(new_output_fp, "\n\toriginally allocated at "); 00562 if (ptr->line != 0) 00563 print_position(ptr->file, ptr->line); 00564 else 00565 print_position(ptr->addr, ptr->line); 00566 fprintf(new_output_fp, "\n"); 00567 fflush(new_output_fp); 00568 _DEBUG_NEW_ERROR_ACTION; 00569 } 00570 #if _DEBUG_NEW_TAILCHECK 00571 if (!check_tail(ptr)) 00572 { 00573 check_mem_corruption(); 00574 fflush(new_output_fp); 00575 _DEBUG_NEW_ERROR_ACTION; 00576 } 00577 #endif 00578 { 00579 fast_mutex_autolock lock(new_ptr_lock); 00580 total_mem_alloc -= ptr->size; 00581 ptr->magic = 0; 00582 ptr->prev->next = ptr->next; 00583 ptr->next->prev = ptr->prev; 00584 } 00585 if (new_verbose_flag) 00586 { 00587 fast_mutex_autolock lock(new_output_lock); 00588 fprintf(new_output_fp, 00589 "delete%s: freed %p (size %u, %u bytes still allocated)\n", 00590 is_array ? "[]" : "", 00591 (char*)ptr + ALIGNED_LIST_ITEM_SIZE, 00592 ptr->size, total_mem_alloc); 00593 } 00594 free(ptr); 00595 return; 00596 } 00597 00603 int check_leaks() 00604 { 00605 int leak_cnt = 0; 00606 fast_mutex_autolock lock_ptr(new_ptr_lock); 00607 fast_mutex_autolock lock_output(new_output_lock); 00608 new_ptr_list_t* ptr = new_ptr_list.next; 00609 while (ptr != &new_ptr_list) 00610 { 00611 const char* const pointer = (char*)ptr + ALIGNED_LIST_ITEM_SIZE; 00612 if (ptr->magic != MAGIC) 00613 { 00614 fprintf(new_output_fp, 00615 "warning: heap data corrupt near %p\n", 00616 pointer); 00617 } 00618 #if _DEBUG_NEW_TAILCHECK 00619 if (!check_tail(ptr)) 00620 { 00621 fprintf(new_output_fp, 00622 "warning: overwritten past end of object at %p\n", 00623 pointer); 00624 } 00625 #endif 00626 fprintf(new_output_fp, 00627 "Leaked object at %p (size %u, ", 00628 pointer, 00629 ptr->size); 00630 if (ptr->line != 0) 00631 print_position(ptr->file, ptr->line); 00632 else 00633 print_position(ptr->addr, ptr->line); 00634 fprintf(new_output_fp, ")\n"); 00635 ptr = ptr->next; 00636 ++leak_cnt; 00637 } 00638 if (new_verbose_flag || leak_cnt) 00639 fprintf(new_output_fp, "*** %d leaks found\n", leak_cnt); 00640 return leak_cnt; 00641 } 00642 00649 int check_mem_corruption() 00650 { 00651 int corrupt_cnt = 0; 00652 fast_mutex_autolock lock_ptr(new_ptr_lock); 00653 fast_mutex_autolock lock_output(new_output_lock); 00654 fprintf(new_output_fp, "*** Checking for memory corruption: START\n"); 00655 for (new_ptr_list_t* ptr = new_ptr_list.next; 00656 ptr != &new_ptr_list; 00657 ptr = ptr->next) 00658 { 00659 const char* const pointer = (char*)ptr + ALIGNED_LIST_ITEM_SIZE; 00660 if (ptr->magic == MAGIC 00661 #if _DEBUG_NEW_TAILCHECK 00662 && check_tail(ptr) 00663 #endif 00664 ) 00665 continue; 00666 #if _DEBUG_NEW_TAILCHECK 00667 if (ptr->magic != MAGIC) 00668 { 00669 #endif 00670 fprintf(new_output_fp, 00671 "Heap data corrupt near %p (size %u, ", 00672 pointer, 00673 ptr->size); 00674 #if _DEBUG_NEW_TAILCHECK 00675 } 00676 else 00677 { 00678 fprintf(new_output_fp, 00679 "Overwritten past end of object at %p (size %u, ", 00680 pointer, 00681 ptr->size); 00682 } 00683 #endif 00684 if (ptr->line != 0) 00685 print_position(ptr->file, ptr->line); 00686 else 00687 print_position(ptr->addr, ptr->line); 00688 fprintf(new_output_fp, ")\n"); 00689 ++corrupt_cnt; 00690 } 00691 fprintf(new_output_fp, "*** Checking for memory corruption: %d FOUND\n", 00692 corrupt_cnt); 00693 return corrupt_cnt; 00694 } 00695 00696 void __debug_new_recorder::_M_process(void* pointer) 00697 { 00698 if (pointer == NULL) 00699 return; 00700 new_ptr_list_t* ptr = 00701 (new_ptr_list_t*)((char*)pointer - ALIGNED_LIST_ITEM_SIZE); 00702 if (ptr->magic != MAGIC || ptr->line != 0) 00703 { 00704 fast_mutex_autolock lock(new_output_lock); 00705 fprintf(new_output_fp, 00706 "warning: debug_new used with placement new (%s:%d)\n", 00707 _M_file, _M_line); 00708 return; 00709 } 00710 #if _DEBUG_NEW_FILENAME_LEN == 0 00711 ptr->file = _M_file; 00712 #else 00713 strncpy(ptr->file, _M_file, _DEBUG_NEW_FILENAME_LEN - 1) 00714 [_DEBUG_NEW_FILENAME_LEN - 1] = '\0'; 00715 #endif 00716 ptr->line = _M_line; 00717 } 00718 00719 void* operator new(size_t size, const char* file, int line) 00720 { 00721 void* ptr = alloc_mem(size, file, line, false); 00722 #if _DEBUG_NEW_STD_OPER_NEW 00723 if (ptr) 00724 return ptr; 00725 else 00726 throw std::bad_alloc(); 00727 #else 00728 return ptr; 00729 #endif 00730 } 00731 00732 void* operator new[](size_t size, const char* file, int line) 00733 { 00734 void* ptr = alloc_mem(size, file, line, true); 00735 #if _DEBUG_NEW_STD_OPER_NEW 00736 if (ptr) 00737 return ptr; 00738 else 00739 throw std::bad_alloc(); 00740 #else 00741 return ptr; 00742 #endif 00743 } 00744 00745 void* operator new(size_t size) throw(std::bad_alloc) 00746 { 00747 return operator new(size, (char*)_DEBUG_NEW_CALLER_ADDRESS, 0); 00748 } 00749 00750 void* operator new[](size_t size) throw(std::bad_alloc) 00751 { 00752 return operator new[](size, (char*)_DEBUG_NEW_CALLER_ADDRESS, 0); 00753 } 00754 00755 #if !defined(__BORLANDC__) || __BORLANDC__ > 0x551 00756 void* operator new(size_t size, const std::nothrow_t&) throw() 00757 { 00758 return alloc_mem(size, (char*)_DEBUG_NEW_CALLER_ADDRESS, 0, false); 00759 } 00760 00761 void* operator new[](size_t size, const std::nothrow_t&) throw() 00762 { 00763 return alloc_mem(size, (char*)_DEBUG_NEW_CALLER_ADDRESS, 0, true); 00764 } 00765 #endif 00766 00767 void operator delete(void* pointer) throw() 00768 { 00769 free_pointer(pointer, _DEBUG_NEW_CALLER_ADDRESS, false); 00770 } 00771 00772 void operator delete[](void* pointer) throw() 00773 { 00774 free_pointer(pointer, _DEBUG_NEW_CALLER_ADDRESS, true); 00775 } 00776 00777 #if HAVE_PLACEMENT_DELETE 00778 void operator delete(void* pointer, const char* file, int line) throw() 00779 { 00780 if (new_verbose_flag) 00781 { 00782 fast_mutex_autolock lock(new_output_lock); 00783 fprintf(new_output_fp, 00784 "info: exception thrown on initializing object at %p (", 00785 pointer); 00786 print_position(file, line); 00787 fprintf(new_output_fp, ")\n"); 00788 } 00789 operator delete(pointer); 00790 } 00791 00792 void operator delete[](void* pointer, const char* file, int line) throw() 00793 { 00794 if (new_verbose_flag) 00795 { 00796 fast_mutex_autolock lock(new_output_lock); 00797 fprintf(new_output_fp, 00798 "info: exception thrown on initializing objects at %p (", 00799 pointer); 00800 print_position(file, line); 00801 fprintf(new_output_fp, ")\n"); 00802 } 00803 operator delete[](pointer); 00804 } 00805 00806 void operator delete(void* pointer, const std::nothrow_t&) throw() 00807 { 00808 operator delete(pointer, (char*)_DEBUG_NEW_CALLER_ADDRESS, 0); 00809 } 00810 00811 void operator delete[](void* pointer, const std::nothrow_t&) throw() 00812 { 00813 operator delete[](pointer, (char*)_DEBUG_NEW_CALLER_ADDRESS, 0); 00814 } 00815 #endif // HAVE_PLACEMENT_DELETE 00816 00817 int __debug_new_counter::_S_count = 0; 00818 00822 __debug_new_counter::__debug_new_counter() 00823 { 00824 ++_S_count; 00825 } 00826 00831 __debug_new_counter::~__debug_new_counter() 00832 { 00833 if (--_S_count == 0 && new_autocheck_flag) 00834 if (check_leaks()) 00835 { 00836 new_verbose_flag = true; 00837 #if defined(__GNUC__) && __GNUC__ >= 3 00838 if (!getenv("GLIBCPP_FORCE_NEW") && !getenv("GLIBCXX_FORCE_NEW")) 00839 fprintf(new_output_fp, 00840 "*** WARNING: GCC 3 or later is detected, please make sure the\n" 00841 " environment variable GLIBCPP_FORCE_NEW (GCC 3.2 and 3.3) or\n" 00842 " GLIBCXX_FORCE_NEW (GCC 3.4 and later) is defined. Check the\n" 00843 " README file for details.\n"); 00844 #endif 00845 } 00846 } 00847 00848 00849 #endif