1 #ifndef CADO_UTILS_ELECTRIC_ALLOC_H_
2 #define CADO_UTILS_ELECTRIC_ALLOC_H_
3
4 /* This file is a debugging aid. It carries good chances of working on
5 * POSIX system, but I wouldn't bet much on it, since mmap is kind of
6 * strongly tied to the OS.
7 *
8 * To use, simply include this .h file, and use electric_alloc and
9 * electric_free for for allocation/free routines.
10 *
11 * The vanilla electric_free needs the size of the allocated area. If
12 * this is an inconvenient, try the _nosize versions below. Never tested.
13 */
14
15 /* By default we protect overruns. Undefine this macro to protect
16 * underruns instead */
17 #define PROTECT_OVERRUN
18
19 #include <fcntl.h>
20 #include <sys/mman.h>
21
22 #ifndef __APPLE__
23 #ifndef MAP_ANONYMOUS
24 #error "Please define _GNU_SOURCE or _BSD_SOURCE on top of the translation unit"
25 #endif
26 #endif
27
28 #ifdef __cplusplus
29 #include <new> /* for std::bad_alloc */
30 #include <stdlib.h>
31 #endif
32
33 static inline
electric_alloc(size_t s)34 void * electric_alloc(size_t s)
35 {
36 /* Use the method of the good old days from electric fence. */
37 char *p;
38 size_t r = 8192; /* Any multiple of the page size will do. */
39 unsigned int multip = (s+r-1)/r;
40 p = (char *)
41 #ifndef __APPLE__
42 mmap(0, (multip + 1) * r, PROT_READ | PROT_WRITE,
43 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
44 #else
45 mmap(0, (multip + 1) * r, PROT_READ | PROT_WRITE,
46 MAP_PRIVATE | MAP_ANON, -1, 0);
47 #endif
48 // could please valgrind ?
49 // memset(p, 0, (multip + 1) * r);
50 #ifdef PROTECT_OVERRUN
51 p += (multip + 1) * r;
52 mprotect((void*) (p-r), r, PROT_NONE);
53 p -= r+s;
54 #else
55 /* protect underrun */
56 mprotect(p, r, PROT_NONE);
57 p += r;
58 #endif
59 return (void *) p;
60 }
61
62 static inline
electric_free(void * p0,size_t s)63 void electric_free(void * p0, size_t s)
64 {
65 char * p = (char *) p0;
66 size_t r = 8192;
67 unsigned int multip = (s+r-1)/r;
68 #ifdef PROTECT_OVERRUN
69 p += s;
70 mprotect((void*) p, r, PROT_READ | PROT_WRITE);
71 p -= multip * r;
72 #else
73 p -= r;
74 mprotect(p, r, PROT_READ | PROT_WRITE);
75 #endif
76 munmap(p, (multip + 1) * r);
77 }
78
79 static inline
electric_alloc_nosize(size_t s)80 void * electric_alloc_nosize(size_t s)
81 {
82 void * ptr = electric_alloc(s + sizeof(s));
83 *(size_t *)ptr = s;
84 return (void *) (((size_t *) ptr) + 1);
85 }
86
87 static inline
electric_free_nosize(void * p0)88 void electric_free_nosize(void * p0)
89 {
90 p0 = (void*) (((size_t *)p0)-1);
91 size_t s = * (size_t *) p0;
92 electric_free(p0, s + sizeof(s));
93 }
94
95 #ifdef __cplusplus
electric_new(size_t s)96 template<typename T> inline T * electric_new(size_t s) {
97 T * res = (T*) electric_alloc(sizeof(T)*s);
98 if (!res)
99 throw std::bad_alloc();
100 return res;
101 }
electric_delete(T * p,size_t s)102 template<typename T> inline void electric_delete(T * p, size_t s) {
103 electric_free(p, sizeof(T)*s);
104 }
105 #endif
106
107 #endif /* CADO_UTILS_ELECTRIC_ALLOC_H_ */
108