mirror of
https://github.com/frida/tinycc
synced 2025-01-11 22:29:18 +03:00
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:
parent
4429cef9f6
commit
b5b92c7d6d
13
i386-gen.c
13
i386-gen.c
@ -97,7 +97,7 @@ static int func_ret_sub;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
static addr_t func_bound_offset;
|
||||
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_epilog(void);
|
||||
#endif
|
||||
@ -359,8 +359,11 @@ static void gcall_or_jmp(int is_jmp)
|
||||
greloc(cur_text_section, vtop->sym, ind + 1, R_386_PC32);
|
||||
oad(0xe8 + is_jmp, vtop->c.i - 4); /* call/jmp im */
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check && vtop->sym->v == TOK_alloca)
|
||||
func_bound_alloca_used = 1;
|
||||
if (tcc_state->do_bounds_check &&
|
||||
(vtop->sym->v == TOK_alloca ||
|
||||
vtop->sym->v == TOK_setjmp ||
|
||||
vtop->sym->v == TOK__setjmp))
|
||||
func_bound_add_epilog = 1;
|
||||
#endif
|
||||
} else {
|
||||
/* otherwise, indirect call */
|
||||
@ -1069,7 +1072,7 @@ static void gen_bounds_prolog(void)
|
||||
/* leave some room for bound checking code */
|
||||
func_bound_offset = lbounds_section->data_offset;
|
||||
func_bound_ind = ind;
|
||||
func_bound_alloca_used = 0;
|
||||
func_bound_add_epilog = 0;
|
||||
oad(0xb8, 0); /* lbound section pointer */
|
||||
oad(0xb8, 0); /* call to function */
|
||||
}
|
||||
@ -1080,7 +1083,7 @@ static void gen_bounds_epilog(void)
|
||||
addr_t *bounds_ptr;
|
||||
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;
|
||||
|
||||
/* add end of table info */
|
||||
|
316
lib/bcheck.c
316
lib/bcheck.c
@ -21,6 +21,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#if !defined(__FreeBSD__) \
|
||||
&& !defined(__FreeBSD_kernel__) \
|
||||
@ -32,6 +33,7 @@
|
||||
|
||||
#if !defined(_WIN32)
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#endif
|
||||
|
||||
#define BOUND_DEBUG (1)
|
||||
@ -158,6 +160,25 @@ typedef struct alloca_list_struct {
|
||||
struct alloca_list_struct *next;
|
||||
} 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)
|
||||
static Tree * splay (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);
|
||||
#endif
|
||||
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 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);
|
||||
@ -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_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_memalign(size_t size, size_t align, 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;
|
||||
#endif
|
||||
static alloca_list_type *alloca_list;
|
||||
static jmp_list_type *jmp_list;
|
||||
|
||||
static unsigned char inited;
|
||||
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_munmap_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_memcmp_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)
|
||||
{
|
||||
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)
|
||||
return;
|
||||
@ -487,39 +525,63 @@ void FASTCALL __bound_local_delete(void *p1)
|
||||
p += 2;
|
||||
}
|
||||
{
|
||||
alloca_list_type *last = NULL;
|
||||
alloca_list_type *cur = alloca_list;
|
||||
alloca_list_type *last = NULL;
|
||||
alloca_list_type *cur = alloca_list;
|
||||
|
||||
while (cur) {
|
||||
if (cur->fp == fp) {
|
||||
if (last)
|
||||
last->next = cur->next;
|
||||
else
|
||||
alloca_list = cur->next;
|
||||
tree = splay_delete ((size_t) cur->p, tree);
|
||||
cur->next = free_list;
|
||||
free_list = cur;
|
||||
cur = last ? last->next : alloca_list;
|
||||
}
|
||||
else {
|
||||
last = cur;
|
||||
cur = cur->next;
|
||||
}
|
||||
while (cur) {
|
||||
if (cur->fp == fp) {
|
||||
if (last)
|
||||
last->next = cur->next;
|
||||
else
|
||||
alloca_list = cur->next;
|
||||
tree = splay_delete ((size_t) cur->p, tree);
|
||||
cur->next = alloca_free_list;
|
||||
alloca_free_list = cur;
|
||||
cur = last ? last->next : alloca_list;
|
||||
}
|
||||
else {
|
||||
last = cur;
|
||||
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 ();
|
||||
while (free_list) {
|
||||
alloca_list_type *next = free_list->next;
|
||||
while (alloca_free_list) {
|
||||
alloca_list_type *next = alloca_free_list->next;
|
||||
|
||||
dprintf(stderr, "%s, %s(): remove alloca/vla %p\n",
|
||||
__FILE__, __FUNCTION__, free_list->p);
|
||||
#if MALLOC_REDIR
|
||||
free_redir (free_list);
|
||||
#else
|
||||
free (free_list);
|
||||
#endif
|
||||
free_list = next;
|
||||
__FILE__, __FUNCTION__, alloca_free_list->p);
|
||||
BOUND_FREE (alloca_free_list);
|
||||
alloca_free_list = next;
|
||||
}
|
||||
while (jmp_free_list) {
|
||||
jmp_list_type *next = jmp_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 (print_calls) {
|
||||
@ -547,11 +609,7 @@ void __bound_new_region(void *p, size_t size)
|
||||
dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
|
||||
__FILE__, __FUNCTION__, p, (unsigned long)size);
|
||||
GET_CALLER_FP (fp);
|
||||
#if MALLOC_REDIR
|
||||
new = malloc_redir (sizeof (alloca_list_type));
|
||||
#else
|
||||
new = malloc (sizeof (alloca_list_type));
|
||||
#endif
|
||||
new = BOUND_MALLOC (sizeof (alloca_list_type));
|
||||
WAIT_SEM ();
|
||||
INCR_COUNT(bound_alloca_count);
|
||||
last = NULL;
|
||||
@ -580,14 +638,116 @@ void __bound_new_region(void *p, size_t size)
|
||||
if (cur) {
|
||||
dprintf(stderr, "%s, %s(): remove alloca/vla %p\n",
|
||||
__FILE__, __FUNCTION__, cur->p);
|
||||
#if MALLOC_REDIR
|
||||
free_redir (cur);
|
||||
#else
|
||||
free (cur);
|
||||
#endif
|
||||
BOUND_FREE (cur);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
@ -811,21 +971,19 @@ void __attribute__((destructor)) __bound_exit(void)
|
||||
alloca_list_type *next = alloca_list->next;
|
||||
|
||||
tree = splay_delete ((size_t) alloca_list->p, tree);
|
||||
#if MALLOC_REDIR
|
||||
free_redir (alloca_list);
|
||||
#else
|
||||
free (alloca_list);
|
||||
#endif
|
||||
BOUND_FREE (alloca_list);
|
||||
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++) {
|
||||
if (free_reuse_list[i]) {
|
||||
tree = splay_delete ((size_t) free_reuse_list[i], tree);
|
||||
#if MALLOC_REDIR
|
||||
free_redir (free_reuse_list[i]);
|
||||
#else
|
||||
free (free_reuse_list[i]);
|
||||
#endif
|
||||
BOUND_FREE (free_reuse_list[i]);
|
||||
}
|
||||
}
|
||||
while (tree) {
|
||||
@ -838,11 +996,7 @@ void __attribute__((destructor)) __bound_exit(void)
|
||||
#if TREE_REUSE
|
||||
while (tree_free_list) {
|
||||
Tree *next = tree_free_list->left;
|
||||
#if MALLOC_REDIR
|
||||
free_redir (tree_free_list);
|
||||
#else
|
||||
free (tree_free_list);
|
||||
#endif
|
||||
BOUND_FREE (tree_free_list);
|
||||
tree_free_list = next;
|
||||
}
|
||||
#endif
|
||||
@ -868,6 +1022,8 @@ void __attribute__((destructor)) __bound_exit(void)
|
||||
fprintf (stderr, "bound_mmap_count %llu\n", bound_mmap_count);
|
||||
fprintf (stderr, "bound_munmap_count %llu\n", bound_munmap_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_memcmp_count %llu\n", bound_memcmp_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
|
||||
separated by at least one byte. With the glibc malloc, it may
|
||||
be in fact not necessary */
|
||||
#if MALLOC_REDIR
|
||||
ptr = malloc_redir (size + 1);
|
||||
#else
|
||||
ptr = malloc(size + 1);
|
||||
#endif
|
||||
ptr = BOUND_MALLOC (size + 1);
|
||||
dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
|
||||
__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
|
||||
separated by at least one byte. With the glibc malloc, it may
|
||||
be in fact not necessary */
|
||||
#if MALLOC_REDIR
|
||||
ptr = memalign_redir(size + 1, align);
|
||||
#else
|
||||
ptr = memalign(size + 1, align);
|
||||
#endif
|
||||
ptr = BOUND_MEMALIGN(size + 1, align);
|
||||
#else
|
||||
if (align > 4) {
|
||||
/* XXX: handle it ? */
|
||||
ptr = NULL;
|
||||
} else {
|
||||
/* we suppose that malloc aligns to at least four bytes */
|
||||
#if MALLOC_REDIR
|
||||
ptr = malloc_redir(size + 1);
|
||||
#else
|
||||
ptr = malloc(size + 1);
|
||||
#endif
|
||||
ptr = BOUND_MALLOC(size + 1);
|
||||
}
|
||||
#endif
|
||||
dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
|
||||
@ -1035,11 +1179,7 @@ void __bound_free(void *ptr, const void *caller)
|
||||
ptr = p;
|
||||
}
|
||||
POST_SEM ();
|
||||
#if MALLOC_REDIR
|
||||
free_redir (ptr);
|
||||
#else
|
||||
free(ptr);
|
||||
#endif
|
||||
BOUND_FREE (ptr);
|
||||
}
|
||||
|
||||
#if MALLOC_REDIR
|
||||
@ -1059,11 +1199,7 @@ void *__bound_realloc(void *ptr, size_t size, const void *caller)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if MALLOC_REDIR
|
||||
new_ptr = realloc_redir (ptr, size);
|
||||
#else
|
||||
new_ptr = realloc (ptr, size);
|
||||
#endif
|
||||
new_ptr = BOUND_REALLOC (ptr, size);
|
||||
dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
|
||||
__FILE__, __FUNCTION__, new_ptr, (unsigned long)size);
|
||||
|
||||
@ -1108,11 +1244,7 @@ void *__bound_calloc(size_t nmemb, size_t size)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if MALLOC_REDIR
|
||||
ptr = malloc_redir(size + 1);
|
||||
#else
|
||||
ptr = malloc(size + 1);
|
||||
#endif
|
||||
ptr = BOUND_MALLOC(size + 1);
|
||||
dprintf (stderr, "%s, %s(): %p, 0x%lx\n",
|
||||
__FILE__, __FUNCTION__, ptr, (unsigned long)size);
|
||||
|
||||
@ -1377,11 +1509,7 @@ char *__bound_strdup(const char *s)
|
||||
INCR_COUNT(bound_strdup_count);
|
||||
while (*p++);
|
||||
__bound_check(s, p - s, "strdup");
|
||||
#if MALLOC_REDIR
|
||||
new = malloc_redir ((p - s) + 1);
|
||||
#else
|
||||
new = malloc ((p - s) + 1);
|
||||
#endif
|
||||
new = BOUND_MALLOC ((p - s) + 1);
|
||||
dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
|
||||
__FILE__, __FUNCTION__, new, (unsigned long)(p -s));
|
||||
if (new) {
|
||||
@ -1574,11 +1702,7 @@ static Tree * splay_insert(size_t addr, size_t size, Tree * t)
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#if MALLOC_REDIR
|
||||
new = (Tree *) malloc_redir (sizeof (Tree));
|
||||
#else
|
||||
new = (Tree *) malloc (sizeof (Tree));
|
||||
#endif
|
||||
new = (Tree *) BOUND_MALLOC (sizeof (Tree));
|
||||
}
|
||||
if (new == NULL) {
|
||||
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;
|
||||
tree_free_list = t;
|
||||
#else
|
||||
#if MALLOC_REDIR
|
||||
free_redir(t);
|
||||
#else
|
||||
free(t);
|
||||
#endif
|
||||
BOUND_FREE(t);
|
||||
#endif
|
||||
return x;
|
||||
} else {
|
||||
|
14
tccgen.c
14
tccgen.c
@ -909,6 +909,7 @@ ST_FUNC void put_extern_sym2(Sym *sym, int sh_num,
|
||||
case TOK_alloca:
|
||||
case TOK_mmap:
|
||||
case TOK_munmap:
|
||||
case TOK_longjmp:
|
||||
strcpy(buf, "__bound_");
|
||||
strcat(buf, name);
|
||||
name = buf;
|
||||
@ -6010,6 +6011,19 @@ special_math_val:
|
||||
if (sa)
|
||||
tcc_error("too few arguments to function");
|
||||
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);
|
||||
|
||||
if (ret_nregs < 0) {
|
||||
|
4
tcctok.h
4
tcctok.h
@ -305,6 +305,7 @@
|
||||
DEF(TOK___bound_main_arg, "__bound_main_arg")
|
||||
DEF(TOK___bound_local_new, "__bound_local_new")
|
||||
DEF(TOK___bound_local_delete, "__bound_local_delete")
|
||||
DEF(TOK___bound_setjmp, "__bound_setjmp")
|
||||
# ifdef TCC_TARGET_PE
|
||||
# ifdef TCC_TARGET_X86_64
|
||||
DEF(TOK___bound_alloca_nr, "__bound_alloca_nr")
|
||||
@ -326,6 +327,9 @@
|
||||
DEF(TOK_strcat, "strcat")
|
||||
DEF(TOK_strchr, "strchr")
|
||||
DEF(TOK_strdup, "strdup")
|
||||
DEF(TOK_setjmp, "setjmp")
|
||||
DEF(TOK__setjmp, "_setjmp")
|
||||
DEF(TOK_longjmp, "longjmp")
|
||||
#endif
|
||||
|
||||
/* Tiny Assembler */
|
||||
|
169
tests/tests2/115_bound_setjmp.c
Normal file
169
tests/tests2/115_bound_setjmp.c
Normal 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;
|
||||
}
|
||||
|
||||
|
0
tests/tests2/115_bound_setjmp.expect
Normal file
0
tests/tests2/115_bound_setjmp.expect
Normal file
84
tests/tests2/116_bound_setjmp2.c
Normal file
84
tests/tests2/116_bound_setjmp2.c
Normal 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;
|
||||
}
|
0
tests/tests2/116_bound_setjmp2.expect
Normal file
0
tests/tests2/116_bound_setjmp2.expect
Normal file
@ -26,6 +26,8 @@ ifeq (,$(filter i386 x86_64,$(ARCH)))
|
||||
SKIP += 85_asm-outside-function.test
|
||||
SKIP += 112_backtrace.test 113_btdll.test
|
||||
SKIP += 114_bound_signal.test
|
||||
SKIP += 115_bound_setjmp.test
|
||||
SKIP += 116_bound_setjmp2.test
|
||||
endif
|
||||
ifeq (-$(CONFIG_musl)-,-yes-)
|
||||
SKIP += 112_backtrace.test
|
||||
@ -91,6 +93,8 @@ GEN-ALWAYS =
|
||||
-bt a1$(DLLSUF) a2$(DLLSUF) -Wl,-rpath=.
|
||||
|
||||
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 = 2>&1 | sed -e 's,$(SRC)/,,g'
|
||||
|
13
x86_64-gen.c
13
x86_64-gen.c
@ -149,7 +149,7 @@ static int func_ret_sub;
|
||||
#if defined(CONFIG_TCC_BCHECK)
|
||||
static addr_t func_bound_offset;
|
||||
static unsigned long func_bound_ind;
|
||||
static int func_bound_alloca_used;
|
||||
static int func_bound_add_epilog;
|
||||
#endif
|
||||
|
||||
#ifdef TCC_TARGET_PE
|
||||
@ -637,8 +637,11 @@ static void gcall_or_jmp(int is_jmp)
|
||||
#endif
|
||||
oad(0xe8 + is_jmp, 0); /* call/jmp im */
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check && vtop->sym->v == TOK_alloca)
|
||||
func_bound_alloca_used = 1;
|
||||
if (tcc_state->do_bounds_check &&
|
||||
(vtop->sym->v == TOK_alloca ||
|
||||
vtop->sym->v == TOK_setjmp ||
|
||||
vtop->sym->v == TOK__setjmp))
|
||||
func_bound_add_epilog = 1;
|
||||
#endif
|
||||
} else {
|
||||
/* otherwise, indirect call */
|
||||
@ -725,7 +728,7 @@ static void gen_bounds_prolog(void)
|
||||
/* leave some room for bound checking code */
|
||||
func_bound_offset = lbounds_section->data_offset;
|
||||
func_bound_ind = ind;
|
||||
func_bound_alloca_used = 0;
|
||||
func_bound_add_epilog = 0;
|
||||
o(0xb848 + TREG_FASTCALL_1 * 0x100); /*lbound section pointer */
|
||||
gen_le64 (0);
|
||||
oad(0xb8, 0); /* call to function */
|
||||
@ -737,7 +740,7 @@ static void gen_bounds_epilog(void)
|
||||
addr_t *bounds_ptr;
|
||||
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;
|
||||
|
||||
/* add end of table info */
|
||||
|
Loading…
Reference in New Issue
Block a user