Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add wasm_runtime_detect_native_stack_overflow_size #3355

Merged
merged 21 commits into from
Apr 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
df96828
add wasm_runtime_detect_native_stack_overflow
yamt Apr 23, 2024
ffa17f3
consume wasm_runtime_detect_native_stack_overflow
yamt Apr 23, 2024
49d2a64
export wasm_runtime_detect_native_stack_overflow
yamt Apr 23, 2024
81e5d03
samples/native-stack-overflow: use wasm_runtime_detect_native_stack_o…
yamt Apr 23, 2024
0c95ad0
Add wasm_runtime_detect_native_stack_overflow_size
yamt Apr 23, 2024
2107dba
interpreters: Check native stack overflow for recursive calls
yamt Apr 23, 2024
32e5b5d
interpreters: Check native stack overflow before calling native funct…
yamt Apr 23, 2024
5b22812
add a comment on wasm_runtime_detect_native_stack_overflow
yamt Apr 24, 2024
b373c27
add a comment on wasm_runtime_detect_native_stack_overflow_size
yamt Apr 24, 2024
9d5c3ac
host_consume_stack: use wasm_runtime_detect_native_stack_overflow_size
yamt Apr 24, 2024
a8ca169
samples/native-stack-overflow: reduce a margin
yamt Apr 24, 2024
0397d4f
CI: build and run samples/native-stack-overflow
yamt Apr 25, 2024
725aac3
samples/native-stack-overflow: clang-format
yamt Apr 25, 2024
a887eca
appease GCC -Wmaybe-uninitialized
yamt Apr 25, 2024
71d02fd
fix build with GCC
yamt Apr 25, 2024
74be598
samples/native-stack-overflow: use size_level=0
yamt Apr 25, 2024
fcfff69
CI: skip samples/native-stack-overflow on macOS arm64
yamt Apr 25, 2024
6607b2f
disable tail-call for gcc
yamt Apr 25, 2024
f6b57ab
minor comment fixes
yamt Apr 25, 2024
be17b3f
simplify
yamt Apr 26, 2024
6196f1c
handle native_stack_boundary==NULL case
yamt Apr 26, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/workflows/compilation_on_android_ubuntu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,13 @@ jobs:
./iwasm wasm-apps/trap.aot | grep "#" > call_stack_aot.txt
bash -x ../symbolicate.sh

- name: Build Sample [native-stack-overflow]
run: |
cd samples/native-stack-overflow
./build.sh
./run.sh test1
./run.sh test2

test:
needs:
[
Expand Down
9 changes: 9 additions & 0 deletions .github/workflows/compilation_on_macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -379,3 +379,12 @@ jobs:
./iwasm wasm-apps/trap.wasm | grep "#" > call_stack.txt
./iwasm wasm-apps/trap.aot | grep "#" > call_stack_aot.txt
bash -x ../symbolicate.sh

# skip on arm64 (macos-14) for now
- name: Build Sample [native-stack-overflow]
if: matrix.os != 'macos-14'
run: |
cd samples/native-stack-overflow
./build.sh
./run.sh test1
./run.sh test2
8 changes: 8 additions & 0 deletions .github/workflows/nightly_run.yml
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,13 @@ jobs:
./build.sh
./run.sh

- name: Build Sample [native-stack-overflow]
run: |
cd samples/native-stack-overflow
./build.sh
./run.sh test1
./run.sh test2

- name: Build Sample [native-lib]
run: |
mkdir build && cd build
Expand All @@ -567,6 +574,7 @@ jobs:
python3 ./sample_test_run.py $(pwd)/out
exit $?
working-directory: ./wamr-app-framework/samples/simple

test:
needs:
[
Expand Down
11 changes: 2 additions & 9 deletions core/iwasm/aot/aot_runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
}

Expand Down Expand Up @@ -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;
}

Expand Down
56 changes: 56 additions & 0 deletions core/iwasm/common/wasm_runtime_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
wenyongh marked this conversation as resolved.
Show resolved Hide resolved
if ((uint8 *)&boundary < boundary) {
wasm_runtime_set_exception(wasm_runtime_get_module_inst(exec_env),
"native stack overflow");
return false;
}
return true;
}
7 changes: 7 additions & 0 deletions core/iwasm/common/wasm_runtime_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
51 changes: 51 additions & 0 deletions core/iwasm/include/wasm_export.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
25 changes: 19 additions & 6 deletions core/iwasm/interpreter/wasm_interp_classic.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)",
Expand Down Expand Up @@ -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
Expand Down
25 changes: 19 additions & 6 deletions core/iwasm/interpreter/wasm_interp_fast.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)))
Expand Down Expand Up @@ -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)",
Expand Down Expand Up @@ -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
Expand Down
7 changes: 1 addition & 6 deletions core/iwasm/interpreter/wasm_runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
}

Expand Down
5 changes: 5 additions & 0 deletions samples/native-stack-overflow/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ if (CMAKE_C_COMPILER_ID MATCHES "Clang" AND CMAKE_C_COMPILER_VERSION VERSION_GRE
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-usage")
endif ()

# GCC doesn't have disable_tail_calls attribute
if (CMAKE_C_COMPILER_ID MATCHES "GNU")
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-optimize-sibling-calls")
endif ()

# build out vmlib
set (WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..)
include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake)
Expand Down
4 changes: 2 additions & 2 deletions samples/native-stack-overflow/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ echo "#################### build wasm apps done"

echo "#################### aot-compile"
WAMRC=${WAMR_DIR}/wamr-compiler/build/wamrc
${WAMRC} -o ${OUT_DIR}/wasm-apps/${OUT_FILE}.aot ${OUT_DIR}/wasm-apps/${OUT_FILE}
${WAMRC} -o ${OUT_DIR}/wasm-apps/${OUT_FILE}.aot --size-level=0 ${OUT_DIR}/wasm-apps/${OUT_FILE}

echo "#################### aot-compile (--bounds-checks=1)"
${WAMRC} -o ${OUT_DIR}/wasm-apps/${OUT_FILE}.aot.bounds-checks --bounds-checks=1 ${OUT_DIR}/wasm-apps/${OUT_FILE}
${WAMRC} -o ${OUT_DIR}/wasm-apps/${OUT_FILE}.aot.bounds-checks --size-level=0 --bounds-checks=1 ${OUT_DIR}/wasm-apps/${OUT_FILE}
2 changes: 1 addition & 1 deletion samples/native-stack-overflow/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ main(int argc, char **argv)
"--------\n");

unsigned int stack;
unsigned int prevstack;
unsigned int prevstack = 0; /* appease GCC -Wmaybe-uninitialized */
unsigned int stack_range_start = 0;
unsigned int stack_range_end = 4096 * 6;
unsigned int step = 16;
Expand Down
Loading
Loading