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
master
grischka 2016-12-18 22:05:42 +01:00
parent f7fc4f02cf
commit a1c12b9fb9
7 changed files with 54 additions and 37 deletions

View File

@ -248,20 +248,20 @@ PUB_FUNC void tcc_memstats(int bench)
#define MEM_DEBUG_FILE_LEN 15 #define MEM_DEBUG_FILE_LEN 15
struct mem_debug_header { struct mem_debug_header {
size_t magic1; unsigned magic1;
size_t size; unsigned size;
struct mem_debug_header *prev; struct mem_debug_header *prev;
struct mem_debug_header *next; struct mem_debug_header *next;
size_t line_num; int line_num;
char file_name[MEM_DEBUG_FILE_LEN + 1]; char file_name[MEM_DEBUG_FILE_LEN + 1];
size_t magic2; unsigned magic2;
}; };
typedef struct mem_debug_header mem_debug_header_t; typedef struct mem_debug_header mem_debug_header_t;
static mem_debug_header_t *mem_debug_chain; static mem_debug_header_t *mem_debug_chain;
static size_t mem_cur_size; static unsigned mem_cur_size;
static size_t mem_max_size; static unsigned mem_max_size;
PUB_FUNC void *tcc_malloc_debug(unsigned long size, const char *file, int line) 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; header = (mem_debug_header_t *)ptr;
if (header->magic1 != MEM_DEBUG_MAGIC1 || if (header->magic1 != MEM_DEBUG_MAGIC1 ||
header->magic2 != MEM_DEBUG_MAGIC2 || header->magic2 != MEM_DEBUG_MAGIC2 ||
header->size == (size_t)-1 ) header->size == (unsigned)-1 )
{ {
tcc_error("tcc_free check failed"); tcc_error("tcc_free check failed");
} }
mem_cur_size -= header->size; mem_cur_size -= header->size;
header->size = (size_t)-1; header->size = (unsigned)-1;
if (header->next) if (header->next)
header->next->prev = header->prev; 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; header = (mem_debug_header_t *)ptr;
if (header->magic1 != MEM_DEBUG_MAGIC1 || if (header->magic1 != MEM_DEBUG_MAGIC1 ||
header->magic2 != MEM_DEBUG_MAGIC2 || header->magic2 != MEM_DEBUG_MAGIC2 ||
header->size == (size_t)-1 ) header->size == (unsigned)-1 )
{ {
check_error: check_error:
tcc_error("tcc_realloc check failed"); 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->file_name, header->line_num, header->size);
header = header->next; header = header->next;
} }
#if MEM_DEBUG-0 == 2
exit(2);
#endif
} }
else if (bench) else if (bench)
fprintf(stderr, "mem_max_size= %d bytes\n", mem_max_size); fprintf(stderr, "mem_max_size= %d bytes\n", mem_max_size);

1
tcc.h
View File

@ -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 : 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 : 4018) // signed/unsigned mismatch
# pragma warning (disable : 4146) // unary minus operator applied to unsigned type, result still unsigned # pragma warning (disable : 4146) // unary minus operator applied to unsigned type, result still unsigned
# define ssize_t intptr_t
# endif # endif
# undef CONFIG_TCC_STATIC # undef CONFIG_TCC_STATIC
#endif #endif

View File

@ -5288,8 +5288,8 @@ static void expr_cond(void)
/* this is horrible, but we must also convert first /* this is horrible, but we must also convert first
operand */ operand */
vpushv(&sv); if (c != 0) {
if (c != 2) { *vtop = sv;
gen_cast(&type); gen_cast(&type);
if (islv) { if (islv) {
mk_pointer(&vtop->type); mk_pointer(&vtop->type);
@ -5298,17 +5298,14 @@ static void expr_cond(void)
gaddrof(); gaddrof();
} }
if (c != 0)
vswap();
vtop--;
if (c < 0) { if (c < 0) {
r1 = gv(rc); r1 = gv(rc);
move_reg(r2, r1, type.t); move_reg(r2, r1, type.t);
vtop->r = r2; vtop->r = r2;
gsym(tt);
if (islv)
indir();
} }
gsym(tt);
if (islv)
indir();
} }
} }
} }

