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