Skip to content

Commit 709127d

Browse files
authored
Add callback to handle memory.grow failures (#2522)
When embedding WAMR, this PR allows to register a callback that is invoked when memory.grow fails. In case of memory allocation failures, some languages allow to handle the error (e.g. by checking the return code of malloc/calloc in C), some others (e.g. Rust) just panic.
1 parent 48b71a0 commit 709127d

File tree

6 files changed

+119
-17
lines changed

6 files changed

+119
-17
lines changed

core/iwasm/aot/aot_runtime.c

+3
Original file line numberDiff line numberDiff line change
@@ -1443,6 +1443,9 @@ aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function,
14431443
/* set thread handle and stack boundary */
14441444
wasm_exec_env_set_thread_info(exec_env);
14451445

1446+
/* set exec env so it can be later retrieved from instance */
1447+
((AOTModuleInstanceExtra *)module_inst->e)->common.cur_exec_env = exec_env;
1448+
14461449
if (ext_ret_count > 0) {
14471450
uint32 cell_num = 0, i;
14481451
uint8 *ext_ret_types = func_type->types + func_type->param_count + 1;

core/iwasm/common/wasm_memory.c

+90-17
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "../aot/aot_runtime.h"
99
#include "bh_platform.h"
1010
#include "mem_alloc.h"
11+
#include "wasm_memory.h"
1112

1213
#if WASM_ENABLE_SHARED_MEMORY != 0
1314
#include "../common/wasm_shared_memory.h"
@@ -24,6 +25,8 @@ static Memory_Mode memory_mode = MEMORY_MODE_UNKNOWN;
2425

2526
static mem_allocator_t pool_allocator = NULL;
2627

28+
static enlarge_memory_error_callback_t enlarge_memory_error_cb;
29+
2730
#if WASM_MEM_ALLOC_WITH_USER_DATA != 0
2831
static void *allocator_user_data = NULL;
2932
static void *(*malloc_func)(void *user_data, unsigned int size) = NULL;
@@ -570,13 +573,16 @@ wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count)
570573
{
571574
WASMMemoryInstance *memory = wasm_get_default_memory(module);
572575
uint8 *memory_data_old, *memory_data_new, *heap_data_old;
573-
uint32 num_bytes_per_page, heap_size, total_size_old;
576+
uint32 num_bytes_per_page, heap_size, total_size_old = 0;
574577
uint32 cur_page_count, max_page_count, total_page_count;
575578
uint64 total_size_new;
576579
bool ret = true;
580+
enlarge_memory_error_reason_t failure_reason = INTERNAL_ERROR;
577581

578-
if (!memory)
579-
return false;
582+
if (!memory) {
583+
ret = false;
584+
goto return_func;
585+
}
580586

581587
heap_data_old = memory->heap_data;
582588
heap_size = (uint32)(memory->heap_data_end - memory->heap_data);
@@ -594,9 +600,15 @@ wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count)
594600
/* No need to enlarge memory */
595601
return true;
596602

597-
if (total_page_count < cur_page_count /* integer overflow */
598-
|| total_page_count > max_page_count) {
599-
return false;
603+
if (total_page_count < cur_page_count) { /* integer overflow */
604+
ret = false;
605+
goto return_func;
606+
}
607+
608+
if (total_page_count > max_page_count) {
609+
failure_reason = MAX_SIZE_REACHED;
610+
ret = false;
611+
goto return_func;
600612
}
601613

602614
bh_assert(total_size_new <= 4 * (uint64)BH_GB);
@@ -622,14 +634,16 @@ wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count)
622634
if (heap_size > 0) {
623635
if (mem_allocator_is_heap_corrupted(memory->heap_handle)) {
624636
wasm_runtime_show_app_heap_corrupted_prompt();
625-
return false;
637+
ret = false;
638+
goto return_func;
626639
}
627640
}
628641

629642
if (!(memory_data_new =
630643
wasm_runtime_realloc(memory_data_old, (uint32)total_size_new))) {
631644
if (!(memory_data_new = wasm_runtime_malloc((uint32)total_size_new))) {
632-
return false;
645+
ret = false;
646+
goto return_func;
633647
}
634648
if (memory_data_old) {
635649
bh_memcpy_s(memory_data_new, (uint32)total_size_new,
@@ -685,19 +699,43 @@ wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count)
685699
os_writegsbase(memory_data_new);
686700
#endif
687701

702+
return_func:
703+
if (!ret && enlarge_memory_error_cb) {
704+
WASMExecEnv *exec_env = NULL;
705+
706+
#if WASM_ENABLE_INTERP != 0
707+
if (module->module_type == Wasm_Module_Bytecode)
708+
exec_env =
709+
((WASMModuleInstanceExtra *)module->e)->common.cur_exec_env;
710+
#endif
711+
#if WASM_ENABLE_AOT != 0
712+
if (module->module_type == Wasm_Module_AoT)
713+
exec_env =
714+
((AOTModuleInstanceExtra *)module->e)->common.cur_exec_env;
715+
#endif
716+
717+
enlarge_memory_error_cb(inc_page_count, total_size_old, 0,
718+
failure_reason,
719+
(WASMModuleInstanceCommon *)module, exec_env);
720+
}
721+
688722
return ret;
689723
}
690724
#else
691725
bool
692726
wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count)
693727
{
694728
WASMMemoryInstance *memory = wasm_get_default_memory(module);
695-
uint32 num_bytes_per_page, total_size_old;
729+
uint32 num_bytes_per_page, total_size_old = 0;
696730
uint32 cur_page_count, max_page_count, total_page_count;
697731
uint64 total_size_new;
732+
bool ret = true;
733+
enlarge_memory_error_reason_t failure_reason = INTERNAL_ERROR;
698734

699-
if (!memory)
700-
return false;
735+
if (!memory) {
736+
ret = false;
737+
goto return_func;
738+
}
701739

702740
num_bytes_per_page = memory->num_bytes_per_page;
703741
cur_page_count = memory->cur_page_count;
@@ -710,9 +748,15 @@ wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count)
710748
/* No need to enlarge memory */
711749
return true;
712750

713-
if (total_page_count < cur_page_count /* integer overflow */
714-
|| total_page_count > max_page_count) {
715-
return false;
751+
if (total_page_count < cur_page_count) { /* integer overflow */
752+
ret = false;
753+
goto return_func;
754+
}
755+
756+
if (total_page_count > max_page_count) {
757+
failure_reason = MAX_SIZE_REACHED;
758+
ret = false;
759+
goto return_func;
716760
}
717761

718762
bh_assert(total_size_new <= 4 * (uint64)BH_GB);
@@ -727,7 +771,8 @@ wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count)
727771
if (!os_mem_commit(memory->memory_data_end,
728772
(uint32)total_size_new - total_size_old,
729773
MMAP_PROT_READ | MMAP_PROT_WRITE)) {
730-
return false;
774+
ret = false;
775+
goto return_func;
731776
}
732777
#endif
733778

@@ -739,7 +784,8 @@ wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count)
739784
os_mem_decommit(memory->memory_data_end,
740785
(uint32)total_size_new - total_size_old);
741786
#endif
742-
return false;
787+
ret = false;
788+
goto return_func;
743789
}
744790

