Dune Core Modules (2.4.2)

debugallocator.hh
1 // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 // vi: set et ts=4 sw=2 sts=2:
3 #ifndef DUNE_DEBUG_ALLOCATOR_HH
4 #define DUNE_DEBUG_ALLOCATOR_HH
5 
6 #include <dune/common/unused.hh>
7 #include <exception>
8 #include <typeinfo>
9 #include <vector>
10 #include <iostream>
11 #include <cstring>
12 #include <cstdint>
13 #include <cstdlib>
14 #include <new>
15 #if HAVE_SYS_MMAN_H && HAVE_MPROTECT
16 #include <sys/mman.h>
17 #else
18 enum DummyProtFlags { PROT_NONE, PROT_WRITE, PROT_READ };
19 #endif
20 
21 #include "mallocallocator.hh"
22 
23 namespace Dune
24 {
25 
26 #ifndef DOXYGEN // hide implementation details from doxygen
27  namespace DebugMemory
28  {
29 
30  extern const std::ptrdiff_t page_size;
31 
32  struct AllocationManager
33  {
34  typedef std::size_t size_type;
35  typedef std::ptrdiff_t difference_type;
36  typedef void* pointer;
37 
38  protected:
39  static void allocation_error(const char* msg);
40 
41  struct AllocationInfo;
42  friend struct AllocationInfo;
43 
44 #define ALLOCATION_ASSERT(A) { if (!(A)) \
45  { allocation_error("Assertion " # A " failed");\
46  }\
47 };
48 
49  struct AllocationInfo
50  {
51  AllocationInfo(const std::type_info & t) : type(&t) {}
52  const std::type_info * type;
53 
54  pointer page_ptr;
55  pointer ptr;
56  size_type pages;
57  size_type capacity;
58  size_type size;
59  bool not_free;
60  };
61 
62  typedef MallocAllocator<AllocationInfo> Alloc;
63  typedef std::vector<AllocationInfo, Alloc> AllocationList;
64  AllocationList allocation_list;
65 
66  private:
67  void memprotect(void* from, difference_type len, int prot)
68  {
69 #if HAVE_SYS_MMAN_H && HAVE_MPROTECT
70  int result = mprotect(from, len, prot);
71  if (result == -1)
72  {
73 
74  std::cerr << "ERROR: (" << result << ": " << strerror(result) << ")" << std::endl;
75  std::cerr << " Failed to ";
76  if (prot == PROT_NONE)
77  std::cerr << "protect ";
78  else
79  std::cerr << "unprotect ";
80  std::cerr << "memory range: "
81  << from << ", "
82  << static_cast<void*>(
83  static_cast<char*>(from) + len)
84  << std::endl;
85  abort();
86  }
87 #else
91  std::cerr << "WARNING: memory protection not available" << std::endl;
92 #endif
93  }
94 
95  public:
96 
97  ~AllocationManager ()
98  {
99  AllocationList::iterator it;
100  bool error = false;
101  for (it=allocation_list.begin(); it!=allocation_list.end(); it++)
102  {
103  if (it->not_free)
104  {
105  std::cerr << "ERROR: found memory chunk still in use: " <<
106  it->capacity << " bytes at " << it->ptr << std::endl;
107  error = true;
108  }
109  munmap(it->page_ptr, it->pages * page_size);
110  }
111  if (error)
112  allocation_error("lost allocations");
113  }
114 
115  template<typename T>
116  T* allocate(size_type n) throw(std::bad_alloc)
117  {
118  // setup chunk info
119  AllocationInfo ai(typeid(T));
120  ai.size = n;
121  ai.capacity = n * sizeof(T);
122  ai.pages = (ai.capacity) / page_size + 2;
123  ai.not_free = true;
124  size_type overlap = ai.capacity % page_size;
125  ai.page_ptr = mmap(NULL, ai.pages * page_size,
126  PROT_READ | PROT_WRITE,
127 #ifdef __APPLE__
128  MAP_ANON | MAP_PRIVATE,
129 #else
130  MAP_ANONYMOUS | MAP_PRIVATE,
131 #endif
132  -1, 0);
133  if (MAP_FAILED == ai.page_ptr)
134  {
135  throw std::bad_alloc();
136  }
137  ai.ptr = static_cast<char*>(ai.page_ptr) + page_size - overlap;
138  // write protect memory behind the actual data
139  memprotect(static_cast<char*>(ai.page_ptr) + (ai.pages-1) * page_size,
140  page_size,
141  PROT_NONE);
142  // remember the chunk
143  allocation_list.push_back(ai);
144  // return the ptr
145  return static_cast<T*>(ai.ptr);
146  }
147 
148  template<typename T>
149  void deallocate(T* ptr, size_type n = 0) throw()
150  {
151  // compute page address
152  void* page_ptr =
153  static_cast<void*>(
154  (char*)(ptr) - ((std::uintptr_t)(ptr) % page_size));
155  // search list
156  AllocationList::iterator it;
157  unsigned int i = 0;
158  for (it=allocation_list.begin(); it!=allocation_list.end(); it++, i++)
159  {
160  if (it->page_ptr == page_ptr)
161  {
162  // std::cout << "found memory_block in allocation " << i << std::endl;
163  // sanity checks
164  if (n != 0)
165  ALLOCATION_ASSERT(n == it->size);
166  ALLOCATION_ASSERT(ptr == it->ptr);
167  ALLOCATION_ASSERT(true == it->not_free);
168  ALLOCATION_ASSERT(typeid(T) == *(it->type));
169  // free memory
170  it->not_free = false;
171 #if DEBUG_ALLOCATOR_KEEP
172  // write protect old memory
173  memprotect(it->page_ptr,
174  (it->pages) * page_size,
175  PROT_NONE);
176 #else
177  // unprotect old memory
178  memprotect(it->page_ptr,
179  (it->pages) * page_size,
180  PROT_READ | PROT_WRITE);
181  munmap(it->page_ptr, it->pages * page_size);
182  // remove chunk info
183  allocation_list.erase(it);
184 #endif
185  return;
186  }
187  }
188  allocation_error("memory block not found");
189  }
190  };
191 #undef ALLOCATION_ASSERT
192 
193  extern AllocationManager alloc_man;
194  } // end namespace DebugMemory
195 #endif // DOXYGEN
196 
197  template<class T>
198  class DebugAllocator;
199 
200  // specialize for void
201  template <>
202  class DebugAllocator<void> {
203  public:
204  typedef void* pointer;
205  typedef const void* const_pointer;
206  // reference to void members are impossible.
207  typedef void value_type;
208  template <class U> struct rebind {
209  typedef DebugAllocator<U> other;
210  };
211  };
212 
213  // actual implementation
232  template <class T>
234  public:
235  typedef std::size_t size_type;
236  typedef std::ptrdiff_t difference_type;
237  typedef T* pointer;
238  typedef const T* const_pointer;
239  typedef T& reference;
240  typedef const T& const_reference;
241  typedef T value_type;
242  template <class U> struct rebind {
243  typedef DebugAllocator<U> other;
244  };
245 
247  DebugAllocator() throw() {}
249  template <class U>
252  ~DebugAllocator() throw() {}
253 
254  pointer address(reference x) const
255  {
256  return &x;
257  }
258  const_pointer address(const_reference x) const
259  {
260  return &x;
261  }
262 
264  pointer allocate(size_type n,
265  DebugAllocator<void>::const_pointer hint = 0)
266  {
267  DUNE_UNUSED_PARAMETER(hint);
268  return DebugMemory::alloc_man.allocate<T>(n);
269  }
270 
272  void deallocate(pointer p, size_type n)
273  {
274  DebugMemory::alloc_man.deallocate<T>(p,n);
275  }
276 
278  size_type max_size() const throw()
279  {
280  return size_type(-1) / sizeof(T);
281  }
282 
284  void construct(pointer p, const T& val)
285  {
286  ::new((void*)p)T(val);
287  }
288 
290  template<typename ... _Args>
291  void construct(pointer p, _Args&&... __args)
292  {
293  ::new((void *)p)T(std::forward<_Args>(__args) ...);
294  }
295 
297  void destroy(pointer p)
298  {
299  p->~T();
300  }
301  };
302 }
303 
304 #ifdef DEBUG_NEW_DELETE
305 void * operator new(size_t size) throw(std::bad_alloc)
306 {
307  // try to allocate size bytes
308  void *p = Dune::DebugMemory::alloc_man.allocate<char>(size);
309 #if DEBUG_NEW_DELETE > 2
310  std::cout << "NEW " << size
311  << " -> " << p
312  << std::endl;
313 #endif
314  return p;
315 }
316 
317 void operator delete(void * p) throw()
318 {
319 #if DEBUG_NEW_DELETE > 2
320  std::cout << "FREE " << p << std::endl;
321 #endif
322  Dune::DebugMemory::alloc_man.deallocate<char>(static_cast<char*>(p));
323 }
324 
325 #endif // DEBUG_NEW_DELETE
326 
327 #endif // DUNE_DEBUG_ALLOCATOR_HH
Allocators implementation which performs different kind of memory checks.
Definition: debugallocator.hh:233
void destroy(pointer p)
destroy an object of type T (i.e. call the destructor)
Definition: debugallocator.hh:297
~DebugAllocator()
cleanup this allocator
Definition: debugallocator.hh:252
size_type max_size() const
max size for allocate
Definition: debugallocator.hh:278
void deallocate(pointer p, size_type n)
deallocate n objects of type T at address p
Definition: debugallocator.hh:272
DebugAllocator(const DebugAllocator< U > &)
copy construct from an other DebugAllocator, possibly for a different result type
Definition: debugallocator.hh:250
void construct(pointer p, _Args &&... __args)
construct an object of type T from variadic parameters
Definition: debugallocator.hh:291
void construct(pointer p, const T &val)
copy-construct an object of type T (i.e. make a placement new on p)
Definition: debugallocator.hh:284
DebugAllocator()
create a new DebugAllocator
Definition: debugallocator.hh:247
pointer allocate(size_type n, DebugAllocator< void >::const_pointer hint=0)
allocate n objects of type T
Definition: debugallocator.hh:264
Allocators that use malloc/free.
Dune namespace.
Definition: alignment.hh:10
Definition of the DUNE_UNUSED macro for the case that config.h is not available.
#define DUNE_UNUSED_PARAMETER(parm)
A macro to mark intentional unused function parameters with.
Definition: unused.hh:18
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.80.0 (May 14, 22:30, 2024)