Repository: tetratelabs/wazero
Pull request #1101 (2023-02-06 03:09:08)

wasi: makes fd_advise noop, instead of NoSys
part of #1036. `fd_advise.rs` is still failing due to the unimplemented `fd_allocate`. https://github.com/WebAssembly/wasi-testsuite/blob/main/tests/rust/src/bin/fd_advise.rs#L44-L50


Patch:
diff --git a/imports/wasi_snapshot_preview1/fs.go b/imports/wasi_snapshot_preview1/fs.go
index b8168fd0..2f4ab0a1 100644
--- a/imports/wasi_snapshot_preview1/fs.go
+++ b/imports/wasi_snapshot_preview1/fs.go
@@ -24,12 +24,45 @@ import (
 // advisory information on a file descriptor.
 //
 // See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_advisefd-fd-offset-filesize-len-filesize-advice-advice---errno
-var fdAdvise = stubFunction(
-	FdAdviseName,
+var fdAdvise = newHostFunc(
+	FdAdviseName, fdAdviseFn,
 	[]wasm.ValueType{i32, i64, i64, i32},
 	"fd", "offset", "len", "advice",
 )
 
+func fdAdviseFn(_ context.Context, mod api.Module, params []uint64) Errno {
+	fd := uint32(params[0])
+	_ = params[1]
+	_ = params[2]
+	advice := byte(params[3])
+	fsc := mod.(*wasm.CallContext).Sys.FS()
+
+	_, ok := fsc.LookupFile(fd)
+	if !ok {
+		return ErrnoBadf
+	}
+
+	switch advice {
+	case FdAdviceNormal,
+		FdAdviceSequential,
+		FdAdviceRandom,
+		FdAdviceWillNeed,
+		FdAdviceDontNeed,
+		FdAdviceNoReuse:
+	default:
+		return ErrnoInval
+	}
+
+	// FdAdvice corresponds to posix_fadvise, but it can only be supported on linux.
+	// However, the purpose of the call is just to do best-effort optimization on OS kernels,
+	// so just making this noop rather than returning NoSup error makes sense and doesn't affect
+	// the semantics of Wasm applications.
+	// TODO: invoke posix_fadvise on linux, and partially on darwin.
+	// - https://gitlab.com/cznic/fileutil/-/blob/v1.1.2/fileutil_linux.go#L87-95
+	// - https://github.com/bytecodealliance/system-interface/blob/62b97f9776b86235f318c3a6e308395a1187439b/src/fs/file_io_ext.rs#L430-L442
+	return ErrnoSuccess
+}
+
 // fdAllocate is the WASI function named FdAllocateName which forces the
 // allocation of space in a file.
 //
diff --git a/internal/wasi_snapshot_preview1/fs.go b/internal/wasi_snapshot_preview1/fs.go
index b5990ca8..ede6d38a 100644
--- a/internal/wasi_snapshot_preview1/fs.go
+++ b/internal/wasi_snapshot_preview1/fs.go
@@ -141,3 +141,13 @@ const (
 	FileStatAdjustFlagsMtim
 	FileStatAdjustFlagsMtimNow
 )
+
+// https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-advice-enumu8
+const (
+	FdAdviceNormal byte = iota
+	FdAdviceSequential
+	FdAdviceRandom
+	FdAdviceWillNeed
+	FdAdviceDontNeed
+	FdAdviceNoReuse
+)


Test patch:
diff --git a/imports/wasi_snapshot_preview1/fs_test.go b/imports/wasi_snapshot_preview1/fs_test.go
index e1147d53..78e48937 100644
--- a/imports/wasi_snapshot_preview1/fs_test.go
+++ b/imports/wasi_snapshot_preview1/fs_test.go
@@ -24,13 +24,17 @@ import (
 	"github.com/tetratelabs/wazero/internal/wasm"
 )
 
-// Test_fdAdvise only tests it is stubbed for GrainLang per #271
 func Test_fdAdvise(t *testing.T) {
-	log := requireErrnoNosys(t, FdAdviseName, 0, 0, 0, 0)
-	require.Equal(t, `
---> wasi_snapshot_preview1.fd_advise(fd=0,offset=0,len=0,advice=0)
-<-- errno=ENOSYS
-`, log)
+	mod, r, _ := requireProxyModule(t, wazero.NewModuleConfig().WithFS(fstest.FS))
+	defer r.Close(testCtx)
+	requireErrno(t, ErrnoSuccess, mod, FdAdviseName, uint64(3), 0, 0, uint64(FdAdviceNormal))
+	requireErrno(t, ErrnoSuccess, mod, FdAdviseName, uint64(3), 0, 0, uint64(FdAdviceSequential))
+	requireErrno(t, ErrnoSuccess, mod, FdAdviseName, uint64(3), 0, 0, uint64(FdAdviceRandom))
+	requireErrno(t, ErrnoSuccess, mod, FdAdviseName, uint64(3), 0, 0, uint64(FdAdviceWillNeed))
+	requireErrno(t, ErrnoSuccess, mod, FdAdviseName, uint64(3), 0, 0, uint64(FdAdviceDontNeed))
+	requireErrno(t, ErrnoSuccess, mod, FdAdviseName, uint64(3), 0, 0, uint64(FdAdviceNoReuse))
+	requireErrno(t, ErrnoInval, mod, FdAdviseName, uint64(3), 0, 0, uint64(FdAdviceNoReuse+1))
+	requireErrno(t, ErrnoBadf, mod, FdAdviseName, uint64(1111111), 0, 0, uint64(FdAdviceNoReuse+1))
 }
 
 // Test_fdAllocate only tests it is stubbed for GrainLang per #271
@@ -2096,7 +2100,6 @@ func Test_fdReaddir_Errors(t *testing.T) {
 	}
 }
 
-// Test_fdRenumber only tests it is stubbed for GrainLang per #271
 func Test_fdRenumber(t *testing.T) {
 	const preopenFd, fileFd, dirFd = 3, 4, 5