745791
/* The increased pages are filled with zero by the OS when os_mmap,
@@ -759,10 +805,37 @@ wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count)
759805
memory->mem_bound_check_16bytes.u64 = total_size_new - 16;
760806
#endif
761807

762-
return true;
808+
return_func:
809+
if (!ret && enlarge_memory_error_cb) {
810+
WASMExecEnv *exec_env = NULL;
811+
812+
#if WASM_ENABLE_INTERP != 0
813+
if (module->module_type == Wasm_Module_Bytecode)
814+
exec_env =
815+
((WASMModuleInstanceExtra *)module->e)->common.cur_exec_env;
816+
#endif
817+
#if WASM_ENABLE_AOT != 0
818+
if (module->module_type == Wasm_Module_AoT)
819+
exec_env =
820+
((AOTModuleInstanceExtra *)module->e)->common.cur_exec_env;
821+
#endif
822+
823+
enlarge_memory_error_cb(inc_page_count, total_size_old, 0,
824+
failure_reason,
825+
(WASMModuleInstanceCommon *)module, exec_env);
826+
}
827+
828+
return ret;
763829
}
764830
#endif /* end of OS_ENABLE_HW_BOUND_CHECK */
765831

832+
void
833+
wasm_runtime_set_enlarge_mem_error_callback(
834+
const enlarge_memory_error_callback_t callback)
835+
{
836+
enlarge_memory_error_cb = callback;
837+
}
838+
766839
bool
767840
wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count)
768841
{

core/iwasm/common/wasm_memory.h

+4
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ wasm_runtime_memory_destroy();
2424
unsigned
2525
wasm_runtime_memory_pool_size();
2626

27+
void
28+
wasm_runtime_set_enlarge_mem_error_callback(
29+
const enlarge_memory_error_callback_t callback);
30+
2731
#ifdef __cplusplus
2832
}
2933
#endif

