ManaPlus
Data Structures | Macros | Typedefs | Functions | Variables
debug_new.h File Reference

(986a3bf)

#include <new>
#include <stdio.h>
#include "debug/nvwa/_nvwa.h"
#include "debug/nvwa/c++11.h"

Go to the source code of this file.

Data Structures

class  debug_new_recorder
 
class  debug_new_counter
 

Macros

#define _DEBUG_NEW_REDEFINE_NEW   1
 
#define _DEBUG_NEW_TYPE   1
 
#define DEBUG_NEW   NVWA::debug_new_recorder(__FILE__, __LINE__) ->* new
 
#define new   DEBUG_NEW
 

Typedefs

typedef void(* stacktrace_print_callback_t) (FILE *fp, void **stacktrace)
 
typedef bool(* leak_whitelist_callback_t) (char const *file, int line, void *addr, void **stacktrace)
 

Functions

void * operator new (size_t size, const char *file, int line)
 
void * operator new[] (size_t size, const char *file, int line)
 
void operator delete (void *ptr, const char *file, int line) throw ()
 
void operator delete[] (void *ptr, const char *file, int line) throw ()
 
int check_leaks ()
 
int check_mem_corruption ()
 

Variables

bool new_autocheck_flag
 
bool new_verbose_flag
 
FILE * new_output_fp
 
const char * new_progname
 
stacktrace_print_callback_t stacktrace_print_callback
 
leak_whitelist_callback_t leak_whitelist_callback
 
static debug_new_counter __debug_new_count
 

Detailed Description

Header file for checking leaks caused by unmatched new/delete.

Date
2015-10-25

Definition in file debug_new.h.

Macro Definition Documentation

◆ _DEBUG_NEW_REDEFINE_NEW

#define _DEBUG_NEW_REDEFINE_NEW   1

Macro to indicate whether redefinition of new is wanted. If one wants to define one's own operator new, or to call operator new directly, it should be defined to 0 to alter the default behaviour. Unless, of course, one is willing to take the trouble to write something like:

# ifdef new
# define _NEW_REDEFINED
# undef new
# endif
// Code that uses new is here
# ifdef _NEW_REDEFINED
# ifdef DEBUG_NEW
# define new DEBUG_NEW
# endif
# undef _NEW_REDEFINED
# endif

Definition at line 78 of file debug_new.h.

◆ _DEBUG_NEW_TYPE

#define _DEBUG_NEW_TYPE   1

Macro to indicate which variant of DEBUG_NEW is wanted. The default value 1 allows the use of placement new (like new(std::nothrow)), but the verbose output (when nvwa::new_verbose_flag is true) looks worse than some older versions (no file/line information for allocations). Define it to 2 to revert to the old behaviour that records file and line information directly on the call to operator new.

Definition at line 93 of file debug_new.h.

◆ DEBUG_NEW

#define DEBUG_NEW   NVWA::debug_new_recorder(__FILE__, __LINE__) ->* new

Macro to catch file/line information on allocation. If _DEBUG_NEW_REDEFINE_NEW is 0, one can use this macro directly; otherwise new will be defined to it, and one must use new instead.

Definition at line 141 of file debug_new.h.

◆ new

#define new   DEBUG_NEW

Definition at line 147 of file debug_new.h.

Typedef Documentation

◆ leak_whitelist_callback_t

typedef bool(* leak_whitelist_callback_t) (char const *file, int line, void *addr, void **stacktrace)

Callback type for the leak whitelist function. file, address, and backtrace might be null depending on library configuration, platform, and amount of runtime information available. line can be 0 when line number info is not available at runtime.

Parameters
filenull-terminated string of the file name
lineline number
addraddress of code where leakage happens
stacktracepointer to the stack trace array (null-terminated)
Returns
true if the leak should be whitelisted; false otherwise

Definition at line 117 of file debug_new.h.

◆ stacktrace_print_callback_t

typedef void(* stacktrace_print_callback_t) (FILE *fp, void **stacktrace)

Callback type for stack trace printing.

Parameters
fppointer to the output stream
stacktracepointer to the stack trace array (null-terminated)

