1 /*
2 This file is part of tgl-library
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
18 Copyright Vitaly Valtman 2013-2015
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #define _GNU_SOURCE
26
27 #include <assert.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include "crypto/rand.h"
32 #include <zlib.h>
33 #include <time.h>
34 #include <sys/time.h>
35
36 //#include "interface.h"
37 #include "tools.h"
38
39 #ifdef __MACH__
40 #include <mach/clock.h>
41 #include <mach/mach.h>
42 #endif
43
44 #ifndef CLOCK_REALTIME
45 #define CLOCK_REALTIME 0
46 #define CLOCK_MONOTONIC 1
47 #endif
48
49 #ifdef WIN32
50 #include <winsock2.h>
51 #include <windows.h>
vasprintf(char ** __restrict__ ret,const char * __restrict__ format,va_list ap)52 int vasprintf(char ** __restrict__ ret,
53 const char * __restrict__ format,
54 va_list ap) {
55 int len;
56 /* Get Length */
57 len = _vsnprintf(NULL,0,format,ap);
58 if (len < 0) return -1;
59 /* +1 for \0 terminator. */
60 *ret = malloc(len + 1);
61 /* Check malloc fail*/
62 if (!*ret) return -1;
63 /* Write String */
64 _vsnprintf(*ret,len+1,format,ap);
65 /* Terminate explicitly */
66 (*ret)[len] = '\0';
67 return len;
68 }
69
clock_gettime(int ignored,struct timespec * spec)70 int clock_gettime(int ignored, struct timespec *spec)
71 {
72 __int64 wintime;
73 GetSystemTimeAsFileTime((FILETIME*)&wintime);
74 wintime -= 116444736000000000; //1jan1601 to 1jan1970
75 spec->tv_sec = wintime / 10000000; //seconds
76 spec->tv_nsec = wintime % 10000000 *100; //nano-seconds
77 return 0;
78 }
79 #endif
80
81 #ifdef VALGRIND_FIXES
82 #include "valgrind/memcheck.h"
83 #endif
84
85 #define RES_PRE 8
86 #define RES_AFTER 8
87 #define MAX_BLOCKS 1000000
88 static void *blocks[MAX_BLOCKS];
89 static void *free_blocks[MAX_BLOCKS];
90 static int used_blocks;
91 static int free_blocks_cnt;
92
93 static long long total_allocated_bytes;
94
95 void logprintf (const char *format, ...) __attribute__ ((format (printf, 1, 2), weak));
logprintf(const char * format,...)96 void logprintf (const char *format, ...) {
97 va_list ap;
98 va_start (ap, format);
99 vfprintf (stdout, format, ap);
100 va_end (ap);
101 }
102
103 //extern int verbosity;
104
105 //static long long total_allocated_bytes;
106
tgl_snprintf(char * buf,int len,const char * format,...)107 int tgl_snprintf (char *buf, int len, const char *format, ...) {
108 va_list ap;
109 va_start (ap, format);
110 int r = vsnprintf (buf, len, format, ap);
111 va_end (ap);
112 assert (r <= len && "tsnprintf buffer overflow");
113 return r;
114 }
115
tgl_asprintf(char ** res,const char * format,...)116 int tgl_asprintf (char **res, const char *format, ...) {
117 va_list ap;
118 va_start (ap, format);
119 int r = vasprintf (res, format, ap);
120 assert (r >= 0);
121 va_end (ap);
122 void *rs = talloc (strlen (*res) + 1);
123 memcpy (rs, *res, strlen (*res) + 1);
124 free (*res);
125 *res = rs;
126 return r;
127 }
128
tgl_free_debug(void * ptr,int size)129 void tgl_free_debug (void *ptr, int size __attribute__ ((unused))) {
130 if (!ptr) {
131 assert (!size);
132 return;
133 }
134 total_allocated_bytes -= size;
135 ptr -= RES_PRE;
136 if (size != (int)((*(int *)ptr) ^ 0xbedabeda)) {
137 logprintf ("size = %d, ptr = %d\n", size, (*(int *)ptr) ^ 0xbedabeda);
138 }
139 assert (*(int *)ptr == (int)((size) ^ 0xbedabeda));
140 assert (*(int *)(ptr + RES_PRE + size) == (int)((size) ^ 0x7bed7bed));
141 assert (*(int *)(ptr + 4) == size);
142 int block_num = *(int *)(ptr + 4 + RES_PRE + size);
143 if (block_num >= used_blocks) {
144 logprintf ("block_num = %d, used = %d\n", block_num, used_blocks);
145 }
146 assert (block_num < used_blocks);
147 if (block_num < used_blocks - 1) {
148 void *p = blocks[used_blocks - 1];
149 int s = (*(int *)p) ^ 0xbedabeda;
150 *(int *)(p + 4 + RES_PRE + s) = block_num;
151 blocks[block_num] = p;
152 }
153 blocks[--used_blocks] = 0;
154 memset (ptr, 0, size + RES_PRE + RES_AFTER);
155 *(int *)ptr = size + 12;
156 free_blocks[free_blocks_cnt ++] = ptr;
157 }
158
tgl_free_release(void * ptr,int size)159 void tgl_free_release (void *ptr, int size) {
160 total_allocated_bytes -= size;
161 memset (ptr, 0, size);
162 free (ptr);
163 }
164
165
166
tgl_realloc_debug(void * ptr,size_t old_size,size_t size)167 void *tgl_realloc_debug (void *ptr, size_t old_size __attribute__ ((unused)), size_t size) {
168 void *p = talloc (size);
169 memcpy (p, ptr, size >= old_size ? old_size : size);
170 if (ptr) {
171 tfree (ptr, old_size);
172 } else {
173 assert (!old_size);
174 }
175 return p;
176 }
177
tgl_realloc_release(void * ptr,size_t old_size,size_t size)178 void *tgl_realloc_release (void *ptr, size_t old_size __attribute__ ((unused)), size_t size) {
179 total_allocated_bytes += (size - old_size);
180 void *p = realloc (ptr, size);
181 ensure_ptr (p);
182 return p;
183 }
184
tgl_alloc_debug(size_t size)185 void *tgl_alloc_debug (size_t size) {
186 total_allocated_bytes += size;
187 void *p = malloc (size + RES_PRE + RES_AFTER);
188 ensure_ptr (p);
189 *(int *)p = size ^ 0xbedabeda;
190 *(int *)(p + 4) = size;
191 *(int *)(p + RES_PRE + size) = size ^ 0x7bed7bed;
192 *(int *)(p + RES_AFTER + 4 + size) = used_blocks;
193 blocks[used_blocks ++] = p;
194
195 //tcheck ();
196 return p + 8;
197 }
198
tgl_alloc_release(size_t size)199 void *tgl_alloc_release (size_t size) {
200 total_allocated_bytes += size;
201 void *p = malloc (size);
202 ensure_ptr (p);
203 return p;
204 }
205
tgl_alloc0(size_t size)206 void *tgl_alloc0 (size_t size) {
207 void *p = talloc (size);
208 memset (p, 0, size);
209 return p;
210 }
211
tgl_strdup(const char * s)212 char *tgl_strdup (const char *s) {
213 int l = strlen (s);
214 char *p = talloc (l + 1);
215 memcpy (p, s, l + 1);
216 return p;
217 }
218
tgl_strndup(const char * s,size_t n)219 char *tgl_strndup (const char *s, size_t n) {
220 size_t l = 0;
221 for (l = 0; l < n && s[l]; l++) { }
222 char *p = talloc (l + 1);
223 memcpy (p, s, l);
224 p[l] = 0;
225 return p;
226 }
227
tgl_memdup(const void * s,size_t n)228 void *tgl_memdup (const void *s, size_t n) {
229 void *r = talloc (n);
230 memcpy (r, s, n);
231 return r;
232 }
233
234
tgl_inflate(void * input,int ilen,void * output,int olen)235 int tgl_inflate (void *input, int ilen, void *output, int olen) {
236 z_stream strm;
237 memset (&strm, 0, sizeof (strm));
238 assert (inflateInit2 (&strm, 16 + MAX_WBITS) == Z_OK);
239 strm.avail_in = ilen;
240 strm.next_in = input;
241 strm.avail_out = olen ;
242 strm.next_out = output;
243 int err = inflate (&strm, Z_FINISH);
244 int total_out = strm.total_out;
245
246 if (err != Z_OK && err != Z_STREAM_END) {
247 logprintf ( "inflate error = %d\n", err);
248 logprintf ( "inflated %d bytes\n", (int) strm.total_out);
249 total_out = 0;
250 }
251 inflateEnd (&strm);
252 return total_out;
253 }
254
tgl_check_debug(void)255 void tgl_check_debug (void) {
256 int i;
257 for (i = 0; i < used_blocks; i++) {
258 void *ptr = blocks[i];
259 int size = (*(int *)ptr) ^ 0xbedabeda;
260 if (!(*(int *)(ptr + 4) == size) ||
261 !(*(int *)(ptr + RES_PRE + size) == (size ^ 0x7bed7bed)) ||
262 !(*(int *)(ptr + RES_PRE + 4 + size) == i)) {
263 logprintf ("Bad block at address %p (size %d, num %d)\n", ptr, size, i);
264 assert (0 && "Bad block");
265 }
266 }
267 for (i = 0; i < free_blocks_cnt; i++) {
268 void *ptr = free_blocks[i];
269 int l = *(int *)ptr;
270 int j = 0;
271 for (j = 0; j < l; j++) {
272 if (*(char *)(ptr + 4 + j)) {
273 hexdump (ptr + 8, ptr + 8 + l + ((-l) & 3));
274 logprintf ("Used freed memory size = %d. ptr = %p\n", l + 4 - RES_PRE - RES_AFTER, ptr);
275 assert (0);
276 }
277 }
278 }
279 //logprintf ("ok. Used_blocks = %d. Free blocks = %d\n", used_blocks, free_blocks_cnt);
280 }
281
tgl_exists_debug(void * ptr,int size)282 void tgl_exists_debug (void *ptr, int size) {
283 ptr -= RES_PRE;
284 if (size != (int)((*(int *)ptr) ^ 0xbedabeda)) {
285 logprintf ("size = %d, ptr = %d\n", size, (*(int *)ptr) ^ 0xbedabeda);
286 }
287 assert (*(int *)ptr == (int)((size) ^ 0xbedabeda));
288 assert (*(int *)(ptr + RES_PRE + size) == (int)((size) ^ 0x7bed7bed));
289 assert (*(int *)(ptr + 4) == size);
290 int block_num = *(int *)(ptr + 4 + RES_PRE + size);
291 if (block_num >= used_blocks) {
292 logprintf ("block_num = %d, used = %d\n", block_num, used_blocks);
293 }
294 assert (block_num < used_blocks);
295 }
296
tgl_exists_release(void * ptr,int size)297 void tgl_exists_release (void *ptr, int size) {}
tgl_check_release(void)298 void tgl_check_release (void) {}
299
tgl_my_clock_gettime(int clock_id,struct timespec * T)300 void tgl_my_clock_gettime (int clock_id, struct timespec *T) {
301 #ifdef __MACH__
302 // We are ignoring MONOTONIC and hope time doesn't go back too often
303 clock_serv_t cclock;
304 mach_timespec_t mts;
305 host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
306 clock_get_time(cclock, &mts);
307 mach_port_deallocate(mach_task_self(), cclock);
308 T->tv_sec = mts.tv_sec;
309 T->tv_nsec = mts.tv_nsec;
310 #else
311 assert (clock_gettime(clock_id, T) >= 0);
312 #endif
313 }
314
tglt_get_double_time(void)315 double tglt_get_double_time (void) {
316 struct timespec tv;
317 tgl_my_clock_gettime (CLOCK_REALTIME, &tv);
318 return tv.tv_sec + 1e-9 * tv.tv_nsec;
319 }
320
tglt_secure_random(void * s,int l)321 void tglt_secure_random (void *s, int l) {
322 if (TGLC_rand_bytes (s, l) <= 0) {
323 /*if (allow_weak_random) {
324 TGLC_rand_pseudo_bytes (s, l);
325 } else {*/
326 assert (0 && "End of random. If you want, you can start with -w");
327 //}
328 } else {
329 #ifdef VALGRIND_FIXES
330 VALGRIND_MAKE_MEM_DEFINED (s, l);
331 VALGRIND_CHECK_MEM_IS_DEFINED (s, l);
332 #endif
333 }
334 }
335
336 struct tgl_allocator tgl_allocator_debug = {
337 .alloc = tgl_alloc_debug,
338 .realloc = tgl_realloc_debug,
339 .free = tgl_free_debug,
340 .check = tgl_check_debug,
341 .exists = tgl_exists_debug
342 };
343
344 struct tgl_allocator tgl_allocator_release = {
345 .alloc = tgl_alloc_release,
346 .realloc = tgl_realloc_release,
347 .free = tgl_free_release,
348 .check = tgl_check_release,
349 .exists = tgl_exists_release
350 };
351
tgl_get_allocated_bytes(void)352 long long tgl_get_allocated_bytes (void) {
353 return total_allocated_bytes;
354 }
355 struct tgl_allocator *tgl_allocator = &tgl_allocator_release;
356