Add WASI ABI compatibility check for multi-module (#913)

Refer to https://github.com/WebAssembly/WASI/blob/main/design/application-abi.md
to check the WASI ABI compatibility:
- Command (main module) may export _start function with signature "()"
- Reactor (sub module) may export _initialize function with signature "()"
- _start and _initialize can not be exported at the same time
- Reactor cannot export _start function
- Command and Reactor must export memory

And
- Rename module->is_wasi_module to module->import_wasi_api
- Refactor wasm_loader_find_export()
- Remove MULTI_MODULE related codes from mini_loader
- Update multi-module samples
- Fix a "use-after-free" issue. Since we reuse the memory instance of sub module,
   just to protect it from freeing an imported memory instance
This commit is contained in:
liang.he
2021-12-29 11:04:36 +08:00
committed by GitHub
parent 936206f97b
commit 50b6474f54
20 changed files with 654 additions and 219 deletions

View File

@ -48,10 +48,6 @@ static union {
/**
* Implementation of wasm_application_execute_main()
*/
static WASMFunctionInstanceCommon *
resolve_function(const WASMModuleInstanceCommon *module_inst, const char *name);
static bool
check_main_func_type(const WASMType *type)
{
@ -96,23 +92,29 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, int32 argc,
bool ret, is_import_func = true;
#if WASM_ENABLE_LIBC_WASI != 0
if (wasm_runtime_is_wasi_mode(module_inst)) {
/* In wasi mode, we should call function named "_start"
which initializes the wasi envrionment and then calls
the actual main function. Directly call main function
may cause exception thrown. */
if ((func = wasm_runtime_lookup_wasi_start_function(module_inst)))
return wasm_runtime_create_exec_env_and_call_wasm(module_inst, func,
0, NULL);
/* If no start function was found, we execute
the main function as normal */
/* In wasi mode, we should call function named "_start"
which initializes the wasi envrionment and then calls
the actual main function. Directly call main function
may cause exception thrown. */
if ((func = wasm_runtime_lookup_wasi_start_function(module_inst))) {
return wasm_runtime_create_exec_env_and_call_wasm(module_inst, func, 0,
NULL);
}
#endif /* end of WASM_ENABLE_LIBC_WASI */
if (!(func = resolve_function(module_inst, "main"))
&& !(func = resolve_function(module_inst, "__main_argc_argv"))
&& !(func = resolve_function(module_inst, "_main"))) {
wasm_runtime_set_exception(module_inst, "lookup main function failed");
if (!(func = wasm_runtime_lookup_function(module_inst, "main", NULL))
&& !(func = wasm_runtime_lookup_function(module_inst,
"__main_argc_argv", NULL))
&& !(func = wasm_runtime_lookup_function(module_inst, "_main", NULL))) {
#if WASM_ENABLE_LIBC_WASI != 0
wasm_runtime_set_exception(
module_inst, "lookup the entry point symbol (like _start, main, "
"_main, __main_argc_argv) failed");
#else
wasm_runtime_set_exception(module_inst,
"lookup the entry point symbol (like main, "
"_main, __main_argc_argv) failed");
#endif
return false;
}
@ -238,21 +240,23 @@ parse_function_name(char *orig_function_name, char **p_module_name,
* Implementation of wasm_application_execute_func()
*/
static WASMFunctionInstanceCommon *
resolve_function(const WASMModuleInstanceCommon *module_inst, const char *name)
static bool
resolve_function(WASMModuleInstanceCommon *module_inst, const char *name,
WASMFunctionInstanceCommon **out_func,
WASMModuleInstanceCommon **out_module_inst)
{
uint32 i = 0;
WASMFunctionInstanceCommon *ret = NULL;
WASMFunctionInstanceCommon *target_func = NULL;
WASMModuleInstanceCommon *target_inst = NULL;
#if WASM_ENABLE_MULTI_MODULE != 0
WASMModuleInstance *sub_module_inst = NULL;
char *function_name = NULL;
char *orig_name = NULL;
char *sub_module_name = NULL;
char *function_name = NULL;
uint32 length = (uint32)(strlen(name) + 1);
orig_name = runtime_malloc(sizeof(char) * length, NULL, NULL, 0);
if (!orig_name) {
return NULL;
goto LEAVE;
}
strncpy(orig_name, name, length);
@ -264,53 +268,33 @@ resolve_function(const WASMModuleInstanceCommon *module_inst, const char *name)
LOG_DEBUG("%s -> %s and %s", name, sub_module_name, function_name);
if (sub_module_name) {
sub_module_inst = get_sub_module_inst((WASMModuleInstance *)module_inst,
sub_module_name);
if (!sub_module_inst) {
target_inst = (WASMModuleInstanceCommon *)get_sub_module_inst(
(WASMModuleInstance *)module_inst, sub_module_name);
if (!target_inst) {
LOG_DEBUG("can not find a sub module named %s", sub_module_name);
goto LEAVE;
}
}
else {
target_inst = module_inst;
}
#else
const char *function_name = name;
target_inst = module_inst;
#endif
#if WASM_ENABLE_INTERP != 0
if (module_inst->module_type == Wasm_Module_Bytecode) {
WASMModuleInstance *wasm_inst = (WASMModuleInstance *)module_inst;
#if WASM_ENABLE_MULTI_MODULE != 0
wasm_inst = sub_module_inst ? sub_module_inst : wasm_inst;
#endif /* WASM_ENABLE_MULTI_MODULE */
for (i = 0; i < wasm_inst->export_func_count; i++) {
if (!strcmp(wasm_inst->export_functions[i].name, function_name)) {
ret = wasm_inst->export_functions[i].function;
break;
}
}
}
#endif /* WASM_ENABLE_INTERP */
#if WASM_ENABLE_AOT != 0
if (module_inst->module_type == Wasm_Module_AoT) {
AOTModuleInstance *aot_inst = (AOTModuleInstance *)module_inst;
AOTFunctionInstance *export_funcs =
(AOTFunctionInstance *)aot_inst->export_funcs.ptr;
for (i = 0; i < aot_inst->export_func_count; i++) {
if (!strcmp(export_funcs[i].func_name, function_name)) {
ret = &export_funcs[i];
break;
}
}
}
#endif
target_func =
wasm_runtime_lookup_function(target_inst, function_name, NULL);
#if WASM_ENABLE_MULTI_MODULE != 0
LEAVE:
wasm_runtime_free(orig_name);
if (orig_name)
wasm_runtime_free(orig_name);
#endif
return ret;
*out_func = target_func;
*out_module_inst = target_inst;
return target_func;
}
union ieee754_float {
@ -358,7 +342,8 @@ bool
wasm_application_execute_func(WASMModuleInstanceCommon *module_inst,
const char *name, int32 argc, char *argv[])
{
WASMFunctionInstanceCommon *func;
WASMFunctionInstanceCommon *target_func;
WASMModuleInstanceCommon *target_inst;
WASMType *type = NULL;
uint32 argc1, *argv1 = NULL, cell_num = 0, j, k = 0;
int32 i, p, module_type;
@ -368,31 +353,15 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst,
bh_assert(argc >= 0);
LOG_DEBUG("call a function \"%s\" with %d arguments", name, argc);
func = resolve_function(module_inst, name);
if (!func) {
if (!resolve_function(module_inst, name, &target_func, &target_inst)) {
snprintf(buf, sizeof(buf), "lookup function %s failed", name);
wasm_runtime_set_exception(module_inst, buf);
goto fail;
}
#if WASM_ENABLE_INTERP != 0
if (module_inst->module_type == Wasm_Module_Bytecode) {
WASMFunctionInstance *wasm_func = (WASMFunctionInstance *)func;
if (wasm_func->is_import_func
#if WASM_ENABLE_MULTI_MODULE != 0
&& !wasm_func->import_func_inst
#endif
) {
snprintf(buf, sizeof(buf), "lookup function %s failed", name);
wasm_runtime_set_exception(module_inst, buf);
goto fail;
}
}
#endif
module_type = module_inst->module_type;
type = wasm_runtime_get_function_type(func, module_type);
module_type = target_inst->module_type;
type = wasm_runtime_get_function_type(target_func, module_type);
if (!type) {
LOG_ERROR("invalid module instance type");
@ -408,7 +377,7 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst,
cell_num = (argc1 > type->ret_cell_num) ? argc1 : type->ret_cell_num;
total_size = sizeof(uint32) * (uint64)(cell_num > 2 ? cell_num : 2);
if ((!(argv1 = runtime_malloc((uint32)total_size, module_inst, NULL, 0)))) {
if ((!(argv1 = runtime_malloc((uint32)total_size, target_inst, NULL, 0)))) {
goto fail;
}
@ -538,7 +507,7 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst,
void *extern_obj = (void *)(uintptr_t)val;
uint32 externref_idx;
if (!wasm_externref_obj2ref(module_inst, extern_obj,
if (!wasm_externref_obj2ref(target_inst, extern_obj,
&externref_idx)) {
wasm_runtime_set_exception(
module_inst, "map extern object to ref failed");
@ -563,8 +532,8 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst,
bh_assert(p == (int32)argc1);
wasm_runtime_set_exception(module_inst, NULL);
if (!wasm_runtime_create_exec_env_and_call_wasm(module_inst, func, argc1,
argv1)) {
if (!wasm_runtime_create_exec_env_and_call_wasm(target_inst, target_func,
argc1, argv1)) {
goto fail;
}