logging: avoids logging activity to stdio file descriptors (#1007)

This avoids logging activity on stdio file descriptors, in order to help
make troubleshooting easier. Usually, there isn't an issue in these, yet
wasm panics are harder to read if there is also logging of the ..
logging.

Signed-off-by: Adrian Cole <adrian@tetrate.io>
This commit is contained in:
Crypt Keeper
2023-01-04 16:04:40 +08:00
committed by GitHub
parent 3ab7e4b36d
commit f8a33cef8d
11 changed files with 73 additions and 80 deletions

View File

@@ -8,7 +8,7 @@ import (
// newJsGlobal = js.Global() // js.go init
func newJsGlobal(rt http.RoundTripper) *jsVal {
var fetchProperty interface{} = undefined
var fetchProperty interface{} = goos.Undefined
if rt != nil {
fetchProperty = goos.RefHttpFetch
}
@@ -19,7 +19,7 @@ func newJsGlobal(rt http.RoundTripper) *jsVal {
"crypto": jsCrypto,
"Uint8Array": uint8ArrayConstructor,
"fetch": fetchProperty,
"AbortController": undefined,
"AbortController": goos.Undefined,
"Headers": headersConstructor,
"process": jsProcess,
"fs": jsfs,

View File

@@ -90,7 +90,7 @@ type jsfsOpen struct{}
func (jsfsOpen) invoke(ctx context.Context, mod api.Module, args ...interface{}) (interface{}, error) {
path := args[0].(string)
flags := toUint64(args[1]) // flags are derived from constants like oWRONLY
perm := toUint32(args[2])
perm := goos.ValueToUint32(args[2])
callback := args[3].(funcWrapper)
fsc := mod.(*wasm.CallContext).Sys.FS()
@@ -146,7 +146,7 @@ type jsfsFstat struct{}
func (jsfsFstat) invoke(ctx context.Context, mod api.Module, args ...interface{}) (interface{}, error) {
fsc := mod.(*wasm.CallContext).Sys.FS()
fd := toUint32(args[0])
fd := goos.ValueToUint32(args[0])
callback := args[1].(funcWrapper)
fstat, err := syscallFstat(fsc, fd)
@@ -231,7 +231,7 @@ type jsfsClose struct{}
func (jsfsClose) invoke(ctx context.Context, mod api.Module, args ...interface{}) (interface{}, error) {
fsc := mod.(*wasm.CallContext).Sys.FS()
fd := toUint32(args[0])
fd := goos.ValueToUint32(args[0])
callback := args[1].(funcWrapper)
err := fsc.CloseFile(fd)
@@ -246,13 +246,13 @@ func (jsfsClose) invoke(ctx context.Context, mod api.Module, args ...interface{}
type jsfsRead struct{}
func (jsfsRead) invoke(ctx context.Context, mod api.Module, args ...interface{}) (interface{}, error) {
fd := toUint32(args[0])
fd := goos.ValueToUint32(args[0])
buf, ok := args[1].(*byteArray)
if !ok {
return nil, fmt.Errorf("arg[1] is %v not a []byte", args[1])
}
offset := toUint32(args[2])
byteCount := toUint32(args[3])
offset := goos.ValueToUint32(args[2])
byteCount := goos.ValueToUint32(args[3])
fOffset := args[4] // nil unless Pread
callback := args[5].(funcWrapper)
@@ -297,13 +297,13 @@ func syscallRead(mod api.Module, fd uint32, offset interface{}, p []byte) (n uin
type jsfsWrite struct{}
func (jsfsWrite) invoke(ctx context.Context, mod api.Module, args ...interface{}) (interface{}, error) {
fd := toUint32(args[0])
fd := goos.ValueToUint32(args[0])
buf, ok := args[1].(*byteArray)
if !ok {
return nil, fmt.Errorf("arg[1] is %v not a []byte", args[1])
}
offset := toUint32(args[2])
byteCount := toUint32(args[3])
offset := goos.ValueToUint32(args[2])
byteCount := goos.ValueToUint32(args[3])
fOffset := args[4] // nil unless Pread
callback := args[5].(funcWrapper)
@@ -418,7 +418,7 @@ type jsfsMkdir struct{}
func (jsfsMkdir) invoke(ctx context.Context, mod api.Module, args ...interface{}) (interface{}, error) {
path := args[0].(string)
perm := toUint32(args[1])
perm := goos.ValueToUint32(args[1])
callback := args[2].(funcWrapper)
fsc := mod.(*wasm.CallContext).Sys.FS()
@@ -502,7 +502,7 @@ type jsfsChmod struct{}
func (jsfsChmod) invoke(ctx context.Context, mod api.Module, args ...interface{}) (interface{}, error) {
path := args[0].(string)
mode := toUint32(args[1])
mode := goos.ValueToUint32(args[1])
callback := args[2].(funcWrapper)
_, _ = path, mode // TODO
@@ -517,8 +517,8 @@ func (jsfsChmod) invoke(ctx context.Context, mod api.Module, args ...interface{}
type jsfsFchmod struct{}
func (jsfsFchmod) invoke(ctx context.Context, mod api.Module, args ...interface{}) (interface{}, error) {
fd := toUint32(args[0])
mode := toUint32(args[1])
fd := goos.ValueToUint32(args[0])
mode := goos.ValueToUint32(args[1])
callback := args[2].(funcWrapper)
_, _ = fd, mode // TODO
@@ -534,8 +534,8 @@ type jsfsChown struct{}
func (jsfsChown) invoke(ctx context.Context, mod api.Module, args ...interface{}) (interface{}, error) {
path := args[0].(string)
uid := toUint32(args[1])
gid := toUint32(args[2])
uid := goos.ValueToUint32(args[1])
gid := goos.ValueToUint32(args[2])
callback := args[3].(funcWrapper)
_, _, _ = path, uid, gid // TODO
@@ -550,9 +550,9 @@ func (jsfsChown) invoke(ctx context.Context, mod api.Module, args ...interface{}
type jsfsFchown struct{}
func (jsfsFchown) invoke(ctx context.Context, mod api.Module, args ...interface{}) (interface{}, error) {
fd := toUint32(args[0])
uid := toUint32(args[1])
gid := toUint32(args[2])
fd := goos.ValueToUint32(args[0])
uid := goos.ValueToUint32(args[1])
gid := goos.ValueToUint32(args[2])
callback := args[3].(funcWrapper)
_, _, _ = fd, uid, gid // TODO
@@ -568,8 +568,8 @@ type jsfsLchown struct{}
func (jsfsLchown) invoke(ctx context.Context, mod api.Module, args ...interface{}) (interface{}, error) {
path := args[0].(string)
uid := toUint32(args[1])
gid := toUint32(args[2])
uid := goos.ValueToUint32(args[1])
gid := goos.ValueToUint32(args[2])
callback := args[3].(funcWrapper)
_, _, _ = path, uid, gid // TODO
@@ -600,7 +600,7 @@ func (jsfsTruncate) invoke(ctx context.Context, mod api.Module, args ...interfac
type jsfsFtruncate struct{}
func (jsfsFtruncate) invoke(ctx context.Context, mod api.Module, args ...interface{}) (interface{}, error) {
fd := toUint32(args[0])
fd := goos.ValueToUint32(args[0])
length := toInt64(args[1])
callback := args[2].(funcWrapper)
@@ -664,7 +664,7 @@ func (jsfsSymlink) invoke(ctx context.Context, mod api.Module, args ...interface
type jsfsFsync struct{}
func (jsfsFsync) invoke(ctx context.Context, mod api.Module, args ...interface{}) (interface{}, error) {
fd := toUint32(args[0])
fd := goos.ValueToUint32(args[0])
callback := args[1].(funcWrapper)
_ = fd // TODO

View File

@@ -251,3 +251,14 @@ func (f *stackFunc) Call(ctx context.Context, mod api.Module, wasmStack []uint64
func NewStack(name string, mem api.Memory, sp uint32) *stack {
return &stack{goarch.NewStack(name, mem, sp)}
}
var Undefined = struct{ name string }{name: "undefined"}
func ValueToUint32(arg interface{}) uint32 {
if arg == RefValueZero || arg == Undefined {
return 0
} else if u, ok := arg.(uint32); ok {
return u
}
return uint32(arg.(float64))
}

View File

@@ -89,7 +89,7 @@ func (s *fetchResult) get(_ context.Context, propertyKey string) interface{} {
return h
case "body":
// return undefined as arrayPromise is more complicated than an array.
return undefined
return goos.Undefined
case "status":
return uint32(s.res.StatusCode)
}

View File

@@ -5,7 +5,6 @@ import (
"fmt"
"io/fs"
"os"
"strconv"
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/internal/gojs"
@@ -13,12 +12,12 @@ import (
"github.com/tetratelabs/wazero/internal/gojs/goarch"
"github.com/tetratelabs/wazero/internal/gojs/goos"
"github.com/tetratelabs/wazero/internal/logging"
"github.com/tetratelabs/wazero/internal/sys"
)
func Config(fnd api.FunctionDefinition) (pSampler logging.ParamSampler, pLoggers []logging.ParamLogger, rLoggers []logging.ResultLogger) {
switch fnd.Name() {
case custom.NameRuntimeWasmWrite:
pLoggers = []logging.ParamLogger{runtimeWasmWriteParamLogger}
// Don't log NameRuntimeWasmWrite as it is used in panics
case custom.NameSyscallValueCall:
pSampler = syscallValueCallParamSampler
pLoggers = []logging.ParamLogger{syscallValueCallParamLogger}
@@ -28,21 +27,6 @@ func Config(fnd api.FunctionDefinition) (pSampler logging.ParamSampler, pLoggers
return
}
func runtimeWasmWriteParamLogger(_ context.Context, mod api.Module, w logging.Writer, params []uint64) {
mem := mod.Memory()
funcName := custom.NameSyscallValueCall
stack := goos.NewStack(funcName, mem, uint32(params[0]))
fd := stack.ParamUint32(0)
pLen := stack.ParamUint32(2)
w.WriteString(funcName) //nolint
w.WriteString("(fd=") //nolint
writeI32(w, fd)
w.WriteString(",p_len=") //nolint
writeI32(w, pLen)
w.WriteByte(')') //nolint
}
func syscallValueCallParamLogger(ctx context.Context, mod api.Module, w logging.Writer, params []uint64) {
vRef, m, args := syscallValueCallParams(ctx, mod, params)
@@ -73,10 +57,20 @@ func syscallValueCallParamLogger(ctx context.Context, mod api.Module, w logging.
}
func syscallValueCallParamSampler(ctx context.Context, mod api.Module, params []uint64) bool {
vRef, _, _ := syscallValueCallParams(ctx, mod, params)
vRef, m, args := syscallValueCallParams(ctx, mod, params)
// TODO: add more than just filesystem
return vRef == goos.RefJsfs
if vRef != goos.RefJsfs {
return false
}
// Don't amplify logs with stdio reads or writes
switch m {
case custom.NameFsWrite, custom.NameFsRead:
fd := goos.ValueToUint32(args[0])
return fd > sys.FdStderr
}
return true
}
func syscallValueCallParams(ctx context.Context, mod api.Module, params []uint64) (goos.Ref, string, []interface{}) {
@@ -168,7 +162,3 @@ var oflagToString = [...]string{
"SYNC",
"TRUNC",
}
func writeI32(w logging.Writer, v uint32) {
w.WriteString(strconv.FormatInt(int64(int32(v)), 10)) //nolint
}

View File

@@ -57,10 +57,7 @@ func (e *event) get(_ context.Context, propertyKey string) interface{} {
panic(fmt.Sprintf("TODO: event.%s", propertyKey))
}
var (
undefined = struct{ name string }{name: "undefined"}
NaN = math.NaN()
)
var NaN = math.NaN()
// LoadValue reads up to 8 bytes at the memory offset `addr` to return the
// value written by storeValue.
@@ -69,7 +66,7 @@ var (
func LoadValue(ctx context.Context, ref goos.Ref) interface{} { //nolint
switch ref {
case 0:
return undefined
return goos.Undefined
case goos.RefValueNaN:
return NaN
case goos.RefValueZero:
@@ -119,7 +116,7 @@ func LoadValue(ctx context.Context, ref goos.Ref) interface{} { //nolint
// See https://github.com/golang/go/blob/go1.19/misc/wasm/wasm_exec.js#L135-L183
func storeRef(ctx context.Context, v interface{}) goos.Ref { //nolint
// allow-list because we control all implementations
if v == undefined {
if v == goos.Undefined {
return goos.RefValueUndefined
} else if v == nil {
return goos.RefValueNull
@@ -271,7 +268,7 @@ func (s *State) close() {
}
func toInt64(arg interface{}) int64 {
if arg == goos.RefValueZero || arg == undefined {
if arg == goos.RefValueZero || arg == goos.Undefined {
return 0
} else if u, ok := arg.(int64); ok {
return u
@@ -280,7 +277,7 @@ func toInt64(arg interface{}) int64 {
}
func toUint64(arg interface{}) uint64 {
if arg == goos.RefValueZero || arg == undefined {
if arg == goos.RefValueZero || arg == goos.Undefined {
return 0
} else if u, ok := arg.(uint64); ok {
return u
@@ -288,15 +285,6 @@ func toUint64(arg interface{}) uint64 {
return uint64(arg.(float64))
}
func toUint32(arg interface{}) uint32 {
if arg == goos.RefValueZero || arg == undefined {
return 0
} else if u, ok := arg.(uint32); ok {
return u
}
return uint32(arg.(float64))
}
// valueString returns the string form of JavaScript string, boolean and number types.
func valueString(v interface{}) string { //nolint
if s, ok := v.(string); ok {