QTrk
memdbg.cpp
Go to the documentation of this file.
1 // Simple memory tracker for debugging memory leaks
2 // Completed version of the one posted http://stackoverflow.com/questions/438515/how-to-track-memory-allocations-in-c-especially-new-delete
3 #ifdef USE_MEMDBG
4 #include <map>
5 #include <cstdint>
6 
7 #include <Windows.h>
8 
9 #include "dllmacros.h"
10 
11 void dbgprintf(const char *fmt,...);
12 
13 struct Allocation {
14  const char *srcfile;
15  int line;
16  size_t size;
17 };
18 
19 template<typename T>
20 struct track_alloc : std::allocator<T> {
21  typedef typename std::allocator<T>::pointer pointer;
22  typedef typename std::allocator<T>::size_type size_type;
23 
24  template<typename U>
25  struct rebind {
26  typedef track_alloc<U> other;
27  };
28 
29  track_alloc() {}
30 
31  template<typename U>
32  track_alloc(track_alloc<U> const& u)
33  :std::allocator<T>(u) {}
34 
35  pointer allocate(size_type size,
36  std::allocator<void>::const_pointer = 0) {
37  void * p = std::malloc(size * sizeof(T));
38  if(p == 0) {
39  throw std::bad_alloc();
40  }
41  return static_cast<pointer>(p);
42  }
43 
44  void deallocate(pointer p, size_type) {
45  std::free(p);
46  }
47 };
48 
49 
50 struct MemDbgMutex {
51  HANDLE h;
52  int lockCount;
53 
54  MemDbgMutex (){
55  h=CreateMutex(0,FALSE,0);
56  lockCount=0;
57  }
58  ~MemDbgMutex () { CloseHandle(h); }
59  void lock() {
60  WaitForSingleObject(h, INFINITE);
61  lockCount++;
62  }
63  void unlock() {
64  lockCount--;
65  ReleaseMutex(h);
66  }
67 };
68 
69 
70 struct AllocMap {
71  typedef std::map< void*, Allocation, std::less<void*>,
72  track_alloc< std::pair<void* const, std::size_t> > > MapType;
73  MapType map;
74 
75 
76  MemDbgMutex mutex;
77  void Store(void *mem, const Allocation& alloc) {
78  mutex.lock();
79  map[mem] = alloc;
80  mutex.unlock();
81  }
82  void Remove(void *mem) {
83  mutex.lock();
84  map.erase(mem);
85  mutex.unlock();
86  }
87  void Print()
88  {
89  dbgprintf("Allocations: %d\n", map.size());
90  size_t total = 0;
91  for (auto i = map.begin(); i != map.end(); ++i)
92  {
93  Allocation& a = i->second;
94  dbgprintf("Allocation: %d bytes: @ line %d in '%s'\n" , a.size, a.line, a.srcfile);
95  total += a.size;
96  }
97  dbgprintf("Total: %d bytes\n", total);
98  }
99 };
100 
101 struct track_printer {
102  AllocMap* track;
103  track_printer(AllocMap * track):track(track) {}
104  ~track_printer()
105  {
106  track->Print();
107  }
108 };
109 
110 AllocMap * get_map() {
111  // don't use normal new to avoid infinite recursion.
112  static AllocMap * track = new (std::malloc(sizeof *track)) AllocMap;
113  static track_printer printer(track);
114  return track;
115 }
116 
117 void * operator new(size_t s, const char* file, int line) {
118  // we are required to return non-null
119  void * mem = std::malloc(s == 0 ? 1 : s);
120  if(mem == 0) {
121  throw std::bad_alloc();
122  }
123  Allocation alloc = { file, line ,s };
124  get_map()->Store (mem, alloc);
125  return mem;
126 }
127 void * operator new[](size_t s, const char* file, int line) {
128  // we are required to return non-null
129  void * mem = std::malloc(s == 0 ? 1 : s);
130  if(mem == 0) {
131  throw std::bad_alloc();
132  }
133  Allocation alloc = { file, line ,s };
134  get_map()->Store(mem,alloc);
135  return mem;
136 }
137 
138 void operator delete(void * mem) {
139  get_map()->Remove(mem);
140  std::free(mem);
141 }
142 void operator delete[](void * mem) {
143  get_map()->Remove(mem);
144  std::free(mem);
145 }
146 
147 
148 #endif
STL namespace.
void dbgprintf(const char *fmt,...)
Definition: utils.cpp:149