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