Add control for the native stack check with hardware trap (#1682)

Add a new options to control the native stack hw bound check feature:
- Besides the original option `cmake -DWAMR_DISABLE_HW_BOUND_CHECK=1/0`,
  add a new option `cmake -DWAMR_DISABLE_STACK_HW_BOUND_CHECK=1/0`
- When the linear memory hw bound check is disabled, the stack hw bound check
   will be disabled automatically, no matter what the input option is
- When the linear memory hw bound check is enabled, the stack hw bound check
  is enabled/disabled according to the value of input option
- Besides the original option `--bounds-checks=1/0`, add a new option
  `--stack-bounds-checks=1/0` for wamrc

Refer to: https://github.com/bytecodealliance/wasm-micro-runtime/issues/1677
This commit is contained in:
Wenyong Huang 2022-11-07 18:26:33 +08:00 committed by GitHub
parent 810007857b
commit 7fd37190e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 103 additions and 7 deletions

View File

@ -92,6 +92,7 @@ else:
if GetDepend(['WAMR_DISABLE_HW_BOUND_CHECK']):
CPPDEFINES += ['WASM_DISABLE_HW_BOUND_CHECK=1']
CPPDEFINES += ['WASM_DISABLE_STACK_HW_BOUND_CHECK=1']
print("[WAMR] Hardware boundary check disabled")
if GetDepend(['WAMR_BUILD_SIMD']):

View File

@ -205,9 +205,16 @@ else ()
endif ()
if (WAMR_DISABLE_HW_BOUND_CHECK EQUAL 1)
add_definitions (-DWASM_DISABLE_HW_BOUND_CHECK=1)
add_definitions (-DWASM_DISABLE_STACK_HW_BOUND_CHECK=1)
message (" Hardware boundary check disabled")
else ()
add_definitions (-DWASM_DISABLE_HW_BOUND_CHECK=0)
if (WAMR_DISABLE_STACK_HW_BOUND_CHECK EQUAL 1)
add_definitions (-DWASM_DISABLE_STACK_HW_BOUND_CHECK=1)
message (" Hardware boundary check for native stack disabled")
else ()
add_definitions (-DWASM_DISABLE_STACK_HW_BOUND_CHECK=0)
endif ()
endif ()
if (WAMR_BUILD_SIMD EQUAL 1)
if (NOT WAMR_BUILD_TARGET MATCHES "RISCV64.*")

View File

@ -260,6 +260,12 @@
#define WASM_DISABLE_HW_BOUND_CHECK 0
#endif
/* Disable native stack access boundary check with hardware
* trap or not, enable it by default if it is supported */
#ifndef WASM_DISABLE_STACK_HW_BOUND_CHECK
#define WASM_DISABLE_STACK_HW_BOUND_CHECK 0
#endif
/* Disable SIMD unless it is manualy enabled somewhere */
#ifndef WASM_ENABLE_SIMD
#define WASM_ENABLE_SIMD 0

View File

@ -143,9 +143,11 @@ runtime_signal_handler(void *sig_addr)
WASMJmpBuf *jmpbuf_node;
uint8 *mapped_mem_start_addr = NULL;
uint8 *mapped_mem_end_addr = NULL;
#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0
uint8 *stack_min_addr;
uint32 page_size;
uint32 guard_page_count = STACK_OVERFLOW_CHECK_GUARD_PAGE_COUNT;
#endif
/* Check whether current thread is running wasm function */
if (exec_env_tls && exec_env_tls->handle == os_self_thread()
@ -159,9 +161,11 @@ runtime_signal_handler(void *sig_addr)
mapped_mem_end_addr = memory_inst->memory_data + 8 * (uint64)BH_GB;
}
#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0
/* Get stack info of current thread */
page_size = os_getpagesize();
stack_min_addr = os_thread_get_stack_boundary();
#endif
if (memory_inst
&& (mapped_mem_start_addr <= (uint8 *)sig_addr
@ -171,6 +175,7 @@ runtime_signal_handler(void *sig_addr)
wasm_set_exception(module_inst, "out of bounds memory access");
os_longjmp(jmpbuf_node->jmpbuf, 1);
}
#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0
else if (stack_min_addr - page_size <= (uint8 *)sig_addr
&& (uint8 *)sig_addr
< stack_min_addr + page_size * guard_page_count) {
@ -179,6 +184,7 @@ runtime_signal_handler(void *sig_addr)
wasm_set_exception(module_inst, "native stack overflow");
os_longjmp(jmpbuf_node->jmpbuf, 1);
}
#endif
}
}
#else
@ -230,6 +236,7 @@ runtime_exception_handler(EXCEPTION_POINTERS *exce_info)
}
}
}
#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0
else if (ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) {
/* Set stack overflow exception and let the wasm func continue
to run, when the wasm func returns, the caller will check
@ -243,6 +250,7 @@ runtime_exception_handler(EXCEPTION_POINTERS *exce_info)
return EXCEPTION_CONTINUE_EXECUTION;
}
}
#endif
}
os_printf("Unhandled exception thrown: exception code: 0x%lx, "

View File

@ -797,7 +797,7 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
callee_cell_num =
aot_func->param_cell_num + aot_func->local_cell_num + 1;
if (comp_ctx->enable_bound_check
if (comp_ctx->enable_stack_bound_check
&& !check_stack_boundary(comp_ctx, func_ctx, callee_cell_num))
goto fail;
@ -1411,7 +1411,7 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
/* Translate call non-import block */
LLVMPositionBuilderAtEnd(comp_ctx->builder, block_call_non_import);
if (comp_ctx->enable_bound_check
if (comp_ctx->enable_stack_bound_check
&& !check_stack_boundary(comp_ctx, func_ctx,
param_cell_num + ext_cell_num
+ 1

View File

@ -1555,8 +1555,22 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option)
#ifndef OS_ENABLE_HW_BOUND_CHECK
comp_ctx->enable_bound_check = true;
/* Always enable stack boundary check if `bounds-checks`
is enabled */
comp_ctx->enable_stack_bound_check = true;
#else
comp_ctx->enable_bound_check = false;
/* When `bounds-checks` is disabled, we set stack boundary
check status according to the compilation option */
#if WASM_DISABLE_STACK_HW_BOUND_CHECK != 0
/* Native stack overflow check with hardware trap is disabled,
we need to enable the check by LLVM JITed/AOTed code */
comp_ctx->enable_stack_bound_check = true;
#else
/* Native stack overflow check with hardware trap is enabled,
no need to enable the check by LLVM JITed/AOTed code */
comp_ctx->enable_stack_bound_check = false;
#endif
#endif
}
else {
@ -1868,6 +1882,18 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option)
}
}
if (comp_ctx->enable_bound_check) {
/* Always enable stack boundary check if `bounds-checks`
is enabled */
comp_ctx->enable_stack_bound_check = true;
}
else {
/* When `bounds-checks` is disabled, we set stack boundary
check status according to the input option */
comp_ctx->enable_stack_bound_check =
(option->stack_bounds_checks == 1) ? true : false;
}
os_printf("Create AoT compiler with:\n");
os_printf(" target: %s\n", comp_ctx->target_arch);
os_printf(" target cpu: %s\n", cpu);