35
tccpp.c
View File

@ -137,22 +137,22 @@ ST_FUNC void expect(const char *msg)
#define CSTR_TAL_LIMIT 1024 #define CSTR_TAL_LIMIT 1024
typedef struct TinyAlloc { typedef struct TinyAlloc {
size_t limit; unsigned limit;
size_t size; unsigned size;
uint8_t *buffer; uint8_t *buffer;
uint8_t *p; uint8_t *p;
size_t nb_allocs; unsigned nb_allocs;
struct TinyAlloc *next, *top; struct TinyAlloc *next, *top;
#ifdef TAL_INFO #ifdef TAL_INFO
size_t nb_peak; unsigned nb_peak;
size_t nb_total; unsigned nb_total;
size_t nb_missed; unsigned nb_missed;
uint8_t *peak_p; uint8_t *peak_p;
#endif #endif
} TinyAlloc; } TinyAlloc;
typedef struct tal_header_t { typedef struct tal_header_t {
size_t size; unsigned size;
#ifdef TAL_DEBUG #ifdef TAL_DEBUG
int line_num; /* negative line_num used for double free check */ int line_num; /* negative line_num used for double free check */
char file_name[TAL_DEBUG_FILE_LEN + 1]; 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)); TinyAlloc *al = tcc_mallocz(sizeof(TinyAlloc));
al->p = al->buffer = tcc_malloc(size); 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; return al;
} }
ST_FUNC void tal_delete(TinyAlloc *al) static void tal_delete(TinyAlloc *al)
{ {
TinyAlloc *next; TinyAlloc *next;
@ -192,11 +192,14 @@ tail_call:
while (p < al->p) { while (p < al->p) {
tal_header_t *header = (tal_header_t *)p; tal_header_t *header = (tal_header_t *)p;
if (header->line_num > 0) { 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); header->file_name, header->line_num, header->size);
} }
p += header->size + sizeof(tal_header_t); p += header->size + sizeof(tal_header_t);
} }
#if MEM_DEBUG-0 == 2
exit(2);
#endif
} }
#endif #endif
next = al->next; next = al->next;
@ -206,7 +209,7 @@ tail_call:
goto 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) if (!p)
return; return;
@ -215,10 +218,10 @@ tail_call:
#ifdef TAL_DEBUG #ifdef TAL_DEBUG
tal_header_t *header = (((tal_header_t *)p) - 1); tal_header_t *header = (((tal_header_t *)p) - 1);
if (header->line_num < 0) { 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); file, line);
fprintf(stderr, " file %s, line %u: %u bytes\n", fprintf(stderr, "%s:%d: %d bytes\n",
header->file_name, -header->line_num, header->size); header->file_name, (int)-header->line_num, (int)header->size);
} else } else
header->line_num = -header->line_num; header->line_num = -header->line_num;
#endif #endif
@ -233,12 +236,12 @@ tail_call:
tcc_free(p); 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; tal_header_t *header;
void *ret; void *ret;
int is_own; int is_own;
size_t adj_size = (size + 3) & -4; unsigned adj_size = (size + 3) & -4;
TinyAlloc *al = *pal; TinyAlloc *al = *pal;
tail_call: tail_call:

View File

@ -5,7 +5,7 @@
TOP = .. TOP = ..
include $(TOP)/Makefile include $(TOP)/Makefile
VPATH = $(TOPSRC)/tests $(TOPSRC) $(TOP) VPATH = $(TOPSRC)/tests $(TOPSRC) $(TOP)
CFLAGS = -I$(TOPSRC) -I$(TOP) CFLAGS := $(filter-out -W% -g% -O%,$(CFLAGS)) -I$(TOPSRC)
# what tests to run # what tests to run
TESTS = \ TESTS = \
@ -13,6 +13,7 @@ TESTS = \
hello-run \ hello-run \
libtest \ libtest \
test3 \ test3 \
memtest \
dlltest \ dlltest \
abitest \ abitest \
vla_test-run \ vla_test-run \
@ -145,6 +146,12 @@ ifndef CONFIG_WIN32
endif endif
@rm tcc2$(EXESUF) libtcc2$(DLLSUF) @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 # memory and bound check auto test
BOUNDS_OK = 1 4 8 10 14 BOUNDS_OK = 1 4 8 10 14