Definition at line 102 of file debug_new.h.

Function Documentation

◆ check_leaks()

int check_leaks ( )

Checks for memory leaks.

Returns
zero if no leakage is found; the number of leaks otherwise

Definition at line 769 of file debug_new.cpp.

770 {
771  int leak_cnt = 0;
772  int whitelisted_leak_cnt = 0;
776 
777  while (ptr != &new_ptr_list)
778  {
779  const char* const usr_ptr = (char*)ptr + ALIGNED_LIST_ITEM_SIZE;
780  if (ptr->magic != DEBUG_NEW_MAGIC)
781  {
782  fprintf(new_output_fp,
783  "warning: heap data corrupt near %p\n",
784  usr_ptr);
785  }
786 #if _DEBUG_NEW_TAILCHECK
787  if (!check_tail(ptr))
788  {
789  fprintf(new_output_fp,
790  "warning: overwritten past end of object at %p\n",
791  usr_ptr);
792  }
793 #endif
794 
795  if (is_leak_whitelisted(ptr))
796  {
797  ++whitelisted_leak_cnt;
798  }
799  else
800  {
801  fprintf(new_output_fp,
802  "Leaked object at %p (size %lu, ",
803  usr_ptr,
804  (unsigned long)ptr->size);
805 
806  if (ptr->line != 0)
807  print_position(ptr->file, ptr->line);
808  else
809  print_position(ptr->addr, ptr->line);
810 
811  fprintf(new_output_fp, ")\n");
812 
813 #if _DEBUG_NEW_REMEMBER_STACK_TRACE
814  if (ptr->stacktrace != _NULLPTR)
815  print_stacktrace(ptr->stacktrace);
816 #endif
817  }
818 
819  ptr = ptr->next;
820  ++leak_cnt;
821  }
822  if (new_verbose_flag || leak_cnt)
823  {
824  if (whitelisted_leak_cnt > 0)
825  {
826  fprintf(new_output_fp, "*** %d leaks found (%d whitelisted)\n",
827  leak_cnt, whitelisted_leak_cnt);
828  }
829  else
830  {
831  fprintf(new_output_fp, "*** %d leaks found\n", leak_cnt);
832  }
833  }
834 
835  return leak_cnt;
836 }
#define _NULLPTR
Definition: c++11.h:327
static void print_position(const void *ptr, int line)
Definition: debug_new.cpp:488
static bool is_leak_whitelisted(new_ptr_list_t *ptr)
Definition: debug_new.cpp:540
static fast_mutex new_output_lock
Definition: debug_new.cpp:322
bool new_verbose_flag
Definition: debug_new.cpp:338
static fast_mutex new_ptr_lock
Definition: debug_new.cpp:317
static new_ptr_list_t new_ptr_list
Definition: debug_new.cpp:295
static const unsigned DEBUG_NEW_MAGIC
Definition: debug_new.cpp:285
static const int ALIGNED_LIST_ITEM_SIZE
Definition: debug_new.cpp:290
FILE * new_output_fp
Definition: debug_new.cpp:345
new_ptr_list_t * next
Pointer to the next memory block.
Definition: debug_new.cpp:262
char file[44]
File name of the caller.
Definition: debug_new.cpp:270
size_t size
Size of the memory block.
Definition: debug_new.cpp:264
unsigned magic
Magic number for error detection.
Definition: debug_new.cpp:279
void * addr
Address of the caller to new.
Definition: debug_new.cpp:272
unsigned line
Line number of the caller; or 0.
Definition: debug_new.cpp:274

References _NULLPTR, new_ptr_list_t::addr, ALIGNED_LIST_ITEM_SIZE, DEBUG_NEW_MAGIC, new_ptr_list_t::file, is_leak_whitelisted(), new_ptr_list_t::line, new_ptr_list_t::magic, new_output_fp, new_output_lock, new_ptr_list, new_ptr_lock, new_verbose_flag, new_ptr_list_t::next, print_position(), and new_ptr_list_t::size.

Referenced by debug_new_counter::~debug_new_counter().

◆ check_mem_corruption()

int check_mem_corruption ( )