core/iwasm/include/wasm_export.h

+17
Original file line numberDiff line numberDiff line change
@@ -1439,6 +1439,23 @@ WASM_RUNTIME_API_EXTERN bool
14391439
wasm_runtime_is_import_global_linked(const char *module_name,
14401440
const char *global_name);
14411441

1442+
typedef enum {
1443+
INTERNAL_ERROR,
1444+
MAX_SIZE_REACHED,
1445+
} enlarge_memory_error_reason_t;
1446+
1447+
typedef void (*enlarge_memory_error_callback_t)(
1448+
uint32_t inc_page_count, uint64_t current_memory_size,
1449+
uint32_t memory_index, enlarge_memory_error_reason_t failure_reason,
1450+
wasm_module_inst_t instance, wasm_exec_env_t exec_env);
1451+
1452+
/**
1453+
* Setup callback invoked when memory.grow fails
1454+
*/
1455+
WASM_RUNTIME_API_EXTERN void
1456+
wasm_runtime_set_enlarge_mem_error_callback(
1457+
const enlarge_memory_error_callback_t callback);
1458+
14421459
/* clang-format on */
14431460

14441461
#ifdef __cplusplus

core/iwasm/interpreter/wasm_runtime.c

+3
Original file line numberDiff line numberDiff line change
@@ -2400,6 +2400,9 @@ wasm_call_function(WASMExecEnv *exec_env, WASMFunctionInstance *function,
24002400
/* set thread handle and stack boundary */
24012401
wasm_exec_env_set_thread_info(exec_env);
24022402

2403+
/* set exec env so it can be later retrieved from instance */
2404+
module_inst->e->common.cur_exec_env = exec_env;
2405+
24032406
interp_call_wasm(module_inst, exec_env, function, argc, argv);
24042407
return !wasm_copy_exception(module_inst, NULL);
24052408
}

core/iwasm/interpreter/wasm_runtime.h

+2
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,8 @@ typedef struct CApiFuncImport {
213213
/* The common part of WASMModuleInstanceExtra and AOTModuleInstanceExtra */
214214
typedef struct WASMModuleInstanceExtraCommon {
215215
CApiFuncImport *c_api_func_imports;
216+
/* pointer to the exec env currently used */
217+
WASMExecEnv *cur_exec_env;
216218
#if WASM_CONFIGUABLE_BOUNDS_CHECKS != 0
217219
/* Disable bounds checks or not */
218220
bool disable_bounds_checks;

0 commit comments

Comments
 (0)