3#ifndef DUNE_DEBUG_ALLOCATOR_HH
4#define DUNE_DEBUG_ALLOCATOR_HH
15#if HAVE_SYS_MMAN_H && HAVE_MPROTECT
18enum DummyProtFlags { PROT_NONE, PROT_WRITE, PROT_READ };
24#error mprotect is required to use the DebugAllocator
34 extern const std::ptrdiff_t page_size;
36 struct AllocationManager
38 typedef std::size_t size_type;
39 typedef std::ptrdiff_t difference_type;
40 typedef void* pointer;
43 static void allocation_error(
const char* msg);
45 struct AllocationInfo;
46 friend struct AllocationInfo;
48#define ALLOCATION_ASSERT(A) { if (!(A)) \
49 { allocation_error("Assertion " # A " failed");\
55 AllocationInfo(
const std::type_info & t) : type(&t) {}
56 const std::type_info * type;
66 typedef MallocAllocator<AllocationInfo> Alloc;
67 typedef std::vector<AllocationInfo, Alloc> AllocationList;
68 AllocationList allocation_list;
71 void memprotect(
void* from, difference_type len,
int prot)
73#if HAVE_SYS_MMAN_H && HAVE_MPROTECT
74 int result = mprotect(from, len, prot);
78 std::cerr <<
"ERROR: (" << result <<
": " << strerror(result) <<
")" << std::endl;
79 std::cerr <<
" Failed to ";
80 if (prot == PROT_NONE)
81 std::cerr <<
"protect ";
83 std::cerr <<
"unprotect ";
84 std::cerr <<
"memory range: "
86 <<
static_cast<void*
>(
87 static_cast<char*
>(from) + len)
95 std::cerr <<
"WARNING: memory protection not available" << std::endl;
101 ~AllocationManager ()
103 AllocationList::iterator it;
105 for (it=allocation_list.begin(); it!=allocation_list.end(); it++)
109 std::cerr <<
"ERROR: found memory chunk still in use: " <<
110 it->capacity <<
" bytes at " << it->ptr << std::endl;
113 munmap(it->page_ptr, it->pages * page_size);
116 allocation_error(
"lost allocations");
120 T* allocate(size_type n)
123 AllocationInfo ai(
typeid(T));
125 ai.capacity = n *
sizeof(T);
126 ai.pages = (ai.capacity) / page_size + 2;
128 size_type overlap = ai.capacity % page_size;
129 ai.page_ptr = mmap(NULL, ai.pages * page_size,
130 PROT_READ | PROT_WRITE,
132 MAP_ANON | MAP_PRIVATE,
134 MAP_ANONYMOUS | MAP_PRIVATE,
137 if (MAP_FAILED == ai.page_ptr)
139 throw std::bad_alloc();
141 ai.ptr =
static_cast<char*
>(ai.page_ptr) + page_size - overlap;
143 memprotect(
static_cast<char*
>(ai.page_ptr) + (ai.pages-1) * page_size,
147 allocation_list.push_back(ai);
149 return static_cast<T*
>(ai.ptr);
153 void deallocate(T* ptr, size_type n = 0) noexcept
158 (
char*)(ptr) - ((std::uintptr_t)(ptr) % page_size));
160 AllocationList::iterator it;
162 for (it=allocation_list.begin(); it!=allocation_list.end(); it++, i++)
164 if (it->page_ptr == page_ptr)
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));
174 it->not_free =
false;
175#if DEBUG_ALLOCATOR_KEEP
177 memprotect(it->page_ptr,
178 (it->pages) * page_size,
182 memprotect(it->page_ptr,
183 (it->pages) * page_size,
184 PROT_READ | PROT_WRITE);
185 munmap(it->page_ptr, it->pages * page_size);
187 allocation_list.erase(it);
192 allocation_error(
"memory block not found");
195#undef ALLOCATION_ASSERT
197 extern AllocationManager alloc_man;
202 class DebugAllocator;
206 class DebugAllocator<void> {
208 typedef void* pointer;
209 typedef const void* const_pointer;
211 typedef void value_type;
212 template <
class U>
struct rebind {
213 typedef DebugAllocator<U> other;
237 class DebugAllocator {
239 typedef std::size_t size_type;
240 typedef std::ptrdiff_t difference_type;
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;
251 DebugAllocator() noexcept {}
254 DebugAllocator(
const DebugAllocator<U>&)
noexcept {}
256 ~DebugAllocator() noexcept {}
258 pointer address(reference x)
const
262 const_pointer address(const_reference x)
const
268 pointer allocate(size_type n,
269 DebugAllocator<void>::const_pointer hint = 0)
272 return DebugMemory::alloc_man.allocate<T>(n);
276 void deallocate(pointer p, size_type n)
278 DebugMemory::alloc_man.deallocate<T>(p,n);
282 size_type max_size() const noexcept
284 return size_type(-1) /
sizeof(T);
288 void construct(pointer p,
const T& val)
290 ::new((
void*)p)T(val);
294 template<
typename ... Args>
295 void construct(pointer p, Args&&... args)
297 ::new((
void *)p)T(std::forward<Args>(args) ...);
301 void destroy(pointer p)
310 operator==(
const DebugAllocator<T> &,
const DebugAllocator<T> &)
318 operator!=(
const DebugAllocator<T> &,
const DebugAllocator<T> &)
324#ifdef DEBUG_NEW_DELETE
325void *
operator new(
size_t size)
328 void *p = Dune::DebugMemory::alloc_man.allocate<
char>(size);
329#if DEBUG_NEW_DELETE > 2
330 std::cout <<
"NEW " << size
337void operator delete(
void * p)
noexcept
339#if DEBUG_NEW_DELETE > 2
340 std::cout <<
"FREE " << p << std::endl;
342 Dune::DebugMemory::alloc_man.deallocate<
char>(
static_cast<char*
>(p));
345void operator delete(
void * p,
size_t size)
noexcept
347#if DEBUG_NEW_DELETE > 2
348 std::cout <<
"FREE " << p << std::endl;
350 Dune::DebugMemory::alloc_man.deallocate<
char>(
static_cast<char*
>(p), size);
#define DUNE_UNUSED_PARAMETER(parm)
A macro to mark intentionally unused function parameters with.
Definition: unused.hh:25
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:14
Definition of the DUNE_UNUSED macro for the case that config.h is not available.