Dune Core Modules (2.8.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
6#if __has_include(<sys/mman.h>)
7
8#include <sys/mman.h>
9#define HAVE_SYS_MMAN_H 1
10#define HAVE_MPROTECT 1
11
12#include <exception>
13#include <typeinfo>
14#include <vector>
15#include <iostream>
16#include <cstring>
17#include <cstdint>
18#include <cstdlib>
19#include <new>
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([[maybe_unused]] void* from,
68 [[maybe_unused]] difference_type len,
69 [[maybe_unused]] int prot)
70 {
71#if HAVE_SYS_MMAN_H && HAVE_MPROTECT
72 int result = mprotect(from, len, prot);
73 if (result == -1)
74 {
75
76 std::cerr << "ERROR: (" << result << ": " << strerror(result) << ")" << std::endl;
77 std::cerr << " Failed to ";
78 if (prot == PROT_NONE)
79 std::cerr << "protect ";
80 else
81 std::cerr << "unprotect ";
82 std::cerr << "memory range: "
83 << from << ", "
84 << static_cast<void*>(
85 static_cast<char*>(from) + len)
86 << std::endl;
87 abort();
88 }
89#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 munmap(it->page_ptr, it->pages * page_size);
109 }
110 if (error)
111 allocation_error("lost allocations");
112 }
113
114 template<typename T>
115 T* allocate(size_type n)
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 ai.page_ptr = mmap(NULL, ai.pages * page_size,
125 PROT_READ | PROT_WRITE,
126#ifdef __APPLE__
127 MAP_ANON | MAP_PRIVATE,
128#else
129 MAP_ANONYMOUS | MAP_PRIVATE,
130#endif
131 -1, 0);
132 if (MAP_FAILED == ai.page_ptr)
133 {
134 throw std::bad_alloc();
135 }
136 ai.ptr = static_cast<char*>(ai.page_ptr) + page_size - overlap;
137 // write protect memory behind the actual data
138 memprotect(static_cast<char*>(ai.page_ptr) + (ai.pages-1) * page_size,
139 page_size,
140 PROT_NONE);
141 // remember the chunk
142 allocation_list.push_back(ai);
143 // return the ptr
144 return static_cast<T*>(ai.ptr);
145 }
146
147 template<typename T>
148 void deallocate(T* ptr, size_type n = 0) noexcept
149 {
150 // compute page address
151 void* page_ptr =
152 static_cast<void*>(
153 (char*)(ptr) - ((std::uintptr_t)(ptr) % page_size));
154 // search list
155 AllocationList::iterator it;
156 unsigned int i = 0;
157 for (it=allocation_list.begin(); it!=allocation_list.end(); it++, i++)
158 {
159 if (it->page_ptr == page_ptr)
160 {
161 // std::cout << "found memory_block in allocation " << i << std::endl;
162 // sanity checks
163 if (n != 0)
164 ALLOCATION_ASSERT(n == it->size);
165 ALLOCATION_ASSERT(ptr == it->ptr);
166 ALLOCATION_ASSERT(true == it->not_free);
167 ALLOCATION_ASSERT(typeid(T) == *(it->type));
168 // free memory
169 it->not_free = false;
170#if DEBUG_ALLOCATOR_KEEP
171 // write protect old memory
172 memprotect(it->page_ptr,
173 (it->pages) * page_size,
174 PROT_NONE);
175#else
176 // unprotect old memory
177 memprotect(it->page_ptr,
178 (it->pages) * page_size,
179 PROT_READ | PROT_WRITE);
180 munmap(it->page_ptr, it->pages * page_size);
181 // remove chunk info
182 allocation_list.erase(it);
183#endif
184 return;
185 }
186 }
187 allocation_error("memory block not found");
188 }
189 };
190#undef ALLOCATION_ASSERT
191
192 extern AllocationManager alloc_man;
193 } // end namespace DebugMemory
194#endif // DOXYGEN
195
196 template<class T>
197 class DebugAllocator;
198
199 // specialize for void
200 template <>
201 class DebugAllocator<void> {
202 public:
203 typedef void* pointer;
204 typedef const void* const_pointer;
205 // reference to void members are impossible.
206 typedef void value_type;
207 template <class U> struct rebind {
208 typedef DebugAllocator<U> other;
209 };
210 };
211
212 // actual implementation
231 template <class T>
232 class DebugAllocator {
233 public:
234 typedef std::size_t size_type;
235 typedef std::ptrdiff_t difference_type;
236 typedef T* pointer;
237 typedef const T* const_pointer;
238 typedef T& reference;
239 typedef const T& const_reference;
240 typedef T value_type;
241 template <class U> struct rebind {
242 typedef DebugAllocator<U> other;
243 };
244
246 DebugAllocator() noexcept {}
248 template <class U>
249 DebugAllocator(const DebugAllocator<U>&) noexcept {}
251 ~DebugAllocator() noexcept {}
252
253 pointer address(reference x) const
254 {
255 return &x;
256 }
257 const_pointer address(const_reference x) const
258 {
259 return &x;
260 }
261
263 pointer allocate(size_type n,
264 [[maybe_unused]] DebugAllocator<void>::const_pointer hint = 0)
265 {
266 return DebugMemory::alloc_man.allocate<T>(n);
267 }
268
270 void deallocate(pointer p, size_type n)
271 {
272 DebugMemory::alloc_man.deallocate<T>(p,n);
273 }
274
276 size_type max_size() const noexcept
277 {
278 return size_type(-1) / sizeof(T);
279 }
280
282 void construct(pointer p, const T& val)
283 {
284 ::new((void*)p)T(val);
285 }
286
288 template<typename ... Args>
289 void construct(pointer p, Args&&... args)
290 {
291 ::new((void *)p)T(std::forward<Args>(args) ...);
292 }
293
295 void destroy(pointer p)
296 {
297 p->~T();
298 }
299 };
300
302 template<class T>
303 constexpr bool
304 operator==(const DebugAllocator<T> &, const DebugAllocator<T> &)
305 {
306 return true;
307 }
308
310 template<class T>
311 constexpr bool
312 operator!=(const DebugAllocator<T> &, const DebugAllocator<T> &)
313 {
314 return false;
315 }
316}
317
318#ifdef DEBUG_NEW_DELETE
319void * operator new(size_t size)
320{
321 // try to allocate size bytes
322 void *p = Dune::DebugMemory::alloc_man.allocate<char>(size);
323#if DEBUG_NEW_DELETE > 2
324 std::cout << "NEW " << size
325 << " -> " << p
326 << std::endl;
327#endif
328 return p;
329}
330
331void operator delete(void * p) noexcept
332{
333#if DEBUG_NEW_DELETE > 2
334 std::cout << "FREE " << p << std::endl;
335#endif
336 Dune::DebugMemory::alloc_man.deallocate<char>(static_cast<char*>(p));
337}
338
339void operator delete(void * p, size_t size) noexcept
340{
341#if DEBUG_NEW_DELETE > 2
342 std::cout << "FREE " << p << std::endl;
343#endif
344 Dune::DebugMemory::alloc_man.deallocate<char>(static_cast<char*>(p), size);
345}
346
347#endif // DEBUG_NEW_DELETE
348
349#endif // __has_include(<sys/mman.h>)
350
351#endif // DUNE_DEBUG_ALLOCATOR_HH
EnableIfInterOperable< T1, T2, bool >::type operator==(const ForwardIteratorFacade< T1, V1, R1, D > &lhs, const ForwardIteratorFacade< T2, V2, R2, D > &rhs)
Checks for equality.
Definition: iteratorfacades.hh:235
EnableIfInterOperable< T1, T2, bool >::type operator!=(const ForwardIteratorFacade< T1, V1, R1, D > &lhs, const ForwardIteratorFacade< T2, V2, R2, D > &rhs)
Checks for inequality.
Definition: iteratorfacades.hh:257
Allocators that use malloc/free.
Dune namespace.
Definition: alignedallocator.hh:11
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Dec 22, 23:30, 2024)