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:
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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`,
|
||||
},
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
13
namespace.go
13
namespace.go
@@ -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)
|
||||
|
||||
12
runtime.go
12
runtime.go
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user