Checks for heap corruption.

Returns
zero if no problem is found; the number of found memory corruptions otherwise

Definition at line 844 of file debug_new.cpp.

845 {
846  int corrupt_cnt = 0;
849  fprintf(new_output_fp, "*** Checking for memory corruption: START\n");
850  for (new_ptr_list_t* ptr = new_ptr_list.next;
851  ptr != &new_ptr_list;
852  ptr = ptr->next)
853  {
854  const char* const usr_ptr = (char*)ptr + ALIGNED_LIST_ITEM_SIZE;
855  if (ptr->magic == DEBUG_NEW_MAGIC
857  && check_tail(ptr)
858 #endif
859  )
860  continue;
861 #if _DEBUG_NEW_TAILCHECK
862  if (ptr->magic != DEBUG_NEW_MAGIC)
863  {
864 #endif
865  fprintf(new_output_fp,
866  "Heap data corrupt near %p (size %lu, ",
867  usr_ptr,
868  (unsigned long)ptr->size);
869 #if _DEBUG_NEW_TAILCHECK
870  }
871  else
872  {
873  fprintf(new_output_fp,
874  "Overwritten past end of object at %p (size %lu, ",
875  usr_ptr,
876  (unsigned long)ptr->size);
877  }
878 #endif
879  if (ptr->line != 0)
880  print_position(ptr->file, ptr->line);
881  else
882  print_position(ptr->addr, ptr->line);
883  fprintf(new_output_fp, ")\n");
884 
885 #if _DEBUG_NEW_REMEMBER_STACK_TRACE
886  if (ptr->stacktrace != _NULLPTR)
887  print_stacktrace(ptr->stacktrace);
888 #endif
889 
890  ++corrupt_cnt;
891  }
892  fprintf(new_output_fp, "*** Checking for memory corruption: %d FOUND\n",
893  corrupt_cnt);
894  return corrupt_cnt;
895 }
#define _DEBUG_NEW_TAILCHECK

References _DEBUG_NEW_TAILCHECK, _NULLPTR, new_ptr_list_t::addr, ALIGNED_LIST_ITEM_SIZE, DEBUG_NEW_MAGIC, new_ptr_list_t::file, new_ptr_list_t::line, new_ptr_list_t::magic, new_output_fp, new_output_lock, new_ptr_list, new_ptr_lock, new_ptr_list_t::next, print_position(), and new_ptr_list_t::size.

Referenced by free_pointer().

◆ operator delete()

void operator delete ( void *  ptr,
const char *  file,
int  line 
)
throw (
)

Placement deallocation function. For details, please check Section 5.3.4 of the C++ 1998 or 2011 Standard.

Parameters
ptrpointer to the previously allocated memory
filenull-terminated string of the file name
lineline number
See also
http://www.csci.csusb.edu/dick/c++std/cd2/expr.html#expr.new
http://wyw.dcweb.cn/leakage.htm

Definition at line 1134 of file debug_new.cpp.

1135 {
1136  if (new_verbose_flag)
1137  {
1139  fprintf(new_output_fp,
1140  "info: exception thrown on initializing object at %p (",
1141  ptr);
1142  print_position(file, line);
1143  fprintf(new_output_fp, ")\n");
1144  }
1145  operator delete(ptr);
1146 }

References new_output_fp, new_output_lock, new_verbose_flag, and print_position().

◆ operator delete[]()

void operator delete[] ( void *  ptr,
const char *  file,
int  line 
)
throw (
)

Placement deallocation function. For details, please check Section 5.3.4 of the C++ 1998 or 2011 Standard.

Parameters
ptrpointer to the previously allocated memory
filenull-terminated string of the file name
lineline number

Definition at line 1156 of file debug_new.cpp.

1157 {
1158  if (new_verbose_flag)
1159  {
1161  fprintf(new_output_fp,
1162  "info: exception thrown on initializing objects at %p (",
1163  ptr);
1164  print_position(file, line);
1165  fprintf(new_output_fp, ")\n");
1166  }
1167  operator delete[](ptr);
1168 }

References new_output_fp, new_output_lock, new_verbose_flag, and print_position().