View File

@ -310,6 +310,9 @@ typedef struct AOTCompContext {
/* Bounday Check */
bool enable_bound_check;
/* Native stack bounday Check */
bool enable_stack_bound_check;
/* 128-bit SIMD */
bool enable_simd;
@ -404,6 +407,7 @@ typedef struct AOTCompOption {
uint32 size_level;
uint32 output_format;
uint32 bounds_checks;
uint32 stack_bounds_checks;
char **custom_sections;
uint32 custom_sections_count;
} AOTCompOption, *aot_comp_option_t;

View File

@ -59,6 +59,7 @@ typedef struct AOTCompOption {
uint32_t size_level;
uint32_t output_format;
uint32_t bounds_checks;
uint32_t stack_bounds_checks;
char **custom_sections;
uint32_t custom_sections_count;
} AOTCompOption, *aot_comp_option_t;

View File

@ -4115,7 +4115,8 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
}
argc = function->param_cell_num;
#ifndef OS_ENABLE_HW_BOUND_CHECK
#if !(defined(OS_ENABLE_HW_BOUND_CHECK) \
&& WASM_DISABLE_STACK_HW_BOUND_CHECK == 0)
if ((uint8 *)&prev_frame < exec_env->native_stack_boundary) {
wasm_set_exception((WASMModuleInstance *)exec_env->module_inst,
"native stack overflow");

View File

@ -3911,7 +3911,8 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
}
argc = function->param_cell_num;
#ifndef OS_ENABLE_HW_BOUND_CHECK
#if !(defined(OS_ENABLE_HW_BOUND_CHECK) \
&& WASM_DISABLE_STACK_HW_BOUND_CHECK == 0)
if ((uint8 *)&prev_frame < exec_env->native_stack_boundary) {
wasm_set_exception((WASMModuleInstance *)exec_env->module_inst,
"native stack overflow");

View File

@ -425,6 +425,7 @@ os_thread_get_stack_boundary()
*/
static os_thread_local_attribute bool thread_signal_inited = false;
#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0
/* The signal alternate stack base addr */
static os_thread_local_attribute uint8 *sigalt_stack_base_addr;
@ -488,6 +489,7 @@ destroy_stack_guard_pages()
os_mprotect(stack_min_addr, page_size * guard_page_count,
MMAP_PROT_READ | MMAP_PROT_WRITE);
}
#endif /* end of WASM_DISABLE_STACK_HW_BOUND_CHECK == 0 */
static void
mask_signals(int how)
@ -553,13 +555,16 @@ int
os_thread_signal_init(os_signal_handler handler)
{
struct sigaction sig_act;
#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0
stack_t sigalt_stack_info;
uint32 map_size = SIG_ALT_STACK_SIZE;
uint8 *map_addr;
#endif
if (thread_signal_inited)
return 0;
#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0
if (!init_stack_guard_pages()) {
os_printf("Failed to init stack guard pages\n");
return -1;
@ -581,13 +586,17 @@ os_thread_signal_init(os_signal_handler handler)
os_printf("Failed to init signal alternate stack\n");
goto fail2;
}
#endif
memset(&prev_sig_act_SIGSEGV, 0, sizeof(struct sigaction));
memset(&prev_sig_act_SIGBUS, 0, sizeof(struct sigaction));
/* Install signal hanlder */
sig_act.sa_sigaction = signal_callback;
sig_act.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_NODEFER;
sig_act.sa_flags = SA_SIGINFO | SA_NODEFER;
#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0
sig_act.sa_flags |= SA_ONSTACK;
#endif
sigemptyset(&sig_act.sa_mask);
if (sigaction(SIGSEGV, &sig_act, &prev_sig_act_SIGSEGV) != 0
|| sigaction(SIGBUS, &sig_act, &prev_sig_act_SIGBUS) != 0) {
@ -595,12 +604,15 @@ os_thread_signal_init(os_signal_handler handler)
goto fail3;
}
#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0
sigalt_stack_base_addr = map_addr;
#endif
signal_handler = handler;
thread_signal_inited = true;
return 0;
fail3:
#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0
memset(&sigalt_stack_info, 0, sizeof(stack_t));
sigalt_stack_info.ss_flags = SS_DISABLE;
sigalt_stack_info.ss_size = map_size;
@ -609,17 +621,21 @@ fail2:
os_munmap(map_addr, map_size);
fail1:
destroy_stack_guard_pages();
#endif
return -1;
}
void
os_thread_signal_destroy()
{
#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0
stack_t sigalt_stack_info;
#endif
if (!thread_signal_inited)
return;
#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0
/* Disable signal alternate stack */
memset(&sigalt_stack_info, 0, sizeof(stack_t));
sigalt_stack_info.ss_flags = SS_DISABLE;
@ -629,6 +645,7 @@ os_thread_signal_destroy()
os_munmap(sigalt_stack_base_addr, SIG_ALT_STACK_SIZE);
destroy_stack_guard_pages();
#endif
thread_signal_inited = false;
}
@ -648,6 +665,7 @@ os_signal_unmask()
void
os_sigreturn()
{
#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0
#if defined(__APPLE__)
#define UC_RESET_ALT_STACK 0x80000000
extern int __sigreturn(void *, int);
@ -656,5 +674,6 @@ os_sigreturn()
after exiting the signal handler. */
__sigreturn(NULL, UC_RESET_ALT_STACK);
#endif
#endif
}
#endif /* end of OS_ENABLE_HW_BOUND_CHECK */

