diff --git a/.github/workflows/compilation_on_nuttx.yml b/.github/workflows/compilation_on_nuttx.yml index 2f4e3aca3..6125c1f56 100644 --- a/.github/workflows/compilation_on_nuttx.yml +++ b/.github/workflows/compilation_on_nuttx.yml @@ -94,9 +94,9 @@ jobs: - name: Install RISC-V Compilers if: contains(matrix.nuttx_board_config, 'risc-v') run: | - curl -L -k https://static.dev.sifive.com/dev-tools/freedom-tools/v2020.12/riscv64-unknown-elf-toolchain-10.2.0-2020.12.8-x86_64-linux-ubuntu14.tar.gz > riscv.tar.gz + curl -L https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/download/v12.3.0-1/xpack-riscv-none-elf-gcc-12.3.0-1-linux-x64.tar.gz > riscv.tar.gz tar xvf riscv.tar.gz - echo "$PWD/riscv64-unknown-elf-toolchain-10.2.0-2020.12.8-x86_64-linux-ubuntu14/bin" >> $GITHUB_PATH + echo "$PWD/xpack-riscv-none-elf-gcc-12.3.0-1/bin" >> $GITHUB_PATH - name: Install WASI-SDK run: | diff --git a/.github/workflows/compilation_on_windows.yml b/.github/workflows/compilation_on_windows.yml index 0d38e8ae5..97a4aaae2 100644 --- a/.github/workflows/compilation_on_windows.yml +++ b/.github/workflows/compilation_on_windows.yml @@ -39,6 +39,16 @@ on: # allow to be triggered manually workflow_dispatch: +env: + # For Spec Test + DEFAULT_TEST_OPTIONS: "-s spec -b" + MULTI_MODULES_TEST_OPTIONS: "-s spec -b -M" + THREADS_TEST_OPTIONS: "-s spec -b -p" + WASI_TEST_OPTIONS: "-s wasi_certification -w" + WASI_TEST_FILTER: ${{ github.workspace }}/product-mini/platforms/windows/wasi_filtered_tests.json + # Used when building the WASI socket and thread tests + CC: ${{ github.workspace }}/wasi-sdk/bin/clang + # Cancel any in-flight jobs for the same PR/branch so there's only one active # at a time concurrency: @@ -60,12 +70,14 @@ jobs: "-DWAMR_BUILD_SIMD=1", "-DWAMR_BUILD_DEBUG_INTERP=1", "-DWAMR_BUILD_LIB_PTHREAD=1", - "-DWAMR_BUILD_LIB_WASI_THREADS=1" + "-DWAMR_BUILD_LIB_WASI_THREADS=1", + "-DWAMR_BUILD_LIBC_UVWASI=0 -DWAMR_BUILD_LIBC_WASI=1" ] steps: - uses: actions/checkout@v3 - name: clone uvwasi library + if: ${{ !contains(matrix.build_options, '-DWAMR_BUILD_LIBC_UVWASI=0') }} run: | cd core/deps git clone https://github.com/nodejs/uvwasi.git @@ -75,3 +87,50 @@ jobs: mkdir build && cd build cmake .. ${{ matrix.build_options }} cmake --build . --config Release --parallel 4 + + test: + runs-on: windows-latest + needs: [build] + strategy: + fail-fast: false + matrix: + running_mode: + [ + "classic-interp", + "fast-interp", + ] + test_option: + [ + $DEFAULT_TEST_OPTIONS, + $MULTI_MODULES_TEST_OPTIONS, + $THREADS_TEST_OPTIONS, + $WASI_TEST_OPTIONS, + ] + steps: + - name: checkout + uses: actions/checkout@v3 + + - name: download and install wasi-sdk + if: matrix.test_option == '$WASI_TEST_OPTIONS' + run: | + curl "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-20/wasi-sdk-20.0.m-mingw.tar.gz" -o wasi-sdk.tar.gz -L + mkdir wasi-sdk + tar -xzf wasi-sdk.tar.gz -C wasi-sdk --strip-components 1 + + - name: build socket api tests + shell: bash + if: matrix.test_option == '$WASI_TEST_OPTIONS' + run: ./build.sh + working-directory: ./core/iwasm/libraries/lib-socket/test/ + + - name: Build WASI thread tests + shell: bash + if: matrix.test_option == '$WASI_TEST_OPTIONS' + run: ./build.sh + working-directory: ./core/iwasm/libraries/lib-wasi-threads/test/ + + - name: run tests + shell: bash + timeout-minutes: 20 + run: ./test_wamr.sh ${{ matrix.test_option }} -t ${{ matrix.running_mode }} + working-directory: ./tests/wamr-test-suites diff --git a/.github/workflows/nightly_run.yml b/.github/workflows/nightly_run.yml index bef639792..7b85f2cda 100644 --- a/.github/workflows/nightly_run.yml +++ b/.github/workflows/nightly_run.yml @@ -49,10 +49,17 @@ jobs: with: os: "ubuntu-20.04" arch: "X86" + build_llvm_libraries_on_ubuntu_2204: + uses: ./.github/workflows/build_llvm_libraries.yml + with: + os: "ubuntu-22.04" + arch: "X86" build_wamrc: needs: - [build_llvm_libraries_on_ubuntu_2004] + [ + build_llvm_libraries_on_ubuntu_2004, + ] runs-on: ${{ matrix.os }} strategy: matrix: @@ -90,7 +97,9 @@ jobs: build_iwasm: needs: - [build_llvm_libraries_on_ubuntu_2004] + [ + build_llvm_libraries_on_ubuntu_2004, + ] runs-on: ${{ matrix.os }} strategy: matrix: @@ -497,14 +506,15 @@ jobs: [ build_iwasm, build_llvm_libraries_on_ubuntu_2004, + build_llvm_libraries_on_ubuntu_2204, build_wamrc, ] runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: - os: [ubuntu-20.04] - sanitizer: ["", "ubsan", "asan"] + os: [ubuntu-20.04, ubuntu-22.04] + sanitizer: ["", "ubsan", "asan", "tsan"] running_mode: [ "classic-interp", @@ -530,11 +540,14 @@ jobs: - os: ubuntu-20.04 llvm_cache_key: ${{ needs.build_llvm_libraries_on_ubuntu_2004.outputs.cache_key }} ubuntu_version: "20.04" + - os: ubuntu-22.04 + llvm_cache_key: ${{ needs.build_llvm_libraries_on_ubuntu_2204.outputs.cache_key }} + ubuntu_version: "22.04" exclude: # uncompatiable modes and features - os: ubuntu-20.04 - sanitizer: asan + sanitizer: tsan # asan works only for aot now - running_mode: "classic-interp" sanitizer: asan @@ -546,6 +559,14 @@ jobs: sanitizer: asan - running_mode: "multi-tier-jit" sanitizer: asan + - running_mode: "classic-interp" + sanitizer: tsan + - running_mode: "jit" + sanitizer: tsan + - running_mode: "fast-jit" + sanitizer: tsan + - running_mode: "multi-tier-jit" + sanitizer: tsan # classic-interp and fast-interp don't support simd - running_mode: "classic-interp" test_option: $SIMD_TEST_OPTIONS @@ -595,9 +616,10 @@ jobs: || matrix.test_option == '$WASI_TEST_OPTIONS') && matrix.running_mode != 'fast-jit' && matrix.running_mode != 'jit' && matrix.running_mode != 'multi-tier-jit' run: echo "TEST_ON_X86_32=true" >> $GITHUB_ENV - - - name: set sanitizer - run: echo "WAMR_BUILD_SANITIZER=${{ matrix.sanitizer }}" >> $GITHUB_ENV + + - name: set additional tsan options + run: echo "TSAN_OPTIONS=suppressions=$PWD/tsan_suppressions.txt" >> $GITHUB_ENV + working-directory: tests/wamr-test-suites #only download llvm libraries in jit and aot mode - name: Get LLVM libraries @@ -638,7 +660,7 @@ jobs: - name: run tests timeout-minutes: 40 - run: ./test_wamr.sh ${{ matrix.test_option }} -t ${{ matrix.running_mode }} + run: ./test_wamr.sh ${{ matrix.test_option }} -t ${{ matrix.running_mode }} -T %{{matrix.sanitizer}} working-directory: ./tests/wamr-test-suites #only install x32 support libraries when to run x86_32 cases diff --git a/.github/workflows/spec_test_on_nuttx.yml b/.github/workflows/spec_test_on_nuttx.yml index 4ffa943a9..32efc35da 100644 --- a/.github/workflows/spec_test_on_nuttx.yml +++ b/.github/workflows/spec_test_on_nuttx.yml @@ -52,9 +52,9 @@ jobs: - name: Install RISC-V Compilers if: contains(matrix.nuttx_board_config, 'risc-v') run: | - curl -L -k https://static.dev.sifive.com/dev-tools/freedom-tools/v2020.12/riscv64-unknown-elf-toolchain-10.2.0-2020.12.8-x86_64-linux-ubuntu14.tar.gz > riscv.tar.gz + curl -L https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/download/v12.3.0-1/xpack-riscv-none-elf-gcc-12.3.0-1-linux-x64.tar.gz > riscv.tar.gz tar xvf riscv.tar.gz - echo "$PWD/riscv64-unknown-elf-toolchain-10.2.0-2020.12.8-x86_64-linux-ubuntu14/bin" >> $GITHUB_PATH + echo "$PWD/xpack-riscv-none-elf-gcc-12.3.0-1/bin" >> $GITHUB_PATH - name: Install WASI-SDK run: | diff --git a/build-scripts/runtime_lib.cmake b/build-scripts/runtime_lib.cmake index 8ac519b77..811009df6 100644 --- a/build-scripts/runtime_lib.cmake +++ b/build-scripts/runtime_lib.cmake @@ -165,7 +165,11 @@ file (GLOB header ) LIST (APPEND RUNTIME_LIB_HEADER_LIST ${header}) -enable_language (ASM) +if (WAMR_BUILD_PLATFORM STREQUAL "windows") + enable_language (ASM_MASM) +else() + enable_language (ASM) +endif() include (${SHARED_PLATFORM_CONFIG}) include (${SHARED_DIR}/mem-alloc/mem_alloc.cmake) diff --git a/core/app-mgr/app-manager/module_wasm_app.c b/core/app-mgr/app-manager/module_wasm_app.c index 2005ad8e8..6fd929b10 100644 --- a/core/app-mgr/app-manager/module_wasm_app.c +++ b/core/app-mgr/app-manager/module_wasm_app.c @@ -1467,7 +1467,7 @@ wasm_app_module_on_install_request_byte_arrive(uint8 ch, int request_total_size, if (total_size >= UINT32_MAX || !(section->section_body = os_mmap(NULL, (uint32)total_size, map_prot, - map_flags))) { + map_flags, os_get_invalid_handle()))) { app_manager_printf( "Allocate executable memory failed!\n"); SEND_ERR_RESPONSE(recv_ctx.message.request_mid, diff --git a/core/config.h b/core/config.h index c63de091f..7ef406a76 100644 --- a/core/config.h +++ b/core/config.h @@ -315,6 +315,11 @@ #define BH_ENABLE_GC_VERIFY 0 #endif +/* Heap corruption check, enabled by default */ +#ifndef BH_ENABLE_GC_CORRUPTION_CHECK +#define BH_ENABLE_GC_CORRUPTION_CHECK 1 +#endif + /* Enable global heap pool if heap verification is enabled */ #if BH_ENABLE_GC_VERIFY != 0 #define WASM_ENABLE_GLOBAL_HEAP_POOL 1 diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index 6575c8aca..37084ba8e 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -1574,8 +1574,9 @@ load_object_data_sections(const uint8 **p_buf, const uint8 *buf_end, /* Allocate memory for data */ if (data_sections[i].size > 0 - && !(data_sections[i].data = os_mmap(NULL, data_sections[i].size, - map_prot, map_flags))) { + && !(data_sections[i].data = + os_mmap(NULL, data_sections[i].size, map_prot, map_flags, + os_get_invalid_handle()))) { set_error_buf(error_buf, error_buf_size, "allocate memory failed"); return false; } @@ -2470,7 +2471,8 @@ load_relocation_section(const uint8 *buf, const uint8 *buf_end, if (size > UINT32_MAX || !(module->extra_plt_data = - os_mmap(NULL, (uint32)size, map_prot, map_flags))) { + os_mmap(NULL, (uint32)size, map_prot, map_flags, + os_get_invalid_handle()))) { set_error_buf(error_buf, error_buf_size, "mmap memory failed"); goto fail; } @@ -2593,7 +2595,8 @@ load_relocation_section(const uint8 *buf, const uint8 *buf_end, size = (uint64)sizeof(void *) * got_item_count; if (size > UINT32_MAX || !(module->got_func_ptrs = - os_mmap(NULL, (uint32)size, map_prot, map_flags))) { + os_mmap(NULL, (uint32)size, map_prot, map_flags, + os_get_invalid_handle()))) { set_error_buf(error_buf, error_buf_size, "mmap memory failed"); goto fail; } @@ -3106,8 +3109,9 @@ create_sections(AOTModule *module, const uint8 *buf, uint32 size, (uint64)section_size + aot_get_plt_table_size(); total_size = (total_size + 3) & ~((uint64)3); if (total_size >= UINT32_MAX - || !(aot_text = os_mmap(NULL, (uint32)total_size, - map_prot, map_flags))) { + || !(aot_text = + os_mmap(NULL, (uint32)total_size, map_prot, + map_flags, os_get_invalid_handle()))) { wasm_runtime_free(section); set_error_buf(error_buf, error_buf_size, "mmap memory failed"); diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 954da4153..f747cb43f 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -489,6 +489,12 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModuleInstance *parent, if (max_page_count > DEFAULT_MAX_PAGES) max_page_count = DEFAULT_MAX_PAGES; } + else { /* heap_size == 0 */ + if (init_page_count == DEFAULT_MAX_PAGES) { + num_bytes_per_page = UINT32_MAX; + init_page_count = max_page_count = 1; + } + } LOG_VERBOSE("Memory instantiate:"); LOG_VERBOSE(" page bytes: %u, init pages: %u, max pages: %u", @@ -531,8 +537,8 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModuleInstance *parent, * both i and memarg.offset are u32 in range 0 to 4G * so the range of ea is 0 to 8G */ - if (!(p = mapped_mem = - os_mmap(NULL, map_size, MMAP_PROT_NONE, MMAP_MAP_NONE))) { + if (!(p = mapped_mem = os_mmap(NULL, map_size, MMAP_PROT_NONE, + MMAP_MAP_NONE, os_get_invalid_handle()))) { set_error_buf(error_buf, error_buf_size, "mmap memory failed"); return NULL; } @@ -554,8 +560,12 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModuleInstance *parent, os_munmap(mapped_mem, map_size); return NULL; } + /* Newly allocated pages are filled with zero by the OS, we don't fill it * again here */ + + if (memory_data_size > UINT32_MAX) + memory_data_size = UINT32_MAX; #endif /* end of OS_ENABLE_HW_BOUND_CHECK */ memory_inst->module_type = Wasm_Module_AoT; @@ -972,7 +982,8 @@ execute_post_instantiate_functions(AOTModuleInstance *module_inst, wasm functions, and ensure that the exec_env's module inst is the correct one. */ module_inst_main = exec_env_main->module_inst; - exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst; + wasm_exec_env_set_module_inst(exec_env, + (WASMModuleInstanceCommon *)module_inst); } else { /* Try using the existing exec_env */ @@ -997,7 +1008,8 @@ execute_post_instantiate_functions(AOTModuleInstance *module_inst, module inst to ensure that the exec_env's module inst is the correct one. */ module_inst_main = exec_env->module_inst; - exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst; + wasm_exec_env_set_module_inst( + exec_env, (WASMModuleInstanceCommon *)module_inst); } } @@ -1047,12 +1059,12 @@ execute_post_instantiate_functions(AOTModuleInstance *module_inst, fail: if (is_sub_inst) { /* Restore the parent exec_env's module inst */ - exec_env_main->module_inst = module_inst_main; + wasm_exec_env_restore_module_inst(exec_env_main, module_inst_main); } else { if (module_inst_main) /* Restore the existing exec_env's module inst */ - exec_env->module_inst = module_inst_main; + wasm_exec_env_restore_module_inst(exec_env, module_inst_main); if (exec_env_created) wasm_exec_env_destroy(exec_env_created); } @@ -1703,7 +1715,8 @@ execute_malloc_function(AOTModuleInstance *module_inst, WASMExecEnv *exec_env, module inst to ensure that the exec_env's module inst is the correct one. */ module_inst_old = exec_env->module_inst; - exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst; + wasm_exec_env_set_module_inst( + exec_env, (WASMModuleInstanceCommon *)module_inst); } } @@ -1714,7 +1727,7 @@ execute_malloc_function(AOTModuleInstance *module_inst, WASMExecEnv *exec_env, if (module_inst_old) /* Restore the existing exec_env's module inst */ - exec_env->module_inst = module_inst_old; + wasm_exec_env_restore_module_inst(exec_env, module_inst_old); if (exec_env_created) wasm_exec_env_destroy(exec_env_created); @@ -1770,7 +1783,8 @@ execute_free_function(AOTModuleInstance *module_inst, WASMExecEnv *exec_env, module inst to ensure that the exec_env's module inst is the correct one. */ module_inst_old = exec_env->module_inst; - exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst; + wasm_exec_env_set_module_inst( + exec_env, (WASMModuleInstanceCommon *)module_inst); } } @@ -1778,7 +1792,7 @@ execute_free_function(AOTModuleInstance *module_inst, WASMExecEnv *exec_env, if (module_inst_old) /* Restore the existing exec_env's module inst */ - exec_env->module_inst = module_inst_old; + wasm_exec_env_restore_module_inst(exec_env, module_inst_old); if (exec_env_created) wasm_exec_env_destroy(exec_env_created); diff --git a/core/iwasm/common/wasm_application.c b/core/iwasm/common/wasm_application.c index d29d379b3..bcd0a6d0b 100644 --- a/core/iwasm/common/wasm_application.c +++ b/core/iwasm/common/wasm_application.c @@ -388,6 +388,18 @@ execute_func(WASMModuleInstanceCommon *module_inst, const char *name, { float32 f32 = strtof(argv[i], &endptr); if (isnan(f32)) { +#ifdef _MSC_VER + /* + * Spec tests require the binary representation of NaN to be + * 0x7fc00000 for float and 0x7ff8000000000000 for float; + * however, in MSVC compiler, strtof doesn't return this + * exact value, causing some of the spec test failures. We + * use the value returned by nan/nanf as it is the one + * expected by spec tests. + * + */ + f32 = nanf(""); +#endif if (argv[i][0] == '-') { union ieee754_float u; u.f = f32; @@ -422,6 +434,9 @@ execute_func(WASMModuleInstanceCommon *module_inst, const char *name, } u; u.val = strtod(argv[i], &endptr); if (isnan(u.val)) { +#ifdef _MSC_VER + u.val = nan(""); +#endif if (argv[i][0] == '-') { union ieee754_double ud; ud.d = u.val; @@ -585,7 +600,7 @@ execute_func(WASMModuleInstanceCommon *module_inst, const char *name, { #if UINTPTR_MAX == UINT32_MAX if (argv1[k] != 0 && argv1[k] != (uint32)-1) - os_printf("%p:ref.extern", (void *)argv1[k]); + os_printf("0x%" PRIxPTR ":ref.extern", (void *)argv1[k]); else os_printf("extern:ref.null"); k++; @@ -598,7 +613,7 @@ execute_func(WASMModuleInstanceCommon *module_inst, const char *name, u.parts[1] = argv1[k + 1]; k += 2; if (u.val && u.val != (uintptr_t)-1LL) - os_printf("%p:ref.extern", (void *)u.val); + os_printf("0x%" PRIxPTR ":ref.extern", (void *)u.val); else os_printf("extern:ref.null"); #endif diff --git a/core/iwasm/common/wasm_exec_env.c b/core/iwasm/common/wasm_exec_env.c index 622bcd71e..d524c7de0 100644 --- a/core/iwasm/common/wasm_exec_env.c +++ b/core/iwasm/common/wasm_exec_env.c @@ -58,7 +58,8 @@ wasm_exec_env_create_internal(struct WASMModuleInstanceCommon *module_inst, #ifdef OS_ENABLE_HW_BOUND_CHECK if (!(exec_env->exce_check_guard_page = - os_mmap(NULL, os_getpagesize(), MMAP_PROT_NONE, MMAP_MAP_NONE))) + os_mmap(NULL, os_getpagesize(), MMAP_PROT_NONE, MMAP_MAP_NONE, + os_get_invalid_handle()))) goto fail5; #endif @@ -201,7 +202,52 @@ void wasm_exec_env_set_module_inst(WASMExecEnv *exec_env, WASMModuleInstanceCommon *const module_inst) { +#if WASM_ENABLE_THREAD_MGR != 0 + wasm_cluster_traverse_lock(exec_env); +#endif exec_env->module_inst = module_inst; +#if WASM_ENABLE_THREAD_MGR != 0 + wasm_cluster_traverse_unlock(exec_env); +#endif +} + +void +wasm_exec_env_restore_module_inst( + WASMExecEnv *exec_env, WASMModuleInstanceCommon *const module_inst_common) +{ + WASMModuleInstanceCommon *old_module_inst_common = exec_env->module_inst; + WASMModuleInstance *old_module_inst = + (WASMModuleInstance *)old_module_inst_common; + WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_common; + char cur_exception[EXCEPTION_BUF_LEN]; + +#if WASM_ENABLE_THREAD_MGR != 0 + wasm_cluster_traverse_lock(exec_env); +#endif + exec_env->module_inst = module_inst_common; + /* + * propagate an exception if any. + */ + exception_lock(old_module_inst); + if (old_module_inst->cur_exception[0] != '\0') { + bh_memcpy_s(cur_exception, sizeof(cur_exception), + old_module_inst->cur_exception, + sizeof(old_module_inst->cur_exception)); + } + else { + cur_exception[0] = '\0'; + } + exception_unlock(old_module_inst); +#if WASM_ENABLE_THREAD_MGR != 0 + wasm_cluster_traverse_unlock(exec_env); +#endif + if (cur_exception[0] != '\0') { + exception_lock(module_inst); + bh_memcpy_s(module_inst->cur_exception, + sizeof(module_inst->cur_exception), cur_exception, + sizeof(cur_exception)); + exception_unlock(module_inst); + } } void diff --git a/core/iwasm/common/wasm_exec_env.h b/core/iwasm/common/wasm_exec_env.h index bf9892080..132642ea8 100644 --- a/core/iwasm/common/wasm_exec_env.h +++ b/core/iwasm/common/wasm_exec_env.h @@ -291,6 +291,10 @@ void wasm_exec_env_set_module_inst( WASMExecEnv *exec_env, struct WASMModuleInstanceCommon *const module_inst); +void +wasm_exec_env_restore_module_inst( + WASMExecEnv *exec_env, struct WASMModuleInstanceCommon *const module_inst); + void wasm_exec_env_set_thread_info(WASMExecEnv *exec_env); diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 36d9c33a6..a8b3da6dd 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -2778,7 +2778,7 @@ wasm_runtime_set_wasi_args_ex(WASMModuleCommon *module, const char *dir_list[], uint32 dir_count, const char *map_dir_list[], uint32 map_dir_count, const char *env_list[], uint32 env_count, char *argv[], int argc, - int stdinfd, int stdoutfd, int stderrfd) + int64 stdinfd, int64 stdoutfd, int64 stderrfd) { WASIArguments *wasi_args = get_wasi_args_from_module(module); @@ -2792,9 +2792,9 @@ wasm_runtime_set_wasi_args_ex(WASMModuleCommon *module, const char *dir_list[], wasi_args->env_count = env_count; wasi_args->argv = argv; wasi_args->argc = (uint32)argc; - wasi_args->stdio[0] = stdinfd; - wasi_args->stdio[1] = stdoutfd; - wasi_args->stdio[2] = stderrfd; + wasi_args->stdio[0] = (os_raw_file_handle)stdinfd; + wasi_args->stdio[1] = (os_raw_file_handle)stdoutfd; + wasi_args->stdio[2] = (os_raw_file_handle)stderrfd; #if WASM_ENABLE_MULTI_MODULE != 0 #if WASM_ENABLE_INTERP != 0 @@ -2889,8 +2889,9 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, const char *env[], uint32 env_count, const char *addr_pool[], uint32 addr_pool_size, const char *ns_lookup_pool[], uint32 ns_lookup_pool_size, - char *argv[], uint32 argc, int stdinfd, int stdoutfd, - int stderrfd, char *error_buf, uint32 error_buf_size) + char *argv[], uint32 argc, os_raw_file_handle stdinfd, + os_raw_file_handle stdoutfd, os_raw_file_handle stderrfd, + char *error_buf, uint32 error_buf_size) { WASIContext *wasi_ctx; char *argv_buf = NULL; @@ -2908,7 +2909,7 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, bool argv_environ_inited = false; bool addr_pool_inited = false; __wasi_fd_t wasm_fd = 3; - int32 raw_fd; + os_file_handle file_handle; char *path, resolved_path[PATH_MAX]; uint32 i; @@ -2978,15 +2979,19 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, } addr_pool_inited = true; - /* Prepopulate curfds with stdin, stdout, and stderr file descriptors. - * - * If -1 is given, use STDIN_FILENO (0), STDOUT_FILENO (1), - * STDERR_FILENO (2) respectively. - */ - if (!fd_table_insert_existing(curfds, 0, (stdinfd != -1) ? stdinfd : 0) - || !fd_table_insert_existing(curfds, 1, (stdoutfd != -1) ? stdoutfd : 1) - || !fd_table_insert_existing(curfds, 2, - (stderrfd != -1) ? stderrfd : 2)) { + os_file_handle stdin_file_handle = os_convert_stdin_handle(stdinfd); + os_file_handle stdout_file_handle = os_convert_stdout_handle(stdoutfd); + os_file_handle stderr_file_handle = os_convert_stderr_handle(stderrfd); + + if (!os_is_handle_valid(&stdin_file_handle) + || !os_is_handle_valid(&stdout_file_handle) + || !os_is_handle_valid(&stderr_file_handle)) + goto fail; + + /* Prepopulate curfds with stdin, stdout, and stderr file descriptors. */ + if (!fd_table_insert_existing(curfds, 0, stdin_file_handle, true) + || !fd_table_insert_existing(curfds, 1, stdout_file_handle, true) + || !fd_table_insert_existing(curfds, 2, stderr_file_handle, true)) { set_error_buf(error_buf, error_buf_size, "Init wasi environment failed: init fd table failed"); goto fail; @@ -2994,7 +2999,7 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, wasm_fd = 3; for (i = 0; i < dir_count; i++, wasm_fd++) { - path = realpath(dir_list[i], resolved_path); + path = os_realpath(dir_list[i], resolved_path); if (!path) { if (error_buf) snprintf(error_buf, error_buf_size, @@ -3003,22 +3008,31 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, goto fail; } - raw_fd = open(path, O_RDONLY | O_DIRECTORY, 0); - if (raw_fd == -1) { + __wasi_errno_t error = os_open_preopendir(path, &file_handle); + + if (error != __WASI_ESUCCESS) { if (error_buf) snprintf(error_buf, error_buf_size, "error while pre-opening directory %s: %d\n", - dir_list[i], errno); + dir_list[i], error); goto fail; } - if (!fd_table_insert_existing(curfds, wasm_fd, raw_fd) - || !fd_prestats_insert(prestats, dir_list[i], wasm_fd)) { + if (!fd_table_insert_existing(curfds, wasm_fd, file_handle, false)) { if (error_buf) - snprintf( - error_buf, error_buf_size, - "error while pre-opening directory %s: insertion failed\n", - dir_list[i]); + snprintf(error_buf, error_buf_size, + "error inserting preopen fd %u (directory %s) into fd " + "table", + (unsigned int)wasm_fd, dir_list[i]); + goto fail; + } + + if (!fd_prestats_insert(prestats, dir_list[i], wasm_fd)) { + if (error_buf) + snprintf(error_buf, error_buf_size, + "error inserting preopen fd %u (directory %s) into " + "prestats table", + (unsigned int)wasm_fd, dir_list[i]); goto fail; } } @@ -3053,7 +3067,7 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, goto fail; } - path = realpath(map_host, resolved_path); + path = os_realpath(map_host, resolved_path); if (!path) { if (error_buf) snprintf(error_buf, error_buf_size, @@ -3064,8 +3078,8 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, goto fail; } - raw_fd = open(path, O_RDONLY | O_DIRECTORY, 0); - if (raw_fd == -1) { + __wasi_errno_t error = os_open_preopendir(path, &file_handle); + if (error != __WASI_ESUCCESS) { if (error_buf) snprintf(error_buf, error_buf_size, "error while pre-opening mapped directory %s: %d\n", @@ -3075,7 +3089,7 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, goto fail; } - if (!fd_table_insert_existing(curfds, wasm_fd, raw_fd) + if (!fd_table_insert_existing(curfds, wasm_fd, file_handle, false) || !fd_prestats_insert(prestats, map_mapped, wasm_fd)) { if (error_buf) snprintf(error_buf, error_buf_size, @@ -3216,8 +3230,9 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, const char *env[], uint32 env_count, const char *addr_pool[], uint32 addr_pool_size, const char *ns_lookup_pool[], uint32 ns_lookup_pool_size, - char *argv[], uint32 argc, int stdinfd, int stdoutfd, - int stderrfd, char *error_buf, uint32 error_buf_size) + char *argv[], uint32 argc, os_raw_file_handle stdinfd, + os_raw_file_handle stdoutfd, os_raw_file_handle stderrfd, + char *error_buf, uint32 error_buf_size) { WASIContext *ctx; uvwasi_t *uvwasi; diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index 4e14ed4a1..367ea88f9 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -12,9 +12,9 @@ #include "wasm_native.h" #include "../include/wasm_export.h" #include "../interpreter/wasm.h" + #if WASM_ENABLE_LIBC_WASI != 0 #if WASM_ENABLE_UVWASI == 0 -#include "wasmtime_ssp.h" #include "posix.h" #else #include "uvwasi.h" @@ -44,15 +44,16 @@ extern "C" { /* For STORE opcodes */ #define STORE_I64 PUT_I64_TO_ADDR -#define STORE_U32(addr, value) \ - do { \ - *(uint32 *)(addr) = (uint32)(value); \ - } while (0) -#define STORE_U16(addr, value) \ - do { \ - *(uint16 *)(addr) = (uint16)(value); \ - } while (0) - +static inline void +STORE_U32(void *addr, uint32_t value) +{ + *(uint32_t *)(addr) = (uint32_t)(value); +} +static inline void +STORE_U16(void *addr, uint16_t value) +{ + *(uint16_t *)(addr) = (uint16_t)(value); +} /* For LOAD opcodes */ #define LOAD_I64(addr) (*(int64 *)(addr)) #define LOAD_F64(addr) (*(float64 *)(addr)) @@ -147,42 +148,42 @@ GET_F64_FROM_ADDR(uint32 *addr) } \ } while (0) -#define STORE_U32(addr, value) \ - do { \ - uintptr_t addr_ = (uintptr_t)(addr); \ - union { \ - uint32 val; \ - uint16 u16[2]; \ - uint8 u8[4]; \ - } u; \ - if ((addr_ & (uintptr_t)3) == 0) \ - *(uint32 *)(addr) = (uint32)(value); \ - else { \ - u.val = (uint32)(value); \ - if ((addr_ & (uintptr_t)1) == 0) { \ - ((uint16 *)(addr))[0] = u.u16[0]; \ - ((uint16 *)(addr))[1] = u.u16[1]; \ - } \ - else { \ - ((uint8 *)(addr))[0] = u.u8[0]; \ - ((uint8 *)(addr))[1] = u.u8[1]; \ - ((uint8 *)(addr))[2] = u.u8[2]; \ - ((uint8 *)(addr))[3] = u.u8[3]; \ - } \ - } \ - } while (0) - -#define STORE_U16(addr, value) \ - do { \ - union { \ - uint16 val; \ - uint8 u8[2]; \ - } u; \ - u.val = (uint16)(value); \ - ((uint8 *)(addr))[0] = u.u8[0]; \ - ((uint8 *)(addr))[1] = u.u8[1]; \ - } while (0) - +static inline void +STORE_U32(void *addr, uint32_t value) +{ + uintptr_t addr_ = (uintptr_t)(addr); + union { + uint32_t val; + uint16_t u16[2]; + uint8_t u8[4]; + } u; + if ((addr_ & (uintptr_t)3) == 0) + *(uint32_t *)(addr) = (uint32_t)(value); + else { + u.val = (uint32_t)(value); + if ((addr_ & (uintptr_t)1) == 0) { + ((uint16_t *)(addr))[0] = u.u16[0]; + ((uint16_t *)(addr))[1] = u.u16[1]; + } + else { + ((uint8_t *)(addr))[0] = u.u8[0]; + ((uint8_t *)(addr))[1] = u.u8[1]; + ((uint8_t *)(addr))[2] = u.u8[2]; + ((uint8_t *)(addr))[3] = u.u8[3]; + } + } +} +static inline void +STORE_U16(void *addr, uint16_t value) +{ + union { + uint16_t val; + uint8_t u8[2]; + } u; + u.val = (uint16_t)(value); + ((uint8_t *)(addr))[0] = u.u8[0]; + ((uint8_t *)(addr))[1] = u.u8[1]; +} /* For LOAD opcodes */ static inline int64 LOAD_I64(void *addr) @@ -861,7 +862,7 @@ wasm_runtime_set_wasi_args_ex(WASMModuleCommon *module, const char *dir_list[], uint32 dir_count, const char *map_dir_list[], uint32 map_dir_count, const char *env_list[], uint32 env_count, char *argv[], int argc, - int stdinfd, int stdoutfd, int stderrfd); + int64 stdinfd, int64 stdoutfd, int64 stderrfd); /* See wasm_export.h for description */ WASM_RUNTIME_API_EXTERN void @@ -889,8 +890,9 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, const char *env[], uint32 env_count, const char *addr_pool[], uint32 addr_pool_size, const char *ns_lookup_pool[], uint32 ns_lookup_pool_size, - char *argv[], uint32 argc, int stdinfd, int stdoutfd, - int stderrfd, char *error_buf, uint32 error_buf_size); + char *argv[], uint32 argc, os_raw_file_handle stdinfd, + os_raw_file_handle stdoutfd, os_raw_file_handle stderrfd, + char *error_buf, uint32 error_buf_size); void wasm_runtime_destroy_wasi(WASMModuleInstanceCommon *module_inst); diff --git a/core/iwasm/compilation/aot_emit_control.c b/core/iwasm/compilation/aot_emit_control.c index 446ca5ea6..895bf7e35 100644 --- a/core/iwasm/compilation/aot_emit_control.c +++ b/core/iwasm/compilation/aot_emit_control.c @@ -344,7 +344,9 @@ push_aot_block_to_stack_and_pass_params(AOTCompContext *comp_ctx, for (i = 0; i < block->param_count; i++) { param_index = block->param_count - 1 - i; POP(value, block->param_types[param_index]); - ADD_TO_PARAM_PHIS(block, value, param_index); + if (block->llvm_entry_block) + /* Only add incoming phis if the entry block was created */ + ADD_TO_PARAM_PHIS(block, value, param_index); if (block->label_type == LABEL_TYPE_IF && !block->skip_wasm_code_else) { if (block->llvm_else_block) { @@ -366,7 +368,17 @@ push_aot_block_to_stack_and_pass_params(AOTCompContext *comp_ctx, /* Push param phis to the new block */ for (i = 0; i < block->param_count; i++) { - PUSH(block->param_phis[i], block->param_types[i]); + if (block->llvm_entry_block) + /* Push param phis if the entry basic block was created */ + PUSH(block->param_phis[i], block->param_types[i]); + else { + bh_assert(block->label_type == LABEL_TYPE_IF + && block->llvm_else_block && block->else_param_phis + && !block->skip_wasm_code_else); + /* Push else param phis if we start to translate the + else branch */ + PUSH(block->else_param_phis[i], block->param_types[i]); + } } return true; diff --git a/core/iwasm/compilation/aot_emit_memory.c b/core/iwasm/compilation/aot_emit_memory.c index 7484d4b5b..8c35c3fe6 100644 --- a/core/iwasm/compilation/aot_emit_memory.c +++ b/core/iwasm/compilation/aot_emit_memory.c @@ -157,7 +157,10 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, if (mem_offset + bytes <= mem_data_size) { /* inside memory space */ - offset1 = I32_CONST((uint32)mem_offset); + if (comp_ctx->pointer_size == sizeof(uint64)) + offset1 = I64_CONST((uint32)mem_offset); + else + offset1 = I32_CONST((uint32)mem_offset); CHECK_LLVM_CONST(offset1); if (!enable_segue) { if (!(maddr = LLVMBuildInBoundsGEP2(comp_ctx->builder, diff --git a/core/iwasm/compilation/aot_emit_numberic.c b/core/iwasm/compilation/aot_emit_numberic.c index 04cfaada3..8b6ec02d6 100644 --- a/core/iwasm/compilation/aot_emit_numberic.c +++ b/core/iwasm/compilation/aot_emit_numberic.c @@ -777,17 +777,25 @@ compile_int_rot(AOTCompContext *comp_ctx, LLVMValueRef left, LLVMValueRef right, if (IS_CONST_ZERO(right)) return left; - /* Calculate (bits - shif_count) */ + /* Calculate (bits - shift_count) */ LLVM_BUILD_OP(Sub, is_i32 ? I32_32 : I64_64, right, bits_minus_shift_count, "bits_minus_shift_count", NULL); + /* Calculate (bits - shift_count) & mask */ + bits_minus_shift_count = + LLVMBuildAnd(comp_ctx->builder, bits_minus_shift_count, + is_i32 ? I32_31 : I64_63, "bits_minus_shift_count_and"); + if (!bits_minus_shift_count) { + aot_set_last_error("llvm build and failed."); + return NULL; + } if (is_rotl) { - /* left<>(BITS-count) */ + /* (left << count) | (left >> ((BITS - count) & mask)) */ LLVM_BUILD_OP(Shl, left, right, tmp_l, "tmp_l", NULL); LLVM_BUILD_OP(LShr, left, bits_minus_shift_count, tmp_r, "tmp_r", NULL); } else { - /* left>>count | left<<(BITS-count) */ + /* (left >> count) | (left << ((BITS - count) & mask)) */ LLVM_BUILD_OP(LShr, left, right, tmp_l, "tmp_l", NULL); LLVM_BUILD_OP(Shl, left, bits_minus_shift_count, tmp_r, "tmp_r", NULL); } diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index 6dc3a0f7d..dacdb83d7 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -153,6 +153,13 @@ aot_target_precheck_can_use_musttail(const AOTCompContext *comp_ctx) */ return false; } + if (strstr(comp_ctx->target_arch, "thumb")) { + /* + * cf. + * https://github.com/bytecodealliance/wasm-micro-runtime/issues/2412 + */ + return false; + } /* * x86-64/i386: true * @@ -1915,6 +1922,7 @@ static ArchItem valid_archs[] = { static const char *valid_abis[] = { "gnu", "eabi", + "eabihf", "gnueabihf", "msvc", "ilp32", @@ -1992,6 +2000,18 @@ get_target_arch_from_triple(const char *triple, char *arch_buf, uint32 buf_size) bh_assert(*triple == '-' || *triple == '\0'); } +static bool +is_baremetal_target(const char *target, const char *cpu, const char *abi) +{ + /* TODO: support more baremetal targets */ + if (target) { + /* If target is thumbxxx, then it is baremetal target */ + if (!strncmp(target, "thumb", strlen("thumb"))) + return true; + } + return false; +} + void aot_handle_llvm_errmsg(const char *string, LLVMErrorRef err) { @@ -2214,7 +2234,7 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option) char *triple_norm_new = NULL, *cpu_new = NULL; char *err = NULL, *fp_round = "round.tonearest", *fp_exce = "fpexcept.strict"; - char triple_buf[32] = { 0 }, features_buf[128] = { 0 }; + char triple_buf[128] = { 0 }, features_buf[128] = { 0 }; uint32 opt_level, size_level, i; LLVMCodeModel code_model; LLVMTargetDataRef target_data_ref; @@ -2510,6 +2530,7 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option) * for Windows/MacOS under Linux host, or generating AOT file for * Linux/MacOS under Windows host. */ + if (!strcmp(abi, "msvc")) { if (!strcmp(arch1, "i386")) vendor_sys = "-pc-win32-"; @@ -2517,7 +2538,10 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option) vendor_sys = "-pc-windows-"; } else { - vendor_sys = "-pc-linux-"; + if (is_baremetal_target(arch, cpu, abi)) + vendor_sys = "-unknown-none-"; + else + vendor_sys = "-pc-linux-"; } bh_assert(strlen(arch1) + strlen(vendor_sys) + strlen(abi) @@ -2553,6 +2577,11 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option) if (!abi) abi = "msvc"; } + else if (is_baremetal_target(arch, cpu, abi)) { + vendor_sys = "-unknown-none-"; + if (!abi) + abi = "gnu"; + } else { vendor_sys = "-pc-linux-"; if (!abi) diff --git a/core/iwasm/compilation/simd/simd_bit_shifts.c b/core/iwasm/compilation/simd/simd_bit_shifts.c index 675ffbcfe..1d645ed71 100644 --- a/core/iwasm/compilation/simd/simd_bit_shifts.c +++ b/core/iwasm/compilation/simd/simd_bit_shifts.c @@ -30,11 +30,11 @@ simd_shift(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, LLVM_CONST(i16x8_vec_zero), LLVM_CONST(i32x4_vec_zero), LLVM_CONST(i64x2_vec_zero) }; - LLVMValueRef lane_bits[] = { - LLVM_CONST(i32_eight), - LLVMConstInt(I32_TYPE, 16, true), - LLVMConstInt(I32_TYPE, 32, true), - LLVMConstInt(I32_TYPE, 64, true), + LLVMValueRef lane_shift_masks[] = { + LLVMConstInt(I32_TYPE, 7, true), + LLVMConstInt(I32_TYPE, 15, true), + LLVMConstInt(I32_TYPE, 31, true), + LLVMConstInt(I32_TYPE, 63, true), }; POP_I32(offset); @@ -44,11 +44,11 @@ simd_shift(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, return false; } - /* offset mod LaneBits */ - if (!lane_bits[itype] - || !(offset = LLVMBuildSRem(comp_ctx->builder, offset, lane_bits[itype], - "offset_fix"))) { - HANDLE_FAILURE("LLVMBuildSRem"); + /* offset = offset & shift_mask */ + if (!lane_shift_masks[itype] + || !(offset = LLVMBuildAnd(comp_ctx->builder, offset, + lane_shift_masks[itype], "offset_fix"))) { + HANDLE_FAILURE("LLVMBuildAnd"); return false; } diff --git a/core/iwasm/fast-jit/fe/jit_emit_compare.c b/core/iwasm/fast-jit/fe/jit_emit_compare.c index d41249346..8fe48f142 100644 --- a/core/iwasm/fast-jit/fe/jit_emit_compare.c +++ b/core/iwasm/fast-jit/fe/jit_emit_compare.c @@ -227,7 +227,7 @@ jit_compile_op_f32_compare(JitCompContext *cc, FloatCond cond) POP_F32(rhs); POP_F32(lhs); - if (jit_reg_is_const_val(lhs) && jit_reg_is_const_val(rhs)) { + if (jit_reg_is_const(lhs) && jit_reg_is_const(rhs)) { float32 lvalue = jit_cc_get_const_F32(cc, lhs); float32 rvalue = jit_cc_get_const_F32(cc, rhs); @@ -290,7 +290,7 @@ jit_compile_op_f64_compare(JitCompContext *cc, FloatCond cond) POP_F64(rhs); POP_F64(lhs); - if (jit_reg_is_const_val(lhs) && jit_reg_is_const_val(rhs)) { + if (jit_reg_is_const(lhs) && jit_reg_is_const(rhs)) { float64 lvalue = jit_cc_get_const_F64(cc, lhs); float64 rvalue = jit_cc_get_const_F64(cc, rhs); diff --git a/core/iwasm/fast-jit/fe/jit_emit_control.c b/core/iwasm/fast-jit/fe/jit_emit_control.c index f7536c73e..5438bc62c 100644 --- a/core/iwasm/fast-jit/fe/jit_emit_control.c +++ b/core/iwasm/fast-jit/fe/jit_emit_control.c @@ -808,7 +808,7 @@ jit_compile_op_block(JitCompContext *cc, uint8 **p_frame_ip, else if (label_type == LABEL_TYPE_IF) { POP_I32(value); - if (!jit_reg_is_const_val(value)) { + if (!jit_reg_is_const(value)) { /* Compare value is not constant, create condition br IR */ /* Create entry block */ diff --git a/core/iwasm/fast-jit/fe/jit_emit_function.c b/core/iwasm/fast-jit/fe/jit_emit_function.c index 3ac9e3ed6..43a71e26a 100644 --- a/core/iwasm/fast-jit/fe/jit_emit_function.c +++ b/core/iwasm/fast-jit/fe/jit_emit_function.c @@ -827,23 +827,45 @@ emit_callnative(JitCompContext *cc, JitReg native_func_reg, JitReg res, JitReg *params, uint32 param_count) { JitInsn *insn; + char *i32_arg_names[] = { "edi", "esi", "edx", "ecx" }; char *i64_arg_names[] = { "rdi", "rsi", "rdx", "rcx", "r8", "r9" }; char *f32_arg_names[] = { "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" }; char *f64_arg_names[] = { "xmm0_f64", "xmm1_f64", "xmm2_f64", "xmm3_f64", "xmm4_f64", "xmm5_f64" }; - JitReg i64_arg_regs[6], f32_arg_regs[6], f64_arg_regs[6], res_reg = 0; + JitReg i32_arg_regs[4], i64_arg_regs[6]; + JitReg f32_arg_regs[6], f64_arg_regs[6], res_reg = 0; JitReg eax_hreg = jit_codegen_get_hreg_by_name("eax"); JitReg xmm0_hreg = jit_codegen_get_hreg_by_name("xmm0"); - uint32 i, i64_reg_idx, float_reg_idx; + uint32 i, i64_reg_idx, float_reg_idx, lock_i32_reg_num; bh_assert(param_count <= 6); + for (i = 0; i < 4; i++) { + i32_arg_regs[i] = jit_codegen_get_hreg_by_name(i32_arg_names[i]); + } + for (i = 0; i < 6; i++) { i64_arg_regs[i] = jit_codegen_get_hreg_by_name(i64_arg_names[i]); f32_arg_regs[i] = jit_codegen_get_hreg_by_name(f32_arg_names[i]); f64_arg_regs[i] = jit_codegen_get_hreg_by_name(f64_arg_names[i]); } + lock_i32_reg_num = param_count < 4 ? param_count : 4; + + /* + * Lock i32 registers so that they won't be allocated for the operand + * of below I32TOI64 insn, which may have been overwritten in the + * previous MOV, for example, in the below insns: + * MOV I5, I15 + * I32TOI64 I6, i5 + * CALLNATIVE VOID, native_func, I5, I6 + * i5 is used in the second insn, but it has been overwritten in I5 + * by the first insn + */ + for (i = 0; i < lock_i32_reg_num; i++) { + GEN_INSN(MOV, i32_arg_regs[i], i32_arg_regs[i]); + } + i64_reg_idx = float_reg_idx = 0; for (i = 0; i < param_count; i++) { switch (jit_reg_kind(params[i])) { @@ -865,6 +887,14 @@ emit_callnative(JitCompContext *cc, JitReg native_func_reg, JitReg res, } } + /* + * Announce the locked i32 registers are being used, and do necessary + * spill ASAP + */ + for (i = 0; i < lock_i32_reg_num; i++) { + GEN_INSN(MOV, i32_arg_regs[i], i32_arg_regs[i]); + } + if (res) { switch (jit_reg_kind(res)) { case JIT_REG_KIND_I32: diff --git a/core/iwasm/fast-jit/jit_codecache.c b/core/iwasm/fast-jit/jit_codecache.c index 73a034f34..ef2074747 100644 --- a/core/iwasm/fast-jit/jit_codecache.c +++ b/core/iwasm/fast-jit/jit_codecache.c @@ -17,8 +17,8 @@ jit_code_cache_init(uint32 code_cache_size) int map_prot = MMAP_PROT_READ | MMAP_PROT_WRITE | MMAP_PROT_EXEC; int map_flags = MMAP_MAP_NONE; - if (!(code_cache_pool = - os_mmap(NULL, code_cache_size, map_prot, map_flags))) { + if (!(code_cache_pool = os_mmap(NULL, code_cache_size, map_prot, map_flags, + os_get_invalid_handle()))) { return false; } diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index 1d90cc37a..86f4573c7 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -432,26 +432,31 @@ wasm_runtime_get_module_hash(wasm_module_t module); * @param env_count The number of elements in env. * @param argv The list of command line arguments. * @param argc The number of elements in argv. - * @param stdinfd The host file descriptor to back WASI STDIN_FILENO. - * If -1 is specified, STDIN_FILENO is used. - * @param stdoutfd The host file descriptor to back WASI STDOUT_FILENO. - * If -1 is specified, STDOUT_FILENO is used. - * @param stderrfd The host file descriptor to back WASI STDERR_FILENO. - * If -1 is specified, STDERR_FILENO is used. + * @param stdin_handle The raw host handle to back WASI STDIN_FILENO. + * If an invalid handle is specified (e.g. -1 on POSIX, + * INVALID_HANDLE_VALUE on Windows), the platform default + * for STDIN is used. + * @param stdoutfd The raw host handle to back WASI STDOUT_FILENO. + * If an invalid handle is specified (e.g. -1 on POSIX, + * INVALID_HANDLE_VALUE on Windows), the platform default + * for STDOUT is used. + * @param stderrfd The raw host handle to back WASI STDERR_FILENO. + * If an invalid handle is specified (e.g. -1 on POSIX, + * INVALID_HANDLE_VALUE on Windows), the platform default + * for STDERR is used. */ WASM_RUNTIME_API_EXTERN void wasm_runtime_set_wasi_args_ex(wasm_module_t module, const char *dir_list[], uint32_t dir_count, const char *map_dir_list[], uint32_t map_dir_count, const char *env[], uint32_t env_count, - char *argv[], int argc, - int stdinfd, int stdoutfd, int stderrfd); + char *argv[], int argc, int64_t stdinfd, + int64_t stdoutfd, int64_t stderrfd); /** * Set WASI parameters. * - * Same as wasm_runtime_set_wasi_args_ex with stdinfd = -1, stdoutfd = -1, - * stderrfd = -1. + * Same as wasm_runtime_set_wasi_args_ex but with default stdio handles */ WASM_RUNTIME_API_EXTERN void wasm_runtime_set_wasi_args(wasm_module_t module, diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index 9b2dd1082..af359f336 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -403,7 +403,7 @@ typedef struct WASIArguments { uint32 ns_lookup_count; char **argv; uint32 argc; - int stdio[3]; + os_raw_file_handle stdio[3]; } WASIArguments; #endif diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index f9f1172b1..02eb8cdc3 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -1034,7 +1034,8 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst, } /* - module_inst */ - exec_env->module_inst = (WASMModuleInstanceCommon *)sub_module_inst; + wasm_exec_env_set_module_inst(exec_env, + (WASMModuleInstanceCommon *)sub_module_inst); /* - aux_stack_boundary */ aux_stack_origin_boundary = exec_env->aux_stack_boundary.boundary; exec_env->aux_stack_boundary.boundary = @@ -1056,15 +1057,8 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst, prev_frame->ip = ip; exec_env->aux_stack_boundary.boundary = aux_stack_origin_boundary; exec_env->aux_stack_bottom.bottom = aux_stack_origin_bottom; - exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst; - - /* transfer exception if it is thrown */ - if (wasm_copy_exception(sub_module_inst, NULL)) { - bh_memcpy_s(module_inst->cur_exception, - sizeof(module_inst->cur_exception), - sub_module_inst->cur_exception, - sizeof(sub_module_inst->cur_exception)); - } + wasm_exec_env_restore_module_inst(exec_env, + (WASMModuleInstanceCommon *)module_inst); } #endif diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index 9afa6eebb..d70d48482 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -1031,7 +1031,8 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst, } /* - module_inst */ - exec_env->module_inst = (WASMModuleInstanceCommon *)sub_module_inst; + wasm_exec_env_set_module_inst(exec_env, + (WASMModuleInstanceCommon *)sub_module_inst); /* - aux_stack_boundary */ aux_stack_origin_boundary = exec_env->aux_stack_boundary.boundary; exec_env->aux_stack_boundary.boundary = @@ -1053,15 +1054,8 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst, prev_frame->ip = ip; exec_env->aux_stack_boundary.boundary = aux_stack_origin_boundary; exec_env->aux_stack_bottom.bottom = aux_stack_origin_bottom; - exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst; - - /* transfer exception if it is thrown */ - if (wasm_copy_exception(sub_module_inst, NULL)) { - bh_memcpy_s(module_inst->cur_exception, - sizeof(module_inst->cur_exception), - sub_module_inst->cur_exception, - sizeof(sub_module_inst->cur_exception)); - } + wasm_exec_env_restore_module_inst(exec_env, + (WASMModuleInstanceCommon *)module_inst); } #endif diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index feed5ee51..bc2e4df1b 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -173,7 +173,6 @@ fail: #define read_uint8(p) TEMPLATE_READ_VALUE(uint8, p) #define read_uint32(p) TEMPLATE_READ_VALUE(uint32, p) -#define read_bool(p) TEMPLATE_READ_VALUE(bool, p) #define read_leb_int64(p, p_end, res) \ do { \ @@ -490,6 +489,7 @@ load_init_expr(const uint8 **p_buf, const uint8 *buf_end, if (type != VALUE_TYPE_V128) goto fail_type_mismatch; + CHECK_BUF(p, p_end, 1); flag = read_uint8(p); (void)flag; @@ -7456,6 +7456,7 @@ re_scan: BlockType block_type; p_org = p - 1; + CHECK_BUF(p, p_end, 1); value_type = read_uint8(p); if (is_byte_a_type(value_type)) { /* If the first byte is one of these special values: @@ -9596,6 +9597,7 @@ re_scan: { uint32 opcode1; + CHECK_BUF(p, p_end, 1); opcode1 = read_uint8(p); /* follow the order of enum WASMSimdEXTOpcode in wasm_opcode.h */ @@ -10257,6 +10259,7 @@ re_scan: { uint32 opcode1; + CHECK_BUF(p, p_end, 1); opcode1 = read_uint8(p); #if WASM_ENABLE_FAST_INTERP != 0 emit_byte(loader_ctx, opcode1); diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index a87001696..720a78f03 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -276,6 +276,12 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent, if (max_page_count > DEFAULT_MAX_PAGES) max_page_count = DEFAULT_MAX_PAGES; } + else { /* heap_size == 0 */ + if (init_page_count == DEFAULT_MAX_PAGES) { + num_bytes_per_page = UINT32_MAX; + init_page_count = max_page_count = 1; + } + } LOG_VERBOSE("Memory instantiate:"); LOG_VERBOSE(" page bytes: %u, init pages: %u, max pages: %u", @@ -318,14 +324,16 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent, * so the range of ea is 0 to 8G */ if (!(memory->memory_data = mapped_mem = - os_mmap(NULL, map_size, MMAP_PROT_NONE, MMAP_MAP_NONE))) { + os_mmap(NULL, map_size, MMAP_PROT_NONE, MMAP_MAP_NONE, + os_get_invalid_handle()))) { set_error_buf(error_buf, error_buf_size, "mmap memory failed"); goto fail1; } #ifdef BH_PLATFORM_WINDOWS - if (!os_mem_commit(mapped_mem, memory_data_size, - MMAP_PROT_READ | MMAP_PROT_WRITE)) { + if (memory_data_size > 0 + && !os_mem_commit(mapped_mem, memory_data_size, + MMAP_PROT_READ | MMAP_PROT_WRITE)) { set_error_buf(error_buf, error_buf_size, "commit memory failed"); os_munmap(mapped_mem, map_size); goto fail1; @@ -338,8 +346,12 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent, set_error_buf(error_buf, error_buf_size, "mprotect memory failed"); goto fail2; } + /* Newly allocated pages are filled with zero by the OS, we don't fill it * again here */ + + if (memory_data_size > UINT32_MAX) + memory_data_size = UINT32_MAX; #endif /* end of OS_ENABLE_HW_BOUND_CHECK */ memory->module_type = Wasm_Module_Bytecode; @@ -1050,7 +1062,8 @@ execute_post_instantiate_functions(WASMModuleInstance *module_inst, wasm functions, and ensure that the exec_env's module inst is the correct one. */ module_inst_main = exec_env_main->module_inst; - exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst; + wasm_exec_env_set_module_inst(exec_env, + (WASMModuleInstanceCommon *)module_inst); } else { /* Try using the existing exec_env */ @@ -1075,7 +1088,8 @@ execute_post_instantiate_functions(WASMModuleInstance *module_inst, module inst to ensure that the exec_env's module inst is the correct one. */ module_inst_main = exec_env->module_inst; - exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst; + wasm_exec_env_set_module_inst( + exec_env, (WASMModuleInstanceCommon *)module_inst); } } @@ -1108,12 +1122,12 @@ execute_post_instantiate_functions(WASMModuleInstance *module_inst, fail: if (is_sub_inst) { /* Restore the parent exec_env's module inst */ - exec_env_main->module_inst = module_inst_main; + wasm_exec_env_restore_module_inst(exec_env_main, module_inst_main); } else { if (module_inst_main) /* Restore the existing exec_env's module inst */ - exec_env->module_inst = module_inst_main; + wasm_exec_env_restore_module_inst(exec_env, module_inst_main); if (exec_env_created) wasm_exec_env_destroy(exec_env_created); } @@ -1182,7 +1196,8 @@ execute_malloc_function(WASMModuleInstance *module_inst, WASMExecEnv *exec_env, module inst to ensure that the exec_env's module inst is the correct one. */ module_inst_old = exec_env->module_inst; - exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst; + wasm_exec_env_set_module_inst( + exec_env, (WASMModuleInstanceCommon *)module_inst); } } @@ -1193,7 +1208,7 @@ execute_malloc_function(WASMModuleInstance *module_inst, WASMExecEnv *exec_env, if (module_inst_old) /* Restore the existing exec_env's module inst */ - exec_env->module_inst = module_inst_old; + wasm_exec_env_restore_module_inst(exec_env, module_inst_old); if (exec_env_created) wasm_exec_env_destroy(exec_env_created); @@ -1249,7 +1264,8 @@ execute_free_function(WASMModuleInstance *module_inst, WASMExecEnv *exec_env, module inst to ensure that the exec_env's module inst is the correct one. */ module_inst_old = exec_env->module_inst; - exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst; + wasm_exec_env_set_module_inst( + exec_env, (WASMModuleInstanceCommon *)module_inst); } } @@ -1257,7 +1273,7 @@ execute_free_function(WASMModuleInstance *module_inst, WASMExecEnv *exec_env, if (module_inst_old) /* Restore the existing exec_env's module inst */ - exec_env->module_inst = module_inst_old; + wasm_exec_env_restore_module_inst(exec_env, module_inst_old); if (exec_env_created) wasm_exec_env_destroy(exec_env_created); diff --git a/core/iwasm/libraries/lib-socket/test/manifest.json b/core/iwasm/libraries/lib-socket/test/manifest.json new file mode 100644 index 000000000..b0afd1d6b --- /dev/null +++ b/core/iwasm/libraries/lib-socket/test/manifest.json @@ -0,0 +1,3 @@ +{ + "name": "WAMR lib-socket tests" +} \ No newline at end of file diff --git a/core/iwasm/libraries/libc-uvwasi/libc_uvwasi_wrapper.c b/core/iwasm/libraries/libc-uvwasi/libc_uvwasi_wrapper.c index 504ff7f93..6ead65406 100644 --- a/core/iwasm/libraries/libc-uvwasi/libc_uvwasi_wrapper.c +++ b/core/iwasm/libraries/libc-uvwasi/libc_uvwasi_wrapper.c @@ -30,7 +30,16 @@ wasm_runtime_module_free(module_inst, offset) /* clang-format on */ -#define wasi_errno_t uvwasi_errno_t +// uvwasi_errno_t is typedef'd to uint16 which is correct according to the ABI +// specification. However, in WASM, the smallest integer type is int32. If we +// return uint16, we would rely on language SDKs to implement the correct +// behaviour of casting to uint16 before checking the value or using it any way. +// Failure to do so can cause tricky bugs as the upper 16 bits of the error +// result are not guaranteed to be zero'ed by us so the result essentially +// contains garbage from the WASM app perspective. To prevent this, we return +// uint32 directly instead so as not to be reliant on the correct behaviour of +// any current/future SDK implementations. +#define wasi_errno_t uint32_t #define wasi_fd_t uvwasi_fd_t #define wasi_clockid_t uvwasi_clockid_t #define wasi_timestamp_t uvwasi_timestamp_t diff --git a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c index 292bd8379..9f35b81a7 100644 --- a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c +++ b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c @@ -7,6 +7,7 @@ #include "bh_platform.h" #include "wasm_export.h" #include "wasm_runtime_common.h" +#include "wasmtime_ssp.h" #if WASM_ENABLE_THREAD_MGR != 0 #include "../../../thread-mgr/thread_manager.h" @@ -192,7 +193,7 @@ wasi_clock_res_get(wasm_exec_env_t exec_env, if (!validate_native_addr(resolution, sizeof(wasi_timestamp_t))) return (wasi_errno_t)-1; - return wasmtime_ssp_clock_res_get(clock_id, resolution); + return os_clock_res_get(clock_id, resolution); } static wasi_errno_t @@ -206,7 +207,7 @@ wasi_clock_time_get(wasm_exec_env_t exec_env, if (!validate_native_addr(time, sizeof(wasi_timestamp_t))) return (wasi_errno_t)-1; - return wasmtime_ssp_clock_time_get(clock_id, precision, time); + return os_clock_time_get(clock_id, precision, time); } static wasi_errno_t diff --git a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.h b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.h index be509576b..d958fa39c 100644 --- a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.h +++ b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.h @@ -6,7 +6,6 @@ #ifndef _LIBC_WASI_WRAPPER_H #define _LIBC_WASI_WRAPPER_H -#include "wasmtime_ssp.h" #include "posix.h" #ifdef __cplusplus @@ -19,7 +18,16 @@ typedef __wasi_advice_t wasi_advice_t; typedef __wasi_ciovec_t wasi_ciovec_t; typedef __wasi_clockid_t wasi_clockid_t; typedef __wasi_dircookie_t wasi_dircookie_t; -typedef __wasi_errno_t wasi_errno_t; +// __wasi_errno_t is typedef'd to uint16 which is correct according to the ABI +// specification. However, in WASM, the smallest integer type is int32. If we +// return uint16, we would rely on language SDKs to implement the correct +// behaviour of casting to uint16 before checking the value or using it any way. +// Failure to do so can cause tricky bugs as the upper 16 bits of the error +// result are not guaranteed to be zero'ed by us so the result essentially +// contains garbage from the WASM app perspective. To prevent this, we return +// uint32 directly instead so as not to be reliant on the correct behaviour of +// any current/future WASI SDK implemenations. +typedef uint32_t wasi_errno_t; typedef __wasi_event_t wasi_event_t; typedef __wasi_exitcode_t wasi_exitcode_t; typedef __wasi_fdflags_t wasi_fdflags_t; diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h index efe7c8e3a..ed8463866 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h @@ -3,10 +3,6 @@ * LLVM Exceptions. See * https://github.com/bytecodealliance/wasmtime/blob/main/LICENSE * for license information. - * - * This file declares an interface similar to WASI, but augmented to expose - * some implementation details such as the curfds arguments that we pass - * around to avoid storing them in TLS. */ /** @@ -22,1338 +18,584 @@ #include #include +#include "bh_platform.h" #include "wasm_export.h" -/* clang-format off */ - #ifdef __cplusplus -#ifndef _Static_assert -#define _Static_assert static_assert -#endif /* _Static_assert */ - -#ifndef _Alignof -#define _Alignof alignof -#endif /* _Alignof */ - -#ifndef _Noreturn -#define _Noreturn [[ noreturn ]] -#endif /* _Noreturn */ extern "C" { #endif -_Static_assert(_Alignof(int8_t) == 1, "non-wasi data layout"); -_Static_assert(_Alignof(uint8_t) == 1, "non-wasi data layout"); -_Static_assert(_Alignof(int16_t) == 2, "non-wasi data layout"); -_Static_assert(_Alignof(uint16_t) == 2, "non-wasi data layout"); -_Static_assert(_Alignof(int32_t) == 4, "non-wasi data layout"); -_Static_assert(_Alignof(uint32_t) == 4, "non-wasi data layout"); -#if 0 -_Static_assert(_Alignof(int64_t) == 8, "non-wasi data layout"); -_Static_assert(_Alignof(uint64_t) == 8, "non-wasi data layout"); -#endif - -typedef uint32_t __wasi_size_t; -_Static_assert(_Alignof(__wasi_size_t) == 4, "non-wasi data layout"); - -typedef uint8_t __wasi_advice_t; -#define __WASI_ADVICE_NORMAL (0) -#define __WASI_ADVICE_SEQUENTIAL (1) -#define __WASI_ADVICE_RANDOM (2) -#define __WASI_ADVICE_WILLNEED (3) -#define __WASI_ADVICE_DONTNEED (4) -#define __WASI_ADVICE_NOREUSE (5) - -typedef uint32_t __wasi_clockid_t; -#define __WASI_CLOCK_REALTIME (0) -#define __WASI_CLOCK_MONOTONIC (1) -#define __WASI_CLOCK_PROCESS_CPUTIME_ID (2) -#define __WASI_CLOCK_THREAD_CPUTIME_ID (3) - -typedef uint64_t __wasi_device_t; - -typedef uint64_t __wasi_dircookie_t; -#define __WASI_DIRCOOKIE_START (0) - -typedef uint32_t __wasi_dirnamlen_t; - -typedef uint16_t __wasi_errno_t; -#define __WASI_ESUCCESS (0) -#define __WASI_E2BIG (1) -#define __WASI_EACCES (2) -#define __WASI_EADDRINUSE (3) -#define __WASI_EADDRNOTAVAIL (4) -#define __WASI_EAFNOSUPPORT (5) -#define __WASI_EAGAIN (6) -#define __WASI_EALREADY (7) -#define __WASI_EBADF (8) -#define __WASI_EBADMSG (9) -#define __WASI_EBUSY (10) -#define __WASI_ECANCELED (11) -#define __WASI_ECHILD (12) -#define __WASI_ECONNABORTED (13) -#define __WASI_ECONNREFUSED (14) -#define __WASI_ECONNRESET (15) -#define __WASI_EDEADLK (16) -#define __WASI_EDESTADDRREQ (17) -#define __WASI_EDOM (18) -#define __WASI_EDQUOT (19) -#define __WASI_EEXIST (20) -#define __WASI_EFAULT (21) -#define __WASI_EFBIG (22) -#define __WASI_EHOSTUNREACH (23) -#define __WASI_EIDRM (24) -#define __WASI_EILSEQ (25) -#define __WASI_EINPROGRESS (26) -#define __WASI_EINTR (27) -#define __WASI_EINVAL (28) -#define __WASI_EIO (29) -#define __WASI_EISCONN (30) -#define __WASI_EISDIR (31) -#define __WASI_ELOOP (32) -#define __WASI_EMFILE (33) -#define __WASI_EMLINK (34) -#define __WASI_EMSGSIZE (35) -#define __WASI_EMULTIHOP (36) -#define __WASI_ENAMETOOLONG (37) -#define __WASI_ENETDOWN (38) -#define __WASI_ENETRESET (39) -#define __WASI_ENETUNREACH (40) -#define __WASI_ENFILE (41) -#define __WASI_ENOBUFS (42) -#define __WASI_ENODEV (43) -#define __WASI_ENOENT (44) -#define __WASI_ENOEXEC (45) -#define __WASI_ENOLCK (46) -#define __WASI_ENOLINK (47) -#define __WASI_ENOMEM (48) -#define __WASI_ENOMSG (49) -#define __WASI_ENOPROTOOPT (50) -#define __WASI_ENOSPC (51) -#define __WASI_ENOSYS (52) -#define __WASI_ENOTCONN (53) -#define __WASI_ENOTDIR (54) -#define __WASI_ENOTEMPTY (55) -#define __WASI_ENOTRECOVERABLE (56) -#define __WASI_ENOTSOCK (57) -#define __WASI_ENOTSUP (58) -#define __WASI_ENOTTY (59) -#define __WASI_ENXIO (60) -#define __WASI_EOVERFLOW (61) -#define __WASI_EOWNERDEAD (62) -#define __WASI_EPERM (63) -#define __WASI_EPIPE (64) -#define __WASI_EPROTO (65) -#define __WASI_EPROTONOSUPPORT (66) -#define __WASI_EPROTOTYPE (67) -#define __WASI_ERANGE (68) -#define __WASI_EROFS (69) -#define __WASI_ESPIPE (70) -#define __WASI_ESRCH (71) -#define __WASI_ESTALE (72) -#define __WASI_ETIMEDOUT (73) -#define __WASI_ETXTBSY (74) -#define __WASI_EXDEV (75) -#define __WASI_ENOTCAPABLE (76) - -typedef uint16_t __wasi_eventrwflags_t; -#define __WASI_EVENT_FD_READWRITE_HANGUP (0x0001) - -typedef uint8_t __wasi_eventtype_t; -#define __WASI_EVENTTYPE_CLOCK (0) -#define __WASI_EVENTTYPE_FD_READ (1) -#define __WASI_EVENTTYPE_FD_WRITE (2) - -typedef uint32_t __wasi_exitcode_t; - -typedef uint32_t __wasi_fd_t; - -typedef uint16_t __wasi_fdflags_t; -#define __WASI_FDFLAG_APPEND (0x0001) -#define __WASI_FDFLAG_DSYNC (0x0002) -#define __WASI_FDFLAG_NONBLOCK (0x0004) -#define __WASI_FDFLAG_RSYNC (0x0008) -#define __WASI_FDFLAG_SYNC (0x0010) - -typedef int64_t __wasi_filedelta_t; - -typedef uint64_t __wasi_filesize_t; - -typedef uint8_t __wasi_filetype_t; -#define __WASI_FILETYPE_UNKNOWN (0) -#define __WASI_FILETYPE_BLOCK_DEVICE (1) -#define __WASI_FILETYPE_CHARACTER_DEVICE (2) -#define __WASI_FILETYPE_DIRECTORY (3) -#define __WASI_FILETYPE_REGULAR_FILE (4) -#define __WASI_FILETYPE_SOCKET_DGRAM (5) -#define __WASI_FILETYPE_SOCKET_STREAM (6) -#define __WASI_FILETYPE_SYMBOLIC_LINK (7) - -typedef uint16_t __wasi_fstflags_t; -#define __WASI_FILESTAT_SET_ATIM (0x0001) -#define __WASI_FILESTAT_SET_ATIM_NOW (0x0002) -#define __WASI_FILESTAT_SET_MTIM (0x0004) -#define __WASI_FILESTAT_SET_MTIM_NOW (0x0008) - -typedef uint64_t __wasi_inode_t; - -typedef uint64_t __wasi_linkcount_t __attribute__((aligned(8))); - -typedef uint32_t __wasi_lookupflags_t; -#define __WASI_LOOKUP_SYMLINK_FOLLOW (0x00000001) - -typedef uint16_t __wasi_oflags_t; -#define __WASI_O_CREAT (0x0001) -#define __WASI_O_DIRECTORY (0x0002) -#define __WASI_O_EXCL (0x0004) -#define __WASI_O_TRUNC (0x0008) - -typedef uint16_t __wasi_riflags_t; -#define __WASI_SOCK_RECV_PEEK (0x0001) -#define __WASI_SOCK_RECV_WAITALL (0x0002) - -typedef uint64_t __wasi_rights_t; - -/** - * Observe that WASI defines rights in the plural form - * TODO: refactor to use RIGHTS instead of RIGHT - */ -#define __WASI_RIGHT_FD_DATASYNC ((__wasi_rights_t)(UINT64_C(1) << 0)) -#define __WASI_RIGHT_FD_READ ((__wasi_rights_t)(UINT64_C(1) << 1)) -#define __WASI_RIGHT_FD_SEEK ((__wasi_rights_t)(UINT64_C(1) << 2)) -#define __WASI_RIGHT_FD_FDSTAT_SET_FLAGS ((__wasi_rights_t)(UINT64_C(1) << 3)) -#define __WASI_RIGHT_FD_SYNC ((__wasi_rights_t)(UINT64_C(1) << 4)) -#define __WASI_RIGHT_FD_TELL ((__wasi_rights_t)(UINT64_C(1) << 5)) -#define __WASI_RIGHT_FD_WRITE ((__wasi_rights_t)(UINT64_C(1) << 6)) -#define __WASI_RIGHT_FD_ADVISE ((__wasi_rights_t)(UINT64_C(1) << 7)) -#define __WASI_RIGHT_FD_ALLOCATE ((__wasi_rights_t)(UINT64_C(1) << 8)) -#define __WASI_RIGHT_PATH_CREATE_DIRECTORY ((__wasi_rights_t)(UINT64_C(1) << 9)) -#define __WASI_RIGHT_PATH_CREATE_FILE ((__wasi_rights_t)(UINT64_C(1) << 10)) -#define __WASI_RIGHT_PATH_LINK_SOURCE ((__wasi_rights_t)(UINT64_C(1) << 11)) -#define __WASI_RIGHT_PATH_LINK_TARGET ((__wasi_rights_t)(UINT64_C(1) << 12)) -#define __WASI_RIGHT_PATH_OPEN ((__wasi_rights_t)(UINT64_C(1) << 13)) -#define __WASI_RIGHT_FD_READDIR ((__wasi_rights_t)(UINT64_C(1) << 14)) -#define __WASI_RIGHT_PATH_READLINK ((__wasi_rights_t)(UINT64_C(1) << 15)) -#define __WASI_RIGHT_PATH_RENAME_SOURCE ((__wasi_rights_t)(UINT64_C(1) << 16)) -#define __WASI_RIGHT_PATH_RENAME_TARGET ((__wasi_rights_t)(UINT64_C(1) << 17)) -#define __WASI_RIGHT_PATH_FILESTAT_GET ((__wasi_rights_t)(UINT64_C(1) << 18)) -#define __WASI_RIGHT_PATH_FILESTAT_SET_SIZE ((__wasi_rights_t)(UINT64_C(1) << 19)) -#define __WASI_RIGHT_PATH_FILESTAT_SET_TIMES ((__wasi_rights_t)(UINT64_C(1) << 20)) -#define __WASI_RIGHT_FD_FILESTAT_GET ((__wasi_rights_t)(UINT64_C(1) << 21)) -#define __WASI_RIGHT_FD_FILESTAT_SET_SIZE ((__wasi_rights_t)(UINT64_C(1) << 22)) -#define __WASI_RIGHT_FD_FILESTAT_SET_TIMES ((__wasi_rights_t)(UINT64_C(1) << 23)) -#define __WASI_RIGHT_PATH_SYMLINK ((__wasi_rights_t)(UINT64_C(1) << 24)) -#define __WASI_RIGHT_PATH_REMOVE_DIRECTORY ((__wasi_rights_t)(UINT64_C(1) << 25)) -#define __WASI_RIGHT_PATH_UNLINK_FILE ((__wasi_rights_t)(UINT64_C(1) << 26)) -#define __WASI_RIGHT_POLL_FD_READWRITE ((__wasi_rights_t)(UINT64_C(1) << 27)) -#define __WASI_RIGHT_SOCK_CONNECT ((__wasi_rights_t)(UINT64_C(1) << 28)) -#define __WASI_RIGHT_SOCK_LISTEN ((__wasi_rights_t)(UINT64_C(1) << 29)) -#define __WASI_RIGHT_SOCK_BIND ((__wasi_rights_t)(UINT64_C(1) << 30)) -#define __WASI_RIGHT_SOCK_ACCEPT ((__wasi_rights_t)(UINT64_C(1) << 31)) -#define __WASI_RIGHT_SOCK_RECV ((__wasi_rights_t)(UINT64_C(1) << 32)) -#define __WASI_RIGHT_SOCK_SEND ((__wasi_rights_t)(UINT64_C(1) << 33)) -#define __WASI_RIGHT_SOCK_ADDR_LOCAL ((__wasi_rights_t)(UINT64_C(1) << 34)) -#define __WASI_RIGHT_SOCK_ADDR_REMOTE ((__wasi_rights_t)(UINT64_C(1) << 35)) -#define __WASI_RIGHT_SOCK_RECV_FROM ((__wasi_rights_t)(UINT64_C(1) << 36)) -#define __WASI_RIGHT_SOCK_SEND_TO ((__wasi_rights_t)(UINT64_C(1) << 37)) - -typedef uint16_t __wasi_roflags_t; -#define __WASI_SOCK_RECV_DATA_TRUNCATED (0x0001) - -typedef uint8_t __wasi_sdflags_t; -#define __WASI_SHUT_RD (0x01) -#define __WASI_SHUT_WR (0x02) - -typedef uint16_t __wasi_siflags_t; - -typedef uint8_t __wasi_signal_t; - -typedef uint16_t __wasi_subclockflags_t; -#define __WASI_SUBSCRIPTION_CLOCK_ABSTIME (0x0001) - -typedef uint64_t __wasi_timestamp_t; - -typedef uint64_t __wasi_userdata_t; - -typedef uint8_t __wasi_whence_t; -#define __WASI_WHENCE_SET (0) -#define __WASI_WHENCE_CUR (1) -#define __WASI_WHENCE_END (2) - -typedef uint8_t __wasi_preopentype_t; -#define __WASI_PREOPENTYPE_DIR (0) - -struct fd_table; -struct fd_prestats; -struct argv_environ_values; -struct addr_pool; - -typedef struct __wasi_dirent_t { - __wasi_dircookie_t d_next; - __wasi_inode_t d_ino; - __wasi_dirnamlen_t d_namlen; - __wasi_filetype_t d_type; -} __wasi_dirent_t __attribute__((aligned(8))); -_Static_assert(offsetof(__wasi_dirent_t, d_next) == 0, "non-wasi data layout"); -_Static_assert(offsetof(__wasi_dirent_t, d_ino) == 8, "non-wasi data layout"); -_Static_assert(offsetof(__wasi_dirent_t, d_namlen) == 16, "non-wasi data layout"); -_Static_assert(offsetof(__wasi_dirent_t, d_type) == 20, "non-wasi data layout"); -_Static_assert(sizeof(__wasi_dirent_t) == 24, "non-wasi data layout"); -_Static_assert(_Alignof(__wasi_dirent_t) == 8, "non-wasi data layout"); - -typedef struct __wasi_event_t { - __wasi_userdata_t userdata; - __wasi_errno_t error; - __wasi_eventtype_t type; - uint8_t __paddings[5]; - union __wasi_event_u { - struct __wasi_event_u_fd_readwrite_t { - __wasi_filesize_t nbytes; - __wasi_eventrwflags_t flags; - uint8_t __paddings[6]; - } fd_readwrite; - } u; -} __wasi_event_t __attribute__((aligned(8))); -_Static_assert(offsetof(__wasi_event_t, userdata) == 0, "non-wasi data layout"); -_Static_assert(offsetof(__wasi_event_t, error) == 8, "non-wasi data layout"); -_Static_assert(offsetof(__wasi_event_t, type) == 10, "non-wasi data layout"); -_Static_assert( - offsetof(__wasi_event_t, u.fd_readwrite.nbytes) == 16, "non-wasi data layout"); -_Static_assert( - offsetof(__wasi_event_t, u.fd_readwrite.flags) == 24, "non-wasi data layout"); -_Static_assert(sizeof(__wasi_event_t) == 32, "non-wasi data layout"); -_Static_assert(_Alignof(__wasi_event_t) == 8, "non-wasi data layout"); - -typedef struct __wasi_prestat_t { - __wasi_preopentype_t pr_type; - union __wasi_prestat_u { - struct __wasi_prestat_u_dir_t { - size_t pr_name_len; - } dir; - } u; -} __wasi_prestat_t; -_Static_assert(offsetof(__wasi_prestat_t, pr_type) == 0, "non-wasi data layout"); -_Static_assert(sizeof(void *) != 4 || - offsetof(__wasi_prestat_t, u.dir.pr_name_len) == 4, "non-wasi data layout"); -_Static_assert(sizeof(void *) != 8 || - offsetof(__wasi_prestat_t, u.dir.pr_name_len) == 8, "non-wasi data layout"); -_Static_assert(sizeof(void *) != 4 || - sizeof(__wasi_prestat_t) == 8, "non-wasi data layout"); -_Static_assert(sizeof(void *) != 8 || - sizeof(__wasi_prestat_t) == 16, "non-wasi data layout"); -_Static_assert(sizeof(void *) != 4 || - _Alignof(__wasi_prestat_t) == 4, "non-wasi data layout"); -_Static_assert(sizeof(void *) != 8 || - _Alignof(__wasi_prestat_t) == 8, "non-wasi data layout"); - -typedef struct __wasi_fdstat_t { - __wasi_filetype_t fs_filetype; - __wasi_fdflags_t fs_flags; - uint8_t __paddings[4]; - __wasi_rights_t fs_rights_base; - __wasi_rights_t fs_rights_inheriting; -} __wasi_fdstat_t __attribute__((aligned(8))); -_Static_assert( - offsetof(__wasi_fdstat_t, fs_filetype) == 0, "non-wasi data layout"); -_Static_assert(offsetof(__wasi_fdstat_t, fs_flags) == 2, "non-wasi data layout"); -_Static_assert( - offsetof(__wasi_fdstat_t, fs_rights_base) == 8, "non-wasi data layout"); -_Static_assert( - offsetof(__wasi_fdstat_t, fs_rights_inheriting) == 16, - "non-wasi data layout"); -_Static_assert(sizeof(__wasi_fdstat_t) == 24, "non-wasi data layout"); -_Static_assert(_Alignof(__wasi_fdstat_t) == 8, "non-wasi data layout"); - -typedef struct __wasi_filestat_t { - __wasi_device_t st_dev; - __wasi_inode_t st_ino; - __wasi_filetype_t st_filetype; - __wasi_linkcount_t st_nlink; - __wasi_filesize_t st_size; - __wasi_timestamp_t st_atim; - __wasi_timestamp_t st_mtim; - __wasi_timestamp_t st_ctim; -} __wasi_filestat_t __attribute__((aligned(8))); -_Static_assert(offsetof(__wasi_filestat_t, st_dev) == 0, "non-wasi data layout"); -_Static_assert(offsetof(__wasi_filestat_t, st_ino) == 8, "non-wasi data layout"); -_Static_assert( - offsetof(__wasi_filestat_t, st_filetype) == 16, "non-wasi data layout"); -_Static_assert( - offsetof(__wasi_filestat_t, st_nlink) == 24, "non-wasi data layout"); -_Static_assert( - offsetof(__wasi_filestat_t, st_size) == 32, "non-wasi data layout"); -_Static_assert( - offsetof(__wasi_filestat_t, st_atim) == 40, "non-wasi data layout"); -_Static_assert( - offsetof(__wasi_filestat_t, st_mtim) == 48, "non-wasi data layout"); -_Static_assert( - offsetof(__wasi_filestat_t, st_ctim) == 56, "non-wasi data layout"); -_Static_assert(sizeof(__wasi_filestat_t) == 64, "non-wasi data layout"); -_Static_assert(_Alignof(__wasi_filestat_t) == 8, "non-wasi data layout"); - -typedef struct __wasi_ciovec_t { - const void *buf; - size_t buf_len; -} __wasi_ciovec_t; -_Static_assert(offsetof(__wasi_ciovec_t, buf) == 0, "non-wasi data layout"); -_Static_assert(sizeof(void *) != 4 || - offsetof(__wasi_ciovec_t, buf_len) == 4, "non-wasi data layout"); -_Static_assert(sizeof(void *) != 8 || - offsetof(__wasi_ciovec_t, buf_len) == 8, "non-wasi data layout"); -_Static_assert(sizeof(void *) != 4 || - sizeof(__wasi_ciovec_t) == 8, "non-wasi data layout"); -_Static_assert(sizeof(void *) != 8 || - sizeof(__wasi_ciovec_t) == 16, "non-wasi data layout"); -_Static_assert(sizeof(void *) != 4 || - _Alignof(__wasi_ciovec_t) == 4, "non-wasi data layout"); -_Static_assert(sizeof(void *) != 8 || - _Alignof(__wasi_ciovec_t) == 8, "non-wasi data layout"); - -typedef struct __wasi_iovec_t { - void *buf; - size_t buf_len; -} __wasi_iovec_t; -_Static_assert(offsetof(__wasi_iovec_t, buf) == 0, "non-wasi data layout"); -_Static_assert(sizeof(void *) != 4 || - offsetof(__wasi_iovec_t, buf_len) == 4, "non-wasi data layout"); -_Static_assert(sizeof(void *) != 8 || - offsetof(__wasi_iovec_t, buf_len) == 8, "non-wasi data layout"); -_Static_assert(sizeof(void *) != 4 || - sizeof(__wasi_iovec_t) == 8, "non-wasi data layout"); -_Static_assert(sizeof(void *) != 8 || - sizeof(__wasi_iovec_t) == 16, "non-wasi data layout"); -_Static_assert(sizeof(void *) != 4 || - _Alignof(__wasi_iovec_t) == 4, "non-wasi data layout"); -_Static_assert(sizeof(void *) != 8 || - _Alignof(__wasi_iovec_t) == 8, "non-wasi data layout"); - -/** - * The contents of a `subscription` when type is `eventtype::clock`. - */ -typedef struct __wasi_subscription_clock_t { - /** - * The clock against which to compare the timestamp. - */ - __wasi_clockid_t clock_id; - - uint8_t __paddings1[4]; - - /** - * The absolute or relative timestamp. - */ - __wasi_timestamp_t timeout; - - /** - * The amount of time that the implementation may wait additionally - * to coalesce with other events. - */ - __wasi_timestamp_t precision; - - /** - * Flags specifying whether the timeout is absolute or relative - */ - __wasi_subclockflags_t flags; - - uint8_t __paddings2[4]; - -} __wasi_subscription_clock_t __attribute__((aligned(8))); - -_Static_assert(sizeof(__wasi_subscription_clock_t) == 32, "witx calculated size"); -_Static_assert(_Alignof(__wasi_subscription_clock_t) == 8, "witx calculated align"); -_Static_assert(offsetof(__wasi_subscription_clock_t, clock_id) == 0, "witx calculated offset"); -_Static_assert(offsetof(__wasi_subscription_clock_t, timeout) == 8, "witx calculated offset"); -_Static_assert(offsetof(__wasi_subscription_clock_t, precision) == 16, "witx calculated offset"); -_Static_assert(offsetof(__wasi_subscription_clock_t, flags) == 24, "witx calculated offset"); - -/** - * The contents of a `subscription` when type is type is - * `eventtype::fd_read` or `eventtype::fd_write`. - */ -typedef struct __wasi_subscription_fd_readwrite_t { - /** - * The file descriptor on which to wait for it to become ready for reading or writing. - */ - __wasi_fd_t fd; - -} __wasi_subscription_fd_readwrite_t; - -_Static_assert(sizeof(__wasi_subscription_fd_readwrite_t) == 4, "witx calculated size"); -_Static_assert(_Alignof(__wasi_subscription_fd_readwrite_t) == 4, "witx calculated align"); -_Static_assert(offsetof(__wasi_subscription_fd_readwrite_t, fd) == 0, "witx calculated offset"); - -/** - * The contents of a `subscription`. - */ -typedef union __wasi_subscription_u_u_t { - __wasi_subscription_clock_t clock; - __wasi_subscription_fd_readwrite_t fd_readwrite; -} __wasi_subscription_u_u_t ; - -typedef struct __wasi_subscription_u_t { - __wasi_eventtype_t type; - __wasi_subscription_u_u_t u; -} __wasi_subscription_u_t __attribute__((aligned(8))); - -_Static_assert(sizeof(__wasi_subscription_u_t) == 40, "witx calculated size"); -_Static_assert(_Alignof(__wasi_subscription_u_t) == 8, "witx calculated align"); -_Static_assert(offsetof(__wasi_subscription_u_t, u) == 8, "witx calculated union offset"); -_Static_assert(sizeof(__wasi_subscription_u_u_t) == 32, "witx calculated union size"); -_Static_assert(_Alignof(__wasi_subscription_u_u_t) == 8, "witx calculated union align"); - -/** - * Subscription to an event. - */ -typedef struct __wasi_subscription_t { - /** - * User-provided value that is attached to the subscription in the - * implementation and returned through `event::userdata`. - */ - __wasi_userdata_t userdata; - - /** - * The type of the event to which to subscribe, and its contents - */ - __wasi_subscription_u_t u; - -} __wasi_subscription_t; - -_Static_assert(sizeof(__wasi_subscription_t) == 48, "witx calculated size"); -_Static_assert(_Alignof(__wasi_subscription_t) == 8, "witx calculated align"); -_Static_assert(offsetof(__wasi_subscription_t, userdata) == 0, "witx calculated offset"); -_Static_assert(offsetof(__wasi_subscription_t, u) == 8, "witx calculated offset"); - -/* keep syncing with wasi_socket_ext.h */ -typedef enum { - /* Used only for sock_addr_resolve hints */ - SOCKET_ANY = -1, - SOCKET_DGRAM = 0, - SOCKET_STREAM, -} __wasi_sock_type_t; - -typedef uint16_t __wasi_ip_port_t; - -typedef enum { IPv4 = 0, IPv6 } __wasi_addr_type_t; - -/* n0.n1.n2.n3 */ -typedef struct __wasi_addr_ip4_t { - uint8_t n0; - uint8_t n1; - uint8_t n2; - uint8_t n3; -} __wasi_addr_ip4_t; - -typedef struct __wasi_addr_ip4_port_t { - __wasi_addr_ip4_t addr; - __wasi_ip_port_t port; -} __wasi_addr_ip4_port_t; - -typedef struct __wasi_addr_ip6_t { - uint16_t n0; - uint16_t n1; - uint16_t n2; - uint16_t n3; - uint16_t h0; - uint16_t h1; - uint16_t h2; - uint16_t h3; -} __wasi_addr_ip6_t; - -typedef struct __wasi_addr_ip6_port_t { - __wasi_addr_ip6_t addr; - __wasi_ip_port_t port; -} __wasi_addr_ip6_port_t; - -typedef struct __wasi_addr_ip_t { - __wasi_addr_type_t kind; - union { - __wasi_addr_ip4_t ip4; - __wasi_addr_ip6_t ip6; - } addr; -} __wasi_addr_ip_t; - -typedef struct __wasi_addr_t { - __wasi_addr_type_t kind; - union { - __wasi_addr_ip4_port_t ip4; - __wasi_addr_ip6_port_t ip6; - } addr; -} __wasi_addr_t; - -typedef enum { INET4 = 0, INET6, INET_UNSPEC } __wasi_address_family_t; - -typedef struct __wasi_addr_info_t { - __wasi_addr_t addr; - __wasi_sock_type_t type; -} __wasi_addr_info_t; - -typedef struct __wasi_addr_info_hints_t { - __wasi_sock_type_t type; - __wasi_address_family_t family; - // this is to workaround lack of optional parameters - uint8_t hints_enabled; -} __wasi_addr_info_hints_t; - #if defined(WASMTIME_SSP_WASI_API) -#define WASMTIME_SSP_SYSCALL_NAME(name) \ - asm("__wasi_" #name) +#define WASMTIME_SSP_SYSCALL_NAME(name) asm("__wasi_" #name) #else #define WASMTIME_SSP_SYSCALL_NAME(name) #endif -__wasi_errno_t wasmtime_ssp_args_get( - struct argv_environ_values *arg_environ, - char **argv, - char *argv_buf -) WASMTIME_SSP_SYSCALL_NAME(args_get) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_args_sizes_get( - struct argv_environ_values *arg_environ, - size_t *argc, - size_t *argv_buf_size -) WASMTIME_SSP_SYSCALL_NAME(args_sizes_get) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_clock_res_get( - __wasi_clockid_t clock_id, - __wasi_timestamp_t *resolution -) WASMTIME_SSP_SYSCALL_NAME(clock_res_get) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_clock_time_get( - __wasi_clockid_t clock_id, - __wasi_timestamp_t precision, - __wasi_timestamp_t *time -) WASMTIME_SSP_SYSCALL_NAME(clock_time_get) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_environ_get( - struct argv_environ_values *arg_environ, - char **environ, - char *environ_buf -) WASMTIME_SSP_SYSCALL_NAME(environ_get) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_environ_sizes_get( - struct argv_environ_values *arg_environ, - size_t *environ_count, - size_t *environ_buf_size -) WASMTIME_SSP_SYSCALL_NAME(environ_sizes_get) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_prestat_get( - struct fd_prestats *prestats, - __wasi_fd_t fd, - __wasi_prestat_t *buf -) WASMTIME_SSP_SYSCALL_NAME(fd_prestat_get) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_prestat_dir_name( - struct fd_prestats *prestats, - __wasi_fd_t fd, - char *path, - size_t path_len -) WASMTIME_SSP_SYSCALL_NAME(fd_prestat_dir_name) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_close( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - struct fd_prestats *prestats, - __wasi_fd_t fd -) WASMTIME_SSP_SYSCALL_NAME(fd_close) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_datasync( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd -) WASMTIME_SSP_SYSCALL_NAME(fd_datasync) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_pread( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - const __wasi_iovec_t *iovs, - size_t iovs_len, - __wasi_filesize_t offset, - size_t *nread -) WASMTIME_SSP_SYSCALL_NAME(fd_pread) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_pwrite( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - const __wasi_ciovec_t *iovs, - size_t iovs_len, - __wasi_filesize_t offset, - size_t *nwritten -) WASMTIME_SSP_SYSCALL_NAME(fd_pwrite) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_read( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - const __wasi_iovec_t *iovs, - size_t iovs_len, - size_t *nread -) WASMTIME_SSP_SYSCALL_NAME(fd_read) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_renumber( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - struct fd_prestats *prestats, - __wasi_fd_t from, - __wasi_fd_t to -) WASMTIME_SSP_SYSCALL_NAME(fd_renumber) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_seek( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - __wasi_filedelta_t offset, - __wasi_whence_t whence, - __wasi_filesize_t *newoffset -) WASMTIME_SSP_SYSCALL_NAME(fd_seek) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_tell( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - __wasi_filesize_t *newoffset -) WASMTIME_SSP_SYSCALL_NAME(fd_tell) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_fdstat_get( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - __wasi_fdstat_t *buf -) WASMTIME_SSP_SYSCALL_NAME(fd_fdstat_get) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_fdstat_set_flags( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - __wasi_fdflags_t flags -) WASMTIME_SSP_SYSCALL_NAME(fd_fdstat_set_flags) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_fdstat_set_rights( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - __wasi_rights_t fs_rights_base, - __wasi_rights_t fs_rights_inheriting -) WASMTIME_SSP_SYSCALL_NAME(fd_fdstat_set_rights) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_sync( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd -) WASMTIME_SSP_SYSCALL_NAME(fd_sync) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_write( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - const __wasi_ciovec_t *iovs, - size_t iovs_len, - size_t *nwritten -) WASMTIME_SSP_SYSCALL_NAME(fd_write) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_advise( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - __wasi_filesize_t offset, - __wasi_filesize_t len, - __wasi_advice_t advice -) WASMTIME_SSP_SYSCALL_NAME(fd_advise) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_allocate( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - __wasi_filesize_t offset, - __wasi_filesize_t len -) WASMTIME_SSP_SYSCALL_NAME(fd_allocate) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_path_create_directory( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - const char *path, - size_t path_len -) WASMTIME_SSP_SYSCALL_NAME(path_create_directory) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_path_link( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - struct fd_prestats *prestats, - __wasi_fd_t old_fd, - __wasi_lookupflags_t old_flags, - const char *old_path, - size_t old_path_len, - __wasi_fd_t new_fd, - const char *new_path, - size_t new_path_len -) WASMTIME_SSP_SYSCALL_NAME(path_link) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_path_open( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t dirfd, - __wasi_lookupflags_t dirflags, - const char *path, - size_t path_len, - __wasi_oflags_t oflags, - __wasi_rights_t fs_rights_base, - __wasi_rights_t fs_rights_inheriting, - __wasi_fdflags_t fs_flags, - __wasi_fd_t *fd -) WASMTIME_SSP_SYSCALL_NAME(path_open) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_readdir( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - void *buf, - size_t buf_len, - __wasi_dircookie_t cookie, - size_t *bufused -) WASMTIME_SSP_SYSCALL_NAME(fd_readdir) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_path_readlink( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - const char *path, - size_t path_len, - char *buf, - size_t buf_len, - size_t *bufused -) WASMTIME_SSP_SYSCALL_NAME(path_readlink) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_path_rename( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t old_fd, - const char *old_path, - size_t old_path_len, - __wasi_fd_t new_fd, - const char *new_path, - size_t new_path_len -) WASMTIME_SSP_SYSCALL_NAME(path_rename) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_filestat_get( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - __wasi_filestat_t *buf -) WASMTIME_SSP_SYSCALL_NAME(fd_filestat_get) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_filestat_set_times( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - __wasi_timestamp_t st_atim, - __wasi_timestamp_t st_mtim, - __wasi_fstflags_t fstflags -) WASMTIME_SSP_SYSCALL_NAME(fd_filestat_set_times) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_filestat_set_size( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - __wasi_filesize_t st_size -) WASMTIME_SSP_SYSCALL_NAME(fd_filestat_set_size) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_path_filestat_get( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - __wasi_lookupflags_t flags, - const char *path, - size_t path_len, - __wasi_filestat_t *buf -) WASMTIME_SSP_SYSCALL_NAME(path_filestat_get) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_path_filestat_set_times( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - __wasi_lookupflags_t flags, - const char *path, - size_t path_len, - __wasi_timestamp_t st_atim, - __wasi_timestamp_t st_mtim, - __wasi_fstflags_t fstflags -) WASMTIME_SSP_SYSCALL_NAME(path_filestat_set_times) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_path_symlink( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - struct fd_prestats *prestats, - const char *old_path, - size_t old_path_len, - __wasi_fd_t fd, - const char *new_path, - size_t new_path_len -) WASMTIME_SSP_SYSCALL_NAME(path_symlink) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_path_unlink_file( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - const char *path, - size_t path_len -) WASMTIME_SSP_SYSCALL_NAME(path_unlink_file) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_path_remove_directory( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - const char *path, - size_t path_len -) WASMTIME_SSP_SYSCALL_NAME(path_remove_directory) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_poll_oneoff( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - const __wasi_subscription_t *in, - __wasi_event_t *out, - size_t nsubscriptions, - size_t *nevents -) WASMTIME_SSP_SYSCALL_NAME(poll_oneoff) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_random_get( - void *buf, - size_t buf_len -) WASMTIME_SSP_SYSCALL_NAME(random_get) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_args_get(struct argv_environ_values *arg_environ, char **argv, + char *argv_buf) + WASMTIME_SSP_SYSCALL_NAME(args_get) WARN_UNUSED; __wasi_errno_t -wasi_ssp_sock_accept( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, __wasi_fdflags_t flags, __wasi_fd_t *fd_new -) __attribute__((__warn_unused_result__)); +wasmtime_ssp_args_sizes_get(struct argv_environ_values *arg_environ, + size_t *argc, size_t *argv_buf_size) + WASMTIME_SSP_SYSCALL_NAME(args_sizes_get) WARN_UNUSED; __wasi_errno_t -wasi_ssp_sock_addr_local( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, __wasi_addr_t *addr -) __attribute__((__warn_unused_result__)); +wasmtime_ssp_environ_get(struct argv_environ_values *arg_environ, + char **environs, char *environ_buf) + WASMTIME_SSP_SYSCALL_NAME(environ_get) WARN_UNUSED; __wasi_errno_t -wasi_ssp_sock_addr_remote( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, __wasi_addr_t *addr -) __attribute__((__warn_unused_result__)); +wasmtime_ssp_environ_sizes_get(struct argv_environ_values *arg_environ, + size_t *environ_count, size_t *environ_buf_size) + WASMTIME_SSP_SYSCALL_NAME(environ_sizes_get) WARN_UNUSED; __wasi_errno_t -wasi_ssp_sock_open( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t poolfd, __wasi_address_family_t af, __wasi_sock_type_t socktype, - __wasi_fd_t *sockfd -) __attribute__((__warn_unused_result__)); +wasmtime_ssp_fd_prestat_get(struct fd_prestats *prestats, __wasi_fd_t fd, + __wasi_prestat_t *buf) + WASMTIME_SSP_SYSCALL_NAME(fd_prestat_get) WARN_UNUSED; __wasi_errno_t -wasi_ssp_sock_bind( - wasm_exec_env_t exec_env, - struct fd_table *curfds, struct addr_pool *addr_pool, - __wasi_fd_t fd, __wasi_addr_t *addr -) __attribute__((__warn_unused_result__)); +wasmtime_ssp_fd_prestat_dir_name(struct fd_prestats *prestats, __wasi_fd_t fd, + char *path, size_t path_len) + WASMTIME_SSP_SYSCALL_NAME(fd_prestat_dir_name) WARN_UNUSED; __wasi_errno_t -wasi_ssp_sock_addr_resolve( - wasm_exec_env_t exec_env, - struct fd_table *curfds, char **ns_lookup_list, - const char *host, const char* service, - __wasi_addr_info_hints_t *hints, __wasi_addr_info_t *addr_info, - __wasi_size_t addr_info_size, __wasi_size_t *max_info_size -) __attribute__((__warn_unused_result__)); +wasmtime_ssp_fd_close(wasm_exec_env_t exec_env, struct fd_table *curfds, + struct fd_prestats *prestats, __wasi_fd_t fd) + WASMTIME_SSP_SYSCALL_NAME(fd_close) WARN_UNUSED; __wasi_errno_t -wasi_ssp_sock_connect( - wasm_exec_env_t exec_env, - struct fd_table *curfds, struct addr_pool *addr_pool, - __wasi_fd_t fd, __wasi_addr_t *addr -) __attribute__((__warn_unused_result__)); +wasmtime_ssp_fd_datasync(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd) + WASMTIME_SSP_SYSCALL_NAME(fd_datasync) WARN_UNUSED; __wasi_errno_t -wasi_ssp_sock_get_recv_buf_size( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, __wasi_size_t *size -) __attribute__((__warn_unused_result__)); +wasmtime_ssp_fd_pread(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, const __wasi_iovec_t *iovs, + size_t iovs_len, __wasi_filesize_t offset, size_t *nread) + WASMTIME_SSP_SYSCALL_NAME(fd_pread) WARN_UNUSED; __wasi_errno_t -wasi_ssp_sock_get_reuse_addr( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, uint8_t *reuse -) __attribute__((__warn_unused_result__)); +wasmtime_ssp_fd_pwrite(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, const __wasi_ciovec_t *iovs, + size_t iovs_len, __wasi_filesize_t offset, + size_t *nwritten) + WASMTIME_SSP_SYSCALL_NAME(fd_pwrite) WARN_UNUSED; __wasi_errno_t -wasi_ssp_sock_get_reuse_port( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, uint8_t *reuse -) __attribute__((__warn_unused_result__)); +wasmtime_ssp_fd_read(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, const __wasi_iovec_t *iovs, + size_t iovs_len, size_t *nread) + WASMTIME_SSP_SYSCALL_NAME(fd_read) WARN_UNUSED; __wasi_errno_t -wasi_ssp_sock_get_send_buf_size( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, __wasi_size_t *size -) __attribute__((__warn_unused_result__)); +wasmtime_ssp_fd_renumber(wasm_exec_env_t exec_env, struct fd_table *curfds, + struct fd_prestats *prestats, __wasi_fd_t from, + __wasi_fd_t to) + WASMTIME_SSP_SYSCALL_NAME(fd_renumber) WARN_UNUSED; __wasi_errno_t -wasi_ssp_sock_set_recv_buf_size( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, __wasi_size_t size -) __attribute__((__warn_unused_result__)); +wasmtime_ssp_fd_seek(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, __wasi_filedelta_t offset, + __wasi_whence_t whence, __wasi_filesize_t *newoffset) + WASMTIME_SSP_SYSCALL_NAME(fd_seek) WARN_UNUSED; __wasi_errno_t -wasi_ssp_sock_set_reuse_addr( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, uint8_t reuse -) __attribute__((__warn_unused_result__)); +wasmtime_ssp_fd_tell(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, __wasi_filesize_t *newoffset) + WASMTIME_SSP_SYSCALL_NAME(fd_tell) WARN_UNUSED; __wasi_errno_t -wasi_ssp_sock_set_reuse_port( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, uint8_t reuse -) __attribute__((__warn_unused_result__)); +wasmtime_ssp_fd_fdstat_get(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, __wasi_fdstat_t *buf) + WASMTIME_SSP_SYSCALL_NAME(fd_fdstat_get) WARN_UNUSED; __wasi_errno_t -wasi_ssp_sock_set_send_buf_size( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, __wasi_size_t size -) __attribute__((__warn_unused_result__)); +wasmtime_ssp_fd_fdstat_set_flags(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t fd, + __wasi_fdflags_t flags) + WASMTIME_SSP_SYSCALL_NAME(fd_fdstat_set_flags) WARN_UNUSED; __wasi_errno_t -wasi_ssp_sock_listen( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, __wasi_size_t backlog -) __attribute__((__warn_unused_result__)); +wasmtime_ssp_fd_fdstat_set_rights(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t fd, + __wasi_rights_t fs_rights_base, + __wasi_rights_t fs_rights_inheriting) + WASMTIME_SSP_SYSCALL_NAME(fd_fdstat_set_rights) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_recv( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - void *buf, - size_t buf_len, - size_t *recv_len -) WASMTIME_SSP_SYSCALL_NAME(sock_recv) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_fd_sync(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd) + WASMTIME_SSP_SYSCALL_NAME(fd_sync) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_recv_from( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - void *buf, - size_t buf_len, - __wasi_riflags_t ri_flags, - __wasi_addr_t *src_addr, - size_t *recv_len -) WASMTIME_SSP_SYSCALL_NAME(sock_recv_from) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_fd_write(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, const __wasi_ciovec_t *iovs, + size_t iovs_len, size_t *nwritten) + WASMTIME_SSP_SYSCALL_NAME(fd_write) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_send( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - const void *buf, - size_t buf_len, - size_t *sent_len -) WASMTIME_SSP_SYSCALL_NAME(sock_send) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_fd_advise(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, __wasi_filesize_t offset, + __wasi_filesize_t len, __wasi_advice_t advice) + WASMTIME_SSP_SYSCALL_NAME(fd_advise) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_send_to( - wasm_exec_env_t exec_env, - struct fd_table *curfds, struct addr_pool *addr_pool, - __wasi_fd_t sock, - const void *buf, - size_t buf_len, - __wasi_siflags_t si_flags, - const __wasi_addr_t *dest_addr, - size_t *sent_len -) WASMTIME_SSP_SYSCALL_NAME(sock_send_to) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_fd_allocate(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, __wasi_filesize_t offset, + __wasi_filesize_t len) + WASMTIME_SSP_SYSCALL_NAME(fd_allocate) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_shutdown( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock -) WASMTIME_SSP_SYSCALL_NAME(sock_shutdown) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_path_create_directory(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t fd, + const char *path, size_t path_len) + WASMTIME_SSP_SYSCALL_NAME(path_create_directory) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_recv_timeout( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - uint64_t timeout_us -) WASMTIME_SSP_SYSCALL_NAME(sock_set_recv_timeout) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_path_link(wasm_exec_env_t exec_env, struct fd_table *curfds, + struct fd_prestats *prestats, __wasi_fd_t old_fd, + __wasi_lookupflags_t old_flags, const char *old_path, + size_t old_path_len, __wasi_fd_t new_fd, + const char *new_path, size_t new_path_len) + WASMTIME_SSP_SYSCALL_NAME(path_link) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_get_recv_timeout( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - uint64_t *timeout_us -) WASMTIME_SSP_SYSCALL_NAME(sock_get_recv_timeout) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_path_open(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t dirfd, __wasi_lookupflags_t dirflags, + const char *path, size_t path_len, + __wasi_oflags_t oflags, __wasi_rights_t fs_rights_base, + __wasi_rights_t fs_rights_inheriting, + __wasi_fdflags_t fs_flags, __wasi_fd_t *fd) + WASMTIME_SSP_SYSCALL_NAME(path_open) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_send_timeout( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - uint64_t timeout_us -) WASMTIME_SSP_SYSCALL_NAME(sock_set_send_timeout) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_fd_readdir(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, void *buf, size_t buf_len, + __wasi_dircookie_t cookie, size_t *bufused) + WASMTIME_SSP_SYSCALL_NAME(fd_readdir) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_get_send_timeout( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - uint64_t *timeout_us -) WASMTIME_SSP_SYSCALL_NAME(sock_get_send_timeout) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_path_readlink(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, const char *path, size_t path_len, + char *buf, size_t buf_len, size_t *bufused) + WASMTIME_SSP_SYSCALL_NAME(path_readlink) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_send_buf_size( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - size_t bufsiz -) WASMTIME_SSP_SYSCALL_NAME(sock_set_send_buf_size) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_path_rename(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t old_fd, const char *old_path, + size_t old_path_len, __wasi_fd_t new_fd, + const char *new_path, size_t new_path_len) + WASMTIME_SSP_SYSCALL_NAME(path_rename) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_get_send_buf_size( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - size_t *bufsiz -) WASMTIME_SSP_SYSCALL_NAME(sock_get_send_buf_size) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_fd_filestat_get(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, __wasi_filestat_t *buf) + WASMTIME_SSP_SYSCALL_NAME(fd_filestat_get) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_recv_buf_size( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - size_t bufsiz -) WASMTIME_SSP_SYSCALL_NAME(sock_set_recv_buf_size) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_fd_filestat_set_times(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t fd, + __wasi_timestamp_t st_atim, + __wasi_timestamp_t st_mtim, + __wasi_fstflags_t fstflags) + WASMTIME_SSP_SYSCALL_NAME(fd_filestat_set_times) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_get_recv_buf_size( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - size_t *bufsiz -) WASMTIME_SSP_SYSCALL_NAME(sock_get_recv_buf_size) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_fd_filestat_set_size(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t fd, + __wasi_filesize_t st_size) + WASMTIME_SSP_SYSCALL_NAME(fd_filestat_set_size) WARN_UNUSED; +__wasi_errno_t +wasmtime_ssp_path_filestat_get(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t fd, + __wasi_lookupflags_t flags, const char *path, + size_t path_len, __wasi_filestat_t *buf) + WASMTIME_SSP_SYSCALL_NAME(path_filestat_get) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_keep_alive( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - bool is_enabled -) WASMTIME_SSP_SYSCALL_NAME(sock_set_keep_alive) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_path_filestat_set_times(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t fd, + __wasi_lookupflags_t flags, + const char *path, size_t path_len, + __wasi_timestamp_t st_atim, + __wasi_timestamp_t st_mtim, + __wasi_fstflags_t fstflags) + WASMTIME_SSP_SYSCALL_NAME(path_filestat_set_times) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_get_keep_alive( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - bool *is_enabled -) WASMTIME_SSP_SYSCALL_NAME(sock_get_keep_alive) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_path_symlink(wasm_exec_env_t exec_env, struct fd_table *curfds, + struct fd_prestats *prestats, const char *old_path, + size_t old_path_len, __wasi_fd_t fd, + const char *new_path, size_t new_path_len) + WASMTIME_SSP_SYSCALL_NAME(path_symlink) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_reuse_addr( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - bool is_enabled -) WASMTIME_SSP_SYSCALL_NAME(sock_set_reuse_addr) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_path_unlink_file(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, const char *path, size_t path_len) + WASMTIME_SSP_SYSCALL_NAME(path_unlink_file) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_get_reuse_addr( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - bool *is_enabled -) WASMTIME_SSP_SYSCALL_NAME(sock_get_reuse_addr) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_path_remove_directory(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t fd, + const char *path, size_t path_len) + WASMTIME_SSP_SYSCALL_NAME(path_remove_directory) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_reuse_port( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - bool is_enabled -) WASMTIME_SSP_SYSCALL_NAME(sock_set_reuse_port) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_poll_oneoff(wasm_exec_env_t exec_env, struct fd_table *curfds, + const __wasi_subscription_t *in, __wasi_event_t *out, + size_t nsubscriptions, size_t *nevents) + WASMTIME_SSP_SYSCALL_NAME(poll_oneoff) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_get_reuse_port( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - bool *is_enabled -) WASMTIME_SSP_SYSCALL_NAME(sock_get_reuse_port) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_random_get(void *buf, size_t buf_len) + WASMTIME_SSP_SYSCALL_NAME(random_get) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_linger( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - bool is_enabled, - int linger_s -) WASMTIME_SSP_SYSCALL_NAME(sock_set_linger) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasi_ssp_sock_accept(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, __wasi_fdflags_t flags, + __wasi_fd_t *fd_new) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_get_linger( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, bool *is_enabled, int *linger_s -) WASMTIME_SSP_SYSCALL_NAME(sock_get_linger) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasi_ssp_sock_addr_local(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, __wasi_addr_t *addr) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_broadcast( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - bool is_enabled -) WASMTIME_SSP_SYSCALL_NAME(sock_set_broadcast) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasi_ssp_sock_addr_remote(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, __wasi_addr_t *addr) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_get_broadcast( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - bool *is_enabled -) WASMTIME_SSP_SYSCALL_NAME(sock_get_broadcast) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasi_ssp_sock_open(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t poolfd, __wasi_address_family_t af, + __wasi_sock_type_t socktype, + __wasi_fd_t *sockfd) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_tcp_no_delay( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - bool is_enabled -) WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_no_delay) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasi_ssp_sock_bind(wasm_exec_env_t exec_env, struct fd_table *curfds, + struct addr_pool *addr_pool, __wasi_fd_t fd, + __wasi_addr_t *addr) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_get_tcp_no_delay( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - bool *is_enabled -) WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_no_delay) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasi_ssp_sock_addr_resolve(wasm_exec_env_t exec_env, struct fd_table *curfds, + char **ns_lookup_list, const char *host, + const char *service, __wasi_addr_info_hints_t *hints, + __wasi_addr_info_t *addr_info, + __wasi_size_t addr_info_size, + __wasi_size_t *max_info_size) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_tcp_quick_ack( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - bool is_enabled -) WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_quick_ack) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasi_ssp_sock_connect(wasm_exec_env_t exec_env, struct fd_table *curfds, + struct addr_pool *addr_pool, __wasi_fd_t fd, + __wasi_addr_t *addr) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_get_tcp_quick_ack( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - bool *is_enabled -) WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_quick_ack) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasi_ssp_sock_get_recv_buf_size(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t fd, + __wasi_size_t *size) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_tcp_keep_idle( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - uint32_t time_s -) WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_keep_idle) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasi_ssp_sock_get_reuse_addr(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, uint8_t *reuse) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_get_tcp_keep_idle( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - uint32_t *time_s -) WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_keep_idle) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasi_ssp_sock_get_reuse_port(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, uint8_t *reuse) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_tcp_keep_intvl( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - uint32_t time_s -) WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_keep_intvl) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasi_ssp_sock_get_send_buf_size(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t fd, + __wasi_size_t *size) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_get_tcp_keep_intvl( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - uint32_t *time_s -) WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_keep_intvl) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasi_ssp_sock_set_recv_buf_size(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t fd, + __wasi_size_t size) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_tcp_fastopen_connect( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - bool is_enabled -) WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_fastopen_connect) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasi_ssp_sock_set_reuse_addr(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, uint8_t reuse) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_get_tcp_fastopen_connect( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - bool *is_enabled -) WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_fastopen_connect) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasi_ssp_sock_set_reuse_port(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, uint8_t reuse) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_ip_multicast_loop( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - bool ipv6, - bool is_enabled -) WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_multicast_loop) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasi_ssp_sock_set_send_buf_size(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t fd, + __wasi_size_t size) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_get_ip_multicast_loop( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - bool ipv6, - bool *is_enabled -) WASMTIME_SSP_SYSCALL_NAME(sock_get_ip_multicast_loop) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasi_ssp_sock_listen(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, __wasi_size_t backlog) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_ip_add_membership( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - __wasi_addr_ip_t *imr_multiaddr, - uint32_t imr_interface -) WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_add_membership) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_sock_recv(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t sock, void *buf, size_t buf_len, + size_t *recv_len) + WASMTIME_SSP_SYSCALL_NAME(sock_recv) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_ip_drop_membership( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - __wasi_addr_ip_t *imr_multiaddr, - uint32_t imr_interface -) WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_drop_membership) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_sock_recv_from(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t sock, void *buf, size_t buf_len, + __wasi_riflags_t ri_flags, __wasi_addr_t *src_addr, + size_t *recv_len) + WASMTIME_SSP_SYSCALL_NAME(sock_recv_from) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_ip_ttl( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - uint8_t ttl_s -) WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_ttl) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_sock_send(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t sock, const void *buf, size_t buf_len, + size_t *sent_len) + WASMTIME_SSP_SYSCALL_NAME(sock_send) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_get_ip_ttl( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - uint8_t *ttl_s -) WASMTIME_SSP_SYSCALL_NAME(sock_get_ip_ttl) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_sock_send_to(wasm_exec_env_t exec_env, struct fd_table *curfds, + struct addr_pool *addr_pool, __wasi_fd_t sock, + const void *buf, size_t buf_len, + __wasi_siflags_t si_flags, + const __wasi_addr_t *dest_addr, size_t *sent_len) + WASMTIME_SSP_SYSCALL_NAME(sock_send_to) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_ip_multicast_ttl( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - uint8_t ttl_s -) WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_multicast_ttl) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_sock_shutdown(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t sock) + WASMTIME_SSP_SYSCALL_NAME(sock_shutdown) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_get_ip_multicast_ttl( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - uint8_t *ttl_s -) WASMTIME_SSP_SYSCALL_NAME(sock_get_ip_multicast_ttl) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_sock_set_recv_timeout(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + uint64_t timeout_us) + WASMTIME_SSP_SYSCALL_NAME(sock_set_recv_timeout) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_ipv6_only( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - bool is_enabled -) WASMTIME_SSP_SYSCALL_NAME(sock_set_ipv6_only) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_sock_get_recv_timeout(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + uint64_t *timeout_us) + WASMTIME_SSP_SYSCALL_NAME(sock_get_recv_timeout) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_get_ipv6_only( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - bool *is_enabled -) WASMTIME_SSP_SYSCALL_NAME(sock_get_ipv6_only) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_sock_set_send_timeout(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + uint64_t timeout_us) + WASMTIME_SSP_SYSCALL_NAME(sock_set_send_timeout) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sched_yield(void) - WASMTIME_SSP_SYSCALL_NAME(sched_yield) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_sock_get_send_timeout(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + uint64_t *timeout_us) + WASMTIME_SSP_SYSCALL_NAME(sock_get_send_timeout) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_set_send_buf_size(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + size_t bufsiz) + WASMTIME_SSP_SYSCALL_NAME(sock_set_send_buf_size) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_get_send_buf_size(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + size_t *bufsiz) + WASMTIME_SSP_SYSCALL_NAME(sock_get_send_buf_size) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_set_recv_buf_size(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + size_t bufsiz) + WASMTIME_SSP_SYSCALL_NAME(sock_set_recv_buf_size) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_get_recv_buf_size(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + size_t *bufsiz) + WASMTIME_SSP_SYSCALL_NAME(sock_get_recv_buf_size) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_set_keep_alive(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + bool is_enabled) + WASMTIME_SSP_SYSCALL_NAME(sock_set_keep_alive) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_get_keep_alive(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + bool *is_enabled) + WASMTIME_SSP_SYSCALL_NAME(sock_get_keep_alive) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_set_reuse_addr(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + bool is_enabled) + WASMTIME_SSP_SYSCALL_NAME(sock_set_reuse_addr) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_get_reuse_addr(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + bool *is_enabled) + WASMTIME_SSP_SYSCALL_NAME(sock_get_reuse_addr) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_set_reuse_port(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + bool is_enabled) + WASMTIME_SSP_SYSCALL_NAME(sock_set_reuse_port) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_get_reuse_port(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + bool *is_enabled) + WASMTIME_SSP_SYSCALL_NAME(sock_get_reuse_port) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_set_linger(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t sock, bool is_enabled, int linger_s) + WASMTIME_SSP_SYSCALL_NAME(sock_set_linger) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_get_linger(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t sock, bool *is_enabled, int *linger_s) + WASMTIME_SSP_SYSCALL_NAME(sock_get_linger) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_set_broadcast(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + bool is_enabled) + WASMTIME_SSP_SYSCALL_NAME(sock_set_broadcast) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_get_broadcast(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + bool *is_enabled) + WASMTIME_SSP_SYSCALL_NAME(sock_get_broadcast) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_set_tcp_no_delay(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + bool is_enabled) + WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_no_delay) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_get_tcp_no_delay(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + bool *is_enabled) + WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_no_delay) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_set_tcp_quick_ack(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + bool is_enabled) + WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_quick_ack) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_get_tcp_quick_ack(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + bool *is_enabled) + WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_quick_ack) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_set_tcp_keep_idle(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + uint32_t time_s) + WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_keep_idle) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_get_tcp_keep_idle(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + uint32_t *time_s) + WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_keep_idle) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_set_tcp_keep_intvl(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + uint32_t time_s) + WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_keep_intvl) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_get_tcp_keep_intvl(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + uint32_t *time_s) + WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_keep_intvl) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_set_tcp_fastopen_connect(wasm_exec_env_t exec_env, + struct fd_table *curfds, + __wasi_fd_t sock, bool is_enabled) + WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_fastopen_connect) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_get_tcp_fastopen_connect(wasm_exec_env_t exec_env, + struct fd_table *curfds, + __wasi_fd_t sock, bool *is_enabled) + WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_fastopen_connect) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_set_ip_multicast_loop(wasm_exec_env_t exec_env, + struct fd_table *curfds, + __wasi_fd_t sock, bool ipv6, + bool is_enabled) + WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_multicast_loop) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_get_ip_multicast_loop(wasm_exec_env_t exec_env, + struct fd_table *curfds, + __wasi_fd_t sock, bool ipv6, + bool *is_enabled) + WASMTIME_SSP_SYSCALL_NAME(sock_get_ip_multicast_loop) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_set_ip_add_membership(wasm_exec_env_t exec_env, + struct fd_table *curfds, + __wasi_fd_t sock, + __wasi_addr_ip_t *imr_multiaddr, + uint32_t imr_interface) + WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_add_membership) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_set_ip_drop_membership(wasm_exec_env_t exec_env, + struct fd_table *curfds, + __wasi_fd_t sock, + __wasi_addr_ip_t *imr_multiaddr, + uint32_t imr_interface) + WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_drop_membership) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_set_ip_ttl(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t sock, uint8_t ttl_s) + WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_ttl) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_get_ip_ttl(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t sock, uint8_t *ttl_s) + WASMTIME_SSP_SYSCALL_NAME(sock_get_ip_ttl) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_set_ip_multicast_ttl(wasm_exec_env_t exec_env, + struct fd_table *curfds, + __wasi_fd_t sock, uint8_t ttl_s) + WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_multicast_ttl) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_get_ip_multicast_ttl(wasm_exec_env_t exec_env, + struct fd_table *curfds, + __wasi_fd_t sock, uint8_t *ttl_s) + WASMTIME_SSP_SYSCALL_NAME(sock_get_ip_multicast_ttl) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_set_ipv6_only(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + bool is_enabled) + WASMTIME_SSP_SYSCALL_NAME(sock_set_ipv6_only) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_get_ipv6_only(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + bool *is_enabled) + WASMTIME_SSP_SYSCALL_NAME(sock_get_ipv6_only) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sched_yield(void) + WASMTIME_SSP_SYSCALL_NAME(sched_yield) WARN_UNUSED; #ifdef __cplusplus } @@ -1361,6 +603,4 @@ __wasi_errno_t wasmtime_ssp_sched_yield(void) #undef WASMTIME_SSP_SYSCALL_NAME -/* clang-format on */ - #endif /* end of WASMTIME_SSP_H */ diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/blocking_op.c b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/blocking_op.c index 9d01f2bfe..ec1481c2e 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/blocking_op.c +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/blocking_op.c @@ -8,99 +8,68 @@ #include "ssp_config.h" #include "blocking_op.h" -int -blocking_op_close(wasm_exec_env_t exec_env, int fd) +__wasi_errno_t +blocking_op_close(wasm_exec_env_t exec_env, os_file_handle handle, + bool is_stdio) { if (!wasm_runtime_begin_blocking_op(exec_env)) { - errno = EINTR; - return -1; + return __WASI_EINTR; } - int ret = close(fd); + __wasi_errno_t error = os_close(handle, is_stdio); + wasm_runtime_end_blocking_op(exec_env); + return error; +} + +__wasi_errno_t +blocking_op_readv(wasm_exec_env_t exec_env, os_file_handle handle, + const struct __wasi_iovec_t *iov, int iovcnt, size_t *nread) +{ + if (!wasm_runtime_begin_blocking_op(exec_env)) { + return __WASI_EINTR; + } + __wasi_errno_t error = os_readv(handle, iov, iovcnt, nread); + wasm_runtime_end_blocking_op(exec_env); + return error; +} + +__wasi_errno_t +blocking_op_preadv(wasm_exec_env_t exec_env, os_file_handle handle, + const struct __wasi_iovec_t *iov, int iovcnt, + __wasi_filesize_t offset, size_t *nread) +{ + if (!wasm_runtime_begin_blocking_op(exec_env)) { + return __WASI_EINTR; + } + __wasi_errno_t ret = os_preadv(handle, iov, iovcnt, offset, nread); wasm_runtime_end_blocking_op(exec_env); return ret; } -ssize_t -blocking_op_readv(wasm_exec_env_t exec_env, int fd, const struct iovec *iov, - int iovcnt) +__wasi_errno_t +blocking_op_writev(wasm_exec_env_t exec_env, os_file_handle handle, + const struct __wasi_ciovec_t *iov, int iovcnt, + size_t *nwritten) { if (!wasm_runtime_begin_blocking_op(exec_env)) { - errno = EINTR; - return -1; + return __WASI_EINTR; } - ssize_t ret = readv(fd, iov, iovcnt); + __wasi_errno_t error = os_writev(handle, iov, iovcnt, nwritten); wasm_runtime_end_blocking_op(exec_env); - return ret; + return error; } -#if CONFIG_HAS_PREADV -ssize_t -blocking_op_preadv(wasm_exec_env_t exec_env, int fd, const struct iovec *iov, - int iovcnt, off_t offset) +__wasi_errno_t +blocking_op_pwritev(wasm_exec_env_t exec_env, os_file_handle handle, + const struct __wasi_ciovec_t *iov, int iovcnt, + __wasi_filesize_t offset, size_t *nwritten) { if (!wasm_runtime_begin_blocking_op(exec_env)) { - errno = EINTR; - return -1; + return __WASI_EINTR; } - ssize_t ret = preadv(fd, iov, iovcnt, offset); + __wasi_errno_t error = os_pwritev(handle, iov, iovcnt, offset, nwritten); wasm_runtime_end_blocking_op(exec_env); - return ret; + return error; } -#else /* CONFIG_HAS_PREADV */ -ssize_t -blocking_op_pread(wasm_exec_env_t exec_env, int fd, void *p, size_t nb, - off_t offset) -{ - if (!wasm_runtime_begin_blocking_op(exec_env)) { - errno = EINTR; - return -1; - } - ssize_t ret = pread(fd, p, nb, offset); - wasm_runtime_end_blocking_op(exec_env); - return ret; -} -#endif /* CONFIG_HAS_PREADV */ - -ssize_t -blocking_op_writev(wasm_exec_env_t exec_env, int fd, const struct iovec *iov, - int iovcnt) -{ - if (!wasm_runtime_begin_blocking_op(exec_env)) { - errno = EINTR; - return -1; - } - ssize_t ret = writev(fd, iov, iovcnt); - wasm_runtime_end_blocking_op(exec_env); - return ret; -} - -#if CONFIG_HAS_PWRITEV -ssize_t -blocking_op_pwritev(wasm_exec_env_t exec_env, int fd, const struct iovec *iov, - int iovcnt, off_t offset) -{ - if (!wasm_runtime_begin_blocking_op(exec_env)) { - errno = EINTR; - return -1; - } - ssize_t ret = pwritev(fd, iov, iovcnt, offset); - wasm_runtime_end_blocking_op(exec_env); - return ret; -} -#else /* CONFIG_HAS_PWRITEV */ -ssize_t -blocking_op_pwrite(wasm_exec_env_t exec_env, int fd, const void *p, size_t nb, - off_t offset) -{ - if (!wasm_runtime_begin_blocking_op(exec_env)) { - errno = EINTR; - return -1; - } - ssize_t ret = pwrite(fd, p, nb, offset); - wasm_runtime_end_blocking_op(exec_env); - return ret; -} -#endif /* CONFIG_HAS_PWRITEV */ int blocking_op_socket_accept(wasm_exec_env_t exec_env, bh_socket_t server_sock, @@ -187,15 +156,17 @@ blocking_op_socket_addr_resolve(wasm_exec_env_t exec_env, const char *host, return ret; } -int -blocking_op_openat(wasm_exec_env_t exec_env, int fd, const char *path, - int oflags, mode_t mode) +__wasi_errno_t +blocking_op_openat(wasm_exec_env_t exec_env, os_file_handle handle, + const char *path, __wasi_oflags_t oflags, + __wasi_fdflags_t fd_flags, __wasi_lookupflags_t lookup_flags, + wasi_libc_file_access_mode access_mode, os_file_handle *out) { if (!wasm_runtime_begin_blocking_op(exec_env)) { - errno = EINTR; - return -1; + return __WASI_EINTR; } - int ret = openat(fd, path, oflags, mode); + __wasi_errno_t error = os_openat(handle, path, oflags, fd_flags, + lookup_flags, access_mode, out); wasm_runtime_end_blocking_op(exec_env); - return ret; + return error; } diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/blocking_op.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/blocking_op.h index 44a16d338..afaa4a4f0 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/blocking_op.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/blocking_op.h @@ -6,26 +6,24 @@ #include "bh_platform.h" #include "wasm_export.h" -int -blocking_op_close(wasm_exec_env_t exec_env, int fd); -ssize_t -blocking_op_readv(wasm_exec_env_t exec_env, int fd, const struct iovec *iov, - int iovcnt); -ssize_t -blocking_op_preadv(wasm_exec_env_t exec_env, int fd, const struct iovec *iov, - int iovcnt, off_t offset); -ssize_t -blocking_op_pread(wasm_exec_env_t exec_env, int fd, void *p, size_t nb, - off_t offset); -ssize_t -blocking_op_writev(wasm_exec_env_t exec_env, int fd, const struct iovec *iov, - int iovcnt); -ssize_t -blocking_op_pwritev(wasm_exec_env_t exec_env, int fd, const struct iovec *iov, - int iovcnt, off_t offset); -ssize_t -blocking_op_pwrite(wasm_exec_env_t exec_env, int fd, const void *p, size_t nb, - off_t offset); +__wasi_errno_t +blocking_op_close(wasm_exec_env_t exec_env, os_file_handle handle, + bool is_stdio); +__wasi_errno_t +blocking_op_readv(wasm_exec_env_t exec_env, os_file_handle handle, + const struct __wasi_iovec_t *iov, int iovcnt, size_t *nread); +__wasi_errno_t +blocking_op_preadv(wasm_exec_env_t exec_env, os_file_handle handle, + const struct __wasi_iovec_t *iov, int iovcnt, + __wasi_filesize_t offset, size_t *nread); +__wasi_errno_t +blocking_op_writev(wasm_exec_env_t exec_env, os_file_handle handle, + const struct __wasi_ciovec_t *iov, int iovcnt, + size_t *nwritten); +__wasi_errno_t +blocking_op_pwritev(wasm_exec_env_t exec_env, os_file_handle handle, + const struct __wasi_ciovec_t *iov, int iovcnt, + __wasi_filesize_t offset, size_t *nwritten); int blocking_op_socket_accept(wasm_exec_env_t exec_env, bh_socket_t server_sock, bh_socket_t *sockp, void *addr, @@ -47,6 +45,9 @@ blocking_op_socket_addr_resolve(wasm_exec_env_t exec_env, const char *host, uint8_t *hint_is_ipv4, bh_addr_info_t *addr_info, size_t addr_info_size, size_t *max_info_size); -int -blocking_op_openat(wasm_exec_env_t exec_env, int fd, const char *path, - int oflags, mode_t mode); + +__wasi_errno_t +blocking_op_openat(wasm_exec_env_t exec_env, os_file_handle handle, + const char *path, __wasi_oflags_t oflags, + __wasi_fdflags_t fd_flags, __wasi_lookupflags_t lookup_flags, + wasi_libc_file_access_mode access_mode, os_file_handle *out); \ No newline at end of file diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/locking.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/locking.h index 40b064b81..5e0778c3f 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/locking.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/locking.h @@ -49,7 +49,7 @@ /* Mutex that uses the lock annotations. */ struct LOCKABLE mutex { - pthread_mutex_t object; + korp_mutex object; }; /* clang-format off */ @@ -60,69 +60,71 @@ struct LOCKABLE mutex { static inline bool mutex_init(struct mutex *lock) REQUIRES_UNLOCKED(*lock) { - return pthread_mutex_init(&lock->object, NULL) == 0 ? true : false; + return os_mutex_init(&lock->object) == BHT_OK ? true : false; } static inline void mutex_destroy(struct mutex *lock) REQUIRES_UNLOCKED(*lock) { - pthread_mutex_destroy(&lock->object); + os_mutex_destroy(&lock->object); } static inline void mutex_lock(struct mutex *lock) LOCKS_EXCLUSIVE(*lock) NO_LOCK_ANALYSIS { - pthread_mutex_lock(&lock->object); + os_mutex_lock(&lock->object); } static inline void mutex_unlock(struct mutex *lock) UNLOCKS(*lock) NO_LOCK_ANALYSIS { - pthread_mutex_unlock(&lock->object); + os_mutex_unlock(&lock->object); } /* Read-write lock that uses the lock annotations. */ struct LOCKABLE rwlock { - pthread_rwlock_t object; + korp_rwlock object; }; static inline bool rwlock_init(struct rwlock *lock) REQUIRES_UNLOCKED(*lock) { - return pthread_rwlock_init(&lock->object, NULL) == 0 ? true : false; + return os_rwlock_init(&lock->object) == 0 ? true : false; } static inline void rwlock_rdlock(struct rwlock *lock) LOCKS_SHARED(*lock) NO_LOCK_ANALYSIS { - pthread_rwlock_rdlock(&lock->object); + os_rwlock_rdlock(&lock->object); } static inline void rwlock_wrlock(struct rwlock *lock) LOCKS_EXCLUSIVE(*lock) NO_LOCK_ANALYSIS { - pthread_rwlock_wrlock(&lock->object); + os_rwlock_wrlock(&lock->object); } static inline void rwlock_unlock(struct rwlock *lock) UNLOCKS(*lock) NO_LOCK_ANALYSIS { - pthread_rwlock_unlock(&lock->object); + os_rwlock_unlock(&lock->object); } static inline void rwlock_destroy(struct rwlock *lock) UNLOCKS(*lock) NO_LOCK_ANALYSIS { - pthread_rwlock_destroy(&lock->object); + os_rwlock_destroy(&lock->object); } /* Condition variable that uses the lock annotations. */ struct LOCKABLE cond { - pthread_cond_t object; -#if !CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK \ - || !CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP + korp_cond object; + +#if !CONFIG_HAS_CLOCK_NANOSLEEP \ + && (!CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK \ + || !CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP) clockid_t clock; #endif }; @@ -147,43 +149,49 @@ cond_init_monotonic(struct cond *cond) fail: pthread_condattr_destroy(&attr); #else - if (pthread_cond_init(&cond->object, NULL) != 0) + if (os_cond_init(&cond->object) != 0) return false; ret = true; #endif -#if !CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK \ - || !CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP +#if !CONFIG_HAS_CLOCK_NANOSLEEP \ + && (!CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK \ + || !CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP) cond->clock = CLOCK_MONOTONIC; #endif + return ret; } static inline bool cond_init_realtime(struct cond *cond) { - if (pthread_cond_init(&cond->object, NULL) != 0) + if (os_cond_init(&cond->object) != 0) return false; -#if !CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK \ - || !CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP + +#if !CONFIG_HAS_CLOCK_NANOSLEEP \ + && (!CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK \ + || !CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP) cond->clock = CLOCK_REALTIME; #endif + return true; } static inline void cond_destroy(struct cond *cond) { - pthread_cond_destroy(&cond->object); + os_cond_destroy(&cond->object); } static inline void cond_signal(struct cond *cond) { - pthread_cond_signal(&cond->object); + os_cond_signal(&cond->object); } #if !CONFIG_HAS_CLOCK_NANOSLEEP + static inline bool cond_timedwait(struct cond *cond, struct mutex *lock, uint64_t timeout, bool abstime) REQUIRES_EXCLUSIVE(*lock) NO_LOCK_ANALYSIS @@ -259,7 +267,7 @@ static inline void cond_wait(struct cond *cond, struct mutex *lock) REQUIRES_EXCLUSIVE(*lock) NO_LOCK_ANALYSIS { - pthread_cond_wait(&cond->object, &lock->object); + os_cond_wait(&cond->object, &lock->object); } #endif diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c index d5d181f8b..385aa15cf 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c @@ -15,6 +15,7 @@ #include "bh_platform.h" #include "blocking_op.h" #include "wasmtime_ssp.h" +#include "libc_errno.h" #include "locking.h" #include "posix.h" #include "random.h" @@ -22,6 +23,18 @@ #include "rights.h" #include "str.h" +/* Some platforms (e.g. Windows) already define `min()` macro. + We're undefing it here to make sure the `min` call does exactly + what we want it to do. */ +#ifdef min +#undef min +#endif +static inline size_t +min(size_t a, size_t b) +{ + return a > b ? b : a; +} + #if 0 /* TODO: -std=gnu99 causes compile error, comment them first */ // struct iovec must have the same layout as __wasi_iovec_t. static_assert(offsetof(struct iovec, iov_base) == @@ -56,105 +69,6 @@ static_assert(sizeof(struct iovec) == sizeof(__wasi_ciovec_t), "Size mismatch"); #endif -// Converts a POSIX error code to a CloudABI error code. -static __wasi_errno_t -convert_errno(int error) -{ - __wasi_errno_t code = __WASI_ENOSYS; -#define X(v) \ - case v: \ - code = __WASI_##v; \ - break; - switch (error) { - X(E2BIG) - X(EACCES) - X(EADDRINUSE) - X(EADDRNOTAVAIL) - X(EAFNOSUPPORT) - X(EAGAIN) - X(EALREADY) - X(EBADF) - X(EBADMSG) - X(EBUSY) - X(ECANCELED) - X(ECHILD) - X(ECONNABORTED) - X(ECONNREFUSED) - X(ECONNRESET) - X(EDEADLK) - X(EDESTADDRREQ) - X(EDOM) - X(EDQUOT) - X(EEXIST) - X(EFAULT) - X(EFBIG) - X(EHOSTUNREACH) - X(EIDRM) - X(EILSEQ) - X(EINPROGRESS) - X(EINTR) - X(EINVAL) - X(EIO) - X(EISCONN) - X(EISDIR) - X(ELOOP) - X(EMFILE) - X(EMLINK) - X(EMSGSIZE) - X(EMULTIHOP) - X(ENAMETOOLONG) - X(ENETDOWN) - X(ENETRESET) - X(ENETUNREACH) - X(ENFILE) - X(ENOBUFS) - X(ENODEV) - X(ENOENT) - X(ENOEXEC) - X(ENOLCK) - X(ENOLINK) - X(ENOMEM) - X(ENOMSG) - X(ENOPROTOOPT) - X(ENOSPC) - X(ENOSYS) -#ifdef ENOTCAPABLE - X(ENOTCAPABLE) -#endif - X(ENOTCONN) - X(ENOTDIR) - X(ENOTEMPTY) - X(ENOTRECOVERABLE) - X(ENOTSOCK) - X(ENOTSUP) - X(ENOTTY) - X(ENXIO) - X(EOVERFLOW) - X(EOWNERDEAD) - X(EPERM) - X(EPIPE) - X(EPROTO) - X(EPROTONOSUPPORT) - X(EPROTOTYPE) - X(ERANGE) - X(EROFS) - X(ESPIPE) - X(ESRCH) - X(ESTALE) - X(ETIMEDOUT) - X(ETXTBSY) - X(EXDEV) - default: - if (error == EOPNOTSUPP) - code = __WASI_ENOTSUP; - else if (code == EWOULDBLOCK) - code = __WASI_EAGAIN; - break; - } -#undef X - return code; -} - static bool ns_lookup_list_search(char **list, const char *host) { @@ -180,21 +94,9 @@ ns_lookup_list_search(char **list, const char *host) return false; } -// Converts a POSIX timespec to a CloudABI timestamp. -static __wasi_timestamp_t -convert_timespec(const struct timespec *ts) -{ - if (ts->tv_sec < 0) - return 0; - if ((__wasi_timestamp_t)ts->tv_sec >= UINT64_MAX / 1000000000) - return UINT64_MAX; - return (__wasi_timestamp_t)ts->tv_sec * 1000000000 - + (__wasi_timestamp_t)ts->tv_nsec; -} - -// Converts a CloudABI clock identifier to a POSIX clock identifier. +#if !defined(BH_PLATFORM_WINDOWS) && CONFIG_HAS_CLOCK_NANOSLEEP static bool -convert_clockid(__wasi_clockid_t in, clockid_t *out) +wasi_clockid_to_clockid(__wasi_clockid_t in, clockid_t *out) { switch (in) { case __WASI_CLOCK_MONOTONIC: @@ -217,6 +119,7 @@ convert_clockid(__wasi_clockid_t in, clockid_t *out) return false; } } +#endif static void wasi_addr_to_bh_sockaddr(const __wasi_addr_t *wasi_addr, @@ -294,35 +197,6 @@ wasi_addr_ip_to_bh_ip_addr_buffer(__wasi_addr_ip_t *addr, } } -__wasi_errno_t -wasmtime_ssp_clock_res_get(__wasi_clockid_t clock_id, - __wasi_timestamp_t *resolution) -{ - clockid_t nclock_id; - if (!convert_clockid(clock_id, &nclock_id)) - return __WASI_EINVAL; - struct timespec ts; - if (clock_getres(nclock_id, &ts) < 0) - return convert_errno(errno); - *resolution = convert_timespec(&ts); - return 0; -} - -__wasi_errno_t -wasmtime_ssp_clock_time_get(__wasi_clockid_t clock_id, - __wasi_timestamp_t precision, - __wasi_timestamp_t *time) -{ - clockid_t nclock_id; - if (!convert_clockid(clock_id, &nclock_id)) - return __WASI_EINVAL; - struct timespec ts; - if (clock_gettime(nclock_id, &ts) < 0) - return convert_errno(errno); - *time = convert_timespec(&ts); - return 0; -} - struct fd_prestat { const char *dir; }; @@ -442,13 +316,16 @@ fd_prestats_remove_entry(struct fd_prestats *pt, __wasi_fd_t fd) struct fd_object { struct refcount refcount; __wasi_filetype_t type; - int number; + os_file_handle file_handle; + // Keep track of whether this fd object refers to a stdio stream so we know + // whether to close the underlying file handle when releasing the object. + bool is_stdio; union { // Data associated with directory file descriptors. struct { struct mutex lock; // Lock to protect members below. - DIR *handle; // Directory handle. + os_dir_stream handle; // Directory handle. __wasi_dircookie_t offset; // Offset of the directory. } directory; }; @@ -530,7 +407,7 @@ fd_table_grow(struct fd_table *ft, size_t min, size_t incr) // Allocates a new file descriptor object. static __wasi_errno_t -fd_object_new(__wasi_filetype_t type, struct fd_object **fo) +fd_object_new(__wasi_filetype_t type, bool is_stdio, struct fd_object **fo) TRYLOCKS_SHARED(0, (*fo)->refcount) { *fo = wasm_runtime_malloc(sizeof(**fo)); @@ -538,7 +415,8 @@ fd_object_new(__wasi_filetype_t type, struct fd_object **fo) return __WASI_ENOMEM; refcount_init(&(*fo)->refcount, 1); (*fo)->type = type; - (*fo)->number = -1; + (*fo)->file_handle = os_get_invalid_handle(); + (*fo)->is_stdio = is_stdio; return 0; } @@ -576,139 +454,119 @@ fd_table_detach(struct fd_table *ft, __wasi_fd_t fd, struct fd_object **fo) // Determines the type of a file descriptor and its maximum set of // rights that should be attached to it. static __wasi_errno_t -fd_determine_type_rights(int fd, __wasi_filetype_t *type, +fd_determine_type_rights(os_file_handle fd, __wasi_filetype_t *type, __wasi_rights_t *rights_base, __wasi_rights_t *rights_inheriting) { - struct stat sb; - if (fstat(fd, &sb) < 0) - return convert_errno(errno); - if (S_ISBLK(sb.st_mode)) { - *type = __WASI_FILETYPE_BLOCK_DEVICE; - *rights_base = RIGHTS_BLOCK_DEVICE_BASE; - *rights_inheriting = RIGHTS_BLOCK_DEVICE_INHERITING; - } - else if (S_ISCHR(sb.st_mode)) { - *type = __WASI_FILETYPE_CHARACTER_DEVICE; -#if CONFIG_HAS_ISATTY - if (isatty(fd)) { - *rights_base = RIGHTS_TTY_BASE; - *rights_inheriting = RIGHTS_TTY_INHERITING; - } - else -#endif - { - *rights_base = RIGHTS_CHARACTER_DEVICE_BASE; - *rights_inheriting = RIGHTS_CHARACTER_DEVICE_INHERITING; - } - } - else if (S_ISDIR(sb.st_mode)) { - *type = __WASI_FILETYPE_DIRECTORY; - *rights_base = RIGHTS_DIRECTORY_BASE; - *rights_inheriting = RIGHTS_DIRECTORY_INHERITING; - } - else if (S_ISREG(sb.st_mode)) { - *type = __WASI_FILETYPE_REGULAR_FILE; - *rights_base = RIGHTS_REGULAR_FILE_BASE; - *rights_inheriting = RIGHTS_REGULAR_FILE_INHERITING; - } - else if (S_ISSOCK(sb.st_mode)) { - int socktype; - socklen_t socktypelen = sizeof(socktype); - if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &socktype, &socktypelen) < 0) - return convert_errno(errno); - switch (socktype) { - case SOCK_DGRAM: - *type = __WASI_FILETYPE_SOCKET_DGRAM; - break; - case SOCK_STREAM: - *type = __WASI_FILETYPE_SOCKET_STREAM; - break; - default: - return __WASI_EINVAL; - } - *rights_base = RIGHTS_SOCKET_BASE; - *rights_inheriting = RIGHTS_SOCKET_INHERITING; - } - else if (S_ISFIFO(sb.st_mode)) { - *type = __WASI_FILETYPE_SOCKET_STREAM; - *rights_base = RIGHTS_SOCKET_BASE; - *rights_inheriting = RIGHTS_SOCKET_INHERITING; - } - else { - return __WASI_EINVAL; + struct __wasi_filestat_t buf; + __wasi_errno_t error = os_fstat(fd, &buf); + + if (error != __WASI_ESUCCESS) + return error; + + *type = buf.st_filetype; + + switch (buf.st_filetype) { + case __WASI_FILETYPE_BLOCK_DEVICE: + *rights_base = RIGHTS_BLOCK_DEVICE_BASE; + *rights_inheriting = RIGHTS_BLOCK_DEVICE_INHERITING; + break; + case __WASI_FILETYPE_CHARACTER_DEVICE: + error = os_isatty(fd); + + if (error == __WASI_ESUCCESS) { + *rights_base = RIGHTS_TTY_BASE; + *rights_inheriting = RIGHTS_TTY_INHERITING; + } + else { + *rights_base = RIGHTS_CHARACTER_DEVICE_BASE; + *rights_inheriting = RIGHTS_CHARACTER_DEVICE_INHERITING; + } + break; + case __WASI_FILETYPE_DIRECTORY: + *rights_base = RIGHTS_DIRECTORY_BASE; + *rights_inheriting = RIGHTS_DIRECTORY_INHERITING; + break; + case __WASI_FILETYPE_REGULAR_FILE: + *rights_base = RIGHTS_REGULAR_FILE_BASE; + *rights_inheriting = RIGHTS_REGULAR_FILE_INHERITING; + break; + case __WASI_FILETYPE_SOCKET_DGRAM: + case __WASI_FILETYPE_SOCKET_STREAM: + *rights_base = RIGHTS_SOCKET_BASE; + *rights_inheriting = RIGHTS_SOCKET_INHERITING; + break; + case __WASI_FILETYPE_SYMBOLIC_LINK: + case __WASI_FILETYPE_UNKNOWN: + // If we don't know the type, allow for the maximum set of + // rights + *rights_base = RIGHTS_ALL; + *rights_inheriting = RIGHTS_ALL; + break; + default: + return __WASI_EINVAL; } + wasi_libc_file_access_mode access_mode; + error = os_file_get_access_mode(fd, &access_mode); + + if (error != __WASI_ESUCCESS) + return error; + // Strip off read/write bits based on the access mode. - switch (fcntl(fd, F_GETFL) & O_ACCMODE) { - case O_RDONLY: + switch (access_mode) { + case WASI_LIBC_ACCESS_MODE_READ_ONLY: *rights_base &= ~(__wasi_rights_t)__WASI_RIGHT_FD_WRITE; break; - case O_WRONLY: + case WASI_LIBC_ACCESS_MODE_WRITE_ONLY: *rights_base &= ~(__wasi_rights_t)__WASI_RIGHT_FD_READ; break; } - return 0; -} -// Returns the underlying file descriptor number of a file descriptor -// object. This function can only be applied to objects that have an -// underlying file descriptor number. -static int -fd_number(const struct fd_object *fo) -{ - int number = fo->number; - assert(number >= 0 && "fd_number() called on virtual file descriptor"); - return number; + return error; } -// The env == NULL case is for -// fd_table_destroy, path_get, path_put, fd_table_insert_existing -#define CLOSE_NON_STD_FD(env, fd) \ - do { \ - if (fd > 2) { \ - if (env == NULL) { \ - close(fd); \ - } \ - else { \ - blocking_op_close(env, fd); \ - } \ - } \ - } while (0) - // Lowers the reference count on a file descriptor object. When the // reference count reaches zero, its resources are cleaned up. -static void +static __wasi_errno_t fd_object_release(wasm_exec_env_t env, struct fd_object *fo) UNLOCKS(fo->refcount) { + __wasi_errno_t error = __WASI_ESUCCESS; + if (refcount_release(&fo->refcount)) { int saved_errno = errno; switch (fo->type) { case __WASI_FILETYPE_DIRECTORY: - // For directories we may keep track of a DIR object. Calling - // closedir() on it also closes the underlying file descriptor. + // For directories we may keep track of a DIR object. + // Calling os_closedir() on it also closes the underlying file + // descriptor. mutex_destroy(&fo->directory.lock); - if (fo->directory.handle == NULL) { - CLOSE_NON_STD_FD(env, fd_number(fo)); + if (os_is_dir_stream_valid(&fo->directory.handle)) { + error = os_closedir(fo->directory.handle); + break; } - else { - closedir(fo->directory.handle); - } - break; + // Fallthrough. default: - CLOSE_NON_STD_FD(env, fd_number(fo)); + // The env == NULL case is for + // fd_table_destroy, path_get, path_put, + // fd_table_insert_existing + error = (env == NULL) ? os_close(fo->file_handle, fo->is_stdio) + : blocking_op_close(env, fo->file_handle, + fo->is_stdio); break; } wasm_runtime_free(fo); errno = saved_errno; } + return error; } // Inserts an already existing file descriptor into the file descriptor // table. bool -fd_table_insert_existing(struct fd_table *ft, __wasi_fd_t in, int out) +fd_table_insert_existing(struct fd_table *ft, __wasi_fd_t in, + os_file_handle out, bool is_stdio) { __wasi_filetype_t type = __WASI_FILETYPE_UNKNOWN; __wasi_rights_t rights_base = 0, rights_inheriting = 0; @@ -720,8 +578,8 @@ fd_table_insert_existing(struct fd_table *ft, __wasi_fd_t in, int out) if (error != 0) { #ifdef BH_PLATFORM_EGO /** - * since it is an already opened file and we can assume the opened file - * has all necessary rights no matter how to get + * since it is an already opened file and we can assume the opened + * file has all necessary rights no matter how to get */ if (error != __WASI_ENOTSUP) return false; @@ -730,16 +588,16 @@ fd_table_insert_existing(struct fd_table *ft, __wasi_fd_t in, int out) #endif } - error = fd_object_new(type, &fo); + error = fd_object_new(type, is_stdio, &fo); if (error != 0) return false; - fo->number = out; + fo->file_handle = out; if (type == __WASI_FILETYPE_DIRECTORY) { if (!mutex_init(&fo->directory.lock)) { fd_object_release(NULL, fo); return false; } - fo->directory.handle = NULL; + fo->directory.handle = os_get_invalid_dir_stream(); } // Grow the file descriptor table if needed. @@ -791,26 +649,27 @@ fd_table_insert(wasm_exec_env_t exec_env, struct fd_table *ft, // Inserts a numerical file descriptor into the file descriptor table. static __wasi_errno_t -fd_table_insert_fd(wasm_exec_env_t exec_env, struct fd_table *ft, int in, - __wasi_filetype_t type, __wasi_rights_t rights_base, +fd_table_insert_fd(wasm_exec_env_t exec_env, struct fd_table *ft, + os_file_handle in, __wasi_filetype_t type, + __wasi_rights_t rights_base, __wasi_rights_t rights_inheriting, __wasi_fd_t *out) REQUIRES_UNLOCKED(ft->lock) { struct fd_object *fo; - __wasi_errno_t error = fd_object_new(type, &fo); + __wasi_errno_t error = fd_object_new(type, false, &fo); if (error != 0) { - close(in); + os_close(in, false); return error; } - fo->number = in; + fo->file_handle = in; if (type == __WASI_FILETYPE_DIRECTORY) { if (!mutex_init(&fo->directory.lock)) { fd_object_release(exec_env, fo); return (__wasi_errno_t)-1; } - fo->directory.handle = NULL; + fo->directory.handle = os_get_invalid_dir_stream(); } return fd_table_insert(exec_env, ft, fo, rights_base, rights_inheriting, out); @@ -948,15 +807,11 @@ wasmtime_ssp_fd_datasync(wasm_exec_env_t exec_env, struct fd_table *curfds, if (error != 0) return error; -#if CONFIG_HAS_FDATASYNC - int ret = fdatasync(fd_number(fo)); -#else - int ret = fsync(fd_number(fo)); -#endif + error = os_fdatasync(fo->file_handle); + fd_object_release(exec_env, fo); - if (ret < 0) - return convert_errno(errno); - return 0; + + return error; } __wasi_errno_t @@ -970,67 +825,16 @@ wasmtime_ssp_fd_pread(wasm_exec_env_t exec_env, struct fd_table *curfds, struct fd_object *fo; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_READ, 0); + if (error != 0) return error; -#if CONFIG_HAS_PREADV - ssize_t len = - blocking_op_preadv(exec_env, fd_number(fo), (const struct iovec *)iov, - (int)iovcnt, (off_t)offset); + error = blocking_op_preadv(exec_env, fo->file_handle, iov, (int)iovcnt, + offset, nread); + fd_object_release(exec_env, fo); - if (len < 0) - return convert_errno(errno); - *nread = (size_t)len; - return 0; -#else - if (iovcnt == 1) { - ssize_t len = blocking_op_pread(exec_env, fd_number(fo), iov->buf, - iov->buf_len, offset); - fd_object_release(exec_env, fo); - if (len < 0) - return convert_errno(errno); - *nread = len; - return 0; - } - else { - // Allocate a single buffer to fit all data. - size_t totalsize = 0; - for (size_t i = 0; i < iovcnt; ++i) - totalsize += iov[i].buf_len; - char *buf = wasm_runtime_malloc(totalsize); - if (buf == NULL) { - fd_object_release(exec_env, fo); - return __WASI_ENOMEM; - } - // Perform a single read operation. - ssize_t len = - blocking_op_pread(exec_env, fd_number(fo), buf, totalsize, offset); - fd_object_release(exec_env, fo); - if (len < 0) { - wasm_runtime_free(buf); - return convert_errno(errno); - } - - // Copy data back to vectors. - size_t bufoff = 0; - for (size_t i = 0; i < iovcnt; ++i) { - if (bufoff + iov[i].buf_len < (size_t)len) { - bh_memcpy_s(iov[i].buf, iov[i].buf_len, buf + bufoff, - iov[i].buf_len); - bufoff += iov[i].buf_len; - } - else { - bh_memcpy_s(iov[i].buf, iov[i].buf_len, buf + bufoff, - len - bufoff); - break; - } - } - wasm_runtime_free(buf); - *nread = len; - return 0; - } -#endif + return error; } __wasi_errno_t @@ -1039,53 +843,18 @@ wasmtime_ssp_fd_pwrite(wasm_exec_env_t exec_env, struct fd_table *curfds, size_t iovcnt, __wasi_filesize_t offset, size_t *nwritten) { - if (iovcnt == 0) - return __WASI_EINVAL; - struct fd_object *fo; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_WRITE, 0); + if (error != 0) return error; - ssize_t len; -#if CONFIG_HAS_PWRITEV - len = - blocking_op_pwritev(exec_env, fd_number(fo), (const struct iovec *)iov, - (int)iovcnt, (off_t)offset); -#else - if (iovcnt == 1) { - len = blocking_op_pwrite(exec_env, fd_number(fo), iov->buf, - iov->buf_len, offset); - } - else { - // Allocate a single buffer to fit all data. - size_t totalsize = 0; - for (size_t i = 0; i < iovcnt; ++i) - totalsize += iov[i].buf_len; - char *buf = wasm_runtime_malloc(totalsize); - if (buf == NULL) { - fd_object_release(exec_env, fo); - return __WASI_ENOMEM; - } - size_t bufoff = 0; - for (size_t i = 0; i < iovcnt; ++i) { - bh_memcpy_s(buf + bufoff, totalsize - bufoff, iov[i].buf, - iov[i].buf_len); - bufoff += iov[i].buf_len; - } - - // Perform a single write operation. - len = - blocking_op_pwrite(exec_env, fd_number(fo), buf, totalsize, offset); - wasm_runtime_free(buf); - } -#endif + error = blocking_op_pwritev(exec_env, fo->file_handle, iov, (int)iovcnt, + offset, nwritten); fd_object_release(exec_env, fo); - if (len < 0) - return convert_errno(errno); - *nwritten = (size_t)len; - return 0; + + return error; } __wasi_errno_t @@ -1096,16 +865,16 @@ wasmtime_ssp_fd_read(wasm_exec_env_t exec_env, struct fd_table *curfds, struct fd_object *fo; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_READ, 0); + if (error != 0) return error; - ssize_t len = blocking_op_readv(exec_env, fd_number(fo), - (const struct iovec *)iov, (int)iovcnt); + error = + blocking_op_readv(exec_env, fo->file_handle, iov, (int)iovcnt, nread); + fd_object_release(exec_env, fo); - if (len < 0) - return convert_errno(errno); - *nread = (size_t)len; - return 0; + + return error; } __wasi_errno_t @@ -1167,9 +936,9 @@ wasmtime_ssp_fd_renumber(wasm_exec_env_t exec_env, struct fd_table *curfds, (void)fd_prestats_remove_entry(prestats, to); } } - // Renumbering from a non-preopened fd to a preopened fd. In this case, we - // can't a keep the destination fd entry in the preopened table so remove - // it entirely. + // Renumbering from a non-preopened fd to a preopened fd. In this case, + // we can't a keep the destination fd entry in the preopened table so + // remove it entirely. else if (prestat_from_error != __WASI_ESUCCESS && prestat_to_error == __WASI_ESUCCESS) { (void)fd_prestats_remove_entry(prestats, to); @@ -1198,21 +967,6 @@ wasmtime_ssp_fd_seek(wasm_exec_env_t exec_env, struct fd_table *curfds, __wasi_fd_t fd, __wasi_filedelta_t offset, __wasi_whence_t whence, __wasi_filesize_t *newoffset) { - int nwhence; - switch (whence) { - case __WASI_WHENCE_CUR: - nwhence = SEEK_CUR; - break; - case __WASI_WHENCE_END: - nwhence = SEEK_END; - break; - case __WASI_WHENCE_SET: - nwhence = SEEK_SET; - break; - default: - return __WASI_EINVAL; - } - struct fd_object *fo; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, @@ -1223,12 +977,11 @@ wasmtime_ssp_fd_seek(wasm_exec_env_t exec_env, struct fd_table *curfds, if (error != 0) return error; - off_t ret = lseek(fd_number(fo), offset, nwhence); + error = os_lseek(fo->file_handle, offset, whence, newoffset); + fd_object_release(exec_env, fo); - if (ret < 0) - return convert_errno(errno); - *newoffset = (__wasi_filesize_t)ret; - return 0; + + return error; } __wasi_errno_t @@ -1241,12 +994,11 @@ wasmtime_ssp_fd_tell(wasm_exec_env_t exec_env, struct fd_table *curfds, if (error != 0) return error; - off_t ret = lseek(fd_number(fo), 0, SEEK_CUR); + error = os_lseek(fo->file_handle, 0, __WASI_WHENCE_CUR, newoffset); + fd_object_release(exec_env, fo); - if (ret < 0) - return convert_errno(errno); - *newoffset = (__wasi_filesize_t)ret; - return 0; + + return error; } __wasi_errno_t @@ -1257,47 +1009,29 @@ wasmtime_ssp_fd_fdstat_get(wasm_exec_env_t exec_env, struct fd_table *curfds, rwlock_rdlock(&ft->lock); struct fd_entry *fe; __wasi_errno_t error = fd_table_get_entry(ft, fd, 0, 0, &fe); - if (error != 0) { + if (error != __WASI_ESUCCESS) { rwlock_unlock(&ft->lock); return error; } // Extract file descriptor type and rights. struct fd_object *fo = fe->object; - *buf = (__wasi_fdstat_t){ - .fs_filetype = fo->type, - .fs_rights_base = fe->rights_base, - .fs_rights_inheriting = fe->rights_inheriting, - }; - // Fetch file descriptor flags. - int ret; - switch (fo->type) { - default: - ret = fcntl(fd_number(fo), F_GETFL); - break; + __wasi_fdflags_t flags; + error = os_file_get_fdflags(fo->file_handle, &flags); + + if (error != __WASI_ESUCCESS) { + rwlock_unlock(&ft->lock); + return error; } - rwlock_unlock(&ft->lock); - if (ret < 0) - return convert_errno(errno); - if ((ret & O_APPEND) != 0) - buf->fs_flags |= __WASI_FDFLAG_APPEND; -#ifdef CONFIG_HAS_O_DSYNC - if ((ret & O_DSYNC) != 0) - buf->fs_flags |= __WASI_FDFLAG_DSYNC; -#endif - if ((ret & O_NONBLOCK) != 0) - buf->fs_flags |= __WASI_FDFLAG_NONBLOCK; -#ifdef CONFIG_HAS_O_RSYNC - if ((ret & O_RSYNC) != 0) - buf->fs_flags |= __WASI_FDFLAG_RSYNC; -#endif -#ifdef CONFIG_HAS_O_SYNC - if ((ret & O_SYNC) != 0) - buf->fs_flags |= __WASI_FDFLAG_SYNC; -#endif - return 0; + *buf = (__wasi_fdstat_t){ .fs_filetype = fo->type, + .fs_rights_base = fe->rights_base, + .fs_rights_inheriting = fe->rights_inheriting, + .fs_flags = flags }; + + rwlock_unlock(&ft->lock); + return error; } __wasi_errno_t @@ -1305,41 +1039,18 @@ wasmtime_ssp_fd_fdstat_set_flags(wasm_exec_env_t exec_env, struct fd_table *curfds, __wasi_fd_t fd, __wasi_fdflags_t fs_flags) { - int noflags = 0; - if ((fs_flags & __WASI_FDFLAG_APPEND) != 0) - noflags |= O_APPEND; - if ((fs_flags & __WASI_FDFLAG_DSYNC) != 0) -#ifdef CONFIG_HAS_O_DSYNC - noflags |= O_DSYNC; -#else - return __WASI_ENOTSUP; -#endif - if ((fs_flags & __WASI_FDFLAG_NONBLOCK) != 0) - noflags |= O_NONBLOCK; - if ((fs_flags & __WASI_FDFLAG_RSYNC) != 0) -#ifdef CONFIG_HAS_O_RSYNC - noflags |= O_RSYNC; -#else - return __WASI_ENOTSUP; -#endif - if ((fs_flags & __WASI_FDFLAG_SYNC) != 0) -#ifdef CONFIG_HAS_O_SYNC - noflags |= O_SYNC; -#else - return __WASI_ENOTSUP; -#endif - struct fd_object *fo; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_FDSTAT_SET_FLAGS, 0); + if (error != 0) return error; - int ret = fcntl(fd_number(fo), F_SETFL, noflags); + error = os_file_set_fdflags(fo->file_handle, fs_flags); + fd_object_release(exec_env, fo); - if (ret < 0) - return convert_errno(errno); - return 0; + + return error; } __wasi_errno_t @@ -1372,14 +1083,15 @@ wasmtime_ssp_fd_sync(wasm_exec_env_t exec_env, struct fd_table *curfds, struct fd_object *fo; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_SYNC, 0); + if (error != 0) return error; - int ret = fsync(fd_number(fo)); + error = os_fsync(fo->file_handle); + fd_object_release(exec_env, fo); - if (ret < 0) - return convert_errno(errno); - return 0; + + return error; } __wasi_errno_t @@ -1394,33 +1106,31 @@ wasmtime_ssp_fd_write(wasm_exec_env_t exec_env, struct fd_table *curfds, return error; #ifndef BH_VPRINTF - ssize_t len = writev(fd_number(fo), (const struct iovec *)iov, (int)iovcnt); + error = blocking_op_writev(exec_env, fo->file_handle, iov, (int)iovcnt, + nwritten); #else - ssize_t len = 0; /* redirect stdout/stderr output to BH_VPRINTF function */ - if (fd_number(fo) == 1 || fd_number(fo) == 2) { + if (fo->is_stdio) { int i; - const struct iovec *iov1 = (const struct iovec *)iov; - - for (i = 0; i < (int)iovcnt; i++, iov1++) { - if (iov1->iov_len > 0 && iov1->iov_base) { + *nwritten = 0; + for (i = 0; i < (int)iovcnt; i++) { + if (iov[i].buf_len > 0 && iov[i].buf != NULL) { char format[16]; /* make up format string "%.ns" */ - snprintf(format, sizeof(format), "%%.%ds", (int)iov1->iov_len); - len += (ssize_t)os_printf(format, iov1->iov_base); + snprintf(format, sizeof(format), "%%.%ds", (int)iov[i].buf_len); + *nwritten += (size_t)os_printf(format, iov[i].buf); } } } else { - len = writev(fd_number(fo), (const struct iovec *)iov, (int)iovcnt); + error = blocking_op_writev(exec_env, fo->file_handle, iov, (int)iovcnt, + nwritten); } #endif /* end of BH_VPRINTF */ fd_object_release(exec_env, fo); - if (len < 0) - return convert_errno(errno); - *nwritten = (size_t)len; - return 0; + + return error; } __wasi_errno_t @@ -1428,65 +1138,17 @@ wasmtime_ssp_fd_advise(wasm_exec_env_t exec_env, struct fd_table *curfds, __wasi_fd_t fd, __wasi_filesize_t offset, __wasi_filesize_t len, __wasi_advice_t advice) { -#ifdef POSIX_FADV_NORMAL - int nadvice; - switch (advice) { - case __WASI_ADVICE_DONTNEED: - nadvice = POSIX_FADV_DONTNEED; - break; - case __WASI_ADVICE_NOREUSE: - nadvice = POSIX_FADV_NOREUSE; - break; - case __WASI_ADVICE_NORMAL: - nadvice = POSIX_FADV_NORMAL; - break; - case __WASI_ADVICE_RANDOM: - nadvice = POSIX_FADV_RANDOM; - break; - case __WASI_ADVICE_SEQUENTIAL: - nadvice = POSIX_FADV_SEQUENTIAL; - break; - case __WASI_ADVICE_WILLNEED: - nadvice = POSIX_FADV_WILLNEED; - break; - default: - return __WASI_EINVAL; - } - struct fd_object *fo; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_ADVISE, 0); if (error != 0) return error; - int ret = posix_fadvise(fd_number(fo), (off_t)offset, (off_t)len, nadvice); - fd_object_release(exec_env, fo); - if (ret != 0) - return convert_errno(ret); - return 0; -#else - // Advisory information can safely be ignored if unsupported. - switch (advice) { - case __WASI_ADVICE_DONTNEED: - case __WASI_ADVICE_NOREUSE: - case __WASI_ADVICE_NORMAL: - case __WASI_ADVICE_RANDOM: - case __WASI_ADVICE_SEQUENTIAL: - case __WASI_ADVICE_WILLNEED: - break; - default: - return __WASI_EINVAL; - } + error = os_fadvise(fo->file_handle, offset, len, advice); + + fd_object_release(exec_env, fo); - // At least check for file descriptor existence. - struct fd_table *ft = curfds; - rwlock_rdlock(&ft->lock); - struct fd_entry *fe; - __wasi_errno_t error = - fd_table_get_entry(ft, fd, __WASI_RIGHT_FD_ADVISE, 0, &fe); - rwlock_unlock(&ft->lock); return error; -#endif } __wasi_errno_t @@ -1497,34 +1159,23 @@ wasmtime_ssp_fd_allocate(wasm_exec_env_t exec_env, struct fd_table *curfds, struct fd_object *fo; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_ALLOCATE, 0); - if (error != 0) + if (error != __WASI_ESUCCESS) return error; -#if CONFIG_HAS_POSIX_FALLOCATE - int ret = posix_fallocate(fd_number(fo), (off_t)offset, (off_t)len); -#else - // At least ensure that the file is grown to the right size. - // TODO(ed): See if this can somehow be implemented without any race - // conditions. We may end up shrinking the file right now. - struct stat sb; - int ret = fstat(fd_number(fo), &sb); - off_t newsize = (off_t)(offset + len); - if (ret == 0 && sb.st_size < newsize) - ret = ftruncate(fd_number(fo), newsize); -#endif + error = os_fallocate(fo->file_handle, offset, len); fd_object_release(exec_env, fo); - if (ret != 0) - return convert_errno(ret); - return 0; + + return error; } // Reads the entire contents of a symbolic link, returning the contents // in an allocated buffer. The allocated buffer is large enough to fit // at least one extra byte, so the caller may append a trailing slash to // it. This is needed by path_get(). -static char * -readlinkat_dup(int fd, const char *path, size_t *p_len) +__wasi_errno_t +readlinkat_dup(os_file_handle handle, const char *path, size_t *p_len, + char **out_buf) { char *buf = NULL; size_t len = 32; @@ -1536,7 +1187,8 @@ readlinkat_dup(int fd, const char *path, size_t *p_len) if (newbuf == NULL) { if (buf) wasm_runtime_free(buf); - return NULL; + *out_buf = NULL; + return __WASI_ENOMEM; } if (buf != NULL) { @@ -1545,15 +1197,20 @@ readlinkat_dup(int fd, const char *path, size_t *p_len) } buf = newbuf; - ssize_t ret = readlinkat(fd, path, buf, len); - if (ret < 0) { + size_t bytes_read = 0; + __wasi_errno_t error = + os_readlinkat(handle, path, buf, len, &bytes_read); + if (error != __WASI_ESUCCESS) { wasm_runtime_free(buf); - return NULL; + *out_buf = NULL; + return error; } - if ((size_t)ret + 1 < len) { - buf[ret] = '\0'; + if ((size_t)bytes_read + 1 < len) { + buf[bytes_read] = '\0'; *p_len = len; - return buf; + *out_buf = buf; + + return __WASI_ESUCCESS; } len_org = len; len *= 2; @@ -1567,7 +1224,7 @@ readlinkat_dup(int fd, const char *path, size_t *p_len) // descriptor representing the directory where the lookup needs to start // and the actual pathname string. struct path_access { - int fd; // Directory file descriptor. + os_file_handle fd; // Directory file descriptor. const char *path; // Pathname. bool follow; // Whether symbolic links should be followed. char *path_start; // Internal: pathname to free. @@ -1579,10 +1236,10 @@ struct path_access { // pathname to ensure the target path is placed underneath the // directory. static __wasi_errno_t -path_get(struct fd_table *curfds, struct path_access *pa, __wasi_fd_t fd, - __wasi_lookupflags_t flags, const char *upath, size_t upathlen, - __wasi_rights_t rights_base, __wasi_rights_t rights_inheriting, - bool needs_final_component) +path_get(wasm_exec_env_t exec_env, struct fd_table *curfds, + struct path_access *pa, __wasi_fd_t fd, __wasi_lookupflags_t flags, + const char *upath, size_t upathlen, __wasi_rights_t rights_base, + __wasi_rights_t rights_inheriting, bool needs_final_component) TRYLOCKS_EXCLUSIVE(0, pa->fd_object->refcount) { char *path = str_nullterminate(upath, upathlen); @@ -1601,7 +1258,7 @@ path_get(struct fd_table *curfds, struct path_access *pa, __wasi_fd_t fd, #if CONFIG_HAS_CAP_ENTER // Rely on the kernel to constrain access to automatically constrain // access to files stored underneath this directory. - pa->fd = fd_number(fo); + pa->fd = fo->file_handle; pa->path = pa->path_start = path; pa->follow = (flags & __WASI_LOOKUP_SYMLINK_FOLLOW) != 0; pa->fd_object = fo; @@ -1616,8 +1273,8 @@ path_get(struct fd_table *curfds, struct path_access *pa, __wasi_fd_t fd, // causes a file descriptor to be pushed, while handling ".." entries // causes an entry to be popped. Index 0 cannot be popped, as this // would imply escaping the base directory. - int fds[128]; - fds[0] = fd_number(fo); + os_file_handle fds[128]; + fds[0] = fo->file_handle; size_t curfd = 0; // Stack of pathname strings used for symlink expansion. By using a @@ -1628,8 +1285,13 @@ path_get(struct fd_table *curfds, struct path_access *pa, __wasi_fd_t fd, paths[0] = paths_start[0] = path; size_t curpath = 0; size_t expansions = 0; - char *symlink; + char *symlink = NULL; size_t symlink_len; +#ifdef BH_PLATFORM_WINDOWS +#define PATH_SEPARATORS "/\\" +#else +#define PATH_SEPARATORS "/" +#endif for (;;) { // Extract the next pathname component from 'paths[curpath]', null @@ -1637,9 +1299,10 @@ path_get(struct fd_table *curfds, struct path_access *pa, __wasi_fd_t fd, // whether the pathname component is followed by one or more // trailing slashes, as this requires it to be a directory. char *file = paths[curpath]; - char *file_end = file + strcspn(file, "/"); - paths[curpath] = file_end + strspn(file_end, "/"); - bool ends_with_slashes = *file_end == '/'; + char *file_end = file + strcspn(file, PATH_SEPARATORS); + paths[curpath] = file_end + strspn(file_end, PATH_SEPARATORS); + bool ends_with_slashes = + (*file_end != '\0' && strchr(PATH_SEPARATORS, *file_end)); *file_end = '\0'; // Test for empty pathname strings and absolute paths. @@ -1659,7 +1322,10 @@ path_get(struct fd_table *curfds, struct path_access *pa, __wasi_fd_t fd, error = __WASI_ENOTCAPABLE; goto fail; } - close(fds[curfd--]); + error = os_close(fds[curfd--], false); + + if (error != __WASI_ESUCCESS) + goto fail; } else if (curpath > 0 || *paths[curpath] != '\0' || (ends_with_slashes && !needs_final_component)) { @@ -1668,19 +1334,14 @@ path_get(struct fd_table *curfds, struct path_access *pa, __wasi_fd_t fd, // components. In other words, a pathname component that must be a // directory. First attempt to obtain a directory file descriptor // for it. - // - // Note: we don't bother to use blocking_op_openat here - // because openat with O_DIRECTORY should not block. - int newdir = -#ifdef O_SEARCH - openat(fds[curfd], file, O_SEARCH | O_DIRECTORY | O_NOFOLLOW); -#else - openat(fds[curfd], file, O_RDONLY | O_DIRECTORY | O_NOFOLLOW); -#endif - if (newdir != -1) { + os_file_handle newdir; + error = blocking_op_openat( + exec_env, fds[curfd], file, __WASI_O_DIRECTORY, 0, 0, + WASI_LIBC_ACCESS_MODE_READ_ONLY, &newdir); + if (error == __WASI_ESUCCESS) { // Success. Push it onto the directory stack. if (curfd + 1 == sizeof(fds) / sizeof(fds[0])) { - close(newdir); + os_close(newdir, false); error = __WASI_ENAMETOOLONG; goto fail; } @@ -1688,20 +1349,23 @@ path_get(struct fd_table *curfds, struct path_access *pa, __wasi_fd_t fd, } else { // Failed to open it. Attempt symlink expansion. - if (errno != ELOOP && errno != EMLINK && errno != ENOTDIR) { - error = convert_errno(errno); + if (error != __WASI_ELOOP && error != __WASI_EMLINK + && error != __WASI_ENOTDIR) { goto fail; } - symlink = readlinkat_dup(fds[curfd], file, &symlink_len); - if (symlink != NULL) + error = + readlinkat_dup(fds[curfd], file, &symlink_len, &symlink); + + if (error == __WASI_ESUCCESS) { + bh_assert(symlink != NULL); goto push_symlink; + } // readlink returns EINVAL if the path isn't a symlink. In that // case, it's more informative to return ENOTDIR. - if (errno == EINVAL) - errno = ENOTDIR; + if (error == __WASI_EINVAL) + error = __WASI_ENOTDIR; - error = convert_errno(errno); goto fail; } } @@ -1711,11 +1375,13 @@ path_get(struct fd_table *curfds, struct path_access *pa, __wasi_fd_t fd, // expansion. if (ends_with_slashes || (flags & __WASI_LOOKUP_SYMLINK_FOLLOW) != 0) { - symlink = readlinkat_dup(fds[curfd], file, &symlink_len); - if (symlink != NULL) + error = + readlinkat_dup(fds[curfd], file, &symlink_len, &symlink); + if (error == __WASI_ESUCCESS) { + bh_assert(symlink != NULL); goto push_symlink; - if (errno != EINVAL && errno != ENOENT) { - error = convert_errno(errno); + } + if (error != __WASI_EINVAL && error != __WASI_ENOENT) { goto fail; } } @@ -1792,7 +1458,7 @@ success: // Return the lease. Close all directories, except the one the caller // needs to use. for (size_t i = 1; i < curfd; ++i) - close(fds[i]); + os_close(fds[i], false); pa->fd = fds[curfd]; pa->follow = false; pa->fd_object = fo; @@ -1801,7 +1467,7 @@ success: fail: // Failure. Free all resources. for (size_t i = 1; i <= curfd; ++i) - close(fds[i]); + os_close(fds[i], false); for (size_t i = 0; i <= curpath; ++i) wasm_runtime_free(paths_start[i]); fd_object_release(NULL, fo); @@ -1810,14 +1476,14 @@ fail: } static __wasi_errno_t -path_get_nofollow(struct fd_table *curfds, struct path_access *pa, - __wasi_fd_t fd, const char *path, size_t pathlen, - __wasi_rights_t rights_base, +path_get_nofollow(wasm_exec_env_t exec_env, struct fd_table *curfds, + struct path_access *pa, __wasi_fd_t fd, const char *path, + size_t pathlen, __wasi_rights_t rights_base, __wasi_rights_t rights_inheriting, bool needs_final_component) TRYLOCKS_EXCLUSIVE(0, pa->fd_object->refcount) { __wasi_lookupflags_t flags = 0; - return path_get(curfds, pa, fd, flags, path, pathlen, rights_base, + return path_get(exec_env, curfds, pa, fd, flags, path, pathlen, rights_base, rights_inheriting, needs_final_component); } @@ -1826,8 +1492,8 @@ path_put(struct path_access *pa) UNLOCKS(pa->fd_object->refcount) { if (pa->path_start) wasm_runtime_free(pa->path_start); - if (fd_number(pa->fd_object) != pa->fd) - close(pa->fd); + if (pa->fd_object->file_handle != pa->fd) + os_close(pa->fd, false); fd_object_release(NULL, pa->fd_object); } @@ -1838,16 +1504,15 @@ wasmtime_ssp_path_create_directory(wasm_exec_env_t exec_env, { struct path_access pa; __wasi_errno_t error = - path_get_nofollow(curfds, &pa, fd, path, pathlen, + path_get_nofollow(exec_env, curfds, &pa, fd, path, pathlen, __WASI_RIGHT_PATH_CREATE_DIRECTORY, 0, true); if (error != 0) return error; - int ret = mkdirat(pa.fd, pa.path, 0777); + error = os_mkdirat(pa.fd, pa.path); path_put(&pa); - if (ret < 0) - return convert_errno(errno); - return 0; + + return error; } static bool @@ -1857,7 +1522,7 @@ validate_path(const char *path, struct fd_prestats *pt) char path_resolved[PATH_MAX], prestat_dir_resolved[PATH_MAX]; char *path_real, *prestat_dir_real; - if (!(path_real = realpath(path, path_resolved))) + if (!(path_real = os_realpath(path, path_resolved))) /* path doesn't exist, creating a link to this file is allowed: if this file is to be created in the future, WASI will strictly check whether it @@ -1867,7 +1532,7 @@ validate_path(const char *path, struct fd_prestats *pt) for (i = 0; i < pt->size; i++) { if (pt->prestats[i].dir) { if (!(prestat_dir_real = - realpath(pt->prestats[i].dir, prestat_dir_resolved))) + os_realpath(pt->prestats[i].dir, prestat_dir_resolved))) return false; if (!strncmp(path_real, prestat_dir_real, strlen(prestat_dir_real))) return true; @@ -1886,14 +1551,15 @@ wasmtime_ssp_path_link(wasm_exec_env_t exec_env, struct fd_table *curfds, { struct path_access old_pa; __wasi_errno_t error = - path_get(curfds, &old_pa, old_fd, old_flags, old_path, old_path_len, - __WASI_RIGHT_PATH_LINK_SOURCE, 0, false); + path_get(exec_env, curfds, &old_pa, old_fd, old_flags, old_path, + old_path_len, __WASI_RIGHT_PATH_LINK_SOURCE, 0, false); if (error != 0) return error; struct path_access new_pa; - error = path_get_nofollow(curfds, &new_pa, new_fd, new_path, new_path_len, - __WASI_RIGHT_PATH_LINK_TARGET, 0, true); + error = + path_get_nofollow(exec_env, curfds, &new_pa, new_fd, new_path, + new_path_len, __WASI_RIGHT_PATH_LINK_TARGET, 0, true); if (error != 0) { path_put(&old_pa); return error; @@ -1907,14 +1573,18 @@ wasmtime_ssp_path_link(wasm_exec_env_t exec_env, struct fd_table *curfds, } rwlock_unlock(&prestats->lock); - int ret = linkat(old_pa.fd, old_pa.path, new_pa.fd, new_pa.path, - old_pa.follow ? AT_SYMLINK_FOLLOW : 0); - if (ret < 0 && errno == ENOTSUP && !old_pa.follow) { + error = os_linkat(old_pa.fd, old_pa.path, new_pa.fd, new_pa.path, + old_pa.follow ? __WASI_LOOKUP_SYMLINK_FOLLOW : 0); + +#if defined(__APPLE__) + if (error == __WASI_ENOTSUP && !old_pa.follow) { // OS X doesn't allow creating hardlinks to symbolic links. // Duplicate the symbolic link instead. size_t target_len; - char *target = readlinkat_dup(old_pa.fd, old_pa.path, &target_len); - if (target != NULL) { + char *target = NULL; + error = readlinkat_dup(old_pa.fd, old_pa.path, &target_len, &target); + if (error == __WASI_ESUCCESS) { + bh_assert(target != NULL); bh_assert(target[target_len] == '\0'); rwlock_rdlock(&prestats->lock); if (!validate_path(target, prestats)) { @@ -1923,15 +1593,16 @@ wasmtime_ssp_path_link(wasm_exec_env_t exec_env, struct fd_table *curfds, return __WASI_EBADF; } rwlock_unlock(&prestats->lock); - ret = symlinkat(target, new_pa.fd, new_pa.path); + error = os_symlinkat(target, new_pa.fd, new_pa.path); wasm_runtime_free(target); } } +#endif + path_put(&old_pa); path_put(&new_pa); - if (ret < 0) - return convert_errno(errno); - return 0; + + return error; } __wasi_errno_t @@ -1954,7 +1625,11 @@ wasmtime_ssp_path_open(wasm_exec_env_t exec_env, struct fd_table *curfds, & (__WASI_RIGHT_FD_DATASYNC | __WASI_RIGHT_FD_WRITE | __WASI_RIGHT_FD_ALLOCATE | __WASI_RIGHT_FD_FILESTAT_SET_SIZE)) != 0; - int noflags = write ? read ? O_RDWR : O_WRONLY : O_RDONLY; + + wasi_libc_file_access_mode access_mode = + write ? read ? WASI_LIBC_ACCESS_MODE_READ_WRITE + : WASI_LIBC_ACCESS_MODE_WRITE_ONLY + : WASI_LIBC_ACCESS_MODE_READ_ONLY; // Which rights are needed on the directory file descriptor. __wasi_rights_t needed_base = __WASI_RIGHT_PATH_OPEN; @@ -1962,103 +1637,57 @@ wasmtime_ssp_path_open(wasm_exec_env_t exec_env, struct fd_table *curfds, // Convert open flags. if ((oflags & __WASI_O_CREAT) != 0) { - noflags |= O_CREAT; needed_base |= __WASI_RIGHT_PATH_CREATE_FILE; } - if ((oflags & __WASI_O_DIRECTORY) != 0) - noflags |= O_DIRECTORY; - if ((oflags & __WASI_O_EXCL) != 0) - noflags |= O_EXCL; if ((oflags & __WASI_O_TRUNC) != 0) { - noflags |= O_TRUNC; needed_base |= __WASI_RIGHT_PATH_FILESTAT_SET_SIZE; } // Convert file descriptor flags. - if ((fs_flags & __WASI_FDFLAG_APPEND) != 0) - noflags |= O_APPEND; - if ((fs_flags & __WASI_FDFLAG_DSYNC) != 0) { -#ifdef CONFIG_HAS_O_DSYNC - noflags |= O_DSYNC; - needed_inheriting |= __WASI_RIGHT_FD_DATASYNC; -#else - return __WASI_ENOTSUP; -#endif - } - if ((fs_flags & __WASI_FDFLAG_NONBLOCK) != 0) - noflags |= O_NONBLOCK; - if ((fs_flags & __WASI_FDFLAG_RSYNC) != 0) { -#ifdef CONFIG_HAS_O_RSYNC - noflags |= O_RSYNC; - needed_inheriting |= __WASI_RIGHT_FD_SYNC; -#else - return __WASI_ENOTSUP; -#endif - } if ((fs_flags & __WASI_FDFLAG_SYNC) != 0) { -#ifdef CONFIG_HAS_O_SYNC - noflags |= O_SYNC; needed_inheriting |= __WASI_RIGHT_FD_SYNC; -#else - return __WASI_ENOTSUP; -#endif } - if (write && (noflags & (O_APPEND | O_TRUNC)) == 0) + if ((fs_flags & __WASI_FDFLAG_RSYNC) != 0) { + needed_inheriting |= __WASI_RIGHT_FD_SYNC; + } + if ((fs_flags & __WASI_FDFLAG_DSYNC) != 0) { + needed_inheriting |= __WASI_RIGHT_FD_DATASYNC; + } + + if (write + && !((fs_flags & __WASI_FDFLAG_APPEND) || (__WASI_O_TRUNC & oflags))) needed_inheriting |= __WASI_RIGHT_FD_SEEK; struct path_access pa; - __wasi_errno_t error = - path_get(curfds, &pa, dirfd, dirflags, path, pathlen, needed_base, - needed_inheriting, (oflags & __WASI_O_CREAT) != 0); + __wasi_errno_t error = path_get( + exec_env, curfds, &pa, dirfd, dirflags, path, pathlen, needed_base, + needed_inheriting, (oflags & __WASI_O_CREAT) != 0); + if (error != 0) return error; - if (!pa.follow) - noflags |= O_NOFOLLOW; - int nfd = blocking_op_openat(exec_env, pa.fd, pa.path, noflags, 0666); - if (nfd < 0) { - int openat_errno = errno; - // Linux returns ENXIO instead of EOPNOTSUPP when opening a socket. - if (openat_errno == ENXIO) { - struct stat sb; - int ret = fstatat(pa.fd, pa.path, &sb, - pa.follow ? 0 : AT_SYMLINK_NOFOLLOW); - path_put(&pa); - return ret == 0 && S_ISSOCK(sb.st_mode) ? __WASI_ENOTSUP - : __WASI_ENXIO; - } - // Linux returns ENOTDIR instead of ELOOP when using - // O_NOFOLLOW|O_DIRECTORY on a symlink. - if (openat_errno == ENOTDIR - && (noflags & (O_NOFOLLOW | O_DIRECTORY)) != 0) { - struct stat sb; - int ret = fstatat(pa.fd, pa.path, &sb, AT_SYMLINK_NOFOLLOW); - if (S_ISLNK(sb.st_mode)) { - path_put(&pa); - return __WASI_ELOOP; - } - (void)ret; - } - path_put(&pa); - // FreeBSD returns EMLINK instead of ELOOP when using O_NOFOLLOW on - // a symlink. - if (!pa.follow && openat_errno == EMLINK) - return __WASI_ELOOP; - return convert_errno(openat_errno); - } + os_file_handle handle; + error = blocking_op_openat(exec_env, pa.fd, pa.path, oflags, fs_flags, + dirflags, access_mode, &handle); + path_put(&pa); + if (error != __WASI_ESUCCESS) + return error; + // Determine the type of the new file descriptor and which rights // contradict with this type. __wasi_filetype_t type; __wasi_rights_t max_base, max_inheriting; - error = fd_determine_type_rights(nfd, &type, &max_base, &max_inheriting); - if (error != 0) { - close(nfd); + + error = fd_determine_type_rights(handle, &type, &max_base, &max_inheriting); + + if (error != __WASI_ESUCCESS) { + os_close(handle, false); return error; } - return fd_table_insert_fd(exec_env, curfds, nfd, type, + return fd_table_insert_fd(exec_env, curfds, handle, type, rights_base & max_base, rights_inheriting & max_inheriting, fd); } @@ -2091,15 +1720,13 @@ wasmtime_ssp_fd_readdir(wasm_exec_env_t exec_env, struct fd_table *curfds, // Create a directory handle if none has been opened yet. mutex_lock(&fo->directory.lock); - DIR *dp = fo->directory.handle; - if (dp == NULL) { - dp = fdopendir(fd_number(fo)); - if (dp == NULL) { + if (!os_is_dir_stream_valid(&fo->directory.handle)) { + error = os_fdopendir(fo->file_handle, &fo->directory.handle); + if (error != __WASI_ESUCCESS) { mutex_unlock(&fo->directory.lock); fd_object_release(exec_env, fo); - return convert_errno(errno); + return error; } - fo->directory.handle = dp; fo->directory.offset = __WASI_DIRCOOKIE_START; } @@ -2107,70 +1734,34 @@ wasmtime_ssp_fd_readdir(wasm_exec_env_t exec_env, struct fd_table *curfds, // the current offset. if (fo->directory.offset != cookie) { if (cookie == __WASI_DIRCOOKIE_START) - rewinddir(dp); + os_rewinddir(fo->directory.handle); else - seekdir(dp, (long)cookie); + os_seekdir(fo->directory.handle, cookie); fo->directory.offset = cookie; } *bufused = 0; while (*bufused < nbyte) { // Read the next directory entry. - errno = 0; - struct dirent *de = readdir(dp); - if (de == NULL) { + __wasi_dirent_t cde; + const char *d_name = NULL; + + error = os_readdir(fo->directory.handle, &cde, &d_name); + if (d_name == NULL) { mutex_unlock(&fo->directory.lock); fd_object_release(exec_env, fo); - return errno == 0 || *bufused > 0 ? 0 : convert_errno(errno); - } - fo->directory.offset = (__wasi_dircookie_t)telldir(dp); - // Craft a directory entry and copy that back. - size_t namlen = strlen(de->d_name); - __wasi_dirent_t cde = { - .d_next = fo->directory.offset, -#if CONFIG_HAS_D_INO - .d_ino = de->d_ino, -#else - .d_ino = 0, -#endif - .d_namlen = (uint32)namlen, - }; - switch (de->d_type) { - case DT_BLK: - cde.d_type = __WASI_FILETYPE_BLOCK_DEVICE; - break; - case DT_CHR: - cde.d_type = __WASI_FILETYPE_CHARACTER_DEVICE; - break; - case DT_DIR: - cde.d_type = __WASI_FILETYPE_DIRECTORY; - break; - case DT_FIFO: - cde.d_type = __WASI_FILETYPE_SOCKET_STREAM; - break; - case DT_LNK: - cde.d_type = __WASI_FILETYPE_SYMBOLIC_LINK; - break; - case DT_REG: - cde.d_type = __WASI_FILETYPE_REGULAR_FILE; - break; -#ifdef DT_SOCK - case DT_SOCK: - // Technically not correct, but good enough. - cde.d_type = __WASI_FILETYPE_SOCKET_STREAM; - break; -#endif - default: - cde.d_type = __WASI_FILETYPE_UNKNOWN; - break; + return *bufused > 0 ? __WASI_ESUCCESS : error; } + + fo->directory.offset = cde.d_next; + fd_readdir_put(buf, nbyte, bufused, &cde, sizeof(cde)); - fd_readdir_put(buf, nbyte, bufused, de->d_name, namlen); + fd_readdir_put(buf, nbyte, bufused, d_name, cde.d_namlen); } mutex_unlock(&fo->directory.lock); fd_object_release(exec_env, fo); - return 0; + return __WASI_ESUCCESS; } __wasi_errno_t @@ -2179,21 +1770,18 @@ wasmtime_ssp_path_readlink(wasm_exec_env_t exec_env, struct fd_table *curfds, char *buf, size_t bufsize, size_t *bufused) { struct path_access pa; - __wasi_errno_t error = path_get_nofollow( - curfds, &pa, fd, path, pathlen, __WASI_RIGHT_PATH_READLINK, 0, false); + __wasi_errno_t error = + path_get_nofollow(exec_env, curfds, &pa, fd, path, pathlen, + __WASI_RIGHT_PATH_READLINK, 0, false); + if (error != 0) return error; - // Linux requires that the buffer size is positive. whereas POSIX does - // not. Use a fake buffer to store the results if the size is zero. - char fakebuf[1]; - ssize_t len = readlinkat(pa.fd, pa.path, bufsize == 0 ? fakebuf : buf, - bufsize == 0 ? sizeof(fakebuf) : bufsize); + error = os_readlinkat(pa.fd, pa.path, buf, bufsize, bufused); + path_put(&pa); - if (len < 0) - return convert_errno(errno); - *bufused = (size_t)len < bufsize ? (size_t)len : bufsize; - return 0; + + return error; } __wasi_errno_t @@ -2203,42 +1791,27 @@ wasmtime_ssp_path_rename(wasm_exec_env_t exec_env, struct fd_table *curfds, const char *new_path, size_t new_path_len) { struct path_access old_pa; - __wasi_errno_t error = - path_get_nofollow(curfds, &old_pa, old_fd, old_path, old_path_len, - __WASI_RIGHT_PATH_RENAME_SOURCE, 0, true); + __wasi_errno_t error = path_get_nofollow( + exec_env, curfds, &old_pa, old_fd, old_path, old_path_len, + __WASI_RIGHT_PATH_RENAME_SOURCE, 0, true); if (error != 0) return error; struct path_access new_pa; - error = path_get_nofollow(curfds, &new_pa, new_fd, new_path, new_path_len, - __WASI_RIGHT_PATH_RENAME_TARGET, 0, true); + error = path_get_nofollow(exec_env, curfds, &new_pa, new_fd, new_path, + new_path_len, __WASI_RIGHT_PATH_RENAME_TARGET, 0, + true); if (error != 0) { path_put(&old_pa); return error; } - int ret = renameat(old_pa.fd, old_pa.path, new_pa.fd, new_pa.path); + error = os_renameat(old_pa.fd, old_pa.path, new_pa.fd, new_pa.path); + path_put(&old_pa); path_put(&new_pa); - if (ret < 0) { - return convert_errno(errno); - } - return 0; -} -// Converts a POSIX stat structure to a CloudABI filestat structure. -static void -convert_stat(const struct stat *in, __wasi_filestat_t *out) -{ - *out = (__wasi_filestat_t){ - .st_dev = in->st_dev, - .st_ino = in->st_ino, - .st_nlink = (__wasi_linkcount_t)in->st_nlink, - .st_size = (__wasi_filesize_t)in->st_size, - .st_atim = convert_timespec(&in->st_atim), - .st_mtim = convert_timespec(&in->st_mtim), - .st_ctim = convert_timespec(&in->st_ctim), - }; + return error; } __wasi_errno_t @@ -2248,24 +1821,15 @@ wasmtime_ssp_fd_filestat_get(wasm_exec_env_t exec_env, struct fd_table *curfds, struct fd_object *fo; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_FILESTAT_GET, 0); + if (error != 0) return error; - int ret; - switch (fo->type) { - default: - { - struct stat sb; - ret = fstat(fd_number(fo), &sb); - convert_stat(&sb, buf); - break; - } - } - buf->st_filetype = fo->type; + error = os_fstat(fo->file_handle, buf); + fd_object_release(exec_env, fo); - if (ret < 0) - return convert_errno(errno); - return 0; + + return error; } static void @@ -2283,34 +1847,6 @@ convert_timestamp(__wasi_timestamp_t in, struct timespec *out) out->tv_sec = (time_t)in < BH_TIME_T_MAX ? (time_t)in : BH_TIME_T_MAX; } -// Converts the provided timestamps and flags to a set of arguments for -// futimens() and utimensat(). -static void -convert_utimens_arguments(__wasi_timestamp_t st_atim, - __wasi_timestamp_t st_mtim, - __wasi_fstflags_t fstflags, struct timespec *ts) -{ - if ((fstflags & __WASI_FILESTAT_SET_ATIM_NOW) != 0) { - ts[0].tv_nsec = UTIME_NOW; - } - else if ((fstflags & __WASI_FILESTAT_SET_ATIM) != 0) { - convert_timestamp(st_atim, &ts[0]); - } - else { - ts[0].tv_nsec = UTIME_OMIT; - } - - if ((fstflags & __WASI_FILESTAT_SET_MTIM_NOW) != 0) { - ts[1].tv_nsec = UTIME_NOW; - } - else if ((fstflags & __WASI_FILESTAT_SET_MTIM) != 0) { - convert_timestamp(st_mtim, &ts[1]); - } - else { - ts[1].tv_nsec = UTIME_OMIT; - } -} - __wasi_errno_t wasmtime_ssp_fd_filestat_set_size(wasm_exec_env_t exec_env, struct fd_table *curfds, __wasi_fd_t fd, @@ -2319,14 +1855,14 @@ wasmtime_ssp_fd_filestat_set_size(wasm_exec_env_t exec_env, struct fd_object *fo; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_FILESTAT_SET_SIZE, 0); + if (error != 0) return error; - int ret = ftruncate(fd_number(fo), (off_t)st_size); + error = os_ftruncate(fo->file_handle, st_size); fd_object_release(exec_env, fo); - if (ret < 0) - return convert_errno(errno); - return 0; + + return error; } __wasi_errno_t @@ -2348,14 +1884,11 @@ wasmtime_ssp_fd_filestat_set_times(wasm_exec_env_t exec_env, if (error != 0) return error; - struct timespec ts[2]; - convert_utimens_arguments(st_atim, st_mtim, fstflags, ts); - int ret = futimens(fd_number(fo), ts); + error = os_futimens(fo->file_handle, st_atim, st_mtim, fstflags); fd_object_release(exec_env, fo); - if (ret < 0) - return convert_errno(errno); - return 0; + + return error; } __wasi_errno_t @@ -2365,35 +1898,18 @@ wasmtime_ssp_path_filestat_get(wasm_exec_env_t exec_env, size_t pathlen, __wasi_filestat_t *buf) { struct path_access pa; - __wasi_errno_t error = path_get(curfds, &pa, fd, flags, path, pathlen, - __WASI_RIGHT_PATH_FILESTAT_GET, 0, false); + __wasi_errno_t error = + path_get(exec_env, curfds, &pa, fd, flags, path, pathlen, + __WASI_RIGHT_PATH_FILESTAT_GET, 0, false); if (error != 0) return error; - struct stat sb; - int ret = fstatat(pa.fd, pa.path, &sb, pa.follow ? 0 : AT_SYMLINK_NOFOLLOW); - path_put(&pa); - if (ret < 0) - return convert_errno(errno); - convert_stat(&sb, buf); + error = os_fstatat(pa.fd, pa.path, buf, + pa.follow ? __WASI_LOOKUP_SYMLINK_FOLLOW : 0); - // Convert the file type. In the case of sockets there is no way we - // can easily determine the exact socket type. - if (S_ISBLK(sb.st_mode)) - buf->st_filetype = __WASI_FILETYPE_BLOCK_DEVICE; - else if (S_ISCHR(sb.st_mode)) - buf->st_filetype = __WASI_FILETYPE_CHARACTER_DEVICE; - else if (S_ISDIR(sb.st_mode)) - buf->st_filetype = __WASI_FILETYPE_DIRECTORY; - else if (S_ISFIFO(sb.st_mode)) - buf->st_filetype = __WASI_FILETYPE_SOCKET_STREAM; - else if (S_ISLNK(sb.st_mode)) - buf->st_filetype = __WASI_FILETYPE_SYMBOLIC_LINK; - else if (S_ISREG(sb.st_mode)) - buf->st_filetype = __WASI_FILETYPE_REGULAR_FILE; - else if (S_ISSOCK(sb.st_mode)) - buf->st_filetype = __WASI_FILETYPE_SOCKET_STREAM; - return 0; + path_put(&pa); + + return error; } __wasi_errno_t @@ -2419,20 +1935,16 @@ wasmtime_ssp_path_filestat_set_times(wasm_exec_env_t exec_env, struct path_access pa; __wasi_errno_t error = - path_get(curfds, &pa, fd, flags, path, pathlen, + path_get(exec_env, curfds, &pa, fd, flags, path, pathlen, __WASI_RIGHT_PATH_FILESTAT_SET_TIMES, 0, false); if (error != 0) return error; - struct timespec ts[2]; - convert_utimens_arguments(st_atim, st_mtim, fstflags, ts); - int ret = - utimensat(pa.fd, pa.path, ts, pa.follow ? 0 : AT_SYMLINK_NOFOLLOW); + error = os_utimensat(pa.fd, pa.path, st_atim, st_mtim, fstflags, + pa.follow ? __WASI_LOOKUP_SYMLINK_FOLLOW : 0); path_put(&pa); - if (ret < 0) - return convert_errno(errno); - return 0; + return error; } __wasi_errno_t @@ -2447,7 +1959,7 @@ wasmtime_ssp_path_symlink(wasm_exec_env_t exec_env, struct fd_table *curfds, struct path_access pa; __wasi_errno_t error = - path_get_nofollow(curfds, &pa, fd, new_path, new_path_len, + path_get_nofollow(exec_env, curfds, &pa, fd, new_path, new_path_len, __WASI_RIGHT_PATH_SYMLINK, 0, true); if (error != 0) { wasm_runtime_free(target); @@ -2462,12 +1974,12 @@ wasmtime_ssp_path_symlink(wasm_exec_env_t exec_env, struct fd_table *curfds, } rwlock_unlock(&prestats->lock); - int ret = symlinkat(target, pa.fd, pa.path); + error = os_symlinkat(target, pa.fd, pa.path); + path_put(&pa); wasm_runtime_free(target); - if (ret < 0) - return convert_errno(errno); - return 0; + + return error; } __wasi_errno_t @@ -2475,33 +1987,17 @@ wasmtime_ssp_path_unlink_file(wasm_exec_env_t exec_env, struct fd_table *curfds, __wasi_fd_t fd, const char *path, size_t pathlen) { struct path_access pa; - __wasi_errno_t error = path_get_nofollow( - curfds, &pa, fd, path, pathlen, __WASI_RIGHT_PATH_UNLINK_FILE, 0, true); - if (error != 0) + __wasi_errno_t error = + path_get_nofollow(exec_env, curfds, &pa, fd, path, pathlen, + __WASI_RIGHT_PATH_UNLINK_FILE, 0, true); + if (error != __WASI_ESUCCESS) return error; - int ret = unlinkat(pa.fd, pa.path, 0); -#ifndef __linux__ - // Non-Linux implementations may return EPERM when attempting to remove a - // directory without REMOVEDIR. While that's what POSIX specifies, it's - // less useful. Adjust this to EISDIR. It doesn't matter that this is not - // atomic with the unlinkat, because if the file is removed and a directory - // is created before fstatat sees it, we're racing with that change anyway - // and unlinkat could have legitimately seen the directory if the race had - // turned out differently. - if (ret < 0 && errno == EPERM) { - struct stat statbuf; - if (fstatat(pa.fd, pa.path, &statbuf, AT_SYMLINK_NOFOLLOW) == 0 - && S_ISDIR(statbuf.st_mode)) { - errno = EISDIR; - } - } -#endif + error = os_unlinkat(pa.fd, pa.path, false); + path_put(&pa); - if (ret < 0) { - return convert_errno(errno); - } - return 0; + + return error; } __wasi_errno_t @@ -2511,24 +2007,16 @@ wasmtime_ssp_path_remove_directory(wasm_exec_env_t exec_env, { struct path_access pa; __wasi_errno_t error = - path_get_nofollow(curfds, &pa, fd, path, pathlen, + path_get_nofollow(exec_env, curfds, &pa, fd, path, pathlen, __WASI_RIGHT_PATH_REMOVE_DIRECTORY, 0, true); if (error != 0) return error; - int ret = unlinkat(pa.fd, pa.path, AT_REMOVEDIR); -#ifndef __linux__ - // POSIX permits either EEXIST or ENOTEMPTY when the directory is not empty. - // Map it to ENOTEMPTY. - if (ret < 0 && errno == EEXIST) { - errno = ENOTEMPTY; - } -#endif + error = os_unlinkat(pa.fd, pa.path, true); + path_put(&pa); - if (ret < 0) { - return convert_errno(errno); - } - return 0; + + return error; } __wasi_errno_t @@ -2537,6 +2025,9 @@ wasmtime_ssp_poll_oneoff(wasm_exec_env_t exec_env, struct fd_table *curfds, size_t nsubscriptions, size_t *nevents) NO_LOCK_ANALYSIS { +#ifdef BH_PLATFORM_WINDOWS + return __WASI_ENOSYS; +#else // Sleeping. if (nsubscriptions == 1 && in[0].u.type == __WASI_EVENTTYPE_CLOCK) { out[0] = (__wasi_event_t){ @@ -2545,7 +2036,7 @@ wasmtime_ssp_poll_oneoff(wasm_exec_env_t exec_env, struct fd_table *curfds, }; #if CONFIG_HAS_CLOCK_NANOSLEEP clockid_t clock_id; - if (convert_clockid(in[0].u.u.clock.clock_id, &clock_id)) { + if (wasi_clockid_to_clockid(in[0].u.u.clock.clock_id, &clock_id)) { struct timespec ts; convert_timestamp(in[0].u.u.clock.timeout, &ts); int ret = clock_nanosleep( @@ -2652,7 +2143,7 @@ wasmtime_ssp_poll_oneoff(wasm_exec_env_t exec_env, struct fd_table *curfds, if (error == 0) { // Proper file descriptor on which we can poll(). pfds[i] = (struct pollfd){ - .fd = fd_number(fos[i]), + .fd = fos[i]->file_handle, .events = s->u.type == __WASI_EVENTTYPE_FD_READ ? POLLIN : POLLOUT, @@ -2708,6 +2199,7 @@ wasmtime_ssp_poll_oneoff(wasm_exec_env_t exec_env, struct fd_table *curfds, else { timeout = -1; } + int ret = poll(pfds, nsubscriptions, timeout); __wasi_errno_t error = 0; @@ -2728,7 +2220,7 @@ wasmtime_ssp_poll_oneoff(wasm_exec_env_t exec_env, struct fd_table *curfds, __wasi_filesize_t nbytes = 0; if (in[i].u.type == __WASI_EVENTTYPE_FD_READ) { int l; - if (ioctl(fd_number(fos[i]), FIONREAD, &l) == 0) + if (ioctl(fos[i]->file_handle, FIONREAD, &l) == 0) nbytes = (__wasi_filesize_t)l; } if ((pfds[i].revents & POLLNVAL) != 0) { @@ -2784,6 +2276,7 @@ wasmtime_ssp_poll_oneoff(wasm_exec_env_t exec_env, struct fd_table *curfds, wasm_runtime_free(fos); wasm_runtime_free(pfds); return error; +#endif } __wasi_errno_t @@ -2801,7 +2294,7 @@ wasi_ssp_sock_accept(wasm_exec_env_t exec_env, struct fd_table *curfds, __wasi_filetype_t wasi_type; __wasi_rights_t max_base, max_inheriting; struct fd_object *fo; - bh_socket_t new_sock = -1; + bh_socket_t new_sock = os_get_invalid_handle(); int ret; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, __WASI_RIGHT_SOCK_ACCEPT, 0); @@ -2809,7 +2302,7 @@ wasi_ssp_sock_accept(wasm_exec_env_t exec_env, struct fd_table *curfds, goto fail; } - ret = blocking_op_socket_accept(exec_env, fd_number(fo), &new_sock, NULL, + ret = blocking_op_socket_accept(exec_env, fo->file_handle, &new_sock, NULL, NULL); fd_object_release(exec_env, fo); if (BHT_OK != ret) { @@ -2827,14 +2320,14 @@ wasi_ssp_sock_accept(wasm_exec_env_t exec_env, struct fd_table *curfds, max_inheriting, fd_new); if (error != __WASI_ESUCCESS) { /* released in fd_table_insert_fd() */ - new_sock = -1; + new_sock = os_get_invalid_handle(); goto fail; } return __WASI_ESUCCESS; fail: - if (-1 != new_sock) { + if (os_is_handle_valid(&new_sock)) { os_socket_close(new_sock); } return error; @@ -2853,7 +2346,7 @@ wasi_ssp_sock_addr_local(wasm_exec_env_t exec_env, struct fd_table *curfds, if (error != __WASI_ESUCCESS) return error; - ret = os_socket_addr_local(fd_number(fo), &bh_addr); + ret = os_socket_addr_local(fo->file_handle, &bh_addr); fd_object_release(exec_env, fo); if (ret != BHT_OK) { return convert_errno(errno); @@ -2877,7 +2370,7 @@ wasi_ssp_sock_addr_remote(wasm_exec_env_t exec_env, struct fd_table *curfds, if (error != __WASI_ESUCCESS) return error; - ret = os_socket_addr_remote(fd_number(fo), &bh_addr); + ret = os_socket_addr_remote(fo->file_handle, &bh_addr); fd_object_release(exec_env, fo); if (ret != BHT_OK) { return convert_errno(errno); @@ -2940,7 +2433,7 @@ wasi_ssp_sock_bind(wasm_exec_env_t exec_env, struct fd_table *curfds, if (error != __WASI_ESUCCESS) return error; - ret = os_socket_bind(fd_number(fo), buf, &port); + ret = os_socket_bind(fo->file_handle, buf, &port); fd_object_release(exec_env, fo); if (BHT_OK != ret) { return convert_errno(errno); @@ -3023,7 +2516,7 @@ wasi_ssp_sock_connect(wasm_exec_env_t exec_env, struct fd_table *curfds, if (error != __WASI_ESUCCESS) return error; - ret = blocking_op_socket_connect(exec_env, fd_number(fo), buf, + ret = blocking_op_socket_connect(exec_env, fo->file_handle, buf, addr->kind == IPv4 ? addr->addr.ip4.port : addr->addr.ip6.port); fd_object_release(exec_env, fo); @@ -3040,21 +2533,18 @@ wasi_ssp_sock_get_recv_buf_size(wasm_exec_env_t exec_env, __wasi_size_t *size) { struct fd_object *fo; - int ret; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, 0, 0); if (error != __WASI_ESUCCESS) return error; - int optval; - socklen_t optlen = sizeof(optval); - - ret = getsockopt(fd_number(fo), SOL_SOCKET, SO_RCVBUF, &optval, &optlen); + size_t bufsize = 0; + int ret = os_socket_get_recv_buf_size(fo->file_handle, &bufsize); fd_object_release(exec_env, fo); if (BHT_OK != ret) { return convert_errno(errno); } - *size = optval; + *size = (__wasi_size_t)bufsize; return __WASI_ESUCCESS; } @@ -3063,23 +2553,20 @@ __wasi_errno_t wasi_ssp_sock_get_reuse_addr(wasm_exec_env_t exec_env, struct fd_table *curfds, __wasi_fd_t fd, uint8_t *reuse) { - struct fd_object *fo; - int ret; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, 0, 0); if (error != __WASI_ESUCCESS) return error; - int optval; - socklen_t optlen = sizeof(optval); + bool enabled = false; - ret = getsockopt(fd_number(fo), SOL_SOCKET, SO_REUSEADDR, &optval, &optlen); + int ret = os_socket_get_reuse_addr(fo->file_handle, &enabled); fd_object_release(exec_env, fo); if (BHT_OK != ret) { return convert_errno(errno); } - *reuse = optval; + *reuse = (uint8_t)enabled; return __WASI_ESUCCESS; } @@ -3089,28 +2576,19 @@ wasi_ssp_sock_get_reuse_port(wasm_exec_env_t exec_env, struct fd_table *curfds, __wasi_fd_t fd, uint8_t *reuse) { struct fd_object *fo; - int ret; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, 0, 0); if (error != __WASI_ESUCCESS) return error; - int optval; - socklen_t optlen = sizeof(optval); - -#if defined(SO_REUSEPORT) /* NuttX doesn't have SO_REUSEPORT */ - ret = getsockopt(fd_number(fo), SOL_SOCKET, SO_REUSEPORT, &optval, &optlen); -#else - errno = ENOTSUP; - ret = BHT_ERROR; - optval = 0; -#endif /* defined(SO_REUSEPORT) */ + bool enabled = false; + int ret = os_socket_get_reuse_port(fo->file_handle, &enabled); fd_object_release(exec_env, fo); if (BHT_OK != ret) { return convert_errno(errno); } - *reuse = optval; + *reuse = (uint8_t)enabled; return __WASI_ESUCCESS; } @@ -3121,21 +2599,19 @@ wasi_ssp_sock_get_send_buf_size(wasm_exec_env_t exec_env, __wasi_size_t *size) { struct fd_object *fo; - int ret; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, 0, 0); if (error != __WASI_ESUCCESS) return error; - int optval; - socklen_t optlen = sizeof(optval); + size_t bufsize = 0; + int ret = os_socket_get_send_buf_size(fo->file_handle, &bufsize); - ret = getsockopt(fd_number(fo), SOL_SOCKET, SO_SNDBUF, &optval, &optlen); fd_object_release(exec_env, fo); if (BHT_OK != ret) { return convert_errno(errno); } - *size = optval; + *size = (__wasi_size_t)bufsize; return __WASI_ESUCCESS; } @@ -3151,7 +2627,7 @@ wasi_ssp_sock_listen(wasm_exec_env_t exec_env, struct fd_table *curfds, if (error != __WASI_ESUCCESS) return error; - ret = os_socket_listen(fd_number(fo), backlog); + ret = os_socket_listen(fo->file_handle, backlog); fd_object_release(exec_env, fo); if (BHT_OK != ret) { return convert_errno(errno); @@ -3210,15 +2686,12 @@ wasi_ssp_sock_set_recv_buf_size(wasm_exec_env_t exec_env, __wasi_size_t size) { struct fd_object *fo; - int ret; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, 0, 0); if (error != __WASI_ESUCCESS) return error; - int optval = size; + int ret = os_socket_set_recv_buf_size(fo->file_handle, size); - ret = setsockopt(fd_number(fo), SOL_SOCKET, SO_RCVBUF, &optval, - sizeof(optval)); fd_object_release(exec_env, fo); if (BHT_OK != ret) { return convert_errno(errno); @@ -3232,15 +2705,12 @@ wasi_ssp_sock_set_reuse_addr(wasm_exec_env_t exec_env, struct fd_table *curfds, __wasi_fd_t fd, uint8_t reuse) { struct fd_object *fo; - int ret; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, 0, 0); if (error != __WASI_ESUCCESS) return error; - int optval = reuse; + int ret = os_socket_set_reuse_addr(fo->file_handle, (bool)reuse); - ret = setsockopt(fd_number(fo), SOL_SOCKET, SO_REUSEADDR, &optval, - sizeof(optval)); fd_object_release(exec_env, fo); if (BHT_OK != ret) { return convert_errno(errno); @@ -3254,20 +2724,11 @@ wasi_ssp_sock_set_reuse_port(wasm_exec_env_t exec_env, struct fd_table *curfds, __wasi_fd_t fd, uint8_t reuse) { struct fd_object *fo; - int ret; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, 0, 0); if (error != __WASI_ESUCCESS) return error; - int optval = reuse; - -#if defined(SO_REUSEPORT) /* NuttX doesn't have SO_REUSEPORT */ - ret = setsockopt(fd_number(fo), SOL_SOCKET, SO_REUSEPORT, &optval, - sizeof(optval)); -#else - errno = ENOTSUP; - ret = BHT_ERROR; -#endif /* defined(SO_REUSEPORT) */ + int ret = os_socket_set_reuse_port(fo->file_handle, (bool)reuse); fd_object_release(exec_env, fo); if (BHT_OK != ret) { @@ -3283,15 +2744,11 @@ wasi_ssp_sock_set_send_buf_size(wasm_exec_env_t exec_env, __wasi_size_t size) { struct fd_object *fo; - int ret; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, 0, 0); if (error != __WASI_ESUCCESS) return error; - int optval = size; - - ret = setsockopt(fd_number(fo), SOL_SOCKET, SO_SNDBUF, &optval, - sizeof(optval)); + int ret = os_socket_set_send_buf_size(fo->file_handle, size); fd_object_release(exec_env, fo); if (BHT_OK != ret) { @@ -3328,8 +2785,8 @@ wasmtime_ssp_sock_recv_from(wasm_exec_env_t exec_env, struct fd_table *curfds, return error; } - ret = blocking_op_socket_recv_from(exec_env, fd_number(fo), buf, buf_len, 0, - &sockaddr); + ret = blocking_op_socket_recv_from(exec_env, fo->file_handle, buf, buf_len, + 0, &sockaddr); fd_object_release(exec_env, fo); if (-1 == ret) { return convert_errno(errno); @@ -3355,7 +2812,7 @@ wasmtime_ssp_sock_send(wasm_exec_env_t exec_env, struct fd_table *curfds, return error; } - ret = os_socket_send(fd_number(fo), buf, buf_len); + ret = os_socket_send(fo->file_handle, buf, buf_len); fd_object_release(exec_env, fo); if (-1 == ret) { return convert_errno(errno); @@ -3393,7 +2850,7 @@ wasmtime_ssp_sock_send_to(wasm_exec_env_t exec_env, struct fd_table *curfds, wasi_addr_to_bh_sockaddr(dest_addr, &sockaddr); - ret = blocking_op_socket_send_to(exec_env, fd_number(fo), buf, buf_len, 0, + ret = blocking_op_socket_send_to(exec_env, fo->file_handle, buf, buf_len, 0, &sockaddr); fd_object_release(exec_env, fo); if (-1 == ret) { @@ -3416,7 +2873,7 @@ wasmtime_ssp_sock_shutdown(wasm_exec_env_t exec_env, struct fd_table *curfds, if (error != 0) return error; - ret = os_socket_shutdown(fd_number(fo)); + ret = os_socket_shutdown(fo->file_handle); fd_object_release(exec_env, fo); if (BHT_OK != ret) return convert_errno(errno); @@ -3427,8 +2884,12 @@ wasmtime_ssp_sock_shutdown(wasm_exec_env_t exec_env, struct fd_table *curfds, __wasi_errno_t wasmtime_ssp_sched_yield(void) { +#ifdef BH_PLATFORM_WINDOWS + SwitchToThread(); +#else if (sched_yield() < 0) return convert_errno(errno); +#endif return 0; } @@ -3457,14 +2918,14 @@ wasmtime_ssp_args_sizes_get(struct argv_environ_values *argv_environ, __wasi_errno_t wasmtime_ssp_environ_get(struct argv_environ_values *argv_environ, - char **environ, char *environ_buf) + char **environs, char *environ_buf) { for (size_t i = 0; i < argv_environ->environ_count; ++i) { - environ[i] = + environs[i] = environ_buf + (argv_environ->environ_list[i] - argv_environ->environ_buf); } - environ[argv_environ->environ_count] = NULL; + environs[argv_environ->environ_count] = NULL; bh_memcpy_s(environ_buf, (uint32)argv_environ->environ_buf_size, argv_environ->environ_buf, (uint32)argv_environ->environ_buf_size); @@ -3580,12 +3041,6 @@ addr_pool_insert(struct addr_pool *addr_pool, const char *addr, uint8 mask) return true; } -static inline size_t -min(size_t a, size_t b) -{ - return a > b ? b : a; -} - static void init_address_mask(uint8_t *buf, size_t buflen, size_t mask) { @@ -3714,7 +3169,7 @@ addr_pool_destroy(struct addr_pool *addr_pool) error = fd_object_get(curfds, &fo, sock, 0, 0); \ if (error != 0) \ return error; \ - ret = os_socket_##FUNC_NAME(fd_number(fo), option); \ + ret = os_socket_##FUNC_NAME(fo->file_handle, option); \ fd_object_release(exec_env, fo); \ if (BHT_OK != ret) \ return convert_errno(errno); \ @@ -3768,7 +3223,7 @@ wasmtime_ssp_sock_set_linger(wasm_exec_env_t exec_env, struct fd_table *curfds, if (error != 0) return error; - ret = os_socket_set_linger(fd_number(fo), is_enabled, linger_s); + ret = os_socket_set_linger(fo->file_handle, is_enabled, linger_s); fd_object_release(exec_env, fo); if (BHT_OK != ret) return convert_errno(errno); @@ -3786,7 +3241,7 @@ wasmtime_ssp_sock_get_linger(wasm_exec_env_t exec_env, struct fd_table *curfds, if (error != 0) return error; - ret = os_socket_get_linger(fd_number(fo), is_enabled, linger_s); + ret = os_socket_get_linger(fo->file_handle, is_enabled, linger_s); fd_object_release(exec_env, fo); if (BHT_OK != ret) return convert_errno(errno); @@ -3812,7 +3267,7 @@ wasmtime_ssp_sock_set_ip_add_membership(wasm_exec_env_t exec_env, wasi_addr_ip_to_bh_ip_addr_buffer(imr_multiaddr, &addr_info); is_ipv6 = imr_multiaddr->kind == IPv6; - ret = os_socket_set_ip_add_membership(fd_number(fo), &addr_info, + ret = os_socket_set_ip_add_membership(fo->file_handle, &addr_info, imr_interface, is_ipv6); fd_object_release(exec_env, fo); if (BHT_OK != ret) @@ -3838,7 +3293,7 @@ wasmtime_ssp_sock_set_ip_drop_membership(wasm_exec_env_t exec_env, wasi_addr_ip_to_bh_ip_addr_buffer(imr_multiaddr, &addr_info); is_ipv6 = imr_multiaddr->kind == IPv6; - ret = os_socket_set_ip_drop_membership(fd_number(fo), &addr_info, + ret = os_socket_set_ip_drop_membership(fo->file_handle, &addr_info, imr_interface, is_ipv6); fd_object_release(exec_env, fo); if (BHT_OK != ret) @@ -3859,7 +3314,7 @@ wasmtime_ssp_sock_set_ip_multicast_loop(wasm_exec_env_t exec_env, if (error != 0) return error; - ret = os_socket_set_ip_multicast_loop(fd_number(fo), ipv6, is_enabled); + ret = os_socket_set_ip_multicast_loop(fo->file_handle, ipv6, is_enabled); fd_object_release(exec_env, fo); if (BHT_OK != ret) return convert_errno(errno); @@ -3879,7 +3334,7 @@ wasmtime_ssp_sock_get_ip_multicast_loop(wasm_exec_env_t exec_env, if (error != 0) return error; - ret = os_socket_get_ip_multicast_loop(fd_number(fo), ipv6, is_enabled); + ret = os_socket_get_ip_multicast_loop(fo->file_handle, ipv6, is_enabled); fd_object_release(exec_env, fo); if (BHT_OK != ret) return convert_errno(errno); diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.h index 7a593390a..75ed59784 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.h @@ -60,7 +60,8 @@ struct addr_pool { bool fd_table_init(struct fd_table *); bool -fd_table_insert_existing(struct fd_table *, __wasi_fd_t, int); +fd_table_insert_existing(struct fd_table *, __wasi_fd_t, os_file_handle, + bool is_stdio); bool fd_prestats_init(struct fd_prestats *); bool diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.c b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.c index 01a1dab3a..b21aa197a 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.c +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.c @@ -47,6 +47,23 @@ random_buf(void *buf, size_t len) } } +#elif defined(BH_PLATFORM_WINDOWS) + +#include + +void +random_buf(void *buf, size_t len) +{ + static int crypt_initialized = 0; + static HCRYPTPROV provider; + if (!crypt_initialized) { + CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT); + crypt_initialized = 1; + } + CryptGenRandom(provider, len, buf); +} + #else static int urandom; diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h index 6a1db8690..bcc750c26 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h @@ -47,75 +47,19 @@ #define CONFIG_HAS_CLOCK_NANOSLEEP 0 #endif -#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(ESP_PLATFORM) -#define CONFIG_HAS_FDATASYNC 1 -#else -#define CONFIG_HAS_FDATASYNC 0 -#endif - -/* - * For NuttX, CONFIG_HAS_ISATTY is provided by its platform header. - * (platform_internal.h) - */ -#ifndef __NuttX__ -#ifndef __CloudABI__ -#define CONFIG_HAS_ISATTY 1 -#else -#define CONFIG_HAS_ISATTY 0 -#endif -#endif - -#if !defined(__APPLE__) && !defined(ESP_PLATFORM) && !defined(__COSMOPOLITAN__) -#define CONFIG_HAS_POSIX_FALLOCATE 1 -#else -#define CONFIG_HAS_POSIX_FALLOCATE 0 -#endif - -#if !defined(__APPLE__) && !defined(ESP_PLATFORM) -#define CONFIG_HAS_PREADV 1 -#else -#define CONFIG_HAS_PREADV 0 -#endif - #if defined(__APPLE__) || defined(__CloudABI__) #define CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP 1 #else #define CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP 0 #endif -#if !defined(__APPLE__) && !defined(BH_PLATFORM_LINUX_SGX) \ +#if !defined(__APPLE__) && !defined(BH_PLATFORM_LINUX_SGX) && !defined(_WIN32) \ && !defined(__COSMOPOLITAN__) #define CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK 1 #else #define CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK 0 #endif -#if !defined(__APPLE__) && !defined(ESP_PLATFORM) -#define CONFIG_HAS_PWRITEV 1 -#else -#define CONFIG_HAS_PWRITEV 0 -#endif - -#ifdef __APPLE__ -#define st_atim st_atimespec -#define st_ctim st_ctimespec -#define st_mtim st_mtimespec -#endif - -#if defined(O_DSYNC) -#define CONFIG_HAS_O_DSYNC -#endif - -// POSIX requires O_RSYNC to be defined, but Linux explicitly doesn't support -// it. -#if defined(O_RSYNC) && !defined(__linux__) -#define CONFIG_HAS_O_RSYNC -#endif - -#if defined(O_SYNC) -#define CONFIG_HAS_O_SYNC -#endif - #if !defined(BH_PLATFORM_LINUX_SGX) /* Clang's __GNUC_PREREQ macro has a different meaning than GCC one, so we have to handle this case specially */ @@ -143,10 +87,4 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58016 */ #define CONFIG_HAS_STD_ATOMIC 0 #endif /* end of !defined(BH_PLATFORM_LINUX_SGX) */ -#if !defined(__NuttX__) -#define CONFIG_HAS_D_INO 1 -#else -#define CONFIG_HAS_D_INO 0 -#endif - #endif diff --git a/core/iwasm/libraries/thread-mgr/thread_manager.c b/core/iwasm/libraries/thread-mgr/thread_manager.c index 49545de72..dbf002468 100644 --- a/core/iwasm/libraries/thread-mgr/thread_manager.c +++ b/core/iwasm/libraries/thread-mgr/thread_manager.c @@ -1406,3 +1406,19 @@ exception_unlock(WASMModuleInstance *module_inst) { os_mutex_unlock(&_exception_lock); } + +void +wasm_cluster_traverse_lock(WASMExecEnv *exec_env) +{ + WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); + bh_assert(cluster); + os_mutex_lock(&cluster->lock); +} + +void +wasm_cluster_traverse_unlock(WASMExecEnv *exec_env) +{ + WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); + bh_assert(cluster); + os_mutex_unlock(&cluster->lock); +} diff --git a/core/iwasm/libraries/thread-mgr/thread_manager.h b/core/iwasm/libraries/thread-mgr/thread_manager.h index 19186f597..b95f434ae 100644 --- a/core/iwasm/libraries/thread-mgr/thread_manager.h +++ b/core/iwasm/libraries/thread-mgr/thread_manager.h @@ -215,6 +215,12 @@ wasm_cluster_set_debug_inst(WASMCluster *cluster, WASMDebugInstance *inst); #endif /* end of WASM_ENABLE_DEBUG_INTERP != 0 */ +void +wasm_cluster_traverse_lock(WASMExecEnv *exec_env); + +void +wasm_cluster_traverse_unlock(WASMExecEnv *exec_env); + #ifdef __cplusplus } #endif diff --git a/core/shared/mem-alloc/ems/ems_alloc.c b/core/shared/mem-alloc/ems/ems_alloc.c index a29539dd5..0e2c4da7c 100644 --- a/core/shared/mem-alloc/ems/ems_alloc.c +++ b/core/shared/mem-alloc/ems/ems_alloc.c @@ -24,19 +24,23 @@ hmu_is_in_heap(void *hmu, gc_uint8 *heap_base_addr, gc_uint8 *heap_end_addr) static bool remove_tree_node(gc_heap_t *heap, hmu_tree_node_t *p) { - hmu_tree_node_t *q = NULL, **slot = NULL, *parent; - hmu_tree_node_t *root = heap->kfc_tree_root; + hmu_tree_node_t *q = NULL, **slot = NULL; +#if BH_ENABLE_GC_CORRUPTION_CHECK != 0 + hmu_tree_node_t *root = heap->kfc_tree_root, *parent; gc_uint8 *base_addr = heap->base_addr; gc_uint8 *end_addr = base_addr + heap->current_size; +#endif bh_assert(p); +#if BH_ENABLE_GC_CORRUPTION_CHECK != 0 parent = p->parent; if (!parent || p == root /* p can not be the ROOT node */ || !hmu_is_in_heap(p, base_addr, end_addr) || (parent != root && !hmu_is_in_heap(parent, base_addr, end_addr))) { goto fail; } +#endif /* get the slot which holds pointer to node p */ if (p == p->parent->right) { @@ -67,9 +71,11 @@ remove_tree_node(gc_heap_t *heap, hmu_tree_node_t *p) /* move right child up*/ *slot = p->right; if (p->right) { +#if BH_ENABLE_GC_CORRUPTION_CHECK != 0 if (!hmu_is_in_heap(p->right, base_addr, end_addr)) { goto fail; } +#endif p->right->parent = p->parent; } @@ -80,9 +86,11 @@ remove_tree_node(gc_heap_t *heap, hmu_tree_node_t *p) if (!p->right) { /* move left child up*/ *slot = p->left; +#if BH_ENABLE_GC_CORRUPTION_CHECK != 0 if (!hmu_is_in_heap(p->left, base_addr, end_addr)) { goto fail; } +#endif /* p->left can never be NULL unless it is corrupted. */ p->left->parent = p->parent; @@ -92,14 +100,18 @@ remove_tree_node(gc_heap_t *heap, hmu_tree_node_t *p) /* both left & right exist, find p's predecessor at first*/ q = p->left; +#if BH_ENABLE_GC_CORRUPTION_CHECK != 0 if (!hmu_is_in_heap(q, base_addr, end_addr)) { goto fail; } +#endif while (q->right) { q = q->right; +#if BH_ENABLE_GC_CORRUPTION_CHECK != 0 if (!hmu_is_in_heap(q, base_addr, end_addr)) { goto fail; } +#endif } /* remove from the tree*/ @@ -111,15 +123,19 @@ remove_tree_node(gc_heap_t *heap, hmu_tree_node_t *p) q->left = p->left; q->right = p->right; if (q->left) { +#if BH_ENABLE_GC_CORRUPTION_CHECK != 0 if (!hmu_is_in_heap(q->left, base_addr, end_addr)) { goto fail; } +#endif q->left->parent = q; } if (q->right) { +#if BH_ENABLE_GC_CORRUPTION_CHECK != 0 if (!hmu_is_in_heap(q->right, base_addr, end_addr)) { goto fail; } +#endif q->right->parent = q; } @@ -127,27 +143,35 @@ remove_tree_node(gc_heap_t *heap, hmu_tree_node_t *p) return true; fail: +#if BH_ENABLE_GC_CORRUPTION_CHECK != 0 heap->is_heap_corrupted = true; +#endif return false; } static bool unlink_hmu(gc_heap_t *heap, hmu_t *hmu) { +#if BH_ENABLE_GC_CORRUPTION_CHECK != 0 gc_uint8 *base_addr, *end_addr; +#endif gc_size_t size; bh_assert(gci_is_heap_valid(heap)); bh_assert(hmu && (gc_uint8 *)hmu >= heap->base_addr && (gc_uint8 *)hmu < heap->base_addr + heap->current_size); +#if BH_ENABLE_GC_CORRUPTION_CHECK != 0 if (hmu_get_ut(hmu) != HMU_FC) { heap->is_heap_corrupted = true; return false; } +#endif +#if BH_ENABLE_GC_CORRUPTION_CHECK != 0 base_addr = heap->base_addr; end_addr = base_addr + heap->current_size; +#endif size = hmu_get_size(hmu); if (HMU_IS_FC_NORMAL(size)) { @@ -156,10 +180,12 @@ unlink_hmu(gc_heap_t *heap, hmu_t *hmu) hmu_normal_node_t *node = heap->kfc_normal_list[node_idx].next; while (node) { +#if BH_ENABLE_GC_CORRUPTION_CHECK != 0 if (!hmu_is_in_heap(node, base_addr, end_addr)) { heap->is_heap_corrupted = true; return false; } +#endif node_next = get_hmu_normal_node_next(node); if ((hmu_t *)node == hmu) { if (!node_prev) /* list head */ @@ -205,7 +231,9 @@ hmu_set_free_size(hmu_t *hmu) bool gci_add_fc(gc_heap_t *heap, hmu_t *hmu, gc_size_t size) { +#if BH_ENABLE_GC_CORRUPTION_CHECK != 0 gc_uint8 *base_addr, *end_addr; +#endif hmu_normal_node_t *np = NULL; hmu_tree_node_t *root = NULL, *tp = NULL, *node = NULL; uint32 node_idx; @@ -219,8 +247,10 @@ gci_add_fc(gc_heap_t *heap, hmu_t *hmu, gc_size_t size) <= heap->base_addr + heap->current_size); bh_assert(!(size & 7)); +#if BH_ENABLE_GC_CORRUPTION_CHECK != 0 base_addr = heap->base_addr; end_addr = base_addr + heap->current_size; +#endif hmu_set_ut(hmu, HMU_FC); hmu_set_size(hmu, size); @@ -228,10 +258,12 @@ gci_add_fc(gc_heap_t *heap, hmu_t *hmu, gc_size_t size) if (HMU_IS_FC_NORMAL(size)) { np = (hmu_normal_node_t *)hmu; +#if BH_ENABLE_GC_CORRUPTION_CHECK != 0 if (!hmu_is_in_heap(np, base_addr, end_addr)) { heap->is_heap_corrupted = true; return false; } +#endif node_idx = size >> 3; set_hmu_normal_node_next(np, heap->kfc_normal_list[node_idx].next); @@ -265,10 +297,12 @@ gci_add_fc(gc_heap_t *heap, hmu_t *hmu, gc_size_t size) } tp = tp->left; } +#if BH_ENABLE_GC_CORRUPTION_CHECK != 0 if (!hmu_is_in_heap(tp, base_addr, end_addr)) { heap->is_heap_corrupted = true; return false; } +#endif } return true; } @@ -321,15 +355,19 @@ alloc_hmu(gc_heap_t *heap, gc_size_t size) bh_assert(node_idx >= init_node_idx); p = normal_head->next; +#if BH_ENABLE_GC_CORRUPTION_CHECK != 0 if (!hmu_is_in_heap(p, base_addr, end_addr)) { heap->is_heap_corrupted = true; return NULL; } +#endif normal_head->next = get_hmu_normal_node_next(p); +#if BH_ENABLE_GC_CORRUPTION_CHECK != 0 if (((gc_int32)(uintptr_t)hmu_to_obj(p) & 7) != 0) { heap->is_heap_corrupted = true; return NULL; } +#endif if ((gc_size_t)node_idx != (uint32)init_node_idx /* with bigger size*/ @@ -365,10 +403,12 @@ alloc_hmu(gc_heap_t *heap, gc_size_t size) bh_assert(root); tp = root->right; while (tp) { +#if BH_ENABLE_GC_CORRUPTION_CHECK != 0 if (!hmu_is_in_heap(tp, base_addr, end_addr)) { heap->is_heap_corrupted = true; return NULL; } +#endif if (tp->size < size) { tp = tp->right; @@ -462,10 +502,12 @@ gc_alloc_vo_internal(void *vheap, gc_size_t size, const char *file, int line) /* integer overflow */ return NULL; +#if BH_ENABLE_GC_CORRUPTION_CHECK != 0 if (heap->is_heap_corrupted) { os_printf("[GC_ERROR]Heap is corrupted, allocate memory failed.\n"); return NULL; } +#endif os_mutex_lock(&heap->lock); @@ -522,10 +564,12 @@ gc_realloc_vo_internal(void *vheap, void *ptr, gc_size_t size, const char *file, /* integer overflow */ return NULL; +#if BH_ENABLE_GC_CORRUPTION_CHECK != 0 if (heap->is_heap_corrupted) { os_printf("[GC_ERROR]Heap is corrupted, allocate memory failed.\n"); return NULL; } +#endif if (obj_old) { hmu_old = obj_to_hmu(obj_old); @@ -647,10 +691,12 @@ gc_free_vo_internal(void *vheap, gc_object_t obj, const char *file, int line) return GC_SUCCESS; } +#if BH_ENABLE_GC_CORRUPTION_CHECK != 0 if (heap->is_heap_corrupted) { os_printf("[GC_ERROR]Heap is corrupted, free memory failed.\n"); return GC_ERROR; } +#endif hmu = obj_to_hmu(obj); @@ -767,11 +813,13 @@ gci_dump(gc_heap_t *heap) else if (ut == HMU_FC) inuse = 'F'; +#if BH_ENABLE_GC_CORRUPTION_CHECK != 0 if (size == 0 || size > (uint32)((uint8 *)end - (uint8 *)cur)) { os_printf("[GC_ERROR]Heap is corrupted, heap dump failed.\n"); heap->is_heap_corrupted = true; return; } +#endif os_printf("#%d %08" PRIx32 " %" PRIx32 " %d %d" " %c %" PRId32 "\n", @@ -788,8 +836,12 @@ gci_dump(gc_heap_t *heap) i++; } +#if BH_ENABLE_GC_CORRUPTION_CHECK != 0 if (cur != end) { os_printf("[GC_ERROR]Heap is corrupted, heap dump failed.\n"); heap->is_heap_corrupted = true; } +#else + bh_assert(cur == end); +#endif } diff --git a/core/shared/mem-alloc/ems/ems_gc_internal.h b/core/shared/mem-alloc/ems/ems_gc_internal.h index 68b505453..6abe2b12a 100644 --- a/core/shared/mem-alloc/ems/ems_gc_internal.h +++ b/core/shared/mem-alloc/ems/ems_gc_internal.h @@ -271,9 +271,11 @@ typedef struct gc_heap_struct { size[left] <= size[cur] < size[right] */ hmu_tree_node_t *kfc_tree_root; +#if BH_ENABLE_GC_CORRUPTION_CHECK != 0 /* whether heap is corrupted, e.g. the hmu nodes are modified by user */ bool is_heap_corrupted; +#endif gc_size_t init_size; gc_size_t highmark_size; diff --git a/core/shared/mem-alloc/ems/ems_hmu.c b/core/shared/mem-alloc/ems/ems_hmu.c index 41745e161..f9d7c0f4a 100644 --- a/core/shared/mem-alloc/ems/ems_hmu.c +++ b/core/shared/mem-alloc/ems/ems_hmu.c @@ -83,7 +83,9 @@ hmu_verify(void *vheap, hmu_t *hmu) os_printf("Invalid padding for object created at %s:%d\n", (prefix->file_name ? prefix->file_name : ""), prefix->line_no); +#if BH_ENABLE_GC_CORRUPTION_CHECK != 0 heap->is_heap_corrupted = true; +#endif } } } diff --git a/core/shared/mem-alloc/ems/ems_kfc.c b/core/shared/mem-alloc/ems/ems_kfc.c index 80d202679..1dda3ae03 100644 --- a/core/shared/mem-alloc/ems/ems_kfc.c +++ b/core/shared/mem-alloc/ems/ems_kfc.c @@ -133,8 +133,11 @@ gc_destroy_with_pool(gc_handle_t handle) hmu_t *cur = (hmu_t *)heap->base_addr; hmu_t *end = (hmu_t *)((char *)heap->base_addr + heap->current_size); - if (!heap->is_heap_corrupted - && (hmu_t *)((char *)cur + hmu_get_size(cur)) != end) { + if ( +#if BH_ENABLE_GC_CORRUPTION_CHECK != 0 + !heap->is_heap_corrupted && +#endif + (hmu_t *)((char *)cur + hmu_get_size(cur)) != end) { os_printf("Memory leak detected:\n"); gci_dump(heap); ret = GC_ERROR; @@ -186,10 +189,12 @@ gc_migrate(gc_handle_t handle, char *pool_buf_new, gc_size_t pool_buf_size) if (offset == 0) return 0; +#if BH_ENABLE_GC_CORRUPTION_CHECK != 0 if (heap->is_heap_corrupted) { os_printf("[GC_ERROR]Heap is corrupted, heap migrate failed.\n"); return GC_ERROR; } +#endif heap->base_addr = (uint8 *)base_addr_new; @@ -211,11 +216,13 @@ gc_migrate(gc_handle_t handle, char *pool_buf_new, gc_size_t pool_buf_size) while (cur < end) { size = hmu_get_size(cur); +#if BH_ENABLE_GC_CORRUPTION_CHECK != 0 if (size <= 0 || size > (uint32)((uint8 *)end - (uint8 *)cur)) { os_printf("[GC_ERROR]Heap is corrupted, heap migrate failed.\n"); heap->is_heap_corrupted = true; return GC_ERROR; } +#endif if (hmu_get_ut(cur) == HMU_FC && !HMU_IS_FC_NORMAL(size)) { tree_node = (hmu_tree_node_t *)cur; @@ -238,11 +245,15 @@ gc_migrate(gc_handle_t handle, char *pool_buf_new, gc_size_t pool_buf_size) cur = (hmu_t *)((char *)cur + size); } +#if BH_ENABLE_GC_CORRUPTION_CHECK != 0 if (cur != end) { os_printf("[GC_ERROR]Heap is corrupted, heap migrate failed.\n"); heap->is_heap_corrupted = true; return GC_ERROR; } +#else + bh_assert(cur == end); +#endif return 0; } @@ -250,9 +261,13 @@ gc_migrate(gc_handle_t handle, char *pool_buf_new, gc_size_t pool_buf_size) bool gc_is_heap_corrupted(gc_handle_t handle) { +#if BH_ENABLE_GC_CORRUPTION_CHECK != 0 gc_heap_t *heap = (gc_heap_t *)handle; return heap->is_heap_corrupted ? true : false; +#else + return false; +#endif } #if BH_ENABLE_GC_VERIFY != 0 diff --git a/core/shared/mem-alloc/mem_alloc.cmake b/core/shared/mem-alloc/mem_alloc.cmake index c0b4157f4..1754a1aca 100644 --- a/core/shared/mem-alloc/mem_alloc.cmake +++ b/core/shared/mem-alloc/mem_alloc.cmake @@ -10,6 +10,14 @@ if (WAMR_BUILD_GC_VERIFY EQUAL 1) add_definitions (-DBH_ENABLE_GC_VERIFY=1) endif () +if (NOT DEFINED WAMR_BUILD_GC_CORRUPTION_CHECK) + set (WAMR_BUILD_GC_CORRUPTION_CHECK 1) +endif () + +if (WAMR_BUILD_GC_CORRUPTION_CHECK EQUAL 0) + add_definitions (-DBH_ENABLE_GC_CORRUPTION_CHECK=0) +endif () + file (GLOB_RECURSE source_all ${MEM_ALLOC_DIR}/ems/*.c ${MEM_ALLOC_DIR}/tlsf/*.c diff --git a/core/shared/platform/alios/alios_platform.c b/core/shared/platform/alios/alios_platform.c index 60393ae52..24bf9c7ff 100644 --- a/core/shared/platform/alios/alios_platform.c +++ b/core/shared/platform/alios/alios_platform.c @@ -47,7 +47,7 @@ os_dumps_proc_mem_info(char *out, unsigned int size) } void * -os_mmap(void *hint, size_t size, int prot, int flags) +os_mmap(void *hint, size_t size, int prot, int flags, os_file_handle file) { if ((uint64)size >= UINT32_MAX) return NULL; diff --git a/core/shared/platform/alios/platform_internal.h b/core/shared/platform/alios/platform_internal.h index f6a4ba11e..dbdf74953 100644 --- a/core/shared/platform/alios/platform_internal.h +++ b/core/shared/platform/alios/platform_internal.h @@ -64,4 +64,14 @@ int signbit(double x); int isnan(double x); /* clang-format on */ +typedef int os_file_handle; +typedef DIR *os_dir_stream; +typedef int os_raw_file_handle; + +static inline os_file_handle +os_get_invalid_handle() +{ + return -1; +} + #endif /* end of _BH_PLATFORM_H */ diff --git a/core/shared/platform/android/platform_internal.h b/core/shared/platform/android/platform_internal.h index c28a7b9be..42e4e726c 100644 --- a/core/shared/platform/android/platform_internal.h +++ b/core/shared/platform/android/platform_internal.h @@ -56,6 +56,7 @@ typedef pthread_t korp_tid; typedef pthread_mutex_t korp_mutex; typedef pthread_cond_t korp_cond; typedef pthread_t korp_thread; +typedef pthread_rwlock_t korp_rwlock; typedef sem_t korp_sem; #define OS_THREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER @@ -145,6 +146,16 @@ preadv(int __fd, const struct iovec *__iov, int __count, off_t __offset); ssize_t pwritev(int __fd, const struct iovec *__iov, int __count, off_t __offset); +typedef int os_file_handle; +typedef DIR *os_dir_stream; +typedef int os_raw_file_handle; + +static inline os_file_handle +os_get_invalid_handle() +{ + return -1; +} + #ifdef __cplusplus } #endif diff --git a/core/shared/platform/common/libc-util/libc_errno.c b/core/shared/platform/common/libc-util/libc_errno.c new file mode 100644 index 000000000..e6c26c839 --- /dev/null +++ b/core/shared/platform/common/libc-util/libc_errno.c @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "errno.h" +#include "libc_errno.h" + +__wasi_errno_t +convert_errno(int error) +{ + // The C standard library only requires EDOM, EILSEQ and ERANGE to be + // defined. Other error codes are POSIX-specific and hence may or may + // not be available on non-POSIX platforms. + __wasi_errno_t code = __WASI_ENOSYS; +#define X(v) \ + case v: \ + code = __WASI_##v; \ + break; + switch (error) { + X(EDOM) + X(EILSEQ) + X(ERANGE) +#ifdef E2BIG + X(E2BIG) +#endif +#ifdef EACCES + X(EACCES) +#endif +#ifdef EADDRINUSE + X(EADDRINUSE) +#endif +#ifdef EADDRNOTAVAIL + X(EADDRNOTAVAIL) +#endif +#ifdef EAFNOSUPPORT + X(EAFNOSUPPORT) +#endif +#ifdef EAGAIN + X(EAGAIN) +#endif +#ifdef EALREADY + X(EALREADY) +#endif +#ifdef EBADF + X(EBADF) +#endif +#ifdef EBADMSG + X(EBADMSG) +#endif +#ifdef EBUSY + X(EBUSY) +#endif +#ifdef ECANCELED + X(ECANCELED) +#endif +#ifdef ECHILD + X(ECHILD) +#endif +#ifdef ECONNABORTED + X(ECONNABORTED) +#endif +#ifdef ECONNREFUSED + X(ECONNREFUSED) +#endif +#ifdef ECONNRESET + X(ECONNRESET) +#endif +#ifdef EDEADLK + X(EDEADLK) +#endif +#ifdef EDESTADDRREQ + X(EDESTADDRREQ) +#endif +#ifdef EDQUOT + X(EDQUOT) +#endif +#ifdef EEXIST + X(EEXIST) +#endif +#ifdef EFAULT + X(EFAULT) +#endif +#ifdef EFBIG + X(EFBIG) +#endif +#ifdef EHOSTUNREACH + X(EHOSTUNREACH) +#endif +#ifdef EIDRM + X(EIDRM) +#endif +#ifdef EINPROGRESS + X(EINPROGRESS) +#endif +#ifdef EINTR + X(EINTR) +#endif +#ifdef EINVAL + X(EINVAL) +#endif +#ifdef EIO + X(EIO) +#endif +#ifdef EISCONN + X(EISCONN) +#endif +#ifdef EISDIR + X(EISDIR) +#endif +#ifdef ELOOP + X(ELOOP) +#endif +#ifdef EMFILE + X(EMFILE) +#endif +#ifdef EMLINK + X(EMLINK) +#endif +#ifdef EMSGSIZE + X(EMSGSIZE) +#endif +#ifdef EMULTIHOP + X(EMULTIHOP) +#endif +#ifdef ENAMETOOLONG + X(ENAMETOOLONG) +#endif +#ifdef ENETDOWN + X(ENETDOWN) +#endif +#ifdef ENETRESET + X(ENETRESET) +#endif +#ifdef ENETUNREACH + X(ENETUNREACH) +#endif +#ifdef ENFILE + X(ENFILE) +#endif +#ifdef ENOBUFS + X(ENOBUFS) +#endif +#ifdef ENODEV + X(ENODEV) +#endif +#ifdef ENOENT + X(ENOENT) +#endif +#ifdef ENOEXEC + X(ENOEXEC) +#endif +#ifdef ENOLCK + X(ENOLCK) +#endif +#ifdef ENOLINK + X(ENOLINK) +#endif +#ifdef ENOMEM + X(ENOMEM) +#endif +#ifdef ENOMSG + X(ENOMSG) +#endif +#ifdef ENOPROTOOPT + X(ENOPROTOOPT) +#endif +#ifdef ENOSPC + X(ENOSPC) +#endif +#ifdef ENOSYS + X(ENOSYS) +#endif +#ifdef ENOTCAPABLE + X(ENOTCAPABLE) +#endif +#ifdef ENOTCONN + X(ENOTCONN) +#endif +#ifdef ENOTDIR + X(ENOTDIR) +#endif +#ifdef ENOTEMPTY + X(ENOTEMPTY) +#endif +#ifdef ENOTRECOVERABLE + X(ENOTRECOVERABLE) +#endif +#ifdef ENOTSOCK + X(ENOTSOCK) +#endif +#ifdef ENOTSUP + X(ENOTSUP) +#endif +#ifdef ENOTTY + X(ENOTTY) +#endif +#ifdef ENXIO + X(ENXIO) +#endif +#ifdef EOVERFLOW + X(EOVERFLOW) +#endif +#ifdef EOWNERDEAD + X(EOWNERDEAD) +#endif +#ifdef EPERM + X(EPERM) +#endif +#ifdef EPIPE + X(EPIPE) +#endif +#ifdef EPROTO + X(EPROTO) +#endif +#ifdef EPROTONOSUPPORT + X(EPROTONOSUPPORT) +#endif +#ifdef EPROTOTYPE + X(EPROTOTYPE) +#endif +#ifdef EROFS + X(EROFS) +#endif +#ifdef ESPIPE + X(ESPIPE) +#endif +#ifdef ESRCH + X(ESRCH) +#endif +#ifdef ESTALE + X(ESTALE) +#endif +#ifdef ETIMEDOUT + X(ETIMEDOUT) +#endif +#ifdef ETXTBSY + X(ETXTBSY) +#endif +#ifdef EXDEV + X(EXDEV) +#endif + default: +#ifdef EOPNOTSUPP + if (error == EOPNOTSUPP) + code = __WASI_ENOTSUP; +#endif +#ifdef EWOULDBLOCK + if (error == EWOULDBLOCK) + code = __WASI_EAGAIN; +#endif + break; + } +#undef X + return code; +} \ No newline at end of file diff --git a/core/shared/platform/common/libc-util/libc_errno.h b/core/shared/platform/common/libc-util/libc_errno.h new file mode 100644 index 000000000..b0a8b78c6 --- /dev/null +++ b/core/shared/platform/common/libc-util/libc_errno.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef WASI_ERRNO_H +#define WASI_ERRNO_H + +#include "platform_wasi_types.h" + +// Converts an errno error code to a WASI error code. +__wasi_errno_t +convert_errno(int error); + +#endif /* end of WASI_ERRNO_H */ \ No newline at end of file diff --git a/core/shared/platform/common/libc-util/platform_common_libc_util.cmake b/core/shared/platform/common/libc-util/platform_common_libc_util.cmake new file mode 100644 index 000000000..a7c7645ce --- /dev/null +++ b/core/shared/platform/common/libc-util/platform_common_libc_util.cmake @@ -0,0 +1,8 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +set (PLATFORM_COMMON_LIBC_UTIL_DIR ${CMAKE_CURRENT_LIST_DIR}) + +include_directories(${PLATFORM_COMMON_LIBC_UTIL_DIR}) + +file (GLOB_RECURSE PLATFORM_COMMON_LIBC_UTIL_SOURCE ${PLATFORM_COMMON_LIBC_UTIL_DIR}/*.c) \ No newline at end of file diff --git a/core/shared/platform/common/posix/platform_api_posix.cmake b/core/shared/platform/common/posix/platform_api_posix.cmake index 4abefff1e..258be4632 100644 --- a/core/shared/platform/common/posix/platform_api_posix.cmake +++ b/core/shared/platform/common/posix/platform_api_posix.cmake @@ -5,4 +5,14 @@ set (PLATFORM_COMMON_POSIX_DIR ${CMAKE_CURRENT_LIST_DIR}) file (GLOB_RECURSE source_all ${PLATFORM_COMMON_POSIX_DIR}/*.c) +if (NOT WAMR_BUILD_LIBC_WASI EQUAL 1) + list(REMOVE_ITEM source_all + ${PLATFORM_COMMON_POSIX_DIR}/posix_file.c + ${PLATFORM_COMMON_POSIX_DIR}/posix_clock.c + ) +else() + include (${CMAKE_CURRENT_LIST_DIR}/../libc-util/platform_common_libc_util.cmake) + set(source_all ${source_all} ${PLATFORM_COMMON_LIBC_UTIL_SOURCE}) +endif() + set (PLATFORM_COMMON_POSIX_SOURCE ${source_all} ) diff --git a/core/shared/platform/common/posix/posix_clock.c b/core/shared/platform/common/posix/posix_clock.c new file mode 100644 index 000000000..280306c42 --- /dev/null +++ b/core/shared/platform/common/posix/posix_clock.c @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2023 Amazon Inc. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "libc_errno.h" +#include "platform_api_extension.h" + +#define NANOSECONDS_PER_SECOND 1000000000ULL + +static __wasi_errno_t +wasi_clockid_to_clockid(__wasi_clockid_t in, clockid_t *out) +{ + switch (in) { + case __WASI_CLOCK_MONOTONIC: + *out = CLOCK_MONOTONIC; + return __WASI_ESUCCESS; + case __WASI_CLOCK_REALTIME: + *out = CLOCK_REALTIME; + return __WASI_ESUCCESS; + case __WASI_CLOCK_PROCESS_CPUTIME_ID: +#if defined(CLOCK_PROCESS_CPUTIME_ID) + *out = CLOCK_PROCESS_CPUTIME_ID; + return __WASI_ESUCCESS; +#else + return __WASI_ENOTSUP; +#endif + case __WASI_CLOCK_THREAD_CPUTIME_ID: +#if defined(CLOCK_THREAD_CPUTIME_ID) + *out = CLOCK_THREAD_CPUTIME_ID; + return __WASI_ESUCCESS; +#else + return __WASI_ENOTSUP; +#endif + default: + return __WASI_EINVAL; + } +} + +static __wasi_timestamp_t +timespec_to_nanoseconds(const struct timespec *ts) +{ + if (ts->tv_sec < 0) + return 0; + if ((__wasi_timestamp_t)ts->tv_sec >= UINT64_MAX / NANOSECONDS_PER_SECOND) + return UINT64_MAX; + return (__wasi_timestamp_t)ts->tv_sec * NANOSECONDS_PER_SECOND + + (__wasi_timestamp_t)ts->tv_nsec; +} + +__wasi_errno_t +os_clock_res_get(__wasi_clockid_t clock_id, __wasi_timestamp_t *resolution) +{ + clockid_t nclock_id; + __wasi_errno_t error = wasi_clockid_to_clockid(clock_id, &nclock_id); + + if (error != __WASI_ESUCCESS) + return error; + + struct timespec ts; + if (clock_getres(nclock_id, &ts) < 0) + return convert_errno(errno); + + *resolution = timespec_to_nanoseconds(&ts); + + return error; +} + +__wasi_errno_t +os_clock_time_get(__wasi_clockid_t clock_id, __wasi_timestamp_t precision, + __wasi_timestamp_t *time) +{ + clockid_t nclock_id; + __wasi_errno_t error = wasi_clockid_to_clockid(clock_id, &nclock_id); + + if (error != __WASI_ESUCCESS) + return error; + + struct timespec ts; + if (clock_gettime(nclock_id, &ts) < 0) + return convert_errno(errno); + + *time = timespec_to_nanoseconds(&ts); + + return error; +} diff --git a/core/shared/platform/common/posix/posix_file.c b/core/shared/platform/common/posix/posix_file.c new file mode 100644 index 000000000..a16509760 --- /dev/null +++ b/core/shared/platform/common/posix/posix_file.c @@ -0,0 +1,1007 @@ +/* + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "platform_api_extension.h" +#include "libc_errno.h" +#include + +#if !defined(__APPLE__) && !defined(ESP_PLATFORM) +#define CONFIG_HAS_PWRITEV 1 +#define CONFIG_HAS_PREADV 1 +#else +#define CONFIG_HAS_PWRITEV 0 +#define CONFIG_HAS_PREADV 0 +#endif + +#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(ESP_PLATFORM) +#define CONFIG_HAS_FDATASYNC 1 +#else +#define CONFIG_HAS_FDATASYNC 0 +#endif + +/* + * For NuttX, CONFIG_HAS_ISATTY is provided by its platform header. + * (platform_internal.h) + */ +#if !defined(__NuttX__) +#define CONFIG_HAS_D_INO 1 +#define CONFIG_HAS_ISATTY 1 +#else +#define CONFIG_HAS_D_INO 0 +#endif + +#if !defined(__APPLE__) && !defined(ESP_PLATFORM) && !defined(__COSMOPOLITAN__) +#define CONFIG_HAS_POSIX_FALLOCATE 1 +#else +#define CONFIG_HAS_POSIX_FALLOCATE 0 +#endif + +#if defined(O_DSYNC) +#define CONFIG_HAS_O_DSYNC +#endif + +// POSIX requires O_RSYNC to be defined, but Linux explicitly doesn't support +// it. +#if defined(O_RSYNC) && !defined(__linux__) +#define CONFIG_HAS_O_RSYNC +#endif + +#if defined(O_SYNC) +#define CONFIG_HAS_O_SYNC +#endif + +// Converts a POSIX timespec to a WASI timestamp. +static __wasi_timestamp_t +convert_timespec(const struct timespec *ts) +{ + if (ts->tv_sec < 0) + return 0; + if ((__wasi_timestamp_t)ts->tv_sec >= UINT64_MAX / 1000000000) + return UINT64_MAX; + return (__wasi_timestamp_t)ts->tv_sec * 1000000000 + + (__wasi_timestamp_t)ts->tv_nsec; +} + +// Converts a POSIX stat structure to a WASI filestat structure +static void +convert_stat(os_file_handle handle, const struct stat *in, + __wasi_filestat_t *out) +{ + out->st_dev = in->st_dev; + out->st_ino = in->st_ino; + out->st_nlink = (__wasi_linkcount_t)in->st_nlink; + out->st_size = (__wasi_filesize_t)in->st_size; +#ifdef __APPLE__ + out->st_atim = convert_timespec(&in->st_atimespec); + out->st_mtim = convert_timespec(&in->st_mtimespec); + out->st_ctim = convert_timespec(&in->st_ctimespec); +#else + out->st_atim = convert_timespec(&in->st_atim); + out->st_mtim = convert_timespec(&in->st_mtim); + out->st_ctim = convert_timespec(&in->st_ctim); +#endif + + // Convert the file type. In the case of sockets there is no way we + // can easily determine the exact socket type. + if (S_ISBLK(in->st_mode)) { + out->st_filetype = __WASI_FILETYPE_BLOCK_DEVICE; + } + else if (S_ISCHR(in->st_mode)) { + out->st_filetype = __WASI_FILETYPE_CHARACTER_DEVICE; + } + else if (S_ISDIR(in->st_mode)) { + out->st_filetype = __WASI_FILETYPE_DIRECTORY; + } + else if (S_ISFIFO(in->st_mode)) { + out->st_filetype = __WASI_FILETYPE_SOCKET_STREAM; + } + else if (S_ISLNK(in->st_mode)) { + out->st_filetype = __WASI_FILETYPE_SYMBOLIC_LINK; + } + else if (S_ISREG(in->st_mode)) { + out->st_filetype = __WASI_FILETYPE_REGULAR_FILE; + } + else if (S_ISSOCK(in->st_mode)) { + int socktype; + socklen_t socktypelen = sizeof(socktype); + + if (getsockopt(handle, SOL_SOCKET, SO_TYPE, &socktype, &socktypelen) + < 0) { + out->st_filetype = __WASI_FILETYPE_UNKNOWN; + return; + } + + switch (socktype) { + case SOCK_DGRAM: + out->st_filetype = __WASI_FILETYPE_SOCKET_DGRAM; + break; + case SOCK_STREAM: + out->st_filetype = __WASI_FILETYPE_SOCKET_STREAM; + break; + default: + out->st_filetype = __WASI_FILETYPE_UNKNOWN; + return; + } + } + else { + out->st_filetype = __WASI_FILETYPE_UNKNOWN; + } +} + +static void +convert_timestamp(__wasi_timestamp_t in, struct timespec *out) +{ + // Store sub-second remainder. +#if defined(__SYSCALL_SLONG_TYPE) + out->tv_nsec = (__SYSCALL_SLONG_TYPE)(in % 1000000000); +#else + out->tv_nsec = (long)(in % 1000000000); +#endif + in /= 1000000000; + + // Clamp to the maximum in case it would overflow our system's time_t. + out->tv_sec = (time_t)in < BH_TIME_T_MAX ? (time_t)in : BH_TIME_T_MAX; +} + +// Converts the provided timestamps and flags to a set of arguments for +// futimens() and utimensat(). +static void +convert_utimens_arguments(__wasi_timestamp_t st_atim, + __wasi_timestamp_t st_mtim, + __wasi_fstflags_t fstflags, struct timespec *ts) +{ + if ((fstflags & __WASI_FILESTAT_SET_ATIM_NOW) != 0) { + ts[0].tv_nsec = UTIME_NOW; + } + else if ((fstflags & __WASI_FILESTAT_SET_ATIM) != 0) { + convert_timestamp(st_atim, &ts[0]); + } + else { + ts[0].tv_nsec = UTIME_OMIT; + } + + if ((fstflags & __WASI_FILESTAT_SET_MTIM_NOW) != 0) { + ts[1].tv_nsec = UTIME_NOW; + } + else if ((fstflags & __WASI_FILESTAT_SET_MTIM) != 0) { + convert_timestamp(st_mtim, &ts[1]); + } + else { + ts[1].tv_nsec = UTIME_OMIT; + } +} + +__wasi_errno_t +os_fstat(os_file_handle handle, struct __wasi_filestat_t *buf) +{ + struct stat stat_buf; + int ret = fstat(handle, &stat_buf); + + if (ret < 0) + return convert_errno(errno); + + convert_stat(handle, &stat_buf, buf); + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +os_fstatat(os_file_handle handle, const char *path, + struct __wasi_filestat_t *buf, __wasi_lookupflags_t lookup_flags) +{ + struct stat stat_buf; + int ret = fstatat(handle, path, &stat_buf, + (lookup_flags & __WASI_LOOKUP_SYMLINK_FOLLOW) + ? AT_SYMLINK_FOLLOW + : AT_SYMLINK_NOFOLLOW); + + if (ret < 0) + return convert_errno(errno); + + convert_stat(handle, &stat_buf, buf); + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +os_file_get_fdflags(os_file_handle handle, __wasi_fdflags_t *flags) +{ + int ret = fcntl(handle, F_GETFL); + + if (ret < 0) + return convert_errno(errno); + + *flags = 0; + + if ((ret & O_APPEND) != 0) + *flags |= __WASI_FDFLAG_APPEND; +#ifdef CONFIG_HAS_O_DSYNC + if ((ret & O_DSYNC) != 0) + *flags |= __WASI_FDFLAG_DSYNC; +#endif + if ((ret & O_NONBLOCK) != 0) + *flags |= __WASI_FDFLAG_NONBLOCK; +#ifdef CONFIG_HAS_O_RSYNC + if ((ret & O_RSYNC) != 0) + *flags |= __WASI_FDFLAG_RSYNC; +#endif +#ifdef CONFIG_HAS_O_SYNC + if ((ret & O_SYNC) != 0) + *flags |= __WASI_FDFLAG_SYNC; +#endif + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +os_file_set_fdflags(os_file_handle handle, __wasi_fdflags_t flags) +{ + int fcntl_flags = 0; + + if ((flags & __WASI_FDFLAG_APPEND) != 0) + fcntl_flags |= O_APPEND; + if ((flags & __WASI_FDFLAG_DSYNC) != 0) +#ifdef CONFIG_HAS_O_DSYNC + fcntl_flags |= O_DSYNC; +#else + return __WASI_ENOTSUP; +#endif + if ((flags & __WASI_FDFLAG_NONBLOCK) != 0) + fcntl_flags |= O_NONBLOCK; + if ((flags & __WASI_FDFLAG_RSYNC) != 0) +#ifdef CONFIG_HAS_O_RSYNC + fcntl_flags |= O_RSYNC; +#else + return __WASI_ENOTSUP; +#endif + if ((flags & __WASI_FDFLAG_SYNC) != 0) +#ifdef CONFIG_HAS_O_SYNC + fcntl_flags |= O_SYNC; +#else + return __WASI_ENOTSUP; +#endif + + int ret = fcntl(handle, F_SETFL, fcntl_flags); + + if (ret < 0) + return convert_errno(errno); + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +os_fdatasync(os_file_handle handle) +{ +#if CONFIG_HAS_FDATASYNC + int ret = fdatasync(handle); +#else + int ret = fsync(handle); +#endif + + if (ret < 0) + return convert_errno(errno); + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +os_fsync(os_file_handle handle) +{ + int ret = fsync(handle); + + if (ret < 0) + return convert_errno(errno); + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +os_open_preopendir(const char *path, os_file_handle *out) +{ + + int fd = open(path, O_RDONLY | O_DIRECTORY, 0); + + if (fd < 0) + return convert_errno(errno); + + *out = fd; + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +os_openat(os_file_handle handle, const char *path, __wasi_oflags_t oflags, + __wasi_fdflags_t fs_flags, __wasi_lookupflags_t lookup_flags, + wasi_libc_file_access_mode read_write_mode, os_file_handle *out) +{ + int open_flags = 0; + + // Convert open flags. + if ((oflags & __WASI_O_CREAT) != 0) { + open_flags |= O_CREAT; + } + if ((oflags & __WASI_O_DIRECTORY) != 0) + open_flags |= O_DIRECTORY; + if ((oflags & __WASI_O_EXCL) != 0) + open_flags |= O_EXCL; + if ((oflags & __WASI_O_TRUNC) != 0) { + open_flags |= O_TRUNC; + } + + // Convert file descriptor flags. + if ((fs_flags & __WASI_FDFLAG_APPEND) != 0) + open_flags |= O_APPEND; + if ((fs_flags & __WASI_FDFLAG_DSYNC) != 0) { +#ifdef CONFIG_HAS_O_DSYNC + open_flags |= O_DSYNC; +#else + return __WASI_ENOTSUP; +#endif + } + if ((fs_flags & __WASI_FDFLAG_NONBLOCK) != 0) + open_flags |= O_NONBLOCK; + if ((fs_flags & __WASI_FDFLAG_RSYNC) != 0) { +#ifdef CONFIG_HAS_O_RSYNC + open_flags |= O_RSYNC; +#else + return __WASI_ENOTSUP; +#endif + } + if ((fs_flags & __WASI_FDFLAG_SYNC) != 0) { +#ifdef CONFIG_HAS_O_SYNC + open_flags |= O_SYNC; +#else + return __WASI_ENOTSUP; +#endif + } + + if ((lookup_flags & __WASI_LOOKUP_SYMLINK_FOLLOW) == 0) { + open_flags |= O_NOFOLLOW; + } + + switch (read_write_mode) { + case WASI_LIBC_ACCESS_MODE_READ_WRITE: + open_flags |= O_RDWR; + break; + case WASI_LIBC_ACCESS_MODE_READ_ONLY: + open_flags |= O_RDONLY; + break; + case WASI_LIBC_ACCESS_MODE_WRITE_ONLY: + open_flags |= O_WRONLY; + break; + default: + return __WASI_EINVAL; + } + + int fd = openat(handle, path, open_flags, 0666); + + if (fd < 0) { + int openat_errno = errno; + // Linux returns ENXIO instead of EOPNOTSUPP when opening a socket. + if (openat_errno == ENXIO) { + struct stat sb; + int ret = fstatat(fd, path, &sb, + (lookup_flags & __WASI_LOOKUP_SYMLINK_FOLLOW) + ? 0 + : AT_SYMLINK_NOFOLLOW); + return ret == 0 && S_ISSOCK(sb.st_mode) ? __WASI_ENOTSUP + : __WASI_ENXIO; + } + // Linux returns ENOTDIR instead of ELOOP when using + // O_NOFOLLOW|O_DIRECTORY on a symlink. + if (openat_errno == ENOTDIR + && (open_flags & (O_NOFOLLOW | O_DIRECTORY)) != 0) { + struct stat sb; + int ret = fstatat(fd, path, &sb, AT_SYMLINK_NOFOLLOW); + if (S_ISLNK(sb.st_mode)) { + return __WASI_ELOOP; + } + (void)ret; + } + // FreeBSD returns EMLINK instead of ELOOP when using O_NOFOLLOW on + // a symlink. + if ((lookup_flags & __WASI_LOOKUP_SYMLINK_FOLLOW) == 0 + && openat_errno == EMLINK) + return __WASI_ELOOP; + + return convert_errno(openat_errno); + } + + *out = fd; + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +os_file_get_access_mode(os_file_handle handle, + wasi_libc_file_access_mode *access_mode) +{ + int ret = fcntl(handle, F_GETFL, 0); + + if (ret < 0) + return convert_errno(errno); + + switch (ret & O_ACCMODE) { + case O_RDONLY: + *access_mode = WASI_LIBC_ACCESS_MODE_READ_ONLY; + break; + case O_WRONLY: + *access_mode = WASI_LIBC_ACCESS_MODE_WRITE_ONLY; + break; + case O_RDWR: + *access_mode = WASI_LIBC_ACCESS_MODE_READ_WRITE; + break; + default: + return __WASI_EINVAL; + } + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +os_close(os_file_handle handle, bool is_stdio) +{ + if (is_stdio) + return __WASI_ESUCCESS; + + int ret = close(handle); + + if (ret < 0) + return convert_errno(errno); + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +os_preadv(os_file_handle handle, const struct __wasi_iovec_t *iov, int iovcnt, + __wasi_filesize_t offset, size_t *nread) +{ +#if CONFIG_HAS_PREADV + ssize_t len = + preadv(handle, (const struct iovec *)iov, (int)iovcnt, (off_t)offset); + if (len < 0) + return convert_errno(errno); + + *nread = (size_t)len; + return __WASI_ESUCCESS; +#else + if (iovcnt == 1) { + ssize_t len = pread(handle, iov->buf, iov->buf_len, offset); + + if (len < 0) + return convert_errno(errno); + + *nread = len; + return __WASI_ESUCCESS; + } + + // Allocate a single buffer to fit all data. + size_t totalsize = 0; + for (size_t i = 0; i < iovcnt; ++i) + totalsize += iov[i].buf_len; + + char *buf = BH_MALLOC(totalsize); + + if (buf == NULL) { + return __WASI_ENOMEM; + } + + // Perform a single read operation. + ssize_t len = pread(handle, buf, totalsize, offset); + + if (len < 0) { + BH_FREE(buf); + return convert_errno(errno); + } + + // Copy data back to vectors. + size_t bufoff = 0; + for (size_t i = 0; i < iovcnt; ++i) { + if (bufoff + iov[i].buf_len < (size_t)len) { + memcpy(iov[i].buf, buf + bufoff, iov[i].buf_len); + bufoff += iov[i].buf_len; + } + else { + memcpy(iov[i].buf, buf + bufoff, len - bufoff); + break; + } + } + BH_FREE(buf); + *nread = len; + + return __WASI_ESUCCESS; +#endif +} + +__wasi_errno_t +os_pwritev(os_file_handle handle, const struct __wasi_ciovec_t *iov, int iovcnt, + __wasi_filesize_t offset, size_t *nwritten) +{ + if (iovcnt == 0) + return __WASI_EINVAL; + + ssize_t len = 0; +#if CONFIG_HAS_PWRITEV + len = + pwritev(handle, (const struct iovec *)iov, (int)iovcnt, (off_t)offset); +#else + if (iovcnt == 1) { + len = pwrite(handle, iov->buf, iov->buf_len, offset); + } + else { + // Allocate a single buffer to fit all data. + size_t totalsize = 0; + for (size_t i = 0; i < iovcnt; ++i) + totalsize += iov[i].buf_len; + char *buf = BH_MALLOC(totalsize); + if (buf == NULL) { + return __WASI_ENOMEM; + } + size_t bufoff = 0; + for (size_t i = 0; i < iovcnt; ++i) { + memcpy(buf + bufoff, iov[i].buf, iov[i].buf_len); + bufoff += iov[i].buf_len; + } + + // Perform a single write operation. + len = pwrite(handle, buf, totalsize, offset); + BH_FREE(buf); + } +#endif + if (len < 0) + return convert_errno(errno); + + *nwritten = (size_t)len; + return __WASI_ESUCCESS; +} + +__wasi_errno_t +os_readv(os_file_handle handle, const struct __wasi_iovec_t *iov, int iovcnt, + size_t *nread) +{ + ssize_t len = readv(handle, (const struct iovec *)iov, (int)iovcnt); + + if (len < 0) + return convert_errno(errno); + + *nread = (size_t)len; + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +os_writev(os_file_handle handle, const struct __wasi_ciovec_t *iov, int iovcnt, + size_t *nwritten) +{ + ssize_t len = writev(handle, (const struct iovec *)iov, (int)iovcnt); + + if (len < 0) + return convert_errno(errno); + + *nwritten = (size_t)len; + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +os_fallocate(os_file_handle handle, __wasi_filesize_t offset, + __wasi_filesize_t length) +{ +#if CONFIG_HAS_POSIX_FALLOCATE + int ret = posix_fallocate(handle, (off_t)offset, (off_t)length); +#else + // At least ensure that the file is grown to the right size. + // TODO(ed): See if this can somehow be implemented without any race + // conditions. We may end up shrinking the file right now. + struct stat sb; + int ret = fstat(handle, &sb); + off_t newsize = (off_t)(offset + length); + + if (ret == 0 && sb.st_size < newsize) + ret = ftruncate(handle, newsize); +#endif + + if (ret != 0) + return convert_errno(ret); + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +os_ftruncate(os_file_handle handle, __wasi_filesize_t size) +{ + int ret = ftruncate(handle, (off_t)size); + + if (ret < 0) + return convert_errno(errno); + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +os_futimens(os_file_handle handle, __wasi_timestamp_t access_time, + __wasi_timestamp_t modification_time, __wasi_fstflags_t fstflags) +{ + struct timespec ts[2]; + convert_utimens_arguments(access_time, modification_time, fstflags, ts); + + int ret = futimens(handle, ts); + + if (ret < 0) + return convert_errno(errno); + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +os_utimensat(os_file_handle handle, const char *path, + __wasi_timestamp_t access_time, + __wasi_timestamp_t modification_time, __wasi_fstflags_t fstflags, + __wasi_lookupflags_t lookup_flags) +{ + struct timespec ts[2]; + convert_utimens_arguments(access_time, modification_time, fstflags, ts); + + int ret = utimensat(handle, path, ts, + (lookup_flags & __WASI_LOOKUP_SYMLINK_FOLLOW) + ? 0 + : AT_SYMLINK_NOFOLLOW); + + if (ret < 0) + return convert_errno(errno); + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +os_readlinkat(os_file_handle handle, const char *path, char *buf, + size_t bufsize, size_t *nread) +{ + // Linux requires that the buffer size is positive. whereas POSIX does + // not. Use a fake buffer to store the results if the size is zero. + char fakebuf[1]; + ssize_t len = readlinkat(handle, path, bufsize == 0 ? fakebuf : buf, + bufsize == 0 ? sizeof(fakebuf) : bufsize); + + if (len < 0) + return convert_errno(errno); + + *nread = (size_t)len < bufsize ? (size_t)len : bufsize; + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +os_linkat(os_file_handle from_handle, const char *from_path, + os_file_handle to_handle, const char *to_path, + __wasi_lookupflags_t lookup_flags) +{ + int ret = linkat( + from_handle, from_path, to_handle, to_path, + (lookup_flags & __WASI_LOOKUP_SYMLINK_FOLLOW) ? AT_SYMLINK_FOLLOW : 0); + + if (ret < 0) + return convert_errno(errno); + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +os_symlinkat(const char *old_path, os_file_handle handle, const char *new_path) +{ + int ret = symlinkat(old_path, handle, new_path); + + if (ret < 0) + return convert_errno(errno); + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +os_mkdirat(os_file_handle handle, const char *path) +{ + int ret = mkdirat(handle, path, 0777); + + if (ret < 0) + return convert_errno(errno); + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +os_renameat(os_file_handle old_handle, const char *old_path, + os_file_handle new_handle, const char *new_path) +{ + + int ret = renameat(old_handle, old_path, new_handle, new_path); + + if (ret < 0) + return convert_errno(errno); + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +os_unlinkat(os_file_handle handle, const char *path, bool is_dir) +{ + int ret = unlinkat(handle, path, is_dir ? AT_REMOVEDIR : 0); + +#ifndef __linux__ + if (ret < 0) { + // Non-Linux implementations may return EPERM when attempting to remove + // a directory without REMOVEDIR. While that's what POSIX specifies, + // it's less useful. Adjust this to EISDIR. It doesn't matter that this + // is not atomic with the unlinkat, because if the file is removed and a + // directory is created before fstatat sees it, we're racing with that + // change anyway and unlinkat could have legitimately seen the directory + // if the race had turned out differently. + if (errno == EPERM) { + struct stat statbuf; + if (fstatat(handle, path, &statbuf, AT_SYMLINK_NOFOLLOW) == 0 + && S_ISDIR(statbuf.st_mode)) { + errno = EISDIR; + } + } + // POSIX permits either EEXIST or ENOTEMPTY when the directory is not + // empty. Map it to ENOTEMPTY. + else if (errno == EEXIST) { + errno = ENOTEMPTY; + } + + return convert_errno(errno); + } +#endif + + if (ret < 0) + return convert_errno(errno); + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +os_lseek(os_file_handle handle, __wasi_filedelta_t offset, + __wasi_whence_t whence, __wasi_filesize_t *new_offset) +{ + int nwhence; + + switch (whence) { + case __WASI_WHENCE_CUR: + nwhence = SEEK_CUR; + break; + case __WASI_WHENCE_END: + nwhence = SEEK_END; + break; + case __WASI_WHENCE_SET: + nwhence = SEEK_SET; + break; + default: + return __WASI_EINVAL; + } + + off_t ret = lseek(handle, offset, nwhence); + + if (ret < 0) + return convert_errno(errno); + + *new_offset = (__wasi_filesize_t)ret; + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +os_fadvise(os_file_handle handle, __wasi_filesize_t offset, + __wasi_filesize_t length, __wasi_advice_t advice) +{ +#ifdef POSIX_FADV_NORMAL + int nadvice; + switch (advice) { + case __WASI_ADVICE_DONTNEED: + nadvice = POSIX_FADV_DONTNEED; + break; + case __WASI_ADVICE_NOREUSE: + nadvice = POSIX_FADV_NOREUSE; + break; + case __WASI_ADVICE_NORMAL: + nadvice = POSIX_FADV_NORMAL; + break; + case __WASI_ADVICE_RANDOM: + nadvice = POSIX_FADV_RANDOM; + break; + case __WASI_ADVICE_SEQUENTIAL: + nadvice = POSIX_FADV_SEQUENTIAL; + break; + case __WASI_ADVICE_WILLNEED: + nadvice = POSIX_FADV_WILLNEED; + break; + default: + return __WASI_EINVAL; + } + + int ret = posix_fadvise(handle, (off_t)offset, (off_t)length, nadvice); + + if (ret < 0) + return convert_errno(ret); + + return __WASI_ESUCCESS; +#else + // Advisory information can be safely ignored if not supported + switch (advice) { + case __WASI_ADVICE_DONTNEED: + case __WASI_ADVICE_NOREUSE: + case __WASI_ADVICE_NORMAL: + case __WASI_ADVICE_RANDOM: + case __WASI_ADVICE_SEQUENTIAL: + case __WASI_ADVICE_WILLNEED: + return __WASI_ESUCCESS; + default: + return __WASI_EINVAL; + } +#endif +} + +__wasi_errno_t +os_isatty(os_file_handle handle) +{ +#if CONFIG_HAS_ISATTY + int ret = isatty(handle); + + if (ret == 1) + return __WASI_ESUCCESS; + + return __WASI_ENOTTY; +#else + return __WASI_ENOTSUP; +#endif +} + +os_file_handle +os_convert_stdin_handle(os_raw_file_handle raw_stdin) +{ +#ifndef STDIN_FILENO +#define STDIN_FILENO 0 +#endif + return raw_stdin >= 0 ? raw_stdin : STDIN_FILENO; +} + +os_file_handle +os_convert_stdout_handle(os_raw_file_handle raw_stdout) +{ +#ifndef STDOUT_FILENO +#define STDOUT_FILENO 1 +#endif + return raw_stdout >= 0 ? raw_stdout : STDOUT_FILENO; +} + +os_file_handle +os_convert_stderr_handle(os_raw_file_handle raw_stderr) +{ +#ifndef STDERR_FILENO +#define STDERR_FILENO 2 +#endif + return raw_stderr >= 0 ? raw_stderr : STDERR_FILENO; +} + +__wasi_errno_t +os_fdopendir(os_file_handle handle, os_dir_stream *dir_stream) +{ + *dir_stream = fdopendir(handle); + + if (*dir_stream == NULL) + return convert_errno(errno); + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +os_rewinddir(os_dir_stream dir_stream) +{ + rewinddir(dir_stream); + return __WASI_ESUCCESS; +} + +__wasi_errno_t +os_seekdir(os_dir_stream dir_stream, __wasi_dircookie_t position) +{ + seekdir(dir_stream, (long)position); + return __WASI_ESUCCESS; +} + +__wasi_errno_t +os_readdir(os_dir_stream dir_stream, __wasi_dirent_t *entry, + const char **d_name) +{ + errno = 0; + + struct dirent *dent = readdir(dir_stream); + + if (dent == NULL) { + *d_name = NULL; + return convert_errno(errno); + } + + long offset = (__wasi_dircookie_t)telldir(dir_stream); + + size_t namlen = strlen(dent->d_name); + + *d_name = dent->d_name; + entry->d_next = offset; + entry->d_namlen = (__wasi_dirnamlen_t)namlen; +#if CONFIG_HAS_D_INO + entry->d_ino = dent->d_ino; +#else + entry->d_ino = 0; +#endif + + switch (dent->d_type) { + case DT_BLK: + entry->d_type = __WASI_FILETYPE_BLOCK_DEVICE; + break; + case DT_CHR: + entry->d_type = __WASI_FILETYPE_CHARACTER_DEVICE; + break; + case DT_DIR: + entry->d_type = __WASI_FILETYPE_DIRECTORY; + break; + case DT_FIFO: + entry->d_type = __WASI_FILETYPE_SOCKET_STREAM; + break; + case DT_LNK: + entry->d_type = __WASI_FILETYPE_SYMBOLIC_LINK; + break; + case DT_REG: + entry->d_type = __WASI_FILETYPE_REGULAR_FILE; + break; +#ifdef DT_SOCK + case DT_SOCK: + // Technically not correct, but good enough. + entry->d_type = __WASI_FILETYPE_SOCKET_STREAM; + break; +#endif + default: + entry->d_type = __WASI_FILETYPE_UNKNOWN; + break; + } + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +os_closedir(os_dir_stream dir_stream) +{ + int ret = closedir(dir_stream); + + if (ret < 0) + return convert_errno(errno); + + return __WASI_ESUCCESS; +} + +os_dir_stream +os_get_invalid_dir_stream() +{ + return NULL; +} + +bool +os_is_dir_stream_valid(os_dir_stream *dir_stream) +{ + assert(dir_stream != NULL); + + return *dir_stream != NULL; +} + +bool +os_is_handle_valid(os_file_handle *handle) +{ + assert(handle != NULL); + + return *handle > -1; +} + +char * +os_realpath(const char *path, char *resolved_path) +{ + return realpath(path, resolved_path); +} \ No newline at end of file diff --git a/core/shared/platform/common/posix/posix_memmap.c b/core/shared/platform/common/posix/posix_memmap.c index 5d33dcc81..583557bb8 100644 --- a/core/shared/platform/common/posix/posix_memmap.c +++ b/core/shared/platform/common/posix/posix_memmap.c @@ -37,7 +37,7 @@ round_down(uintptr_t v, uintptr_t b) #endif void * -os_mmap(void *hint, size_t size, int prot, int flags) +os_mmap(void *hint, size_t size, int prot, int flags, os_file_handle file) { int map_prot = PROT_NONE; #if (defined(__APPLE__) || defined(__MACH__)) && defined(__arm64__) @@ -114,7 +114,7 @@ os_mmap(void *hint, size_t size, int prot, int flags) /* try 10 times, step with 1MB each time */ for (i = 0; i < 10 && hint_addr < (uint8 *)(uintptr_t)(2ULL * BH_GB); i++) { - addr = mmap(hint_addr, request_size, map_prot, map_flags, -1, 0); + addr = mmap(hint_addr, request_size, map_prot, map_flags, file, 0); if (addr != MAP_FAILED) { if (addr > (uint8 *)(uintptr_t)(2ULL * BH_GB)) { /* unmap and try again if the mapped address doesn't @@ -136,7 +136,7 @@ os_mmap(void *hint, size_t size, int prot, int flags) if (addr == MAP_FAILED) { /* try 5 times */ for (i = 0; i < 5; i++) { - addr = mmap(hint, request_size, map_prot, map_flags, -1, 0); + addr = mmap(hint, request_size, map_prot, map_flags, file, 0); if (addr != MAP_FAILED) break; } @@ -266,4 +266,4 @@ os_icache_flush(void *start, size_t len) #if (defined(__APPLE__) || defined(__MACH__)) && defined(__arm64__) sys_icache_invalidate(start, len); #endif -} \ No newline at end of file +} diff --git a/core/shared/platform/common/posix/posix_thread.c b/core/shared/platform/common/posix/posix_thread.c index 46a4bd993..616420c94 100644 --- a/core/shared/platform/common/posix/posix_thread.c +++ b/core/shared/platform/common/posix/posix_thread.c @@ -329,6 +329,61 @@ os_cond_broadcast(korp_cond *cond) return BHT_OK; } +int +os_rwlock_init(korp_rwlock *lock) +{ + assert(lock); + + if (pthread_rwlock_init(lock, NULL) != BHT_OK) + return BHT_ERROR; + + return BHT_OK; +} + +int +os_rwlock_rdlock(korp_rwlock *lock) +{ + assert(lock); + + if (pthread_rwlock_rdlock(lock) != BHT_OK) + return BHT_ERROR; + + return BHT_OK; +} + +int +os_rwlock_wrlock(korp_rwlock *lock) +{ + assert(lock); + + if (pthread_rwlock_wrlock(lock) != BHT_OK) + return BHT_ERROR; + + return BHT_OK; +} + +int +os_rwlock_unlock(korp_rwlock *lock) +{ + assert(lock); + + if (pthread_rwlock_unlock(lock) != BHT_OK) + return BHT_ERROR; + + return BHT_OK; +} + +int +os_rwlock_destroy(korp_rwlock *lock) +{ + assert(lock); + + if (pthread_rwlock_destroy(lock) != BHT_OK) + return BHT_ERROR; + + return BHT_OK; +} + int os_thread_join(korp_tid thread, void **value_ptr) { @@ -609,7 +664,7 @@ os_thread_signal_init(os_signal_handler handler) /* Initialize memory for signal alternate stack of current thread */ if (!(map_addr = os_mmap(NULL, map_size, MMAP_PROT_READ | MMAP_PROT_WRITE, - MMAP_MAP_NONE))) { + MMAP_MAP_NONE, os_get_invalid_handle()))) { os_printf("Failed to mmap memory for alternate stack\n"); goto fail1; } diff --git a/core/shared/platform/cosmopolitan/platform_internal.h b/core/shared/platform/cosmopolitan/platform_internal.h index ed2545436..02cd78be4 100644 --- a/core/shared/platform/cosmopolitan/platform_internal.h +++ b/core/shared/platform/cosmopolitan/platform_internal.h @@ -63,6 +63,10 @@ typedef sem_t korp_sem; #define bh_socket_t int +typedef int os_file_handle; +typedef DIR *os_dir_stream; +typedef int os_raw_file_handle; + #if WASM_DISABLE_WRITE_GS_BASE == 0 #if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) #define os_writegsbase(base_addr) \ diff --git a/core/shared/platform/darwin/platform_internal.h b/core/shared/platform/darwin/platform_internal.h index d72d48b53..30b89624e 100644 --- a/core/shared/platform/darwin/platform_internal.h +++ b/core/shared/platform/darwin/platform_internal.h @@ -58,6 +58,7 @@ typedef pthread_t korp_tid; typedef pthread_mutex_t korp_mutex; typedef pthread_cond_t korp_cond; typedef pthread_t korp_thread; +typedef pthread_rwlock_t korp_rwlock; typedef sem_t korp_sem; #define OS_THREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER @@ -108,6 +109,16 @@ os_sigreturn(); void os_set_signal_number_for_blocking_op(int signo); +typedef int os_file_handle; +typedef DIR *os_dir_stream; +typedef int os_raw_file_handle; + +static inline os_file_handle +os_get_invalid_handle() +{ + return -1; +} + #ifdef __cplusplus } #endif diff --git a/core/shared/platform/esp-idf/espidf_memmap.c b/core/shared/platform/esp-idf/espidf_memmap.c index ce94a9549..9f3ec47a6 100644 --- a/core/shared/platform/esp-idf/espidf_memmap.c +++ b/core/shared/platform/esp-idf/espidf_memmap.c @@ -19,7 +19,7 @@ static portMUX_TYPE s_spinlock = portMUX_INITIALIZER_UNLOCKED; #endif void * -os_mmap(void *hint, size_t size, int prot, int flags) +os_mmap(void *hint, size_t size, int prot, int flags, os_file_handle file) { if (prot & MMAP_PROT_EXEC) { #if (WASM_MEM_DUAL_BUS_MIRROR != 0) diff --git a/core/shared/platform/esp-idf/platform_internal.h b/core/shared/platform/esp-idf/platform_internal.h index 81304ea80..70c4fe7b1 100644 --- a/core/shared/platform/esp-idf/platform_internal.h +++ b/core/shared/platform/esp-idf/platform_internal.h @@ -39,6 +39,7 @@ typedef pthread_t korp_tid; typedef pthread_mutex_t korp_mutex; typedef pthread_cond_t korp_cond; typedef pthread_t korp_thread; +typedef pthread_rwlock_t korp_rwlock; typedef unsigned int korp_sem; #define OS_THREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER @@ -108,6 +109,16 @@ typedef unsigned int korp_sem; #define DT_LNK DTYPE_LINK #define DT_SOCK DTYPE_SOCK +typedef int os_file_handle; +typedef DIR *os_dir_stream; +typedef int os_raw_file_handle; + +static inline os_file_handle +os_get_invalid_handle() +{ + return -1; +} + #ifdef __cplusplus } #endif diff --git a/core/shared/platform/freebsd/platform_internal.h b/core/shared/platform/freebsd/platform_internal.h index 50cabd344..5241c6456 100644 --- a/core/shared/platform/freebsd/platform_internal.h +++ b/core/shared/platform/freebsd/platform_internal.h @@ -57,6 +57,7 @@ typedef pthread_t korp_tid; typedef pthread_mutex_t korp_mutex; typedef pthread_cond_t korp_cond; typedef pthread_t korp_thread; +typedef pthread_rwlock_t korp_rwlock; typedef sem_t korp_sem; #define OS_THREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER @@ -65,6 +66,10 @@ typedef sem_t korp_sem; #define bh_socket_t int +typedef int os_file_handle; +typedef DIR *os_dir_stream; +typedef int os_raw_file_handle; + #if WASM_DISABLE_HW_BOUND_CHECK == 0 #if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) \ || defined(BUILD_TARGET_AARCH64) || defined(BUILD_TARGET_RISCV64_LP64D) \ @@ -107,6 +112,14 @@ os_sigreturn(); void os_set_signal_number_for_blocking_op(int signo); +typedef int os_file_handle; + +static inline os_file_handle +os_get_invalid_handle() +{ + return -1; +} + #ifdef __cplusplus } #endif diff --git a/core/shared/platform/include/platform_api_extension.h b/core/shared/platform/include/platform_api_extension.h index 06bd9ee89..2795fc6ac 100644 --- a/core/shared/platform/include/platform_api_extension.h +++ b/core/shared/platform/include/platform_api_extension.h @@ -7,6 +7,7 @@ #define PLATFORM_API_EXTENSION_H #include "platform_common.h" +#include "platform_wasi_types.h" /** * The related data structures should be defined * in platform_internal.h @@ -238,6 +239,56 @@ os_cond_signal(korp_cond *cond); int os_cond_broadcast(korp_cond *cond); +/** + * Initialize readwrite lock object + * + * @param cond [OUTPUT] pointer to a lock object variable + * + * @return 0 if success + */ +int +os_rwlock_init(korp_rwlock *lock); + +/** + * Acquire the read lock + * + * @param lock lock variable + * + * @return 0 if success + */ +int +os_rwlock_rdlock(korp_rwlock *lock); + +/** + * Acquire the write lock + * + * @param lock lock variable + * + * @return 0 if success + */ +int +os_rwlock_wrlock(korp_rwlock *lock); + +/** + * Unlocks the lock object + * + * @param lock lock variable + * + * @return 0 if success + */ +int +os_rwlock_unlock(korp_rwlock *lock); + +/** + * Destroy a lock object + * + * @param lock lock variable + * + * @return 0 if success + */ +int +os_rwlock_destroy(korp_rwlock *lock); + /** * Creates a new POSIX-like semaphore or opens an existing * semaphore. The semaphore is identified by name. For details of @@ -1061,6 +1112,526 @@ os_socket_get_broadcast(bh_socket_t socket, bool *is_enabled); int os_dumps_proc_mem_info(char *out, unsigned int size); +/**************************************************** + * Section 3 * + * Filesystem support * + ****************************************************/ + +/** + * NOTES: + * Fileystem APIs are required for WASI libc support. If you don't need to + * support WASI libc, there is no need to implement these APIs. With a + * few exceptions, each filesystem function has been named after the equivalent + * POSIX filesystem function with an os_ prefix. + * + * Filesystem types + * + * os_raw_file_handle: the underlying OS file handle type e.g. int on POSIX + * systems and HANDLE on Windows. This type exists to allow embedders to provide + * custom file handles for stdout/stdin/stderr. + * + * os_file_handle: the file handle type used in the WASI libc fd + * table. Filesystem implementations can use it as a means to store any + * necessary platform-specific information which may not be directly available + * through the raw OS file handle. Similiar to POSIX file descriptors, file + * handles may also refer to sockets, directories, symbolic links or character + * devices and any of the filesystem operations which make sense for these + * resource types should be supported as far as possible. + * + * os_dir_stream: a directory stream type in which fileystem implementations + * can store any necessary state to iterate over the entries in a directory. + */ + +/** + * Obtain information about an open file associated with the given handle. + * + * @param handle the handle for which to obtain file information + * @param buf a buffer in which to store the information + */ +__wasi_errno_t +os_fstat(os_file_handle handle, struct __wasi_filestat_t *buf); + +/** + * Obtain information about an open file or directory. + * @param handle the directory handle from which to resolve the file/directory + * path + * @param path the relative path of the file or directory for which to obtain + * information + * @param buf a buffer in which to store the information + * @param follow_symlink whether to follow symlinks when resolving the path + */ +__wasi_errno_t +os_fstatat(os_file_handle handle, const char *path, + struct __wasi_filestat_t *buf, __wasi_lookupflags_t lookup_flags); + +/** + * Obtain the file status flags for the provided handle. This is similiar to the + * POSIX function fcntl called with the F_GETFL command. + * + * @param handle the handle for which to obtain the file status flags + * @param flags a pointer in which to store the output + */ +__wasi_errno_t +os_file_get_fdflags(os_file_handle handle, __wasi_fdflags_t *flags); + +/** + * Set the file status flags for the provided handle. This is similiar to the + * POSIX function fcntl called with the F_SETFL command. + * + * @param handle the handle for which to set the file status flags + * @param flags the flags to set + */ +__wasi_errno_t +os_file_set_fdflags(os_file_handle handle, __wasi_fdflags_t flags); + +/** + * Synchronize the data of a file to disk. + * + * @param handle + */ +__wasi_errno_t +os_fdatasync(os_file_handle handle); + +/** + * Synchronize the data and metadata of a file to disk. + * + * @param handle + */ +__wasi_errno_t +os_fsync(os_file_handle handle); + +/** + * Open a preopen directory. The path provided must refer to a directory and the + * returned handle will allow only readonly operations. + * + * @param path the path of the preopen directory to open + * @param out a pointer in which to store the newly opened handle + */ +__wasi_errno_t +os_open_preopendir(const char *path, os_file_handle *out); + +typedef uint8 wasi_libc_file_access_mode; +#define WASI_LIBC_ACCESS_MODE_READ_ONLY 0 +#define WASI_LIBC_ACCESS_MODE_WRITE_ONLY 1 +#define WASI_LIBC_ACCESS_MODE_READ_WRITE 2 + +/** + * Open a file or directory at the given path. + * + * @param handle a handle to the directory in which to open the new file or + * directory + * @param path the relative path of the file or directory to open + * @param oflags the flags to determine how the file or directory is opened + * @param fd_flags the flags to set on the returned handle + * @param lookup_flags whether to follow symlinks when resolving the path + * @param access_mode whether the file is opened as read only, write only or + * both + * @param out a pointer in which to store the newly opened handle + */ +__wasi_errno_t +os_openat(os_file_handle handle, const char *path, __wasi_oflags_t oflags, + __wasi_fdflags_t fd_flags, __wasi_lookupflags_t lookup_flags, + wasi_libc_file_access_mode access_mode, os_file_handle *out); + +/** + * Obtain the file access mode for the provided handle. This is similiar to the + * POSIX function fcntl called with the F_GETFL command combined with the + * O_ACCMODE mask. + * + * @param handle the handle for which to obtain the access mode + * @param access_mode a pointer in which to store the access mode + */ +__wasi_errno_t +os_file_get_access_mode(os_file_handle handle, + wasi_libc_file_access_mode *access_mode); + +/** + * Close the provided handle. If is_stdio is true, the raw file handle + * associated with the given file handle will not be closed. + * + * @param handle the handle to close + * @param is_stdio whether the provided handle refers to a stdio device + */ +__wasi_errno_t +os_close(os_file_handle handle, bool is_stdio); + +/** + * Read data from the provided handle at the given offset into multiple buffers. + * + * @param handle the handle to read from + * @param iov the buffers to read into + * @param iovcnt the number of buffers to read into + * @param offset the offset to read from + * @param nread a pointer in which to store the number of bytes read + */ +__wasi_errno_t +os_preadv(os_file_handle handle, const struct __wasi_iovec_t *iov, int iovcnt, + __wasi_filesize_t offset, size_t *nread); + +/** + * Write data from multiple buffers at the given offset to the provided handle. + * + * @param handle the handle to write to + * @param iov the buffers to write from + * @param iovcnt the number of buffers to write from + * @param offset the offset to write from + * @param nwritten a pointer in which to store the number of bytes written + */ +__wasi_errno_t +os_pwritev(os_file_handle handle, const struct __wasi_ciovec_t *iov, int iovcnt, + __wasi_filesize_t offset, size_t *nwritten); + +/** + * Read data from the provided handle into multiple buffers. + * + * @param handle the handle to read from + * @param iov the buffers to read into + * @param iovcnt the number of buffers to read into + * @param nread a pointer in which to store the number of bytes read + */ +__wasi_errno_t +os_readv(os_file_handle handle, const struct __wasi_iovec_t *iov, int iovcnt, + size_t *nread); + +/** + * Write data from multiple buffers to the provided handle. + * + * @param handle the handle to write to + * @param iov the buffers to write from + * @param iovcnt the number of buffers to write from + * @param nwritten a pointer in which to store the number of bytes written + */ +__wasi_errno_t +os_writev(os_file_handle handle, const struct __wasi_ciovec_t *iov, int iovcnt, + size_t *nwritten); + +/** + * Allocate storage space for the file associated with the provided handle. This + * is similar to the POSIX function posix_fallocate. + * + * @param handle the handle to allocate space for + * @param offset the offset to allocate space at + * @param length the amount of space to allocate + */ +__wasi_errno_t +os_fallocate(os_file_handle handle, __wasi_filesize_t offset, + __wasi_filesize_t length); + +/** + * Adjust the size of an open file. + * + * @param handle the associated file handle for which to adjust the size + * @param size the new size of the file + */ +__wasi_errno_t +os_ftruncate(os_file_handle handle, __wasi_filesize_t size); + +/** + * Set file access and modification times on an open file or directory. + * + * @param handle the associated file handle for which to adjust the + * access/modification times + * @param access_time the timestamp for the new access time + * @param modification_time the timestamp for the new modification time + * @param fstflags a bitmask to indicate which timestamps to adjust + */ +__wasi_errno_t +os_futimens(os_file_handle handle, __wasi_timestamp_t access_time, + __wasi_timestamp_t modification_time, __wasi_fstflags_t fstflags); + +/** + * Set file access and modification times on an open file or directory. + * + * @param handle the directory handle from which to resolve the path + * @param path the relative path of the file or directory for which to adjust + * the access/modification times + * @param access_time the timestamp for the new access time + * @param modification_time the timestamp for the new modification time + * @param fstflags a bitmask to indicate which timestamps to adjust + * @param lookup_flags whether to follow symlinks when resolving the path + */ +__wasi_errno_t +os_utimensat(os_file_handle handle, const char *path, + __wasi_timestamp_t access_time, + __wasi_timestamp_t modification_time, __wasi_fstflags_t fstflags, + __wasi_lookupflags_t lookup_flags); + +/** + * Read the contents of a symbolic link relative to the provided directory + * handle. + * + * @param handle the directory handle + * @param path the relative path of the symbolic link from which to read + * @param buf the buffer to read the link contents into + * @param bufsize the size of the provided buffer + * @param nread a pointer in which to store the number of bytes read into the + * buffer + */ +__wasi_errno_t +os_readlinkat(os_file_handle handle, const char *path, char *buf, + size_t bufsize, size_t *nread); + +/** + * Create a link from one path to another path. + * + * @param from_handle the directory handle from which to resolve the origin path + * @param from_path the origin path to link from + * @param to_handle the directory handle from which to resolve the destination + * path + * @param to_path the destination path at which to create the link + * @param lookup_flags whether to follow symlinks when resolving the origin path + */ +__wasi_errno_t +os_linkat(os_file_handle from_handle, const char *from_path, + os_file_handle to_handle, const char *to_path, + __wasi_lookupflags_t lookup_flags); + +/** + * Create a symbolic link from one path to another path. + * + * @param old_path the symbolic link contents + * @param handle the directory handle from which to resolve the destination path + * @param new_path the destination path at which to create the symbolic link + */ +__wasi_errno_t +os_symlinkat(const char *old_path, os_file_handle handle, const char *new_path); + +/** + * Create a directory relative to the provided directory handle. + * + * @param handle the directory handle + * @param path the relative path of the directory to create + */ +__wasi_errno_t +os_mkdirat(os_file_handle handle, const char *path); + +/** + * Rename a file or directory. + * + * @param old_handle the directory handle from which to resolve the old path + * @param old_path the source path to rename + * @param new_handle the directory handle from which to resolve the destination + * path + * @param new_path the destination path to which to rename the file or directory + */ +__wasi_errno_t +os_renameat(os_file_handle old_handle, const char *old_path, + os_file_handle new_handle, const char *new_path); + +/** + * Unlink a file or directory. + * + * @param handle the directory handle from which to resolve the path + * @param path the relative path of the file or directory to unlink + * @param is_dir whether the provided handle refers to a directory or file + */ +__wasi_errno_t +os_unlinkat(os_file_handle handle, const char *path, bool is_dir); + +/** + * Move the read/write offset of an open file. + * + * @param handle the associated file handle for which to adjust the offset + * @param offset the number of bytes to adjust the offset by + * @param whence the position whence to adjust the offset + * @param new_offset a pointer in which to store the new offset + */ +__wasi_errno_t +os_lseek(os_file_handle handle, __wasi_filedelta_t offset, + __wasi_whence_t whence, __wasi_filesize_t *new_offset); + +/** + * Provide file advisory information for the given handle. This is similar to + * the POSIX function posix_fadvise. + * + * @param handle the associated file handle for which to provide advisory + * information + * @param offset the offset within the file to which the advisory + * information applies + * @param length the length of the region for which the advisory information + * applies + * @param advice the advice to provide + */ +__wasi_errno_t +os_fadvise(os_file_handle handle, __wasi_filesize_t offset, + __wasi_filesize_t length, __wasi_advice_t advice); + +/** + * Determine if the given handle refers to a terminal device. __WASI_ESUCCESS + * will be returned if the handle is associated with a terminal device, + * otherwise an appropriate error code will be returned. + * + * @param handle + */ +__wasi_errno_t +os_isatty(os_file_handle handle); + +/** + * Converts a raw file handle to STDIN to a corresponding file handle to STDIN. + * If the provided raw file handle is invalid, the platform-default raw handle + * for STDIN will be used. + * + * @param raw_stdin a raw file handle to STDIN + * + * @return a handle to STDIN + */ +os_file_handle +os_convert_stdin_handle(os_raw_file_handle raw_stdin); + +/** + * Converts a raw file handle to STDOUT to a correponding file handle to STDOUT. + * If the provided raw file handle is invalid, the platform-default raw handle + * for STDOUT will be used. + * + * @param raw_stdout a raw file handle to STDOUT + * + * @return a handle to STDOUT + */ +os_file_handle +os_convert_stdout_handle(os_raw_file_handle raw_stdout); + +/** + * Converts a raw file handle to STDERR to a correponding file handle to STDERR. + * If the provided raw file handle is invalid, the platform-default raw handle + * for STDERR will be used. + * + * @param raw_stderr a raw file handle to STDERR + * + * @return a handle to STDERR + */ +os_file_handle +os_convert_stderr_handle(os_raw_file_handle raw_stderr); + +/** + * Open a directory stream for the provided directory handle. The returned + * directory stream will be positioned at the first entry in the directory. + * + * @param handle the directory handle + * @param dir_stream a pointer in which to store the new directory stream + */ +__wasi_errno_t +os_fdopendir(os_file_handle handle, os_dir_stream *dir_stream); + +/** + * Reset the position of a directory stream to the beginning of the directory. + * + * @param dir_stream the directory stream for which to reset the position + */ +__wasi_errno_t +os_rewinddir(os_dir_stream dir_stream); + +/** + * Set the position of the given directory stream. + * + * @param dir_stream the directory stream for which to set the position + * @param position the position to set + */ +__wasi_errno_t +os_seekdir(os_dir_stream dir_stream, __wasi_dircookie_t position); + +/** + * Read a directory entry from the given directory stream. The directory name + * will be NULL if the end of the directory is reached or an error is + * encountered. + * + * @param dir_stream the directory stream from which to read the entry + * @param entry a pointer in which to store the directory entry + * @param d_name a pointer in which to store the directory entry name + */ +__wasi_errno_t +os_readdir(os_dir_stream dir_stream, __wasi_dirent_t *entry, + const char **d_name); + +/** + * Close the given directory stream. The handle associated with the directory + * stream will also be closed. + * + * @param dir_stream the directory stream to close + */ +__wasi_errno_t +os_closedir(os_dir_stream dir_stream); + +/** + * Returns an invalid directory stream that is guaranteed to cause failure when + * called with any directory filesystem operation. + * + * @return the invalid directory stream + */ +os_dir_stream +os_get_invalid_dir_stream(); + +/** + * Checks whether the given directory stream is valid. An invalid directory + * stream is guaranteed to cause failure when called with any directory + * filesystem operation. + * + * @param dir_stream a pointer to a directory stream + */ +bool +os_is_dir_stream_valid(os_dir_stream *dir_stream); + +/** + * Returns an invalid handle that is guaranteed to cause failure when + * called with any filesystem operation. + * + * @return the invalid handle + */ +os_file_handle +os_get_invalid_handle(); + +/** + * Checks whether the given file handle is valid. An invalid handle is + * guaranteed to cause failure when called with any filesystem operation. + * + * @param handle a pointer to a file handle + */ +bool +os_is_handle_valid(os_file_handle *handle); + +/** + * Resolve a pathname. The generated pathname will be stored as a + * null-terminated string, with a maximum length of PATH_MAX bytes. + * + * @param path the path to resolve + * @param resolved_path the buffer to store the resolved path in + * + * @return the resolved path if success, NULL otherwise + */ +char * +os_realpath(const char *path, char *resolved_path); + +/**************************************************** + * Section 4 * + * Clock functions * + ****************************************************/ + +/** + * NOTES: + * Clock functions are required for WASI libc support. If you don't need to + * support WASI libc, there is no need to implement these APIs. + */ + +/** + * Get the resolution of the specified clock. + * + * @param clock_id clock identifier + * @param resolution output variable to store the clock resolution + */ +__wasi_errno_t +os_clock_res_get(__wasi_clockid_t clock_id, __wasi_timestamp_t *resolution); + +/** + * Get the current time of the specified clock. + * + * @param clock_id clock identifier + * @param precision the maximum lag that the returned time value may have, + * compared to its actual value. + * @param time output variable to store the clock time + */ +__wasi_errno_t +os_clock_time_get(__wasi_clockid_t clock_id, __wasi_timestamp_t precision, + __wasi_timestamp_t *time); + #ifdef __cplusplus } #endif diff --git a/core/shared/platform/include/platform_api_vmcore.h b/core/shared/platform/include/platform_api_vmcore.h index c803c12e4..559141f75 100644 --- a/core/shared/platform/include/platform_api_vmcore.h +++ b/core/shared/platform/include/platform_api_vmcore.h @@ -130,7 +130,7 @@ enum { }; void * -os_mmap(void *hint, size_t size, int prot, int flags); +os_mmap(void *hint, size_t size, int prot, int flags, os_file_handle file); void os_munmap(void *addr, size_t size); int diff --git a/core/shared/platform/include/platform_wasi_types.h b/core/shared/platform/include/platform_wasi_types.h new file mode 100644 index 000000000..ac1a95ea1 --- /dev/null +++ b/core/shared/platform/include/platform_wasi_types.h @@ -0,0 +1,610 @@ +/* + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +/* + * This file declares the WASI interface. The definitions of types, macros and + * structures in this file should be consistent with those in wasi-libc: + * https://github.com/WebAssembly/wasi-libc/blob/main/libc-bottom-half/headers/public/wasi/api.h + */ + +#ifndef _PLATFORM_WASI_TYPES_H +#define _PLATFORM_WASI_TYPES_H + +#include "../../../config.h" + +#include +#include + +/* clang-format off */ + +#ifdef __cplusplus +#ifndef _Static_assert +#define _Static_assert static_assert +#endif /* _Static_assert */ + +#ifndef _Alignof +#define _Alignof alignof +#endif /* _Alignof */ + +extern "C" { +#endif + +/* There is no need to check the WASI layout if we're using uvwasi or libc-wasi + * is not enabled at all. */ +#if WASM_ENABLE_UVWASI != 0 || WASM_ENABLE_LIBC_WASI == 0 +#define assert_wasi_layout(expr, message) /* nothing */ +#else +#define assert_wasi_layout(expr, message) _Static_assert(expr, message) +#endif + +assert_wasi_layout(_Alignof(int8_t) == 1, "non-wasi data layout"); +assert_wasi_layout(_Alignof(uint8_t) == 1, "non-wasi data layout"); +assert_wasi_layout(_Alignof(int16_t) == 2, "non-wasi data layout"); +assert_wasi_layout(_Alignof(uint16_t) == 2, "non-wasi data layout"); +assert_wasi_layout(_Alignof(int32_t) == 4, "non-wasi data layout"); +assert_wasi_layout(_Alignof(uint32_t) == 4, "non-wasi data layout"); +#if 0 +assert_wasi_layout(_Alignof(int64_t) == 8, "non-wasi data layout"); +assert_wasi_layout(_Alignof(uint64_t) == 8, "non-wasi data layout"); +#endif + +typedef uint32_t __wasi_size_t; +assert_wasi_layout(_Alignof(__wasi_size_t) == 4, "non-wasi data layout"); + +typedef uint8_t __wasi_advice_t; +#define __WASI_ADVICE_NORMAL (0) +#define __WASI_ADVICE_SEQUENTIAL (1) +#define __WASI_ADVICE_RANDOM (2) +#define __WASI_ADVICE_WILLNEED (3) +#define __WASI_ADVICE_DONTNEED (4) +#define __WASI_ADVICE_NOREUSE (5) + +typedef uint32_t __wasi_clockid_t; +#define __WASI_CLOCK_REALTIME (0) +#define __WASI_CLOCK_MONOTONIC (1) +#define __WASI_CLOCK_PROCESS_CPUTIME_ID (2) +#define __WASI_CLOCK_THREAD_CPUTIME_ID (3) + +typedef uint64_t __wasi_device_t; + +typedef uint64_t __wasi_dircookie_t; +#define __WASI_DIRCOOKIE_START (0) + +typedef uint32_t __wasi_dirnamlen_t; + +typedef uint16_t __wasi_errno_t; +#define __WASI_ESUCCESS (0) +#define __WASI_E2BIG (1) +#define __WASI_EACCES (2) +#define __WASI_EADDRINUSE (3) +#define __WASI_EADDRNOTAVAIL (4) +#define __WASI_EAFNOSUPPORT (5) +#define __WASI_EAGAIN (6) +#define __WASI_EALREADY (7) +#define __WASI_EBADF (8) +#define __WASI_EBADMSG (9) +#define __WASI_EBUSY (10) +#define __WASI_ECANCELED (11) +#define __WASI_ECHILD (12) +#define __WASI_ECONNABORTED (13) +#define __WASI_ECONNREFUSED (14) +#define __WASI_ECONNRESET (15) +#define __WASI_EDEADLK (16) +#define __WASI_EDESTADDRREQ (17) +#define __WASI_EDOM (18) +#define __WASI_EDQUOT (19) +#define __WASI_EEXIST (20) +#define __WASI_EFAULT (21) +#define __WASI_EFBIG (22) +#define __WASI_EHOSTUNREACH (23) +#define __WASI_EIDRM (24) +#define __WASI_EILSEQ (25) +#define __WASI_EINPROGRESS (26) +#define __WASI_EINTR (27) +#define __WASI_EINVAL (28) +#define __WASI_EIO (29) +#define __WASI_EISCONN (30) +#define __WASI_EISDIR (31) +#define __WASI_ELOOP (32) +#define __WASI_EMFILE (33) +#define __WASI_EMLINK (34) +#define __WASI_EMSGSIZE (35) +#define __WASI_EMULTIHOP (36) +#define __WASI_ENAMETOOLONG (37) +#define __WASI_ENETDOWN (38) +#define __WASI_ENETRESET (39) +#define __WASI_ENETUNREACH (40) +#define __WASI_ENFILE (41) +#define __WASI_ENOBUFS (42) +#define __WASI_ENODEV (43) +#define __WASI_ENOENT (44) +#define __WASI_ENOEXEC (45) +#define __WASI_ENOLCK (46) +#define __WASI_ENOLINK (47) +#define __WASI_ENOMEM (48) +#define __WASI_ENOMSG (49) +#define __WASI_ENOPROTOOPT (50) +#define __WASI_ENOSPC (51) +#define __WASI_ENOSYS (52) +#define __WASI_ENOTCONN (53) +#define __WASI_ENOTDIR (54) +#define __WASI_ENOTEMPTY (55) +#define __WASI_ENOTRECOVERABLE (56) +#define __WASI_ENOTSOCK (57) +#define __WASI_ENOTSUP (58) +#define __WASI_ENOTTY (59) +#define __WASI_ENXIO (60) +#define __WASI_EOVERFLOW (61) +#define __WASI_EOWNERDEAD (62) +#define __WASI_EPERM (63) +#define __WASI_EPIPE (64) +#define __WASI_EPROTO (65) +#define __WASI_EPROTONOSUPPORT (66) +#define __WASI_EPROTOTYPE (67) +#define __WASI_ERANGE (68) +#define __WASI_EROFS (69) +#define __WASI_ESPIPE (70) +#define __WASI_ESRCH (71) +#define __WASI_ESTALE (72) +#define __WASI_ETIMEDOUT (73) +#define __WASI_ETXTBSY (74) +#define __WASI_EXDEV (75) +#define __WASI_ENOTCAPABLE (76) + +#if defined(_MSC_VER) +#define ALIGNED_(x) __declspec(align(x)) +#define WARN_UNUSED _Check_return_ +#elif defined(__GNUC__) +#define ALIGNED_(x) __attribute__ ((aligned(x))) +#define WARN_UNUSED __attribute__((__warn_unused_result__)) +#endif + +#define ALIGNED_TYPE(t,x) typedef t ALIGNED_(x) + +typedef uint16_t __wasi_eventrwflags_t; +#define __WASI_EVENT_FD_READWRITE_HANGUP (0x0001) + +typedef uint8_t __wasi_eventtype_t; +#define __WASI_EVENTTYPE_CLOCK (0) +#define __WASI_EVENTTYPE_FD_READ (1) +#define __WASI_EVENTTYPE_FD_WRITE (2) + +typedef uint32_t __wasi_exitcode_t; + +typedef uint32_t __wasi_fd_t; + +typedef uint16_t __wasi_fdflags_t; +#define __WASI_FDFLAG_APPEND (0x0001) +#define __WASI_FDFLAG_DSYNC (0x0002) +#define __WASI_FDFLAG_NONBLOCK (0x0004) +#define __WASI_FDFLAG_RSYNC (0x0008) +#define __WASI_FDFLAG_SYNC (0x0010) + +typedef int64_t __wasi_filedelta_t; + +typedef uint64_t __wasi_filesize_t; + +typedef uint8_t __wasi_filetype_t; +#define __WASI_FILETYPE_UNKNOWN (0) +#define __WASI_FILETYPE_BLOCK_DEVICE (1) +#define __WASI_FILETYPE_CHARACTER_DEVICE (2) +#define __WASI_FILETYPE_DIRECTORY (3) +#define __WASI_FILETYPE_REGULAR_FILE (4) +#define __WASI_FILETYPE_SOCKET_DGRAM (5) +#define __WASI_FILETYPE_SOCKET_STREAM (6) +#define __WASI_FILETYPE_SYMBOLIC_LINK (7) + +typedef uint16_t __wasi_fstflags_t; +#define __WASI_FILESTAT_SET_ATIM (0x0001) +#define __WASI_FILESTAT_SET_ATIM_NOW (0x0002) +#define __WASI_FILESTAT_SET_MTIM (0x0004) +#define __WASI_FILESTAT_SET_MTIM_NOW (0x0008) + +typedef uint64_t __wasi_inode_t; + +ALIGNED_TYPE(uint64_t, 8) __wasi_linkcount_t; + +typedef uint32_t __wasi_lookupflags_t; +#define __WASI_LOOKUP_SYMLINK_FOLLOW (0x00000001) + +typedef uint16_t __wasi_oflags_t; +#define __WASI_O_CREAT (0x0001) +#define __WASI_O_DIRECTORY (0x0002) +#define __WASI_O_EXCL (0x0004) +#define __WASI_O_TRUNC (0x0008) + +typedef uint16_t __wasi_riflags_t; +#define __WASI_SOCK_RECV_PEEK (0x0001) +#define __WASI_SOCK_RECV_WAITALL (0x0002) + +typedef uint64_t __wasi_rights_t; + +/** + * Observe that WASI defines rights in the plural form + * TODO: refactor to use RIGHTS instead of RIGHT + */ +#define __WASI_RIGHT_FD_DATASYNC ((__wasi_rights_t)(UINT64_C(1) << 0)) +#define __WASI_RIGHT_FD_READ ((__wasi_rights_t)(UINT64_C(1) << 1)) +#define __WASI_RIGHT_FD_SEEK ((__wasi_rights_t)(UINT64_C(1) << 2)) +#define __WASI_RIGHT_FD_FDSTAT_SET_FLAGS ((__wasi_rights_t)(UINT64_C(1) << 3)) +#define __WASI_RIGHT_FD_SYNC ((__wasi_rights_t)(UINT64_C(1) << 4)) +#define __WASI_RIGHT_FD_TELL ((__wasi_rights_t)(UINT64_C(1) << 5)) +#define __WASI_RIGHT_FD_WRITE ((__wasi_rights_t)(UINT64_C(1) << 6)) +#define __WASI_RIGHT_FD_ADVISE ((__wasi_rights_t)(UINT64_C(1) << 7)) +#define __WASI_RIGHT_FD_ALLOCATE ((__wasi_rights_t)(UINT64_C(1) << 8)) +#define __WASI_RIGHT_PATH_CREATE_DIRECTORY ((__wasi_rights_t)(UINT64_C(1) << 9)) +#define __WASI_RIGHT_PATH_CREATE_FILE ((__wasi_rights_t)(UINT64_C(1) << 10)) +#define __WASI_RIGHT_PATH_LINK_SOURCE ((__wasi_rights_t)(UINT64_C(1) << 11)) +#define __WASI_RIGHT_PATH_LINK_TARGET ((__wasi_rights_t)(UINT64_C(1) << 12)) +#define __WASI_RIGHT_PATH_OPEN ((__wasi_rights_t)(UINT64_C(1) << 13)) +#define __WASI_RIGHT_FD_READDIR ((__wasi_rights_t)(UINT64_C(1) << 14)) +#define __WASI_RIGHT_PATH_READLINK ((__wasi_rights_t)(UINT64_C(1) << 15)) +#define __WASI_RIGHT_PATH_RENAME_SOURCE ((__wasi_rights_t)(UINT64_C(1) << 16)) +#define __WASI_RIGHT_PATH_RENAME_TARGET ((__wasi_rights_t)(UINT64_C(1) << 17)) +#define __WASI_RIGHT_PATH_FILESTAT_GET ((__wasi_rights_t)(UINT64_C(1) << 18)) +#define __WASI_RIGHT_PATH_FILESTAT_SET_SIZE ((__wasi_rights_t)(UINT64_C(1) << 19)) +#define __WASI_RIGHT_PATH_FILESTAT_SET_TIMES ((__wasi_rights_t)(UINT64_C(1) << 20)) +#define __WASI_RIGHT_FD_FILESTAT_GET ((__wasi_rights_t)(UINT64_C(1) << 21)) +#define __WASI_RIGHT_FD_FILESTAT_SET_SIZE ((__wasi_rights_t)(UINT64_C(1) << 22)) +#define __WASI_RIGHT_FD_FILESTAT_SET_TIMES ((__wasi_rights_t)(UINT64_C(1) << 23)) +#define __WASI_RIGHT_PATH_SYMLINK ((__wasi_rights_t)(UINT64_C(1) << 24)) +#define __WASI_RIGHT_PATH_REMOVE_DIRECTORY ((__wasi_rights_t)(UINT64_C(1) << 25)) +#define __WASI_RIGHT_PATH_UNLINK_FILE ((__wasi_rights_t)(UINT64_C(1) << 26)) +#define __WASI_RIGHT_POLL_FD_READWRITE ((__wasi_rights_t)(UINT64_C(1) << 27)) +#define __WASI_RIGHT_SOCK_CONNECT ((__wasi_rights_t)(UINT64_C(1) << 28)) +#define __WASI_RIGHT_SOCK_LISTEN ((__wasi_rights_t)(UINT64_C(1) << 29)) +#define __WASI_RIGHT_SOCK_BIND ((__wasi_rights_t)(UINT64_C(1) << 30)) +#define __WASI_RIGHT_SOCK_ACCEPT ((__wasi_rights_t)(UINT64_C(1) << 31)) +#define __WASI_RIGHT_SOCK_RECV ((__wasi_rights_t)(UINT64_C(1) << 32)) +#define __WASI_RIGHT_SOCK_SEND ((__wasi_rights_t)(UINT64_C(1) << 33)) +#define __WASI_RIGHT_SOCK_ADDR_LOCAL ((__wasi_rights_t)(UINT64_C(1) << 34)) +#define __WASI_RIGHT_SOCK_ADDR_REMOTE ((__wasi_rights_t)(UINT64_C(1) << 35)) +#define __WASI_RIGHT_SOCK_RECV_FROM ((__wasi_rights_t)(UINT64_C(1) << 36)) +#define __WASI_RIGHT_SOCK_SEND_TO ((__wasi_rights_t)(UINT64_C(1) << 37)) + +typedef uint16_t __wasi_roflags_t; +#define __WASI_SOCK_RECV_DATA_TRUNCATED (0x0001) + +typedef uint8_t __wasi_sdflags_t; +#define __WASI_SHUT_RD (0x01) +#define __WASI_SHUT_WR (0x02) + +typedef uint16_t __wasi_siflags_t; + +typedef uint8_t __wasi_signal_t; + +typedef uint16_t __wasi_subclockflags_t; +#define __WASI_SUBSCRIPTION_CLOCK_ABSTIME (0x0001) + +typedef uint64_t __wasi_timestamp_t; + +typedef uint64_t __wasi_userdata_t; + +typedef uint8_t __wasi_whence_t; +#define __WASI_WHENCE_SET (0) +#define __WASI_WHENCE_CUR (1) +#define __WASI_WHENCE_END (2) + +typedef uint8_t __wasi_preopentype_t; +#define __WASI_PREOPENTYPE_DIR (0) + +struct fd_table; +struct fd_prestats; +struct argv_environ_values; +struct addr_pool; + +typedef struct ALIGNED_(8) __wasi_dirent_t { + __wasi_dircookie_t d_next; + __wasi_inode_t d_ino; + __wasi_dirnamlen_t d_namlen; + __wasi_filetype_t d_type; +} __wasi_dirent_t; +assert_wasi_layout(offsetof(__wasi_dirent_t, d_next) == 0, "non-wasi data layout"); +assert_wasi_layout(offsetof(__wasi_dirent_t, d_ino) == 8, "non-wasi data layout"); +assert_wasi_layout(offsetof(__wasi_dirent_t, d_namlen) == 16, "non-wasi data layout"); +assert_wasi_layout(offsetof(__wasi_dirent_t, d_type) == 20, "non-wasi data layout"); +assert_wasi_layout(sizeof(__wasi_dirent_t) == 24, "non-wasi data layout"); +assert_wasi_layout(_Alignof(__wasi_dirent_t) == 8, "non-wasi data layout"); + +typedef struct ALIGNED_(8) __wasi_event_t { + __wasi_userdata_t userdata; + __wasi_errno_t error; + __wasi_eventtype_t type; + uint8_t __paddings[5]; + union __wasi_event_u { + struct __wasi_event_u_fd_readwrite_t { + __wasi_filesize_t nbytes; + __wasi_eventrwflags_t flags; + uint8_t __paddings[6]; + } fd_readwrite; + } u; +} __wasi_event_t; +assert_wasi_layout(offsetof(__wasi_event_t, userdata) == 0, "non-wasi data layout"); +assert_wasi_layout(offsetof(__wasi_event_t, error) == 8, "non-wasi data layout"); +assert_wasi_layout(offsetof(__wasi_event_t, type) == 10, "non-wasi data layout"); +assert_wasi_layout( + offsetof(__wasi_event_t, u.fd_readwrite.nbytes) == 16, "non-wasi data layout"); +assert_wasi_layout( + offsetof(__wasi_event_t, u.fd_readwrite.flags) == 24, "non-wasi data layout"); +assert_wasi_layout(sizeof(__wasi_event_t) == 32, "non-wasi data layout"); +assert_wasi_layout(_Alignof(__wasi_event_t) == 8, "non-wasi data layout"); + +typedef struct __wasi_prestat_t { + __wasi_preopentype_t pr_type; + union __wasi_prestat_u { + struct __wasi_prestat_u_dir_t { + size_t pr_name_len; + } dir; + } u; +} __wasi_prestat_t; +assert_wasi_layout(offsetof(__wasi_prestat_t, pr_type) == 0, "non-wasi data layout"); +assert_wasi_layout(sizeof(void *) != 4 || + offsetof(__wasi_prestat_t, u.dir.pr_name_len) == 4, "non-wasi data layout"); +assert_wasi_layout(sizeof(void *) != 8 || + offsetof(__wasi_prestat_t, u.dir.pr_name_len) == 8, "non-wasi data layout"); +assert_wasi_layout(sizeof(void *) != 4 || + sizeof(__wasi_prestat_t) == 8, "non-wasi data layout"); +assert_wasi_layout(sizeof(void *) != 8 || + sizeof(__wasi_prestat_t) == 16, "non-wasi data layout"); +assert_wasi_layout(sizeof(void *) != 4 || + _Alignof(__wasi_prestat_t) == 4, "non-wasi data layout"); +assert_wasi_layout(sizeof(void *) != 8 || + _Alignof(__wasi_prestat_t) == 8, "non-wasi data layout"); + +typedef struct ALIGNED_(8) __wasi_fdstat_t { + __wasi_filetype_t fs_filetype; + __wasi_fdflags_t fs_flags; + uint8_t __paddings[4]; + __wasi_rights_t fs_rights_base; + __wasi_rights_t fs_rights_inheriting; +} __wasi_fdstat_t; +assert_wasi_layout( + offsetof(__wasi_fdstat_t, fs_filetype) == 0, "non-wasi data layout"); +assert_wasi_layout(offsetof(__wasi_fdstat_t, fs_flags) == 2, "non-wasi data layout"); +assert_wasi_layout( + offsetof(__wasi_fdstat_t, fs_rights_base) == 8, "non-wasi data layout"); +assert_wasi_layout( + offsetof(__wasi_fdstat_t, fs_rights_inheriting) == 16, + "non-wasi data layout"); +assert_wasi_layout(sizeof(__wasi_fdstat_t) == 24, "non-wasi data layout"); +assert_wasi_layout(_Alignof(__wasi_fdstat_t) == 8, "non-wasi data layout"); + +typedef struct ALIGNED_(8) __wasi_filestat_t { + __wasi_device_t st_dev; + __wasi_inode_t st_ino; + __wasi_filetype_t st_filetype; + __wasi_linkcount_t st_nlink; + __wasi_filesize_t st_size; + __wasi_timestamp_t st_atim; + __wasi_timestamp_t st_mtim; + __wasi_timestamp_t st_ctim; +} __wasi_filestat_t; +assert_wasi_layout(offsetof(__wasi_filestat_t, st_dev) == 0, "non-wasi data layout"); +assert_wasi_layout(offsetof(__wasi_filestat_t, st_ino) == 8, "non-wasi data layout"); +assert_wasi_layout( + offsetof(__wasi_filestat_t, st_filetype) == 16, "non-wasi data layout"); +assert_wasi_layout( + offsetof(__wasi_filestat_t, st_nlink) == 24, "non-wasi data layout"); +assert_wasi_layout( + offsetof(__wasi_filestat_t, st_size) == 32, "non-wasi data layout"); +assert_wasi_layout( + offsetof(__wasi_filestat_t, st_atim) == 40, "non-wasi data layout"); +assert_wasi_layout( + offsetof(__wasi_filestat_t, st_mtim) == 48, "non-wasi data layout"); +assert_wasi_layout( + offsetof(__wasi_filestat_t, st_ctim) == 56, "non-wasi data layout"); +assert_wasi_layout(sizeof(__wasi_filestat_t) == 64, "non-wasi data layout"); +assert_wasi_layout(_Alignof(__wasi_filestat_t) == 8, "non-wasi data layout"); + +typedef struct __wasi_ciovec_t { + const void *buf; + size_t buf_len; +} __wasi_ciovec_t; +assert_wasi_layout(offsetof(__wasi_ciovec_t, buf) == 0, "non-wasi data layout"); +assert_wasi_layout(sizeof(void *) != 4 || + offsetof(__wasi_ciovec_t, buf_len) == 4, "non-wasi data layout"); +assert_wasi_layout(sizeof(void *) != 8 || + offsetof(__wasi_ciovec_t, buf_len) == 8, "non-wasi data layout"); +assert_wasi_layout(sizeof(void *) != 4 || + sizeof(__wasi_ciovec_t) == 8, "non-wasi data layout"); +assert_wasi_layout(sizeof(void *) != 8 || + sizeof(__wasi_ciovec_t) == 16, "non-wasi data layout"); +assert_wasi_layout(sizeof(void *) != 4 || + _Alignof(__wasi_ciovec_t) == 4, "non-wasi data layout"); +assert_wasi_layout(sizeof(void *) != 8 || + _Alignof(__wasi_ciovec_t) == 8, "non-wasi data layout"); + +typedef struct __wasi_iovec_t { + void *buf; + size_t buf_len; +} __wasi_iovec_t; +assert_wasi_layout(offsetof(__wasi_iovec_t, buf) == 0, "non-wasi data layout"); +assert_wasi_layout(sizeof(void *) != 4 || + offsetof(__wasi_iovec_t, buf_len) == 4, "non-wasi data layout"); +assert_wasi_layout(sizeof(void *) != 8 || + offsetof(__wasi_iovec_t, buf_len) == 8, "non-wasi data layout"); +assert_wasi_layout(sizeof(void *) != 4 || + sizeof(__wasi_iovec_t) == 8, "non-wasi data layout"); +assert_wasi_layout(sizeof(void *) != 8 || + sizeof(__wasi_iovec_t) == 16, "non-wasi data layout"); +assert_wasi_layout(sizeof(void *) != 4 || + _Alignof(__wasi_iovec_t) == 4, "non-wasi data layout"); +assert_wasi_layout(sizeof(void *) != 8 || + _Alignof(__wasi_iovec_t) == 8, "non-wasi data layout"); + +/** + * The contents of a `subscription` when type is `eventtype::clock`. + */ +typedef struct ALIGNED_(8) __wasi_subscription_clock_t { + /** + * The clock against which to compare the timestamp. + */ + __wasi_clockid_t clock_id; + + uint8_t __paddings1[4]; + + /** + * The absolute or relative timestamp. + */ + __wasi_timestamp_t timeout; + + /** + * The amount of time that the implementation may wait additionally + * to coalesce with other events. + */ + __wasi_timestamp_t precision; + + /** + * Flags specifying whether the timeout is absolute or relative + */ + __wasi_subclockflags_t flags; + + uint8_t __paddings2[4]; + +} __wasi_subscription_clock_t; + +assert_wasi_layout(sizeof(__wasi_subscription_clock_t) == 32, "witx calculated size"); +assert_wasi_layout(_Alignof(__wasi_subscription_clock_t) == 8, "witx calculated align"); +assert_wasi_layout(offsetof(__wasi_subscription_clock_t, clock_id) == 0, "witx calculated offset"); +assert_wasi_layout(offsetof(__wasi_subscription_clock_t, timeout) == 8, "witx calculated offset"); +assert_wasi_layout(offsetof(__wasi_subscription_clock_t, precision) == 16, "witx calculated offset"); +assert_wasi_layout(offsetof(__wasi_subscription_clock_t, flags) == 24, "witx calculated offset"); + +/** + * The contents of a `subscription` when type is type is + * `eventtype::fd_read` or `eventtype::fd_write`. + */ +typedef struct __wasi_subscription_fd_readwrite_t { + /** + * The file descriptor on which to wait for it to become ready for reading or writing. + */ + __wasi_fd_t fd; + +} __wasi_subscription_fd_readwrite_t; + +assert_wasi_layout(sizeof(__wasi_subscription_fd_readwrite_t) == 4, "witx calculated size"); +assert_wasi_layout(_Alignof(__wasi_subscription_fd_readwrite_t) == 4, "witx calculated align"); +assert_wasi_layout(offsetof(__wasi_subscription_fd_readwrite_t, fd) == 0, "witx calculated offset"); + +/** + * The contents of a `subscription`. + */ +typedef union __wasi_subscription_u_u_t { + __wasi_subscription_clock_t clock; + __wasi_subscription_fd_readwrite_t fd_readwrite; +} __wasi_subscription_u_u_t ; + +typedef struct ALIGNED_(8) __wasi_subscription_u_t { + __wasi_eventtype_t type; + __wasi_subscription_u_u_t u; +} __wasi_subscription_u_t; + +assert_wasi_layout(sizeof(__wasi_subscription_u_t) == 40, "witx calculated size"); +assert_wasi_layout(_Alignof(__wasi_subscription_u_t) == 8, "witx calculated align"); +assert_wasi_layout(offsetof(__wasi_subscription_u_t, u) == 8, "witx calculated union offset"); +assert_wasi_layout(sizeof(__wasi_subscription_u_u_t) == 32, "witx calculated union size"); +assert_wasi_layout(_Alignof(__wasi_subscription_u_u_t) == 8, "witx calculated union align"); + +/** + * Subscription to an event. + */ +typedef struct __wasi_subscription_t { + /** + * User-provided value that is attached to the subscription in the + * implementation and returned through `event::userdata`. + */ + __wasi_userdata_t userdata; + + /** + * The type of the event to which to subscribe, and its contents + */ + __wasi_subscription_u_t u; + +} __wasi_subscription_t; + +assert_wasi_layout(sizeof(__wasi_subscription_t) == 48, "witx calculated size"); +assert_wasi_layout(_Alignof(__wasi_subscription_t) == 8, "witx calculated align"); +assert_wasi_layout(offsetof(__wasi_subscription_t, userdata) == 0, "witx calculated offset"); +assert_wasi_layout(offsetof(__wasi_subscription_t, u) == 8, "witx calculated offset"); + +/* keep syncing with wasi_socket_ext.h */ +typedef enum { + /* Used only for sock_addr_resolve hints */ + SOCKET_ANY = -1, + SOCKET_DGRAM = 0, + SOCKET_STREAM, +} __wasi_sock_type_t; + +typedef uint16_t __wasi_ip_port_t; + +typedef enum { IPv4 = 0, IPv6 } __wasi_addr_type_t; + +/* n0.n1.n2.n3 */ +typedef struct __wasi_addr_ip4_t { + uint8_t n0; + uint8_t n1; + uint8_t n2; + uint8_t n3; +} __wasi_addr_ip4_t; + +typedef struct __wasi_addr_ip4_port_t { + __wasi_addr_ip4_t addr; + __wasi_ip_port_t port; +} __wasi_addr_ip4_port_t; + +typedef struct __wasi_addr_ip6_t { + uint16_t n0; + uint16_t n1; + uint16_t n2; + uint16_t n3; + uint16_t h0; + uint16_t h1; + uint16_t h2; + uint16_t h3; +} __wasi_addr_ip6_t; + +typedef struct __wasi_addr_ip6_port_t { + __wasi_addr_ip6_t addr; + __wasi_ip_port_t port; +} __wasi_addr_ip6_port_t; + +typedef struct __wasi_addr_ip_t { + __wasi_addr_type_t kind; + union { + __wasi_addr_ip4_t ip4; + __wasi_addr_ip6_t ip6; + } addr; +} __wasi_addr_ip_t; + +typedef struct __wasi_addr_t { + __wasi_addr_type_t kind; + union { + __wasi_addr_ip4_port_t ip4; + __wasi_addr_ip6_port_t ip6; + } addr; +} __wasi_addr_t; + +typedef enum { INET4 = 0, INET6, INET_UNSPEC } __wasi_address_family_t; + +typedef struct __wasi_addr_info_t { + __wasi_addr_t addr; + __wasi_sock_type_t type; +} __wasi_addr_info_t; + +typedef struct __wasi_addr_info_hints_t { + __wasi_sock_type_t type; + __wasi_address_family_t family; + // this is to workaround lack of optional parameters + uint8_t hints_enabled; +} __wasi_addr_info_hints_t; + +#undef assert_wasi_layout + +/* clang-format on */ +#ifdef __cplusplus +} +#endif + +#endif /* end of _PLATFORM_WASI_TYPES_H */ \ No newline at end of file diff --git a/core/shared/platform/linux-sgx/platform_internal.h b/core/shared/platform/linux-sgx/platform_internal.h index d18f015ee..c96768e32 100644 --- a/core/shared/platform/linux-sgx/platform_internal.h +++ b/core/shared/platform/linux-sgx/platform_internal.h @@ -50,6 +50,7 @@ typedef pthread_t korp_thread; typedef pthread_t korp_tid; typedef pthread_mutex_t korp_mutex; typedef pthread_cond_t korp_cond; +typedef pthread_rwlock_t korp_rwlock; typedef unsigned int korp_sem; #ifndef SGX_DISABLE_PTHREAD @@ -68,6 +69,16 @@ strcpy(char *dest, const char *src); #define os_memory_order_seq_cst __ATOMIC_SEQ_CST #define os_atomic_thread_fence __atomic_thread_fence +typedef int os_file_handle; +typedef DIR *os_dir_stream; +typedef int os_raw_file_handle; + +static inline os_file_handle +os_get_invalid_handle() +{ + return -1; +} + #ifdef __cplusplus } #endif diff --git a/core/shared/platform/linux-sgx/sgx_ipfs.h b/core/shared/platform/linux-sgx/sgx_ipfs.h index e4de90274..3a911d2b6 100644 --- a/core/shared/platform/linux-sgx/sgx_ipfs.h +++ b/core/shared/platform/linux-sgx/sgx_ipfs.h @@ -7,7 +7,6 @@ #define _LIBC_WASI_SGX_PFS_H #include "bh_hashmap.h" -#include "wasmtime_ssp.h" #ifdef __cplusplus extern "C" { diff --git a/core/shared/platform/linux-sgx/sgx_platform.c b/core/shared/platform/linux-sgx/sgx_platform.c index 1a90af4c6..32b956826 100644 --- a/core/shared/platform/linux-sgx/sgx_platform.c +++ b/core/shared/platform/linux-sgx/sgx_platform.c @@ -120,13 +120,20 @@ strcpy(char *dest, const char *src) } void * -os_mmap(void *hint, size_t size, int prot, int flags) +os_mmap(void *hint, size_t size, int prot, int flags, os_file_handle file) { int mprot = 0; uint64 aligned_size, page_size; void *ret = NULL; sgx_status_t st = 0; + if (os_is_handle_valid(&file)) { + os_printf("os_mmap(size=%u, prot=0x%x, file=%x) failed: file is not " + "supported.\n", + size, prot, file); + return NULL; + } + page_size = getpagesize(); aligned_size = (size + page_size - 1) & ~(page_size - 1); @@ -198,4 +205,4 @@ os_dcache_flush(void) void os_icache_flush(void *start, size_t len) -{} \ No newline at end of file +{} diff --git a/core/shared/platform/linux-sgx/sgx_thread.c b/core/shared/platform/linux-sgx/sgx_thread.c index d9412927b..73f3005fa 100644 --- a/core/shared/platform/linux-sgx/sgx_thread.c +++ b/core/shared/platform/linux-sgx/sgx_thread.c @@ -213,4 +213,69 @@ os_thread_get_stack_boundary() void os_thread_jit_write_protect_np(bool enabled) -{} \ No newline at end of file +{} + +int +os_rwlock_init(korp_rwlock *lock) +{ +#ifndef SGX_DISABLE_PTHREAD + assert(lock); + + if (pthread_rwlock_init(lock, NULL) != BHT_OK) + return BHT_ERROR; +#endif + + return BHT_OK; +} + +int +os_rwlock_rdlock(korp_rwlock *lock) +{ +#ifndef SGX_DISABLE_PTHREAD + assert(lock); + + if (pthread_rwlock_rdlock(lock) != BHT_OK) + return BHT_ERROR; +#endif + + return BHT_OK; +} + +int +os_rwlock_wrlock(korp_rwlock *lock) +{ +#ifndef SGX_DISABLE_PTHREAD + assert(lock); + + if (pthread_rwlock_wrlock(lock) != BHT_OK) + return BHT_ERROR; +#endif + + return BHT_OK; +} + +int +os_rwlock_unlock(korp_rwlock *lock) +{ +#ifndef SGX_DISABLE_PTHREAD + assert(lock); + + if (pthread_rwlock_unlock(lock) != BHT_OK) + return BHT_ERROR; +#endif + + return BHT_OK; +} + +int +os_rwlock_destroy(korp_rwlock *lock) +{ +#ifndef SGX_DISABLE_PTHREAD + assert(lock); + + if (pthread_rwlock_destroy(lock) != BHT_OK) + return BHT_ERROR; +#endif + + return BHT_OK; +} diff --git a/core/shared/platform/linux-sgx/shared_platform.cmake b/core/shared/platform/linux-sgx/shared_platform.cmake index b2de1ab06..e8e167005 100644 --- a/core/shared/platform/linux-sgx/shared_platform.cmake +++ b/core/shared/platform/linux-sgx/shared_platform.cmake @@ -20,16 +20,23 @@ if (NOT BUILD_UNTRUST_PART EQUAL 1) ${SGX_SDK_DIR}/include/libcxx) endif () -if (NOT WAMR_BUILD_LIBC_WASI EQUAL 1) - add_definitions(-DSGX_DISABLE_WASI) -endif () - if (NOT WAMR_BUILD_THREAD_MGR EQUAL 1) add_definitions(-DSGX_DISABLE_PTHREAD) endif () file (GLOB source_all ${PLATFORM_SHARED_DIR}/*.c) +if (NOT WAMR_BUILD_LIBC_WASI EQUAL 1) + add_definitions(-DSGX_DISABLE_WASI) +else() + list(APPEND source_all + ${PLATFORM_SHARED_DIR}/../common/posix/posix_file.c + ${PLATFORM_SHARED_DIR}/../common/posix/posix_clock.c + ) + include (${CMAKE_CURRENT_LIST_DIR}/../common/libc-util/platform_common_libc_util.cmake) + set(source_all ${source_all} ${PLATFORM_COMMON_LIBC_UTIL_SOURCE}) +endif() + file (GLOB source_all_untrusted ${PLATFORM_SHARED_DIR}/untrusted/*.c) set (PLATFORM_SHARED_SOURCE ${source_all}) diff --git a/core/shared/platform/linux/platform_internal.h b/core/shared/platform/linux/platform_internal.h index 337cdd9cc..335070bf8 100644 --- a/core/shared/platform/linux/platform_internal.h +++ b/core/shared/platform/linux/platform_internal.h @@ -55,6 +55,7 @@ typedef pthread_t korp_tid; typedef pthread_mutex_t korp_mutex; typedef pthread_cond_t korp_cond; typedef pthread_t korp_thread; +typedef pthread_rwlock_t korp_rwlock; typedef sem_t korp_sem; #define OS_THREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER @@ -121,6 +122,16 @@ os_sigreturn(); void os_set_signal_number_for_blocking_op(int signo); +typedef int os_file_handle; +typedef DIR *os_dir_stream; +typedef int os_raw_file_handle; + +static inline os_file_handle +os_get_invalid_handle() +{ + return -1; +} + #ifdef __cplusplus } #endif diff --git a/core/shared/platform/nuttx/nuttx_platform.c b/core/shared/platform/nuttx/nuttx_platform.c index 92c17ed48..38e70076d 100644 --- a/core/shared/platform/nuttx/nuttx_platform.c +++ b/core/shared/platform/nuttx/nuttx_platform.c @@ -85,7 +85,7 @@ os_dumps_proc_mem_info(char *out, unsigned int size) } void * -os_mmap(void *hint, size_t size, int prot, int flags) +os_mmap(void *hint, size_t size, int prot, int flags, os_file_handle file) { #if (WASM_MEM_DUAL_BUS_MIRROR != 0) void *i_addr, *d_addr; diff --git a/core/shared/platform/nuttx/platform_internal.h b/core/shared/platform/nuttx/platform_internal.h index 97ab5f697..2fb80a6e3 100644 --- a/core/shared/platform/nuttx/platform_internal.h +++ b/core/shared/platform/nuttx/platform_internal.h @@ -41,6 +41,7 @@ typedef pthread_t korp_tid; typedef pthread_mutex_t korp_mutex; typedef pthread_cond_t korp_cond; typedef pthread_t korp_thread; +typedef pthread_rwlock_t korp_rwlock; typedef sem_t korp_sem; #define OS_THREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER @@ -129,6 +130,16 @@ fdopendir(int fd); void os_set_signal_number_for_blocking_op(int signo); +typedef int os_file_handle; +typedef DIR *os_dir_stream; +typedef int os_raw_file_handle; + +static inline os_file_handle +os_get_invalid_handle() +{ + return -1; +} + #ifdef __cplusplus } #endif diff --git a/core/shared/platform/nuttx/shared_platform.cmake b/core/shared/platform/nuttx/shared_platform.cmake index 7b29b5f09..1cbe2218b 100644 --- a/core/shared/platform/nuttx/shared_platform.cmake +++ b/core/shared/platform/nuttx/shared_platform.cmake @@ -10,5 +10,11 @@ include_directories(${PLATFORM_SHARED_DIR}/../include) file (GLOB_RECURSE source_all ${PLATFORM_SHARED_DIR}/*.c) +if (WAMR_BUILD_LIBC_WASI EQUAL 1) + list(APPEND source_all ${PLATFORM_SHARED_DIR}/../common/posix/posix_file.c) + include (${CMAKE_CURRENT_LIST_DIR}/../common/libc-util/platform_common_libc_util.cmake) + set(source_all ${source_all} ${PLATFORM_COMMON_LIBC_UTIL_SOURCE}) +endif () + set (PLATFORM_SHARED_SOURCE ${source_all} ${PLATFORM_COMMON_MATH_SOURCE}) diff --git a/core/shared/platform/riot/platform_internal.h b/core/shared/platform/riot/platform_internal.h index 8fec6dd0b..1f71ffdb2 100644 --- a/core/shared/platform/riot/platform_internal.h +++ b/core/shared/platform/riot/platform_internal.h @@ -52,6 +52,10 @@ typedef struct korp_cond { #define os_printf printf #define os_vprintf vprintf +typedef int os_file_handle; +typedef DIR *os_dir_stream; +typedef int os_raw_file_handle; + #if WA_MATH /* clang-format off */ /* math functions which are not provided by os*/ @@ -76,4 +80,10 @@ int isnan(double x); /* clang-format on */ #endif +static inline os_file_handle +os_get_invalid_handle() +{ + return -1; +} + #endif /* end of _BH_PLATFORM_H */ diff --git a/core/shared/platform/riot/riot_platform.c b/core/shared/platform/riot/riot_platform.c index 6fd6617b4..ad5927e51 100644 --- a/core/shared/platform/riot/riot_platform.c +++ b/core/shared/platform/riot/riot_platform.c @@ -50,7 +50,7 @@ os_dumps_proc_mem_info(char *out, unsigned int size) } void * -os_mmap(void *hint, size_t size, int prot, int flags) +os_mmap(void *hint, size_t size, int prot, int flags, os_file_handle file) { if (size > ((unsigned)~0)) return NULL; diff --git a/core/shared/platform/rt-thread/platform_internal.h b/core/shared/platform/rt-thread/platform_internal.h index 5f9cc8bc8..0c2e1d82b 100644 --- a/core/shared/platform/rt-thread/platform_internal.h +++ b/core/shared/platform/rt-thread/platform_internal.h @@ -45,4 +45,14 @@ typedef rt_int16_t int16_t; typedef rt_uint64_t uint64_t; typedef rt_int64_t int64_t; +typedef int os_file_handle; +typedef DIR *os_dir_stream; +typedef int os_raw_file_handle; + +static inline os_file_handle +os_get_invalid_handle() +{ + return -1; +} + #endif /* RTTHREAD_PLATFORM_INTERNAL_H */ diff --git a/core/shared/platform/rt-thread/rtt_platform.c b/core/shared/platform/rt-thread/rtt_platform.c index 6dc719f01..37b247d35 100644 --- a/core/shared/platform/rt-thread/rtt_platform.c +++ b/core/shared/platform/rt-thread/rtt_platform.c @@ -191,7 +191,7 @@ os_cond_wait(korp_cond *cond, korp_mutex *mutex) } void * -os_mmap(void *hint, size_t size, int prot, int flags) +os_mmap(void *hint, size_t size, int prot, int flags, os_file_handle file) { return rt_malloc(size); } diff --git a/core/shared/platform/vxworks/platform_internal.h b/core/shared/platform/vxworks/platform_internal.h index f72f60322..930ff7777 100644 --- a/core/shared/platform/vxworks/platform_internal.h +++ b/core/shared/platform/vxworks/platform_internal.h @@ -54,12 +54,17 @@ typedef pthread_t korp_tid; typedef pthread_mutex_t korp_mutex; typedef pthread_cond_t korp_cond; typedef pthread_t korp_thread; +typedef pthread_rwlock_t korp_rwlock; typedef sem_t korp_sem; #define OS_THREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER #define os_thread_local_attribute __thread +typedef int os_file_handle; +typedef DIR *os_dir_stream; +typedef int os_raw_file_handle; + #if WASM_DISABLE_HW_BOUND_CHECK == 0 #if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) \ || defined(BUILD_TARGET_AARCH64) @@ -95,6 +100,12 @@ os_sigreturn(); #endif /* end of BUILD_TARGET_X86_64/AMD_64/AARCH64 */ #endif /* end of WASM_DISABLE_HW_BOUND_CHECK */ +static inline os_file_handle +os_get_invalid_handle() +{ + return -1; +} + #ifdef __cplusplus } #endif diff --git a/core/shared/platform/windows/platform_internal.h b/core/shared/platform/windows/platform_internal.h index 500ab200c..8bb77e7cb 100644 --- a/core/shared/platform/windows/platform_internal.h +++ b/core/shared/platform/windows/platform_internal.h @@ -25,10 +25,14 @@ #include #include #include +#include #include #include #include #include +#include + +#include "platform_wasi_types.h" #ifdef __cplusplus extern "C" { @@ -57,6 +61,11 @@ typedef void *korp_tid; typedef void *korp_mutex; typedef void *korp_sem; +typedef struct { + SRWLOCK lock; + bool exclusive; +} korp_rwlock; + /** * Create the mutex when os_mutex_lock is called, and no need to * CloseHandle() for the static lock's lifetime, since @@ -76,8 +85,6 @@ typedef struct korp_cond { struct os_thread_wait_node *thread_wait_list_end; } korp_cond; -#define bh_socket_t SOCKET - unsigned os_getpagesize(); void * @@ -131,6 +138,61 @@ bh_atomic_thread_fence(int mem_order); #define os_atomic_thread_fence bh_atomic_thread_fence +typedef enum windows_handle_type { + windows_handle_type_socket, + windows_handle_type_file +} windows_handle_type; + +typedef enum windows_access_mode { + windows_access_mode_read = 1 << 0, + windows_access_mode_write = 1 << 1 +} windows_access_mode; + +typedef struct windows_handle { + windows_handle_type type; + __wasi_fdflags_t fdflags; + windows_access_mode access_mode; + union { + HANDLE handle; + SOCKET socket; + } raw; +} windows_handle; + +typedef struct windows_dir_stream { + // Enough space for the wide filename and the info struct itself + char info_buf[PATH_MAX * sizeof(wchar_t) + sizeof(FILE_ID_BOTH_DIR_INFO)]; + char current_entry_name[PATH_MAX]; + // An offset into info_buf to read the next entry from + DWORD cursor; + int cookie; + windows_handle *handle; +} windows_dir_stream; + +typedef windows_handle *os_file_handle; +typedef windows_dir_stream *os_dir_stream; + +#if WASM_ENABLE_UVWASI != 1 +typedef HANDLE os_raw_file_handle; +#else +typedef uint32_t os_raw_file_handle; +#endif + +#define bh_socket_t windows_handle * + +// UWP apps do not have stdout/stderr handles so provide a default +// implementation of vprintf on debug builds so output from WASI libc is sent to +// the debugger and not lost completely. +#if !defined(BH_VPRINTF) && !defined(NDEBUG) && WINAPI_PARTITION_DESKTOP == 0 +#define BH_VPRINTF uwp_print_to_debugger +#define UWP_DEFAULT_VPRINTF +#endif + +static inline os_file_handle +os_get_invalid_handle() +{ + return NULL; +} + #ifdef __cplusplus } #endif diff --git a/core/shared/platform/windows/shared_platform.cmake b/core/shared/platform/windows/shared_platform.cmake index a68d63177..3c531c17c 100644 --- a/core/shared/platform/windows/shared_platform.cmake +++ b/core/shared/platform/windows/shared_platform.cmake @@ -13,6 +13,13 @@ include_directories(${PLATFORM_SHARED_DIR}/../include) file (GLOB_RECURSE source_all ${PLATFORM_SHARED_DIR}/*.c ${PLATFORM_SHARED_DIR}/*.cpp) +if (NOT WAMR_BUILD_LIBC_WASI EQUAL 1) + list(REMOVE_ITEM source_all ${PLATFORM_SHARED_DIR}/win_file.c) +else() + include (${CMAKE_CURRENT_LIST_DIR}/../common/libc-util/platform_common_libc_util.cmake) + set(source_all ${source_all} ${PLATFORM_COMMON_LIBC_UTIL_SOURCE}) +endif() + set (PLATFORM_SHARED_SOURCE ${source_all}) file (GLOB header ${PLATFORM_SHARED_DIR}/../include/*.h) diff --git a/core/shared/platform/windows/win_atomic.cpp b/core/shared/platform/windows/win_atomic.cpp index 80e8ef518..4e09405bb 100644 --- a/core/shared/platform/windows/win_atomic.cpp +++ b/core/shared/platform/windows/win_atomic.cpp @@ -14,8 +14,8 @@ void bh_atomic_thread_fence(int mem_order) { std::memory_order order = - (std::memory_order)(std::memory_order::memory_order_relaxed + mem_order - - os_memory_order_relaxed); + (std::memory_order)((int)std::memory_order::memory_order_relaxed + + mem_order - os_memory_order_relaxed); std::atomic_thread_fence(order); } diff --git a/core/shared/platform/windows/win_clock.c b/core/shared/platform/windows/win_clock.c new file mode 100644 index 000000000..c96bdfb3b --- /dev/null +++ b/core/shared/platform/windows/win_clock.c @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2023 Amazon Inc. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "platform_api_extension.h" +#include +#include "win_util.h" + +#define NANOSECONDS_PER_SECOND 1000000000ULL +#define NANOSECONDS_PER_TICK 100 + +static __wasi_errno_t +calculate_monotonic_clock_frequency(uint64 *out_frequency) +{ + LARGE_INTEGER frequency; + if (!QueryPerformanceFrequency(&frequency)) + return convert_windows_error_code(GetLastError()); + + *out_frequency = (uint64)frequency.QuadPart; + return __WASI_ESUCCESS; +} + +static __wasi_errno_t +get_performance_counter_value(uint64 *out_counter) +{ + LARGE_INTEGER counter; + if (!QueryPerformanceCounter(&counter)) + return convert_windows_error_code(GetLastError()); + + *out_counter = counter.QuadPart; + return __WASI_ESUCCESS; +} + +__wasi_errno_t +os_clock_res_get(__wasi_clockid_t clock_id, __wasi_timestamp_t *resolution) +{ + __wasi_errno_t error = __WASI_ESUCCESS; + + switch (clock_id) { + case __WASI_CLOCK_MONOTONIC: + { + uint64 frequency; + error = calculate_monotonic_clock_frequency(&frequency); + + if (error != __WASI_ESUCCESS) + return error; + + const uint64 result = (uint64)NANOSECONDS_PER_SECOND / frequency; + *resolution = result; + return error; + } + case __WASI_CLOCK_REALTIME: + case __WASI_CLOCK_PROCESS_CPUTIME_ID: + case __WASI_CLOCK_THREAD_CPUTIME_ID: + { +#if WINAPI_PARTITION_DESKTOP + ULONG maximum_time; + ULONG minimum_time; + ULONG current_time; + NTSTATUS + status = NtQueryTimerResolution(&maximum_time, &minimum_time, + ¤t_time); + uint64 result = (uint64)current_time * NANOSECONDS_PER_TICK; + *resolution = result / (uint64)NANOSECONDS_PER_SECOND; + return error; +#else + return __WASI_ENOTSUP; +#endif + } + default: + return __WASI_EINVAL; + } +} + +__wasi_errno_t +os_clock_time_get(__wasi_clockid_t clock_id, __wasi_timestamp_t precision, + __wasi_timestamp_t *time) +{ + __wasi_errno_t error = __WASI_ESUCCESS; + + switch (clock_id) { + case __WASI_CLOCK_REALTIME: + { + FILETIME sys_now; +#if NTDDI_VERSION >= NTDDI_WIN8 + GetSystemTimePreciseAsFileTime(&sys_now); +#else + GetSystemTimeAsFileTime(&sys_now); +#endif + *time = convert_filetime_to_wasi_timestamp(&sys_now); + return BHT_OK; + } + case __WASI_CLOCK_MONOTONIC: + { + uint64 frequency; + error = calculate_monotonic_clock_frequency(&frequency); + + if (error != __WASI_ESUCCESS) + return error; + + uint64 counter; + error = get_performance_counter_value(&counter); + + if (error != __WASI_ESUCCESS) + return error; + + if (NANOSECONDS_PER_SECOND % frequency == 0) { + *time = counter * NANOSECONDS_PER_SECOND / frequency; + } + else { + uint64 seconds = counter / frequency; + uint64 fractions = counter % frequency; + *time = seconds * NANOSECONDS_PER_SECOND + + (fractions * NANOSECONDS_PER_SECOND) / frequency; + } + return error; + } + case __WASI_CLOCK_PROCESS_CPUTIME_ID: + case __WASI_CLOCK_THREAD_CPUTIME_ID: + { + FILETIME creation_time; + FILETIME exit_time; + FILETIME kernel_time; + FILETIME user_time; + + HANDLE handle = (clock_id == __WASI_CLOCK_PROCESS_CPUTIME_ID) + ? GetCurrentProcess() + : GetCurrentThread(); + + if (!GetProcessTimes(handle, &creation_time, &exit_time, + &kernel_time, &user_time)) + return convert_windows_error_code(GetLastError()); + + *time = convert_filetime_to_wasi_timestamp(&kernel_time) + + convert_filetime_to_wasi_timestamp(&user_time); + + return error; + } + default: + return __WASI_EINVAL; + } +} \ No newline at end of file diff --git a/core/shared/platform/windows/win_file.c b/core/shared/platform/windows/win_file.c new file mode 100644 index 000000000..7e153b34e --- /dev/null +++ b/core/shared/platform/windows/win_file.c @@ -0,0 +1,1491 @@ +/* + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "platform_api_extension.h" +#include "libc_errno.h" +#include "win_util.h" + +#include "PathCch.h" + +#pragma comment(lib, "Pathcch.lib") + +#define CHECK_VALID_HANDLE_WITH_RETURN_VALUE(win_handle, ret) \ + do { \ + if ((win_handle) == NULL \ + || ((win_handle)->type == windows_handle_type_socket \ + && (win_handle)->raw.socket == INVALID_SOCKET) \ + || ((win_handle)->type == windows_handle_type_file \ + && (win_handle)->raw.handle == INVALID_HANDLE_VALUE)) \ + return (ret); \ + \ + } while (0) + +#define CHECK_VALID_HANDLE(win_handle) \ + CHECK_VALID_HANDLE_WITH_RETURN_VALUE(win_handle, __WASI_EBADF) + +#define CHECK_VALID_FILE_HANDLE(win_handle) \ + do { \ + if ((win_handle) == NULL) \ + return __WASI_EBADF; \ + \ + if ((win_handle)->type == windows_handle_type_socket) \ + return __WASI_EINVAL; \ + \ + if (((win_handle)->type == windows_handle_type_file \ + && (win_handle)->raw.handle == INVALID_HANDLE_VALUE)) \ + return __WASI_EBADF; \ + \ + } while (0) + +#define CHECK_VALID_WIN_DIR_STREAM(win_dir_stream) \ + do { \ + if ((win_dir_stream) == NULL) \ + return __WASI_EINVAL; \ + CHECK_VALID_FILE_HANDLE((win_dir_stream)->handle); \ + } while (0) + +static __wasi_errno_t +convert_winsock_error_code(int error_code) +{ + switch (error_code) { + case WSASYSNOTREADY: + case WSAEWOULDBLOCK: + return __WASI_EAGAIN; + case WSAVERNOTSUPPORTED: + return __WASI_ENOTSUP; + case WSAEINPROGRESS: + return __WASI_EINPROGRESS; + case WSAEPROCLIM: + return __WASI_EBUSY; + case WSAEFAULT: + return __WASI_EFAULT; + case WSAENETDOWN: + return __WASI_ENETDOWN; + case WSAENOTSOCK: + return __WASI_ENOTSOCK; + case WSAEINTR: + return __WASI_EINTR; + case WSAEAFNOSUPPORT: + return __WASI_EAFNOSUPPORT; + case WSAEMFILE: + return __WASI_ENFILE; + case WSAEINVAL: + return __WASI_EINVAL; + case WSAENOBUFS: + return __WASI_ENOBUFS; + case WSAEPROTONOSUPPORT: + return __WASI_EPROTONOSUPPORT; + case WSAEPROTOTYPE: + return __WASI_EPROTOTYPE; + case WSAESOCKTNOSUPPORT: + return __WASI_ENOTSUP; + case WSAEINVALIDPROCTABLE: + case WSAEINVALIDPROVIDER: + case WSAEPROVIDERFAILEDINIT: + case WSANOTINITIALISED: + default: + return __WASI_EINVAL; + } +} + +static __wasi_filetype_t +get_disk_filetype(DWORD attribute) +{ + if (attribute == INVALID_FILE_ATTRIBUTES) + return __WASI_FILETYPE_UNKNOWN; + if (attribute & FILE_ATTRIBUTE_REPARSE_POINT) + return __WASI_FILETYPE_SYMBOLIC_LINK; + if (attribute & FILE_ATTRIBUTE_DIRECTORY) + return __WASI_FILETYPE_DIRECTORY; + + return __WASI_FILETYPE_REGULAR_FILE; +} + +static __wasi_filetype_t +get_socket_filetype(SOCKET socket) +{ + char socket_type = 0; + int size = sizeof(socket_type); + + if (getsockopt(socket, SOL_SOCKET, SO_TYPE, &socket_type, &size) == 0) { + switch (socket_type) { + case SOCK_STREAM: + return __WASI_FILETYPE_SOCKET_STREAM; + case SOCK_DGRAM: + return __WASI_FILETYPE_SOCKET_DGRAM; + } + } + return __WASI_FILETYPE_UNKNOWN; +} + +static __wasi_errno_t +convert_windows_filetype(os_file_handle handle, DWORD filetype, + __wasi_filetype_t *out_filetype) +{ + __wasi_errno_t error = __WASI_ESUCCESS; + + switch (filetype) { + case FILE_TYPE_DISK: + FILE_ATTRIBUTE_TAG_INFO file_info; + + bool success = GetFileInformationByHandleEx( + handle->raw.handle, FileAttributeTagInfo, &file_info, + sizeof(file_info)); + + if (!success + || file_info.FileAttributes == INVALID_FILE_ATTRIBUTES) { + error = convert_windows_error_code(GetLastError()); + break; + } + + *out_filetype = get_disk_filetype(file_info.FileAttributes); + break; + case FILE_TYPE_CHAR: + *out_filetype = __WASI_FILETYPE_CHARACTER_DEVICE; + break; + case FILE_TYPE_PIPE: + if (handle->type == windows_handle_type_socket) + *out_filetype = get_socket_filetype(handle->raw.socket); + else + *out_filetype = __WASI_FILETYPE_BLOCK_DEVICE; + + break; + case FILE_TYPE_REMOTE: + case FILE_TYPE_UNKNOWN: + default: + *out_filetype = __WASI_FILETYPE_UNKNOWN; + } + + return error; +} + +// Converts the input string to a wchar string. +static __wasi_errno_t +convert_to_wchar(const char *str, wchar_t *buf, size_t buf_size) +{ + int converted_chars = + MultiByteToWideChar(CP_UTF8, 0, str, -1, buf, (int)buf_size); + + if (converted_chars == 0) + return convert_windows_error_code(GetLastError()); + + return __WASI_ESUCCESS; +} + +// Get the filepath for a handle. The size of the buffer should be specified in +// terms of wchar. +static __wasi_errno_t +get_handle_filepath(HANDLE handle, wchar_t *buf, DWORD buf_size) +{ + DWORD bufsize_in_chars = buf_size * (sizeof(wchar_t) / sizeof(char)); + DWORD size = GetFinalPathNameByHandleW( + handle, buf, bufsize_in_chars, FILE_NAME_NORMALIZED | VOLUME_NAME_NONE); + + if (size > bufsize_in_chars) + return __WASI_ENAMETOOLONG; + + if (size == 0) + return convert_windows_error_code(GetLastError()); + + return __WASI_ESUCCESS; +} + +static __wasi_errno_t +convert_hresult_error_code(HRESULT error_code) +{ + switch (error_code) { + case E_OUTOFMEMORY: + return __WASI_ENOMEM; + case E_INVALIDARG: + default: + return __WASI_EINVAL; + } +} + +// Returns the absolute filepath from the relative path to the directory +// associated with the provided handle. +static __wasi_errno_t +get_absolute_filepath(HANDLE handle, const char *relative_path, + wchar_t *absolute_path, size_t buf_len) +{ + wchar_t handle_path[PATH_MAX]; + + __wasi_errno_t error = get_handle_filepath(handle, handle_path, PATH_MAX); + + if (error != __WASI_ESUCCESS) + return error; + + wchar_t relative_wpath[PATH_MAX]; + error = convert_to_wchar(relative_path, relative_wpath, PATH_MAX); + + if (error != __WASI_ESUCCESS) + return error; + + HRESULT ret = + PathCchCombine(absolute_path, buf_len, handle_path, relative_wpath); + if (ret != S_OK) + error = convert_hresult_error_code(ret); + + return error; +} + +static bool +has_directory_attribute(DWORD attributes) +{ + if (attributes == INVALID_FILE_ATTRIBUTES) + return false; + + return (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0; +} + +static bool +is_directory(const wchar_t *path) +{ + DWORD attributes = GetFileAttributesW(path); + + return has_directory_attribute(attributes); +} + +static bool +has_symlink_attribute(DWORD attributes) +{ + if (attributes == INVALID_FILE_ATTRIBUTES) + return false; + + return (attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0; +} + +static bool +is_symlink(const wchar_t *path) +{ + DWORD attributes = GetFileAttributesW(path); + + return has_symlink_attribute(attributes); +} + +static void +init_dir_stream(os_dir_stream dir_stream, os_file_handle handle) +{ + dir_stream->cursor = 0; + dir_stream->handle = handle; + dir_stream->cookie = 0; +} + +// Advances to the next directory entry and optionally reads into to the +// provided buffer if not NULL. +static __wasi_errno_t +read_next_dir_entry(os_dir_stream dir_stream, FILE_ID_BOTH_DIR_INFO **out_entry) +{ + FILE_INFO_BY_HANDLE_CLASS file_info_class; + + if (dir_stream->cookie == 0) + file_info_class = FileIdBothDirectoryRestartInfo; + else + file_info_class = FileIdBothDirectoryInfo; + + if (dir_stream->cursor == 0 + && !GetFileInformationByHandleEx(dir_stream->handle->raw.handle, + file_info_class, dir_stream->info_buf, + sizeof(dir_stream->info_buf))) { + if (out_entry != NULL) + *out_entry = NULL; + DWORD win_error = GetLastError(); + // We've reached the end of the directory - return success + if (win_error == ERROR_NO_MORE_FILES) { + dir_stream->cookie = 0; + dir_stream->cursor = 0; + return __WASI_ESUCCESS; + } + + return convert_windows_error_code(win_error); + } + + FILE_ID_BOTH_DIR_INFO *current_info = + (FILE_ID_BOTH_DIR_INFO *)(dir_stream->info_buf + dir_stream->cursor); + + if (current_info->NextEntryOffset == 0) + dir_stream->cursor = 0; + else + dir_stream->cursor += current_info->NextEntryOffset; + + ++dir_stream->cookie; + + if (out_entry != NULL) + *out_entry = current_info; + else + return __WASI_ESUCCESS; + + // Convert and copy over the wchar filename into the entry_name buf + int ret = WideCharToMultiByte( + CP_UTF8, 0, current_info->FileName, + current_info->FileNameLength / (sizeof(wchar_t) / sizeof(char)), + dir_stream->current_entry_name, sizeof(dir_stream->current_entry_name), + NULL, NULL); + + if (ret == 0) + return convert_windows_error_code(GetLastError()); + + return __WASI_ESUCCESS; +} + +static HANDLE +create_handle(wchar_t *path, bool is_dir, bool follow_symlink, bool readonly) +{ + CREATEFILE2_EXTENDED_PARAMETERS create_params; + + create_params.dwSize = sizeof(create_params); + create_params.dwFileAttributes = FILE_ATTRIBUTE_NORMAL; + create_params.dwSecurityQosFlags = 0; + create_params.dwFileFlags = 0; + create_params.lpSecurityAttributes = NULL; + create_params.hTemplateFile = NULL; + + if (is_dir) { + create_params.dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY; + create_params.dwFileFlags |= FILE_FLAG_BACKUP_SEMANTICS; + } + + if (!follow_symlink) + create_params.dwFileFlags |= FILE_FLAG_OPEN_REPARSE_POINT; + + DWORD desired_access = GENERIC_READ; + + if (!readonly) + desired_access |= GENERIC_WRITE; + else + create_params.dwFileAttributes |= FILE_ATTRIBUTE_READONLY; + + return CreateFile2(path, desired_access, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + OPEN_EXISTING, &create_params); +} + +#if WINAPI_PARTITION_DESKTOP == 0 +// Modifies the given path in place and replaces it with the filename component +// (including the extension) of the path. +static __wasi_errno_t +extract_filename_from_path(wchar_t *path, size_t buf_size) +{ + wchar_t extension[256]; + wchar_t filename[256]; + __wasi_errno_t error = __WASI_ESUCCESS; + + // Get the filename from the fullpath. + errno_t ret = + _wsplitpath_s(path, NULL, 0, NULL, 0, filename, 256, extension, 256); + if (ret != 0) { + error = convert_errno(ret); + return error; + } + + ret = wcscat_s(filename, 256, extension); + + if (ret != 0) { + error = convert_errno(ret); + return error; + } + + ret = wcscpy_s(path, buf_size, filename); + + if (ret != 0) + error = convert_errno(ret); + + return error; +} + +static __wasi_errno_t +get_handle_to_parent_directory(HANDLE handle, HANDLE *out_dir_handle) +{ + wchar_t path[PATH_MAX]; + __wasi_errno_t error = get_handle_filepath(handle, path, PATH_MAX); + + if (error != __WASI_ESUCCESS) + return error; + + wchar_t parent_dir_path[PATH_MAX]; + errno_t ret = wcscpy_s(parent_dir_path, PATH_MAX, path); + + if (ret != 0) { + error = convert_errno(ret); + return error; + } + + ret = wcscat_s(parent_dir_path, PATH_MAX, L"/.."); + + if (ret != 0) { + error = convert_errno(ret); + return error; + } + + HANDLE dir_handle = create_handle(parent_dir_path, true, true, true); + + if (dir_handle == INVALID_HANDLE_VALUE) { + error = convert_windows_error_code(GetLastError()); + return error; + } + + *out_dir_handle = dir_handle; + return error; +} + +// The easiest way to get all the necessary file information for files is to +// open a handle to the parent directory and iterate through the entries via +// FileIdBothDirectoryInfo. Other file information classes are only +// available on desktop. +static __wasi_errno_t +get_disk_file_information(HANDLE handle, __wasi_filestat_t *buf) +{ + __wasi_errno_t error = __WASI_ESUCCESS; + HANDLE raw_dir_handle = INVALID_HANDLE_VALUE; + + wchar_t path[PATH_MAX] = L"."; + + if (buf->st_filetype != __WASI_FILETYPE_DIRECTORY) { + error = get_handle_filepath(handle, path, PATH_MAX); + + if (error != __WASI_ESUCCESS) + goto fail; + + error = get_handle_to_parent_directory(handle, &raw_dir_handle); + + if (error != __WASI_ESUCCESS) + goto fail; + + error = extract_filename_from_path(path, PATH_MAX); + + if (error != __WASI_ESUCCESS) + goto fail; + } + else { + raw_dir_handle = handle; + } + + windows_handle dir_handle = { .access_mode = windows_access_mode_read, + .raw = { .handle = raw_dir_handle }, + .fdflags = 0, + .type = windows_handle_type_file }; + windows_dir_stream dir_stream; + init_dir_stream(&dir_stream, &dir_handle); + + do { + FILE_ID_BOTH_DIR_INFO *file_id_both_dir_info = NULL; + __wasi_errno_t error = + read_next_dir_entry(&dir_stream, &file_id_both_dir_info); + + if (error != __WASI_ESUCCESS || file_id_both_dir_info == NULL) + goto fail; + + const DWORD filename_length = file_id_both_dir_info->FileNameLength + / (sizeof(wchar_t) / sizeof(char)); + + if (wcsncmp(file_id_both_dir_info->FileName, path, filename_length) + == 0) { + buf->st_ino = + (__wasi_inode_t)(file_id_both_dir_info->FileId.QuadPart); + buf->st_atim = convert_filetime_to_wasi_timestamp( + (LPFILETIME)&file_id_both_dir_info->LastAccessTime.QuadPart); + buf->st_mtim = convert_filetime_to_wasi_timestamp( + (LPFILETIME)&file_id_both_dir_info->LastWriteTime.QuadPart); + buf->st_ctim = convert_filetime_to_wasi_timestamp( + (LPFILETIME)&file_id_both_dir_info->ChangeTime.QuadPart); + buf->st_size = + (__wasi_filesize_t)(file_id_both_dir_info->EndOfFile.QuadPart); + + break; + } + } while (dir_stream.cookie != 0); + + FILE_STANDARD_INFO file_standard_info; + + bool success = GetFileInformationByHandleEx(handle, FileStandardInfo, + &file_standard_info, + sizeof(file_standard_info)); + + if (!success) { + error = convert_windows_error_code(GetLastError()); + goto fail; + } + + buf->st_nlink = (__wasi_linkcount_t)file_standard_info.NumberOfLinks; +fail: + if (buf->st_filetype != __WASI_FILETYPE_DIRECTORY + && raw_dir_handle != INVALID_HANDLE_VALUE) + CloseHandle(raw_dir_handle); + + return error; +} + +#else + +static __wasi_errno_t +get_disk_file_information(HANDLE handle, __wasi_filestat_t *buf) +{ + __wasi_errno_t error = __WASI_ESUCCESS; + FILE_BASIC_INFO file_basic_info; + + int ret = GetFileInformationByHandleEx( + handle, FileBasicInfo, &file_basic_info, sizeof(file_basic_info)); + + if (ret == 0) { + error = convert_windows_error_code(GetLastError()); + return error; + } + + buf->st_atim = convert_filetime_to_wasi_timestamp( + (LPFILETIME)&file_basic_info.LastAccessTime.QuadPart); + buf->st_mtim = convert_filetime_to_wasi_timestamp( + (LPFILETIME)&file_basic_info.LastWriteTime.QuadPart); + buf->st_ctim = convert_filetime_to_wasi_timestamp( + (LPFILETIME)&file_basic_info.ChangeTime.QuadPart); + + BY_HANDLE_FILE_INFORMATION file_info; + ret = GetFileInformationByHandle(handle, &file_info); + + if (ret == 0) { + error = convert_windows_error_code(GetLastError()); + return error; + } + + ULARGE_INTEGER file_size = { .LowPart = file_info.nFileSizeLow, + .HighPart = file_info.nFileSizeHigh }; + buf->st_size = (__wasi_filesize_t)(file_size.QuadPart); + + ULARGE_INTEGER file_id = { .LowPart = file_info.nFileIndexLow, + .HighPart = file_info.nFileIndexHigh }; + buf->st_ino = (__wasi_inode_t)(file_id.QuadPart); + + buf->st_dev = (__wasi_device_t)file_info.dwVolumeSerialNumber; + buf->st_nlink = (__wasi_linkcount_t)file_info.nNumberOfLinks; + + return error; +} + +#endif /* end of WINAPI_PARTITION_DESKTOP == 0 */ + +static __wasi_errno_t +get_file_information(os_file_handle handle, __wasi_filestat_t *buf) +{ + __wasi_errno_t error = __WASI_ESUCCESS; + + DWORD windows_filetype = GetFileType(handle->raw.handle); + error = + convert_windows_filetype(handle, windows_filetype, &buf->st_filetype); + + if (error != __WASI_ESUCCESS) + return error; + + buf->st_dev = 0; + + if (windows_filetype != FILE_TYPE_DISK) { + buf->st_atim = 0; + buf->st_ctim = 0; + buf->st_mtim = 0; + buf->st_nlink = 0; + buf->st_size = 0; + buf->st_ino = 0; + + return error; + } + + return get_disk_file_information(handle->raw.handle, buf); +} + +__wasi_errno_t +os_fstat(os_file_handle handle, struct __wasi_filestat_t *buf) +{ + CHECK_VALID_HANDLE(handle); + + return get_file_information(handle, buf); +} + +__wasi_errno_t +os_fstatat(os_file_handle handle, const char *path, + struct __wasi_filestat_t *buf, __wasi_lookupflags_t lookup_flags) +{ + CHECK_VALID_FILE_HANDLE(handle); + + return __WASI_ENOSYS; +} + +__wasi_errno_t +os_file_get_fdflags(os_file_handle handle, __wasi_fdflags_t *flags) +{ + CHECK_VALID_HANDLE(handle); + + *flags = handle->fdflags; + return __WASI_ESUCCESS; +} + +__wasi_errno_t +os_file_set_fdflags(os_file_handle handle, __wasi_fdflags_t flags) +{ + CHECK_VALID_HANDLE(handle); + + return __WASI_ENOSYS; +} + +__wasi_errno_t +os_file_get_access_mode(os_file_handle handle, + wasi_libc_file_access_mode *access_mode) +{ + CHECK_VALID_HANDLE(handle); + + if ((handle->access_mode & windows_access_mode_read) != 0 + && (handle->access_mode & windows_access_mode_write) != 0) + *access_mode = WASI_LIBC_ACCESS_MODE_READ_WRITE; + else if ((handle->access_mode & windows_access_mode_write) != 0) + *access_mode = WASI_LIBC_ACCESS_MODE_WRITE_ONLY; + else + *access_mode = WASI_LIBC_ACCESS_MODE_READ_ONLY; + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +os_fdatasync(os_file_handle handle) +{ + CHECK_VALID_FILE_HANDLE(handle); + + return __WASI_ENOSYS; +} + +__wasi_errno_t +os_fsync(os_file_handle handle) +{ + CHECK_VALID_FILE_HANDLE(handle); + + return __WASI_ENOSYS; +} + +__wasi_errno_t +os_open_preopendir(const char *path, os_file_handle *out) +{ + *out = NULL; + + wchar_t wpath[PATH_MAX]; + __wasi_errno_t error = convert_to_wchar(path, wpath, PATH_MAX); + + if (error != __WASI_ESUCCESS) + return error; + + HANDLE dir_handle = create_handle(wpath, true, true, true); + + if (dir_handle == INVALID_HANDLE_VALUE) + return convert_windows_error_code(GetLastError()); + + *out = BH_MALLOC(sizeof(windows_handle)); + + if (*out == NULL) { + CloseHandle(dir_handle); + return __WASI_ENOMEM; + } + + (*out)->type = windows_handle_type_file; + (*out)->raw.handle = dir_handle; + (*out)->fdflags = 0; + (*out)->access_mode = windows_access_mode_read; + + return error; +} + +__wasi_errno_t +os_openat(os_file_handle handle, const char *path, __wasi_oflags_t oflags, + __wasi_fdflags_t fs_flags, __wasi_lookupflags_t lookup_flags, + wasi_libc_file_access_mode access_mode, os_file_handle *out) +{ + CHECK_VALID_FILE_HANDLE(handle); + *out = BH_MALLOC(sizeof(windows_handle)); + + if (*out == NULL) + return __WASI_ENOMEM; + + (*out)->type = windows_handle_type_file; + (*out)->fdflags = fs_flags; + (*out)->raw.handle = INVALID_HANDLE_VALUE; + + DWORD attributes = FILE_FLAG_BACKUP_SEMANTICS; + + if ((fs_flags & (__WASI_FDFLAG_SYNC | __WASI_FDFLAG_RSYNC)) != 0) + attributes |= (FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING); + if ((fs_flags & __WASI_FDFLAG_DSYNC) != 0) + attributes |= FILE_FLAG_WRITE_THROUGH; + + if ((oflags & __WASI_O_DIRECTORY) != 0) { + attributes |= FILE_ATTRIBUTE_DIRECTORY; + oflags &= ~(__WASI_O_DIRECTORY); + } + // Use async operations on the handle if it's not a directory + else { + attributes |= FILE_FLAG_OVERLAPPED; + } + + __wasi_errno_t error = __WASI_ESUCCESS; + + DWORD access_flags = 0; + if ((fs_flags & __WASI_FDFLAG_APPEND) != 0) { + if ((attributes & (FILE_FLAG_NO_BUFFERING)) != 0) { + // FILE_APPEND_DATA and FILE_FLAG_NO_BUFFERING are mutually + // exclusive - CreateFile2 returns 87 (invalid parameter) when they + // are combined. + error = __WASI_ENOTSUP; + goto fail; + } + access_flags |= FILE_APPEND_DATA; + } + + switch (access_mode) { + case WASI_LIBC_ACCESS_MODE_READ_ONLY: + access_flags |= GENERIC_READ; + (*out)->access_mode = windows_access_mode_read; + break; + case WASI_LIBC_ACCESS_MODE_WRITE_ONLY: + access_flags |= GENERIC_WRITE; + (*out)->access_mode = windows_access_mode_write; + break; + case WASI_LIBC_ACCESS_MODE_READ_WRITE: + access_flags |= GENERIC_WRITE | GENERIC_READ; + (*out)->access_mode = + windows_access_mode_read | windows_access_mode_write; + break; + } + + DWORD creation_disposition = 0; + + switch (oflags) { + case __WASI_O_CREAT | __WASI_O_EXCL: + case __WASI_O_CREAT | __WASI_O_EXCL | __WASI_O_TRUNC: + creation_disposition = CREATE_NEW; + break; + case __WASI_O_CREAT | __WASI_O_TRUNC: + creation_disposition = CREATE_ALWAYS; + break; + case __WASI_O_CREAT: + creation_disposition = OPEN_ALWAYS; + break; + case 0: + case __WASI_O_EXCL: + creation_disposition = OPEN_EXISTING; + break; + case __WASI_O_TRUNC: + case __WASI_O_EXCL | __WASI_O_TRUNC: + creation_disposition = TRUNCATE_EXISTING; + // CreateFile2 requires write access if we truncate the file upon + // opening + access_flags |= GENERIC_WRITE; + break; + } + + wchar_t absolute_path[PATH_MAX]; + error = get_absolute_filepath(handle->raw.handle, path, absolute_path, + PATH_MAX); + + if (error != __WASI_ESUCCESS) + goto fail; + + if ((lookup_flags & __WASI_LOOKUP_SYMLINK_FOLLOW) == 0) + attributes |= FILE_FLAG_OPEN_REPARSE_POINT; + + // Check that we're not trying to open an existing file as a directory. + // Windows doesn't seem to throw an error in this case so add an + // explicit check. + if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0 + && creation_disposition == OPEN_EXISTING + && !is_directory(absolute_path)) { + error = __WASI_ENOTDIR; + goto fail; + } + + CREATEFILE2_EXTENDED_PARAMETERS create_params; + create_params.dwSize = sizeof(create_params); + create_params.dwFileAttributes = attributes & 0xFFF; + create_params.dwFileFlags = attributes & 0xFFF00000; + create_params.dwSecurityQosFlags = 0; + create_params.lpSecurityAttributes = NULL; + create_params.hTemplateFile = NULL; + + (*out)->raw.handle = + CreateFile2(absolute_path, access_flags, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + creation_disposition, &create_params); + + if ((*out)->raw.handle == INVALID_HANDLE_VALUE) { + error = convert_windows_error_code(GetLastError()); + goto fail; + } + + return error; +fail: + if (*out != NULL) { + if ((*out)->raw.handle != INVALID_HANDLE_VALUE) + CloseHandle((*out)->raw.handle); + + BH_FREE(*out); + } + + return error; +} + +__wasi_errno_t +os_close(os_file_handle handle, bool is_stdio) +{ + CHECK_VALID_HANDLE(handle); + + // We don't own the underlying raw handle so just free the handle and return + // success. + if (is_stdio) { + BH_FREE(handle); + return __WASI_ESUCCESS; + } + + switch (handle->type) { + case windows_handle_type_file: + bool success = CloseHandle(handle->raw.handle); + + if (!success) + return convert_windows_error_code(GetLastError()); + + break; + case windows_handle_type_socket: + int ret = closesocket(handle->raw.socket); + + if (ret != 0) + return convert_winsock_error_code(WSAGetLastError()); + + break; + default: + assert(false && "unreachable"); + } + + BH_FREE(handle); + + return __WASI_ESUCCESS; +} + +static __wasi_errno_t +read_data_at_offset(HANDLE handle, const struct __wasi_iovec_t *iov, int iovcnt, + __wasi_filesize_t offset, size_t *nwritten) +{ + OVERLAPPED *read_operations = + BH_MALLOC((uint32_t)(sizeof(OVERLAPPED) * (uint32_t)iovcnt)); + + if (read_operations == NULL) + return __WASI_ENOMEM; + + ULARGE_INTEGER query_offset = { .QuadPart = offset }; + __wasi_errno_t error = __WASI_ESUCCESS; + size_t total_bytes_read = 0; + + const __wasi_iovec_t *current = iov; + int successful_read_count = 0; + + for (int i = 0; i < iovcnt; ++i, ++current) { + read_operations[i].Internal = 0; + read_operations[i].InternalHigh = 0; + read_operations[i].Offset = query_offset.LowPart; + read_operations[i].OffsetHigh = query_offset.HighPart; + read_operations[i].hEvent = NULL; + + if (!ReadFileEx(handle, current->buf, (DWORD)current->buf_len, + &read_operations[i], NULL)) { + DWORD win_error = GetLastError(); + if (win_error != ERROR_IO_PENDING) { + error = convert_windows_error_code(win_error); + break; + } + } + ++successful_read_count; + query_offset.QuadPart += (DWORD)current->buf_len; + } + + // Get the result of all the asynchronous read operations + for (int i = 0; i < successful_read_count; ++i) { + DWORD bytes_transferred = 0; + if (!GetOverlappedResult(handle, &read_operations[i], + &bytes_transferred, true)) { + DWORD win_error = GetLastError(); + + if (win_error != ERROR_HANDLE_EOF) + error = convert_windows_error_code(win_error); + else + total_bytes_read += (size_t)bytes_transferred; + + CancelIo(handle); + + for (int j = i + 1; j < iovcnt; ++j) { + GetOverlappedResult(handle, &read_operations[j], + &bytes_transferred, true); + } + break; + } + + total_bytes_read += (size_t)bytes_transferred; + } + + *nwritten = total_bytes_read; + + BH_FREE(read_operations); + return error; +} + +__wasi_errno_t +os_preadv(os_file_handle handle, const struct __wasi_iovec_t *iov, int iovcnt, + __wasi_filesize_t offset, size_t *nread) +{ + CHECK_VALID_FILE_HANDLE(handle); + + return read_data_at_offset(handle->raw.handle, iov, iovcnt, offset, nread); +} + +__wasi_errno_t +os_readv(os_file_handle handle, const struct __wasi_iovec_t *iov, int iovcnt, + size_t *nread) +{ + CHECK_VALID_HANDLE(handle); + + LARGE_INTEGER current_offset = { .QuadPart = 0 }; + + // Seek to the current offset before reading + int ret = SetFilePointerEx(handle->raw.handle, current_offset, + ¤t_offset, FILE_CURRENT); + if (ret == 0) + return convert_windows_error_code(GetLastError()); + + __wasi_errno_t error = + read_data_at_offset(handle->raw.handle, iov, iovcnt, + (__wasi_filesize_t)current_offset.QuadPart, nread); + + if (error != __WASI_ESUCCESS) + return error; + + current_offset.QuadPart += (LONGLONG)(*nread); + + // Update the current offset to match how many bytes we've read + ret = + SetFilePointerEx(handle->raw.handle, current_offset, NULL, FILE_BEGIN); + + if (ret == 0) + error = convert_windows_error_code(GetLastError()); + + return error; +} + +static __wasi_errno_t +write_data_at_offset(HANDLE handle, const struct __wasi_ciovec_t *iov, + int iovcnt, __wasi_filesize_t offset, size_t *nwritten) +{ + OVERLAPPED *write_operations = + BH_MALLOC((uint32_t)(sizeof(OVERLAPPED) * (uint32_t)iovcnt)); + + if (write_operations == NULL) + return __WASI_ENOMEM; + + ULARGE_INTEGER query_offset = { .QuadPart = offset }; + __wasi_errno_t error = __WASI_ESUCCESS; + size_t total_bytes_written = 0; + + const __wasi_ciovec_t *current = iov; + int successful_write_count = 0; + for (int i = 0; i < iovcnt; ++i, ++current) { + write_operations[i].Internal = 0; + write_operations[i].InternalHigh = 0; + write_operations[i].Offset = query_offset.LowPart; + write_operations[i].OffsetHigh = query_offset.HighPart; + write_operations[i].hEvent = NULL; + + if (!WriteFileEx(handle, current->buf, (DWORD)current->buf_len, + &write_operations[i], NULL)) { + DWORD win_error = GetLastError(); + if (win_error != ERROR_IO_PENDING) { + error = convert_windows_error_code(win_error); + break; + } + } + ++successful_write_count; + query_offset.QuadPart += (DWORD)current->buf_len; + } + + // Get the result of all the asynchronous writes + for (int i = 0; i < successful_write_count; ++i) { + DWORD bytes_transferred = 0; + if (!GetOverlappedResult(handle, &write_operations[i], + &bytes_transferred, true)) { + error = convert_windows_error_code(GetLastError()); + CancelIo(handle); + + for (int j = i + 1; j < iovcnt; ++j) { + GetOverlappedResult(handle, &write_operations[j], + &bytes_transferred, true); + } + break; + } + + total_bytes_written += (size_t)bytes_transferred; + } + + *nwritten = total_bytes_written; + + BH_FREE(write_operations); + return error; +} + +__wasi_errno_t +os_pwritev(os_file_handle handle, const struct __wasi_ciovec_t *iov, int iovcnt, + __wasi_filesize_t offset, size_t *nwritten) +{ + CHECK_VALID_FILE_HANDLE(handle); + + return write_data_at_offset(handle->raw.handle, iov, iovcnt, offset, + nwritten); +} + +__wasi_errno_t +os_writev(os_file_handle handle, const struct __wasi_ciovec_t *iov, int iovcnt, + size_t *nwritten) +{ + CHECK_VALID_HANDLE(handle); + + bool append = (handle->fdflags & __WASI_FDFLAG_APPEND) != 0; + LARGE_INTEGER write_offset = { .QuadPart = 0 }; + DWORD move_method = append ? FILE_END : FILE_CURRENT; + + int ret = SetFilePointerEx(handle->raw.handle, write_offset, &write_offset, + move_method); + if (ret == 0) + return convert_windows_error_code(GetLastError()); + + __wasi_errno_t error = write_data_at_offset( + handle->raw.handle, iov, iovcnt, + (__wasi_filesize_t)write_offset.QuadPart, nwritten); + + if (error != __WASI_ESUCCESS) + return error; + + write_offset.QuadPart += (LONGLONG)(*nwritten); + + // Update the write offset to match how many bytes we've written + ret = SetFilePointerEx(handle->raw.handle, write_offset, NULL, FILE_BEGIN); + + if (ret == 0) + error = convert_windows_error_code(GetLastError()); + + return error; +} + +__wasi_errno_t +os_fallocate(os_file_handle handle, __wasi_filesize_t offset, + __wasi_filesize_t length) +{ + CHECK_VALID_FILE_HANDLE(handle); + + return __WASI_ENOSYS; +} + +__wasi_errno_t +os_ftruncate(os_file_handle handle, __wasi_filesize_t size) +{ + CHECK_VALID_FILE_HANDLE(handle); + + return __WASI_ENOSYS; +} + +__wasi_errno_t +os_futimens(os_file_handle handle, __wasi_timestamp_t access_time, + __wasi_timestamp_t modification_time, __wasi_fstflags_t fstflags) +{ + CHECK_VALID_FILE_HANDLE(handle); + + return __WASI_ENOSYS; +} + +__wasi_errno_t +os_utimensat(os_file_handle handle, const char *path, + __wasi_timestamp_t access_time, + __wasi_timestamp_t modification_time, __wasi_fstflags_t fstflags, + __wasi_lookupflags_t lookup_flags) +{ + CHECK_VALID_FILE_HANDLE(handle); + + return __WASI_ENOSYS; +} + +__wasi_errno_t +os_readlinkat(os_file_handle handle, const char *path, char *buf, + size_t bufsize, size_t *nread) +{ + CHECK_VALID_FILE_HANDLE(handle); + + wchar_t symlink_path[PATH_MAX]; + __wasi_errno_t error = + get_absolute_filepath(handle->raw.handle, path, symlink_path, PATH_MAX); + + if (error != __WASI_ESUCCESS) + return error; + + DWORD symlink_attributes = GetFileAttributesW(symlink_path); + + if (!has_symlink_attribute(symlink_attributes)) + return __WASI_EINVAL; + + HANDLE link_handle = create_handle( + symlink_path, has_directory_attribute(symlink_attributes), false, true); + + if (link_handle == INVALID_HANDLE_VALUE) + return convert_windows_error_code(GetLastError()); + +#if WINAPI_PARTITION_DESKTOP != 0 +// MinGW32 already has a definition for REPARSE_DATA_BUFFER +#if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR) + // See + // https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_reparse_data_buffer + // for more details. + typedef struct _REPARSE_DATA_BUFFER { + ULONG ReparseTag; + USHORT ReparseDataLength; + USHORT Reserved; + union { + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + ULONG Flags; + WCHAR PathBuffer[1]; + } SymbolicLinkReparseBuffer; + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + WCHAR PathBuffer[1]; + } MountPointReparseBuffer; + struct { + UCHAR DataBuffer[1]; + } GenericReparseBuffer; + } DUMMYUNIONNAME; + } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; +#endif + + char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + + REPARSE_DATA_BUFFER *reparse_data = (REPARSE_DATA_BUFFER *)buffer; + + if (!DeviceIoControl(link_handle, FSCTL_GET_REPARSE_POINT, NULL, 0, &buffer, + sizeof(buffer), NULL, NULL)) { + error = convert_windows_error_code(GetLastError()); + goto fail; + } + + int wbufsize = 0; + wchar_t *wbuf = NULL; + + // The following checks are taken from the libuv windows filesystem + // implementation, + // https://github.com/libuv/libuv/blob/v1.x/src/win/fs.c#L181-L244. Real + // symlinks can contain pretty much anything, but the only thing we really + // care about is undoing the implicit conversion to an NT namespaced path + // that CreateSymbolicLink will perform on absolute paths. + if (reparse_data->ReparseTag == IO_REPARSE_TAG_SYMLINK) { + wbuf = reparse_data->SymbolicLinkReparseBuffer.PathBuffer + + (reparse_data->SymbolicLinkReparseBuffer.SubstituteNameOffset + / sizeof(wchar_t)); + wbufsize = reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength + / sizeof(wchar_t); + + if (wbufsize >= 4 && wbuf[0] == L'\\' && wbuf[1] == L'?' + && wbuf[2] == L'?' && wbuf[3] == L'\\') { + // Starts with \??\ + if (wbufsize >= 6 + && ((wbuf[4] >= L'A' && wbuf[4] <= L'Z') + || (wbuf[4] >= L'a' && wbuf[4] <= L'z')) + && wbuf[5] == L':' && (wbufsize == 6 || wbuf[6] == L'\\')) + { + // \??\:\ + wbuf += 4; + wbufsize -= 4; + } + else if (wbufsize >= 8 && (wbuf[4] == L'U' || wbuf[4] == L'u') + && (wbuf[5] == L'N' || wbuf[5] == L'n') + && (wbuf[6] == L'C' || wbuf[6] == L'c') + && wbuf[7] == L'\\') + { + // \??\UNC\\\ - make sure the final path looks like \\\\ + wbuf += 6; + wbuf[0] = L'\\'; + wbufsize -= 6; + } + } + } + else if (reparse_data->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) { + // Junction + wbuf = reparse_data->MountPointReparseBuffer.PathBuffer + + (reparse_data->MountPointReparseBuffer.SubstituteNameOffset + / sizeof(wchar_t)); + wbufsize = reparse_data->MountPointReparseBuffer.SubstituteNameLength + / sizeof(wchar_t); + + // Only treat junctions that look like \??\:\ as a symlink. + if (!(wbufsize >= 6 && wbuf[0] == L'\\' && wbuf[1] == L'?' + && wbuf[2] == L'?' && wbuf[3] == L'\\' + && ((wbuf[4] >= L'A' && wbuf[4] <= L'Z') + || (wbuf[4] >= L'a' && wbuf[4] <= L'z')) + && wbuf[5] == L':' && (wbufsize == 6 || wbuf[6] == L'\\'))) { + error = __WASI_EINVAL; + goto fail; + } + + /* Remove leading \??\ */ + wbuf += 4; + wbufsize -= 4; + } + else { + error = __WASI_EINVAL; + goto fail; + } + + if (wbuf != NULL) + *nread = (size_t)WideCharToMultiByte(CP_UTF8, 0, wbuf, wbufsize, buf, + (int)bufsize, NULL, NULL); + + if (*nread == 0 && wbuf != NULL) { + DWORD win_error = GetLastError(); + if (win_error == ERROR_INSUFFICIENT_BUFFER) + *nread = bufsize; + else + error = convert_windows_error_code(win_error); + } +#else + error = __WASI_ENOTSUP; +#endif +fail: + CloseHandle(link_handle); + return error; +} + +__wasi_errno_t +os_linkat(os_file_handle from_handle, const char *from_path, + os_file_handle to_handle, const char *to_path, + __wasi_lookupflags_t lookup_flags) +{ + CHECK_VALID_FILE_HANDLE(from_handle); + CHECK_VALID_FILE_HANDLE(to_handle); + + return __WASI_ENOSYS; +} + +__wasi_errno_t +os_symlinkat(const char *old_path, os_file_handle handle, const char *new_path) +{ + CHECK_VALID_FILE_HANDLE(handle); + + return __WASI_ENOSYS; +} + +__wasi_errno_t +os_mkdirat(os_file_handle handle, const char *path) +{ + CHECK_VALID_FILE_HANDLE(handle); + + wchar_t absolute_path[PATH_MAX]; + __wasi_errno_t error = get_absolute_filepath(handle->raw.handle, path, + absolute_path, PATH_MAX); + + if (error != __WASI_ESUCCESS) + return error; + + bool success = CreateDirectoryW(absolute_path, NULL); + + if (!success) + error = convert_windows_error_code(GetLastError()); + + return error; +} + +__wasi_errno_t +os_renameat(os_file_handle old_handle, const char *old_path, + os_file_handle new_handle, const char *new_path) +{ + CHECK_VALID_FILE_HANDLE(old_handle); + CHECK_VALID_FILE_HANDLE(new_handle); + + return __WASI_ENOSYS; +} + +__wasi_errno_t +os_unlinkat(os_file_handle handle, const char *path, bool is_dir) +{ + CHECK_VALID_FILE_HANDLE(handle); + + wchar_t absolute_path[PATH_MAX]; + __wasi_errno_t error = get_absolute_filepath(handle->raw.handle, path, + absolute_path, PATH_MAX); + + if (error != __WASI_ESUCCESS) + return error; + + DWORD attributes = GetFileAttributesW(absolute_path); + + if (has_symlink_attribute(attributes)) { + // Override is_dir for symlinks. A symlink to a directory counts + // as a directory itself in Windows. + is_dir = has_directory_attribute(attributes); + } + + int ret = + is_dir ? RemoveDirectoryW(absolute_path) : DeleteFileW(absolute_path); + + if (ret == 0) + error = convert_windows_error_code(GetLastError()); + + return error; +} + +__wasi_errno_t +os_lseek(os_file_handle handle, __wasi_filedelta_t offset, + __wasi_whence_t whence, __wasi_filesize_t *new_offset) +{ + CHECK_VALID_FILE_HANDLE(handle); + + return __WASI_ENOSYS; +} + +__wasi_errno_t +os_fadvise(os_file_handle handle, __wasi_filesize_t offset, + __wasi_filesize_t length, __wasi_advice_t advice) +{ + CHECK_VALID_FILE_HANDLE(handle); + + return __WASI_ENOSYS; +} + +__wasi_errno_t +os_isatty(os_file_handle handle) +{ + CHECK_VALID_HANDLE(handle); + + DWORD console_mode; + return GetConsoleMode(handle->raw.handle, &console_mode) ? __WASI_ESUCCESS + : __WASI_ENOTTY; +} + +static os_file_handle +create_stdio_handle(HANDLE raw_stdio_handle, DWORD stdio) +{ + os_file_handle stdio_handle = BH_MALLOC(sizeof(windows_handle)); + + if (stdio_handle == NULL) + return NULL; + + stdio_handle->type = windows_handle_type_file; + stdio_handle->access_mode = + windows_access_mode_read | windows_access_mode_write; + stdio_handle->fdflags = 0; + + if (raw_stdio_handle == INVALID_HANDLE_VALUE) + raw_stdio_handle = GetStdHandle(stdio); + + stdio_handle->raw.handle = raw_stdio_handle; + + return stdio_handle; +} + +os_file_handle +os_convert_stdin_handle(os_raw_file_handle raw_stdin) +{ + return create_stdio_handle(raw_stdin, STD_INPUT_HANDLE); +} + +os_file_handle +os_convert_stdout_handle(os_raw_file_handle raw_stdout) +{ + return create_stdio_handle(raw_stdout, STD_OUTPUT_HANDLE); +} + +os_file_handle +os_convert_stderr_handle(os_raw_file_handle raw_stderr) +{ + return create_stdio_handle(raw_stderr, STD_ERROR_HANDLE); +} + +__wasi_errno_t +os_fdopendir(os_file_handle handle, os_dir_stream *dir_stream) +{ + return __WASI_ENOSYS; +} + +__wasi_errno_t +os_rewinddir(os_dir_stream dir_stream) +{ + CHECK_VALID_WIN_DIR_STREAM(dir_stream); + + return __WASI_ENOSYS; +} + +__wasi_errno_t +os_seekdir(os_dir_stream dir_stream, __wasi_dircookie_t position) +{ + CHECK_VALID_WIN_DIR_STREAM(dir_stream); + + return __WASI_ENOSYS; +} + +__wasi_errno_t +os_readdir(os_dir_stream dir_stream, __wasi_dirent_t *entry, + const char **d_name) +{ + CHECK_VALID_WIN_DIR_STREAM(dir_stream); + + return __WASI_ENOSYS; +} + +__wasi_errno_t +os_closedir(os_dir_stream dir_stream) +{ + CHECK_VALID_WIN_DIR_STREAM(dir_stream); + + return __WASI_ENOSYS; +} + +os_dir_stream +os_get_invalid_dir_stream() +{ + return NULL; +} + +bool +os_is_dir_stream_valid(os_dir_stream *dir_stream) +{ + assert(dir_stream != NULL); + + if (((*dir_stream) == NULL) || ((*dir_stream)->handle == NULL) + || ((*dir_stream)->handle->type != windows_handle_type_file) + || ((*dir_stream)->handle->raw.handle == INVALID_HANDLE_VALUE)) + return false; + + return true; +} + +bool +os_is_handle_valid(os_file_handle *handle) +{ + assert(handle != NULL); + + CHECK_VALID_HANDLE_WITH_RETURN_VALUE(*handle, false); + + return true; +} + +char * +os_realpath(const char *path, char *resolved_path) +{ + resolved_path = _fullpath(resolved_path, path, PATH_MAX); + + // Check the file/directory actually exists + DWORD attributes = GetFileAttributesA(resolved_path); + + if (attributes == INVALID_FILE_ATTRIBUTES) + return NULL; + + return resolved_path; +} \ No newline at end of file diff --git a/core/shared/platform/windows/win_memmap.c b/core/shared/platform/windows/win_memmap.c index c4a6b0756..db0f38a56 100644 --- a/core/shared/platform/windows/win_memmap.c +++ b/core/shared/platform/windows/win_memmap.c @@ -29,7 +29,7 @@ access_to_win32_flags(int prot) } void * -os_mmap(void *hint, size_t size, int prot, int flags) +os_mmap(void *hint, size_t size, int prot, int flags, os_file_handle file) { DWORD alloc_type = MEM_RESERVE; DWORD protect; diff --git a/core/shared/platform/windows/win_socket.c b/core/shared/platform/windows/win_socket.c index 9a1c7a3c9..bc05b0017 100644 --- a/core/shared/platform/windows/win_socket.c +++ b/core/shared/platform/windows/win_socket.c @@ -11,6 +11,22 @@ static bool is_winsock_inited = false; +#define CHECK_VALID_SOCKET_HANDLE(win_handle) \ + do { \ + if ((win_handle) == NULL) { \ + errno = EBADF; \ + return BHT_ERROR; \ + } \ + if ((win_handle)->type != windows_handle_type_socket) { \ + errno = ENOTSOCK; \ + return BHT_ERROR; \ + } \ + if ((win_handle)->raw.socket == INVALID_SOCKET) { \ + errno = EBADF; \ + return BHT_ERROR; \ + } \ + } while (0) + int init_winsock() { @@ -45,6 +61,17 @@ os_socket_create(bh_socket_t *sock, bool is_ipv4, bool is_tcp) return BHT_ERROR; } + *(sock) = BH_MALLOC(sizeof(windows_handle)); + + if ((*sock) == NULL) { + errno = ENOMEM; + return BHT_ERROR; + } + + (*sock)->type = windows_handle_type_socket; + (*sock)->access_mode = windows_access_mode_read | windows_access_mode_write; + (*sock)->fdflags = 0; + if (is_ipv4) { af = AF_INET; } @@ -54,18 +81,24 @@ os_socket_create(bh_socket_t *sock, bool is_ipv4, bool is_tcp) } if (is_tcp) { - *sock = socket(af, SOCK_STREAM, IPPROTO_TCP); + (*sock)->raw.socket = socket(af, SOCK_STREAM, IPPROTO_TCP); } else { - *sock = socket(af, SOCK_DGRAM, 0); + (*sock)->raw.socket = socket(af, SOCK_DGRAM, 0); } - return (*sock == -1) ? BHT_ERROR : BHT_OK; + if ((*sock)->raw.socket == INVALID_SOCKET) { + BH_FREE(*sock); + return BHT_ERROR; + } + + return BHT_OK; } int os_socket_bind(bh_socket_t socket, const char *host, int *port) { + CHECK_VALID_SOCKET_HANDLE(socket); struct sockaddr_in addr; int socklen, ret; @@ -76,13 +109,13 @@ os_socket_bind(bh_socket_t socket, const char *host, int *port) addr.sin_port = htons(*port); addr.sin_family = AF_INET; - ret = bind(socket, (struct sockaddr *)&addr, sizeof(addr)); + ret = bind(socket->raw.socket, (struct sockaddr *)&addr, sizeof(addr)); if (ret < 0) { goto fail; } socklen = sizeof(addr); - if (getsockname(socket, (void *)&addr, &socklen) == -1) { + if (getsockname(socket->raw.socket, (void *)&addr, &socklen) == -1) { os_printf("getsockname failed with error %d\n", WSAGetLastError()); goto fail; } @@ -98,10 +131,12 @@ fail: int os_socket_settimeout(bh_socket_t socket, uint64 timeout_us) { + CHECK_VALID_SOCKET_HANDLE(socket); + DWORD tv = (DWORD)(timeout_us / 1000UL); - if (setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, - sizeof(tv)) + if (setsockopt(socket->raw.socket, SOL_SOCKET, SO_RCVTIMEO, + (const char *)&tv, sizeof(tv)) != 0) { return BHT_ERROR; } @@ -112,7 +147,9 @@ os_socket_settimeout(bh_socket_t socket, uint64 timeout_us) int os_socket_listen(bh_socket_t socket, int max_client) { - if (listen(socket, max_client) != 0) { + CHECK_VALID_SOCKET_HANDLE(socket); + + if (listen(socket->raw.socket, max_client) != 0) { os_printf("socket listen failed with error %d\n", WSAGetLastError()); return BHT_ERROR; } @@ -124,12 +161,26 @@ int os_socket_accept(bh_socket_t server_sock, bh_socket_t *sock, void *addr, unsigned int *addrlen) { + CHECK_VALID_SOCKET_HANDLE(server_sock); + struct sockaddr addr_tmp; unsigned int len = sizeof(struct sockaddr); - *sock = accept(server_sock, (struct sockaddr *)&addr_tmp, &len); + *sock = BH_MALLOC(sizeof(windows_handle)); - if (*sock < 0) { + if (*sock == NULL) { + errno = ENOMEM; + return BHT_ERROR; + } + + (*sock)->type = windows_handle_type_socket; + (*sock)->access_mode = windows_access_mode_read | windows_access_mode_write; + (*sock)->fdflags = 0; + (*sock)->raw.socket = + accept(server_sock->raw.socket, (struct sockaddr *)&addr_tmp, &len); + + if ((*sock)->raw.socket == INVALID_SOCKET) { + BH_FREE(*sock); os_printf("socket accept failed with error %d\n", WSAGetLastError()); return BHT_ERROR; } @@ -140,13 +191,17 @@ os_socket_accept(bh_socket_t server_sock, bh_socket_t *sock, void *addr, int os_socket_recv(bh_socket_t socket, void *buf, unsigned int len) { - return recv(socket, buf, len, 0); + CHECK_VALID_SOCKET_HANDLE(socket); + + return recv(socket->raw.socket, buf, len, 0); } int os_socket_recv_from(bh_socket_t socket, void *buf, unsigned int len, int flags, bh_sockaddr_t *src_addr) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -155,13 +210,17 @@ os_socket_recv_from(bh_socket_t socket, void *buf, unsigned int len, int flags, int os_socket_send(bh_socket_t socket, const void *buf, unsigned int len) { - return send(socket, buf, len, 0); + CHECK_VALID_SOCKET_HANDLE(socket); + + return send(socket->raw.socket, buf, len, 0); } int os_socket_send_to(bh_socket_t socket, const void *buf, unsigned int len, int flags, const bh_sockaddr_t *dest_addr) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -170,14 +229,21 @@ os_socket_send_to(bh_socket_t socket, const void *buf, unsigned int len, int os_socket_close(bh_socket_t socket) { - closesocket(socket); + CHECK_VALID_SOCKET_HANDLE(socket); + + closesocket(socket->raw.socket); + + BH_FREE(socket); + return BHT_OK; } int os_socket_shutdown(bh_socket_t socket) { - shutdown(socket, SD_BOTH); + CHECK_VALID_SOCKET_HANDLE(socket); + + shutdown(socket->raw.socket, SD_BOTH); return BHT_OK; } @@ -206,6 +272,16 @@ os_socket_inet_network(bool is_ipv4, const char *cp, bh_ip_addr_buffer_t *out) return BHT_OK; } +int +os_socket_connect(bh_socket_t socket, const char *addr, int port) +{ + CHECK_VALID_SOCKET_HANDLE(socket); + + errno = ENOSYS; + + return BHT_ERROR; +} + int os_socket_addr_resolve(const char *host, const char *service, uint8_t *hint_is_tcp, uint8_t *hint_is_ipv4, @@ -220,6 +296,8 @@ os_socket_addr_resolve(const char *host, const char *service, int os_socket_addr_local(bh_socket_t socket, bh_sockaddr_t *sockaddr) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -228,6 +306,8 @@ os_socket_addr_local(bh_socket_t socket, bh_sockaddr_t *sockaddr) int os_socket_set_send_timeout(bh_socket_t socket, uint64 timeout_us) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -236,6 +316,8 @@ os_socket_set_send_timeout(bh_socket_t socket, uint64 timeout_us) int os_socket_get_send_timeout(bh_socket_t socket, uint64 *timeout_us) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -244,6 +326,8 @@ os_socket_get_send_timeout(bh_socket_t socket, uint64 *timeout_us) int os_socket_set_recv_timeout(bh_socket_t socket, uint64 timeout_us) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -252,6 +336,8 @@ os_socket_set_recv_timeout(bh_socket_t socket, uint64 timeout_us) int os_socket_get_recv_timeout(bh_socket_t socket, uint64 *timeout_us) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -260,6 +346,8 @@ os_socket_get_recv_timeout(bh_socket_t socket, uint64 *timeout_us) int os_socket_addr_remote(bh_socket_t socket, bh_sockaddr_t *sockaddr) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -268,6 +356,8 @@ os_socket_addr_remote(bh_socket_t socket, bh_sockaddr_t *sockaddr) int os_socket_set_send_buf_size(bh_socket_t socket, size_t bufsiz) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -276,6 +366,8 @@ os_socket_set_send_buf_size(bh_socket_t socket, size_t bufsiz) int os_socket_get_send_buf_size(bh_socket_t socket, size_t *bufsiz) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -284,6 +376,8 @@ os_socket_get_send_buf_size(bh_socket_t socket, size_t *bufsiz) int os_socket_set_recv_buf_size(bh_socket_t socket, size_t bufsiz) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -292,6 +386,8 @@ os_socket_set_recv_buf_size(bh_socket_t socket, size_t bufsiz) int os_socket_get_recv_buf_size(bh_socket_t socket, size_t *bufsiz) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -300,6 +396,8 @@ os_socket_get_recv_buf_size(bh_socket_t socket, size_t *bufsiz) int os_socket_set_keep_alive(bh_socket_t socket, bool is_enabled) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -308,6 +406,8 @@ os_socket_set_keep_alive(bh_socket_t socket, bool is_enabled) int os_socket_get_keep_alive(bh_socket_t socket, bool *is_enabled) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -316,6 +416,8 @@ os_socket_get_keep_alive(bh_socket_t socket, bool *is_enabled) int os_socket_set_reuse_addr(bh_socket_t socket, bool is_enabled) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -324,6 +426,8 @@ os_socket_set_reuse_addr(bh_socket_t socket, bool is_enabled) int os_socket_get_reuse_addr(bh_socket_t socket, bool *is_enabled) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -332,6 +436,8 @@ os_socket_get_reuse_addr(bh_socket_t socket, bool *is_enabled) int os_socket_set_reuse_port(bh_socket_t socket, bool is_enabled) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -340,6 +446,8 @@ os_socket_set_reuse_port(bh_socket_t socket, bool is_enabled) int os_socket_get_reuse_port(bh_socket_t socket, bool *is_enabled) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -348,6 +456,8 @@ os_socket_get_reuse_port(bh_socket_t socket, bool *is_enabled) int os_socket_set_linger(bh_socket_t socket, bool is_enabled, int linger_s) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -356,6 +466,8 @@ os_socket_set_linger(bh_socket_t socket, bool is_enabled, int linger_s) int os_socket_get_linger(bh_socket_t socket, bool *is_enabled, int *linger_s) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -364,6 +476,8 @@ os_socket_get_linger(bh_socket_t socket, bool *is_enabled, int *linger_s) int os_socket_set_tcp_no_delay(bh_socket_t socket, bool is_enabled) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -372,6 +486,8 @@ os_socket_set_tcp_no_delay(bh_socket_t socket, bool is_enabled) int os_socket_get_tcp_no_delay(bh_socket_t socket, bool *is_enabled) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -380,6 +496,8 @@ os_socket_get_tcp_no_delay(bh_socket_t socket, bool *is_enabled) int os_socket_set_tcp_quick_ack(bh_socket_t socket, bool is_enabled) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -388,6 +506,8 @@ os_socket_set_tcp_quick_ack(bh_socket_t socket, bool is_enabled) int os_socket_get_tcp_quick_ack(bh_socket_t socket, bool *is_enabled) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -396,6 +516,8 @@ os_socket_get_tcp_quick_ack(bh_socket_t socket, bool *is_enabled) int os_socket_set_tcp_keep_idle(bh_socket_t socket, uint32 time_s) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -404,6 +526,8 @@ os_socket_set_tcp_keep_idle(bh_socket_t socket, uint32 time_s) int os_socket_get_tcp_keep_idle(bh_socket_t socket, uint32 *time_s) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -412,6 +536,8 @@ os_socket_get_tcp_keep_idle(bh_socket_t socket, uint32 *time_s) int os_socket_set_tcp_keep_intvl(bh_socket_t socket, uint32 time_s) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -420,6 +546,8 @@ os_socket_set_tcp_keep_intvl(bh_socket_t socket, uint32 time_s) int os_socket_get_tcp_keep_intvl(bh_socket_t socket, uint32 *time_s) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -428,6 +556,8 @@ os_socket_get_tcp_keep_intvl(bh_socket_t socket, uint32 *time_s) int os_socket_set_tcp_fastopen_connect(bh_socket_t socket, bool is_enabled) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -436,6 +566,8 @@ os_socket_set_tcp_fastopen_connect(bh_socket_t socket, bool is_enabled) int os_socket_get_tcp_fastopen_connect(bh_socket_t socket, bool *is_enabled) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -444,6 +576,8 @@ os_socket_get_tcp_fastopen_connect(bh_socket_t socket, bool *is_enabled) int os_socket_set_ip_multicast_loop(bh_socket_t socket, bool ipv6, bool is_enabled) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -452,6 +586,8 @@ os_socket_set_ip_multicast_loop(bh_socket_t socket, bool ipv6, bool is_enabled) int os_socket_get_ip_multicast_loop(bh_socket_t socket, bool ipv6, bool *is_enabled) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -462,6 +598,8 @@ os_socket_set_ip_add_membership(bh_socket_t socket, bh_ip_addr_buffer_t *imr_multiaddr, uint32_t imr_interface, bool is_ipv6) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -472,6 +610,8 @@ os_socket_set_ip_drop_membership(bh_socket_t socket, bh_ip_addr_buffer_t *imr_multiaddr, uint32_t imr_interface, bool is_ipv6) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -480,6 +620,8 @@ os_socket_set_ip_drop_membership(bh_socket_t socket, int os_socket_set_ip_ttl(bh_socket_t socket, uint8_t ttl_s) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -488,6 +630,8 @@ os_socket_set_ip_ttl(bh_socket_t socket, uint8_t ttl_s) int os_socket_get_ip_ttl(bh_socket_t socket, uint8_t *ttl_s) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -496,6 +640,8 @@ os_socket_get_ip_ttl(bh_socket_t socket, uint8_t *ttl_s) int os_socket_set_ip_multicast_ttl(bh_socket_t socket, uint8_t ttl_s) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -504,6 +650,8 @@ os_socket_set_ip_multicast_ttl(bh_socket_t socket, uint8_t ttl_s) int os_socket_get_ip_multicast_ttl(bh_socket_t socket, uint8_t *ttl_s) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -512,6 +660,8 @@ os_socket_get_ip_multicast_ttl(bh_socket_t socket, uint8_t *ttl_s) int os_socket_set_ipv6_only(bh_socket_t socket, bool option) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -520,6 +670,8 @@ os_socket_set_ipv6_only(bh_socket_t socket, bool option) int os_socket_get_ipv6_only(bh_socket_t socket, bool *option) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -528,6 +680,8 @@ os_socket_get_ipv6_only(bh_socket_t socket, bool *option) int os_socket_set_broadcast(bh_socket_t socket, bool is_enabled) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -536,6 +690,8 @@ os_socket_set_broadcast(bh_socket_t socket, bool is_enabled) int os_socket_get_broadcast(bh_socket_t socket, bool *is_enabled) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; } diff --git a/core/shared/platform/windows/win_thread.c b/core/shared/platform/windows/win_thread.c index abc36f2fc..f37250fa4 100644 --- a/core/shared/platform/windows/win_thread.c +++ b/core/shared/platform/windows/win_thread.c @@ -541,6 +541,62 @@ os_mutex_unlock(korp_mutex *mutex) return ReleaseMutex(*mutex) ? BHT_OK : BHT_ERROR; } +int +os_rwlock_init(korp_rwlock *lock) +{ + bh_assert(lock); + + InitializeSRWLock(&(lock->lock)); + lock->exclusive = false; + + return BHT_OK; +} + +int +os_rwlock_rdlock(korp_rwlock *lock) +{ + bh_assert(lock); + + AcquireSRWLockShared(&(lock->lock)); + + return BHT_OK; +} + +int +os_rwlock_wrlock(korp_rwlock *lock) +{ + bh_assert(lock); + + AcquireSRWLockExclusive(&(lock->lock)); + lock->exclusive = true; + + return BHT_OK; +} + +int +os_rwlock_unlock(korp_rwlock *lock) +{ + bh_assert(lock); + + if (lock->exclusive) { + lock->exclusive = false; + ReleaseSRWLockExclusive(&(lock->lock)); + } + else { + ReleaseSRWLockShared(&(lock->lock)); + } + + return BHT_OK; +} + +int +os_rwlock_destroy(korp_rwlock *lock) +{ + (void)lock; + + return BHT_OK; +} + int os_cond_init(korp_cond *cond) { diff --git a/core/shared/platform/windows/win_util.c b/core/shared/platform/windows/win_util.c new file mode 100644 index 000000000..50c446d69 --- /dev/null +++ b/core/shared/platform/windows/win_util.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2023 Amazon Inc. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "platform_common.h" +#include "win_util.h" + +__wasi_timestamp_t +convert_filetime_to_wasi_timestamp(LPFILETIME filetime) +{ + // From 1601-01-01 to 1970-01-01 there are 134774 days. + static const uint64_t NT_to_UNIX_epoch = + 134774ull * 86400ull * 1000ull * 1000ull * 1000ull; + + ULARGE_INTEGER temp = { .HighPart = filetime->dwHighDateTime, + .LowPart = filetime->dwLowDateTime }; + + // WASI timestamps are measured in nanoseconds whereas FILETIME structs are + // represented in terms 100-nanosecond intervals. + return (temp.QuadPart * 100ull) - NT_to_UNIX_epoch; +} + +__wasi_errno_t +convert_windows_error_code(DWORD windows_error_code) +{ + switch (windows_error_code) { + case ERROR_INVALID_PARAMETER: + case ERROR_INVALID_HANDLE: + case ERROR_NEGATIVE_SEEK: + return __WASI_EINVAL; + case ERROR_SHARING_VIOLATION: + case ERROR_PIPE_BUSY: + return __WASI_EBUSY; + case ERROR_ACCESS_DENIED: + return __WASI_EACCES; + case ERROR_ALREADY_EXISTS: + case ERROR_FILE_EXISTS: + return __WASI_EEXIST; + case ERROR_NO_MORE_FILES: + case ERROR_FILE_NOT_FOUND: + case ERROR_INVALID_NAME: + return __WASI_ENOENT; + case ERROR_PRIVILEGE_NOT_HELD: + return __WASI_EPERM; + case ERROR_NOT_ENOUGH_MEMORY: + return __WASI_ENOMEM; + case ERROR_NOACCESS: + return __WASI_EFAULT; + case ERROR_DIR_NOT_EMPTY: + return __WASI_ENOTEMPTY; + case ERROR_DIRECTORY: + return __WASI_ENOTDIR; + case ERROR_IO_PENDING: + case ERROR_INSUFFICIENT_BUFFER: + case ERROR_INVALID_FLAGS: + case ERROR_NO_UNICODE_TRANSLATION: + default: + return __WASI_EINVAL; + } +} + +#ifdef UWP_DEFAULT_VPRINTF +int +uwp_print_to_debugger(const char *format, va_list ap) +{ + // Provide a stack buffer which should be large enough for any realistic + // string so we avoid making an allocation on every printf call. + char stack_buf[2048]; + char *buf = stack_buf; + int ret = vsnprintf(stack_buf, sizeof(stack_buf), format, ap); + + if ((size_t)ret >= sizeof(stack_buf)) { + // Allocate an extra byte for the null terminator. + char *heap_buf = BH_MALLOC((unsigned int)(ret) + 1); + buf = heap_buf; + + if (heap_buf == NULL) { + // Output as much as we can to the debugger if allocating a buffer + // fails. + OutputDebugStringA(stack_buf); + return ret; + } + + ret = vsnprintf(heap_buf, (size_t)ret + 1, format, ap); + } + + if (ret >= 0) + OutputDebugStringA(buf); + + if (buf != stack_buf) + BH_FREE(buf); + + return ret; +} +#endif \ No newline at end of file diff --git a/core/shared/platform/windows/win_util.h b/core/shared/platform/windows/win_util.h new file mode 100644 index 000000000..0733b076e --- /dev/null +++ b/core/shared/platform/windows/win_util.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2023 Amazon Inc. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _WIN_UTIL_H +#define _WIN_UTIL_H + +#include "platform_wasi_types.h" +#include "windows.h" + +__wasi_timestamp_t +convert_filetime_to_wasi_timestamp(LPFILETIME filetime); + +// Convert a Windows error code to a WASI error code +__wasi_errno_t +convert_windows_error_code(DWORD windows_error_code); + +#endif /* end of _WIN_UTIL_H */ \ No newline at end of file diff --git a/core/shared/platform/zephyr/platform_internal.h b/core/shared/platform/zephyr/platform_internal.h index d2a94e4ad..048387817 100644 --- a/core/shared/platform/zephyr/platform_internal.h +++ b/core/shared/platform/zephyr/platform_internal.h @@ -42,21 +42,23 @@ #include #include #include - -#ifdef CONFIG_ARM_MPU -#include -#endif #else /* else of KERNEL_VERSION_NUMBER < 0x030200 */ #include #include #include #include #include +#endif /* end of KERNEL_VERSION_NUMBER < 0x030200 */ #ifdef CONFIG_ARM_MPU +#if KERNEL_VERSION_NUMBER < 0x030200 /* version 3.2.0 */ +#include +#elif KERNEL_VERSION_NUMBER < 0x030400 /* version 3.4.0 */ #include +#else /* > 3.4.0 */ +#include +#endif #endif -#endif /* end of KERNEL_VERSION_NUMBER < 0x030200 */ #ifndef BH_PLATFORM_ZEPHYR #define BH_PLATFORM_ZEPHYR @@ -146,4 +148,14 @@ void set_exec_mem_alloc_func(exec_mem_alloc_func_t alloc_func, exec_mem_free_func_t free_func); +typedef int os_file_handle; +typedef DIR *os_dir_stream; +typedef int os_raw_file_handle; + +static inline os_file_handle +os_get_invalid_handle() +{ + return -1; +} + #endif diff --git a/core/shared/platform/zephyr/zephyr_platform.c b/core/shared/platform/zephyr/zephyr_platform.c index 715be8b94..1a5b6621d 100644 --- a/core/shared/platform/zephyr/zephyr_platform.c +++ b/core/shared/platform/zephyr/zephyr_platform.c @@ -173,7 +173,7 @@ strcspn(const char *s, const char *reject) #endif void * -os_mmap(void *hint, size_t size, int prot, int flags) +os_mmap(void *hint, size_t size, int prot, int flags, os_file_handle file) { if ((uint64)size >= UINT32_MAX) return NULL; diff --git a/doc/export_native_api.md b/doc/export_native_api.md index e293e5c0d..ed7385539 100644 --- a/doc/export_native_api.md +++ b/doc/export_native_api.md @@ -155,7 +155,7 @@ As function parameters are always passed in 32 bits numbers, you can also use 'i // // If the function signature used i32 data type ("i") // for buffer address or string parameters, here -// is how to do address conversation and boundary check manually +// is how to do address conversion and boundary check manually // void foo2(wasm_exec_env_t exec_env, uint32 msg_offset, diff --git a/product-mini/platforms/common/libc_wasi.c b/product-mini/platforms/common/libc_wasi.c new file mode 100644 index 000000000..4bcb1d279 --- /dev/null +++ b/product-mini/platforms/common/libc_wasi.c @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include + +#include "bh_platform.h" +#include "wasm_export.h" + +typedef struct { + const char *dir_list[8]; + uint32 dir_list_size; + const char *map_dir_list[8]; + uint32 map_dir_list_size; + const char *env_list[8]; + uint32 env_list_size; + const char *addr_pool[8]; + uint32 addr_pool_size; + const char *ns_lookup_pool[8]; + uint32 ns_lookup_pool_size; +} libc_wasi_parse_context_t; + +typedef enum { + LIBC_WASI_PARSE_RESULT_OK = 0, + LIBC_WASI_PARSE_RESULT_NEED_HELP, + LIBC_WASI_PARSE_RESULT_BAD_PARAM +} libc_wasi_parse_result_t; + +static void +libc_wasi_print_help() +{ + printf(" --env= Pass wasi environment variables with " + "\"key=value\"\n"); + printf(" to the program, for example:\n"); + printf(" --env=\"key1=value1\" " + "--env=\"key2=value2\"\n"); + printf(" --dir= Grant wasi access to the given host " + "directories\n"); + printf(" to the program, for example:\n"); + printf(" --dir= --dir=\n"); + printf(" --map-dir= Grant wasi access to the given host " + "directories\n"); + printf(" to the program at a specific guest " + "path, for example:\n"); + printf(" --map-dir= " + "--map-dir=\n"); + printf(" --addr-pool= Grant wasi access to the given network " + "addresses in\n"); + printf(" CIRD notation to the program, seperated " + "with ',',\n"); + printf(" for example:\n"); + printf(" --addr-pool=1.2.3.4/15,2.3.4.5/16\n"); + printf(" --allow-resolve= Allow the lookup of the specific domain " + "name or domain\n"); + printf(" name suffixes using a wildcard, for " + "example:\n"); + printf(" --allow-resolve=example.com # allow the " + "lookup of the specific domain\n"); + printf(" --allow-resolve=*.example.com # allow " + "the lookup of all subdomains\n"); + printf(" --allow-resolve=* # allow any lookup\n"); +} + +static bool +validate_env_str(char *env) +{ + char *p = env; + int key_len = 0; + + while (*p != '\0' && *p != '=') { + key_len++; + p++; + } + + if (*p != '=' || key_len == 0) + return false; + + return true; +} + +libc_wasi_parse_result_t +libc_wasi_parse(char *arg, libc_wasi_parse_context_t *ctx) +{ + if (!strncmp(arg, "--dir=", 6)) { + if (arg[6] == '\0') + return LIBC_WASI_PARSE_RESULT_NEED_HELP; + if (ctx->dir_list_size >= sizeof(ctx->dir_list) / sizeof(char *)) { + printf("Only allow max dir number %d\n", + (int)(sizeof(ctx->dir_list) / sizeof(char *))); + return LIBC_WASI_PARSE_RESULT_BAD_PARAM; + } + ctx->dir_list[ctx->dir_list_size++] = arg + 6; + } + else if (!strncmp(arg, "--map-dir=", 10)) { + if (arg[10] == '\0') + return LIBC_WASI_PARSE_RESULT_NEED_HELP; + if (ctx->map_dir_list_size + >= sizeof(ctx->map_dir_list) / sizeof(char *)) { + printf("Only allow max map dir number %d\n", + (int)(sizeof(ctx->map_dir_list) / sizeof(char *))); + return 1; + } + ctx->map_dir_list[ctx->map_dir_list_size++] = arg + 10; + } + else if (!strncmp(arg, "--env=", 6)) { + char *tmp_env; + + if (arg[6] == '\0') + return LIBC_WASI_PARSE_RESULT_NEED_HELP; + if (ctx->env_list_size >= sizeof(ctx->env_list) / sizeof(char *)) { + printf("Only allow max env number %d\n", + (int)(sizeof(ctx->env_list) / sizeof(char *))); + return LIBC_WASI_PARSE_RESULT_BAD_PARAM; + } + tmp_env = arg + 6; + if (validate_env_str(tmp_env)) + ctx->env_list[ctx->env_list_size++] = tmp_env; + else { + printf("Wasm parse env string failed: expect \"key=value\", " + "got \"%s\"\n", + tmp_env); + return LIBC_WASI_PARSE_RESULT_NEED_HELP; + } + } + /* TODO: parse the configuration file via --addr-pool-file */ + else if (!strncmp(arg, "--addr-pool=", strlen("--addr-pool="))) { + /* like: --addr-pool=100.200.244.255/30 */ + char *token = NULL; + + if ('\0' == arg[12]) + return LIBC_WASI_PARSE_RESULT_NEED_HELP; + + token = strtok(arg + strlen("--addr-pool="), ","); + while (token) { + if (ctx->addr_pool_size + >= sizeof(ctx->addr_pool) / sizeof(char *)) { + printf("Only allow max address number %d\n", + (int)(sizeof(ctx->addr_pool) / sizeof(char *))); + return LIBC_WASI_PARSE_RESULT_BAD_PARAM; + } + + ctx->addr_pool[ctx->addr_pool_size++] = token; + token = strtok(NULL, ";"); + } + } + else if (!strncmp(arg, "--allow-resolve=", 16)) { + if (arg[16] == '\0') + return LIBC_WASI_PARSE_RESULT_NEED_HELP; + if (ctx->ns_lookup_pool_size + >= sizeof(ctx->ns_lookup_pool) / sizeof(ctx->ns_lookup_pool[0])) { + printf("Only allow max ns lookup number %d\n", + (int)(sizeof(ctx->ns_lookup_pool) + / sizeof(ctx->ns_lookup_pool[0]))); + return LIBC_WASI_PARSE_RESULT_BAD_PARAM; + } + ctx->ns_lookup_pool[ctx->ns_lookup_pool_size++] = arg + 16; + } + return LIBC_WASI_PARSE_RESULT_OK; +} + +void +libc_wasi_init(wasm_module_t wasm_module, int argc, char **argv, + libc_wasi_parse_context_t *ctx) +{ + wasm_runtime_set_wasi_args(wasm_module, ctx->dir_list, ctx->dir_list_size, + ctx->map_dir_list, ctx->map_dir_list_size, + ctx->env_list, ctx->env_list_size, argv, argc); + + wasm_runtime_set_wasi_addr_pool(wasm_module, ctx->addr_pool, + ctx->addr_pool_size); + wasm_runtime_set_wasi_ns_lookup_pool(wasm_module, ctx->ns_lookup_pool, + ctx->ns_lookup_pool_size); +} diff --git a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp index 164fa0b7d..b854c70b4 100644 --- a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp +++ b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp @@ -250,7 +250,8 @@ handle_cmd_load_module(uint64 *args, uint32 argc) if (total_size >= UINT32_MAX || !(enclave_module = (EnclaveModule *)os_mmap( - NULL, (uint32)total_size, map_prot, map_flags))) { + NULL, (uint32)total_size, map_prot, map_flags, + os_get_invalid_handle()))) { set_error_buf(error_buf, error_buf_size, "WASM module load failed: mmap memory failed."); *(void **)args_org = NULL; diff --git a/product-mini/platforms/nuttx/wamr.mk b/product-mini/platforms/nuttx/wamr.mk index d46a17fae..1a5ac1651 100644 --- a/product-mini/platforms/nuttx/wamr.mk +++ b/product-mini/platforms/nuttx/wamr.mk @@ -246,8 +246,12 @@ ifeq ($(CONFIG_INTERPRETERS_WAMR_LIBC_WASI),y) CFLAGS += -DWASM_ENABLE_LIBC_WASI=1 CFLAGS += -I$(IWASM_ROOT)/libraries/libc-wasi/sandboxed-system-primitives/src CFLAGS += -I$(IWASM_ROOT)/libraries/libc-wasi/sandboxed-system-primitives/include +CFLAGS += -I${SHARED_ROOT}/platform/common/libc-util CSRCS += blocking_op.c CSRCS += posix_socket.c +CSRCS += posix_file.c +CSRCS += posix_clock.c +CSRCS += libc_errno.c CSRCS += libc_wasi_wrapper.c VPATH += $(IWASM_ROOT)/libraries/libc-wasi CSRCS += posix.c @@ -395,6 +399,7 @@ ASRCS += $(INVOKE_NATIVE) VPATH += $(SHARED_ROOT)/platform/nuttx VPATH += $(SHARED_ROOT)/platform/common/posix +VPATH += $(SHARED_ROOT)/platform/common/libc-util VPATH += $(SHARED_ROOT)/mem-alloc VPATH += $(SHARED_ROOT)/mem-alloc/ems VPATH += $(SHARED_ROOT)/utils diff --git a/product-mini/platforms/posix/main.c b/product-mini/platforms/posix/main.c index 09bf7c551..c225b0858 100644 --- a/product-mini/platforms/posix/main.c +++ b/product-mini/platforms/posix/main.c @@ -14,6 +14,10 @@ #include "bh_read_file.h" #include "wasm_export.h" +#if WASM_ENABLE_LIBC_WASI != 0 +#include "../common/libc_wasi.c" +#endif + #if BH_HAS_DLFCN #include #endif @@ -69,24 +73,7 @@ print_help() printf(" --disable-bounds-checks Disable bounds checks for memory accesses\n"); #endif #if WASM_ENABLE_LIBC_WASI != 0 - printf(" --env= Pass wasi environment variables with \"key=value\"\n"); - printf(" to the program, for example:\n"); - printf(" --env=\"key1=value1\" --env=\"key2=value2\"\n"); - printf(" --dir= Grant wasi access to the given host directories\n"); - printf(" to the program, for example:\n"); - printf(" --dir= --dir=\n"); - printf(" --map-dir= Grant wasi access to the given host directories\n"); - printf(" to the program at a specific guest path, for example:\n"); - printf(" --map-dir= --map-dir=\n"); - printf(" --addr-pool= Grant wasi access to the given network addresses in\n"); - printf(" CIRD notation to the program, seperated with ',',\n"); - printf(" for example:\n"); - printf(" --addr-pool=1.2.3.4/15,2.3.4.5/16\n"); - printf(" --allow-resolve= Allow the lookup of the specific domain name or domain\n"); - printf(" name suffixes using a wildcard, for example:\n"); - printf(" --allow-resolve=example.com # allow the lookup of the specific domain\n"); - printf(" --allow-resolve=*.example.com # allow the lookup of all subdomains\n"); - printf(" --allow-resolve=* # allow any lookup\n"); + libc_wasi_print_help(); #endif #if BH_HAS_DLFCN printf(" --native-lib= Register native libraries to the WASM module, which\n"); @@ -207,8 +194,11 @@ app_instance_repl(wasm_module_inst_t module_inst) break; } if (app_argc != 0) { + const char *exception; wasm_application_execute_func(module_inst, app_argv[0], app_argc - 1, app_argv + 1); + if ((exception = wasm_runtime_get_exception(module_inst))) + printf("%s\n", exception); } free(app_argv); } @@ -269,25 +259,6 @@ resolve_segue_flags(char *str_flags) } #endif /* end of WASM_ENABLE_JIT != 0 */ -#if WASM_ENABLE_LIBC_WASI != 0 -static bool -validate_env_str(char *env) -{ - char *p = env; - int key_len = 0; - - while (*p != '\0' && *p != '=') { - key_len++; - p++; - } - - if (*p != '=' || key_len == 0) - return false; - - return true; -} -#endif - #if BH_HAS_DLFCN struct native_lib { void *handle; @@ -464,7 +435,37 @@ moudle_destroyer(uint8 *buffer, uint32 size) #if WASM_ENABLE_GLOBAL_HEAP_POOL != 0 static char global_heap_buf[WASM_GLOBAL_HEAP_SIZE] = { 0 }; +#else +static void * +malloc_func( +#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 + void *user_data, #endif + unsigned int size) +{ + return malloc(size); +} + +static void * +realloc_func( +#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 + void *user_data, +#endif + void *ptr, unsigned int size) +{ + return realloc(ptr, size); +} + +static void +free_func( +#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 + void *user_data, +#endif + void *ptr) +{ + free(ptr); +} +#endif /* end of WASM_ENABLE_GLOBAL_HEAP_POOL */ #if WASM_ENABLE_STATIC_PGO != 0 static void @@ -574,16 +575,7 @@ main(int argc, char *argv[]) bool disable_bounds_checks = false; #endif #if WASM_ENABLE_LIBC_WASI != 0 - const char *dir_list[8] = { NULL }; - uint32 dir_list_size = 0; - const char *map_dir_list[8] = { NULL }; - uint32 map_dir_list_size = 0; - const char *env_list[8] = { NULL }; - uint32 env_list_size = 0; - const char *addr_pool[8] = { NULL }; - uint32 addr_pool_size = 0; - const char *ns_lookup_pool[8] = { NULL }; - uint32 ns_lookup_pool_size = 0; + libc_wasi_parse_context_t wasi_parse_ctx; #endif #if BH_HAS_DLFCN const char *native_lib_list[8] = { NULL }; @@ -602,6 +594,10 @@ main(int argc, char *argv[]) int timeout_ms = -1; #endif +#if WASM_ENABLE_LIBC_WASI != 0 + memset(&wasi_parse_ctx, 0, sizeof(wasi_parse_ctx)); +#endif + /* Process options. */ for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) { if (!strcmp(argv[0], "-f") || !strcmp(argv[0], "--function")) { @@ -705,80 +701,6 @@ main(int argc, char *argv[]) return print_help(); } #endif /* end of WASM_ENABLE_JIT != 0 */ -#if WASM_ENABLE_LIBC_WASI != 0 - else if (!strncmp(argv[0], "--dir=", 6)) { - if (argv[0][6] == '\0') - return print_help(); - if (dir_list_size >= sizeof(dir_list) / sizeof(char *)) { - printf("Only allow max dir number %d\n", - (int)(sizeof(dir_list) / sizeof(char *))); - return 1; - } - dir_list[dir_list_size++] = argv[0] + 6; - } - else if (!strncmp(argv[0], "--map-dir=", 10)) { - if (argv[0][10] == '\0') - return print_help(); - if (map_dir_list_size >= sizeof(map_dir_list) / sizeof(char *)) { - printf("Only allow max map dir number %d\n", - (int)(sizeof(map_dir_list) / sizeof(char *))); - return 1; - } - map_dir_list[map_dir_list_size++] = argv[0] + 10; - } - else if (!strncmp(argv[0], "--env=", 6)) { - char *tmp_env; - - if (argv[0][6] == '\0') - return print_help(); - if (env_list_size >= sizeof(env_list) / sizeof(char *)) { - printf("Only allow max env number %d\n", - (int)(sizeof(env_list) / sizeof(char *))); - return 1; - } - tmp_env = argv[0] + 6; - if (validate_env_str(tmp_env)) - env_list[env_list_size++] = tmp_env; - else { - printf("Wasm parse env string failed: expect \"key=value\", " - "got \"%s\"\n", - tmp_env); - return print_help(); - } - } - /* TODO: parse the configuration file via --addr-pool-file */ - else if (!strncmp(argv[0], "--addr-pool=", strlen("--addr-pool="))) { - /* like: --addr-pool=100.200.244.255/30 */ - char *token = NULL; - - if ('\0' == argv[0][12]) - return print_help(); - - token = strtok(argv[0] + strlen("--addr-pool="), ","); - while (token) { - if (addr_pool_size >= sizeof(addr_pool) / sizeof(char *)) { - printf("Only allow max address number %d\n", - (int)(sizeof(addr_pool) / sizeof(char *))); - return 1; - } - - addr_pool[addr_pool_size++] = token; - token = strtok(NULL, ";"); - } - } - else if (!strncmp(argv[0], "--allow-resolve=", 16)) { - if (argv[0][16] == '\0') - return print_help(); - if (ns_lookup_pool_size - >= sizeof(ns_lookup_pool) / sizeof(ns_lookup_pool[0])) { - printf( - "Only allow max ns lookup number %d\n", - (int)(sizeof(ns_lookup_pool) / sizeof(ns_lookup_pool[0]))); - return 1; - } - ns_lookup_pool[ns_lookup_pool_size++] = argv[0] + 16; - } -#endif /* WASM_ENABLE_LIBC_WASI */ #if BH_HAS_DLFCN else if (!strncmp(argv[0], "--native-lib=", 13)) { if (argv[0][13] == '\0') @@ -841,8 +763,22 @@ main(int argc, char *argv[]) patch); return 0; } - else + else { +#if WASM_ENABLE_LIBC_WASI != 0 + libc_wasi_parse_result_t result = + libc_wasi_parse(argv[0], &wasi_parse_ctx); + switch (result) { + case LIBC_WASI_PARSE_RESULT_OK: + continue; + case LIBC_WASI_PARSE_RESULT_NEED_HELP: + return print_help(); + case LIBC_WASI_PARSE_RESULT_BAD_PARAM: + return 1; + } +#else return print_help(); +#endif + } } if (argc == 0) @@ -861,9 +797,13 @@ main(int argc, char *argv[]) init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf); #else init_args.mem_alloc_type = Alloc_With_Allocator; - init_args.mem_alloc_option.allocator.malloc_func = malloc; - init_args.mem_alloc_option.allocator.realloc_func = realloc; - init_args.mem_alloc_option.allocator.free_func = free; +#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 + /* Set user data for the allocator is needed */ + /* init_args.mem_alloc_option.allocator.user_data = user_data; */ +#endif + init_args.mem_alloc_option.allocator.malloc_func = malloc_func; + init_args.mem_alloc_option.allocator.realloc_func = realloc_func; + init_args.mem_alloc_option.allocator.free_func = free_func; #endif #if WASM_ENABLE_FAST_JIT != 0 @@ -908,8 +848,8 @@ main(int argc, char *argv[]) int map_prot = MMAP_PROT_READ | MMAP_PROT_WRITE | MMAP_PROT_EXEC; int map_flags = MMAP_MAP_32BIT; - if (!(wasm_file_mapped = - os_mmap(NULL, (uint32)wasm_file_size, map_prot, map_flags))) { + if (!(wasm_file_mapped = os_mmap(NULL, (uint32)wasm_file_size, map_prot, + map_flags, os_get_invalid_handle()))) { printf("mmap memory failed\n"); wasm_runtime_free(wasm_file_buf); goto fail1; @@ -935,13 +875,7 @@ main(int argc, char *argv[]) } #if WASM_ENABLE_LIBC_WASI != 0 - wasm_runtime_set_wasi_args(wasm_module, dir_list, dir_list_size, - map_dir_list, map_dir_list_size, env_list, - env_list_size, argv, argc); - - wasm_runtime_set_wasi_addr_pool(wasm_module, addr_pool, addr_pool_size); - wasm_runtime_set_wasi_ns_lookup_pool(wasm_module, ns_lookup_pool, - ns_lookup_pool_size); + libc_wasi_init(wasm_module, argc, argv, &wasi_parse_ctx); #endif /* instantiate the module */ diff --git a/product-mini/platforms/windows/CMakeLists.txt b/product-mini/platforms/windows/CMakeLists.txt index db88f42bc..02aa3f31b 100644 --- a/product-mini/platforms/windows/CMakeLists.txt +++ b/product-mini/platforms/windows/CMakeLists.txt @@ -4,7 +4,6 @@ cmake_minimum_required (VERSION 2.9) project (iwasm C ASM CXX) -enable_language(ASM_MASM) # set (CMAKE_VERBOSE_MAKEFILE 1) set (WAMR_BUILD_PLATFORM "windows") @@ -13,8 +12,6 @@ set (WAMR_BUILD_PLATFORM "windows") set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") -set (CMAKE_C_STANDARD 99) - add_definitions(-DCOMPILING_WASM_RUNTIME_API=1) # Set WAMR_BUILD_TARGET, currently values supported: @@ -96,6 +93,15 @@ if (WAMR_BUILD_DEBUG_INTERP EQUAL 1) set (WAMR_BUILD_SIMD 0) endif () +if (WAMR_BUILD_LIBC_WASI EQUAL 1) + set (CMAKE_C_STANDARD 11) + if (MSVC) + add_compile_options(/experimental:c11atomics) + endif() +else() + set (CMAKE_C_STANDARD 99) +endif() + set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..) include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) @@ -147,3 +153,9 @@ target_link_libraries (libiwasm ${LLVM_AVAILABLE_LIBS} ${UV_A_LIBS}) if (MINGW) target_link_libraries (libiwasm ws2_32) endif () + +if (WIN32) + target_link_libraries(libiwasm ntdll) + + target_link_libraries(iwasm ntdll) +endif() diff --git a/product-mini/platforms/windows/main.c b/product-mini/platforms/windows/main.c index bba427302..921b77265 100644 --- a/product-mini/platforms/windows/main.c +++ b/product-mini/platforms/windows/main.c @@ -10,6 +10,10 @@ #include "bh_read_file.h" #include "wasm_export.h" +#if WASM_ENABLE_LIBC_WASI != 0 +#include "../common/libc_wasi.c" +#endif + static int app_argc; static char **app_argv; @@ -48,12 +52,7 @@ print_help() printf(" --repl Start a very simple REPL (read-eval-print-loop) mode\n" " that runs commands in the form of `FUNC ARG...`\n"); #if WASM_ENABLE_LIBC_WASI != 0 - printf(" --env= Pass wasi environment variables with \"key=value\"\n"); - printf(" to the program, for example:\n"); - printf(" --env=\"key1=value1\" --env=\"key2=value2\"\n"); - printf(" --dir= Grant wasi access to the given host directories\n"); - printf(" to the program, for example:\n"); - printf(" --dir= --dir=\n"); + libc_wasi_print_help(); #endif #if WASM_ENABLE_MULTI_MODULE != 0 printf(" --module-path= Indicate a module search path. default is current\n" @@ -141,7 +140,8 @@ app_instance_repl(wasm_module_inst_t module_inst) char *cmd; size_t n; - while ((printf("webassembly> "), cmd = fgets(buffer, sizeof(buffer), stdin)) + while ((printf("webassembly> "), fflush(stdout), + cmd = fgets(buffer, sizeof(buffer), stdin)) != NULL) { bh_assert(cmd); n = strlen(cmd); @@ -161,8 +161,11 @@ app_instance_repl(wasm_module_inst_t module_inst) break; } if (app_argc != 0) { + const char *exception; wasm_application_execute_func(module_inst, app_argv[0], app_argc - 1, app_argv + 1); + if ((exception = wasm_runtime_get_exception(module_inst))) + printf("%s\n", exception); } free(app_argv); } @@ -170,28 +173,39 @@ app_instance_repl(wasm_module_inst_t module_inst) return NULL; } -#if WASM_ENABLE_LIBC_WASI != 0 -static bool -validate_env_str(char *env) -{ - char *p = env; - int key_len = 0; - - while (*p != '\0' && *p != '=') { - key_len++; - p++; - } - - if (*p != '=' || key_len == 0) - return false; - - return true; -} -#endif - #if WASM_ENABLE_GLOBAL_HEAP_POOL != 0 static char global_heap_buf[WASM_GLOBAL_HEAP_SIZE] = { 0 }; +#else +static void * +malloc_func( +#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 + void *user_data, #endif + unsigned int size) +{ + return malloc(size); +} + +static void * +realloc_func( +#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 + void *user_data, +#endif + void *ptr, unsigned int size) +{ + return realloc(ptr, size); +} + +static void +free_func( +#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 + void *user_data, +#endif + void *ptr) +{ + free(ptr); +} +#endif /* end of WASM_ENABLE_GLOBAL_HEAP_POOL */ #if WASM_ENABLE_MULTI_MODULE != 0 static char * @@ -272,16 +286,17 @@ main(int argc, char *argv[]) bool is_repl_mode = false; bool is_xip_file = false; #if WASM_ENABLE_LIBC_WASI != 0 - const char *dir_list[8] = { NULL }; - uint32 dir_list_size = 0; - const char *env_list[8] = { NULL }; - uint32 env_list_size = 0; + libc_wasi_parse_context_t wasi_parse_ctx; #endif #if WASM_ENABLE_DEBUG_INTERP != 0 char *ip_addr = NULL; int instance_port = 0; #endif +#if WASM_ENABLE_LIBC_WASI != 0 + memset(&wasi_parse_ctx, 0, sizeof(wasi_parse_ctx)); +#endif + /* Process options. */ for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) { if (!strcmp(argv[0], "-f") || !strcmp(argv[0], "--function")) { @@ -363,38 +378,6 @@ main(int argc, char *argv[]) } } #endif -#if WASM_ENABLE_LIBC_WASI != 0 - else if (!strncmp(argv[0], "--dir=", 6)) { - if (argv[0][6] == '\0') - return print_help(); - if (dir_list_size >= sizeof(dir_list) / sizeof(char *)) { - printf("Only allow max dir number %d\n", - (int)(sizeof(dir_list) / sizeof(char *))); - return 1; - } - dir_list[dir_list_size++] = argv[0] + 6; - } - else if (!strncmp(argv[0], "--env=", 6)) { - char *tmp_env; - - if (argv[0][6] == '\0') - return print_help(); - if (env_list_size >= sizeof(env_list) / sizeof(char *)) { - printf("Only allow max env number %d\n", - (int)(sizeof(env_list) / sizeof(char *))); - return 1; - } - tmp_env = argv[0] + 6; - if (validate_env_str(tmp_env)) - env_list[env_list_size++] = tmp_env; - else { - printf("Wasm parse env string failed: expect \"key=value\", " - "got \"%s\"\n", - tmp_env); - return print_help(); - } - } -#endif /* WASM_ENABLE_LIBC_WASI */ #if WASM_ENABLE_MULTI_MODULE != 0 else if (!strncmp(argv[0], MODULE_PATH, strlen(MODULE_PATH))) { module_search_path = handle_module_path(argv[0]); @@ -430,8 +413,22 @@ main(int argc, char *argv[]) patch); return 0; } - else + else { +#if WASM_ENABLE_LIBC_WASI != 0 + libc_wasi_parse_result_t result = + libc_wasi_parse(argv[0], &wasi_parse_ctx); + switch (result) { + case LIBC_WASI_PARSE_RESULT_OK: + continue; + case LIBC_WASI_PARSE_RESULT_NEED_HELP: + return print_help(); + case LIBC_WASI_PARSE_RESULT_BAD_PARAM: + return 1; + } +#else return print_help(); +#endif + } } if (argc == 0) @@ -450,9 +447,13 @@ main(int argc, char *argv[]) init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf); #else init_args.mem_alloc_type = Alloc_With_Allocator; - init_args.mem_alloc_option.allocator.malloc_func = malloc; - init_args.mem_alloc_option.allocator.realloc_func = realloc; - init_args.mem_alloc_option.allocator.free_func = free; +#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 + /* Set user data for the allocator is needed */ + /* init_args.mem_alloc_option.allocator.user_data = user_data; */ +#endif + init_args.mem_alloc_option.allocator.malloc_func = malloc_func; + init_args.mem_alloc_option.allocator.realloc_func = realloc_func; + init_args.mem_alloc_option.allocator.free_func = free_func; #endif #if WASM_ENABLE_JIT != 0 @@ -487,8 +488,8 @@ main(int argc, char *argv[]) int map_prot = MMAP_PROT_READ | MMAP_PROT_WRITE | MMAP_PROT_EXEC; int map_flags = MMAP_MAP_32BIT; - if (!(wasm_file_mapped = - os_mmap(NULL, (uint32)wasm_file_size, map_prot, map_flags))) { + if (!(wasm_file_mapped = os_mmap(NULL, (uint32)wasm_file_size, map_prot, + map_flags, os_get_invalid_handle()))) { printf("mmap memory failed\n"); wasm_runtime_free(wasm_file_buf); goto fail1; @@ -514,8 +515,7 @@ main(int argc, char *argv[]) } #if WASM_ENABLE_LIBC_WASI != 0 - wasm_runtime_set_wasi_args(wasm_module, dir_list, dir_list_size, NULL, 0, - env_list, env_list_size, argv, argc); + libc_wasi_init(wasm_module, argc, argv, &wasi_parse_ctx); #endif /* instantiate the module */ diff --git a/product-mini/platforms/windows/wasi_filtered_tests.json b/product-mini/platforms/windows/wasi_filtered_tests.json new file mode 100644 index 000000000..492a746eb --- /dev/null +++ b/product-mini/platforms/windows/wasi_filtered_tests.json @@ -0,0 +1,51 @@ +{ + "WASI C tests": { + "fdopendir-with-access": "Not implemented", + "lseek": "Not implemented" + }, + "WASI Rust tests": { + "dangling_symlink": "Not implemented", + "directory_seek": "Not implemented", + "dir_fd_op_failures": "Not implemented", + "fd_advise": "Not implemented", + "fd_fdstat_set_rights": "Not implemented", + "fd_filestat_set": "Not implemented", + "fd_flags_set": "Not implemented", + "fd_readdir": "Not implemented", + "file_allocate": "Not implemented", + "file_seek_tell": "Not implemented", + "file_truncation": "Not implemented", + "nofollow_errors": "Not implemented", + "path_exists": "Not implemented", + "path_filestat": "Not implemented", + "path_link": "Not implemented", + "path_open_preopen": "Not implemented", + "path_rename": "Not implemented", + "path_rename_dir_trailing_slashes": "Not implemented", + "path_symlink_trailing_slashes": "Not implemented", + "poll_oneoff_stdio": "Not implemented", + "readlink": "Not implemented (path_symlink)", + "symlink_create": "Not implemented", + "symlink_filestat": "Not implemented", + "symlink_loop": "Not implemented", + "truncation_rights": "Not implemented" + }, + "WASI threads proposal": { + "wasi_threads_exit_main_wasi_read": "Blocking ops not implemented", + "wasi_threads_exit_nonmain_wasi_read": "Blocking ops not implemented", + "wasi_threads_return_main_wasi_read": "Blocking ops not implemented", + "wasi_threads_return_main_wasi": "Blocking ops not implemented", + "wasi_threads_exit_nonmain_wasi": "Blocking ops not implemented", + "wasi_threads_exit_main_wasi": "Blocking ops not implemented" + }, + "WAMR lib-socket tests": { + "nslookup": "Not implemented", + "tcp_udp": "Not implemented" + }, + "lib-wasi-threads tests": { + "nonmain_proc_exit_sleep": "poll_oneoff not implemented", + "main_proc_exit_sleep": "poll_oneoff not implemented", + "main_trap_sleep": "poll_oneoff not implemented", + "nonmain_trap_sleep": "poll_oneoff not implemented" + } +} \ No newline at end of file diff --git a/product-mini/platforms/zephyr/simple/src/main.c b/product-mini/platforms/zephyr/simple/src/main.c index 8799e737a..a6479ba75 100644 --- a/product-mini/platforms/zephyr/simple/src/main.c +++ b/product-mini/platforms/zephyr/simple/src/main.c @@ -68,7 +68,7 @@ app_instance_main(wasm_module_inst_t module_inst) if (wasm_runtime_lookup_function(module_inst, "main", NULL) || wasm_runtime_lookup_function(module_inst, "__main_argc_argv", NULL)) { - LOG_VERBOSE("Calling main funciton\n"); + LOG_VERBOSE("Calling main function\n"); wasm_application_execute_main(module_inst, app_argc, app_argv); } else if ((func = wasm_runtime_lookup_function(module_inst, "app_main", @@ -80,7 +80,7 @@ app_instance_main(wasm_module_inst_t module_inst) return NULL; } - LOG_VERBOSE("Calling app_main funciton\n"); + LOG_VERBOSE("Calling app_main function\n"); wasm_runtime_call_wasm(exec_env, func, 0, argv); if (!wasm_runtime_get_exception(module_inst)) { @@ -248,7 +248,7 @@ fail1: end = k_uptime_get_32(); - printf("elpase: %d\n", (end - start)); + printf("elapsed: %d\n", (end - start)); } #define MAIN_THREAD_STACK_SIZE (CONFIG_MAIN_THREAD_STACK_SIZE) diff --git a/samples/basic/CMakeLists.txt b/samples/basic/CMakeLists.txt index 4191ad15d..62edf08fb 100644 --- a/samples/basic/CMakeLists.txt +++ b/samples/basic/CMakeLists.txt @@ -9,7 +9,6 @@ if (NOT WAMR_BUILD_PLATFORM STREQUAL "windows") project (basic) else() project (basic C ASM) - enable_language (ASM_MASM) endif() ################ runtime settings ################ diff --git a/samples/file/src/CMakeLists.txt b/samples/file/src/CMakeLists.txt index 2bc3bec64..1f7a2435f 100644 --- a/samples/file/src/CMakeLists.txt +++ b/samples/file/src/CMakeLists.txt @@ -9,7 +9,6 @@ if (NOT WAMR_BUILD_PLATFORM STREQUAL "windows") project (iwasm) else() project (iwasm C ASM) - enable_language (ASM_MASM) endif() ################ runtime settings ################ diff --git a/samples/inst-context-threads/CMakeLists.txt b/samples/inst-context-threads/CMakeLists.txt index 7326a5436..5ce8696d8 100644 --- a/samples/inst-context-threads/CMakeLists.txt +++ b/samples/inst-context-threads/CMakeLists.txt @@ -9,7 +9,6 @@ if (NOT WAMR_BUILD_PLATFORM STREQUAL "windows") project (inst-context) else() project (inst-context C ASM) - enable_language (ASM_MASM) endif() ################ runtime settings ################ diff --git a/samples/inst-context/CMakeLists.txt b/samples/inst-context/CMakeLists.txt index b1167d277..af387ca26 100644 --- a/samples/inst-context/CMakeLists.txt +++ b/samples/inst-context/CMakeLists.txt @@ -9,7 +9,6 @@ if (NOT WAMR_BUILD_PLATFORM STREQUAL "windows") project (inst-context) else() project (inst-context C ASM) - enable_language (ASM_MASM) endif() ################ runtime settings ################ diff --git a/samples/ref-types/CMakeLists.txt b/samples/ref-types/CMakeLists.txt index 325699b20..fd18e6378 100644 --- a/samples/ref-types/CMakeLists.txt +++ b/samples/ref-types/CMakeLists.txt @@ -9,7 +9,6 @@ if (NOT WAMR_BUILD_PLATFORM STREQUAL "windows") project(ref-types) else() project (ref-types C ASM) - enable_language (ASM_MASM) endif() ################ runtime settings ################ diff --git a/samples/wasm-c-api/CMakeLists.txt b/samples/wasm-c-api/CMakeLists.txt index 4dab0185c..4189f7280 100644 --- a/samples/wasm-c-api/CMakeLists.txt +++ b/samples/wasm-c-api/CMakeLists.txt @@ -9,7 +9,6 @@ if (NOT WAMR_BUILD_PLATFORM STREQUAL "windows") project(c-api) else() project (c-api C ASM) - enable_language (ASM_MASM) endif() if(NOT CMAKE_BUILD_TYPE) diff --git a/tests/wamr-test-suites/spec-test-script/all.py b/tests/wamr-test-suites/spec-test-script/all.py index 6b4ce5a68..48d35acbf 100644 --- a/tests/wamr-test-suites/spec-test-script/all.py +++ b/tests/wamr-test-suites/spec-test-script/all.py @@ -6,7 +6,7 @@ import argparse import multiprocessing as mp -import os +import platform import pathlib import subprocess import sys @@ -28,12 +28,26 @@ To run a single GC case: --aot-compiler wamrc --gc spec/test/core/xxx.wast """ -PLATFORM_NAME = os.uname().sysname.lower() -IWASM_CMD = "../../../product-mini/platforms/" + PLATFORM_NAME + "/build/iwasm" +def exe_file_path(base_path: str) -> str: + if platform.system().lower() == "windows": + base_path += ".exe" + return base_path + +def get_iwasm_cmd(platform: str) -> str: + build_path = "../../../product-mini/platforms/" + platform + "/build/" + exe_name = "iwasm" + + if platform == "windows": + build_path += "RelWithDebInfo/" + + return exe_file_path(build_path + exe_name) + +PLATFORM_NAME = platform.uname().system.lower() +IWASM_CMD = get_iwasm_cmd(PLATFORM_NAME) IWASM_SGX_CMD = "../../../product-mini/platforms/linux-sgx/enclave-sample/iwasm" IWASM_QEMU_CMD = "iwasm" SPEC_TEST_DIR = "spec/test/core" -WAST2WASM_CMD = "./wabt/out/gcc/Release/wat2wasm" +WAST2WASM_CMD = exe_file_path("./wabt/out/gcc/Release/wat2wasm") SPEC_INTERPRETER_CMD = "spec/interpreter/wasm" WAMRC_CMD = "../../../wamr-compiler/build/wamrc" @@ -67,15 +81,15 @@ def ignore_the_case( simd_flag=False, gc_flag=False, xip_flag=False, - qemu_flag=False, eh_flag=False, + qemu_flag=False, ): # print(f"case_name {case_name}\n") - if eh_flag and case_name in [ "tag", "try_catch", "rethrow", "try_delegate" ]: - return False - else: - return True - + if eh_flag: + if case_name in [ "tag", "try_catch", "rethrow", "try_delegate" ]: + return False + else: + return True if case_name in ["comments", "inline-module", "names"]: return True @@ -159,9 +173,9 @@ def test_case( qemu_flag=False, qemu_firmware="", log="", + no_pty=False ): - - CMD = ["python3", "runtest.py"] + CMD = [sys.executable, "runtest.py"] CMD.append("--wast2wasm") CMD.append(WAST2WASM_CMD if not gc_flag else SPEC_INTERPRETER_CMD) CMD.append("--interpreter") @@ -171,6 +185,8 @@ def test_case( CMD.append(IWASM_QEMU_CMD) else: CMD.append(IWASM_CMD) + if no_pty: + CMD.append("--no-pty") CMD.append("--aot-compiler") CMD.append(WAMRC_CMD) @@ -279,6 +295,7 @@ def test_suite( qemu_flag=False, qemu_firmware="", log="", + no_pty=False, ): global SPEC_TEST_DIR if eh_flag: @@ -312,8 +329,8 @@ def test_suite( simd_flag, gc_flag, xip_flag, - qemu_flag, eh_flag, + qemu_flag, ): filtered_case_list.append(case_path) print(f"---> {len(case_list)} --filter--> {len(filtered_case_list)}") @@ -346,6 +363,7 @@ def test_suite( qemu_flag, qemu_firmware, log, + no_pty, ], ) @@ -384,6 +402,7 @@ def test_suite( qemu_flag, qemu_firmware, log, + no_pty, ) successful_case += 1 except Exception as e: @@ -513,6 +532,8 @@ def main(): nargs="*", help=f"Specify all wanted cases. If not the script will go through all cases under {SPEC_TEST_DIR}", ) + parser.add_argument('--no-pty', action='store_true', + help="Use direct pipes instead of pseudo-tty") options = parser.parse_args() @@ -544,6 +565,7 @@ def main(): options.qemu_flag, options.qemu_firmware, options.log, + options.no_pty ) end = time.time_ns() print( @@ -568,6 +590,7 @@ def main(): options.qemu_flag, options.qemu_firmware, options.log, + options.no_pty, ) else: ret = True diff --git a/tests/wamr-test-suites/spec-test-script/runtest.py b/tests/wamr-test-suites/spec-test-script/runtest.py index d4f05428d..ad7cce928 100755 --- a/tests/wamr-test-suites/spec-test-script/runtest.py +++ b/tests/wamr-test-suites/spec-test-script/runtest.py @@ -5,22 +5,21 @@ from __future__ import print_function import argparse import array import atexit -import fcntl import math import os -# Pseudo-TTY and terminal manipulation -import pty import re import shutil import struct import subprocess import sys import tempfile -import termios import time +import threading import traceback from select import select +from queue import Queue from subprocess import PIPE, STDOUT, Popen +from typing import BinaryIO, Optional, Tuple if sys.version_info[0] == 2: IS_PY_3 = False @@ -52,6 +51,10 @@ def log(data, end='\n'): print(data, end=end) sys.stdout.flush() +def create_tmp_file(suffix: str) -> str: + with tempfile.NamedTemporaryFile(suffix=suffix, delete=False) as tmp_file: + return tmp_file.name + # TODO: do we need to support '\n' too import platform @@ -62,6 +65,34 @@ else: sep = "\r\n" rundir = None + +class AsyncStreamReader: + def __init__(self, stream: BinaryIO) -> None: + self._queue = Queue() + self._reader_thread = threading.Thread( + daemon=True, + target=AsyncStreamReader._stdout_reader, + args=(self._queue, stream)) + self._reader_thread.start() + + def read(self) -> Optional[bytes]: + return self._queue.get() + + def cleanup(self) -> None: + self._reader_thread.join() + + @staticmethod + def _stdout_reader(queue: Queue, stdout: BinaryIO) -> None: + while True: + try: + queue.put(stdout.read(1)) + except ValueError as e: + if stdout.closed: + queue.put(None) + break + raise e + + class Runner(): def __init__(self, args, no_pty=False): self.no_pty = no_pty @@ -77,11 +108,14 @@ class Runner(): if no_pty: self.process = Popen(args, bufsize=0, stdin=PIPE, stdout=PIPE, stderr=STDOUT, - preexec_fn=os.setsid, env=env) self.stdin = self.process.stdin self.stdout = self.process.stdout else: + import fcntl + # Pseudo-TTY and terminal manipulation + import pty + import termios # Use tty to setup an interactive environment master, slave = pty.openpty() @@ -101,35 +135,53 @@ class Runner(): self.stdin = os.fdopen(master, 'r+b', 0) self.stdout = self.stdin + if platform.system().lower() == "windows": + self._stream_reader = AsyncStreamReader(self.stdout) + else: + self._stream_reader = None + self.buf = "" + def _read_stdout_byte(self) -> Tuple[bool, Optional[bytes]]: + if self._stream_reader: + return True, self._stream_reader.read() + else: + # select doesn't work on file descriptors on Windows. + # however, this method is much faster than using + # queue, so we keep it for non-windows platforms. + [outs,_,_] = select([self.stdout], [], [], 1) + if self.stdout in outs: + return True, self.stdout.read(1) + else: + return False, None + def read_to_prompt(self, prompts, timeout): wait_until = time.time() + timeout while time.time() < wait_until: - [outs,_,_] = select([self.stdout], [], [], 1) - if self.stdout in outs: - read_byte = self.stdout.read(1) - if not read_byte: - # EOF on macOS ends up here. - break - read_byte = read_byte.decode('utf-8') if IS_PY_3 else read_byte + has_value, read_byte = self._read_stdout_byte() + if not has_value: + continue + if not read_byte: + # EOF on macOS ends up here. + break + read_byte = read_byte.decode('utf-8') if IS_PY_3 else read_byte - debug(read_byte) - if self.no_pty: - self.buf += read_byte.replace('\n', '\r\n') - else: - self.buf += read_byte - self.buf = self.buf.replace('\r\r', '\r') + debug(read_byte) + if self.no_pty: + self.buf += read_byte.replace('\n', '\r\n') + else: + self.buf += read_byte + self.buf = self.buf.replace('\r\r', '\r') - # filter the prompts - for prompt in prompts: - pattern = re.compile(prompt) - match = pattern.search(self.buf) - if match: - end = match.end() - buf = self.buf[0:end-len(prompt)] - self.buf = self.buf[end:] - return buf + # filter the prompts + for prompt in prompts: + pattern = re.compile(prompt) + match = pattern.search(self.buf) + if match: + end = match.end() + buf = self.buf[0:end-len(prompt)] + self.buf = self.buf[end:] + return buf return None def writeline(self, str): @@ -140,6 +192,8 @@ class Runner(): self.stdin.write(str_to_write) def cleanup(self): + atexit.unregister(self.cleanup) + if self.process: try: self.writeline("__exit__") @@ -157,6 +211,8 @@ class Runner(): self.stdout = None if not IS_PY_3: sys.exc_clear() + if self._stream_reader: + self._stream_reader.cleanup() def assert_prompt(runner, prompts, timeout, is_need_execute_result): # Wait for the initial prompt @@ -405,9 +461,9 @@ def cast_v128_to_i64x2(numbers, type, lane_type): unpacked = struct.unpack("Q Q", packed) return unpacked, f"[{unpacked[0]:#x} {unpacked[1]:#x}]:{lane_type}:v128" - def parse_simple_const_w_type(number, type): number = number.replace('_', '') + number = re.sub(r"nan\((ind|snan)\)", "nan", number) if type in ["i32", "i64"]: number = int(number, 16) if '0x' in number else int(number) return number, "0x{:x}:{}".format(number, type) \ @@ -987,7 +1043,8 @@ def skip_test(form, skip_list): def compile_wast_to_wasm(form, wast_tempfile, wasm_tempfile, opts): log("Writing WAST module to '%s'" % wast_tempfile) - open(wast_tempfile, 'w').write(form) + with open(wast_tempfile, 'w') as file: + file.write(form) log("Compiling WASM to '%s'" % wasm_tempfile) # default arguments @@ -1111,13 +1168,10 @@ def run_wasm_with_repl(wasm_tempfile, aot_tempfile, opts, r): def create_tmpfiles(wast_name): tempfiles = [] - (t1fd, wast_tempfile) = tempfile.mkstemp(suffix=".wast") - (t2fd, wasm_tempfile) = tempfile.mkstemp(suffix=".wasm") - tempfiles.append(wast_tempfile) - tempfiles.append(wasm_tempfile) + tempfiles.append(create_tmp_file(".wast")) + tempfiles.append(create_tmp_file(".wasm")) if test_aot: - (t3fd, aot_tempfile) = tempfile.mkstemp(suffix=".aot") - tempfiles.append(aot_tempfile) + tempfiles.append(create_tmp_file(".aot")) # add these temp file to temporal repo, will be deleted when finishing the test temp_file_repo.extend(tempfiles) @@ -1186,10 +1240,10 @@ if __name__ == "__main__": else: SKIP_TESTS = C_SKIP_TESTS - (t1fd, wast_tempfile) = tempfile.mkstemp(suffix=".wast") - (t2fd, wasm_tempfile) = tempfile.mkstemp(suffix=".wasm") + wast_tempfile = create_tmp_file(".wast") + wasm_tempfile = create_tmp_file(".wasm") if test_aot: - (t3fd, aot_tempfile) = tempfile.mkstemp(suffix=".aot") + aot_tempfile = create_tmp_file(".aot") ret_code = 0 try: @@ -1222,17 +1276,16 @@ if __name__ == "__main__": # workaround: spec test changes error message to "malformed" while iwasm still use "invalid" error_msg = m.group(2).replace("malformed", "invalid") log("Testing(malformed)") - f = open(wasm_tempfile, 'wb') - s = m.group(1) - while s: - res = re.match("[^\"]*\"([^\"]*)\"(.*)", s, re.DOTALL) - if IS_PY_3: - context = res.group(1).replace("\\", "\\x").encode("latin1").decode("unicode-escape").encode("latin1") - f.write(context) - else: - f.write(res.group(1).replace("\\", "\\x").decode("string-escape")) - s = res.group(2) - f.close() + with open(wasm_tempfile, 'wb') as f: + s = m.group(1) + while s: + res = re.match("[^\"]*\"([^\"]*)\"(.*)", s, re.DOTALL) + if IS_PY_3: + context = res.group(1).replace("\\", "\\x").encode("latin1").decode("unicode-escape").encode("latin1") + f.write(context) + else: + f.write(res.group(1).replace("\\", "\\x").decode("string-escape")) + s = res.group(2) # compile wasm to aot if test_aot: diff --git a/tests/wamr-test-suites/test_wamr.sh b/tests/wamr-test-suites/test_wamr.sh index 102c4ed5e..9c4b31b45 100755 --- a/tests/wamr-test-suites/test_wamr.sh +++ b/tests/wamr-test-suites/test_wamr.sh @@ -22,7 +22,6 @@ function help() echo "-S enable SIMD feature" echo "-G enable GC feature" echo "-X enable XIP feature" - # added to support WASM_ENABLE_EXCE_HANDLING echo "-e enable exception handling" echo "-x test SGX" echo "-w enable WASI threads" @@ -34,6 +33,7 @@ function help() echo "-F set the firmware path used by qemu" echo "-C enable code coverage collect" echo "-j set the platform to test" + echo "-T set sanitizer to use in tests(ubsan|tsan|asan)" } OPT_PARSED="" @@ -55,14 +55,20 @@ ENABLE_GC_HEAP_VERIFY=0 #unit test case arrary TEST_CASE_ARR=() SGX_OPT="" -PLATFORM=$(uname -s | tr A-Z a-z) +if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" ]]; then + PLATFORM=windows + PYTHON_EXE=python +else + PLATFORM=$(uname -s | tr A-Z a-z) + PYTHON_EXE=python3 +fi PARALLELISM=0 ENABLE_QEMU=0 QEMU_FIRMWARE="" # prod/testsuite-all branch WASI_TESTSUITE_COMMIT="ee807fc551978490bf1c277059aabfa1e589a6c2" -while getopts ":s:cabgvt:m:MCpSXexwPGQF:j:" opt +while getopts ":s:cabgvt:m:MCpSXexwPGQF:j:T:" opt do OPT_PARSED="TRUE" case $opt in @@ -172,9 +178,14 @@ do echo "test platform " ${OPTARG} PLATFORM=${OPTARG} ;; + T) + echo "sanitizer is " ${OPTARG} + WAMR_BUILD_SANITIZER=${OPTARG} + ;; ?) help - exit 1;; + exit 1 + ;; esac done @@ -331,15 +342,18 @@ function setup_wabt() darwin) WABT_PLATFORM=macos ;; + windows) + WABT_PLATFORM=windows + ;; *) echo "wabt platform for ${PLATFORM} in unknown" exit 1 ;; esac if [ ! -f /tmp/wabt-1.0.31-${WABT_PLATFORM}.tar.gz ]; then - wget \ + curl -L \ https://github.com/WebAssembly/wabt/releases/download/1.0.31/wabt-1.0.31-${WABT_PLATFORM}.tar.gz \ - -P /tmp + -o /tmp/wabt-1.0.31-${WABT_PLATFORM}.tar.gz fi cd /tmp \ @@ -494,12 +508,16 @@ function spec_test() ARGS_FOR_SPEC_TEST+="--qemu-firmware ${QEMU_FIRMWARE} " fi + if [[ ${PLATFORM} == "windows" ]]; then + ARGS_FOR_SPEC_TEST+="--no-pty " + fi + # set log directory ARGS_FOR_SPEC_TEST+="--log ${REPORT_DIR}" cd ${WORK_DIR} - echo "python3 ./all.py ${ARGS_FOR_SPEC_TEST} | tee -a ${REPORT_DIR}/spec_test_report.txt" - python3 ./all.py ${ARGS_FOR_SPEC_TEST} | tee -a ${REPORT_DIR}/spec_test_report.txt + echo "${PYTHON_EXE} ./all.py ${ARGS_FOR_SPEC_TEST} | tee -a ${REPORT_DIR}/spec_test_report.txt" + ${PYTHON_EXE} ./all.py ${ARGS_FOR_SPEC_TEST} | tee -a ${REPORT_DIR}/spec_test_report.txt if [[ ${PIPESTATUS[0]} -ne 0 ]];then echo -e "\nspec tests FAILED" | tee -a ${REPORT_DIR}/spec_test_report.txt exit 1 @@ -642,7 +660,7 @@ function wasi_certification_test() cd wasi-testsuite git reset --hard ${WASI_TESTSUITE_COMMIT} - bash ../../wasi-test-script/run_wasi_tests.sh $1 $TARGET \ + TSAN_OPTIONS=${TSAN_OPTIONS} bash ../../wasi-test-script/run_wasi_tests.sh $1 $TARGET $WASI_TEST_FILTER \ | tee -a ${REPORT_DIR}/wasi_test_report.txt ret=${PIPESTATUS[0]} @@ -772,7 +790,7 @@ function build_iwasm_with_cfg() && if [ -d build ]; then rm -rf build/*; else mkdir build; fi \ && cd build \ && cmake $* .. \ - && make -j 4 + && cmake --build . -j 4 --config RelWithDebInfo fi if [ "$?" != 0 ];then @@ -917,6 +935,17 @@ function trigger() EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_SANITIZER=tsan" fi + # Make sure we're using the builtin WASI libc implementation + # if we're running the wasi certification tests. + if [[ $TEST_CASE_ARR ]]; then + for test in "${TEST_CASE_ARR[@]}"; do + if [[ "$test" == "wasi_certification" ]]; then + EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_LIBC_UVWASI=0 -DWAMR_BUILD_LIBC_WASI=1" + break + fi + done + fi + for t in "${TYPE[@]}"; do case $t in "classic-interp") diff --git a/tests/wamr-test-suites/tsan_suppressions.txt b/tests/wamr-test-suites/tsan_suppressions.txt new file mode 100644 index 000000000..d79eafddc --- /dev/null +++ b/tests/wamr-test-suites/tsan_suppressions.txt @@ -0,0 +1,7 @@ +# Proposing to accept this risk for now. It might be wasi-libc related. +# https://github.com/bytecodealliance/wasm-micro-runtime/pull/1963#issuecomment-1455342931 +race:STORE_U32 + +# Suppressing signal-unsafe inside of a signal for AOT mode +# see https://github.com/bytecodealliance/wasm-micro-runtime/issues/2248#issuecomment-1630189656 +signal:* \ No newline at end of file diff --git a/tests/wamr-test-suites/wasi-test-script/run_wasi_tests.sh b/tests/wamr-test-suites/wasi-test-script/run_wasi_tests.sh index b8e3ddfec..4cfe6c29b 100755 --- a/tests/wamr-test-suites/wasi-test-script/run_wasi_tests.sh +++ b/tests/wamr-test-suites/wasi-test-script/run_wasi_tests.sh @@ -9,11 +9,25 @@ THIS_DIR=$(cd $(dirname $0) && pwd -P) readonly MODE=$1 readonly TARGET=$2 +readonly TEST_FILTER=$3 readonly WORK_DIR=$PWD -readonly PLATFORM=$(uname -s | tr A-Z a-z) + +if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" ]]; then + readonly PLATFORM=windows + readonly PYTHON_EXE=python + # see https://github.com/pypa/virtualenv/commit/993ba1316a83b760370f5a3872b3f5ef4dd904c1 + readonly VENV_BIN_DIR=Scripts + readonly IWASM_EXE=$(cygpath -m "${WORK_DIR}/../../../../product-mini/platforms/${PLATFORM}/build/RelWithDebInfo/iwasm.exe") +else + readonly PLATFORM=$(uname -s | tr A-Z a-z) + readonly VENV_BIN_DIR=bin + readonly PYTHON_EXE=python3 + readonly IWASM_EXE="${WORK_DIR}/../../../../product-mini/platforms/${PLATFORM}/build/iwasm" +fi + readonly WAMR_DIR="${WORK_DIR}/../../../.." -readonly IWASM_CMD="${WORK_DIR}/../../../../product-mini/platforms/${PLATFORM}/build/iwasm \ +readonly IWASM_CMD="${IWASM_EXE} \ --allow-resolve=google-public-dns-a.google.com \ --addr-pool=::1/128,127.0.0.1/32" @@ -28,8 +42,21 @@ readonly THREAD_STRESS_TESTS="${WAMR_DIR}/core/iwasm/libraries/lib-wasi-threads/ readonly LIB_SOCKET_TESTS="${WAMR_DIR}/core/iwasm/libraries/lib-socket/test/" run_aot_tests () { - local tests=("$@") + local -n tests=$1 + local -n excluded_tests=$2 + for test_wasm in ${tests[@]}; do + # get the base file name from the filepath + local test_name=${test_wasm##*/} + test_name=${test_name%.wasm} + + for excluded_test in "${excluded_tests[@]}"; do + if [[ $excluded_test == "\"$test_name\"" ]]; then + echo "Skipping test $test_name" + continue 2 + fi + done + local iwasm="${IWASM_CMD}" if [[ $test_wasm =~ "stress" ]]; then iwasm="${IWASM_CMD_STRESS}" @@ -37,7 +64,7 @@ run_aot_tests () { test_aot="${test_wasm%.wasm}.aot" test_json="${test_wasm%.wasm}.json" - + if [ -f ${test_wasm} ]; then expected=$(jq .exit_code ${test_json}) fi @@ -52,7 +79,7 @@ run_aot_tests () { expected=$(jq .exit_code ${test_json}) fi - python3 ${THIS_DIR}/pipe.py | ${iwasm} $test_aot + $PYTHON_EXE ${THIS_DIR}/pipe.py | ${iwasm} $test_aot ret=${PIPESTATUS[1]} echo "expected=$expected, actual=$ret" @@ -63,23 +90,29 @@ run_aot_tests () { } if [[ $MODE != "aot" ]];then - python3 -m venv wasi-env && source wasi-env/bin/activate - python3 -m pip install -r test-runner/requirements.txt + $PYTHON_EXE -m venv wasi-env && source wasi-env/${VENV_BIN_DIR}/activate + $PYTHON_EXE -m pip install -r test-runner/requirements.txt export TEST_RUNTIME_EXE="${IWASM_CMD}" - python3 ${THIS_DIR}/pipe.py | python3 test-runner/wasi_test_runner.py \ - -r adapters/wasm-micro-runtime.py \ - -t \ - ${C_TESTS} \ - ${RUST_TESTS} \ - ${ASSEMBLYSCRIPT_TESTS} \ - ${THREAD_PROPOSAL_TESTS} \ - ${THREAD_INTERNAL_TESTS} \ - ${LIB_SOCKET_TESTS} \ + + TEST_OPTIONS="-r adapters/wasm-micro-runtime.py \ + -t \ + ${C_TESTS} \ + ${RUST_TESTS} \ + ${ASSEMBLYSCRIPT_TESTS} \ + ${THREAD_PROPOSAL_TESTS} \ + ${THREAD_INTERNAL_TESTS} \ + ${LIB_SOCKET_TESTS}" + + if [ -n "$TEST_FILTER" ]; then + TEST_OPTIONS="${TEST_OPTIONS} --exclude-filter ${TEST_FILTER}" + fi + + $PYTHON_EXE ${THIS_DIR}/pipe.py | TSAN_OPTIONS=${TSAN_OPTIONS} $PYTHON_EXE test-runner/wasi_test_runner.py $TEST_OPTIONS ret=${PIPESTATUS[1]} - TEST_RUNTIME_EXE="${IWASM_CMD_STRESS}" python3 test-runner/wasi_test_runner.py \ + TEST_RUNTIME_EXE="${IWASM_CMD_STRESS}" TSAN_OPTIONS=${TSAN_OPTIONS} $PYTHON_EXE test-runner/wasi_test_runner.py \ -r adapters/wasm-micro-runtime.py \ -t \ ${THREAD_STRESS_TESTS} @@ -87,9 +120,9 @@ if [[ $MODE != "aot" ]];then if [ "${ret}" -eq 0 ]; then ret=${PIPESTATUS[0]} fi - + exit_code=${ret} - + deactivate else target_option="" @@ -101,7 +134,17 @@ else for testsuite in ${THREAD_STRESS_TESTS} ${THREAD_PROPOSAL_TESTS} ${THREAD_INTERNAL_TESTS}; do tests=$(ls ${testsuite}*.wasm) tests_array=($tests) - run_aot_tests "${tests_array[@]}" + + if [ -n "$TEST_FILTER" ]; then + readarray -t excluded_tests_array < <(jq -c \ + --slurpfile testsuite_manifest $testsuite/manifest.json \ + '.[$testsuite_manifest[0].name] // {} | keys[]' \ + $TEST_FILTER) + else + excluded_tests_array=() + fi + + run_aot_tests tests_array excluded_tests_array done fi diff --git a/wamr-compiler/CMakeLists.txt b/wamr-compiler/CMakeLists.txt index ba0902cdf..5fe8fae16 100644 --- a/wamr-compiler/CMakeLists.txt +++ b/wamr-compiler/CMakeLists.txt @@ -198,6 +198,12 @@ include_directories (${SHARED_DIR}/include enable_language (ASM) +if (NOT MINGW AND NOT MSVC) + set(WAMR_BUILD_LIBC_WASI 1) +else() + set(WAMR_BUILD_LIBC_UVWASI 1) +endif() + include (${SHARED_DIR}/platform/${WAMR_BUILD_PLATFORM}/shared_platform.cmake) include (${SHARED_DIR}/mem-alloc/mem_alloc.cmake) include (${SHARED_DIR}/utils/shared_utils.cmake)