mirror of
https://github.com/mirror/tinycc.git
synced 2025-01-27 06:10:06 +08:00
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
This commit is contained in:
parent
f7fc4f02cf
commit
a1c12b9fb9
23
libtcc.c
23
libtcc.c
@ -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
1
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 : 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
|
||||||
|
13
tccgen.c
13
tccgen.c
@ -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
35
tccpp.c
@ -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:
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user