Dune Core Modules (2.5.0)

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 <cstdint>
13#include <cstdlib>
14#include <new>
15#if HAVE_SYS_MMAN_H && HAVE_MPROTECT
16#include <sys/mman.h>
17#else
18enum DummyProtFlags { PROT_NONE, PROT_WRITE, PROT_READ };
19#endif
20
21#include "mallocallocator.hh"
22
23namespace 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 {
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
305void * operator new(size_t size)
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
317void 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:11
Definition of the DUNE_UNUSED macro for the case that config.h is not available.
#define DUNE_UNUSED_PARAMETER(parm)
A macro to mark intentionally unused function parameters with.
Definition: unused.hh:18
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Nov 23, 23:29, 2024)