/* This file is part of tgl-library This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Copyright Vitaly Valtman 2013-2015 */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #define _GNU_SOURCE #include #include #include #include #include #include #include "..\..\..\..\libs\zlib\src\zlib.h" #include #if defined(WIN32) || defined(_WIN32) #include #include #include #include #include #else #include #endif // _WIN32 //#include "interface.h" #include "tools.h" #ifdef __MACH__ #include #include #endif #if defined(__MACH__) || defined(WIN32) || defined(_WIN32) #define CLOCK_REALTIME 0 #define CLOCK_MONOTONIC 1 #endif #ifdef VALGRIND_FIXES #include "valgrind/memcheck.h" #endif #define RES_PRE 8 #define RES_AFTER 8 #define MAX_BLOCKS 1000000 static void *blocks[MAX_BLOCKS]; static void *free_blocks[MAX_BLOCKS]; static int used_blocks; static int free_blocks_cnt; static long long total_allocated_bytes; #if defined(WIN32) || defined(_WIN32) #define exp7 10000000i64 //1E+7 //C-file part #define exp9 1000000000i64 //1E+9 #define w2ux 116444736000000000i64 //1.jan1601 to 1.jan1970 #define __need_clock_t #include int gettimeofday(struct timeval* t, void* timezone) { struct _timeb timebuffer; _ftime_s(&timebuffer); t->tv_sec = (long)timebuffer.time; t->tv_usec = 1000 * timebuffer.millitm; return 0; } struct tms { clock_t tms_utime; clock_t tms_stime; clock_t tms_cutime; clock_t tms_cstime; }; clock_t times(struct tms *__buffer) { __buffer->tms_utime = clock(); __buffer->tms_stime = 0; __buffer->tms_cstime = 0; __buffer->tms_cutime = 0; return __buffer->tms_utime; } typedef long long suseconds_t; int vasprintf(char ** __restrict ret, const char * __restrict format, va_list ap) { int len; /* Get Length */ len = _vsnprintf_s(NULL, 0, 0, format, ap); if (len < 0) return -1; /* +1 for \0 terminator. */ *ret = malloc(len + 1); if (!*ret) return -1; _vsnprintf_s(*ret, len + 1, len + 1, format, ap); /* Terminate explicitly */ (*ret)[len] = '\0'; return len; } #endif // WIN32 void logprintf (const char *format, ...) __attribute__ ((format (printf, 1, 2), weak)); void logprintf (const char *format, ...) { va_list ap; va_start (ap, format); vfprintf (stdout, format, ap); va_end (ap); } //extern int verbosity; //static long long total_allocated_bytes; int tgl_snprintf (char *buf, int len, const char *format, ...) { va_list ap; va_start (ap, format); int r = vsnprintf (buf, len, format, ap); va_end (ap); assert (r <= len && "tsnprintf buffer overflow"); return r; } int tgl_asprintf (char **res, const char *format, ...) { va_list ap; va_start (ap, format); int r = vasprintf (res, format, ap); assert (r >= 0); va_end (ap); void *rs = talloc (strlen (*res) + 1); memcpy (rs, *res, strlen (*res) + 1); free (*res); *res = rs; return r; } void tgl_free_debug (void *ptr, int size __attribute__ ((unused))) { total_allocated_bytes -= size; (char*)ptr -= RES_PRE; if (size != (int)((*(int *)ptr) ^ 0xbedabeda)) { logprintf ("size = %d, ptr = %d\n", size, (*(int *)ptr) ^ 0xbedabeda); } assert (*(int *)ptr == (int)((size) ^ 0xbedabeda)); assert (*(int *)((char *)ptr + RES_PRE + size) == (int)((size) ^ 0x7bed7bed)); assert (*(int *)((char *)ptr + 4) == size); int block_num = *(int *)((char*)ptr + 4 + RES_PRE + size); if (block_num >= used_blocks) { logprintf ("block_num = %d, used = %d\n", block_num, used_blocks); } assert (block_num < used_blocks); if (block_num < used_blocks - 1) { void *p = blocks[used_blocks - 1]; int s = (*(int *)p) ^ 0xbedabeda; *(int *)((char *)p + 4 + RES_PRE + s) = block_num; blocks[block_num] = p; } blocks[--used_blocks] = 0; memset (ptr, 0, size + RES_PRE + RES_AFTER); *(int *)ptr = size + 12; free_blocks[free_blocks_cnt ++] = ptr; } void tgl_free_release (void *ptr, int size) { memset (ptr, 0, size); free (ptr); } void *tgl_realloc_debug (void *ptr, size_t old_size __attribute__ ((unused)), size_t size) { void *p = talloc (size); memcpy (p, ptr, size >= old_size ? old_size : size); tfree (ptr, old_size); return p; } void *tgl_realloc_release (void *ptr, size_t old_size __attribute__ ((unused)), size_t size) { void *p = realloc (ptr, size); ensure_ptr (p); return p; } void *tgl_alloc_debug (size_t size) { total_allocated_bytes += size; void *p = malloc (size + RES_PRE + RES_AFTER); ensure_ptr (p); *(int *)p = size ^ 0xbedabeda; *(int *)((char *)p + 4) = size; *(int *)((char *)p + RES_PRE + size) = size ^ 0x7bed7bed; *(int *)((char *)p + RES_AFTER + 4 + size) = used_blocks; blocks[used_blocks ++] = p; //tcheck (); return (char *)p + 8; } void *tgl_alloc_release (size_t size) { void *p = malloc (size); ensure_ptr (p); return p; } void *tgl_alloc0 (size_t size) { void *p = talloc (size); memset (p, 0, size); return p; } char *tgl_strdup (const char *s) { int l = strlen (s); char *p = talloc (l + 1); #if defined(WIN32) || defined(_WIN32) ZeroMemory(p, l + 1); #endif memcpy (p, s, l + 1); return p; } char *tgl_strndup (const char *s, size_t n) { size_t l = 0; for (l = 0; l < n && s[l]; l++) { } char *p = talloc (l + 1); memcpy (p, s, l); p[l] = 0; return p; } void *tgl_memdup (const void *s, size_t n) { void *r = talloc (n); memcpy (r, s, n); return r; } int tgl_inflate (void *input, int ilen, void *output, int olen) { z_stream strm; memset (&strm, 0, sizeof (strm)); assert (inflateInit2 (&strm, 16 + MAX_WBITS) == Z_OK); strm.avail_in = ilen; strm.next_in = input; strm.avail_out = olen ; strm.next_out = output; int err = inflate (&strm, Z_FINISH); int total_out = strm.total_out; if (err != Z_OK && err != Z_STREAM_END) { logprintf ( "inflate error = %d\n", err); logprintf ( "inflated %d bytes\n", (int) strm.total_out); total_out = 0; } inflateEnd (&strm); return total_out; } void tgl_check_debug (void) { int i; for (i = 0; i < used_blocks; i++) { void *ptr = blocks[i]; int size = (*(int *)ptr) ^ 0xbedabeda; if (!(*(int *)((char *)ptr + 4) == size) || !(*(int *)((char *)ptr + RES_PRE + size) == (size ^ 0x7bed7bed)) || !(*(int *)((char *)ptr + RES_PRE + 4 + size) == i)) { logprintf ("Bad block at address %p (size %d, num %d)\n", ptr, size, i); assert (0 && "Bad block"); } } for (i = 0; i < free_blocks_cnt; i++) { void *ptr = free_blocks[i]; int l = *(int *)ptr; int j = 0; for (j = 0; j < l; j++) { if (*(char *)((char *)ptr + 4 + j)) { hexdump ((char *)ptr + 8, (char *)ptr + 8 + l + ((-l) & 3)); logprintf ("Used freed memory size = %d. ptr = %p\n", l + 4 - RES_PRE - RES_AFTER, ptr); assert (0); } } } //logprintf ("ok. Used_blocks = %d. Free blocks = %d\n", used_blocks, free_blocks_cnt); } void tgl_exists_debug (void *ptr, int size) { (char *)ptr -= RES_PRE; if (size != (int)((*(int *)ptr) ^ 0xbedabeda)) { logprintf ("size = %d, ptr = %d\n", size, (*(int *)ptr) ^ 0xbedabeda); } assert (*(int *)ptr == (int)((size) ^ 0xbedabeda)); assert (*(int *)((char *)ptr + RES_PRE + size) == (int)((size) ^ 0x7bed7bed)); assert (*(int *)((char *)ptr + 4) == size); int block_num = *(int *)((char *)ptr + 4 + RES_PRE + size); if (block_num >= used_blocks) { logprintf ("block_num = %d, used = %d\n", block_num, used_blocks); } assert (block_num < used_blocks); } void tgl_exists_release (void *ptr, int size) {} void tgl_check_release (void) {} void tgl_my_clock_gettime (int clock_id, struct timespec *T) { #if defined(WIN32) || defined(_WIN32) static double ticks2nano; static __int64 tps = 0; __int64 tmp, curticks; _Bool real_time = (clock_id == CLOCK_REALTIME); QueryPerformanceFrequency((LARGE_INTEGER*)&tmp); if (tps != tmp) { tps = tmp; ticks2nano = (double)exp9 / tps; } if (clock_id == CLOCK_REALTIME) { __int64 wintime; GetSystemTimeAsFileTime((FILETIME*)&wintime); wintime -= w2ux; T->tv_sec = wintime / exp7; T->tv_nsec = wintime % exp7 * 100; } else { QueryPerformanceCounter((LARGE_INTEGER*)&curticks); T->tv_sec = (long)(curticks / tps); T->tv_nsec = (long)((double)(curticks % tps) * ticks2nano); } if (!(T->tv_nsec < exp9)) { T->tv_sec++; T->tv_nsec -= exp9; } #elif defined( __MACH__) // We are ignoring MONOTONIC and hope time doesn't go back too often clock_serv_t cclock; mach_timespec_t mts; host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); clock_get_time(cclock, &mts); mach_port_deallocate(mach_task_self(), cclock); T->tv_sec = mts.tv_sec; T->tv_nsec = mts.tv_nsec; #else assert (clock_gettime(clock_id, T) >= 0); #endif } double tglt_get_double_time (void) { struct timespec tv; tgl_my_clock_gettime (CLOCK_REALTIME, &tv); return tv.tv_sec + 1e-9 * tv.tv_nsec; } void tglt_secure_random (void *s, int l) { if (RAND_bytes (s, l) <= 0) { /*if (allow_weak_random) { RAND_pseudo_bytes (s, l); } else {*/ assert (0 && "End of random. If you want, you can start with -w"); //} } else { #ifdef VALGRIND_FIXES VALGRIND_MAKE_MEM_DEFINED (s, l); VALGRIND_CHECK_MEM_IS_DEFINED (s, l); #endif } } struct tgl_allocator tgl_allocator_debug = { .alloc = tgl_alloc_debug, .realloc = tgl_realloc_debug, .free = tgl_free_debug, .check = tgl_check_debug, .exists = tgl_exists_debug }; struct tgl_allocator tgl_allocator_release = { .alloc = tgl_alloc_release, .realloc = tgl_realloc_release, .free = tgl_free_release, .check = tgl_check_release, .exists = tgl_exists_release }; struct tgl_allocator *tgl_allocator = &tgl_allocator_release;