SUMO - Simulation of Urban MObility
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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-2013 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 
43 #include <new> // std::bad_alloc/nothrow_t
44 #include <assert.h> // assert
45 #include <stdio.h> // fprintf/stderr
46 #include <stdlib.h> // abort
47 #include <string.h> // strcpy/strncpy/sprintf
48 #if defined(__unix__) || defined(__unix) || \
49  (defined(__APPLE__) && defined(__MACH__))
50 #include <alloca.h> // alloca
51 #endif
52 #ifdef _WIN32
53 #include <malloc.h> // alloca
54 #endif
55 #include "_nvwa.h" // NVWA_NAMESPACE_*
56 #include "c++11.h" // _NOEXCEPT
57 #include "fast_mutex.h" // nvwa::fast_mutex
58 #include "static_assert.h" // STATIC_ASSERT
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 
213 NVWA_NAMESPACE_BEGIN
214 
223 const size_t PLATFORM_MEM_ALIGNMENT = sizeof(size_t) * 2;
224 
228 struct new_ptr_list_t
229 {
230  new_ptr_list_t* next;
231  new_ptr_list_t* prev;
232  size_t size;
233  union
234  {
235 #if _DEBUG_NEW_FILENAME_LEN == 0
236  const char* file;
237 #else
238  char file[_DEBUG_NEW_FILENAME_LEN];
239 #endif
240  void* addr;
241  };
242  unsigned line :31;
243  unsigned is_array:1;
244  unsigned magic;
245 };
246 
250 static const unsigned DEBUG_NEW_MAGIC = 0x4442474E;
251 
255 static const int ALIGNED_LIST_ITEM_SIZE = ALIGN(sizeof(new_ptr_list_t));
256 
260 static new_ptr_list_t new_ptr_list = {
261  &new_ptr_list,
262  &new_ptr_list,
263  0,
264  {
265 #if _DEBUG_NEW_FILENAME_LEN == 0
266  NULL
267 #else
268  ""
269 #endif
270  },
271  0,
272  0,
273  DEBUG_NEW_MAGIC
274 };
275 
279 static fast_mutex new_ptr_lock;
280 
284 static fast_mutex new_output_lock;
285 
289 static size_t total_mem_alloc = 0;
290 
295 bool new_autocheck_flag = true;
296 
300 bool new_verbose_flag = false;
301 
307 FILE* new_output_fp = stderr;
308 
317 const char* new_progname = _DEBUG_NEW_PROGNAME;
318 
319 #if _DEBUG_NEW_USE_ADDR2LINE
320 
329 static bool print_position_from_addr(const void* addr)
330 {
331  static const void* last_addr = NULL;
332  static char last_info[256] = "";
333  if (addr == last_addr)
334  {
335  if (last_info[0] == '\0')
336  return false;
337  fprintf(new_output_fp, "%s", last_info);
338  return true;
339  }
340  if (new_progname)
341  {
342 #if defined(__APPLE__) && defined(__MACH__)
343  const char addr2line_cmd[] = "atos -o ";
344 #else
345  const char addr2line_cmd[] = "addr2line -e ";
346 #endif
347 #if defined(__CYGWIN__) || defined(_WIN32)
348  const int exeext_len = 4;
349 #else
350  const int exeext_len = 0;
351 #endif
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";
359 #else
360  const char ignore_err[] = "";
361 #endif
362  char* cmd = (char*)alloca(strlen(new_progname)
363  + exeext_len
364  + sizeof addr2line_cmd - 1
365  + sizeof ignore_err - 1
366  + sizeof(void*) * 2
367  + 4 /* SP + "0x" + null */);
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)
372  if (len <= 4
373  || (strcmp(cmd + len - 4, ".exe") != 0 &&
374  strcmp(cmd + len - 4, ".EXE") != 0))
375  {
376  strcpy(cmd + len, ".exe");
377  len += 4;
378  }
379 #endif
380  sprintf(cmd + len, " %p%s", addr, ignore_err);
381  FILE* fp = popen(cmd, "r");
382  if (fp)
383  {
384  char buffer[sizeof last_info] = "";
385  len = 0;
386  if (fgets(buffer, sizeof buffer, fp))
387  {
388  len = strlen(buffer);
389  if (buffer[len - 1] == '\n')
390  buffer[--len] = '\0';
391  }
392  int res = pclose(fp);
393  // Display the file/line information only if the command
394  // is executed successfully and the output points to a
395  // valid position, but the result will be cached if only
396  // the command is executed successfully.
397  if (res == 0 && len > 0)
398  {
399  last_addr = addr;
400  if (buffer[len - 1] == '0' && buffer[len - 2] == ':')
401  last_info[0] = '\0';
402  else
403  {
404  fprintf(new_output_fp, "%s", buffer);
405  strcpy(last_info, buffer);
406  return true;
407  }
408  }
409  }
410  }
411  return false;
412 }
413 #else
414 
420 static bool print_position_from_addr(const void*)
421 {
422  return false;
423 }
424 #endif // _DEBUG_NEW_USE_ADDR2LINE
425 
437 static void print_position(const void* ptr, int line)
438 {
439  if (line != 0) // Is file/line information present?
440  {
441  fprintf(new_output_fp, "%s:%d", (const char*)ptr, line);
442  }
443  else if (ptr != NULL) // Is caller address present?
444  {
445  if (!print_position_from_addr(ptr)) // Fail to get source position?
446  fprintf(new_output_fp, "%p", ptr);
447  }
448  else // No information is present
449  {
450  fprintf(new_output_fp, "<Unknown>");
451  }
452 }
453 
454 #if _DEBUG_NEW_TAILCHECK
455 
463 static bool check_tail(new_ptr_list_t* ptr)
464 {
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)
469  return false;
470  return true;
471 }
472 #endif
473 
484 static void* alloc_mem(size_t size, const char* file, int line, bool is_array)
485 {
486  assert(line >= 0);
487 #if _DEBUG_NEW_TYPE == 1
488  STATIC_ASSERT(_DEBUG_NEW_ALIGNMENT >= PLATFORM_MEM_ALIGNMENT,
489  Alignment_too_small);
490 #endif
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);
496  if (ptr == NULL)
497  {
498 #if _DEBUG_NEW_STD_OPER_NEW
499  return NULL;
500 #else
501  fast_mutex_autolock lock(new_output_lock);
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;
507 #endif
508  }
509  void* usr_ptr = (char*)ptr + ALIGNED_LIST_ITEM_SIZE;
510 #if _DEBUG_NEW_FILENAME_LEN == 0
511  ptr->file = file;
512 #else
513  if (line)
514  strncpy(ptr->file, file, _DEBUG_NEW_FILENAME_LEN - 1)
515  [_DEBUG_NEW_FILENAME_LEN - 1] = '\0';
516  else
517  ptr->addr = (void*)file;
518 #endif
519  ptr->line = line;
520  ptr->is_array = is_array;
521  ptr->size = size;
522  ptr->magic = DEBUG_NEW_MAGIC;
523  {
524  fast_mutex_autolock lock(new_ptr_lock);
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;
529  }
530 #if _DEBUG_NEW_TAILCHECK
531  memset((char*)usr_ptr + size, _DEBUG_NEW_TAILCHECK_CHAR,
532  _DEBUG_NEW_TAILCHECK);
533 #endif
534  if (new_verbose_flag)
535  {
536  fast_mutex_autolock lock(new_output_lock);
537  fprintf(new_output_fp,
538  "new%s: allocated %p (size %lu, ",
539  is_array ? "[]" : "",
540  usr_ptr, (unsigned long)size);
541  if (line != 0)
542  print_position(ptr->file, ptr->line);
543  else
544  print_position(ptr->addr, ptr->line);
545  fprintf(new_output_fp, ")\n");
546  }
547  total_mem_alloc += size;
548  return usr_ptr;
549 }
550 
559 static void free_pointer(void* usr_ptr, void* addr, bool is_array)
560 {
561  if (usr_ptr == NULL)
562  return;
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)
566  {
567  {
568  fast_mutex_autolock lock(new_output_lock);
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");
573  }
575  fflush(new_output_fp);
576  _DEBUG_NEW_ERROR_ACTION;
577  }
578  if (is_array != ptr->is_array)
579  {
580  const char* msg;
581  if (is_array)
582  msg = "delete[] after new";
583  else
584  msg = "delete after new[]";
585  fast_mutex_autolock lock(new_output_lock);
586  fprintf(new_output_fp,
587  "%s: pointer %p (size %lu)\n\tat ",
588  msg,
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 ");
593  if (ptr->line != 0)
594  print_position(ptr->file, ptr->line);
595  else
596  print_position(ptr->addr, ptr->line);
597  fprintf(new_output_fp, "\n");
598  fflush(new_output_fp);
599  _DEBUG_NEW_ERROR_ACTION;
600  }
601 #if _DEBUG_NEW_TAILCHECK
602  if (!check_tail(ptr))
603  {
605  fflush(new_output_fp);
606  _DEBUG_NEW_ERROR_ACTION;
607  }
608 #endif
609  {
610  fast_mutex_autolock lock(new_ptr_lock);
611  total_mem_alloc -= ptr->size;
612  ptr->magic = 0;
613  ptr->prev->next = ptr->next;
614  ptr->next->prev = ptr->prev;
615  }
616  if (new_verbose_flag)
617  {
618  fast_mutex_autolock lock(new_output_lock);
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);
624  }
625  free(ptr);
626  return;
627 }
628 
634 int check_leaks()
635 {
636  int leak_cnt = 0;
637  fast_mutex_autolock lock_ptr(new_ptr_lock);
638  fast_mutex_autolock lock_output(new_output_lock);
639  new_ptr_list_t* ptr = new_ptr_list.next;
640  while (ptr != &new_ptr_list)
641  {
642  const char* const usr_ptr = (char*)ptr + ALIGNED_LIST_ITEM_SIZE;
643  if (ptr->magic != DEBUG_NEW_MAGIC)
644  {
645  fprintf(new_output_fp,
646  "warning: heap data corrupt near %p\n",
647  usr_ptr);
648  }
649 #if _DEBUG_NEW_TAILCHECK
650  if (!check_tail(ptr))
651  {
652  fprintf(new_output_fp,
653  "warning: overwritten past end of object at %p\n",
654  usr_ptr);
655  }
656 #endif
657  fprintf(new_output_fp,
658  "Leaked object at %p (size %lu, ",
659  usr_ptr,
660  (unsigned long)ptr->size);
661  if (ptr->line != 0)
662  print_position(ptr->file, ptr->line);
663  else
664  print_position(ptr->addr, ptr->line);
665  fprintf(new_output_fp, ")\n");
666  ptr = ptr->next;
667  ++leak_cnt;
668  }
669  if (new_verbose_flag || leak_cnt)
670  fprintf(new_output_fp, "*** %d leaks found\n", leak_cnt);
671  return leak_cnt;
672 }
673 
681 {
682  int corrupt_cnt = 0;
683  fast_mutex_autolock lock_ptr(new_ptr_lock);
684  fast_mutex_autolock lock_output(new_output_lock);
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;
688  ptr = ptr->next)
689  {
690  const char* const usr_ptr = (char*)ptr + ALIGNED_LIST_ITEM_SIZE;
691  if (ptr->magic == DEBUG_NEW_MAGIC
692 #if _DEBUG_NEW_TAILCHECK
693  && check_tail(ptr)
694 #endif
695  )
696  continue;
697 #if _DEBUG_NEW_TAILCHECK
698  if (ptr->magic != DEBUG_NEW_MAGIC)
699  {
700 #endif
701  fprintf(new_output_fp,
702  "Heap data corrupt near %p (size %lu, ",
703  usr_ptr,
704  (unsigned long)ptr->size);
705 #if _DEBUG_NEW_TAILCHECK
706  }
707  else
708  {
709  fprintf(new_output_fp,
710  "Overwritten past end of object at %p (size %lu, ",
711  usr_ptr,
712  (unsigned long)ptr->size);
713  }
714 #endif
715  if (ptr->line != 0)
716  print_position(ptr->file, ptr->line);
717  else
718  print_position(ptr->addr, ptr->line);
719  fprintf(new_output_fp, ")\n");
720  ++corrupt_cnt;
721  }
722  fprintf(new_output_fp, "*** Checking for memory corruption: %d FOUND\n",
723  corrupt_cnt);
724  return corrupt_cnt;
725 }
726 
734 void debug_new_recorder::_M_process(void* usr_ptr)
735 {
736  if (usr_ptr == NULL)
737  return;
738 
739  // In an expression `new NonPODType[size]', the pointer returned is
740  // not the pointer returned by operator new[], but offset by size_t
741  // to leave room for the size. It needs to be compensated here.
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) {
746  fast_mutex_autolock lock(new_output_lock);
747  fprintf(new_output_fp,
748  "warning: memory unaligned; skipping processing (%s:%d)\n",
749  _M_file, _M_line);
750  return;
751  }
752  usr_ptr = (char*)usr_ptr - sizeof(size_t);
753  }
754 
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)
758  {
759  fast_mutex_autolock lock(new_output_lock);
760  fprintf(new_output_fp,
761  "warning: debug_new used with placement new (%s:%d)\n",
762  _M_file, _M_line);
763  return;
764  }
765  if (new_verbose_flag) {
766  fast_mutex_autolock lock(new_output_lock);
767  fprintf(new_output_fp,
768  "info: pointer %p allocated from %s:%d\n",
769  usr_ptr, _M_file, _M_line);
770  }
771 #if _DEBUG_NEW_FILENAME_LEN == 0
772  ptr->file = _M_file;
773 #else
774  strncpy(ptr->file, _M_file, _DEBUG_NEW_FILENAME_LEN - 1)
775  [_DEBUG_NEW_FILENAME_LEN - 1] = '\0';
776 #endif
777  ptr->line = _M_line;
778 }
779 
784 
789 {
790  ++_S_count;
791 }
792 
798 {
799  if (--_S_count == 0 && new_autocheck_flag)
800  if (check_leaks())
801  {
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");
809 #endif
810  }
811 }
812 
813 NVWA_NAMESPACE_END
814 
815 #if NVWA_USE_NAMESPACE
816 using namespace nvwa;
817 #endif // NVWA_USE_NAMESPACE
818 
829 void* operator new(size_t size, const char* file, int line)
830 {
831  void* ptr = alloc_mem(size, file, line, false);
832 #if _DEBUG_NEW_STD_OPER_NEW
833  if (ptr)
834  return ptr;
835  else
836  throw std::bad_alloc();
837 #else
838  return ptr;
839 #endif
840 }
841 
852 void* operator new[](size_t size, const char* file, int line)
853 {
854  void* ptr = alloc_mem(size, file, line, true);
855 #if _DEBUG_NEW_STD_OPER_NEW
856  if (ptr)
857  return ptr;
858  else
859  throw std::bad_alloc();
860 #else
861  return ptr;
862 #endif
863 }
864 
873 void* operator new(size_t size) _GLIBCXX_THROW (std::bad_alloc) // modified to let it compile with c++11, MB 2015-04-17
874 {
875  return operator new(size, (char*)_DEBUG_NEW_CALLER_ADDRESS, 0);
876 }
877 
886 void* operator new[](size_t size) _GLIBCXX_THROW (std::bad_alloc) // modified to let it compile with c++11, MB 2015-04-17
887 {
888  return operator new[](size, (char*)_DEBUG_NEW_CALLER_ADDRESS, 0);
889 }
890 
898 void* operator new(size_t size, const std::nothrow_t&) _NOEXCEPT
899 {
900  return alloc_mem(size, (char*)_DEBUG_NEW_CALLER_ADDRESS, 0, false);
901 }
902 
910 void* operator new[](size_t size, const std::nothrow_t&) _NOEXCEPT
911 {
912  return alloc_mem(size, (char*)_DEBUG_NEW_CALLER_ADDRESS, 0, true);
913 }
914 
920 void operator delete(void* ptr) _NOEXCEPT
921 {
922  free_pointer(ptr, _DEBUG_NEW_CALLER_ADDRESS, false);
923 }
924 
930 void operator delete[](void* ptr) _NOEXCEPT
931 {
932  free_pointer(ptr, _DEBUG_NEW_CALLER_ADDRESS, true);
933 }
934 
946 void operator delete(void* ptr, const char* file, int line) _NOEXCEPT
947 {
948  if (new_verbose_flag)
949  {
950  fast_mutex_autolock lock(new_output_lock);
951  fprintf(new_output_fp,
952  "info: exception thrown on initializing object at %p (",
953  ptr);
954  print_position(file, line);
955  fprintf(new_output_fp, ")\n");
956  }
957  operator delete(ptr);
958 }
959 
968 void operator delete[](void* ptr, const char* file, int line) _NOEXCEPT
969 {
970  if (new_verbose_flag)
971  {
972  fast_mutex_autolock lock(new_output_lock);
973  fprintf(new_output_fp,
974  "info: exception thrown on initializing objects at %p (",
975  ptr);
976  print_position(file, line);
977  fprintf(new_output_fp, ")\n");
978  }
979  operator delete[](ptr);
980 }
981 
988 void operator delete(void* ptr, const std::nothrow_t&) _NOEXCEPT
989 {
990  operator delete(ptr, (char*)_DEBUG_NEW_CALLER_ADDRESS, 0);
991 }
992 
999 void operator delete[](void* ptr, const std::nothrow_t&) _NOEXCEPT
1000 {
1001  operator delete[](ptr, (char*)_DEBUG_NEW_CALLER_ADDRESS, 0);
1002 }
1003 
1004 #endif
const char * new_progname
#define STATIC_ASSERT(_Expr, _Msg)
Definition: static_assert.h:52
bool new_verbose_flag
const int _M_line
Definition: debug_new.h:141
bool new_autocheck_flag
const char * _M_file
Definition: debug_new.h:140
FILE * new_output_fp
void _M_process(void *ptr)
static int _S_count
Definition: debug_new.h:171
int check_mem_corruption()
int check_leaks()