MEM_DEBUG thread-safe & tccdbg leakless

libtcc.c:
- guard tcc_realloc/free_debug() with a semaphore
tccdbg.c:
- allow tcc_debug_end() to be called twice safely
This commit is contained in:
grischka 2023-04-15 16:57:02 +02:00
parent 7916cf71cc
commit 40131b7e0f
3 changed files with 30 additions and 11 deletions

View file

@ -69,10 +69,6 @@
ST_DATA struct TCCState *tcc_state; ST_DATA struct TCCState *tcc_state;
TCC_SEM(static tcc_compile_sem); TCC_SEM(static tcc_compile_sem);
#ifdef MEM_DEBUG
static int nb_states;
#endif
/********************************************************/ /********************************************************/
#ifdef _WIN32 #ifdef _WIN32
ST_FUNC char *normalize_slashes(char *path) ST_FUNC char *normalize_slashes(char *path)
@ -324,9 +320,11 @@ struct mem_debug_header {
typedef struct mem_debug_header mem_debug_header_t; typedef struct mem_debug_header mem_debug_header_t;
TCC_SEM(static mem_sem);
static mem_debug_header_t *mem_debug_chain; static mem_debug_header_t *mem_debug_chain;
static unsigned mem_cur_size; static unsigned mem_cur_size;
static unsigned mem_max_size; static unsigned mem_max_size;
static int nb_states;
static mem_debug_header_t *malloc_check(void *ptr, const char *msg) static mem_debug_header_t *malloc_check(void *ptr, const char *msg)
{ {
@ -362,15 +360,16 @@ PUB_FUNC void *tcc_malloc_debug(unsigned long size, const char *file, int line)
strncpy(header->file_name, file + (ofs > 0 ? ofs : 0), MEM_DEBUG_FILE_LEN); strncpy(header->file_name, file + (ofs > 0 ? ofs : 0), MEM_DEBUG_FILE_LEN);
header->file_name[MEM_DEBUG_FILE_LEN] = 0; header->file_name[MEM_DEBUG_FILE_LEN] = 0;
WAIT_SEM(&mem_sem);
header->next = mem_debug_chain; header->next = mem_debug_chain;
header->prev = NULL; header->prev = NULL;
if (header->next) if (header->next)
header->next->prev = header; header->next->prev = header;
mem_debug_chain = header; mem_debug_chain = header;
mem_cur_size += size; mem_cur_size += size;
if (mem_cur_size > mem_max_size) if (mem_cur_size > mem_max_size)
mem_max_size = mem_cur_size; mem_max_size = mem_cur_size;
POST_SEM(&mem_sem);
return MEM_USER_PTR(header); return MEM_USER_PTR(header);
} }
@ -381,6 +380,8 @@ PUB_FUNC void tcc_free_debug(void *ptr)
if (!ptr) if (!ptr)
return; return;
header = malloc_check(ptr, "tcc_free"); header = malloc_check(ptr, "tcc_free");
WAIT_SEM(&mem_sem);
mem_cur_size -= header->size; mem_cur_size -= header->size;
header->size = (unsigned)-1; header->size = (unsigned)-1;
if (header->next) if (header->next)
@ -389,6 +390,7 @@ PUB_FUNC void tcc_free_debug(void *ptr)
header->prev->next = header->next; header->prev->next = header->next;
if (header == mem_debug_chain) if (header == mem_debug_chain)
mem_debug_chain = header->next; mem_debug_chain = header->next;
POST_SEM(&mem_sem);
free(header); free(header);
} }
@ -407,6 +409,8 @@ PUB_FUNC void *tcc_realloc_debug(void *ptr, unsigned long size, const char *file
if (!ptr) if (!ptr)
return tcc_malloc_debug(size, file, line); return tcc_malloc_debug(size, file, line);
header = malloc_check(ptr, "tcc_realloc"); header = malloc_check(ptr, "tcc_realloc");
WAIT_SEM(&mem_sem);
mem_cur_size -= header->size; mem_cur_size -= header->size;
mem_debug_chain_update = (header == mem_debug_chain); mem_debug_chain_update = (header == mem_debug_chain);
header = realloc(header, sizeof(mem_debug_header_t) + size); header = realloc(header, sizeof(mem_debug_header_t) + size);
@ -423,6 +427,8 @@ PUB_FUNC void *tcc_realloc_debug(void *ptr, unsigned long size, const char *file
mem_cur_size += size; mem_cur_size += size;
if (mem_cur_size > mem_max_size) if (mem_cur_size > mem_max_size)
mem_max_size = mem_cur_size; mem_max_size = mem_cur_size;
POST_SEM(&mem_sem);
return MEM_USER_PTR(header); return MEM_USER_PTR(header);
} }
@ -434,10 +440,13 @@ PUB_FUNC char *tcc_strdup_debug(const char *str, const char *file, int line)
return ptr; return ptr;
} }
PUB_FUNC void tcc_memcheck(void) PUB_FUNC void tcc_memcheck(int d)
{ {
if (mem_cur_size) { WAIT_SEM(&mem_sem);
nb_states += d;
if (0 == nb_states && mem_cur_size) {
mem_debug_header_t *header = mem_debug_chain; mem_debug_header_t *header = mem_debug_chain;
fflush(stdout);
fprintf(stderr, "MEM_DEBUG: mem_leak= %d bytes, mem_max_size= %d bytes\n", fprintf(stderr, "MEM_DEBUG: mem_leak= %d bytes, mem_max_size= %d bytes\n",
mem_cur_size, mem_max_size); mem_cur_size, mem_max_size);
while (header) { while (header) {
@ -445,10 +454,14 @@ PUB_FUNC void tcc_memcheck(void)
header->file_name, header->line_num, header->size); header->file_name, header->line_num, header->size);
header = header->next; header = header->next;
} }
fflush(stderr);
mem_cur_size = 0;
mem_debug_chain = NULL;
#if MEM_DEBUG-0 == 2 #if MEM_DEBUG-0 == 2
exit(2); exit(2);
#endif #endif
} }
POST_SEM(&mem_sem);
} }
#endif /* MEM_DEBUG */ #endif /* MEM_DEBUG */
@ -785,7 +798,7 @@ LIBTCCAPI TCCState *tcc_new(void)
if (!s) if (!s)
return NULL; return NULL;
#ifdef MEM_DEBUG #ifdef MEM_DEBUG
++nb_states; tcc_memcheck(1);
#endif #endif
#undef gnu_ext #undef gnu_ext
@ -862,8 +875,7 @@ LIBTCCAPI void tcc_delete(TCCState *s1)
tcc_free(s1->dState); tcc_free(s1->dState);
tcc_free(s1); tcc_free(s1);
#ifdef MEM_DEBUG #ifdef MEM_DEBUG
if (0 == --nb_states) tcc_memcheck(-1);
tcc_memcheck();
#endif #endif
} }

