From 292518de50291fac5be55f281245ed634137a13b Mon Sep 17 00:00:00 2001 From: M-SE0K Date: Tue, 7 Apr 2026 23:12:38 +0900 Subject: [PATCH 1/4] Implement fd_datasync WASI function and test for it Signed-off-by: M-SE0K --- src/wasi/WASI.cpp | 5 +++ src/wasi/WASI.h | 1 + test/wasi/fd_datasync.wast | 81 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100644 test/wasi/fd_datasync.wast diff --git a/src/wasi/WASI.cpp b/src/wasi/WASI.cpp index d935be7a2..4204b32ea 100644 --- a/src/wasi/WASI.cpp +++ b/src/wasi/WASI.cpp @@ -285,7 +285,12 @@ void WASI::fd_close(ExecutionState& state, Value* argv, Value* result, Instance* result[0] = Value(uvwasi_fd_close(WASI::g_uvwasi, fd)); } +void WASI::fd_datasync(ExecutionState& state, Value* argv, Value* result, Instance* instance) +{ + uint32_t fd = argv[0].asI32(); + result[0] = Value(uvwasi_fd_datasync(WASI::g_uvwasi, fd)); +} void WASI::fd_fdstat_get(ExecutionState& state, Value* argv, Value* result, Instance* instance) { uint32_t fd = argv[0].asI32(); diff --git a/src/wasi/WASI.h b/src/wasi/WASI.h index 00e0a73a2..c1c051e6f 100644 --- a/src/wasi/WASI.h +++ b/src/wasi/WASI.h @@ -49,6 +49,7 @@ class WASI { F(fd_pread, I32I32I32I64I32_RI32) \ F(fd_readdir, I32I32I32I64I32_RI32) \ F(fd_close, I32_RI32) \ + F(fd_datasync, I32_RI32) \ F(fd_fdstat_get, I32I32_RI32) \ F(fd_fdstat_set_flags, I32I32_RI32) \ F(fd_prestat_get, I32I32_RI32) \ diff --git a/test/wasi/fd_datasync.wast b/test/wasi/fd_datasync.wast new file mode 100644 index 000000000..6caa49fb1 --- /dev/null +++ b/test/wasi/fd_datasync.wast @@ -0,0 +1,81 @@ +(module + (import "wasi_snapshot_preview1" "path_open" + (func $path_open (param i32 i32 i32 i32 i32 i64 i64 i32 i32) (result i32))) + (import "wasi_snapshot_preview1" "fd_write" + (func $fd_write (param i32 i32 i32 i32) (result i32))) + (import "wasi_snapshot_preview1" "fd_datasync" + (func $fd_datasync (param i32) (result i32))) + (import "wasi_snapshot_preview1" "fd_close" + (func $fd_close (param i32) (result i32))) + + (memory 1) + (data (i32.const 200) "datasync test\n") ;; 14 bytes, written to file + (data (i32.const 300) "./write_to_this.txt") ;; 19 bytes, file path + + ;; Open file, write data, call fd_datasync, close. Returns errno of fd_datasync. + (func (export "test_datasync") (result i32) + ;; --- path_open --- + ;; fd=3 (first preopened dir), lookupflags=1, path@300 len=19 + ;; oflags=9 (creat|trunc), rights=8257 (path_open|fd_write|fd_datasync) + i32.const 3 + i32.const 1 + i32.const 300 + i32.const 19 + i32.const 9 + i64.const 8257 ;; fd_datasync(1) | fd_write(64) | path_open(8192) + i64.const 8257 + i32.const 0 + i32.const 0 ;; store opened fd at memory[0] + call $path_open + i32.eqz + (if (then) (else i32.const 1 return)) ;; abort if open failed + + ;; --- set up iovec at offset 500: (buf=200, len=14) --- + i32.const 500 + i32.const 200 + i32.store + i32.const 504 + i32.const 14 + i32.store + + ;; --- fd_write --- + i32.const 0 + i32.load ;; fd + i32.const 500 ;; iovec array + i32.const 1 ;; iovec count + i32.const 600 ;; nwritten output + call $fd_write + drop + + ;; --- fd_datasync: test target --- + i32.const 0 + i32.load ;; fd + call $fd_datasync + ;; stash errno at memory[700] so we can close before returning + i32.const 700 + i32.store + + ;; --- fd_close --- + i32.const 0 + i32.load + call $fd_close + drop + + i32.const 700 + i32.load ;; return stashed errno + ) + + ;; Call fd_datasync with an invalid fd. Expects errno::badf (8). + (func (export "test_datasync_invalid_fd") (result i32) + i32.const 99 ;; non-existent fd + call $fd_datasync + ) + + (export "memory" (memory 0)) +) + +;; Valid fd: fd_datasync should succeed (errno::success = 0) +(assert_return (invoke "test_datasync") (i32.const 0)) + +;; Invalid fd: should return errno::badf (8) +(assert_return (invoke "test_datasync_invalid_fd") (i32.const 8)) From f6b4c5f22218140da6ab3017326900f47d06ba42 Mon Sep 17 00:00:00 2001 From: M-SE0K Date: Wed, 8 Apr 2026 00:27:53 +0900 Subject: [PATCH 2/4] Implement fd_sync WASI function and test for it Signed-off-by: M-SE0K --- src/wasi/WASI.cpp | 8 ++++- src/wasi/WASI.h | 3 +- test/wasi/fd_sync.wast | 79 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 test/wasi/fd_sync.wast diff --git a/src/wasi/WASI.cpp b/src/wasi/WASI.cpp index 4204b32ea..2027574d1 100644 --- a/src/wasi/WASI.cpp +++ b/src/wasi/WASI.cpp @@ -290,7 +290,13 @@ void WASI::fd_datasync(ExecutionState& state, Value* argv, Value* result, Instan uint32_t fd = argv[0].asI32(); result[0] = Value(uvwasi_fd_datasync(WASI::g_uvwasi, fd)); -} +} +void WASI::fd_sync(ExecutionState& state, Value* argv, Value* result, Instance* instance) +{ + uint32_t fd = argv[0].asI32(); + + result[0] = Value(uvwasi_fd_sync(WASI::g_uvwasi, fd)); +} void WASI::fd_fdstat_get(ExecutionState& state, Value* argv, Value* result, Instance* instance) { uint32_t fd = argv[0].asI32(); diff --git a/src/wasi/WASI.h b/src/wasi/WASI.h index c1c051e6f..91c052c00 100644 --- a/src/wasi/WASI.h +++ b/src/wasi/WASI.h @@ -49,7 +49,8 @@ class WASI { F(fd_pread, I32I32I32I64I32_RI32) \ F(fd_readdir, I32I32I32I64I32_RI32) \ F(fd_close, I32_RI32) \ - F(fd_datasync, I32_RI32) \ + F(fd_datasync, I32_RI32) \ + F(fd_sync, I32_RI32) \ F(fd_fdstat_get, I32I32_RI32) \ F(fd_fdstat_set_flags, I32I32_RI32) \ F(fd_prestat_get, I32I32_RI32) \ diff --git a/test/wasi/fd_sync.wast b/test/wasi/fd_sync.wast new file mode 100644 index 000000000..ab123438a --- /dev/null +++ b/test/wasi/fd_sync.wast @@ -0,0 +1,79 @@ +(module + (import "wasi_snapshot_preview1" "path_open" + (func $path_open (param i32 i32 i32 i32 i32 i64 i64 i32 i32) (result i32))) + (import "wasi_snapshot_preview1" "fd_write" + (func $fd_write (param i32 i32 i32 i32) (result i32))) + (import "wasi_snapshot_preview1" "fd_sync" + (func $fd_sync (param i32) (result i32))) + (import "wasi_snapshot_preview1" "fd_close" + (func $fd_close (param i32) (result i32))) + + (memory 1) + (data (i32.const 200) "fd_sync test\n") ;; 13 bytes, written to file + (data (i32.const 300) "./write_to_this.txt") ;; 19 bytes, file path + + ;; Open file, write data, call fd_sync, close. Returns errno of fd_sync. + (func (export "test_sync") (result i32) + ;; --- path_open --- + i32.const 3 + i32.const 1 + i32.const 300 + i32.const 19 + i32.const 9 ;; oflags: creat|trunc + i64.const 8320 ;; fd_sync(64) | fd_write(64) | path_open(8192) = 8320 + i64.const 8320 + i32.const 0 + i32.const 0 ;; store opened fd at memory[0] + call $path_open + i32.eqz + (if (then) (else i32.const 1 return)) ;; abort if open failed + + ;; --- set up iovec at offset 500: (buf=200, len=13) --- + i32.const 500 + i32.const 200 + i32.store + i32.const 504 + i32.const 13 + i32.store + + ;; --- fd_write --- + i32.const 0 + i32.load ;; fd + i32.const 500 ;; iovec array + i32.const 1 ;; iovec count + i32.const 600 ;; nwritten output + call $fd_write + drop + + ;; --- fd_sync: test target --- + i32.const 0 + i32.load ;; fd + call $fd_sync + ;; stash errno at memory[700] so we can close before returning + i32.const 700 + i32.store + + ;; --- fd_close --- + i32.const 0 + i32.load + call $fd_close + drop + + i32.const 700 + i32.load ;; return stashed errno + ) + + ;; Call fd_sync with an invalid fd. Expects errno::badf (8). + (func (export "test_sync_invalid_fd") (result i32) + i32.const 99 ;; non-existent fd + call $fd_sync + ) + + (export "memory" (memory 0)) +) + +;; Valid fd: fd_sync should succeed (errno::success = 0) +(assert_return (invoke "test_sync") (i32.const 0)) + +;; Invalid fd: should return errno::badf (8) +(assert_return (invoke "test_sync_invalid_fd") (i32.const 8)) From d985217bf426cf6ee81a4c4442be7332492a3e97 Mon Sep 17 00:00:00 2001 From: M-SE0K Date: Wed, 8 Apr 2026 00:50:52 +0900 Subject: [PATCH 3/4] Implement fd_renumber WASI function and test for it Signed-off-by: M-SE0K --- src/wasi/WASI.cpp | 7 +++ src/wasi/WASI.h | 1 + test/wasi/fd_renumber.wast | 91 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+) create mode 100644 test/wasi/fd_renumber.wast diff --git a/src/wasi/WASI.cpp b/src/wasi/WASI.cpp index 2027574d1..c3e6a7dea 100644 --- a/src/wasi/WASI.cpp +++ b/src/wasi/WASI.cpp @@ -297,6 +297,13 @@ void WASI::fd_sync(ExecutionState& state, Value* argv, Value* result, Instance* result[0] = Value(uvwasi_fd_sync(WASI::g_uvwasi, fd)); } +void WASI::fd_renumber(ExecutionState& state, Value* argv, Value* result, Instance* instance) +{ + uint32_t from = argv[0].asI32(); + uint32_t to = argv[1].asI32(); + + result[0] = Value(uvwasi_fd_renumber(WASI::g_uvwasi, from, to)); +} void WASI::fd_fdstat_get(ExecutionState& state, Value* argv, Value* result, Instance* instance) { uint32_t fd = argv[0].asI32(); diff --git a/src/wasi/WASI.h b/src/wasi/WASI.h index 91c052c00..14235ac38 100644 --- a/src/wasi/WASI.h +++ b/src/wasi/WASI.h @@ -51,6 +51,7 @@ class WASI { F(fd_close, I32_RI32) \ F(fd_datasync, I32_RI32) \ F(fd_sync, I32_RI32) \ + F(fd_renumber, I32I32_RI32) \ F(fd_fdstat_get, I32I32_RI32) \ F(fd_fdstat_set_flags, I32I32_RI32) \ F(fd_prestat_get, I32I32_RI32) \ diff --git a/test/wasi/fd_renumber.wast b/test/wasi/fd_renumber.wast new file mode 100644 index 000000000..77c9f023d --- /dev/null +++ b/test/wasi/fd_renumber.wast @@ -0,0 +1,91 @@ +(module + (import "wasi_snapshot_preview1" "path_open" + (func $path_open (param i32 i32 i32 i32 i32 i64 i64 i32 i32) (result i32))) + (import "wasi_snapshot_preview1" "fd_write" + (func $fd_write (param i32 i32 i32 i32) (result i32))) + (import "wasi_snapshot_preview1" "fd_renumber" + (func $fd_renumber (param i32 i32) (result i32))) + (import "wasi_snapshot_preview1" "fd_close" + (func $fd_close (param i32) (result i32))) + + (memory 1) + (data (i32.const 200) "renumber test\n") ;; 14 bytes, written to file + (data (i32.const 300) "./write_to_this.txt") ;; 19 bytes, file path + + ;; Set up iovec at offset 500: (buf=200, len=14) + (func $setup_iovec + i32.const 500 + i32.const 200 + i32.store + i32.const 504 + i32.const 14 + i32.store + ) + + ;; Open write_to_this.txt and store fd at memory[offset]. + (func $open_file (param $fd_offset i32) (result i32) + i32.const 3 + i32.const 1 + i32.const 300 + i32.const 19 + i32.const 9 ;; oflags: creat|trunc + i64.const 8320 ;; fd_write | path_open + i64.const 8320 + i32.const 0 + local.get $fd_offset + call $path_open + ) + + ;; Open file (fd stored at memory[0] = "from"), + ;; renumber it to fd 10 ("to"), + ;; write using fd 10 to confirm it works. + ;; Returns errno of fd_renumber. + (func (export "test_renumber") (result i32) + ;; open file → fd at memory[0] + i32.const 0 + call $open_file + i32.eqz + (if (then) (else i32.const 1 return)) + + call $setup_iovec + + ;; fd_renumber(from=memory[0], to=10) + i32.const 0 + i32.load ;; from fd + i32.const 10 ;; to fd number + call $fd_renumber + i32.const 700 + i32.store ;; stash errno + + ;; write via new fd (10) to confirm renumber worked + i32.const 10 ;; to fd + i32.const 500 + i32.const 1 + i32.const 600 + call $fd_write + drop + + ;; close new fd + i32.const 10 + call $fd_close + drop + + i32.const 700 + i32.load ;; return stashed errno of fd_renumber + ) + + ;; fd_renumber with an invalid "from" fd. Expects errno::badf (8). + (func (export "test_renumber_invalid_fd") (result i32) + i32.const 99 ;; non-existent from fd + i32.const 10 + call $fd_renumber + ) + + (export "memory" (memory 0)) +) + +;; fd_renumber succeeds (errno::success = 0) +(assert_return (invoke "test_renumber") (i32.const 0)) + +;; invalid from fd returns errno::badf (8) +(assert_return (invoke "test_renumber_invalid_fd") (i32.const 8)) From 8d90b7b8458fd713b7929e88acf21396cd4c48af Mon Sep 17 00:00:00 2001 From: M-SE0K Date: Thu, 9 Apr 2026 03:25:48 +0900 Subject: [PATCH 4/4] Fix: incorrect rights value in fd_sync.wast, fd_renumber.wast Signed-off-by: M-SE0K --- src/wasi/WASI.cpp | 4 ++++ test/wasi/fd_renumber.wast | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/wasi/WASI.cpp b/src/wasi/WASI.cpp index c3e6a7dea..c154b29af 100644 --- a/src/wasi/WASI.cpp +++ b/src/wasi/WASI.cpp @@ -285,18 +285,21 @@ void WASI::fd_close(ExecutionState& state, Value* argv, Value* result, Instance* result[0] = Value(uvwasi_fd_close(WASI::g_uvwasi, fd)); } + void WASI::fd_datasync(ExecutionState& state, Value* argv, Value* result, Instance* instance) { uint32_t fd = argv[0].asI32(); result[0] = Value(uvwasi_fd_datasync(WASI::g_uvwasi, fd)); } + void WASI::fd_sync(ExecutionState& state, Value* argv, Value* result, Instance* instance) { uint32_t fd = argv[0].asI32(); result[0] = Value(uvwasi_fd_sync(WASI::g_uvwasi, fd)); } + void WASI::fd_renumber(ExecutionState& state, Value* argv, Value* result, Instance* instance) { uint32_t from = argv[0].asI32(); @@ -304,6 +307,7 @@ void WASI::fd_renumber(ExecutionState& state, Value* argv, Value* result, Instan result[0] = Value(uvwasi_fd_renumber(WASI::g_uvwasi, from, to)); } + void WASI::fd_fdstat_get(ExecutionState& state, Value* argv, Value* result, Instance* instance) { uint32_t fd = argv[0].asI32(); diff --git a/test/wasi/fd_renumber.wast b/test/wasi/fd_renumber.wast index 77c9f023d..342ada95b 100644 --- a/test/wasi/fd_renumber.wast +++ b/test/wasi/fd_renumber.wast @@ -29,8 +29,8 @@ i32.const 300 i32.const 19 i32.const 9 ;; oflags: creat|trunc - i64.const 8320 ;; fd_write | path_open - i64.const 8320 + i64.const 8256 ;; fd_write | path_open + i64.const 8256 i32.const 0 local.get $fd_offset call $path_open