◆ operator new()

void* operator new ( size_t  size,
const char *  file,
int  line 
)

Allocates memory with file/line information.

Parameters
sizesize of the required memory block
filenull-terminated string of the file name
lineline number
Returns
pointer to the memory allocated; or null if memory is insufficient (_DEBUG_NEW_STD_OPER_NEW is 0)
Exceptions
bad_allocmemory is insufficient (_DEBUG_NEW_STD_OPER_NEW is 1)

Definition at line 1003 of file debug_new.cpp.

1004 {
1005  void* ptr = alloc_mem(size, file, line, false);
1006 #if _DEBUG_NEW_STD_OPER_NEW
1007  if (ptr)
1008  return ptr;
1009  else
1010  throw std::bad_alloc();
1011 #else
1012  return ptr;
1013 #endif
1014 }
static void * alloc_mem(size_t size, const char *file, int line, bool is_array)
Definition: debug_new.cpp:587
int size()
Definition: emotedb.cpp:306

References alloc_mem(), and EmoteDB::size().

◆ operator new[]()

void* operator new[] ( size_t  size,
const char *  file,
int  line 
)

Allocates array memory with file/line information.

Parameters
sizesize of the required memory block
filenull-terminated string of the file name
lineline number
Returns
pointer to the memory allocated; or null if memory is insufficient (_DEBUG_NEW_STD_OPER_NEW is 0)
Exceptions
bad_allocmemory is insufficient (_DEBUG_NEW_STD_OPER_NEW is 1)

Definition at line 1026 of file debug_new.cpp.

1027 {
1028  void* ptr = alloc_mem(size, file, line, true);
1029 #if _DEBUG_NEW_STD_OPER_NEW
1030  if (ptr)
1031  return ptr;
1032  else
1033  throw std::bad_alloc();
1034 #else
1035  return ptr;
1036 #endif
1037 }

References alloc_mem(), and EmoteDB::size().

Variable Documentation

◆ __debug_new_count

debug_new_counter __debug_new_count
static

Counting object for each file including debug_new.h.

Definition at line 203 of file debug_new.h.

◆ leak_whitelist_callback

leak_whitelist_callback_t leak_whitelist_callback
extern

Pointer to the callback used to filter out false positives from leak reports. A null value means the lack of filtering.

Definition at line 368 of file debug_new.cpp.

Referenced by is_leak_whitelisted().

◆ new_autocheck_flag

bool new_autocheck_flag
extern

Flag to control whether nvwa::check_leaks will be automatically called on program exit.

Definition at line 333 of file debug_new.cpp.

Referenced by debug_new_counter::~debug_new_counter().

◆ new_output_fp

FILE* new_output_fp
extern

Pointer to the output stream. The default output is stderr, and one may change it to a user stream if needed (say, new_verbose_flag is true and there are a lot of (de)allocations).

Definition at line 345 of file debug_new.cpp.

Referenced by debug_new_recorder::_M_process(), alloc_mem(), check_leaks(), check_mem_corruption(), free_pointer(), operator delete(), operator delete[](), print_position(), and debug_new_counter::~debug_new_counter().

◆ new_progname

const char* new_progname
extern

Pointer to the program name. Its initial value is the macro _DEBUG_NEW_PROGNAME. You should try to assign the program path to it early in your application. Assigning argv[0] to it in main is one way. If you use bash or ksh (or similar), the following statement is probably what you want: ‘new_progname = getenv("_");’.

Definition at line 355 of file debug_new.cpp.

◆ new_verbose_flag

bool new_verbose_flag
extern

Flag to control whether verbose messages are output.

Definition at line 338 of file debug_new.cpp.

Referenced by debug_new_recorder::_M_process(), alloc_mem(), check_leaks(), free_pointer(), operator delete(), operator delete[](), and debug_new_counter::~debug_new_counter().

◆ stacktrace_print_callback

stacktrace_print_callback_t stacktrace_print_callback
extern

Pointer to the callback used to print the stack backtrace in case of a memory problem. A null value causes the default stack trace printing routine to be used.

Definition at line 362 of file debug_new.cpp.