View file

@ -889,8 +889,12 @@ ST_FUNC void tcc_debug_start(TCCState *s1)
/* put end of translation unit info */ /* put end of translation unit info */
ST_FUNC void tcc_debug_end(TCCState *s1) ST_FUNC void tcc_debug_end(TCCState *s1)
{ {
if (!s1->do_debug) if (!s1->do_debug || debug_next_type == 0)
return; return;
if (debug_info_root)
tcc_debug_funcend(s1, 0); /* free stuff in case of errors */
if (s1->dwarf) { if (s1->dwarf) {
int i, j; int i, j;
int start_aranges; int start_aranges;
@ -1019,6 +1023,7 @@ ST_FUNC void tcc_debug_end(TCCState *s1)
text_section->data_offset, text_section, section_sym); text_section->data_offset, text_section, section_sym);
} }
tcc_free(debug_hash); tcc_free(debug_hash);
debug_next_type = 0;
} }
static BufferedFile* put_new_file(TCCState *s1) static BufferedFile* put_new_file(TCCState *s1)
@ -1920,6 +1925,7 @@ ST_FUNC void tcc_debug_funcend(TCCState *s1, int size)
{ {
tcc_debug_finish (s1, debug_info_root); tcc_debug_finish (s1, debug_info_root);
} }
debug_info_root = 0;
} }

View file

@ -401,6 +401,7 @@ ST_FUNC int tccgen_compile(TCCState *s1)
ST_FUNC void tccgen_finish(TCCState *s1) ST_FUNC void tccgen_finish(TCCState *s1)
{ {
tcc_debug_end(s1); /* just in case of errors: free memory */
cstr_free(&initstr); cstr_free(&initstr);
free_inline_functions(s1); free_inline_functions(s1);
sym_pop(&global_stack, NULL, 0); sym_pop(&global_stack, NULL, 0);