Dune Core Modules (2.3.1)

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