Add setjmp/longjmp bound checking support

tcctok.h:
- Add __bound_setjmp/setjmp/_setjmp/longjmp

tccgen.c:
- redirect setjmp/longjmp to bcheck.c code

i386-gen.c/x86_64-gen.c
- Change func_bound_alloca_used into func_bound_add_epilog
- Set func_bound_add_epilog also when setjmp is called

bcheck.c:
- Add __bound_setjmp/__bound_longjmp
- __bound_local_delete: remove setjmp if used in function
- __bound_exit: clear setjmp list and print statistic
- make malloc_redir more readable (unrelated)

New testcases:
- 115_bound_setjmp
- 116_bound_setjmp2
This commit is contained in:
herman ten brugge 2020-05-23 20:02:41 +02:00
parent 4429cef9f6
commit b5b92c7d6d
10 changed files with 509 additions and 108 deletions

View file

@ -97,7 +97,7 @@ static int func_ret_sub;
#ifdef CONFIG_TCC_BCHECK #ifdef CONFIG_TCC_BCHECK
static addr_t func_bound_offset; static addr_t func_bound_offset;
static unsigned long func_bound_ind; static unsigned long func_bound_ind;
static int func_bound_alloca_used; static int func_bound_add_epilog;
static void gen_bounds_prolog(void); static void gen_bounds_prolog(void);
static void gen_bounds_epilog(void); static void gen_bounds_epilog(void);
#endif #endif
@ -359,8 +359,11 @@ static void gcall_or_jmp(int is_jmp)
greloc(cur_text_section, vtop->sym, ind + 1, R_386_PC32); greloc(cur_text_section, vtop->sym, ind + 1, R_386_PC32);
oad(0xe8 + is_jmp, vtop->c.i - 4); /* call/jmp im */ oad(0xe8 + is_jmp, vtop->c.i - 4); /* call/jmp im */
#ifdef CONFIG_TCC_BCHECK #ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check && vtop->sym->v == TOK_alloca) if (tcc_state->do_bounds_check &&
func_bound_alloca_used = 1; (vtop->sym->v == TOK_alloca ||
vtop->sym->v == TOK_setjmp ||
vtop->sym->v == TOK__setjmp))
func_bound_add_epilog = 1;
#endif #endif
} else { } else {
/* otherwise, indirect call */ /* otherwise, indirect call */
@ -1069,7 +1072,7 @@ static void gen_bounds_prolog(void)
/* leave some room for bound checking code */ /* leave some room for bound checking code */
func_bound_offset = lbounds_section->data_offset; func_bound_offset = lbounds_section->data_offset;
func_bound_ind = ind; func_bound_ind = ind;
func_bound_alloca_used = 0; func_bound_add_epilog = 0;
oad(0xb8, 0); /* lbound section pointer */ oad(0xb8, 0); /* lbound section pointer */
oad(0xb8, 0); /* call to function */ oad(0xb8, 0); /* call to function */
} }
@ -1080,7 +1083,7 @@ static void gen_bounds_epilog(void)
addr_t *bounds_ptr; addr_t *bounds_ptr;
Sym *sym_data; Sym *sym_data;
if (func_bound_offset == lbounds_section->data_offset && !func_bound_alloca_used) if (func_bound_offset == lbounds_section->data_offset && !func_bound_add_epilog)
return; return;
/* add end of table info */ /* add end of table info */

View file