View File

@ -3122,6 +3122,7 @@ void other_constraints_test(void)
printf ("oc1: %d\n", ret == (unsigned long)&var); printf ("oc1: %d\n", ret == (unsigned long)&var);
} }
#ifndef _WIN32
/* Test global asm blocks playing with aliases. */ /* Test global asm blocks playing with aliases. */
void base_func(void) void base_func(void)
{ {
@ -3161,6 +3162,7 @@ char * get_asm_string (void)
char * str = ((char*)bug_table) + bug_table[1]; char * str = ((char*)bug_table) + bug_table[1];
return str; return str;
} }
#endif
unsigned int set; unsigned int set;
@ -3301,12 +3303,15 @@ void asm_test(void)
printf("set=0x%x\n", set); printf("set=0x%x\n", set);
val = 0x01020304; val = 0x01020304;
printf("swab32(0x%08x) = 0x%0x\n", val, swab32(val)); printf("swab32(0x%08x) = 0x%0x\n", val, swab32(val));
#ifndef _WIN32
override_func1(); override_func1();
override_func2(); override_func2();
/* The base_func ref from the following inline asm should find /* The base_func ref from the following inline asm should find
the global one, not the local decl from this function. */ the global one, not the local decl from this function. */
asm volatile(".weak override_func3\n.set override_func3, base_func"); asm volatile(".weak override_func3\n.set override_func3, base_func");
override_func3(); override_func3();
printf("asmstr: %s\n", get_asm_string());
#endif
/* Check that we can also load structs of appropriate layout /* Check that we can also load structs of appropriate layout
into registers. */ into registers. */
asm volatile("" : "=r" (asmret) : "0"(s2)); asm volatile("" : "=r" (asmret) : "0"(s2));
@ -3319,7 +3324,6 @@ void asm_test(void)
if (!somebool) if (!somebool)
printf("asmbool: failed\n"); printf("asmbool: failed\n");
#endif #endif
printf("asmstr: %s\n", get_asm_string());
val = 43; val = 43;
fancy_copy (&val, &val2); fancy_copy (&val, &val2);
printf ("fancycpy(%d)=%d\n", val, val2); printf ("fancycpy(%d)=%d\n", val, val2);
@ -3677,10 +3681,12 @@ typedef struct gate_struct64 gate_desc;
gate_desc a_gate_desc; gate_desc a_gate_desc;
void attrib_test(void) void attrib_test(void)
{ {
#ifndef _WIN32
printf("attr: %d %d %d %d\n", sizeof(struct Spacked), printf("attr: %d %d %d %d\n", sizeof(struct Spacked),
sizeof(spacked), sizeof(Spacked2), sizeof(spacked2)); sizeof(spacked), sizeof(Spacked2), sizeof(spacked2));
printf("attr: %d %d\n", sizeof(Spacked3), sizeof(spacked3)); printf("attr: %d %d\n", sizeof(Spacked3), sizeof(spacked3));
printf("attr: %d %d\n", sizeof(gate_desc), sizeof(a_gate_desc)); printf("attr: %d %d\n", sizeof(gate_desc), sizeof(a_gate_desc));
#endif
} }
extern __attribute__((__unused__)) char * __attribute__((__unused__)) * extern __attribute__((__unused__)) char * __attribute__((__unused__)) *
strange_attrib_placement (void); strange_attrib_placement (void);

View File

@ -63,7 +63,7 @@ all test: $(filter-out $(SKIP),$(TESTS))
# automatically generate .expect files with gcc: # automatically generate .expect files with gcc:
%.expect : %.c %.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 # tell make not to delete
.PRECIOUS: %.expect .PRECIOUS: %.expect