Removes redundant error handling (#668)

This consolidates to use EBADF in places go uses it in syscalls to
reduce where we formally returned both bool and err. This also removes
the redundant panic type handling as go will already panic with a
similar message.

Signed-off-by: Adrian Cole <adrian@tetrate.io>
This commit is contained in:
Crypt Keeper
2022-06-30 07:33:24 +08:00
committed by GitHub
parent 8688f3fcb4
commit fe1cde140d
16 changed files with 103 additions and 172 deletions

View File

@@ -27,7 +27,6 @@ import (
"github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/internal/ieee754"
internalsys "github.com/tetratelabs/wazero/internal/sys"
"github.com/tetratelabs/wazero/internal/wasm"
)
@@ -156,7 +155,7 @@ func (a *assemblyscript) abort(
columnNumber uint32,
) {
if !a.abortMessageDisabled {
sysCtx := getSysCtx(mod)
sysCtx := mod.(*wasm.CallContext).Sys
msg, err := readAssemblyScriptString(ctx, mod, message)
if err != nil {
return
@@ -184,9 +183,9 @@ func (a *assemblyscript) trace(
case traceDisabled:
return
case traceStdout:
writer = getSysCtx(mod).Stdout()
writer = mod.(*wasm.CallContext).Sys.Stdout()
case traceStderr:
writer = getSysCtx(mod).Stderr()
writer = mod.(*wasm.CallContext).Sys.Stderr()
}
msg, err := readAssemblyScriptString(ctx, mod, message)
@@ -234,10 +233,10 @@ func formatFloat(f float64) string {
//
// See https://github.com/AssemblyScript/assemblyscript/blob/fa14b3b03bd4607efa52aaff3132bea0c03a7989/std/assembly/wasi/index.ts#L111
func (a *assemblyscript) seed(mod api.Module) float64 {
randSource := getSysCtx(mod).RandSource()
randSource := mod.(*wasm.CallContext).Sys.RandSource()
v, err := ieee754.DecodeFloat64(randSource)
if err != nil {
panic(fmt.Errorf("error reading Module.RandSource: %w", err))
panic(fmt.Errorf("error reading random seed: %w", err))
}
return v
}
@@ -269,11 +268,3 @@ func decodeUTF16(b []byte) string {
return string(utf16.Decode(u16s))
}
func getSysCtx(mod api.Module) *internalsys.Context {
if internal, ok := mod.(*wasm.CallContext); !ok {
panic(fmt.Errorf("unsupported wasm.Module implementation: %v", mod))
} else {
return internal.Sys
}
}

View File

@@ -371,14 +371,14 @@ func TestSeed_error(t *testing.T) {
{
name: "not 8 bytes",
source: bytes.NewReader([]byte{0, 1}),
expectedErr: `error reading Module.RandSource: unexpected EOF (recovered by wazero)
expectedErr: `error reading random seed: unexpected EOF (recovered by wazero)
wasm stack trace:
env.seed() f64`,
},
{
name: "error reading",
source: iotest.ErrReader(errors.New("ice cream")),
expectedErr: `error reading Module.RandSource: ice cream (recovered by wazero)
expectedErr: `error reading random seed: ice cream (recovered by wazero)
wasm stack trace:
env.seed() f64`,
},

View File

@@ -281,10 +281,7 @@ func (b *moduleBuilder) ExportGlobalF64(name string, v float64) ModuleBuilder {
// Compile implements ModuleBuilder.Compile
func (b *moduleBuilder) Compile(ctx context.Context, cConfig CompileConfig) (CompiledModule, error) {
config, ok := cConfig.(*compileConfig)
if !ok {
panic(fmt.Errorf("unsupported wazero.CompileConfig implementation: %#v", cConfig))
}
config := cConfig.(*compileConfig)
// Verify the maximum limit here, so we don't have to pass it to wasm.NewHostModule
for name, mem := range b.nameToMemory {

View File

@@ -57,7 +57,7 @@ func Example_withFS() {
// Try to read the path!
if path, ok := mod.Memory().Read(ctx, uint32(pathOffset), uint32(pathLen)); !ok {
log.Panicf("Memory.Read(%d,%d) out of range of memory size %d", pathOffset, pathLen, mod.Memory().Size(ctx))
log.Panicln("out of memory reading path")
} else {
fmt.Println(string(path))
}

View File

@@ -70,7 +70,7 @@ func (r *wazeroRuntime) Name() string {
func (r *wazeroRuntime) log(ctx context.Context, m api.Module, offset, byteCount uint32) {
buf, ok := m.Memory().Read(ctx, offset, byteCount)
if !ok {
panic(fmt.Errorf("Memory.Read(%d, %d) out of range", offset, byteCount))
panic("out of memory reading log buffer")
}
if err := r.logFn(buf); err != nil {
panic(err)

View File

@@ -2,10 +2,17 @@ package sys
import (
"context"
"errors"
"io"
"io/fs"
"math"
"sync/atomic"
"syscall"
)
const (
FdStdin = iota
FdStdout
FdStderr
)
// FSKey is a context.Context Value key. It allows overriding fs.FS for WASI.
@@ -81,7 +88,7 @@ func (c *FSContext) nextFD() uint32 {
return atomic.AddUint32(&c.lastFD, 1)
}
// OpenedFile returns a file and true if it was opened or nil and false, if not.
// OpenedFile returns a file and true if it was opened or nil and false, if syscall.EBADF.
func (c *FSContext) OpenedFile(_ context.Context, fd uint32) (*FileEntry, bool) {
f, ok := c.openedFiles[fd]
return f, ok
@@ -107,27 +114,27 @@ func (c *FSContext) OpenFile(_ context.Context, name string /* TODO: flags int,
newFD := c.nextFD()
if newFD == 0 {
_ = f.Close()
return 0, &fs.PathError{Op: "open", Path: name, Err: errors.New("out of file descriptors")}
return 0, syscall.EBADF
}
c.openedFiles[newFD] = &FileEntry{Path: name, File: f}
return newFD, nil
}
// CloseFile returns true if a file was opened and closed without error, or false if not.
func (c *FSContext) CloseFile(_ context.Context, fd uint32) (bool, error) {
// CloseFile returns true if a file was opened and closed without error, or false if syscall.EBADF.
func (c *FSContext) CloseFile(_ context.Context, fd uint32) bool {
f, ok := c.openedFiles[fd]
if !ok {
return false, nil
return false
}
delete(c.openedFiles, fd)
if f.File == nil { // TODO: currently, this means it is a pre-opened filesystem, but this may change later.
return true, nil
if f.File == nil { // The root entry
return true
}
if err := f.File.Close(); err != nil {
return false, err
return false
}
return true, nil
return true
}
// Close implements io.Closer
@@ -143,3 +150,34 @@ func (c *FSContext) Close(_ context.Context) (err error) {
}
return
}
// FdWriter returns a valid writer for the given file descriptor or nil if syscall.EBADF.
func FdWriter(ctx context.Context, sysCtx *Context, fd uint32) io.Writer {
switch fd {
case FdStdout:
return sysCtx.Stdout()
case FdStderr:
return sysCtx.Stderr()
default:
// Check to see if the file descriptor is available
if f, ok := sysCtx.FS(ctx).OpenedFile(ctx, fd); !ok || f.File == nil {
return nil
} else if writer, ok := f.File.(io.Writer); !ok {
// Go's syscall.Write also returns EBADF if the FD is present, but not writeable
return nil
} else {
return writer
}
}
}
// FdReader returns a valid reader for the given file descriptor or nil if syscall.EBADF.
func FdReader(ctx context.Context, sysCtx *Context, fd uint32) io.Reader {
if fd == FdStdin {
return sysCtx.Stdin()
} else if f, ok := sysCtx.FS(ctx).OpenedFile(ctx, fd); !ok {
return nil
} else {
return f.File
}
}

View File

@@ -113,11 +113,7 @@ func (c *Context) Nanosleep(ctx context.Context, ns int64) {
func (c *Context) FS(ctx context.Context) *FSContext {
// Override Context when it is passed via context
if fsValue := ctx.Value(FSKey{}); fsValue != nil {
fsCtx, ok := fsValue.(*FSContext)
if !ok {
panic(fmt.Errorf("unsupported fs key: %v", fsValue))
}
return fsCtx
return fsValue.(*FSContext)
}
return c.fsc
}

View File

@@ -13,9 +13,9 @@ import (
// compile time check to ensure CallContext implements api.Module
var _ api.Module = &CallContext{}
func NewCallContext(ns *Namespace, instance *ModuleInstance, Sys *internalsys.Context) *CallContext {
func NewCallContext(ns *Namespace, instance *ModuleInstance, sys *internalsys.Context) *CallContext {
zero := uint64(0)
return &CallContext{memory: instance.Memory, module: instance, ns: ns, Sys: Sys, closed: &zero}
return &CallContext{memory: instance.Memory, module: instance, ns: ns, Sys: sys, closed: &zero}
}
// CallContext is a function call context bound to a module. This is important as one module's functions can call

View File

@@ -67,15 +67,8 @@ func (ns *namespace) InstantiateModule(
compiled CompiledModule,
mConfig ModuleConfig,
) (mod api.Module, err error) {
code, ok := compiled.(*compiledModule)
if !ok {
panic(fmt.Errorf("unsupported wazero.CompiledModule implementation: %#v", compiled))
}
config, ok := mConfig.(*moduleConfig)
if !ok {
panic(fmt.Errorf("unsupported wazero.ModuleConfig implementation: %#v", mConfig))
}
code := compiled.(*compiledModule)
config := mConfig.(*moduleConfig)
var sysCtx *internalsys.Context
if sysCtx, err = config.toSysContext(); err != nil {
@@ -117,7 +110,7 @@ func (ns *namespace) InstantiateModule(
}
if _, err = start.Call(ctx); err != nil {
_ = mod.Close(ctx) // Don't leak the module on error.
if _, ok = err.(*sys.ExitError); ok {
if _, ok := err.(*sys.ExitError); ok {
return // Don't wrap an exit error
}
err = fmt.Errorf("module[%s] function[%s] failed: %w", name, fn, err)

View File

@@ -4,7 +4,6 @@ import (
"bytes"
"context"
"errors"
"fmt"
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/internal/wasm"
@@ -125,10 +124,7 @@ func NewRuntime() Runtime {
// NewRuntimeWithConfig returns a runtime with the given configuration.
func NewRuntimeWithConfig(rConfig RuntimeConfig) Runtime {
config, ok := rConfig.(*runtimeConfig)
if !ok {
panic(fmt.Errorf("unsupported wazero.RuntimeConfig implementation: %#v", rConfig))
}
config := rConfig.(*runtimeConfig)
store, ns := wasm.NewStore(config.enabledFeatures, config.newEngine(config.enabledFeatures))
return &runtime{
store: store,
@@ -164,11 +160,7 @@ func (r *runtime) CompileModule(ctx context.Context, binary []byte, cConfig Comp
return nil, errors.New("binary == nil")
}
config, ok := cConfig.(*compileConfig)
if !ok {
panic(fmt.Errorf("unsupported wazero.CompileConfig implementation: %#v", cConfig))
}
config := cConfig.(*compileConfig)
if len(binary) < 4 || !bytes.Equal(binary[0:4], binaryformat.Magic) {
return nil, errors.New("invalid binary")
}

View File

@@ -23,16 +23,6 @@ var (
zero = wasm.Index(0)
)
func TestNewRuntimeWithConfig_PanicsOnWrongImpl(t *testing.T) {
// It causes maintenance to define an impl of RuntimeConfig in tests just to verify the error when it is wrong.
// Instead, we pass nil which is implicitly the wrong type, as that's less work!
err := require.CapturePanic(func() {
NewRuntimeWithConfig(nil)
})
require.EqualError(t, err, "unsupported wazero.RuntimeConfig implementation: <nil>")
}
func TestRuntime_CompileModule(t *testing.T) {
tests := []struct {
name string
@@ -516,35 +506,6 @@ func TestRuntime_InstantiateModuleFromBinary_ErrorOnStart(t *testing.T) {
}
}
func TestRuntime_InstantiateModule_PanicsOnWrongCompiledCodeImpl(t *testing.T) {
// It causes maintenance to define an impl of CompiledModule in tests just to verify the error when it is wrong.
// Instead, we pass nil which is implicitly the wrong type, as that's less work!
r := NewRuntime()
defer r.Close(testCtx)
err := require.CapturePanic(func() {
_, _ = r.InstantiateModule(testCtx, nil, NewModuleConfig())
})
require.EqualError(t, err, "unsupported wazero.CompiledModule implementation: <nil>")
}
func TestRuntime_InstantiateModule_PanicsOnWrongModuleConfigImpl(t *testing.T) {
r := NewRuntime()
defer r.Close(testCtx)
code, err := r.CompileModule(testCtx, binaryformat.EncodeModule(&wasm.Module{}), NewCompileConfig())
require.NoError(t, err)
// It causes maintenance to define an impl of ModuleConfig in tests just to verify the error when it is wrong.
// Instead, we pass nil which is implicitly the wrong type, as that's less work!
err = require.CapturePanic(func() {
_, _ = r.InstantiateModule(testCtx, code, nil)
})
require.EqualError(t, err, "unsupported wazero.ModuleConfig implementation: <nil>")
}
// TestRuntime_InstantiateModule_WithName tests that we can pre-validate (cache) a module and instantiate it under
// different names. This pattern is used in wapc-go.
func TestRuntime_InstantiateModule_WithName(t *testing.T) {

View File

@@ -5,6 +5,7 @@ import (
"time"
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/internal/wasm"
)
const (
@@ -56,7 +57,7 @@ const (
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-clock_res_getid-clockid---errno-timestamp
// See https://linux.die.net/man/3/clock_getres
func (a *wasi) ClockResGet(ctx context.Context, mod api.Module, id uint32, resultResolution uint32) Errno {
sysCtx := getSysCtx(mod)
sysCtx := mod.(*wasm.CallContext).Sys
var resolution uint64 // ns
switch id {
@@ -99,7 +100,7 @@ func (a *wasi) ClockResGet(ctx context.Context, mod api.Module, id uint32, resul
// See https://linux.die.net/man/3/clock_gettime
func (a *wasi) ClockTimeGet(ctx context.Context, mod api.Module, id uint32, precision uint64, resultTimestamp uint32) Errno {
// TODO: precision is currently ignored.
sysCtx := getSysCtx(mod)
sysCtx := mod.(*wasm.CallContext).Sys
var val uint64
switch id {

View File

@@ -5,6 +5,8 @@ import (
"encoding/binary"
"github.com/tetratelabs/wazero/api"
internalsys "github.com/tetratelabs/wazero/internal/sys"
"github.com/tetratelabs/wazero/internal/wasm"
)
// https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-eventtype-enumu8
@@ -114,7 +116,8 @@ func processClockEvent(ctx context.Context, mod api.Module, inBuf []byte) Errno
// unaffected. Since this function only supports relative timeout, we can
// skip clock ID validation and use a single sleep function.
getSysCtx(mod).Nanosleep(ctx, int64(timeout))
sysCtx := mod.(*wasm.CallContext).Sys
sysCtx.Nanosleep(ctx, int64(timeout))
return ErrnoSuccess
}
@@ -122,12 +125,13 @@ func processClockEvent(ctx context.Context, mod api.Module, inBuf []byte) Errno
// subscriptions are not yet supported.
func processFDEvent(ctx context.Context, mod api.Module, eventType byte, inBuf []byte) Errno {
fd := binary.LittleEndian.Uint32(inBuf)
sysCtx := mod.(*wasm.CallContext).Sys
// Choose the best error, which falls back to unsupported, until we support files.
errno := ErrnoNotsup
if eventType == eventTypeFdRead && fdReader(ctx, mod, fd) == nil {
if eventType == eventTypeFdRead && internalsys.FdReader(ctx, sysCtx, fd) == nil {
errno = ErrnoBadf
} else if eventType == eventTypeFdWrite && fdWriter(ctx, mod, fd) == nil {
} else if eventType == eventTypeFdWrite && internalsys.FdWriter(ctx, sysCtx, fd) == nil {
errno = ErrnoBadf
}

View File

@@ -3,6 +3,7 @@ package wasi_snapshot_preview1
import (
"testing"
internalsys "github.com/tetratelabs/wazero/internal/sys"
"github.com/tetratelabs/wazero/internal/testing/require"
"github.com/tetratelabs/wazero/internal/wasm"
)
@@ -121,7 +122,7 @@ func Test_PollOneoff_Errors(t *testing.T) {
mem: []byte{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // userdata
eventTypeFdRead, 0x0, 0x0, 0x0,
fdStdin, 0x0, 0x0, 0x0, // valid readable FD
internalsys.FdStdin, 0x0, 0x0, 0x0, // valid readable FD
'?', // stopped after encoding
},
expectedErrno: ErrnoSuccess,

View File

@@ -17,7 +17,6 @@ package wasi_snapshot_preview1
import (
"context"
"errors"
"fmt"
"io"
"io/fs"
@@ -424,12 +423,6 @@ const (
(func $wasi.sock_shutdown (param $fd i32) (param $how i32) (result (;errno;) i32)))`
)
const (
fdStdin = iota
fdStdout
fdStderr
)
// wasi includes all host functions to export for WASI version "wasi_snapshot_preview1".
//
// ## Translation notes
@@ -542,7 +535,7 @@ func wasiFunctions() map[string]interface{} {
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#args_get
// See https://en.wikipedia.org/wiki/Null-terminated_string
func (a *wasi) ArgsGet(ctx context.Context, mod api.Module, argv, argvBuf uint32) Errno {
sysCtx := getSysCtx(mod)
sysCtx := mod.(*wasm.CallContext).Sys
return writeOffsetsAndNullTerminatedValues(ctx, mod.Memory(), sysCtx.Args(), argv, argvBuf)
}
@@ -573,7 +566,7 @@ func (a *wasi) ArgsGet(ctx context.Context, mod api.Module, argv, argvBuf uint32
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#args_sizes_get
// See https://en.wikipedia.org/wiki/Null-terminated_string
func (a *wasi) ArgsSizesGet(ctx context.Context, mod api.Module, resultArgc, resultArgvBufSize uint32) Errno {
sysCtx := getSysCtx(mod)
sysCtx := mod.(*wasm.CallContext).Sys
mem := mod.Memory()
if !mem.WriteUint32Le(ctx, resultArgc, uint32(len(sysCtx.Args()))) {
@@ -612,8 +605,8 @@ func (a *wasi) ArgsSizesGet(ctx context.Context, mod api.Module, resultArgc, res
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#environ_get
// See https://en.wikipedia.org/wiki/Null-terminated_string
func (a *wasi) EnvironGet(ctx context.Context, mod api.Module, environ uint32, environBuf uint32) Errno {
env := getSysCtx(mod).Environ()
return writeOffsetsAndNullTerminatedValues(ctx, mod.Memory(), env, environ, environBuf)
sysCtx := mod.(*wasm.CallContext).Sys
return writeOffsetsAndNullTerminatedValues(ctx, mod.Memory(), sysCtx.Environ(), environ, environBuf)
}
// EnvironSizesGet is the WASI function named functionEnvironSizesGet that reads environment variable
@@ -644,7 +637,7 @@ func (a *wasi) EnvironGet(ctx context.Context, mod api.Module, environ uint32, e
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#environ_sizes_get
// See https://en.wikipedia.org/wiki/Null-terminated_string
func (a *wasi) EnvironSizesGet(ctx context.Context, mod api.Module, resultEnvironc uint32, resultEnvironBufSize uint32) Errno {
sysCtx := getSysCtx(mod)
sysCtx := mod.(*wasm.CallContext).Sys
mem := mod.Memory()
if !mem.WriteUint32Le(ctx, resultEnvironc, uint32(len(sysCtx.Environ()))) {
@@ -676,9 +669,8 @@ func (a *wasi) FdAllocate(ctx context.Context, mod api.Module, fd uint32, offset
// See https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#fd_close
// See https://linux.die.net/man/3/close
func (a *wasi) FdClose(ctx context.Context, mod api.Module, fd uint32) Errno {
if ok, err := getSysCtx(mod).FS(ctx).CloseFile(ctx, fd); err != nil {
return ErrnoIo
} else if !ok {
sysCtx := mod.(*wasm.CallContext).Sys
if ok := sysCtx.FS(ctx).CloseFile(ctx, fd); !ok {
return ErrnoBadf
}
@@ -723,7 +715,8 @@ func (a *wasi) FdDatasync(ctx context.Context, mod api.Module, fd uint32) Errno
// See https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#fd_fdstat_get
// See https://linux.die.net/man/3/fsync
func (a *wasi) FdFdstatGet(ctx context.Context, mod api.Module, fd uint32, resultStat uint32) Errno {
if _, ok := getSysCtx(mod).FS(ctx).OpenedFile(ctx, fd); !ok {
sysCtx := mod.(*wasm.CallContext).Sys
if _, ok := sysCtx.FS(ctx).OpenedFile(ctx, fd); !ok {
return ErrnoBadf
}
return ErrnoSuccess
@@ -757,7 +750,8 @@ func (a *wasi) FdFdstatGet(ctx context.Context, mod api.Module, fd uint32, resul
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#prestat
// See https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#fd_prestat_get
func (a *wasi) FdPrestatGet(ctx context.Context, mod api.Module, fd uint32, resultPrestat uint32) Errno {
entry, ok := getSysCtx(mod).FS(ctx).OpenedFile(ctx, fd)
sysCtx := mod.(*wasm.CallContext).Sys
entry, ok := sysCtx.FS(ctx).OpenedFile(ctx, fd)
if !ok {
return ErrnoBadf
}
@@ -830,7 +824,8 @@ func (a *wasi) FdPread(ctx context.Context, mod api.Module, fd, iovs, iovsCount
// See FdPrestatGet
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#fd_prestat_dir_name
func (a *wasi) FdPrestatDirName(ctx context.Context, mod api.Module, fd uint32, pathPtr uint32, pathLen uint32) Errno {
f, ok := getSysCtx(mod).FS(ctx).OpenedFile(ctx, fd)
sysCtx := mod.(*wasm.CallContext).Sys
f, ok := sysCtx.FS(ctx).OpenedFile(ctx, fd)
if !ok {
return ErrnoBadf
}
@@ -896,7 +891,8 @@ func (a *wasi) FdPwrite(ctx context.Context, mod api.Module, fd, iovs, iovsCount
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#iovec
// See https://linux.die.net/man/3/readv
func (a *wasi) FdRead(ctx context.Context, mod api.Module, fd, iovs, iovsCount, resultSize uint32) Errno {
reader := fdReader(ctx, mod, fd)
sysCtx := mod.(*wasm.CallContext).Sys
reader := sys.FdReader(ctx, sysCtx, fd)
if reader == nil {
return ErrnoBadf
}
@@ -972,9 +968,10 @@ func (a *wasi) FdRenumber(ctx context.Context, mod api.Module, fd, to uint32) Er
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#fd_seek
// See https://linux.die.net/man/3/lseek
func (a *wasi) FdSeek(ctx context.Context, mod api.Module, fd uint32, offset uint64, whence uint32, resultNewoffset uint32) Errno {
sysCtx := mod.(*wasm.CallContext).Sys
var seeker io.Seeker
// Check to see if the file descriptor is available
if f, ok := getSysCtx(mod).FS(ctx).OpenedFile(ctx, fd); !ok || f.File == nil {
if f, ok := sysCtx.FS(ctx).OpenedFile(ctx, fd); !ok || f.File == nil {
return ErrnoBadf
// fs.FS doesn't declare io.Seeker, but implementations such as os.File implement it.
} else if seeker, ok = f.File.(io.Seeker); !ok {
@@ -1056,7 +1053,8 @@ func (a *wasi) FdTell(ctx context.Context, mod api.Module, fd, resultOffset uint
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#fd_write
// See https://linux.die.net/man/3/writev
func (a *wasi) FdWrite(ctx context.Context, mod api.Module, fd, iovs, iovsCount, resultSize uint32) Errno {
writer := fdWriter(ctx, mod, fd)
sysCtx := mod.(*wasm.CallContext).Sys
writer := sys.FdWriter(ctx, sysCtx, fd)
if writer == nil {
return ErrnoBadf
}
@@ -1088,40 +1086,6 @@ func (a *wasi) FdWrite(ctx context.Context, mod api.Module, fd, iovs, iovsCount,
return ErrnoSuccess
}
// fdReader returns a valid reader for the given file descriptor or nil if ErrnoBadf.
func fdReader(ctx context.Context, mod api.Module, fd uint32) io.Reader {
sysCtx := getSysCtx(mod)
if fd == fdStdin {
return sysCtx.Stdin()
} else if f, ok := sysCtx.FS(ctx).OpenedFile(ctx, fd); !ok {
return nil
} else {
return f.File
}
}
// fdWriter returns a valid writer for the given file descriptor or nil if ErrnoBadf.
func fdWriter(ctx context.Context, mod api.Module, fd uint32) io.Writer {
sysCtx := getSysCtx(mod)
switch fd {
case fdStdout:
return sysCtx.Stdout()
case fdStderr:
return sysCtx.Stderr()
default:
// Check to see if the file descriptor is available
if f, ok := sysCtx.FS(ctx).OpenedFile(ctx, fd); !ok || f.File == nil {
return nil
// fs.FS doesn't declare io.Writer, but implementations such as
// os.File implement it.
} else if writer, ok := f.File.(io.Writer); !ok {
return nil
} else {
return writer
}
}
}
// PathCreateDirectory is the WASI function named functionPathCreateDirectory
func (a *wasi) PathCreateDirectory(ctx context.Context, mod api.Module, fd, path, pathLen uint32) Errno {
return ErrnoNosys // stubbed for GrainLang per #271
@@ -1189,7 +1153,7 @@ func (a *wasi) PathLink(ctx context.Context, mod api.Module, oldFd, oldFlags, ol
// See https://linux.die.net/man/3/openat
func (a *wasi) PathOpen(ctx context.Context, mod api.Module, fd, dirflags, pathPtr, pathLen, oflags uint32, fsRightsBase,
fsRightsInheriting uint64, fdflags, resultOpenedFd uint32) (errno Errno) {
sysCtx := getSysCtx(mod)
sysCtx := mod.(*wasm.CallContext).Sys
fsc := sysCtx.FS(ctx)
if _, ok := fsc.OpenedFile(ctx, fd); !ok {
return ErrnoBadf
@@ -1210,7 +1174,7 @@ func (a *wasi) PathOpen(ctx context.Context, mod api.Module, fd, dirflags, pathP
return ErrnoIo
}
} else if !mod.Memory().WriteUint32Le(ctx, resultOpenedFd, newFD) {
_, _ = fsc.CloseFile(ctx, newFD)
_ = fsc.CloseFile(ctx, newFD)
return ErrnoFault
}
return ErrnoSuccess
@@ -1280,7 +1244,8 @@ func (a *wasi) SchedYield(mod api.Module) Errno {
// Note: importRandomGet shows this signature in the WebAssembly 1.0 Text Format.
// See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-random_getbuf-pointeru8-bufLen-size---errno
func (a *wasi) RandomGet(ctx context.Context, mod api.Module, buf uint32, bufLen uint32) (errno Errno) {
randSource := getSysCtx(mod).RandSource()
sysCtx := mod.(*wasm.CallContext).Sys
randSource := sysCtx.RandSource()
randomBytes, ok := mod.Memory().Read(ctx, buf, bufLen)
if !ok { // out-of-range
@@ -1310,14 +1275,6 @@ func (a *wasi) SockShutdown(ctx context.Context, mod api.Module, fd, how uint32)
return ErrnoNosys // stubbed for GrainLang per #271
}
func getSysCtx(mod api.Module) *sys.Context {
if internal, ok := mod.(*wasm.CallContext); !ok {
panic(fmt.Errorf("unsupported wasm.Module implementation: %v", mod))
} else {
return internal.Sys
}
}
func writeOffsetsAndNullTerminatedValues(ctx context.Context, mem api.Memory, values []string, offsets, bytes uint32) Errno {
for _, value := range values {
// Write current offset and advance it.

View File

@@ -468,7 +468,7 @@ func Test_FdClose(t *testing.T) {
verify := func(mod api.Module) {
// Verify fdToClose is closed and removed from the opened FDs.
fsc := getSysCtx(mod).FS(testCtx)
fsc := mod.(*wasm.CallContext).Sys.FS(testCtx)
_, ok := fsc.OpenedFile(testCtx, fdToClose)
require.False(t, ok)
@@ -1509,7 +1509,7 @@ func Test_PathOpen(t *testing.T) {
require.Equal(t, expectedMemory, actual)
// verify the file was actually opened
fsc := getSysCtx(mod).FS(ctx)
fsc := mod.(*wasm.CallContext).Sys.FS(ctx)
f, ok := fsc.OpenedFile(testCtx, expectedFD)
require.True(t, ok)
require.Equal(t, pathName, f.Path)