diff --git a/.github/workflows/compilation_on_android_ubuntu_macos.yml b/.github/workflows/compilation_on_android_ubuntu_macos.yml index 627ea7460..d15d0649e 100644 --- a/.github/workflows/compilation_on_android_ubuntu_macos.yml +++ b/.github/workflows/compilation_on_android_ubuntu_macos.yml @@ -11,6 +11,7 @@ on: - "ci/**" - "doc/**" - "test-tools/**" + - ".github/workflows/compilation_on_android_ubuntu_macos.yml" # will be triggered on push events push: paths-ignore: @@ -18,6 +19,7 @@ on: - "ci/**" - "doc/**" - "test-tools/**" + - ".github/workflows/compilation_on_android_ubuntu_macos.yml" # allow to be triggered manually workflow_dispatch: diff --git a/.github/workflows/compilation_on_sgx.yml b/.github/workflows/compilation_on_sgx.yml index 3289fa3fe..621ed953d 100644 --- a/.github/workflows/compilation_on_sgx.yml +++ b/.github/workflows/compilation_on_sgx.yml @@ -11,6 +11,7 @@ on: - "ci/**" - "doc/**" - "test-tools/**" + - ".github/workflows/compilation_on_sgx.yml" # will be triggered on push events push: paths-ignore: @@ -18,6 +19,7 @@ on: - "ci/**" - "doc/**" - "test-tools/**" + - ".github/workflows/compilation_on_sgx.yml" # allow to be triggered manually workflow_dispatch: diff --git a/.github/workflows/compilation_on_windows.yml b/.github/workflows/compilation_on_windows.yml index 7560eea59..5306f784b 100644 --- a/.github/workflows/compilation_on_windows.yml +++ b/.github/workflows/compilation_on_windows.yml @@ -11,6 +11,7 @@ on: - "ci/**" - "doc/**" - "test-tools/**" + - ".github/workflows/compilation_on_windows.yml" # will be triggered on push events push: paths-ignore: @@ -18,6 +19,7 @@ on: - "ci/**" - "doc/**" - "test-tools/**" + - ".github/workflows/compilation_on_windows.yml" # allow to be triggered manually workflow_dispatch: diff --git a/.github/workflows/spec_test.yml b/.github/workflows/spec_test.yml index f5b4002f2..336d19379 100644 --- a/.github/workflows/spec_test.yml +++ b/.github/workflows/spec_test.yml @@ -13,6 +13,7 @@ on: - "product-mini/**" - "tests/wamr-test-suites/spec-test-script/**" - "tests/wamr-test-suites/test_wamr.sh" + - ".github/workflows/spec_test.yml" # will be triggered on push events push: paths: @@ -23,6 +24,7 @@ on: - "product-mini/**" - "tests/wamr-test-suites/spec-test-script/**" - "tests/wamr-test-suites/test_wamr.sh" + - ".github/workflows/spec_test.yml" # allow to be triggered manually workflow_dispatch: @@ -140,7 +142,13 @@ jobs: run: echo "::error::can not get prebuilt llvm libraries" && exit 1 - name: install Ninja and x32 support libraries - run: sudo apt install -y g++-multilib libgcc-9-dev lib32gcc-9-dev ninja-build + run: + # Add another apt repository as some packages cannot + # be downloaded with the github default repository + sudo curl -sSL https://packages.microsoft.com/keys/microsoft.asc | sudo tee /etc/apt/trusted.gpg.d/microsoft.asc && + sudo apt-add-repository https://packages.microsoft.com/ubuntu/20.04/prod && + sudo apt-get update && + sudo apt install -y g++-multilib lib32gcc-9-dev ninja-build - name: run spec tests run: ./test_wamr.sh ${{ env.X86_32_TARGET_TEST_OPTIONS }} ${{ matrix.test_option }} diff --git a/.gitignore b/.gitignore index fa9e05133..cb2d2affd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ - +.cache .vs .vscode /.idea diff --git a/core/iwasm/aot/aot_reloc.h b/core/iwasm/aot/aot_reloc.h index c0ca507ed..471bf9c01 100644 --- a/core/iwasm/aot/aot_reloc.h +++ b/core/iwasm/aot/aot_reloc.h @@ -113,6 +113,7 @@ typedef struct { REG_SYM(aot_call_indirect), \ REG_SYM(aot_enlarge_memory), \ REG_SYM(aot_set_exception), \ + REG_SYM(aot_check_app_addr_and_convert),\ { "memset", (void*)aot_memset }, \ { "memmove", (void*)aot_memmove }, \ { "memcpy", (void*)aot_memmove }, \ diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index baa5ce7bc..e4b19a2d9 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -2431,6 +2431,56 @@ aot_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 table_elem_idx, } } +/** + * Check whether the app address and the buf is inside the linear memory, + * and convert the app address into native address + */ +bool +aot_check_app_addr_and_convert(AOTModuleInstance *module_inst, bool is_str, + uint32 app_buf_addr, uint32 app_buf_size, + void **p_native_addr) +{ + AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); + uint8 *native_addr; + + if (!memory_inst) { + goto fail; + } + + native_addr = (uint8 *)memory_inst->memory_data.ptr + app_buf_addr; + + /* No need to check the app_offset and buf_size if memory access + boundary check with hardware trap is enabled */ +#ifndef OS_ENABLE_HW_BOUND_CHECK + if (app_buf_addr >= memory_inst->memory_data_size) { + goto fail; + } + + if (!is_str) { + if (app_buf_size > memory_inst->memory_data_size - app_buf_addr) { + goto fail; + } + } + else { + const char *str, *str_end; + + /* The whole string must be in the linear memory */ + str = (const char *)native_addr; + str_end = (const char *)memory_inst->memory_data_end.ptr; + while (str < str_end && *str != '\0') + str++; + if (str == str_end) + goto fail; + } +#endif + + *p_native_addr = (void *)native_addr; + return true; +fail: + aot_set_exception(module_inst, "out of bounds memory access"); + return false; +} + void * aot_memmove(void *dest, const void *src, size_t n) { diff --git a/core/iwasm/aot/aot_runtime.h b/core/iwasm/aot/aot_runtime.h index 8046880a8..5f1c42e73 100644 --- a/core/iwasm/aot/aot_runtime.h +++ b/core/iwasm/aot/aot_runtime.h @@ -647,6 +647,11 @@ bool aot_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 table_elem_idx, uint32 argc, uint32 *argv); +bool +aot_check_app_addr_and_convert(AOTModuleInstance *module_inst, bool is_str, + uint32 app_buf_addr, uint32 app_buf_size, + void **p_native_addr); + uint32 aot_get_plt_table_size(); diff --git a/core/iwasm/common/wasm_c_api.c b/core/iwasm/common/wasm_c_api.c index 660cdaf05..b19cf75f0 100644 --- a/core/iwasm/common/wasm_c_api.c +++ b/core/iwasm/common/wasm_c_api.c @@ -1947,6 +1947,10 @@ wasm_module_imports(const wasm_module_t *module, own wasm_importtype_vec_t *out) for (i = 0; i != import_count; ++i) { char *module_name_rt = NULL, *field_name_rt = NULL; + memset(&module_name, 0, sizeof(wasm_val_vec_t)); + memset(&name, 0, sizeof(wasm_val_vec_t)); + extern_type = NULL; + if (i < import_func_count) { wasm_functype_t *type = NULL; WASMType *type_rt = NULL; @@ -1974,16 +1978,6 @@ wasm_module_imports(const wasm_module_t *module, own wasm_importtype_vec_t *out) continue; } - wasm_name_new_from_string(&module_name, module_name_rt); - if (strlen(module_name_rt) && !module_name.data) { - goto failed; - } - - wasm_name_new_from_string(&name, field_name_rt); - if (strlen(field_name_rt) && !name.data) { - goto failed; - } - if (!(type = wasm_functype_new_internal(type_rt))) { goto failed; } @@ -2061,16 +2055,6 @@ wasm_module_imports(const wasm_module_t *module, own wasm_importtype_vec_t *out) continue; } - wasm_name_new_from_string(&module_name, module_name_rt); - if (strlen(module_name_rt) && !module_name.data) { - goto failed; - } - - wasm_name_new_from_string(&name, field_name_rt); - if (strlen(field_name_rt) && !name.data) { - goto failed; - } - if (!(type = wasm_memorytype_new_internal(min_page, max_page))) { goto failed; } @@ -2122,8 +2106,16 @@ wasm_module_imports(const wasm_module_t *module, own wasm_importtype_vec_t *out) extern_type = wasm_tabletype_as_externtype(type); } - if (!extern_type) { - continue; + bh_assert(extern_type); + + wasm_name_new_from_string(&module_name, module_name_rt); + if (strlen(module_name_rt) && !module_name.data) { + goto failed; + } + + wasm_name_new_from_string(&name, field_name_rt); + if (strlen(field_name_rt) && !name.data) { + goto failed; } if (!(import_type = @@ -2134,17 +2126,16 @@ wasm_module_imports(const wasm_module_t *module, own wasm_importtype_vec_t *out) if (!bh_vector_append((Vector *)out, &import_type)) { goto failed_importtype_new; } + + continue; + + failed: + wasm_byte_vec_delete(&module_name); + wasm_byte_vec_delete(&name); + wasm_externtype_delete(extern_type); + failed_importtype_new: + wasm_importtype_delete(import_type); } - - return; - -failed: - wasm_byte_vec_delete(&module_name); - wasm_byte_vec_delete(&name); - wasm_externtype_delete(extern_type); -failed_importtype_new: - wasm_importtype_delete(import_type); - wasm_importtype_vec_delete(out); } void diff --git a/core/iwasm/compilation/aot_emit_function.c b/core/iwasm/compilation/aot_emit_function.c index c5f1379cd..0510172ff 100644 --- a/core/iwasm/compilation/aot_emit_function.c +++ b/core/iwasm/compilation/aot_emit_function.c @@ -518,6 +518,111 @@ check_stack_boundary(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, return true; } +/** + * Check whether the app address and its buffer are inside the linear memory, + * if no, throw exception + */ +static bool +check_app_addr_and_convert(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, + bool is_str_arg, LLVMValueRef app_addr, + LLVMValueRef buf_size, + LLVMValueRef *p_native_addr_converted) +{ + LLVMTypeRef func_type, func_ptr_type, func_param_types[5]; + LLVMValueRef func, func_param_values[5], res, native_addr_ptr; + char *func_name = "aot_check_app_addr_and_convert"; + + /* prepare function type of aot_check_app_addr_and_convert */ + func_param_types[0] = comp_ctx->aot_inst_type; /* module_inst */ + func_param_types[1] = INT8_TYPE; /* is_str_arg */ + func_param_types[2] = I32_TYPE; /* app_offset */ + func_param_types[3] = I32_TYPE; /* buf_size */ + func_param_types[4] = + comp_ctx->basic_types.int8_pptr_type; /* p_native_addr */ + if (!(func_type = + LLVMFunctionType(INT8_TYPE, func_param_types, 5, false))) { + aot_set_last_error("llvm add function type failed."); + return false; + } + + /* prepare function pointer */ + if (comp_ctx->is_jit_mode) { + if (!(func_ptr_type = LLVMPointerType(func_type, 0))) { + aot_set_last_error("create LLVM function type failed."); + return false; + } + + /* JIT mode, call the function directly */ + if (!(func = + I64_CONST((uint64)(uintptr_t)aot_check_app_addr_and_convert)) + || !(func = LLVMConstIntToPtr(func, func_ptr_type))) { + aot_set_last_error("create LLVM value failed."); + return false; + } + } + else if (comp_ctx->is_indirect_mode) { + int32 func_index; + if (!(func_ptr_type = LLVMPointerType(func_type, 0))) { + aot_set_last_error("create LLVM function type failed."); + return false; + } + func_index = aot_get_native_symbol_index(comp_ctx, func_name); + if (func_index < 0) { + return false; + } + if (!(func = aot_get_func_from_table(comp_ctx, func_ctx->native_symbol, + func_ptr_type, func_index))) { + return false; + } + } + else { + if (!(func = LLVMGetNamedFunction(func_ctx->module, func_name)) + && !(func = + LLVMAddFunction(func_ctx->module, func_name, func_type))) { + aot_set_last_error("add LLVM function failed."); + return false; + } + } + + if (!(native_addr_ptr = LLVMBuildBitCast( + comp_ctx->builder, func_ctx->argv_buf, + comp_ctx->basic_types.int8_pptr_type, "p_native_addr"))) { + aot_set_last_error("llvm build bit cast failed."); + return false; + } + + func_param_values[0] = func_ctx->aot_inst; + func_param_values[1] = I8_CONST(is_str_arg); + func_param_values[2] = app_addr; + func_param_values[3] = buf_size; + func_param_values[4] = native_addr_ptr; + + if (!func_param_values[1]) { + aot_set_last_error("llvm create const failed."); + return false; + } + + /* call aot_check_app_addr_and_convert() function */ + if (!(res = LLVMBuildCall(comp_ctx->builder, func, func_param_values, 5, + "res"))) { + aot_set_last_error("llvm build call failed."); + return false; + } + + /* Check whether exception was thrown when executing the function */ + if (!check_call_return(comp_ctx, func_ctx, res)) { + return false; + } + + if (!(*p_native_addr_converted = LLVMBuildLoad( + comp_ctx->builder, native_addr_ptr, "native_addr"))) { + aot_set_last_error("llvm build load failed."); + return false; + } + + return true; +} + bool aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, uint32 func_idx, bool tail_call) @@ -539,6 +644,7 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, uint32 callee_cell_num; uint8 wasm_ret_type; uint8 *ext_ret_types = NULL; + const char *signature = NULL; bool ret = false; char buf[32]; @@ -557,11 +663,14 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } /* Get function type */ - if (func_idx < import_func_count) + if (func_idx < import_func_count) { func_type = import_funcs[func_idx].func_type; - else + signature = import_funcs[func_idx].signature; + } + else { func_type = func_ctxes[func_idx - import_func_count]->aot_func->func_type; + } /* Get param cell number */ param_cell_num = func_type->param_cell_num; @@ -659,8 +768,41 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, j = 0; param_types[j++] = comp_ctx->exec_env_type; - for (i = 0; i < param_count; i++) - param_types[j++] = TO_LLVM_TYPE(func_type->types[i]); + for (i = 0; i < param_count; i++, j++) { + param_types[j] = TO_LLVM_TYPE(func_type->types[i]); + + /* If the signature can be gotten, e.g. the signature of the builtin + native libraries, just check the app offset and buf size, and + then convert app offset to native addr and call the native func + directly, no need to call aot_invoke_native to call it */ + if (signature) { + LLVMValueRef native_addr, native_addr_size; + if (signature[i + 1] == '*' || signature[i + 1] == '$') { + param_types[j] = INT8_PTR_TYPE; + } + if (signature[i + 1] == '*') { + if (signature[i + 2] == '~') + native_addr_size = param_values[i + 2]; + else + native_addr_size = I32_ONE; + if (!check_app_addr_and_convert( + comp_ctx, func_ctx, false, param_values[j], + native_addr_size, &native_addr)) { + goto fail; + } + param_values[j] = native_addr; + } + else if (signature[i + 1] == '$') { + native_addr_size = I32_ZERO; + if (!check_app_addr_and_convert( + comp_ctx, func_ctx, true, param_values[j], + native_addr_size, &native_addr)) { + goto fail; + } + param_values[j] = native_addr; + } + } + } if (func_type->result_count) { wasm_ret_type = func_type->types[func_type->param_count]; @@ -671,17 +813,68 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, ret_type = VOID_TYPE; } - /* call aot_invoke_native() */ - if (!call_aot_invoke_native_func( - comp_ctx, func_ctx, import_func_idx, func_type, param_types + 1, - param_values + 1, param_count, param_cell_num, ret_type, - wasm_ret_type, &value_ret, &res)) - goto fail; + if (!signature) { + /* call aot_invoke_native() */ + if (!call_aot_invoke_native_func( + comp_ctx, func_ctx, import_func_idx, func_type, + param_types + 1, param_values + 1, param_count, + param_cell_num, ret_type, wasm_ret_type, &value_ret, &res)) + goto fail; + /* Check whether there was exception thrown when executing + the function */ + if (!check_call_return(comp_ctx, func_ctx, res)) + goto fail; + } + else { /* call native func directly */ + LLVMTypeRef native_func_type, func_ptr_type; + LLVMValueRef func_ptr; - /* Check whether there was exception thrown when executing - the function */ - if (!check_call_return(comp_ctx, func_ctx, res)) - goto fail; + if (!(native_func_type = LLVMFunctionType( + ret_type, param_types, param_count + 1, false))) { + aot_set_last_error("llvm add function type failed."); + goto fail; + } + + if (!(func_ptr_type = LLVMPointerType(native_func_type, 0))) { + aot_set_last_error("create LLVM function type failed."); + goto fail; + } + + /* Load function pointer */ + if (!(func_ptr = LLVMBuildInBoundsGEP( + comp_ctx->builder, func_ctx->func_ptrs, &import_func_idx, + 1, "native_func_ptr_tmp"))) { + aot_set_last_error("llvm build inbounds gep failed."); + goto fail; + } + + if (!(func_ptr = LLVMBuildLoad(comp_ctx->builder, func_ptr, + "native_func_ptr"))) { + aot_set_last_error("llvm build load failed."); + goto fail; + } + + if (!(func = LLVMBuildBitCast(comp_ctx->builder, func_ptr, + func_ptr_type, "native_func"))) { + aot_set_last_error("llvm bit cast failed."); + goto fail; + } + + /* Call the function */ + if (!(value_ret = LLVMBuildCall( + comp_ctx->builder, func, param_values, + (uint32)param_count + 1 + ext_ret_count, + (func_type->result_count > 0 ? "call" : "")))) { + aot_set_last_error("LLVM build call failed."); + goto fail; + } + + /* Check whether there was exception thrown when executing + the function */ + if (!check_exception_thrown(comp_ctx, func_ctx)) { + goto fail; + } + } } else { bool recursive_call = diff --git a/product-mini/platforms/nuttx/wamr.mk b/product-mini/platforms/nuttx/wamr.mk index bec33be8e..d880e17bb 100644 --- a/product-mini/platforms/nuttx/wamr.mk +++ b/product-mini/platforms/nuttx/wamr.mk @@ -74,12 +74,12 @@ else ifeq (${WAMR_BUILD_TARGET}, XTENSA) AOT_RELOC := aot_reloc_xtensa.c else ifeq (${WAMR_BUILD_TARGET}, RISCV64) -ifeq (${CONFIG_ARCH_FPU},y) - $(error riscv64 lp64f is unsupported) -else ifeq (${CONFIG_ARCH_DPFPU}, y) +ifeq (${CONFIG_ARCH_DPFPU},y) CFLAGS += -DBUILD_TARGET_RISCV64_LP64D -else +else ifneq (${CONFIG_ARCH_FPU},y) CFLAGS += -DBUILD_TARGET_RISCV64_LP64 +else + $(error riscv64 lp64f is unsupported) endif INVOKE_NATIVE += invokeNative_riscv.S @@ -87,12 +87,12 @@ endif else ifeq (${WAMR_BUILD_TARGET}, RISCV32) -ifeq (${CONFIG_ARCH_FPU}, y) - $(error riscv32 ilp32f is unsupported) -else ifeq (${CONFIG_ARCH_DPFPU}, y) +ifeq (${CONFIG_ARCH_DPFPU},y) CFLAGS += -DBUILD_TARGET_RISCV32_ILP32D -else +else ifneq (${CONFIG_ARCH_FPU},y) CFLAGS += -DBUILD_TARGET_RISCV32_ILP32 +else + $(error riscv32 ilp32f is unsupported) endif INVOKE_NATIVE += invokeNative_riscv.S diff --git a/wamr-compiler/CMakeLists.txt b/wamr-compiler/CMakeLists.txt index e6f64d820..fa11192f9 100644 --- a/wamr-compiler/CMakeLists.txt +++ b/wamr-compiler/CMakeLists.txt @@ -181,6 +181,8 @@ include (${SHARED_DIR}/utils/shared_utils.cmake) include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake) include (${IWASM_DIR}/libraries/thread-mgr/thread_mgr.cmake) include (${IWASM_DIR}/libraries/libc-builtin/libc_builtin.cmake) +include (${IWASM_DIR}/libraries/libc-wasi/libc_wasi.cmake) +include (${IWASM_DIR}/libraries/lib-pthread/lib_pthread.cmake) include (${IWASM_DIR}/common/iwasm_common.cmake) include (${IWASM_DIR}/interpreter/iwasm_interp.cmake) include (${IWASM_DIR}/aot/iwasm_aot.cmake) @@ -239,6 +241,8 @@ add_library (vmlib ${UNCOMMON_SHARED_SOURCE} ${THREAD_MGR_SOURCE} ${LIBC_BUILTIN_SOURCE} + ${LIBC_WASI_SOURCE} + ${LIB_PTHREAD_SOURCE} ${IWASM_COMMON_SOURCE} ${IWASM_INTERP_SOURCE} ${IWASM_AOT_SOURCE})