From f231f3ce301f205f1eb0f76ba44d917a7a272abd Mon Sep 17 00:00:00 2001 From: TL Date: Thu, 20 Nov 2025 17:46:13 +0800 Subject: [PATCH 1/5] Allow HW OOB exception propagate from callee to caller when multi-module is enabled --- core/iwasm/common/wasm_exec_env.h | 4 ++++ core/iwasm/common/wasm_runtime_common.c | 18 +++++++++++++++++ core/iwasm/interpreter/wasm_runtime.c | 27 +++++++++++++++++++++++++ core/iwasm/interpreter/wasm_runtime.h | 4 ++++ 4 files changed, 53 insertions(+) diff --git a/core/iwasm/common/wasm_exec_env.h b/core/iwasm/common/wasm_exec_env.h index 5d80312fb..6083280b4 100644 --- a/core/iwasm/common/wasm_exec_env.h +++ b/core/iwasm/common/wasm_exec_env.h @@ -30,6 +30,10 @@ typedef struct WASMCurrentEnvStatus WASMCurrentEnvStatus; typedef struct WASMJmpBuf { struct WASMJmpBuf *prev; korp_jmpbuf jmpbuf; +#if WASM_ENABLE_MULTI_MODULE != 0 + /* The owner module instance associated with the current jmpbuf. Used in multi-module to propagate the exception */ + struct WASMModuleInstanceCommon *module_inst; +#endif } WASMJmpBuf; #endif diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 259816e0b..7a5ded2cf 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -248,6 +248,15 @@ runtime_signal_handler(void *sig_addr) if (is_sig_addr_in_guard_pages(sig_addr, module_inst)) { wasm_set_exception(module_inst, "out of bounds memory access"); +#if WASM_ENABLE_MULTI_MODULE != 0 + if (jmpbuf_node->module_inst + && jmpbuf_node->module_inst + != (WASMModuleInstanceCommon *)module_inst) { + wasm_runtime_propagate_exception_from_import( + (WASMModuleInstance *)jmpbuf_node->module_inst, + module_inst); + } +#endif os_longjmp(jmpbuf_node->jmpbuf, 1); } #if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0 @@ -375,6 +384,15 @@ runtime_exception_handler(EXCEPTION_POINTERS *exce_info) the wasm func returns, the caller will check whether the exception is thrown and return to runtime. */ wasm_set_exception(module_inst, "out of bounds memory access"); +#if WASM_ENABLE_MULTI_MODULE != 0 + if (jmpbuf_node->module_inst + && jmpbuf_node->module_inst + != (WASMModuleInstanceCommon *)module_inst) { + wasm_runtime_propagate_exception_from_import( + (WASMModuleInstance *)jmpbuf_node->module_inst, + module_inst); + } +#endif ret = next_action(module_inst, exce_info); if (ret == EXCEPTION_CONTINUE_SEARCH || ret == EXCEPTION_CONTINUE_EXECUTION) diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index a59bc9257..f07950630 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -103,6 +103,29 @@ wasm_resolve_symbols(WASMModule *module) return ret; } +#if WASM_ENABLE_MULTI_MODULE != 0 +void +wasm_runtime_propagate_exception_from_import(WASMModuleInstance *parent, + WASMModuleInstance *sub_module) +{ + static const char exception_prefix[] = "Exception: "; + const char *message = NULL; + + if (!parent || !sub_module) + return; + + message = wasm_get_exception(sub_module); + if (message && message[0] != '\0') { + if (!strncmp(message, exception_prefix, sizeof(exception_prefix) - 1)) { + message += sizeof(exception_prefix) - 1; + } + + wasm_set_exception(parent, message); + wasm_set_exception(sub_module, NULL); + } +} +#endif + #if WASM_ENABLE_MULTI_MODULE != 0 static WASMFunction * wasm_resolve_function(const char *module_name, const char *function_name, @@ -3621,6 +3644,10 @@ call_wasm_with_hw_bound_check(WASMModuleInstance *module_inst, return; } +#if WASM_ENABLE_MULTI_MODULE != 0 + jmpbuf_node.module_inst = (WASMModuleInstanceCommon *)module_inst; +#endif + wasm_exec_env_push_jmpbuf(exec_env, &jmpbuf_node); if (os_setjmp(jmpbuf_node.jmpbuf) == 0) { diff --git a/core/iwasm/interpreter/wasm_runtime.h b/core/iwasm/interpreter/wasm_runtime.h index 0ba2049af..fef6eda43 100644 --- a/core/iwasm/interpreter/wasm_runtime.h +++ b/core/iwasm/interpreter/wasm_runtime.h @@ -593,6 +593,10 @@ wasm_lookup_tag(const WASMModuleInstance *module_inst, const char *name, const char *signature); #endif +void +wasm_runtime_propagate_exception_from_import(WASMModuleInstance *parent, + WASMModuleInstance *sub_module); + #endif bool From 52bc83d8df218d4ba1ba11ada90f7e7b40df0710 Mon Sep 17 00:00:00 2001 From: TL Date: Thu, 20 Nov 2025 18:00:29 +0800 Subject: [PATCH 2/5] format --- core/iwasm/common/wasm_exec_env.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/iwasm/common/wasm_exec_env.h b/core/iwasm/common/wasm_exec_env.h index 6083280b4..827cf3d27 100644 --- a/core/iwasm/common/wasm_exec_env.h +++ b/core/iwasm/common/wasm_exec_env.h @@ -31,9 +31,10 @@ typedef struct WASMJmpBuf { struct WASMJmpBuf *prev; korp_jmpbuf jmpbuf; #if WASM_ENABLE_MULTI_MODULE != 0 - /* The owner module instance associated with the current jmpbuf. Used in multi-module to propagate the exception */ + /* The owner module instance associated with the current jmpbuf. Used in + * multi-module to propagate the exception */ struct WASMModuleInstanceCommon *module_inst; -#endif +#endif } WASMJmpBuf; #endif From 83c87df6385964dca45690f007a34ebdaef9796f Mon Sep 17 00:00:00 2001 From: TL Date: Mon, 24 Nov 2025 09:44:55 +0800 Subject: [PATCH 3/5] fix compile error, making it work with AOT --- core/iwasm/common/wasm_runtime_common.c | 22 ++++++++++++++++++++++ core/iwasm/common/wasm_runtime_common.h | 4 ++++ core/iwasm/interpreter/wasm_runtime.c | 23 ----------------------- core/iwasm/interpreter/wasm_runtime.h | 4 ---- 4 files changed, 26 insertions(+), 27 deletions(-) diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 7a5ded2cf..d50db068d 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -85,6 +85,28 @@ static korp_mutex loading_module_list_lock; static bh_list registered_module_list_head; static bh_list *const registered_module_list = ®istered_module_list_head; static korp_mutex registered_module_list_lock; + +void +wasm_runtime_propagate_exception_from_import( + WASMModuleInstanceCommon *parent, WASMModuleInstanceCommon *sub_module) +{ + static const char exception_prefix[] = "Exception: "; + const char *message = NULL; + + if (!parent || !sub_module) + return; + + message = wasm_get_exception(sub_module); + if (message && message[0] != '\0') { + if (!strncmp(message, exception_prefix, sizeof(exception_prefix) - 1)) { + message += sizeof(exception_prefix) - 1; + } + + wasm_set_exception(parent, message); + wasm_set_exception(sub_module, NULL); + } +} + static void wasm_runtime_destroy_registered_module_list(void); #endif /* WASM_ENABLE_MULTI_MODULE */ diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index 88f23485e..995f7236c 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -578,6 +578,10 @@ typedef struct WASMRegisteredModule { uint8 *orig_file_buf; uint32 orig_file_buf_size; } WASMRegisteredModule; + +void +wasm_runtime_propagate_exception_from_import( + WASMModuleInstanceCommon *parent, WASMModuleInstanceCommon *sub_module); #endif typedef package_type_t PackageType; diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index f07950630..7ac6a66fc 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -103,29 +103,6 @@ wasm_resolve_symbols(WASMModule *module) return ret; } -#if WASM_ENABLE_MULTI_MODULE != 0 -void -wasm_runtime_propagate_exception_from_import(WASMModuleInstance *parent, - WASMModuleInstance *sub_module) -{ - static const char exception_prefix[] = "Exception: "; - const char *message = NULL; - - if (!parent || !sub_module) - return; - - message = wasm_get_exception(sub_module); - if (message && message[0] != '\0') { - if (!strncmp(message, exception_prefix, sizeof(exception_prefix) - 1)) { - message += sizeof(exception_prefix) - 1; - } - - wasm_set_exception(parent, message); - wasm_set_exception(sub_module, NULL); - } -} -#endif - #if WASM_ENABLE_MULTI_MODULE != 0 static WASMFunction * wasm_resolve_function(const char *module_name, const char *function_name, diff --git a/core/iwasm/interpreter/wasm_runtime.h b/core/iwasm/interpreter/wasm_runtime.h index fef6eda43..0ba2049af 100644 --- a/core/iwasm/interpreter/wasm_runtime.h +++ b/core/iwasm/interpreter/wasm_runtime.h @@ -593,10 +593,6 @@ wasm_lookup_tag(const WASMModuleInstance *module_inst, const char *name, const char *signature); #endif -void -wasm_runtime_propagate_exception_from_import(WASMModuleInstance *parent, - WASMModuleInstance *sub_module); - #endif bool From 9492cabfa3ee8feee6154f299190d83a8dfbdbda Mon Sep 17 00:00:00 2001 From: TL Date: Mon, 24 Nov 2025 11:55:32 +0800 Subject: [PATCH 4/5] only handle memory OOB exception --- core/iwasm/common/wasm_runtime_common.c | 75 ++++++++++++++++++++++--- core/iwasm/common/wasm_runtime_common.h | 2 + 2 files changed, 68 insertions(+), 9 deletions(-) diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index d50db068d..4fcfd231d 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -90,20 +90,77 @@ void wasm_runtime_propagate_exception_from_import( WASMModuleInstanceCommon *parent, WASMModuleInstanceCommon *sub_module) { - static const char exception_prefix[] = "Exception: "; + static const uint32 exception_prefix_len = sizeof("Exception: ") - 1; + static const char memory_oob_exception[] = "out of bounds memory access"; + char exception_buf[EXCEPTION_BUF_LEN] = { 0 }; const char *message = NULL; + bool has_exception = false; if (!parent || !sub_module) return; - message = wasm_get_exception(sub_module); - if (message && message[0] != '\0') { - if (!strncmp(message, exception_prefix, sizeof(exception_prefix) - 1)) { - message += sizeof(exception_prefix) - 1; + switch (sub_module->module_type) { +#if WASM_ENABLE_INTERP != 0 + case Wasm_Module_Bytecode: + has_exception = wasm_copy_exception( + (WASMModuleInstance *)sub_module, exception_buf); + break; +#endif +#if WASM_ENABLE_AOT != 0 + case Wasm_Module_AoT: + has_exception = aot_copy_exception((AOTModuleInstance *)sub_module, + exception_buf); + break; +#endif + default: + return; + } + + if (has_exception) { + message = exception_buf; + if (strlen(message) >= exception_prefix_len) { + message += exception_prefix_len; + } + else { + LOG_WARNING("sub-module exception format unexpected: %s", message); + return; } - wasm_set_exception(parent, message); - wasm_set_exception(sub_module, NULL); + if (strcmp(message, memory_oob_exception) != 0) { + LOG_WARNING("skip propagating non-memory-OOB exception: %s", + message); + return; + } + + switch (parent->module_type) { +#if WASM_ENABLE_INTERP != 0 + case Wasm_Module_Bytecode: + wasm_set_exception((WASMModuleInstance *)parent, message); + break; +#endif +#if WASM_ENABLE_AOT != 0 + case Wasm_Module_AoT: + aot_set_exception((AOTModuleInstance *)parent, message); + break; +#endif + default: + break; + } + + switch (sub_module->module_type) { +#if WASM_ENABLE_INTERP != 0 + case Wasm_Module_Bytecode: + wasm_set_exception((WASMModuleInstance *)sub_module, NULL); + break; +#endif +#if WASM_ENABLE_AOT != 0 + case Wasm_Module_AoT: + aot_set_exception((AOTModuleInstance *)sub_module, NULL); + break; +#endif + default: + break; + } } } @@ -275,8 +332,8 @@ runtime_signal_handler(void *sig_addr) && jmpbuf_node->module_inst != (WASMModuleInstanceCommon *)module_inst) { wasm_runtime_propagate_exception_from_import( - (WASMModuleInstance *)jmpbuf_node->module_inst, - module_inst); + (WASMModuleInstanceCommon *)jmpbuf_node->module_inst, + (WASMModuleInstanceCommon *)module_inst); } #endif os_longjmp(jmpbuf_node->jmpbuf, 1); diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index 995f7236c..96cc3e19b 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -579,6 +579,8 @@ typedef struct WASMRegisteredModule { uint32 orig_file_buf_size; } WASMRegisteredModule; +/* Propagate callee's memory OOB exception to caller module in hardware memory + * exception handler */ void wasm_runtime_propagate_exception_from_import( WASMModuleInstanceCommon *parent, WASMModuleInstanceCommon *sub_module); From b8463822eb7a830caf3cdcbe620c16ff68ae12d9 Mon Sep 17 00:00:00 2001 From: TL Date: Mon, 24 Nov 2025 14:33:32 +0800 Subject: [PATCH 5/5] some refactor and add regression test case --- core/iwasm/common/wasm_runtime_common.c | 156 +++++++++--------- tests/regression/ba-issues/build_wamr.sh | 12 +- .../issues/issue-4703/double_page_memory.wasm | Bin 0 -> 132 bytes .../issues/issue-4703/single_page_memory.wasm | Bin 0 -> 88 bytes .../regression/ba-issues/running_config.json | 18 +- 5 files changed, 106 insertions(+), 80 deletions(-) create mode 100644 tests/regression/ba-issues/issues/issue-4703/double_page_memory.wasm create mode 100644 tests/regression/ba-issues/issues/issue-4703/single_page_memory.wasm diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 4fcfd231d..d75d45cf3 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -86,84 +86,6 @@ static bh_list registered_module_list_head; static bh_list *const registered_module_list = ®istered_module_list_head; static korp_mutex registered_module_list_lock; -void -wasm_runtime_propagate_exception_from_import( - WASMModuleInstanceCommon *parent, WASMModuleInstanceCommon *sub_module) -{ - static const uint32 exception_prefix_len = sizeof("Exception: ") - 1; - static const char memory_oob_exception[] = "out of bounds memory access"; - char exception_buf[EXCEPTION_BUF_LEN] = { 0 }; - const char *message = NULL; - bool has_exception = false; - - if (!parent || !sub_module) - return; - - switch (sub_module->module_type) { -#if WASM_ENABLE_INTERP != 0 - case Wasm_Module_Bytecode: - has_exception = wasm_copy_exception( - (WASMModuleInstance *)sub_module, exception_buf); - break; -#endif -#if WASM_ENABLE_AOT != 0 - case Wasm_Module_AoT: - has_exception = aot_copy_exception((AOTModuleInstance *)sub_module, - exception_buf); - break; -#endif - default: - return; - } - - if (has_exception) { - message = exception_buf; - if (strlen(message) >= exception_prefix_len) { - message += exception_prefix_len; - } - else { - LOG_WARNING("sub-module exception format unexpected: %s", message); - return; - } - - if (strcmp(message, memory_oob_exception) != 0) { - LOG_WARNING("skip propagating non-memory-OOB exception: %s", - message); - return; - } - - switch (parent->module_type) { -#if WASM_ENABLE_INTERP != 0 - case Wasm_Module_Bytecode: - wasm_set_exception((WASMModuleInstance *)parent, message); - break; -#endif -#if WASM_ENABLE_AOT != 0 - case Wasm_Module_AoT: - aot_set_exception((AOTModuleInstance *)parent, message); - break; -#endif - default: - break; - } - - switch (sub_module->module_type) { -#if WASM_ENABLE_INTERP != 0 - case Wasm_Module_Bytecode: - wasm_set_exception((WASMModuleInstance *)sub_module, NULL); - break; -#endif -#if WASM_ENABLE_AOT != 0 - case Wasm_Module_AoT: - aot_set_exception((AOTModuleInstance *)sub_module, NULL); - break; -#endif - default: - break; - } - } -} - static void wasm_runtime_destroy_registered_module_list(void); #endif /* WASM_ENABLE_MULTI_MODULE */ @@ -1449,6 +1371,84 @@ wasm_runtime_destroy_loading_module_list() os_mutex_unlock(&loading_module_list_lock); } + +void +wasm_runtime_propagate_exception_from_import( + WASMModuleInstanceCommon *parent, WASMModuleInstanceCommon *sub_module) +{ + static const uint32 exception_prefix_len = sizeof("Exception: ") - 1; + static const char memory_oob_exception[] = "out of bounds memory access"; + char exception_buf[EXCEPTION_BUF_LEN] = { 0 }; + const char *message = NULL; + bool has_exception = false; + + if (!parent || !sub_module) + return; + + switch (sub_module->module_type) { +#if WASM_ENABLE_INTERP != 0 + case Wasm_Module_Bytecode: + has_exception = wasm_copy_exception( + (WASMModuleInstance *)sub_module, exception_buf); + break; +#endif +#if WASM_ENABLE_AOT != 0 + case Wasm_Module_AoT: + has_exception = aot_copy_exception((AOTModuleInstance *)sub_module, + exception_buf); + break; +#endif + default: + return; + } + + if (has_exception) { + message = exception_buf; + if (strlen(message) >= exception_prefix_len) { + message += exception_prefix_len; + } + else { + LOG_WARNING("sub-module exception format unexpected: %s", message); + return; + } + + if (strcmp(message, memory_oob_exception) != 0) { + LOG_WARNING("skip propagating non-memory-OOB exception: %s", + message); + return; + } + + switch (parent->module_type) { +#if WASM_ENABLE_INTERP != 0 + case Wasm_Module_Bytecode: + wasm_set_exception((WASMModuleInstance *)parent, message); + break; +#endif +#if WASM_ENABLE_AOT != 0 + case Wasm_Module_AoT: + aot_set_exception((AOTModuleInstance *)parent, message); + break; +#endif + default: + break; + } + + switch (sub_module->module_type) { +#if WASM_ENABLE_INTERP != 0 + case Wasm_Module_Bytecode: + wasm_set_exception((WASMModuleInstance *)sub_module, NULL); + break; +#endif +#if WASM_ENABLE_AOT != 0 + case Wasm_Module_AoT: + aot_set_exception((AOTModuleInstance *)sub_module, NULL); + break; +#endif + default: + break; + } + } +} #endif /* WASM_ENABLE_MULTI_MODULE */ bool diff --git a/tests/regression/ba-issues/build_wamr.sh b/tests/regression/ba-issues/build_wamr.sh index 76562c5a9..3f0fd82e1 100755 --- a/tests/regression/ba-issues/build_wamr.sh +++ b/tests/regression/ba-issues/build_wamr.sh @@ -25,8 +25,15 @@ function build_iwasm() { cd ${WORK_DIR}/build && if [ -d build-iwasm-$2 ]; then rm -rf build-iwasm-$2; else mkdir build-iwasm-$2; fi && cd build-iwasm-$2 && + + # default: enable asan, when pass false, disable asan + SANITIZER_FLAG="-DWAMR_BUILD_SANITIZER=asan" + if [ "$3" = "false" ]; then + SANITIZER_FLAG="" + fi + cmake ${WAMR_DIR}/product-mini/platforms/${PLATFORM} $1 \ - -DCMAKE_BUILD_TYPE=Debug -DWAMR_BUILD_SANITIZER=asan && + -DCMAKE_BUILD_TYPE=Debug ${SANITIZER_FLAG} && make -j 4 if [ "$?" != 0 ]; then echo -e "build iwasm failed" @@ -60,4 +67,7 @@ build_iwasm "-DWAMR_BUILD_REF_TYPES=1 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LIBC_WASI= # build multi-tier-jit iwasm for testing classic-interp, fast-jit, llvm-jit and multi-tier-jit with libc-wasi disabled build_iwasm "-DWAMR_BUILD_REF_TYPES=1 -DWAMR_BUILD_FAST_JIT=1 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LIBC_WASI=0" "multi-tier-jit-wasi-disabled" +# build default iwasm for testing multi-module +build_iwasm "-DWAMR_BUILD_MULTI_MODULE=1 -DWAMR_BUILD_MULTI_MEMORY=1 -DWAMR_BUILD_AOT=0 -DWAMR_BUILD_FAST_INTERP=0" "multi-memory-multi-module" "false" + # TODO: add more version of iwasm, for example, sgx version diff --git a/tests/regression/ba-issues/issues/issue-4703/double_page_memory.wasm b/tests/regression/ba-issues/issues/issue-4703/double_page_memory.wasm new file mode 100644 index 0000000000000000000000000000000000000000..40b600133c55e015734cf518299c2a6eb93b5e0e GIT binary patch literal 132 zcmZQbEY4+QU|?WmWlUgTtY>CoWME}uVn|^)!N{(_%#oX#n_pBJZ^Xm^V;VCtvgIab z=EWN^FmNd{$}>1VJX{q literal 0 HcmV?d00001 diff --git a/tests/regression/ba-issues/running_config.json b/tests/regression/ba-issues/running_config.json index e7a4a3117..3bb9a7a9a 100644 --- a/tests/regression/ba-issues/running_config.json +++ b/tests/regression/ba-issues/running_config.json @@ -1818,6 +1818,22 @@ "stdout content": "Exception: unsupported opcode", "description": "classic-interp will exit gracefully when meeting simd opcodes" } + }, + { + "deprecated": false, + "ids": [ + 4703 + ], + "runtime": "iwasm-multi-memory-multi-module", + "file": "single_page_memory.wasm", + "mode": "classic-interp", + "options": "--module-path=./issues/issue-4703", + "argument": "", + "expected return": { + "ret code": 1, + "stdout content": "Exception: out of bounds memory access", + "description": "when encounter memory OOB in sub-module when hardware bondary check is enabled, report exception correctly instead of silent exit" + } } ] -} +} \ No newline at end of file