/* * TCC - Tiny C Compiler * * Copyright (c) 2001-2004 Fabrice Bellard * * 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef ONE_SOURCE# define ONE_SOURCE 1#endif #if ONE_SOURCE#include "tccpp.c"#include "tccgen.c"#include "tccdbg.c"#include "tccasm.c"#include "tccelf.c"#include "tccrun.c"#ifdef TCC_TARGET_I386#include "i386-gen.c"#include "i386-link.c"#include "i386-asm.c"#elif defined(TCC_TARGET_ARM)#include "arm-gen.c"#include "arm-link.c"#include "arm-asm.c"#elif defined(TCC_TARGET_ARM64)#include "arm64-gen.c"#include "arm64-link.c"#include "arm64-asm.c"#elif defined(TCC_TARGET_C67)#include "c67-gen.c"#include "c67-link.c"#include "tcccoff.c"#elif defined(TCC_TARGET_X86_64)#include "x86_64-gen.c"#include "x86_64-link.c"#include "i386-asm.c"#elif defined(TCC_TARGET_RISCV64)#include "riscv64-gen.c"#include "riscv64-link.c"#include "riscv64-asm.c"#else#error unknown target#endif#ifdef TCC_TARGET_PE#include "tccpe.c"#endif#ifdef TCC_TARGET_MACHO#include "tccmacho.c"#endif#endif /* ONE_SOURCE */ #include "tcc.h" /********************************************************//* global variables */ /* XXX: get rid of this ASAP (or maybe not) */ST_DATA struct TCCState *tcc_state;TCC_SEM(static tcc_compile_sem);/* an array of pointers to memory to be free'd after errors */ST_DATA void** stk_data;ST_DATA int nb_stk_data;/* option -d<num> (for general development purposes) */ST_DATA int g_debug; /********************************************************/#ifdef _WIN32ST_FUNC char *normalize_slashes(char *path){ char *p; for (p = path; *p; ++p) if (*p == '\\') *p = '/'; return path;} #if defined LIBTCC_AS_DLL && !defined CONFIG_TCCDIRstatic HMODULE tcc_module;BOOL WINAPI DllMain (HINSTANCE hDll, DWORD dwReason, LPVOID lpReserved){ if (DLL_PROCESS_ATTACH == dwReason) tcc_module = hDll; return TRUE;}#else#define tcc_module NULL /* NULL means executable itself */#endif #ifndef CONFIG_TCCDIR/* on win32, we suppose the lib and includes are at the location of 'tcc.exe' */static inline char *config_tccdir_w32(char *path){ char *p; GetModuleFileNameA(tcc_module, path, MAX_PATH); p = tcc_basename(normalize_slashes(strlwr(path))); if (p > path) --p; *p = 0; return path;}#define CONFIG_TCCDIR config_tccdir_w32(alloca(MAX_PATH))#endif #ifdef TCC_IS_NATIVEstatic void tcc_add_systemdir(TCCState *s){ char buf[1000]; GetSystemDirectoryA(buf, sizeof buf); tcc_add_library_path(s, normalize_slashes(buf));}#endif/* for tcc -E : On windows (depending on compiler) a FILE* must be created by the same module where it is used. */PUB_FUNC FILE *tcc_fopen(const char *f, const char *m) { return fopen(f, m);}PUB_FUNC int tcc_fclose(FILE *f) { return fclose(f);}#endif/********************************************************/ PUB_FUNC void tcc_enter_state(TCCState *s1){ if (s1->error_set_jmp_enabled) return; WAIT_SEM(&tcc_compile_sem); tcc_state = s1;} PUB_FUNC void tcc_exit_state(TCCState *s1){ if (s1->error_set_jmp_enabled) return; tcc_state = NULL; POST_SEM(&tcc_compile_sem);} /********************************************************//* copy a string and truncate it. */ST_FUNC char *pstrcpy(char *buf, size_t buf_size, const char *s){ char *q, *q_end; int c; if (buf_size > 0) { q = buf; q_end = buf + buf_size - 1; while (q < q_end) { c = *s++; if (c == '\0') break; *q++ = c; } *q = '\0'; } return buf;} /* strcat and truncate. */ST_FUNC char *pstrcat(char *buf, size_t buf_size, const char *s){ size_t len; len = strlen(buf); if (len < buf_size) pstrcpy(buf + len, buf_size - len, s); return buf;} ST_FUNC char *pstrncpy(char *out, size_t buf_size, const char *s, size_t num){ if (num >= buf_size) num = buf_size - 1; memcpy(out, s, num); out[num] = '\0'; return out;} /* extract the basename of a file */PUB_FUNC char *tcc_basename(const char *name){ char *p = (char *)strchr(name, 0); while (p > name && !IS_DIRSEP(p[-1])) --p; return p;} /* extract extension part of a file * * (if no extension, return pointer to end-of-string) */PUB_FUNC char *tcc_fileextension (const char *name){ char *b = tcc_basename(name); char *e = strrchr(b, '.'); return e ? e : strchr(b, 0);} ST_FUNC char *tcc_load_text(int fd){ int len = lseek(fd, 0, SEEK_END); char *buf = load_data(fd, 0, len + 1); buf[len] = 0; return buf;} /* replace *pp by copy of 'str' or NULL */static void tcc_set_str(char **pp, const char *str){ tcc_free(*pp); *pp = str ? tcc_strdup(str) : NULL;} /* set/append 'str' to *pp (separated by 'sep' unless 0) */static void tcc_concat_str(char **pp, const char *str, int sep){ int l = *pp ? strlen(*pp) + !!sep : 0; *pp = tcc_realloc(*pp, l + strlen(str) + 1); if (l && sep) ((*pp)[l - 1] = sep); strcpy(*pp + l, str);} /********************************************************//* memory management */ /* we'll need the actual versions for a minute */#undef free#undef realloc static void *default_reallocator(void *ptr, unsigned long size){ void *ptr1; if (size == 0) { free(ptr); ptr1 = NULL; } else { ptr1 = realloc(ptr, size); if (!ptr1) { fprintf(stderr, "tcc: memory full\n"); exit (1); } } return ptr1;} ST_FUNC void libc_free(void *ptr){ free(ptr);} /* defined to be not used */#define free(p) use_tcc_free(p)#define realloc(p, s) use_tcc_realloc(p, s) /* global so that every tcc_alloc()/tcc_free() call doesn't need to be changed */static void *(*reallocator)(void*, unsigned long) = default_reallocator; LIBTCCAPI void tcc_set_realloc(TCCReallocFunc *my_realloc){ reallocator = my_realloc ? my_realloc : default_reallocator;} /* in case MEM_DEBUG is #defined */#undef tcc_free#undef tcc_malloc#undef tcc_realloc#undef tcc_mallocz#undef tcc_strdup PUB_FUNC void tcc_free(void *ptr){ reallocator(ptr, 0);} PUB_FUNC void *tcc_malloc(unsigned long size){ return reallocator(0, size);} PUB_FUNC void *tcc_realloc(void *ptr, unsigned long size){ return reallocator(ptr, size);} PUB_FUNC void *tcc_mallocz(unsigned long size){ void *ptr; ptr = tcc_malloc(size); if (size) memset(ptr, 0, size); return ptr;} PUB_FUNC char *tcc_strdup(const char *str){ char *ptr; ptr = tcc_malloc(strlen(str) + 1); strcpy(ptr, str); return ptr;} #ifdef MEM_DEBUG #define MEM_DEBUG_MAGIC1 0xFEEDDEB1#define MEM_DEBUG_MAGIC2 0xFEEDDEB2#define MEM_DEBUG_MAGIC3 0xFEEDDEB3#define MEM_DEBUG_FILE_LEN 40#define MEM_DEBUG_CHECK3(header) \ (((unsigned char *) header->magic3) + header->size)#define MEM_USER_PTR(header) \ ((char *)header + offsetof(mem_debug_header_t, magic3))#define MEM_HEADER_PTR(ptr) \ (mem_debug_header_t *)((char*)ptr - offsetof(mem_debug_header_t, magic3)) struct mem_debug_header { unsigned magic1; unsigned size; struct mem_debug_header *prev; struct mem_debug_header *next; int line_num; char file_name[MEM_DEBUG_FILE_LEN]; unsigned magic2; ALIGNED(16) unsigned char magic3[4];}; typedef struct mem_debug_header mem_debug_header_t; TCC_SEM(static mem_sem);static mem_debug_header_t *mem_debug_chain;static unsigned mem_cur_size;static unsigned mem_max_size;static int nb_states; static mem_debug_header_t *malloc_check(void *ptr, const char *msg){ mem_debug_header_t * header = MEM_HEADER_PTR(ptr); if (header->magic1 != MEM_DEBUG_MAGIC1 || header->magic2 != MEM_DEBUG_MAGIC2 || read32le(MEM_DEBUG_CHECK3(header)) != MEM_DEBUG_MAGIC3 || header->size == (unsigned)-1) { fprintf(stderr, "%s check failed\n", msg); if (header->magic1 == MEM_DEBUG_MAGIC1) fprintf(stderr, "%s:%u: block allocated here.\n", header->file_name, header->line_num); exit(1); } return header;} PUB_FUNC void *tcc_malloc_debug(unsigned long size, const char *file, int line){ int ofs; mem_debug_header_t *header; if (!size) return NULL; header = tcc_malloc(sizeof(mem_debug_header_t) + size); header->magic1 = MEM_DEBUG_MAGIC1; header->magic2 = MEM_DEBUG_MAGIC2; header->size = size; write32le(MEM_DEBUG_CHECK3(header), MEM_DEBUG_MAGIC3); header->line_num = line; ofs = strlen(file) + 1 - MEM_DEBUG_FILE_LEN; strcpy(header->file_name, file + (ofs > 0 ? ofs : 0)); WAIT_SEM(&mem_sem); header->next = mem_debug_chain; header->prev = NULL; if (header->next) header->next->prev = header; mem_debug_chain = header; mem_cur_size += size; if (mem_cur_size > mem_max_size) mem_max_size = mem_cur_size; POST_SEM(&mem_sem); return MEM_USER_PTR(header);} PUB_FUNC void tcc_free_debug(void *ptr){ mem_debug_header_t *header; if (!ptr) return; header = malloc_check(ptr, "tcc_free"); WAIT_SEM(&mem_sem); mem_cur_size -= header->size; header->size = (unsigned)-1; if (header->next) header->next->prev = header->prev; if (header->prev) header->prev->next = header->next; if (header == mem_debug_chain) mem_debug_chain = header->next; POST_SEM(&mem_sem); tcc_free(header);} PUB_FUNC void *tcc_mallocz_debug(unsigned long size, const char *file, int line){ void *ptr; ptr = tcc_malloc_debug(size,file,line); if (size) memset(ptr, 0, size); return ptr;} PUB_FUNC void *tcc_realloc_debug(void *ptr, unsigned long size, const char *file, int line){ mem_debug_header_t *header; int mem_debug_chain_update = 0; if (!ptr) return tcc_malloc_debug(size, file, line); if (!size) { tcc_free_debug(ptr); return NULL; } header = malloc_check(ptr, "tcc_realloc"); WAIT_SEM(&mem_sem); mem_cur_size -= header->size; mem_debug_chain_update = (header == mem_debug_chain); header = tcc_realloc(header, sizeof(mem_debug_header_t) + size); header->size = size; write32le(MEM_DEBUG_CHECK3(header), MEM_DEBUG_MAGIC3); if (header->next) header->next->prev = header; if (header->prev) header->prev->next = header; if (mem_debug_chain_update) mem_debug_chain = header; mem_cur_size += size; if (mem_cur_size > mem_max_size) mem_max_size = mem_cur_size; POST_SEM(&mem_sem); return MEM_USER_PTR(header);} PUB_FUNC char *tcc_strdup_debug(const char *str, const char *file, int line){ char *ptr; ptr = tcc_malloc_debug(strlen(str) + 1, file, line); strcpy(ptr, str); return ptr;} PUB_FUNC void tcc_memcheck(int d){ WAIT_SEM(&mem_sem); nb_states += d; if (0 == nb_states && mem_cur_size) { mem_debug_header_t *header = mem_debug_chain; fflush(stdout); fprintf(stderr, "MEM_DEBUG: mem_leak= %d bytes, mem_max_size= %d bytes\n", mem_cur_size, mem_max_size); while (header) { fprintf(stderr, "%s:%u: error: %u bytes leaked\n", header->file_name, header->line_num, header->size); header = header->next; } fflush(stderr); mem_cur_size = 0; mem_max_size = 0; mem_debug_chain = NULL;#if MEM_DEBUG-0 == 2 exit(2);#endif } POST_SEM(&mem_sem);} /* restore the debug versions */#define tcc_free(ptr) tcc_free_debug(ptr)#define tcc_malloc(size) tcc_malloc_debug(size, __FILE__, __LINE__)#define tcc_mallocz(size) tcc_mallocz_debug(size, __FILE__, __LINE__)#define tcc_realloc(ptr,size) tcc_realloc_debug(ptr, size, __FILE__, __LINE__)#define tcc_strdup(str) tcc_strdup_debug(str, __FILE__, __LINE__) #endif /* MEM_DEBUG */ #ifdef _WIN32# define realpath(file, buf) _fullpath(buf, file, 260)#endif /* for #pragma once */ST_FUNC int normalized_PATHCMP(const char *f1, const char *f2){Lines 1–500 of 2253. Load more
/* * TCC - Tiny C Compiler * * Copyright (c) 2001-2004 Fabrice Bellard * * 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef ONE_SOURCE # define ONE_SOURCE 1 #endif #if ONE_SOURCE #include "tccpp.c" #include "tccgen.c" #include "tccdbg.c" #include "tccasm.c" #include "tccelf.c" #include "tccrun.c" #ifdef TCC_TARGET_I386 #include "i386-gen.c" #include "i386-link.c" #include "i386-asm.c" #elif defined(TCC_TARGET_ARM) #include "arm-gen.c" #include "arm-link.c" #include "arm-asm.c" #elif defined(TCC_TARGET_ARM64) #include "arm64-gen.c" #include "arm64-link.c" #include "arm64-asm.c" #elif defined(TCC_TARGET_C67) #include "c67-gen.c" #include "c67-link.c" #include "tcccoff.c" #elif defined(TCC_TARGET_X86_64) #include "x86_64-gen.c" #include "x86_64-link.c" #include "i386-asm.c" #elif defined(TCC_TARGET_RISCV64) #include "riscv64-gen.c" #include "riscv64-link.c" #include "riscv64-asm.c" #else #error unknown target #endif #ifdef TCC_TARGET_PE #include "tccpe.c" #endif #ifdef TCC_TARGET_MACHO #include "tccmacho.c" #endif #endif /* ONE_SOURCE */ #include "tcc.h" /********************************************************/ /* global variables */ /* XXX: get rid of this ASAP (or maybe not) */ ST_DATA struct TCCState *tcc_state; TCC_SEM(static tcc_compile_sem); /* an array of pointers to memory to be free'd after errors */ ST_DATA void** stk_data; ST_DATA int nb_stk_data; /* option -d<num> (for general development purposes) */ ST_DATA int g_debug; /********************************************************/ #ifdef _WIN32 ST_FUNC char *normalize_slashes(char *path) { char *p; for (p = path; *p; ++p) if (*p == '\\') *p = '/'; return path; } #if defined LIBTCC_AS_DLL && !defined CONFIG_TCCDIR static HMODULE tcc_module; BOOL WINAPI DllMain (HINSTANCE hDll, DWORD dwReason, LPVOID lpReserved) { if (DLL_PROCESS_ATTACH == dwReason) tcc_module = hDll; return TRUE; } #else #define tcc_module NULL /* NULL means executable itself */ #endif #ifndef CONFIG_TCCDIR /* on win32, we suppose the lib and includes are at the location of 'tcc.exe' */ static inline char *config_tccdir_w32(char *path) { char *p; GetModuleFileNameA(tcc_module, path, MAX_PATH); p = tcc_basename(normalize_slashes(strlwr(path))); if (p > path) --p; *p = 0; return path; } #define CONFIG_TCCDIR config_tccdir_w32(alloca(MAX_PATH)) #endif #ifdef TCC_IS_NATIVE static void tcc_add_systemdir(TCCState *s) { char buf[1000]; GetSystemDirectoryA(buf, sizeof buf); tcc_add_library_path(s, normalize_slashes(buf)); } #endif /* for tcc -E : On windows (depending on compiler) a FILE* must be created by the same module where it is used. */ PUB_FUNC FILE *tcc_fopen(const char *f, const char *m) { return fopen(f, m); } PUB_FUNC int tcc_fclose(FILE *f) { return fclose(f); } #endif /********************************************************/ PUB_FUNC void tcc_enter_state(TCCState *s1) { if (s1->error_set_jmp_enabled) return; WAIT_SEM(&tcc_compile_sem); tcc_state = s1; } PUB_FUNC void tcc_exit_state(TCCState *s1) { if (s1->error_set_jmp_enabled) return; tcc_state = NULL; POST_SEM(&tcc_compile_sem); } /********************************************************/ /* copy a string and truncate it. */ ST_FUNC char *pstrcpy(char *buf, size_t buf_size, const char *s) { char *q, *q_end; int c; if (buf_size > 0) { q = buf; q_end = buf + buf_size - 1; while (q < q_end) { c = *s++; if (c == '\0') break; *q++ = c; } *q = '\0'; } return buf; } /* strcat and truncate. */ ST_FUNC char *pstrcat(char *buf, size_t buf_size, const char *s) { size_t len; len = strlen(buf); if (len < buf_size) pstrcpy(buf + len, buf_size - len, s); return buf; } ST_FUNC char *pstrncpy(char *out, size_t buf_size, const char *s, size_t num) { if (num >= buf_size) num = buf_size - 1; memcpy(out, s, num); out[num] = '\0'; return out; } /* extract the basename of a file */ PUB_FUNC char *tcc_basename(const char *name) { char *p = (char *)strchr(name, 0); while (p > name && !IS_DIRSEP(p[-1])) --p; return p; } /* extract extension part of a file * * (if no extension, return pointer to end-of-string) */ PUB_FUNC char *tcc_fileextension (const char *name) { char *b = tcc_basename(name); char *e = strrchr(b, '.'); return e ? e : strchr(b, 0); } ST_FUNC char *tcc_load_text(int fd) { int len = lseek(fd, 0, SEEK_END); char *buf = load_data(fd, 0, len + 1); buf[len] = 0; return buf; } /* replace *pp by copy of 'str' or NULL */ static void tcc_set_str(char **pp, const char *str) { tcc_free(*pp); *pp = str ? tcc_strdup(str) : NULL; } /* set/append 'str' to *pp (separated by 'sep' unless 0) */ static void tcc_concat_str(char **pp, const char *str, int sep) { int l = *pp ? strlen(*pp) + !!sep : 0; *pp = tcc_realloc(*pp, l + strlen(str) + 1); if (l && sep) ((*pp)[l - 1] = sep); strcpy(*pp + l, str); } /********************************************************/ /* memory management */ /* we'll need the actual versions for a minute */ #undef free #undef realloc static void *default_reallocator(void *ptr, unsigned long size) { void *ptr1; if (size == 0) { free(ptr); ptr1 = NULL; } else { ptr1 = realloc(ptr, size); if (!ptr1) { fprintf(stderr, "tcc: memory full\n"); exit (1); } } return ptr1; } ST_FUNC void libc_free(void *ptr) { free(ptr); } /* defined to be not used */ #define free(p) use_tcc_free(p) #define realloc(p, s) use_tcc_realloc(p, s) /* global so that every tcc_alloc()/tcc_free() call doesn't need to be changed */ static void *(*reallocator)(void*, unsigned long) = default_reallocator; LIBTCCAPI void tcc_set_realloc(TCCReallocFunc *my_realloc) { reallocator = my_realloc ? my_realloc : default_reallocator; } /* in case MEM_DEBUG is #defined */ #undef tcc_free #undef tcc_malloc #undef tcc_realloc #undef tcc_mallocz #undef tcc_strdup PUB_FUNC void tcc_free(void *ptr) { reallocator(ptr, 0); } PUB_FUNC void *tcc_malloc(unsigned long size) { return reallocator(0, size); } PUB_FUNC void *tcc_realloc(void *ptr, unsigned long size) { return reallocator(ptr, size); } PUB_FUNC void *tcc_mallocz(unsigned long size) { void *ptr; ptr = tcc_malloc(size); if (size) memset(ptr, 0, size); return ptr; } PUB_FUNC char *tcc_strdup(const char *str) { char *ptr; ptr = tcc_malloc(strlen(str) + 1); strcpy(ptr, str); return ptr; } #ifdef MEM_DEBUG #define MEM_DEBUG_MAGIC1 0xFEEDDEB1 #define MEM_DEBUG_MAGIC2 0xFEEDDEB2 #define MEM_DEBUG_MAGIC3 0xFEEDDEB3 #define MEM_DEBUG_FILE_LEN 40 #define MEM_DEBUG_CHECK3(header) \ (((unsigned char *) header->magic3) + header->size) #define MEM_USER_PTR(header) \ ((char *)header + offsetof(mem_debug_header_t, magic3)) #define MEM_HEADER_PTR(ptr) \ (mem_debug_header_t *)((char*)ptr - offsetof(mem_debug_header_t, magic3)) struct mem_debug_header { unsigned magic1; unsigned size; struct mem_debug_header *prev; struct mem_debug_header *next; int line_num; char file_name[MEM_DEBUG_FILE_LEN]; unsigned magic2; ALIGNED(16) unsigned char magic3[4]; }; typedef struct mem_debug_header mem_debug_header_t; TCC_SEM(static mem_sem); static mem_debug_header_t *mem_debug_chain; static unsigned mem_cur_size; static unsigned mem_max_size; static int nb_states; static mem_debug_header_t *malloc_check(void *ptr, const char *msg) { mem_debug_header_t * header = MEM_HEADER_PTR(ptr); if (header->magic1 != MEM_DEBUG_MAGIC1 || header->magic2 != MEM_DEBUG_MAGIC2 || read32le(MEM_DEBUG_CHECK3(header)) != MEM_DEBUG_MAGIC3 || header->size == (unsigned)-1) { fprintf(stderr, "%s check failed\n", msg); if (header->magic1 == MEM_DEBUG_MAGIC1) fprintf(stderr, "%s:%u: block allocated here.\n", header->file_name, header->line_num); exit(1); } return header; } PUB_FUNC void *tcc_malloc_debug(unsigned long size, const char *file, int line) { int ofs; mem_debug_header_t *header; if (!size) return NULL; header = tcc_malloc(sizeof(mem_debug_header_t) + size); header->magic1 = MEM_DEBUG_MAGIC1; header->magic2 = MEM_DEBUG_MAGIC2; header->size = size; write32le(MEM_DEBUG_CHECK3(header), MEM_DEBUG_MAGIC3); header->line_num = line; ofs = strlen(file) + 1 - MEM_DEBUG_FILE_LEN; strcpy(header->file_name, file + (ofs > 0 ? ofs : 0)); WAIT_SEM(&mem_sem); header->next = mem_debug_chain; header->prev = NULL; if (header->next) header->next->prev = header; mem_debug_chain = header; mem_cur_size += size; if (mem_cur_size > mem_max_size) mem_max_size = mem_cur_size; POST_SEM(&mem_sem); return MEM_USER_PTR(header); } PUB_FUNC void tcc_free_debug(void *ptr) { mem_debug_header_t *header; if (!ptr) return; header = malloc_check(ptr, "tcc_free"); WAIT_SEM(&mem_sem); mem_cur_size -= header->size; header->size = (unsigned)-1; if (header->next) header->next->prev = header->prev; if (header->prev) header->prev->next = header->next; if (header == mem_debug_chain) mem_debug_chain = header->next; POST_SEM(&mem_sem); tcc_free(header); } PUB_FUNC void *tcc_mallocz_debug(unsigned long size, const char *file, int line) { void *ptr; ptr = tcc_malloc_debug(size,file,line); if (size) memset(ptr, 0, size); return ptr; } PUB_FUNC void *tcc_realloc_debug(void *ptr, unsigned long size, const char *file, int line) { mem_debug_header_t *header; int mem_debug_chain_update = 0; if (!ptr) return tcc_malloc_debug(size, file, line); if (!size) { tcc_free_debug(ptr); return NULL; } header = malloc_check(ptr, "tcc_realloc"); WAIT_SEM(&mem_sem); mem_cur_size -= header->size; mem_debug_chain_update = (header == mem_debug_chain); header = tcc_realloc(header, sizeof(mem_debug_header_t) + size); header->size = size; write32le(MEM_DEBUG_CHECK3(header), MEM_DEBUG_MAGIC3); if (header->next) header->next->prev = header; if (header->prev) header->prev->next = header; if (mem_debug_chain_update) mem_debug_chain = header; mem_cur_size += size; if (mem_cur_size > mem_max_size) mem_max_size = mem_cur_size; POST_SEM(&mem_sem); return MEM_USER_PTR(header); } PUB_FUNC char *tcc_strdup_debug(const char *str, const char *file, int line) { char *ptr; ptr = tcc_malloc_debug(strlen(str) + 1, file, line); strcpy(ptr, str); return ptr; } PUB_FUNC void tcc_memcheck(int d) { WAIT_SEM(&mem_sem); nb_states += d; if (0 == nb_states && mem_cur_size) { mem_debug_header_t *header = mem_debug_chain; fflush(stdout); fprintf(stderr, "MEM_DEBUG: mem_leak= %d bytes, mem_max_size= %d bytes\n", mem_cur_size, mem_max_size); while (header) { fprintf(stderr, "%s:%u: error: %u bytes leaked\n", header->file_name, header->line_num, header->size); header = header->next; } fflush(stderr); mem_cur_size = 0; mem_max_size = 0; mem_debug_chain = NULL; #if MEM_DEBUG-0 == 2 exit(2); #endif } POST_SEM(&mem_sem); } /* restore the debug versions */ #define tcc_free(ptr) tcc_free_debug(ptr) #define tcc_malloc(size) tcc_malloc_debug(size, __FILE__, __LINE__) #define tcc_mallocz(size) tcc_mallocz_debug(size, __FILE__, __LINE__) #define tcc_realloc(ptr,size) tcc_realloc_debug(ptr, size, __FILE__, __LINE__) #define tcc_strdup(str) tcc_strdup_debug(str, __FILE__, __LINE__) #endif /* MEM_DEBUG */ #ifdef _WIN32 # define realpath(file, buf) _fullpath(buf, file, 260) #endif /* for #pragma once */ ST_FUNC int normalized_PATHCMP(const char *f1, const char *f2) {