Add wasm_runtime_detect_native_stack_overflow_size (#3355)
- Add a few API (https://github.com/bytecodealliance/wasm-micro-runtime/issues/3325) ```c wasm_runtime_detect_native_stack_overflow_size wasm_runtime_detect_native_stack_overflow ``` - Adapt the runtime to use them - Adapt samples/native-stack-overflow to use them - Add a few missing overflow checks in the interpreters - Build and run the sample on the CI
This commit is contained in:
@ -1967,8 +1967,6 @@ invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr,
|
||||
AOTModuleInstance *module_inst = (AOTModuleInstance *)exec_env->module_inst;
|
||||
WASMExecEnv *exec_env_tls = wasm_runtime_get_exec_env_tls();
|
||||
WASMJmpBuf jmpbuf_node = { 0 }, *jmpbuf_node_pop;
|
||||
uint32 page_size = os_getpagesize();
|
||||
uint32 guard_page_count = STACK_OVERFLOW_CHECK_GUARD_PAGE_COUNT;
|
||||
#ifdef BH_PLATFORM_WINDOWS
|
||||
int result;
|
||||
bool has_exception;
|
||||
@ -1979,10 +1977,7 @@ invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr,
|
||||
/* Check native stack overflow firstly to ensure we have enough
|
||||
native stack to run the following codes before actually calling
|
||||
the aot function in invokeNative function. */
|
||||
RECORD_STACK_USAGE(exec_env, (uint8 *)&module_inst);
|
||||
if ((uint8 *)&module_inst
|
||||
< exec_env->native_stack_boundary + page_size * guard_page_count) {
|
||||
aot_set_exception_with_id(module_inst, EXCE_NATIVE_STACK_OVERFLOW);
|
||||
if (!wasm_runtime_detect_native_stack_overflow(exec_env)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2790,9 +2785,7 @@ aot_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 table_elem_idx,
|
||||
exec_env->native_stack_boundary must have been set, we don't set
|
||||
it again */
|
||||
|
||||
RECORD_STACK_USAGE(exec_env, (uint8 *)&module_inst);
|
||||
if ((uint8 *)&module_inst < exec_env->native_stack_boundary) {
|
||||
aot_set_exception_with_id(module_inst, EXCE_NATIVE_STACK_OVERFLOW);
|
||||
if (!wasm_runtime_detect_native_stack_overflow(exec_env)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
@ -7015,3 +7015,59 @@ wasm_runtime_get_module_name(wasm_module_t module)
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/*
|
||||
* wasm_runtime_detect_native_stack_overflow
|
||||
*
|
||||
* - raise "native stack overflow" exception if available native stack
|
||||
* at this point is less than WASM_STACK_GUARD_SIZE. in that case,
|
||||
* return false.
|
||||
*
|
||||
* - update native_stack_top_min.
|
||||
*/
|
||||
bool
|
||||
wasm_runtime_detect_native_stack_overflow(WASMExecEnv *exec_env)
|
||||
{
|
||||
uint8 *boundary = exec_env->native_stack_boundary;
|
||||
RECORD_STACK_USAGE(exec_env, (uint8 *)&boundary);
|
||||
if (boundary == NULL) {
|
||||
/* the platfrom doesn't support os_thread_get_stack_boundary */
|
||||
return true;
|
||||
}
|
||||
#if defined(OS_ENABLE_HW_BOUND_CHECK) && WASM_DISABLE_STACK_HW_BOUND_CHECK == 0
|
||||
uint32 page_size = os_getpagesize();
|
||||
uint32 guard_page_count = STACK_OVERFLOW_CHECK_GUARD_PAGE_COUNT;
|
||||
boundary = boundary + page_size * guard_page_count;
|
||||
#endif
|
||||
if ((uint8 *)&boundary < boundary) {
|
||||
wasm_runtime_set_exception(wasm_runtime_get_module_inst(exec_env),
|
||||
"native stack overflow");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
wasm_runtime_detect_native_stack_overflow_size(WASMExecEnv *exec_env,
|
||||
uint32 requested_size)
|
||||
{
|
||||
uint8 *boundary = exec_env->native_stack_boundary;
|
||||
RECORD_STACK_USAGE(exec_env, (uint8 *)&boundary);
|
||||
if (boundary == NULL) {
|
||||
/* the platfrom doesn't support os_thread_get_stack_boundary */
|
||||
return true;
|
||||
}
|
||||
#if defined(OS_ENABLE_HW_BOUND_CHECK) && WASM_DISABLE_STACK_HW_BOUND_CHECK == 0
|
||||
uint32 page_size = os_getpagesize();
|
||||
uint32 guard_page_count = STACK_OVERFLOW_CHECK_GUARD_PAGE_COUNT;
|
||||
boundary = boundary + page_size * guard_page_count;
|
||||
#endif
|
||||
/* adjust the boundary for the requested size */
|
||||
boundary = boundary - WASM_STACK_GUARD_SIZE + requested_size;
|
||||
if ((uint8 *)&boundary < boundary) {
|
||||
wasm_runtime_set_exception(wasm_runtime_get_module_inst(exec_env),
|
||||
"native stack overflow");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1189,6 +1189,13 @@ wasm_runtime_end_blocking_op(WASMExecEnv *exec_env);
|
||||
void
|
||||
wasm_runtime_interrupt_blocking_op(WASMExecEnv *exec_env);
|
||||
|
||||
WASM_RUNTIME_API_EXTERN bool
|
||||
wasm_runtime_detect_native_stack_overflow(WASMExecEnv *exec_env);
|
||||
|
||||
WASM_RUNTIME_API_EXTERN bool
|
||||
wasm_runtime_detect_native_stack_overflow_size(WASMExecEnv *exec_env,
|
||||
uint32 requested_size);
|
||||
|
||||
#if WASM_ENABLE_LINUX_PERF != 0
|
||||
bool
|
||||
wasm_runtime_get_linux_perf(void);
|
||||
|
||||
@ -1756,6 +1756,57 @@ wasm_runtime_set_module_name(wasm_module_t module, const char *name,
|
||||
WASM_RUNTIME_API_EXTERN const char *
|
||||
wasm_runtime_get_module_name(wasm_module_t module);
|
||||
|
||||
/*
|
||||
* wasm_runtime_detect_native_stack_overflow
|
||||
*
|
||||
* Detect native stack shortage.
|
||||
* Ensure that the calling thread still has a reasonable amount of
|
||||
* native stack (WASM_STACK_GUARD_SIZE bytes) available.
|
||||
*
|
||||
* If enough stack is left, this function returns true.
|
||||
* Otherwise, this function raises a "native stack overflow" trap and
|
||||
* returns false.
|
||||
*
|
||||
* Note: please do not expect a very strict detection. it's a good idea
|
||||
* to give some margins. wasm_runtime_detect_native_stack_overflow itself
|
||||
* requires a small amount of stack to run.
|
||||
*/
|
||||
WASM_RUNTIME_API_EXTERN bool
|
||||
wasm_runtime_detect_native_stack_overflow(wasm_exec_env_t exec_env);
|
||||
|
||||
/*
|
||||
* wasm_runtime_detect_native_stack_overflow_size
|
||||
*
|
||||
* Similar to wasm_runtime_detect_native_stack_overflow,
|
||||
* but use the caller-specified size instead of WASM_STACK_GUARD_SIZE.
|
||||
*
|
||||
* An expected usage:
|
||||
* ```c
|
||||
* __attribute__((noinline)) // inlining can break the stack check
|
||||
* void stack_hog(void)
|
||||
* {
|
||||
* // consume a lot of stack here
|
||||
* }
|
||||
*
|
||||
* void
|
||||
* stack_hog_wrapper(exec_env) {
|
||||
* // the amount of stack stack_hog would consume,
|
||||
* // plus a small margin
|
||||
* uint32_t size = 10000000;
|
||||
*
|
||||
* if (!wasm_runtime_detect_native_stack_overflow_size(exec_env, size)) {
|
||||
* // wasm_runtime_detect_native_stack_overflow_size has raised
|
||||
* // a trap.
|
||||
* return;
|
||||
* }
|
||||
* stack_hog();
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
WASM_RUNTIME_API_EXTERN bool
|
||||
wasm_runtime_detect_native_stack_overflow_size(wasm_exec_env_t exec_env,
|
||||
uint32_t required_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1159,6 +1159,10 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst,
|
||||
uint8 *frame_ref;
|
||||
#endif
|
||||
|
||||
if (!wasm_runtime_detect_native_stack_overflow(exec_env)) {
|
||||
return;
|
||||
}
|
||||
|
||||
all_cell_num = local_cell_num;
|
||||
#if WASM_ENABLE_GC != 0
|
||||
all_cell_num += (local_cell_num + 3) / 4;
|
||||
@ -1290,6 +1294,14 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
|
||||
uintptr_t aux_stack_origin_boundary = 0;
|
||||
uintptr_t aux_stack_origin_bottom = 0;
|
||||
|
||||
/*
|
||||
* perform stack overflow check before calling
|
||||
* wasm_interp_call_func_bytecode recursively.
|
||||
*/
|
||||
if (!wasm_runtime_detect_native_stack_overflow(exec_env)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sub_func_inst) {
|
||||
snprintf(buf, sizeof(buf),
|
||||
"failed to call unlinked import function (%s, %s)",
|
||||
@ -7108,12 +7120,13 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
|
||||
}
|
||||
argc = function->param_cell_num;
|
||||
|
||||
RECORD_STACK_USAGE(exec_env, (uint8 *)&prev_frame);
|
||||
#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");
|
||||
#if defined(OS_ENABLE_HW_BOUND_CHECK) && WASM_DISABLE_STACK_HW_BOUND_CHECK == 0
|
||||
/*
|
||||
* wasm_runtime_detect_native_stack_overflow is done by
|
||||
* call_wasm_with_hw_bound_check.
|
||||
*/
|
||||
#else
|
||||
if (!wasm_runtime_detect_native_stack_overflow(exec_env)) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1167,6 +1167,10 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst,
|
||||
all_cell_num += (local_cell_num + 3) / 4;
|
||||
#endif
|
||||
|
||||
if (!wasm_runtime_detect_native_stack_overflow(exec_env)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(frame =
|
||||
ALLOC_FRAME(exec_env, wasm_interp_interp_frame_size(all_cell_num),
|
||||
prev_frame)))
|
||||
@ -1275,6 +1279,14 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
|
||||
uintptr_t aux_stack_origin_boundary = 0;
|
||||
uintptr_t aux_stack_origin_bottom = 0;
|
||||
|
||||
/*
|
||||
* perform stack overflow check before calling
|
||||
* wasm_interp_call_func_bytecode recursively.
|
||||
*/
|
||||
if (!wasm_runtime_detect_native_stack_overflow(exec_env)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sub_func_inst) {
|
||||
snprintf(buf, sizeof(buf),
|
||||
"failed to call unlinked import function (%s, %s)",
|
||||
@ -6081,12 +6093,13 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
|
||||
}
|
||||
argc = function->param_cell_num;
|
||||
|
||||
RECORD_STACK_USAGE(exec_env, (uint8 *)&prev_frame);
|
||||
#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");
|
||||
#if defined(OS_ENABLE_HW_BOUND_CHECK) && WASM_DISABLE_STACK_HW_BOUND_CHECK == 0
|
||||
/*
|
||||
* wasm_runtime_detect_native_stack_overflow is done by
|
||||
* call_wasm_with_hw_bound_check.
|
||||
*/
|
||||
#else
|
||||
if (!wasm_runtime_detect_native_stack_overflow(exec_env)) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -3139,8 +3139,6 @@ call_wasm_with_hw_bound_check(WASMModuleInstance *module_inst,
|
||||
{
|
||||
WASMExecEnv *exec_env_tls = wasm_runtime_get_exec_env_tls();
|
||||
WASMJmpBuf jmpbuf_node = { 0 }, *jmpbuf_node_pop;
|
||||
uint32 page_size = os_getpagesize();
|
||||
uint32 guard_page_count = STACK_OVERFLOW_CHECK_GUARD_PAGE_COUNT;
|
||||
WASMRuntimeFrame *prev_frame = wasm_exec_env_get_cur_frame(exec_env);
|
||||
uint8 *prev_top = exec_env->wasm_stack.top;
|
||||
#ifdef BH_PLATFORM_WINDOWS
|
||||
@ -3153,10 +3151,7 @@ call_wasm_with_hw_bound_check(WASMModuleInstance *module_inst,
|
||||
/* Check native stack overflow firstly to ensure we have enough
|
||||
native stack to run the following codes before actually calling
|
||||
the aot function in invokeNative function. */
|
||||
RECORD_STACK_USAGE(exec_env, (uint8 *)&exec_env_tls);
|
||||
if ((uint8 *)&exec_env_tls
|
||||
< exec_env->native_stack_boundary + page_size * guard_page_count) {
|
||||
wasm_set_exception(module_inst, "native stack overflow");
|
||||
if (!wasm_runtime_detect_native_stack_overflow(exec_env)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user