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)29static 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)47void alloc_setlimit(long long l) { 48 limit = l; 49 } 50 alloc_getallocated(void)51long long alloc_getallocated(void) { 52 return allocated; 53 } 54 alloc_getspace(void)55long 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)64static 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)84static 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)98void *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)129void 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)147void 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