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
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
17enum DummyProtFlags { PROT_NONE, PROT_WRITE, PROT_READ };
18#endif
19
20#include "mallocallocator.hh"
21
22namespace 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 {
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
298void * 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
310void 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.111.3 (Jul 15, 22:36, 2024)