SUMO - Simulation of Urban MObility
debug_new.cpp
Go to the documentation of this file.
1 // -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
2 // vim:tabstop=4:shiftwidth=4:expandtab:
3 #ifdef _MSC_VER
4 #include <windows_config.h>
5 #else
6 #include <config.h>
7 #endif
8 #ifdef CHECK_MEMORY_LEAKS
9 
10 /*
11  * Copyright (C) 2004-2011 Wu Yongwei <adah at users dot sourceforge dot net>
12  *
13  * This software is provided 'as-is', without any express or implied
14  * warranty. In no event will the authors be held liable for any
15  * damages arising from the use of this software.
16  *
17  * Permission is granted to anyone to use this software for any purpose,
18  * including commercial applications, and to alter it and redistribute
19  * it freely, subject to the following restrictions:
20  *
21  * 1. The origin of this software must not be misrepresented; you must
22  * not claim that you wrote the original software. If you use this
23  * software in a product, an acknowledgement in the product
24  * documentation would be appreciated but is not required.
25  * 2. Altered source versions must be plainly marked as such, and must
26  * not be misrepresented as being the original software.
27  * 3. This notice may not be removed or altered from any source
28  * distribution.
29  *
30  * This file is part of Stones of Nvwa:
31  * http://sourceforge.net/projects/nvwa
32  *
33  */
34 
45 #include <new>
46 #include <assert.h>
47 #include <limits.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #ifdef __unix__
52 #include <alloca.h>
53 #endif
54 #ifdef _WIN32
55 #include <malloc.h>
56 #endif
57 #include "fast_mutex.h"
58 #include "static_assert.h"
59 
60 #if !_FAST_MUTEX_CHECK_INITIALIZATION && !defined(_NOTHREADS)
61 #error "_FAST_MUTEX_CHECK_INITIALIZATION not set: check_leaks may not work"
62 #endif
63 
70 #ifndef _DEBUG_NEW_ALIGNMENT
71 #define _DEBUG_NEW_ALIGNMENT 16
72 #endif
73 
81 #ifndef _DEBUG_NEW_CALLER_ADDRESS
82 #ifdef __GNUC__
83 #define _DEBUG_NEW_CALLER_ADDRESS __builtin_return_address(0)
84 #else
85 #define _DEBUG_NEW_CALLER_ADDRESS NULL
86 #endif
87 #endif
88 
98 #ifndef _DEBUG_NEW_ERROR_ACTION
99 #ifndef _DEBUG_NEW_ERROR_CRASH
100 #define _DEBUG_NEW_ERROR_ACTION abort()
101 #else
102 #define _DEBUG_NEW_ERROR_ACTION do { *((char*)0) = 0; abort(); } while (0)
103 #endif
104 #endif
105 
118 #ifndef _DEBUG_NEW_FILENAME_LEN
119 #ifdef _WIN32
120 #define _DEBUG_NEW_FILENAME_LEN 0
121 #else
122 #define _DEBUG_NEW_FILENAME_LEN 44
123 #endif
124 #endif
125 
138 #ifndef _DEBUG_NEW_PROGNAME
139 #define _DEBUG_NEW_PROGNAME NULL
140 #endif
141 
149 #ifndef _DEBUG_NEW_STD_OPER_NEW
150 #define _DEBUG_NEW_STD_OPER_NEW 1
151 #endif
152 
160 #ifndef _DEBUG_NEW_TAILCHECK
161 #define _DEBUG_NEW_TAILCHECK 0
162 #endif
163 
169 #ifndef _DEBUG_NEW_TAILCHECK_CHAR
170 #define _DEBUG_NEW_TAILCHECK_CHAR 0xCC
171 #endif
172 
181 #ifndef _DEBUG_NEW_USE_ADDR2LINE
182 #ifdef __GNUC__
183 #define _DEBUG_NEW_USE_ADDR2LINE 1
184 #else
185 #define _DEBUG_NEW_USE_ADDR2LINE 0
186 #endif
187 #endif
188 
189 #ifdef _MSC_VER
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
194 #endif
195 #pragma init_seg(compiler)
196 #endif
197 
198 #undef _DEBUG_NEW_EMULATE_MALLOC
199 #undef _DEBUG_NEW_REDEFINE_NEW
200 
204 #define _DEBUG_NEW_REDEFINE_NEW 0
205 #include "debug_new.h"
206 
210 #define ALIGN(s) \
211  (((s) + _DEBUG_NEW_ALIGNMENT - 1) & ~(_DEBUG_NEW_ALIGNMENT - 1))
212 
221 const size_t PLATFORM_MEM_ALIGNMENT = sizeof(size_t) * 2;
222 
226 struct new_ptr_list_t
227 {
228  new_ptr_list_t* next;
229  new_ptr_list_t* prev;
230  size_t size;
231  union
232  {
233 #if _DEBUG_NEW_FILENAME_LEN == 0
234  const char* file;
235 #else
236  char file[_DEBUG_NEW_FILENAME_LEN];
237 #endif
238  void* addr;
239  };
240  unsigned line :31;
241  unsigned is_array:1;
242  unsigned magic;
243 };
244 
248 const unsigned MAGIC = 0x4442474E;
249 
253 const int ALIGNED_LIST_ITEM_SIZE = ALIGN(sizeof(new_ptr_list_t));
254 
258 static new_ptr_list_t new_ptr_list = {
259  &new_ptr_list,
260  &new_ptr_list,
261  0,
262  {
263 #if _DEBUG_NEW_FILENAME_LEN == 0
264  NULL
265 #else
266  ""
267 #endif
268  },
269  0,
270  0,
271  MAGIC
272 };
273 
277 static fast_mutex new_ptr_lock;
278 
282 static fast_mutex new_output_lock;
283 
287 static size_t total_mem_alloc = 0;
288 
293 bool new_autocheck_flag = true;
294 
298 bool new_verbose_flag = false;
299 
305 FILE* new_output_fp = stderr;
306 
315 const char* new_progname = _DEBUG_NEW_PROGNAME;
316 
317 #if _DEBUG_NEW_USE_ADDR2LINE
318 
327 static bool print_position_from_addr(const void* addr)
328 {
329  static const void* last_addr = NULL;
330  static char last_info[256] = "";
331  if (addr == last_addr)
332  {
333  if (last_info[0] == '\0')
334  return false;
335  fprintf(new_output_fp, "%s", last_info);
336  return true;
337  }
338  if (new_progname)
339  {
340  const char addr2line_cmd[] = "addr2line -e ";
341 #if defined(__CYGWIN__) || defined(_WIN32)
342  const int exeext_len = 4;
343 #else
344  const int exeext_len = 0;
345 #endif
346 #if !defined(__CYGWIN__) && defined(__unix__)
347  const char ignore_err[] = " 2>/dev/null";
348 #elif defined(__CYGWIN__) || \
349  (defined(_WIN32) && defined(WINVER) && WINVER >= 0x0500)
350  const char ignore_err[] = " 2>nul";
351 #else
352  const char ignore_err[] = "";
353 #endif
354  char* cmd = (char*)alloca(strlen(new_progname)
355  + exeext_len
356  + sizeof addr2line_cmd - 1
357  + sizeof ignore_err - 1
358  + sizeof(void*) * 2
359  + 4 /* SP + "0x" + null */);
360  strcpy(cmd, addr2line_cmd);
361  strcpy(cmd + sizeof addr2line_cmd - 1, new_progname);
362  size_t len = strlen(cmd);
363 #if defined(__CYGWIN__) || defined(_WIN32)
364  if (len <= 4
365  || (strcmp(cmd + len - 4, ".exe") != 0 &&
366  strcmp(cmd + len - 4, ".EXE") != 0))
367  {
368  strcpy(cmd + len, ".exe");
369  len += 4;
370  }
371 #endif
372  sprintf(cmd + len, " %p%s", addr, ignore_err);
373  FILE* fp = popen(cmd, "r");
374  if (fp)
375  {
376  char buffer[sizeof last_info] = "";
377  len = 0;
378  if (fgets(buffer, sizeof buffer, fp))
379  {
380  len = strlen(buffer);
381  if (buffer[len - 1] == '\n')
382  buffer[--len] = '\0';
383  }
384  int res = pclose(fp);
385  // Display the file/line information only if the command
386  // is executed successfully and the output points to a
387  // valid position, but the result will be cached if only
388  // the command is executed successfully.
389  if (res == 0 && len > 0)
390  {
391  last_addr = addr;
392  if (buffer[len - 1] == '0' && buffer[len - 2] == ':')
393  last_info[0] = '\0';
394  else
395  {
396  fprintf(new_output_fp, "%s", buffer);
397  strcpy(last_info, buffer);
398  return true;
399  }
400  }
401  }
402  }
403  return false;
404 }
405 #else
406 
412 static bool print_position_from_addr(const void*)
413 {
414  return false;
415 }
416 #endif // _DEBUG_NEW_USE_ADDR2LINE
417 
429 static void print_position(const void* ptr, int line)
430 {
431  if (line != 0) // Is file/line information present?
432  {
433  fprintf(new_output_fp, "%s:%d", (const char*)ptr, line);
434  }
435  else if (ptr != NULL) // Is caller address present?
436  {
437  if (!print_position_from_addr(ptr)) // Fail to get source position?
438  fprintf(new_output_fp, "%p", ptr);
439  }
440  else // No information is present
441  {
442  fprintf(new_output_fp, "<Unknown>");
443  }
444 }
445 
446 #if _DEBUG_NEW_TAILCHECK
447 
455 static bool check_tail(new_ptr_list_t* ptr)
456 {
457  const unsigned char* const pointer = (unsigned char*)ptr +
458  ALIGNED_LIST_ITEM_SIZE + ptr->size;
459  for (int i = 0; i < _DEBUG_NEW_TAILCHECK; ++i)
460  if (pointer[i] != _DEBUG_NEW_TAILCHECK_CHAR)
461  return false;
462  return true;
463 }
464 #endif
465 
476 static void* alloc_mem(size_t size, const char* file, int line, bool is_array)
477 {
478  assert(line >= 0);
479 #if _DEBUG_NEW_TYPE == 1
480  STATIC_ASSERT(_DEBUG_NEW_ALIGNMENT >= PLATFORM_MEM_ALIGNMENT,
481  Alignment_too_small);
482 #endif
483  STATIC_ASSERT((_DEBUG_NEW_ALIGNMENT & (_DEBUG_NEW_ALIGNMENT - 1)) == 0,
484  Alignment_must_be_power_of_two);
485  STATIC_ASSERT(_DEBUG_NEW_TAILCHECK >= 0, Invalid_tail_check_length);
486  size_t s = size + ALIGNED_LIST_ITEM_SIZE + _DEBUG_NEW_TAILCHECK;
487  new_ptr_list_t* ptr = (new_ptr_list_t*)malloc(s);
488  if (ptr == NULL)
489  {
490 #if _DEBUG_NEW_STD_OPER_NEW
491  return NULL;
492 #else
493  fast_mutex_autolock lock(new_output_lock);
494  fprintf(new_output_fp,
495  "Out of memory when allocating %lu bytes\n",
496  (unsigned long)size);
497  fflush(new_output_fp);
498  _DEBUG_NEW_ERROR_ACTION;
499 #endif
500  }
501  void* pointer = (char*)ptr + ALIGNED_LIST_ITEM_SIZE;
502 #if _DEBUG_NEW_FILENAME_LEN == 0
503  ptr->file = file;
504 #else
505  if (line)
506  strncpy(ptr->file, file, _DEBUG_NEW_FILENAME_LEN - 1)
507  [_DEBUG_NEW_FILENAME_LEN - 1] = '\0';
508  else
509  ptr->addr = (void*)file;
510 #endif
511  ptr->line = line;
512  ptr->is_array = is_array;
513  ptr->size = size;
514  ptr->magic = MAGIC;
515  {
516  fast_mutex_autolock lock(new_ptr_lock);
517  ptr->prev = new_ptr_list.prev;
518  ptr->next = &new_ptr_list;
519  new_ptr_list.prev->next = ptr;
520  new_ptr_list.prev = ptr;
521  }
522 #if _DEBUG_NEW_TAILCHECK
523  memset((char*)pointer + size, _DEBUG_NEW_TAILCHECK_CHAR,
524  _DEBUG_NEW_TAILCHECK);
525 #endif
526  if (new_verbose_flag)
527  {
528  fast_mutex_autolock lock(new_output_lock);
529  fprintf(new_output_fp,
530  "new%s: allocated %p (size %lu, ",
531  is_array ? "[]" : "",
532  pointer, (unsigned long)size);
533  if (line != 0)
534  print_position(ptr->file, ptr->line);
535  else
536  print_position(ptr->addr, ptr->line);
537  fprintf(new_output_fp, ")\n");
538  }
539  total_mem_alloc += size;
540  return pointer;
541 }
542 
551 static void free_pointer(void* pointer, void* addr, bool is_array)
552 {
553  if (pointer == NULL)
554  return;
555  new_ptr_list_t* ptr =
556  (new_ptr_list_t*)((char*)pointer - ALIGNED_LIST_ITEM_SIZE);
557  if (ptr->magic != MAGIC)
558  {
559  {
560  fast_mutex_autolock lock(new_output_lock);
561  fprintf(new_output_fp, "delete%s: invalid pointer %p (",
562  is_array ? "[]" : "", pointer);
563  print_position(addr, 0);
564  fprintf(new_output_fp, ")\n");
565  }
567  fflush(new_output_fp);
568  _DEBUG_NEW_ERROR_ACTION;
569  }
570  if (is_array != ptr->is_array)
571  {
572  const char* msg;
573  if (is_array)
574  msg = "delete[] after new";
575  else
576  msg = "delete after new[]";
577  fast_mutex_autolock lock(new_output_lock);
578  fprintf(new_output_fp,
579  "%s: pointer %p (size %lu)\n\tat ",
580  msg,
581  (char*)ptr + ALIGNED_LIST_ITEM_SIZE,
582  (unsigned long)ptr->size);
583  print_position(addr, 0);
584  fprintf(new_output_fp, "\n\toriginally allocated at ");
585  if (ptr->line != 0)
586  print_position(ptr->file, ptr->line);
587  else
588  print_position(ptr->addr, ptr->line);
589  fprintf(new_output_fp, "\n");
590  fflush(new_output_fp);
591  _DEBUG_NEW_ERROR_ACTION;
592  }
593 #if _DEBUG_NEW_TAILCHECK
594  if (!check_tail(ptr))
595  {
597  fflush(new_output_fp);
598  _DEBUG_NEW_ERROR_ACTION;
599  }
600 #endif
601  {
602  fast_mutex_autolock lock(new_ptr_lock);
603  total_mem_alloc -= ptr->size;
604  ptr->magic = 0;
605  ptr->prev->next = ptr->next;
606  ptr->next->prev = ptr->prev;
607  }
608  if (new_verbose_flag)
609  {
610  fast_mutex_autolock lock(new_output_lock);
611  fprintf(new_output_fp,
612  "delete%s: freed %p (size %lu, %lu bytes still allocated)\n",
613  is_array ? "[]" : "",
614  (char*)ptr + ALIGNED_LIST_ITEM_SIZE,
615  (unsigned long)ptr->size, (unsigned long)total_mem_alloc);
616  }
617  free(ptr);
618  return;
619 }
620 
626 int check_leaks()
627 {
628  int leak_cnt = 0;
629  fast_mutex_autolock lock_ptr(new_ptr_lock);
630  fast_mutex_autolock lock_output(new_output_lock);
631  new_ptr_list_t* ptr = new_ptr_list.next;
632  while (ptr != &new_ptr_list)
633  {
634  const char* const pointer = (char*)ptr + ALIGNED_LIST_ITEM_SIZE;
635  if (ptr->magic != MAGIC)
636  {
637  fprintf(new_output_fp,
638  "warning: heap data corrupt near %p\n",
639  pointer);
640  }
641 #if _DEBUG_NEW_TAILCHECK
642  if (!check_tail(ptr))
643  {
644  fprintf(new_output_fp,
645  "warning: overwritten past end of object at %p\n",
646  pointer);
647  }
648 #endif
649  fprintf(new_output_fp,
650  "Leaked object at %p (size %lu, ",
651  pointer,
652  (unsigned long)ptr->size);
653  if (ptr->line != 0)
654  print_position(ptr->file, ptr->line);
655  else
656  print_position(ptr->addr, ptr->line);
657  fprintf(new_output_fp, ")\n");
658  ptr = ptr->next;
659  ++leak_cnt;
660  }
661  if (new_verbose_flag || leak_cnt)
662  fprintf(new_output_fp, "*** %d leaks found\n", leak_cnt);
663  return leak_cnt;
664 }
665 
673 {
674  int corrupt_cnt = 0;
675  fast_mutex_autolock lock_ptr(new_ptr_lock);
676  fast_mutex_autolock lock_output(new_output_lock);
677  fprintf(new_output_fp, "*** Checking for memory corruption: START\n");
678  for (new_ptr_list_t* ptr = new_ptr_list.next;
679  ptr != &new_ptr_list;
680  ptr = ptr->next)
681  {
682  const char* const pointer = (char*)ptr + ALIGNED_LIST_ITEM_SIZE;
683  if (ptr->magic == MAGIC
684 #if _DEBUG_NEW_TAILCHECK
685  && check_tail(ptr)
686 #endif
687  )
688  continue;
689 #if _DEBUG_NEW_TAILCHECK
690  if (ptr->magic != MAGIC)
691  {
692 #endif
693  fprintf(new_output_fp,
694  "Heap data corrupt near %p (size %lu, ",
695  pointer,
696  (unsigned long)ptr->size);
697 #if _DEBUG_NEW_TAILCHECK
698  }
699  else
700  {
701  fprintf(new_output_fp,
702  "Overwritten past end of object at %p (size %lu, ",
703  pointer,
704  (unsigned long)ptr->size);
705  }
706 #endif
707  if (ptr->line != 0)
708  print_position(ptr->file, ptr->line);
709  else
710  print_position(ptr->addr, ptr->line);
711  fprintf(new_output_fp, ")\n");
712  ++corrupt_cnt;
713  }
714  fprintf(new_output_fp, "*** Checking for memory corruption: %d FOUND\n",
715  corrupt_cnt);
716  return corrupt_cnt;
717 }
718 
726 void __debug_new_recorder::_M_process(void* pointer)
727 {
728  if (pointer == NULL)
729  return;
730 
731  // In an expression `new NonPODType[size]', the pointer returned is
732  // not the pointer returned by operator new[], but offset by size_t
733  // to leave room for the size. It needs to be compensated here.
734  size_t offset = (char*)pointer - (char*)NULL;
735  if (offset % PLATFORM_MEM_ALIGNMENT != 0) {
736  offset -= sizeof(size_t);
737  if (offset % PLATFORM_MEM_ALIGNMENT != 0) {
738  return;
739  }
740  pointer = (char*)pointer - sizeof(size_t);
741  }
742 
743  new_ptr_list_t* ptr =
744  (new_ptr_list_t*)((char*)pointer - ALIGNED_LIST_ITEM_SIZE);
745  if (ptr->magic != MAGIC || ptr->line != 0)
746  {
747  fast_mutex_autolock lock(new_output_lock);
748  fprintf(new_output_fp,
749  "warning: debug_new used with placement new (%s:%d)\n",
750  _M_file, _M_line);
751  return;
752  }
753  if (new_verbose_flag) {
754  fast_mutex_autolock lock(new_output_lock);
755  fprintf(new_output_fp,
756  "info: pointer %p allocated from %s:%d\n",
757  pointer, _M_file, _M_line);
758  }
759 #if _DEBUG_NEW_FILENAME_LEN == 0
760  ptr->file = _M_file;
761 #else
762  strncpy(ptr->file, _M_file, _DEBUG_NEW_FILENAME_LEN - 1)
763  [_DEBUG_NEW_FILENAME_LEN - 1] = '\0';
764 #endif
765  ptr->line = _M_line;
766 }
767 
778 void* operator new(size_t size, const char* file, int line)
779 {
780  void* ptr = alloc_mem(size, file, line, false);
781 #if _DEBUG_NEW_STD_OPER_NEW
782  if (ptr)
783  return ptr;
784  else
785  throw std::bad_alloc();
786 #else
787  return ptr;
788 #endif
789 }
790 
801 void* operator new[](size_t size, const char* file, int line)
802 {
803  void* ptr = alloc_mem(size, file, line, true);
804 #if _DEBUG_NEW_STD_OPER_NEW
805  if (ptr)
806  return ptr;
807  else
808  throw std::bad_alloc();
809 #else
810  return ptr;
811 #endif
812 }
813 
822 void* operator new(size_t size) throw(std::bad_alloc)
823 {
824  return operator new(size, (char*)_DEBUG_NEW_CALLER_ADDRESS, 0);
825 }
826 
835 void* operator new[](size_t size) throw(std::bad_alloc)
836 {
837  return operator new[](size, (char*)_DEBUG_NEW_CALLER_ADDRESS, 0);
838 }
839 
847 void* operator new(size_t size, const std::nothrow_t&) throw()
848 {
849  return alloc_mem(size, (char*)_DEBUG_NEW_CALLER_ADDRESS, 0, false);
850 }
851 
859 void* operator new[](size_t size, const std::nothrow_t&) throw()
860 {
861  return alloc_mem(size, (char*)_DEBUG_NEW_CALLER_ADDRESS, 0, true);
862 }
863 
869 void operator delete(void* pointer) throw()
870 {
871  free_pointer(pointer, _DEBUG_NEW_CALLER_ADDRESS, false);
872 }
873 
879 void operator delete[](void* pointer) throw()
880 {
881  free_pointer(pointer, _DEBUG_NEW_CALLER_ADDRESS, true);
882 }
883 
895 void operator delete(void* pointer, const char* file, int line) throw()
896 {
897  if (new_verbose_flag)
898  {
899  fast_mutex_autolock lock(new_output_lock);
900  fprintf(new_output_fp,
901  "info: exception thrown on initializing object at %p (",
902  pointer);
903  print_position(file, line);
904  fprintf(new_output_fp, ")\n");
905  }
906  operator delete(pointer);
907 }
908 
917 void operator delete[](void* pointer, const char* file, int line) throw()
918 {
919  if (new_verbose_flag)
920  {
921  fast_mutex_autolock lock(new_output_lock);
922  fprintf(new_output_fp,
923  "info: exception thrown on initializing objects at %p (",
924  pointer);
925  print_position(file, line);
926  fprintf(new_output_fp, ")\n");
927  }
928  operator delete[](pointer);
929 }
930 
937 void operator delete(void* pointer, const std::nothrow_t&) throw()
938 {
939  operator delete(pointer, (char*)_DEBUG_NEW_CALLER_ADDRESS, 0);
940 }
941 
948 void operator delete[](void* pointer, const std::nothrow_t&) throw()
949 {
950  operator delete[](pointer, (char*)_DEBUG_NEW_CALLER_ADDRESS, 0);
951 }
952 
957 
962 {
963  ++_S_count;
964 }
965 
971 {
972  if (--_S_count == 0 && new_autocheck_flag)
973  if (check_leaks())
974  {
975  new_verbose_flag = true;
976 #if defined(__GNUC__) && __GNUC__ >= 3
977  if (!getenv("GLIBCPP_FORCE_NEW") && !getenv("GLIBCXX_FORCE_NEW"))
978  fprintf(new_output_fp,
979 "*** WARNING: GCC 3 or later is detected, please make sure the\n"
980 " environment variable GLIBCPP_FORCE_NEW (GCC 3.2 and 3.3) or\n"
981 " GLIBCXX_FORCE_NEW (GCC 3.4 and later) is defined. Check the\n"
982 " README file for details.\n");
983 #endif
984  }
985 }
986 
987 #endif
const char * new_progname
#define STATIC_ASSERT(_Expr, _Msg)
Definition: static_assert.h:44
bool new_verbose_flag
void _M_process(void *pointer)
bool new_autocheck_flag
FILE * new_output_fp
int check_mem_corruption()
int check_leaks()
static int _S_count
Definition: debug_new.h:173
const char * _M_file
Definition: debug_new.h:142