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