@ -21,6 +21,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdarg.h> #include <stdarg.h>
#include <string.h> #include <string.h>
#include <setjmp.h>
#if !defined(__FreeBSD__) \ #if !defined(__FreeBSD__) \
&& !defined(__FreeBSD_kernel__) \ && !defined(__FreeBSD_kernel__) \
@ -32,6 +33,7 @@
#if !defined(_WIN32) #if !defined(_WIN32)
#include <unistd.h> #include <unistd.h>
#include <sys/syscall.h>
#endif #endif
#define BOUND_DEBUG (1) #define BOUND_DEBUG (1)
@ -158,6 +160,25 @@ typedef struct alloca_list_struct {
struct alloca_list_struct *next; struct alloca_list_struct *next;
} alloca_list_type; } alloca_list_type;
#if defined(_WIN32)
#define BOUND_TID_TYPE DWORD
#define BOUND_GET_TID GetCurrentThreadId()
#elif defined(__i386__) || defined(__x86_64__)
#define BOUND_TID_TYPE pid_t
#define BOUND_GET_TID syscall (SYS_gettid)
#else
#define BOUND_TID_TYPE int
#define BOUND_GET_TID 0
#endif
typedef struct jmp_list_struct {
void *penv;
size_t fp;
size_t end_fp;
BOUND_TID_TYPE tid;
struct jmp_list_struct *next;
} jmp_list_type;
#define BOUND_STATISTIC_SPLAY (0) #define BOUND_STATISTIC_SPLAY (0)
static Tree * splay (size_t addr, Tree *t); static Tree * splay (size_t addr, Tree *t);
static Tree * splay_end (size_t addr, Tree *t); static Tree * splay_end (size_t addr, Tree *t);
@ -186,6 +207,8 @@ void *__bound_mmap (void *start, size_t size, int prot, int flags, int fd,
int __bound_munmap (void *start, size_t size); int __bound_munmap (void *start, size_t size);
#endif #endif
DLL_EXPORT void __bound_new_region(void *p, size_t size); DLL_EXPORT void __bound_new_region(void *p, size_t size);
DLL_EXPORT void __bound_setjmp(jmp_buf env);
DLL_EXPORT void __bound_longjmp(jmp_buf env, int val);
DLL_EXPORT void *__bound_memcpy(void *dst, const void *src, size_t size); DLL_EXPORT void *__bound_memcpy(void *dst, const void *src, size_t size);
DLL_EXPORT int __bound_memcmp(const void *s1, const void *s2, size_t size); DLL_EXPORT int __bound_memcmp(const void *s1, const void *s2, size_t size);
DLL_EXPORT void *__bound_memmove(void *dst, const void *src, size_t size); DLL_EXPORT void *__bound_memmove(void *dst, const void *src, size_t size);
@ -199,7 +222,18 @@ DLL_EXPORT char *__bound_strcat(char *dest, const char *src);
DLL_EXPORT char *__bound_strchr(const char *string, int ch); DLL_EXPORT char *__bound_strchr(const char *string, int ch);
DLL_EXPORT char *__bound_strdup(const char *s); DLL_EXPORT char *__bound_strdup(const char *s);
#if !MALLOC_REDIR #if MALLOC_REDIR
#define BOUND_MALLOC(a) malloc_redir(a)
#define BOUND_MEMALIGN(a,b) memalign_redir(a,b)
#define BOUND_FREE(a) free_redir(a)
#define BOUND_REALLOC(a,b) realloc_redir(a,b)
#define BOUND_CALLOC(a,b) calloc_redir(a,b)
#else
#define BOUND_MALLOC(a) malloc(a)
#define BOUND_MEMALIGN(a,b) memalign(a,b)
#define BOUND_FREE(a) free(a)
#define BOUND_REALLOC(a,b) realloc(a,b)
#define BOUND_CALLOC(a,b) calloc(a,b)
DLL_EXPORT void *__bound_malloc(size_t size, const void *caller); DLL_EXPORT void *__bound_malloc(size_t size, const void *caller);
DLL_EXPORT void *__bound_memalign(size_t size, size_t align, const void *caller); DLL_EXPORT void *__bound_memalign(size_t size, size_t align, const void *caller);
DLL_EXPORT void __bound_free(void *ptr, const void *caller); DLL_EXPORT void __bound_free(void *ptr, const void *caller);
@ -217,6 +251,7 @@ static Tree *tree = NULL;
static Tree *tree_free_list; static Tree *tree_free_list;
#endif #endif
static alloca_list_type *alloca_list; static alloca_list_type *alloca_list;
static jmp_list_type *jmp_list;
static unsigned char inited; static unsigned char inited;
static unsigned char print_warn_ptr_add; static unsigned char print_warn_ptr_add;
@ -246,6 +281,8 @@ static unsigned long long bound_memalign_count;
static unsigned long long bound_mmap_count; static unsigned long long bound_mmap_count;
static unsigned long long bound_munmap_count; static unsigned long long bound_munmap_count;
static unsigned long long bound_alloca_count; static unsigned long long bound_alloca_count;
static unsigned long long bound_setjmp_count;
static unsigned long long bound_longjmp_count;
static unsigned long long bound_mempcy_count; static unsigned long long bound_mempcy_count;
static unsigned long long bound_memcmp_count; static unsigned long long bound_memcmp_count;
static unsigned long long bound_memmove_count; static unsigned long long bound_memmove_count;
@ -473,7 +510,8 @@ void FASTCALL __bound_local_new(void *p1)
void FASTCALL __bound_local_delete(void *p1) void FASTCALL __bound_local_delete(void *p1)
{ {
size_t addr, fp, *p = p1; size_t addr, fp, *p = p1;
alloca_list_type *free_list = NULL; alloca_list_type *alloca_free_list = NULL;
jmp_list_type *jmp_free_list = NULL;
if (no_checking) if (no_checking)
return; return;
@ -487,39 +525,63 @@ void FASTCALL __bound_local_delete(void *p1)
p += 2; p += 2;
} }
{ {
alloca_list_type *last = NULL; alloca_list_type *last = NULL;
alloca_list_type *cur = alloca_list; alloca_list_type *cur = alloca_list;
while (cur) { while (cur) {
if (cur->fp == fp) { if (cur->fp == fp) {
if (last) if (last)
last->next = cur->next; last->next = cur->next;
else else
alloca_list = cur->next; alloca_list = cur->next;
tree = splay_delete ((size_t) cur->p, tree); tree = splay_delete ((size_t) cur->p, tree);
cur->next = free_list; cur->next = alloca_free_list;
free_list = cur; alloca_free_list = cur;
cur = last ? last->next : alloca_list; cur = last ? last->next : alloca_list;
} }
else { else {
last = cur; last = cur;
cur = cur->next; cur = cur->next;
} }
}
}
{
jmp_list_type *last = NULL;
jmp_list_type *cur = jmp_list;
while (cur) {
if (cur->fp == fp) {
if (last)
last->next = cur->next;
else
jmp_list = cur->next;
cur->next = jmp_free_list;
jmp_free_list = cur;
cur = last ? last->next : jmp_list;
} }
else {
last = cur;
cur = cur->next;
}
}
} }
POST_SEM (); POST_SEM ();
while (free_list) { while (alloca_free_list) {
alloca_list_type *next = free_list->next; alloca_list_type *next = alloca_free_list->next;
dprintf(stderr, "%s, %s(): remove alloca/vla %p\n", dprintf(stderr, "%s, %s(): remove alloca/vla %p\n",
__FILE__, __FUNCTION__, free_list->p); __FILE__, __FUNCTION__, alloca_free_list->p);
#if MALLOC_REDIR BOUND_FREE (alloca_free_list);
free_redir (free_list); alloca_free_list = next;
#else }
free (free_list); while (jmp_free_list) {
#endif jmp_list_type *next = jmp_free_list->next;
free_list = next;
dprintf(stderr, "%s, %s(): remove setjmp %p\n",
__FILE__, __FUNCTION__, jmp_free_list->penv);
BOUND_FREE (jmp_free_list);
jmp_free_list = next;
} }
#if BOUND_DEBUG #if BOUND_DEBUG
if (print_calls) { if (print_calls) {
@ -547,11 +609,7 @@ void __bound_new_region(void *p, size_t size)
dprintf(stderr, "%s, %s(): %p, 0x%lx\n", dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
__FILE__, __FUNCTION__, p, (unsigned long)size); __FILE__, __FUNCTION__, p, (unsigned long)size);
GET_CALLER_FP (fp); GET_CALLER_FP (fp);
#if MALLOC_REDIR new = BOUND_MALLOC (sizeof (alloca_list_type));
new = malloc_redir (sizeof (alloca_list_type));
#else
new = malloc (sizeof (alloca_list_type));
#endif
WAIT_SEM (); WAIT_SEM ();
INCR_COUNT(bound_alloca_count); INCR_COUNT(bound_alloca_count);
last = NULL; last = NULL;
@ -580,14 +638,116 @@ void __bound_new_region(void *p, size_t size)
if (cur) { if (cur) {
dprintf(stderr, "%s, %s(): remove alloca/vla %p\n", dprintf(stderr, "%s, %s(): remove alloca/vla %p\n",
__FILE__, __FUNCTION__, cur->p); __FILE__, __FUNCTION__, cur->p);
#if MALLOC_REDIR BOUND_FREE (cur);
free_redir (cur);
#else
free (cur);
#endif
} }
} }
void __bound_setjmp(jmp_buf env)
{
jmp_list_type *jl;
void *e = (void *) env;
dprintf(stderr, "%s, %s(): %p\n", __FILE__, __FUNCTION__, e);
WAIT_SEM ();
INCR_COUNT(bound_setjmp_count);
jl = jmp_list;
while (jl) {
if (jl->penv == e)
break;
jl = jl->next;
}
if (jl == NULL) {
jl = BOUND_MALLOC (sizeof (jmp_list_type));
if (jl) {
jl->penv = e;
jl->next = jmp_list;
jmp_list = jl;
}
}
if (jl) {
size_t fp;
GET_CALLER_FP (fp);
jl->fp = fp;
jl->end_fp = (size_t)__builtin_frame_address(0);
jl->tid = BOUND_GET_TID;
}
POST_SEM ();
}
void __bound_longjmp(jmp_buf env, int val)
{
jmp_list_type *jl;
void *e = (void *)env;
BOUND_TID_TYPE tid = BOUND_GET_TID;
dprintf(stderr, "%s, %s(): %p\n", __FILE__, __FUNCTION__, e);
WAIT_SEM();
INCR_COUNT(bound_longjmp_count);
jl = jmp_list;
while (jl) {
if (jl->penv == e && jl->tid == tid) {
size_t start_fp = (size_t)__builtin_frame_address(0);
size_t end_fp = jl->end_fp;
jmp_list_type *cur = jmp_list;
jmp_list_type *last = NULL;
while (cur->penv != e || cur->tid != tid) {
if (cur->tid == tid) {
dprintf(stderr, "%s, %s(): remove setjmp %p\n",
__FILE__, __FUNCTION__, cur->penv);
if (last)
last->next = cur->next;
else
jmp_list = cur->next;
BOUND_FREE (cur);
cur = last ? last->next : jmp_list;
}
else {
last = cur;
cur = cur->next;
}
}
for (;;) {
Tree *t = tree;
alloca_list_type *last;
alloca_list_type *cur;
while (t && (t->start < start_fp || t->start > end_fp))
if (t->start < start_fp)
t = t->right;
else
t = t->left;
if (t == NULL)
break;
last = NULL;
cur = alloca_list;
while (cur) {
if ((size_t) cur->p == t->start) {
dprintf(stderr, "%s, %s(): remove alloca/vla %p\n",
__FILE__, __FUNCTION__, cur->p);
if (last)
last->next = cur->next;
else
alloca_list = cur->next;
BOUND_FREE (cur);
break;
}
last = cur;
cur = cur->next;
}
dprintf(stderr, "%s, %s(): delete %p\n",
__FILE__, __FUNCTION__, (void *) t->start);
tree = splay_delete(t->start, tree);
}
break;
}
jl = jl->next;
}
POST_SEM();
longjmp (env, val);
}
#if defined(__GNUC__) && (__GNUC__ >= 6) #if defined(__GNUC__) && (__GNUC__ >= 6)
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#endif #endif
@ -811,21 +971,19 @@ void __attribute__((destructor)) __bound_exit(void)
alloca_list_type *next = alloca_list->next; alloca_list_type *next = alloca_list->next;
tree = splay_delete ((size_t) alloca_list->p, tree); tree = splay_delete ((size_t) alloca_list->p, tree);
#if MALLOC_REDIR BOUND_FREE (alloca_list);
free_redir (alloca_list);
#else
free (alloca_list);
#endif
alloca_list = next; alloca_list = next;
} }
while (jmp_list) {
jmp_list_type *next = jmp_list->next;
BOUND_FREE (jmp_list);
jmp_list = next;
}
for (i = 0; i < FREE_REUSE_SIZE; i++) { for (i = 0; i < FREE_REUSE_SIZE; i++) {
if (free_reuse_list[i]) { if (free_reuse_list[i]) {
tree = splay_delete ((size_t) free_reuse_list[i], tree); tree = splay_delete ((size_t) free_reuse_list[i], tree);
#if MALLOC_REDIR BOUND_FREE (free_reuse_list[i]);
free_redir (free_reuse_list[i]);
#else
free (free_reuse_list[i]);
#endif
} }
} }
while (tree) { while (tree) {
@ -838,11 +996,7 @@ void __attribute__((destructor)) __bound_exit(void)
#if TREE_REUSE #if TREE_REUSE
while (tree_free_list) { while (tree_free_list) {
Tree *next = tree_free_list->left; Tree *next = tree_free_list->left;
#if MALLOC_REDIR BOUND_FREE (tree_free_list);
free_redir (tree_free_list);
#else
free (tree_free_list);
#endif
tree_free_list = next; tree_free_list = next;
} }
#endif #endif
@ -868,6 +1022,8 @@ void __attribute__((destructor)) __bound_exit(void)
fprintf (stderr, "bound_mmap_count %llu\n", bound_mmap_count); fprintf (stderr, "bound_mmap_count %llu\n", bound_mmap_count);
fprintf (stderr, "bound_munmap_count %llu\n", bound_munmap_count); fprintf (stderr, "bound_munmap_count %llu\n", bound_munmap_count);
fprintf (stderr, "bound_alloca_count %llu\n", bound_alloca_count); fprintf (stderr, "bound_alloca_count %llu\n", bound_alloca_count);
fprintf (stderr, "bound_setjmp_count %llu\n", bound_setjmp_count);
fprintf (stderr, "bound_longjmp_count %llu\n", bound_longjmp_count);
fprintf (stderr, "bound_mempcy_count %llu\n", bound_mempcy_count); fprintf (stderr, "bound_mempcy_count %llu\n", bound_mempcy_count);
fprintf (stderr, "bound_memcmp_count %llu\n", bound_memcmp_count); fprintf (stderr, "bound_memcmp_count %llu\n", bound_memcmp_count);
fprintf (stderr, "bound_memmove_count %llu\n", bound_memmove_count); fprintf (stderr, "bound_memmove_count %llu\n", bound_memmove_count);
@ -928,11 +1084,7 @@ void *__bound_malloc(size_t size, const void *caller)
/* we allocate one more byte to ensure the regions will be /* we allocate one more byte to ensure the regions will be
separated by at least one byte. With the glibc malloc, it may separated by at least one byte. With the glibc malloc, it may
be in fact not necessary */ be in fact not necessary */
#if MALLOC_REDIR ptr = BOUND_MALLOC (size + 1);
ptr = malloc_redir (size + 1);
#else
ptr = malloc(size + 1);
#endif
dprintf(stderr, "%s, %s(): %p, 0x%lx\n", dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
__FILE__, __FUNCTION__, ptr, (unsigned long)size); __FILE__, __FUNCTION__, ptr, (unsigned long)size);
@ -962,22 +1114,14 @@ void *__bound_memalign(size_t size, size_t align, const void *caller)
/* we allocate one more byte to ensure the regions will be /* we allocate one more byte to ensure the regions will be
separated by at least one byte. With the glibc malloc, it may separated by at least one byte. With the glibc malloc, it may
be in fact not necessary */ be in fact not necessary */
#if MALLOC_REDIR ptr = BOUND_MEMALIGN(size + 1, align);
ptr = memalign_redir(size + 1, align);
#else
ptr = memalign(size + 1, align);
#endif
#else #else
if (align > 4) { if (align > 4) {
/* XXX: handle it ? */ /* XXX: handle it ? */
ptr = NULL; ptr = NULL;
} else { } else {
/* we suppose that malloc aligns to at least four bytes */ /* we suppose that malloc aligns to at least four bytes */
#if MALLOC_REDIR ptr = BOUND_MALLOC(size + 1);
ptr = malloc_redir(size + 1);
#else
ptr = malloc(size + 1);
#endif
} }
#endif #endif
dprintf(stderr, "%s, %s(): %p, 0x%lx\n", dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
@ -1035,11 +1179,7 @@ void __bound_free(void *ptr, const void *caller)
ptr = p; ptr = p;
} }
POST_SEM (); POST_SEM ();
#if MALLOC_REDIR BOUND_FREE (ptr);
free_redir (ptr);
#else
free(ptr);
#endif
} }
#if MALLOC_REDIR #if MALLOC_REDIR
@ -1059,11 +1199,7 @@ void *__bound_realloc(void *ptr, size_t size, const void *caller)
return NULL; return NULL;
} }
#if MALLOC_REDIR new_ptr = BOUND_REALLOC (ptr, size);
new_ptr = realloc_redir (ptr, size);
#else
new_ptr = realloc (ptr, size);
#endif
dprintf(stderr, "%s, %s(): %p, 0x%lx\n", dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
__FILE__, __FUNCTION__, new_ptr, (unsigned long)size); __FILE__, __FUNCTION__, new_ptr, (unsigned long)size);
@ -1108,11 +1244,7 @@ void *__bound_calloc(size_t nmemb, size_t size)
} }
} }
#endif #endif
#if MALLOC_REDIR ptr = BOUND_MALLOC(size + 1);
ptr = malloc_redir(size + 1);
#else
ptr = malloc(size + 1);
#endif
dprintf (stderr, "%s, %s(): %p, 0x%lx\n", dprintf (stderr, "%s, %s(): %p, 0x%lx\n",
__FILE__, __FUNCTION__, ptr, (unsigned long)size); __FILE__, __FUNCTION__, ptr, (unsigned long)size);
@ -1377,11 +1509,7 @@ char *__bound_strdup(const char *s)
INCR_COUNT(bound_strdup_count); INCR_COUNT(bound_strdup_count);
while (*p++); while (*p++);
__bound_check(s, p - s, "strdup"); __bound_check(s, p - s, "strdup");
#if MALLOC_REDIR new = BOUND_MALLOC ((p - s) + 1);
new = malloc_redir ((p - s) + 1);
#else
new = malloc ((p - s) + 1);
#endif
dprintf(stderr, "%s, %s(): %p, 0x%lx\n", dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
__FILE__, __FUNCTION__, new, (unsigned long)(p -s)); __FILE__, __FUNCTION__, new, (unsigned long)(p -s));
if (new) { if (new) {
@ -1574,11 +1702,7 @@ static Tree * splay_insert(size_t addr, size_t size, Tree * t)
else else
#endif #endif
{ {
#if MALLOC_REDIR new = (Tree *) BOUND_MALLOC (sizeof (Tree));
new = (Tree *) malloc_redir (sizeof (Tree));
#else
new = (Tree *) malloc (sizeof (Tree));
#endif
} }
if (new == NULL) { if (new == NULL) {
bound_alloc_error("not enough memory for bound checking code"); bound_alloc_error("not enough memory for bound checking code");
@ -1626,11 +1750,7 @@ static Tree * splay_delete(size_t addr, Tree *t)
t->left = tree_free_list; t->left = tree_free_list;
tree_free_list = t; tree_free_list = t;
#else #else
#if MALLOC_REDIR BOUND_FREE(t);
free_redir(t);
#else
free(t);
#endif
#endif #endif
return x; return x;
} else { } else {

View file

@ -909,6 +909,7 @@ ST_FUNC void put_extern_sym2(Sym *sym, int sh_num,
case TOK_alloca: case TOK_alloca:
case TOK_mmap: case TOK_mmap:
case TOK_munmap: case TOK_munmap:
case TOK_longjmp:
strcpy(buf, "__bound_"); strcpy(buf, "__bound_");
strcat(buf, name); strcat(buf, name);
name = buf; name = buf;
@ -6010,6 +6011,19 @@ special_math_val:
if (sa) if (sa)
tcc_error("too few arguments to function"); tcc_error("too few arguments to function");
skip(')'); skip(')');
#ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check &&
(nb_args == 1 || nb_args == 2) &&
(vtop[-nb_args].r & VT_SYM) &&
(vtop[-nb_args].sym->v == TOK_setjmp ||
vtop[-nb_args].sym->v == TOK__setjmp)) {
vpush_global_sym(&func_old_type, TOK___bound_setjmp);
vpushv(vtop - nb_args);
if (nb_args == 2)
vpushv(vtop - nb_args);
gfunc_call(nb_args);
}
#endif
gfunc_call(nb_args); gfunc_call(nb_args);
if (ret_nregs < 0) { if (ret_nregs < 0) {

View file

@ -305,6 +305,7 @@
DEF(TOK___bound_main_arg, "__bound_main_arg") DEF(TOK___bound_main_arg, "__bound_main_arg")
DEF(TOK___bound_local_new, "__bound_local_new") DEF(TOK___bound_local_new, "__bound_local_new")
DEF(TOK___bound_local_delete, "__bound_local_delete") DEF(TOK___bound_local_delete, "__bound_local_delete")
DEF(TOK___bound_setjmp, "__bound_setjmp")
# ifdef TCC_TARGET_PE # ifdef TCC_TARGET_PE
# ifdef TCC_TARGET_X86_64 # ifdef TCC_TARGET_X86_64
DEF(TOK___bound_alloca_nr, "__bound_alloca_nr") DEF(TOK___bound_alloca_nr, "__bound_alloca_nr")
@ -326,6 +327,9 @@
DEF(TOK_strcat, "strcat") DEF(TOK_strcat, "strcat")
DEF(TOK_strchr, "strchr") DEF(TOK_strchr, "strchr")
DEF(TOK_strdup, "strdup") DEF(TOK_strdup, "strdup")
DEF(TOK_setjmp, "setjmp")
DEF(TOK__setjmp, "_setjmp")
DEF(TOK_longjmp, "longjmp")
#endif #endif
/* Tiny Assembler */ /* Tiny Assembler */

View file

@ -0,0 +1,169 @@
#include <stdio.h>
#include <string.h>
#include <setjmp.h>
#define TST int i, a[2], b[2]; \
for (i = 0; i < 2; i++) a[i] = 0; \
for (i = 0; i < 2; i++) b[i] = 0
static jmp_buf jmp;
static void tst1 (void)
{
TST;
longjmp(jmp, 1);
}
static void tst2(void)
{
jmp_buf jmp;
setjmp (jmp);
TST;
tst1();
}
static void tst3 (jmp_buf loc)
{
TST;
longjmp(loc, 1);
}
static void tst4(jmp_buf loc)
{
jmp_buf jmp;
setjmp (jmp);
TST;
tst3(loc);
}
static void tst (void)
{
jmp_buf loc;
static int cnt;
cnt = 0;
if (setjmp (jmp) == 0) {
TST;
tst2();
}
else {
cnt++;
}
if (setjmp (loc) == 0) {
TST;
tst4(loc);
}
else {
cnt++;
}
if (cnt != 2)
printf ("incorrect cnt %d\n", cnt);
}
static jmp_buf buf1;
static jmp_buf buf2;
static int *p;
static int n_x = 6;
static int g_counter;
static void stack (void)
{
static int counter;
static int way_point1;
static int way_point2;
counter = 0;
way_point1 = 3;
way_point2 = 2;
g_counter = 0;
if (setjmp (buf1) != 101) {
int a[n_x];
g_counter++;
p = &a[0];
if (g_counter < 5)
longjmp (buf1, 2);
else if (g_counter == 5)
longjmp (buf1, 101);
else {
setjmp (buf2);
longjmp (buf1, 101);
}
}
way_point1--;
if (counter == 0) {
counter++;
{
int a[n_x];
g_counter++;
p = &a[0];
if (g_counter < 5)
longjmp (buf1, 2);
else if (g_counter == 5)
longjmp (buf1, 101);
else {
setjmp (buf2);
longjmp (buf1, 101);
}
}
}
way_point2--;
if (counter == 1) {
counter++;
longjmp (buf2, 2);
}
if (!(way_point1 == 0 && way_point2 == 0 &&
g_counter == 6 && counter == 2))
printf ("Failed %d %d %d %d\n",
way_point1, way_point2, g_counter, counter);
}
static jmp_buf env;
static int last_value;
static void jump (int val)
{
longjmp (env, val);
}
static void check (void)
{
int value;
last_value = -1;
value = setjmp (env);
if (value != last_value + 1) {
printf ("incorrect value %d %d\n",
value, last_value + 1);
return;
}
last_value = value;
switch (value) {
case 0:
jump (0);
default:
if (value < 10)
jump (value + 1);
}
}
int
main (void)
{
int i;
for (i = 0; i < 10; i++) {
tst();
stack();
check();
}
return 0;
}

View file

View file

@ -0,0 +1,84 @@
#include <stdio.h>
#include <string.h>
#include <setjmp.h>
#if !defined(_WIN32)
#include <pthread.h>
#else
#include <windows.h>
#endif
#define SIZE 10
#define COUNT 10
#define TST int i, a[2], b[2]; \
for (i = 0; i < 2; i++) a[i] = 0; \
for (i = 0; i < 2; i++) b[i] = 0
static int count[SIZE];
static void tst1 (jmp_buf loc)
{
TST;
longjmp(loc, 1);
}
static void tst2(jmp_buf loc)
{
jmp_buf jmp;
setjmp (jmp);
TST;
tst1(loc);
}
static void *tst (void * index)
{
jmp_buf loc;
int i = *(int *) index;
static int v[SIZE];
for (v[i] = 0; v[i] < COUNT; v[i]++) {
if (setjmp (loc) == 0) {
TST;
tst2(loc);
}
else {
count[i]++;
}
i = *(int *) index;
}
return NULL;
}
int
main (void)
{
int i;
#if !defined(_WIN32)
pthread_t id[SIZE];
#else
HANDLE id[SIZE];
#endif
int index[SIZE];
for (i = 0; i < SIZE; i++) {
index[i] = i;
#if !defined(_WIN32)
pthread_create (&id[i], NULL, tst, (void *) &index[i]);
#else
id[i] = CreateThread(NULL, 8192, (LPTHREAD_START_ROUTINE) tst, (void *) &index[i], 0, NULL);
#endif
}
for (i = 0; i < SIZE; i++) {
#if !defined(_WIN32)
pthread_join (id[i], NULL);
#else
WaitForSingleObject(id[i], INFINITE);
#endif
}
for (i = 0; i < SIZE; i++) {
if (count[i] != COUNT)
printf ("error: %d %d\n", i, count[i]);
}
return 0;
}

View file

View file

@ -26,6 +26,8 @@ ifeq (,$(filter i386 x86_64,$(ARCH)))
SKIP += 85_asm-outside-function.test SKIP += 85_asm-outside-function.test
SKIP += 112_backtrace.test 113_btdll.test SKIP += 112_backtrace.test 113_btdll.test
SKIP += 114_bound_signal.test SKIP += 114_bound_signal.test
SKIP += 115_bound_setjmp.test
SKIP += 116_bound_setjmp2.test
endif endif
ifeq (-$(CONFIG_musl)-,-yes-) ifeq (-$(CONFIG_musl)-,-yes-)
SKIP += 112_backtrace.test SKIP += 112_backtrace.test
@ -91,6 +93,8 @@ GEN-ALWAYS =
-bt a1$(DLLSUF) a2$(DLLSUF) -Wl,-rpath=. -bt a1$(DLLSUF) a2$(DLLSUF) -Wl,-rpath=.
114_bound_signal.test: FLAGS += -b 114_bound_signal.test: FLAGS += -b
115_bound_setjmp.test: FLAGS += -b
116_bound_setjmp2.test: FLAGS += -b
# Filter source directory in warnings/errors (out-of-tree builds) # Filter source directory in warnings/errors (out-of-tree builds)
FILTER = 2>&1 | sed -e 's,$(SRC)/,,g' FILTER = 2>&1 | sed -e 's,$(SRC)/,,g'

View file

@ -149,7 +149,7 @@ static int func_ret_sub;
#if defined(CONFIG_TCC_BCHECK) #if defined(CONFIG_TCC_BCHECK)
static addr_t func_bound_offset; static addr_t func_bound_offset;
static unsigned long func_bound_ind; static unsigned long func_bound_ind;
static int func_bound_alloca_used; static int func_bound_add_epilog;
#endif #endif
#ifdef TCC_TARGET_PE #ifdef TCC_TARGET_PE
@ -637,8 +637,11 @@ static void gcall_or_jmp(int is_jmp)
#endif #endif
oad(0xe8 + is_jmp, 0); /* call/jmp im */ oad(0xe8 + is_jmp, 0); /* call/jmp im */
#ifdef CONFIG_TCC_BCHECK #ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check && vtop->sym->v == TOK_alloca) if (tcc_state->do_bounds_check &&
func_bound_alloca_used = 1; (vtop->sym->v == TOK_alloca ||
vtop->sym->v == TOK_setjmp ||
vtop->sym->v == TOK__setjmp))
func_bound_add_epilog = 1;
#endif #endif
} else { } else {
/* otherwise, indirect call */ /* otherwise, indirect call */
@ -725,7 +728,7 @@ static void gen_bounds_prolog(void)
/* leave some room for bound checking code */ /* leave some room for bound checking code */
func_bound_offset = lbounds_section->data_offset; func_bound_offset = lbounds_section->data_offset;
func_bound_ind = ind; func_bound_ind = ind;
func_bound_alloca_used = 0; func_bound_add_epilog = 0;
o(0xb848 + TREG_FASTCALL_1 * 0x100); /*lbound section pointer */ o(0xb848 + TREG_FASTCALL_1 * 0x100); /*lbound section pointer */
gen_le64 (0); gen_le64 (0);
oad(0xb8, 0); /* call to function */ oad(0xb8, 0); /* call to function */
@ -737,7 +740,7 @@ static void gen_bounds_epilog(void)
addr_t *bounds_ptr; addr_t *bounds_ptr;
Sym *sym_data; Sym *sym_data;
if (func_bound_offset == lbounds_section->data_offset && !func_bound_alloca_used) if (func_bound_offset == lbounds_section->data_offset && !func_bound_add_epilog)
return; return;
/* add end of table info */ /* add end of table info */