From a1c12b9fb9bd2452a90d3cf504574b3605c09702 Mon Sep 17 00:00:00 2001 From: grischka Date: Sun, 18 Dec 2016 22:05:42 +0100 Subject: [PATCH] tests: add memory leak test Also ... tcctest.c: - exclude stuff that gcc doesn't compile on windows. libtcc.c/tccpp.c: - use unsigned for memory sizes to avoid printf format warnings - use "file:line: message" to make IDE error parsers happy. tccgen.c: fix typo --- libtcc.c | 23 +++++++++++++---------- tcc.h | 1 + tccgen.c | 13 +++++-------- tccpp.c | 35 +++++++++++++++++++---------------- tests/Makefile | 9 ++++++++- tests/tcctest.c | 8 +++++++- tests/tests2/Makefile | 2 +- 7 files changed, 54 insertions(+), 37 deletions(-) diff --git a/libtcc.c b/libtcc.c index 68c3f9d..41ebe2f 100644 --- a/libtcc.c +++ b/libtcc.c @@ -248,20 +248,20 @@ PUB_FUNC void tcc_memstats(int bench) #define MEM_DEBUG_FILE_LEN 15 struct mem_debug_header { - size_t magic1; - size_t size; + unsigned magic1; + unsigned size; struct mem_debug_header *prev; struct mem_debug_header *next; - size_t line_num; - char file_name[MEM_DEBUG_FILE_LEN + 1]; - size_t magic2; + int line_num; + char file_name[MEM_DEBUG_FILE_LEN + 1]; + unsigned magic2; }; typedef struct mem_debug_header mem_debug_header_t; static mem_debug_header_t *mem_debug_chain; -static size_t mem_cur_size; -static size_t mem_max_size; +static unsigned mem_cur_size; +static unsigned mem_max_size; PUB_FUNC void *tcc_malloc_debug(unsigned long size, const char *file, int line) { @@ -312,13 +312,13 @@ PUB_FUNC void tcc_free_debug(void *ptr) header = (mem_debug_header_t *)ptr; if (header->magic1 != MEM_DEBUG_MAGIC1 || header->magic2 != MEM_DEBUG_MAGIC2 || - header->size == (size_t)-1 ) + header->size == (unsigned)-1 ) { tcc_error("tcc_free check failed"); } mem_cur_size -= header->size; - header->size = (size_t)-1; + header->size = (unsigned)-1; if (header->next) header->next->prev = header->prev; @@ -355,7 +355,7 @@ PUB_FUNC void *tcc_realloc_debug(void *ptr, unsigned long size, const char *file header = (mem_debug_header_t *)ptr; if (header->magic1 != MEM_DEBUG_MAGIC1 || header->magic2 != MEM_DEBUG_MAGIC2 || - header->size == (size_t)-1 ) + header->size == (unsigned)-1 ) { check_error: tcc_error("tcc_realloc check failed"); @@ -414,6 +414,9 @@ PUB_FUNC void tcc_memstats(int bench) header->file_name, header->line_num, header->size); header = header->next; } +#if MEM_DEBUG-0 == 2 + exit(2); +#endif } else if (bench) fprintf(stderr, "mem_max_size= %d bytes\n", mem_max_size); diff --git a/tcc.h b/tcc.h index 9b65e6d..fcff9ee 100644 --- a/tcc.h +++ b/tcc.h @@ -71,6 +71,7 @@ # pragma warning (disable : 4996) // The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conformant name # pragma warning (disable : 4018) // signed/unsigned mismatch # pragma warning (disable : 4146) // unary minus operator applied to unsigned type, result still unsigned +# define ssize_t intptr_t # endif # undef CONFIG_TCC_STATIC #endif diff --git a/tccgen.c b/tccgen.c index a4a40f3..dddeea1 100644 --- a/tccgen.c +++ b/tccgen.c @@ -5288,8 +5288,8 @@ static void expr_cond(void) /* this is horrible, but we must also convert first operand */ - vpushv(&sv); - if (c != 2) { + if (c != 0) { + *vtop = sv; gen_cast(&type); if (islv) { mk_pointer(&vtop->type); @@ -5298,17 +5298,14 @@ static void expr_cond(void) gaddrof(); } - if (c != 0) - vswap(); - vtop--; if (c < 0) { r1 = gv(rc); move_reg(r2, r1, type.t); vtop->r = r2; + gsym(tt); + if (islv) + indir(); } - gsym(tt); - if (islv) - indir(); } } } diff --git a/tccpp.c b/tccpp.c index 6659812..05c122b 100644 --- a/tccpp.c +++ b/tccpp.c @@ -137,22 +137,22 @@ ST_FUNC void expect(const char *msg) #define CSTR_TAL_LIMIT 1024 typedef struct TinyAlloc { - size_t limit; - size_t size; + unsigned limit; + unsigned size; uint8_t *buffer; uint8_t *p; - size_t nb_allocs; + unsigned nb_allocs; struct TinyAlloc *next, *top; #ifdef TAL_INFO - size_t nb_peak; - size_t nb_total; - size_t nb_missed; + unsigned nb_peak; + unsigned nb_total; + unsigned nb_missed; uint8_t *peak_p; #endif } TinyAlloc; typedef struct tal_header_t { - size_t size; + unsigned size; #ifdef TAL_DEBUG int line_num; /* negative line_num used for double free check */ char file_name[TAL_DEBUG_FILE_LEN + 1]; @@ -161,7 +161,7 @@ typedef struct tal_header_t { /* ------------------------------------------------------------------------- */ -ST_FUNC TinyAlloc *tal_new(TinyAlloc **pal, size_t limit, size_t size) +static TinyAlloc *tal_new(TinyAlloc **pal, unsigned limit, unsigned size) { TinyAlloc *al = tcc_mallocz(sizeof(TinyAlloc)); al->p = al->buffer = tcc_malloc(size); @@ -171,7 +171,7 @@ ST_FUNC TinyAlloc *tal_new(TinyAlloc **pal, size_t limit, size_t size) return al; } -ST_FUNC void tal_delete(TinyAlloc *al) +static void tal_delete(TinyAlloc *al) { TinyAlloc *next; @@ -192,11 +192,14 @@ tail_call: while (p < al->p) { tal_header_t *header = (tal_header_t *)p; if (header->line_num > 0) { - fprintf(stderr, " file %s, line %u: %u bytes\n", + fprintf(stderr, "%s:%d: chunk of %d bytes\n", header->file_name, header->line_num, header->size); } p += header->size + sizeof(tal_header_t); } +#if MEM_DEBUG-0 == 2 + exit(2); +#endif } #endif next = al->next; @@ -206,7 +209,7 @@ tail_call: goto tail_call; } -ST_FUNC void tal_free_impl(TinyAlloc *al, void *p TAL_DEBUG_PARAMS) +static void tal_free_impl(TinyAlloc *al, void *p TAL_DEBUG_PARAMS) { if (!p) return; @@ -215,10 +218,10 @@ tail_call: #ifdef TAL_DEBUG tal_header_t *header = (((tal_header_t *)p) - 1); if (header->line_num < 0) { - fprintf(stderr, "TAL_DEBUG: file %s, line %u double frees chunk from\n", + fprintf(stderr, "%s:%d: TAL_DEBUG: double frees chunk from\n", file, line); - fprintf(stderr, " file %s, line %u: %u bytes\n", - header->file_name, -header->line_num, header->size); + fprintf(stderr, "%s:%d: %d bytes\n", + header->file_name, (int)-header->line_num, (int)header->size); } else header->line_num = -header->line_num; #endif @@ -233,12 +236,12 @@ tail_call: tcc_free(p); } -ST_FUNC void *tal_realloc_impl(TinyAlloc **pal, void *p, size_t size TAL_DEBUG_PARAMS) +static void *tal_realloc_impl(TinyAlloc **pal, void *p, unsigned size TAL_DEBUG_PARAMS) { tal_header_t *header; void *ret; int is_own; - size_t adj_size = (size + 3) & -4; + unsigned adj_size = (size + 3) & -4; TinyAlloc *al = *pal; tail_call: diff --git a/tests/Makefile b/tests/Makefile index a86e8a2..0cdca35 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -5,7 +5,7 @@ TOP = .. include $(TOP)/Makefile VPATH = $(TOPSRC)/tests $(TOPSRC) $(TOP) -CFLAGS = -I$(TOPSRC) -I$(TOP) +CFLAGS := $(filter-out -W% -g% -O%,$(CFLAGS)) -I$(TOPSRC) # what tests to run TESTS = \ @@ -13,6 +13,7 @@ TESTS = \ hello-run \ libtest \ test3 \ + memtest \ dlltest \ abitest \ vla_test-run \ @@ -145,6 +146,12 @@ ifndef CONFIG_WIN32 endif @rm tcc2$(EXESUF) libtcc2$(DLLSUF) +memtest: + @echo ------------ $@ ------------ + $(CC) $(CFLAGS) $(NATIVE_DEFINES) -DONE_SOURCE -DMEM_DEBUG=2 ../tcc.c $(LIBS) -o memtest-tcc$(EXESUF) + ./memtest-tcc$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES) -DONE_SOURCE ../tcc.c $(LIBS) + ./memtest-tcc$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES) -DONE_SOURCE -run ../tcc.c $(TCCFLAGS) tcctest.c + # memory and bound check auto test BOUNDS_OK = 1 4 8 10 14 diff --git a/tests/tcctest.c b/tests/tcctest.c index 0f71482..2789255 100644 --- a/tests/tcctest.c +++ b/tests/tcctest.c @@ -3122,6 +3122,7 @@ void other_constraints_test(void) printf ("oc1: %d\n", ret == (unsigned long)&var); } +#ifndef _WIN32 /* Test global asm blocks playing with aliases. */ void base_func(void) { @@ -3161,6 +3162,7 @@ char * get_asm_string (void) char * str = ((char*)bug_table) + bug_table[1]; return str; } +#endif unsigned int set; @@ -3301,12 +3303,15 @@ void asm_test(void) printf("set=0x%x\n", set); val = 0x01020304; printf("swab32(0x%08x) = 0x%0x\n", val, swab32(val)); +#ifndef _WIN32 override_func1(); override_func2(); /* The base_func ref from the following inline asm should find the global one, not the local decl from this function. */ asm volatile(".weak override_func3\n.set override_func3, base_func"); override_func3(); + printf("asmstr: %s\n", get_asm_string()); +#endif /* Check that we can also load structs of appropriate layout into registers. */ asm volatile("" : "=r" (asmret) : "0"(s2)); @@ -3319,7 +3324,6 @@ void asm_test(void) if (!somebool) printf("asmbool: failed\n"); #endif - printf("asmstr: %s\n", get_asm_string()); val = 43; fancy_copy (&val, &val2); printf ("fancycpy(%d)=%d\n", val, val2); @@ -3677,10 +3681,12 @@ typedef struct gate_struct64 gate_desc; gate_desc a_gate_desc; void attrib_test(void) { +#ifndef _WIN32 printf("attr: %d %d %d %d\n", sizeof(struct Spacked), sizeof(spacked), sizeof(Spacked2), sizeof(spacked2)); printf("attr: %d %d\n", sizeof(Spacked3), sizeof(spacked3)); printf("attr: %d %d\n", sizeof(gate_desc), sizeof(a_gate_desc)); +#endif } extern __attribute__((__unused__)) char * __attribute__((__unused__)) * strange_attrib_placement (void); diff --git a/tests/tests2/Makefile b/tests/tests2/Makefile index 166fb2a..ababb43 100644 --- a/tests/tests2/Makefile +++ b/tests/tests2/Makefile @@ -63,7 +63,7 @@ all test: $(filter-out $(SKIP),$(TESTS)) # automatically generate .expect files with gcc: %.expect : %.c - (gcc -w $*.c -o a.exe && ./a.exe $(ARGS)) >$*.expect 2>&1; rm -f a.exe + (gcc -w $*.c -o a.exe && ./a.exe $(ARGS)) $(FILTER) >$*.expect 2>&1; rm -f a.exe # tell make not to delete .PRECIOUS: %.expect