1 /*
2 20130503
3 Jan Mojzis
4 Public domain.
5 */
6 
7 #include <stdlib.h>
8 #include <sys/time.h>
9 #include <sys/resource.h>
10 #include "e.h"
11 #include "uint64_pack.h"
12 #include "uint64_unpack.h"
13 #include "byte.h"
14 #include "purge.h"
15 #include "alloc.h"
16 
17 #define ALLOC_ALIGNMENT 16
18 #define ALLOC_SPACE 8192
19 #define ALLOC_LIMIT 4000000000LL
20 
21 typedef union { unsigned char irrelevant[ALLOC_ALIGNMENT]; double d; } aligned;
22 static aligned realspace[ALLOC_SPACE / ALLOC_ALIGNMENT];
23 #define space ((unsigned char *) realspace)
24 static long long avail = ALLOC_SPACE;
25 
26 static long long allocated = 0;
27 static long long limit     = -1;
28 
getlimit(void)29 static long long getlimit(void) {
30 
31     struct rlimit r;
32 
33     if (limit >= 0) return limit;
34 
35 #ifdef RLIMIT_DATA
36     if (getrlimit(RLIMIT_DATA, &r) == 0) {
37         if (r.rlim_cur > r.rlim_max)
38             r.rlim_cur = r.rlim_max;
39         limit = (long long)r.rlim_cur;
40     }
41 #endif
42     if (limit < 0 || limit > ALLOC_LIMIT) limit = ALLOC_LIMIT;
43     return limit;
44 }
45 
46 #ifdef TEST
alloc_setlimit(long long l)47 void alloc_setlimit(long long l) {
48     limit = l;
49 }
50 
alloc_getallocated(void)51 long long alloc_getallocated(void) {
52     return allocated;
53 }
54 
alloc_getspace(void)55 long long alloc_getspace(void) {
56     return ALLOC_SPACE;
57 }
58 #endif
59 
60 static void **ptr = 0;
61 static long long ptrlen = 0;
62 static long long ptralloc = 0;
63 
ptr_add(void * x)64 static int ptr_add(void *x) {
65 
66     void **newptr;
67 
68     if (ptrlen + 1 > ptralloc) {
69         while (ptrlen + 1 > ptralloc)
70             ptralloc = 2 * ptralloc + 1;
71         newptr = (void **)malloc(ptralloc * sizeof(void *));
72         if (!newptr) return 0;
73         if (ptr) {
74             byte_copy(newptr, ptrlen * sizeof(void *), ptr);
75             free(ptr);
76         }
77         ptr = newptr;
78     }
79     if (!x) return 1;
80     ptr[ptrlen++] = x;
81     return 1;
82 }
83 
ptr_remove(void * x)84 static int ptr_remove(void *x) {
85 
86     long long i;
87 
88     for (i = 0; i < ptrlen; ++i) {
89         if (ptr[i] == x) goto ok;
90     }
91     return 0;
92 ok:
93     --ptrlen;
94     ptr[i] = ptr[ptrlen];
95     return 1;
96 }
97 
alloc(long long nn)98 void *alloc(long long nn) {
99 
100     unsigned char *x;
101     crypto_uint64 n;
102 
103     if (nn < 0 || nn > ALLOC_LIMIT) goto nomem;
104     if (nn == 0) nn = 1;
105     n = nn;
106 
107     n = ALLOC_ALIGNMENT + n - (n & (ALLOC_ALIGNMENT - 1));
108     if (n <= avail) { avail -= n; return (void *)(space + avail); }
109 
110     n += ALLOC_ALIGNMENT;
111 
112     if (allocated + n > getlimit()) goto nomem;
113 
114     x = (unsigned char *)malloc(n);
115     if (!x) goto nomem;
116 
117     allocated += n;
118     byte_zero(x, n);
119     uint64_pack(x, n);
120     x += ALLOC_ALIGNMENT;
121     if (!ptr_add(x)) goto nomem;
122     return (void *)x;
123 
124 nomem:
125     errno = ENOMEM;
126     return (void *)0;
127 }
128 
alloc_free(void * xv)129 void alloc_free(void *xv) {
130 
131     crypto_uint64 n;
132     unsigned char *x = xv;
133 
134     if (x >= space)
135         if (x < space + ALLOC_SPACE)
136             return;
137 
138     if (!ptr_remove(x)) return;
139     x -= ALLOC_ALIGNMENT;
140     n = uint64_unpack(x);
141     allocated -= n;
142 
143     purge(x, n);
144     free(x);
145 }
146 
alloc_freeall(void)147 void alloc_freeall(void) {
148 
149     while (ptrlen > 0) {
150         alloc_free(ptr[0]);
151     }
152     if (ptr) { free(ptr); ptr = 0; ptrlen = 0; ptralloc = 0; }
153     purge(space, ALLOC_SPACE);
154 }
155