-
Notifications
You must be signed in to change notification settings - Fork 728
Add a check about WASI ABI compatibility #913
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 a check about WASI ABI compatibility #913
Conversation
d1586d8 to
e583a71
Compare
core/iwasm/common/wasm_application.c
Outdated
| NULL); | ||
| } | ||
| else { | ||
| wasm_runtime_set_exception( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should not set exception here: (1) Must the wasm app compiled as wasi mode export _start function? (2) Here the WASM_ENABLE_LIBC_WASI is enabled, but it doesn't require that the wasm app must be a wasi mode app, the app can be non-wasi mode also, for example /opt/wasi-sdk/bin/clang -nostdlib --no-entry --export=__main_argc_argv ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If with WASI, a .wasm is either a command or a reactor. There should be not a third case. So. YES we run the WASM app if there is a _start. And we quit with a message if there is no _start.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Plus, we shall treat -nostdlib as a behavior of disabled WASI.
|
|
||
| WASMFunctionInstanceCommon * | ||
| wasm_runtime_lookup_function(WASMModuleInstanceCommon *const module_inst, | ||
| wasm_runtime_lookup_function(WASMModuleInstanceCommon *module_inst, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shall we not change the API's prototype? I had a test, it doesn't cause compile error or warning. Here using const is reasonable, and the API had been used for a long time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we not change the function prototype?
core/iwasm/common/wasm_application.c
Outdated
| } | ||
| #else | ||
| const char *function_name = name; | ||
| function_name = name; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Compile warning occurs: assignment discards ‘const’ qualifier from pointer target type
| wasm_loader_find_export(module, "", "_initialize", EXPORT_KIND_FUNC, | ||
| error_buf, error_buf_size); | ||
| if (!initialize) { | ||
| set_error_buf( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The document mentions that A reactor may export a function named _initialize.. If an _initialize export is present, my understanding is that _initialize function can be exported and also be unexported?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A reactor always has an exported _initialize. Hasn't find any exception.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK. And should we also check that the sub-module should not export _start func, and main-module should not export _initialize func?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure about that. Clang should make sure that _start and _initialize can not be exported at the same time. But it is OK if we want to be safe first. I am open to both.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Plus, if needs a check about signatures of _start and _initialize, we should have it done here.
| */ | ||
| WASMFunctionInstance *initialize = | ||
| wasm_lookup_function(sub_module_inst, "_initialize", NULL); | ||
| /* a strong restricttion that a reactor must export a _initialize |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above, seems that it doesn't require that _initialize function must be exported.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And we should not use macro WASM_ENABLE_LIBC_WASI to check that the wasm app is in wasi mode or not, normally we should use module->is_wasi_mode
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, it is what I am worried about. is_wasi_mode doesn't always equal to WASM_ENABLE_LIBC_WASI=1. It represents a module depends on WASI APIs. If a reactor compiled by WASI_SDK and doesn't include any standard libraries, it will not have any imported entries but still a reactor.
void foo() {}There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it is still a reactor and exports _inititialize, but the function does nothing, whehter to call it or not seems meaningless. There ight be two choices: (1) Call _initialize it is found, (2) Call _initialize when it is found and the module is wasi-module.
And also we should check the func signature of _start and _initialize, they must be "()".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tend to make it simple without considering .wasm is import any wasi_snapshot_preview1 function or not.
| Enclave_C_Flags := $(SGX_COMMON_CFLAGS) -nostdinc -fvisibility=hidden -fpie -fstack-protector $(Enclave_Include_Paths) | ||
| ifeq ($(SPEC_TEST), 1) | ||
| Enclave_C_Flags += -DWASM_ENABLE_SPEC_TEST=1 | ||
| Enclave_C_Flags += -DSGX_DISABLE_WASI |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't disable WASI by default, SGX supports WASI and enables WASI by default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since SPEC test cases are all from WAST and can't be compiled with wasi-sdk-clang and they are not using any WASI apis. we'd better run spec test cases by avoiding WASI module rules.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's because that we didn't check module->is_wasi_mode when calling _start and _initialize. My understanding is that we check the wasi module rules only when the module is wasi moduel, or many non wasi cases may run failed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The point here is we should run SPEC-TEST in non-wasi-mode. the modification won't change the default setting of SGX.
tests/wamr-test-suites/test_wamr.sh
Outdated
| local EXTRA_COMPILE_FLAGS="" | ||
| # default enabled features | ||
| EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_BULK_MEMORY=1" | ||
| EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_LIBC_WASI=0" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Had better not disable wasi by default
| wasm_loader_find_export(module, "", "_initialize", EXPORT_KIND_FUNC, | ||
| error_buf, error_buf_size); | ||
| if (!initialize) { | ||
| set_error_buf( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK. And should we also check that the sub-module should not export _start func, and main-module should not export _initialize func?
|
|
||
| #if (WASM_ENABLE_MULTI_MODULE != 0) && (WASM_ENABLE_LIBC_WASI != 0) | ||
| /* do a check about WASI Application ABI */ | ||
| if (!check_wasi_abi_compatibility(module, main_module, error_buf, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only check the compatibility when module is in wasi mode, or error might occur when it is non-wasi module (e.g. compile with /opt/wasi-sdk/bin/clang -nostdlib):
if (module->is_wasi_mode
&& !check_wasi_abi_compatibility(module, main_module, error_buf,There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shall treat clang -nostdlib equal to WASM_ENABLE_LIBC_WASI=0. I mean we don't accept the third kind of .wasm beyond command/reactor model when `WASM_ENABLE_LIBC_WASI=1.
I guess the initial idea with using -nostdlib is to avoid defining main() and to land our builtin libc feature. since WASI has the command/reactor solution, the workaround for not defining main() should be removed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LIBC_WASI and LIBC_BUILTIN can be enabled at the same time.
| */ | ||
| WASMFunctionInstance *initialize = | ||
| wasm_lookup_function(sub_module_inst, "_initialize", NULL); | ||
| /* a strong restricttion that a reactor must export a _initialize |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it is still a reactor and exports _inititialize, but the function does nothing, whehter to call it or not seems meaningless. There ight be two choices: (1) Call _initialize it is found, (2) Call _initialize when it is found and the module is wasi-module.
And also we should check the func signature of _start and _initialize, they must be "()".
| Enclave_C_Flags := $(SGX_COMMON_CFLAGS) -nostdinc -fvisibility=hidden -fpie -fstack-protector $(Enclave_Include_Paths) | ||
| ifeq ($(SPEC_TEST), 1) | ||
| Enclave_C_Flags += -DWASM_ENABLE_SPEC_TEST=1 | ||
| Enclave_C_Flags += -DSGX_DISABLE_WASI |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's because that we didn't check module->is_wasi_mode when calling _start and _initialize. My understanding is that we check the wasi module rules only when the module is wasi moduel, or many non wasi cases may run failed.
e583a71 to
b4ea10b
Compare
core/iwasm/interpreter/wasm_loader.c
Outdated
| start = wasm_loader_find_export(module, "", "_start", EXPORT_KIND_FUNC, | ||
| error_buf, error_buf_size); | ||
| if (!start) { | ||
| /* without _start(), it maybe a reactor which is run via "iwasm -f | ||
| * XXX reactor" */ | ||
| LOG_VERBOSE("A command should export _start function by default"); | ||
| } | ||
| } | ||
| else { | ||
| initialize = | ||
| wasm_loader_find_export(module, "", "_initialize", EXPORT_KIND_FUNC, | ||
| error_buf, error_buf_size); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have implemented API wasm_runtime_lookup_wasi_start_function() in wasm_runtime_common.h/c, could we implement another API e.g. wasm_runtime_lookup_wasi_initialize_function, and here call them instead?
BTW, in wasm_runtime_lookup_wasi_start_function, we check whether the signature of _start func found is "()", can we also check whether the signature of _initialize is also "()"? Or just adding signature checks here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wasm_runtime_lookup_wasi_start_function requires a module instance and we don't have it yet.
Plan to have a type-check during loading.
| * in a reactor | ||
| */ | ||
| WASMFunctionInstance *initialize = | ||
| wasm_lookup_function(sub_module_inst, "_initialize", NULL); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems had better implement API wasm_runtime_lookup_wasi_initialize_function and check the signature
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
after the type check during loading, we can avoid all secondary check.
core/iwasm/common/wasm_application.c
Outdated
| wasm_runtime_set_exception(module_inst, "lookup main function failed"); | ||
| wasm_runtime_set_exception( | ||
| module_inst, | ||
| "lookup the entry point symbol(like _start, _main, _main) failed"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about "lookup the entry point symbol (e.g. main, _main, __main_argc_argv) failed", _start isn't to be find here, and "_main, _main" is duplicated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
plan to include the else case of L99 missing the _start? maybe we shall create two messages when
WASM_EABLE_LIBC_WASI=1. lookup the entry point symbol (like _start, main, _main, __main_argc_argv) failedWAMS_ENABLE_LIBC_WASI=0. lookup the entry point symbol (like main, _main, __main_argc_argv) failed
|
|
||
| WASMFunctionInstanceCommon * | ||
| wasm_runtime_lookup_function(WASMModuleInstanceCommon *const module_inst, | ||
| wasm_runtime_lookup_function(WASMModuleInstanceCommon *module_inst, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we not change the function prototype?
Refer to: https://github.com/WebAssembly/WASI/blob/main/design/application-abi.md Plus, - refactoring wasm_loader_find_export - remove MULTI_MODULE related from mini_loader - Update the sample of multi-modules - Fix a "use-after-free" problem. Since we are reusing the memory instance of sub-module's, just to pretect from freeing an imported memory instance is enough
b4ea10b to
906625c
Compare
core/iwasm/include/wasm_export.h
Outdated
| */ | ||
| WASM_RUNTIME_API_EXTERN wasm_function_inst_t | ||
| wasm_runtime_lookup_function(wasm_module_inst_t const module_inst, | ||
| wasm_runtime_lookup_function(wasm_module_inst_t module_inst, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should restore const
core/iwasm/interpreter/wasm_loader.c
Outdated
| * | ||
| * observations: | ||
| * - clang always injecting either `_start` into a command | ||
| * - clang always injecting either `_initialize` into a reactor |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how about injects?
core/iwasm/interpreter/wasm_loader.c
Outdated
| } | ||
|
|
||
| /* should have one at least */ | ||
| if (module->is_wasi_module && !start && !initialize) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No sure whether ther rust wasi main module exports _start or not, could you check the standalone case test-rust1?
|
|
||
| memory = wasm_loader_find_export(module, "", "memory", EXPORT_KIND_MEMORY, | ||
| error_buf, error_buf_size); | ||
| if (!memory) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should be is_wasi_module && !memory, non-wasi module doesn't need to export memory
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
non-wasi modules are supposed to be all filtered out in L3527
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it only filters out non wasi module which doesn't export start and initialize
L3532 checks is_wasi_module again
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
L3532 and L3545 are kinds of protection to make sure that from L3552, there are all cases about WASI modules.
|
|
||
| /* filter out non-wasi compatiable modules */ | ||
| if (!module->is_wasi_module && !start && !initialize) { | ||
| return true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wasi compatible modules should have at least one of _start or _initialize. observation 1 and 2.
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
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
Refer to:
https://github.com/WebAssembly/WASI/blob/main/design/application-abi.md
Plus,
just to pretect from freeing an imported memory instance is enough