diff --git a/libtcc.c b/libtcc.c
index d6576b90..1f896f26 100644
--- a/libtcc.c
+++ b/libtcc.c
@@ -69,10 +69,6 @@
 ST_DATA struct TCCState *tcc_state;
 TCC_SEM(static tcc_compile_sem);
 
-#ifdef MEM_DEBUG
-static int nb_states;
-#endif
-
 /********************************************************/
 #ifdef _WIN32
 ST_FUNC char *normalize_slashes(char *path)
@@ -324,9 +320,11 @@ struct mem_debug_header {
 
 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)
 {
@@ -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);
     header->file_name[MEM_DEBUG_FILE_LEN] = 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);
 }
@@ -381,6 +380,8 @@ PUB_FUNC void tcc_free_debug(void *ptr)
     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)
@@ -389,6 +390,7 @@ PUB_FUNC void tcc_free_debug(void *ptr)
         header->prev->next = header->next;
     if (header == mem_debug_chain)
         mem_debug_chain = header->next;
+    POST_SEM(&mem_sem);
     free(header);
 }
 
@@ -407,6 +409,8 @@ PUB_FUNC void *tcc_realloc_debug(void *ptr, unsigned long size, const char *file
     if (!ptr)
         return tcc_malloc_debug(size, file, line);
     header = malloc_check(ptr, "tcc_realloc");
+
+    WAIT_SEM(&mem_sem);
     mem_cur_size -= header->size;
     mem_debug_chain_update = (header == mem_debug_chain);
     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;
     if (mem_cur_size > mem_max_size)
         mem_max_size = mem_cur_size;
+    POST_SEM(&mem_sem);
+
     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;
 }
 
-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;
+        fflush(stdout);
         fprintf(stderr, "MEM_DEBUG: mem_leak= %d bytes, mem_max_size= %d bytes\n",
             mem_cur_size, mem_max_size);
         while (header) {
@@ -445,10 +454,14 @@ PUB_FUNC void tcc_memcheck(void)
                 header->file_name, header->line_num, header->size);
             header = header->next;
         }
+        fflush(stderr);
+        mem_cur_size = 0;
+        mem_debug_chain = NULL;
 #if MEM_DEBUG-0 == 2
         exit(2);
 #endif
     }
+    POST_SEM(&mem_sem);
 }
 #endif /* MEM_DEBUG */
 
@@ -785,7 +798,7 @@ LIBTCCAPI TCCState *tcc_new(void)
     if (!s)
         return NULL;
 #ifdef MEM_DEBUG
-    ++nb_states;
+    tcc_memcheck(1);
 #endif
 
 #undef gnu_ext
@@ -862,8 +875,7 @@ LIBTCCAPI void tcc_delete(TCCState *s1)
     tcc_free(s1->dState);
     tcc_free(s1);
 #ifdef MEM_DEBUG
-    if (0 == --nb_states)
-        tcc_memcheck();
+    tcc_memcheck(-1);
 #endif
 }
 
diff --git a/tccdbg.c b/tccdbg.c
index f63ab4b7..18c2cb10 100644
--- a/tccdbg.c
+++ b/tccdbg.c
@@ -889,8 +889,12 @@ ST_FUNC void tcc_debug_start(TCCState *s1)
 /* put end of translation unit info */
 ST_FUNC void tcc_debug_end(TCCState *s1)
 {
-    if (!s1->do_debug)
+    if (!s1->do_debug || debug_next_type == 0)
         return;
+
+    if (debug_info_root)
+        tcc_debug_funcend(s1, 0); /* free stuff in case of errors */
+
     if (s1->dwarf) {
 	int i, j;
 	int start_aranges;
@@ -1019,6 +1023,7 @@ ST_FUNC void tcc_debug_end(TCCState *s1)
                     text_section->data_offset, text_section, section_sym);
     }
     tcc_free(debug_hash);
+    debug_next_type = 0;
 }
 
 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);
     }
+    debug_info_root = 0;
 }
 
 
diff --git a/tccgen.c b/tccgen.c
index bdbff99f..c7e8d136 100644
--- a/tccgen.c
+++ b/tccgen.c
@@ -401,6 +401,7 @@ ST_FUNC int tccgen_compile(TCCState *s1)
 
 ST_FUNC void tccgen_finish(TCCState *s1)
 {
+    tcc_debug_end(s1); /* just in case of errors: free memory */
     cstr_free(&initstr);
     free_inline_functions(s1);
     sym_pop(&global_stack, NULL, 0);