Implement memory access bound check with hardware trap for 64-bit platforms (#293)

Also implement native stack overflow check with hardware trap for 64-bit platforms
Refine classic interpreter and fast interpreter to improve performance
Update document
This commit is contained in:
wenyongh
2020-06-28 15:41:25 +08:00
committed by GitHub
parent 548926ab1a
commit ee315e4049
33 changed files with 1143 additions and 438 deletions

View File

@ -6,7 +6,7 @@
#include "platform_api_vmcore.h"
void *
os_mmap(void *hint, uint32 size, int prot, int flags)
os_mmap(void *hint, size_t size, int prot, int flags)
{
int map_prot = PROT_NONE;
int map_flags = MAP_ANONYMOUS | MAP_PRIVATE;
@ -17,7 +17,12 @@ os_mmap(void *hint, uint32 size, int prot, int flags)
page_size = getpagesize();
request_size = (size + page_size - 1) & ~(page_size - 1);
if (request_size >= UINT32_MAX)
if ((size_t)request_size < size)
/* integer overflow */
return NULL;
if (request_size > 16 * (uint64)UINT32_MAX)
/* At most 16 G is allowed */
return NULL;
if (prot & MMAP_PROT_READ)
@ -53,7 +58,7 @@ os_mmap(void *hint, uint32 size, int prot, int flags)
}
void
os_munmap(void *addr, uint32 size)
os_munmap(void *addr, size_t size)
{
uint64 page_size = getpagesize();
uint64 request_size = (size + page_size - 1) & ~(page_size - 1);
@ -67,9 +72,11 @@ os_munmap(void *addr, uint32 size)
}
int
os_mprotect(void *addr, uint32 size, int prot)
os_mprotect(void *addr, size_t size, int prot)
{
int map_prot = PROT_NONE;
uint64 page_size = getpagesize();
uint64 request_size = (size + page_size - 1) & ~(page_size - 1);
if (!addr)
return 0;
@ -83,7 +90,7 @@ os_mprotect(void *addr, uint32 size, int prot)
if (prot & MMAP_PROT_EXEC)
map_prot |= PROT_EXEC;
return mprotect(addr, size, map_prot);
return mprotect(addr, request_size, map_prot);
}
void

View File

@ -21,7 +21,7 @@ static void *os_thread_wrapper(void *arg)
thread_wrapper_arg * targ = arg;
thread_start_routine_t start_func = targ->start;
void *thread_arg = targ->arg;
printf("THREAD CREATE %p\n", &targ);
os_printf("THREAD CREATED %p\n", &targ);
targ->stack = (void *)((uintptr_t)(&arg) & (uintptr_t)~0xfff);
BH_FREE(targ);
start_func(thread_arg);
@ -41,8 +41,8 @@ int os_thread_create_with_prio(korp_tid *tid, thread_start_routine_t start,
pthread_attr_init(&tattr);
pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE);
if (pthread_attr_setstacksize(&tattr, stack_size) != 0) {
printf("Invalid thread stack size %u. Min stack size on Linux = %u",
stack_size, PTHREAD_STACK_MIN);
os_printf("Invalid thread stack size %u. Min stack size on Linux = %u",
stack_size, PTHREAD_STACK_MIN);
pthread_attr_destroy(&tattr);
return BHT_ERROR;
}
@ -123,7 +123,7 @@ int os_mutex_lock(korp_mutex *mutex)
assert(mutex);
ret = pthread_mutex_lock(mutex);
if (0 != ret) {
printf("vm mutex lock failed (ret=%d)!\n", ret);
os_printf("vm mutex lock failed (ret=%d)!\n", ret);
exit(-1);
}
return ret;
@ -140,7 +140,7 @@ int os_mutex_unlock(korp_mutex *mutex)
assert(mutex);
ret = pthread_mutex_unlock(mutex);
if (0 != ret) {
printf("vm mutex unlock failed (ret=%d)!\n", ret);
os_printf("vm mutex unlock failed (ret=%d)!\n", ret);
exit(-1);
}
return ret;
@ -241,15 +241,16 @@ uint8 *os_thread_get_stack_boundary()
pthread_attr_t attr;
uint8 *addr = NULL;
size_t stack_size, guard_size;
int page_size = getpagesize();
#ifdef __linux__
if (pthread_getattr_np(self, &attr) == 0) {
pthread_attr_getstack(&attr, (void**)&addr, &stack_size);
pthread_attr_getguardsize(&attr, &guard_size);
pthread_attr_destroy(&attr);
if (guard_size < 4 * 1024)
/* Reserved 4 KB guard size at least for safety */
guard_size = 4 * 1024;
if (guard_size < (size_t)page_size)
/* Reserved 1 guard page at least for safety */
guard_size = (size_t)page_size;
addr += guard_size;
}
(void)stack_size;
@ -257,10 +258,150 @@ uint8 *os_thread_get_stack_boundary()
if ((addr = (uint8*)pthread_get_stackaddr_np(self))) {
stack_size = pthread_get_stacksize_np(self);
addr -= stack_size;
/* Reserved 4 KB guard size at least for safety */
addr += 4 * 1024;
/* Reserved 1 guard page at least for safety */
addr += page_size;
}
#endif
return addr;
}
}
#ifdef OS_ENABLE_HW_BOUND_CHECK
#define SIG_ALT_STACK_SIZE (32 * 1024)
/* The signal alternate stack base addr */
static uint8 *sigalt_stack_base_addr;
/* The signal handler passed to os_signal_init() */
static os_signal_handler signal_handler;
static void
mask_signals(int how)
{
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGSEGV);
sigaddset(&set, SIGBUS);
pthread_sigmask(how, &set, NULL);
}
__attribute__((noreturn)) static void
signal_callback(int sig_num, siginfo_t *sig_info, void *sig_ucontext)
{
int i;
void *sig_addr = sig_info->si_addr;
mask_signals(SIG_BLOCK);
if (signal_handler
&& (sig_num == SIGSEGV || sig_num == SIGBUS)) {
signal_handler(sig_addr);
}
/* signal unhandled */
switch (sig_num) {
case SIGSEGV:
os_printf("unhandled SIGSEGV, si_addr: %p\n", sig_addr);
break;
case SIGBUS:
os_printf("unhandled SIGBUS, si_addr: %p\n", sig_addr);
break;
default:
os_printf("unhandle signal %d, si_addr: %p\n",
sig_num, sig_addr);
break;
}
/* divived by 0 to make it abort */
i = os_printf(" ");
os_printf("%d\n", i / (i - 1));
/* access NULL ptr to make it abort */
os_printf("%d\n", *(uint32*)(uintptr_t)(i - 1));
exit(1);
}
int
os_signal_init(os_signal_handler handler)
{
int ret = -1;
struct sigaction sig_act;
stack_t sigalt_stack_info;
uint32 map_size = SIG_ALT_STACK_SIZE;
uint8 *map_addr;
/* Initialize memory for signal alternate stack */
if (!(map_addr = os_mmap(NULL, map_size,
MMAP_PROT_READ | MMAP_PROT_WRITE,
MMAP_MAP_NONE))) {
os_printf("Failed to mmap memory for alternate stack\n");
return -1;
}
/* Initialize signal alternate stack */
memset(map_addr, 0, map_size);
sigalt_stack_info.ss_sp = map_addr;
sigalt_stack_info.ss_size = map_size;
sigalt_stack_info.ss_flags = 0;
if ((ret = sigaltstack(&sigalt_stack_info, NULL)) != 0) {
goto fail1;
}
/* Install signal hanlder */
sig_act.sa_sigaction = signal_callback;
sig_act.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_NODEFER;
sigemptyset(&sig_act.sa_mask);
if ((ret = sigaction(SIGSEGV, &sig_act, NULL)) != 0
|| (ret = sigaction(SIGBUS, &sig_act, NULL)) != 0) {
goto fail2;
}
sigalt_stack_base_addr = map_addr;
signal_handler = handler;
return 0;
fail2:
memset(&sigalt_stack_info, 0, sizeof(stack_t));
sigalt_stack_info.ss_flags = SS_DISABLE;
sigalt_stack_info.ss_size = map_size;
sigaltstack(&sigalt_stack_info, NULL);
fail1:
os_munmap(map_addr, map_size);
return ret;
}
void
os_signal_destroy()
{
stack_t sigalt_stack_info;
/* Disable signal alternate stack */
memset(&sigalt_stack_info, 0, sizeof(stack_t));
sigalt_stack_info.ss_flags = SS_DISABLE;
sigalt_stack_info.ss_size = SIG_ALT_STACK_SIZE;
sigaltstack(&sigalt_stack_info, NULL);
os_munmap(sigalt_stack_base_addr, SIG_ALT_STACK_SIZE);
}
void
os_signal_unmask()
{
mask_signals(SIG_UNBLOCK);
}
void
os_sigreturn()
{
#if defined(__APPLE__)
#define UC_RESET_ALT_STACK 0x80000000
extern int __sigreturn(void *, int);
/* It's necessary to call __sigreturn to restore the sigaltstack state
after exiting the signal handler. */
__sigreturn(NULL, UC_RESET_ALT_STACK);
#endif
}
#endif /* end of OS_ENABLE_HW_BOUND_CHECK */