浏览代码

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
Wenyong Huang 3 年之前
父节点
当前提交
7fd37190e8

+ 1 - 0
build-scripts/SConscript_config

@@ -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']):

+ 7 - 0
build-scripts/config_common.cmake

@@ -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.*")

+ 6 - 0
core/config.h

@@ -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

+ 8 - 0
core/iwasm/common/wasm_runtime_common.c

@@ -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, "

+ 2 - 2
core/iwasm/compilation/aot_emit_function.c

@@ -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

+ 26 - 0
core/iwasm/compilation/aot_llvm.c

@@ -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);

+ 4 - 0
core/iwasm/compilation/aot_llvm.h

@@ -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;

+ 1 - 0
core/iwasm/include/aot_export.h

@@ -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;

+ 2 - 1
core/iwasm/interpreter/wasm_interp_classic.c

@@ -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");

+ 2 - 1
core/iwasm/interpreter/wasm_interp_fast.c

@@ -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");

+ 20 - 1
core/shared/platform/common/posix/posix_thread.c

@@ -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 */

+ 6 - 0
core/shared/platform/windows/win_thread.c

@@ -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;

+ 6 - 2
doc/build_wamr.md

@@ -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

+ 2 - 0
product-mini/platforms/nuttx/wamr.mk

@@ -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)

+ 10 - 0
wamr-compiler/main.c

@@ -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();