View File

@ -706,13 +706,19 @@ static os_thread_local_attribute bool thread_signal_inited = false;
int
os_thread_signal_init()
{
#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0
ULONG StackSizeInBytes = 16 * 1024;
#endif
bool ret;
if (thread_signal_inited)
return 0;
#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0
ret = SetThreadStackGuarantee(&StackSizeInBytes);
#else
ret = true;
#endif
if (ret)
thread_signal_inited = true;
return ret ? 0 : -1;

View File

@ -80,9 +80,13 @@ cmake -DWAMR_BUILD_PLATFORM=linux -DWAMR_BUILD_TARGET=ARM
- **WAMR_BUILD_LIB_PTHREAD_SEMAPHORE**=1/0, default to disable if not set
> Note: This feature depends on `lib-pthread`, it will be enabled automatically if this feature is enabled.
#### **Disable boundary check with hardware trap in AOT or JIT mode**
#### **Disable boundary check with hardware trap**
- **WAMR_DISABLE_HW_BOUND_CHECK**=1/0, default to enable if not set and supported by platform
> Note: by default only platform linux/darwin/android/vxworks 64-bit will enable boundary check with hardware trap in AOT or JIT mode, and the wamrc tool will generate AOT code without boundary check instructions in all 64-bit targets except SGX to improve performance.
> Note: by default only platform linux/darwin/android/windows/vxworks 64-bit will enable the boundary check with hardware trap feature, and the wamrc tool will generate AOT code without boundary check instructions in all 64-bit targets except SGX to improve performance. The boundary check includes linear memory access boundary and native stack access boundary, if `WAMR_DISABLE_STACK_HW_BOUND_CHECK` below isn't set.
#### **Disable native stack boundary check with hardware trap**
- **WAMR_DISABLE_STACK_HW_BOUND_CHECK**=1/0, default to enable if not set and supported by platform, same as `WAMR_DISABLE_HW_BOUND_CHECK`.
> Note: When boundary check with hardware trap is disabled, or `WAMR_DISABLE_HW_BOUND_CHECK` is set to 1, the native stack boundary check with hardware trap will be disabled too, no matter what value is set to `WAMR_DISABLE_STACK_HW_BOUND_CHECK`. And when boundary check with hardware trap is enabled, the status of this feature is set according to the value of `WAMR_DISABLE_STACK_HW_BOUND_CHECK`.
#### **Enable tail call feature**
- **WAMR_BUILD_TAIL_CALL**=1/0, default to disable if not set

View File

@ -268,8 +268,10 @@ endif
ifeq ($(CONFIG_INTERPRETERS_WAMR_DISABLE_HW_BOUND_CHECK),y)
CFLAGS += -DWASM_DISABLE_HW_BOUND_CHECK=1
CFLAGS += -DWASM_DISABLE_STACK_HW_BOUND_CHECK=1
else
CFLAGS += -DWASM_DISABLE_HW_BOUND_CHECK=0
CFLAGS += -DWASM_DISABLE_STACK_HW_BOUND_CHECK=0
endif
ifeq ($(CONFIG_INTERPRETERS_WAMR_CUSTOM_NAME_SECTIONS),y)

View File

@ -37,6 +37,11 @@ print_help()
printf(" by default it is disabled in all 64-bit platforms except SGX and\n");
printf(" in these platforms runtime does bounds checks with hardware trap,\n");
printf(" and by default it is enabled in all 32-bit platforms\n");
printf(" --stack-bounds-checks=1/0 Enable or disable the bounds checks for native stack:\n");
printf(" if the option isn't set, the status is same as `--bounds-check`,\n");
printf(" if the option is set:\n");
printf(" (1) it is always enabled when `--bounds-checks` is enabled,\n");
printf(" (2) else it is enabled/disabled according to the option value\n");
printf(" --format=<format> Specifies the format of the output file\n");
printf(" The format supported:\n");
printf(" aot (default) AoT file\n");
@ -139,6 +144,8 @@ main(int argc, char *argv[])
option.output_format = AOT_FORMAT_FILE;
/* default value, enable or disable depends on the platform */
option.bounds_checks = 2;
/* default value, enable or disable depends on the platform */
option.stack_bounds_checks = 2;
option.enable_simd = true;
option.enable_aux_stack_check = true;
option.enable_bulk_memory = true;
@ -193,6 +200,9 @@ main(int argc, char *argv[])
else if (!strncmp(argv[0], "--bounds-checks=", 16)) {
option.bounds_checks = (atoi(argv[0] + 16) == 1) ? 1 : 0;
}
else if (!strncmp(argv[0], "--stack-bounds-checks=", 22)) {
option.stack_bounds_checks = (atoi(argv[0] + 22) == 1) ? 1 : 0;
}
else if (!strncmp(argv[0], "--format=", 9)) {
if (argv[0][9] == '\0')
PRINT_HELP_AND_EXIT();