Skip to content

Commit

Permalink
Add timeout support in wazero run cli
Browse files Browse the repository at this point in the history
- ensure the module initialization function is evaluated
  regardless if it's WASI or GoJS
- add a `-timeout duration` flag
- ensure flag gets propagated to the rt config builder
  (also ensure cache flag gets propagated to the rt config builder)
- print a message to stderr when the deadline is exceeded
- configure GitHub Actions to use `-timeout=10m` flag
  instead of GHA's `timeout-minutes: 10`

Signed-off-by: Edoardo Vacchi <evacchi@users.noreply.github.com>
  • Loading branch information
evacchi committed Feb 27, 2023
1 parent d955cd7 commit de39257
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 4 deletions.
3 changes: 1 addition & 2 deletions .github/workflows/integration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,7 @@ jobs:
# adding filter argument to the "Build Stdlib test binary" step.
# e.g. --test-filter "Dir.Iterator but dir is deleted during iteration"
- name: Run the test binary with wazero CLI
timeout-minutes: 10 # Prevent crashes from timing out
run: go run ./cmd/wazero run -mount=:/ test.wasm
run: go run ./cmd/wazero run -mount=:/ -timeout=10m test.wasm

build_tinygo_test_binary:
name: Build TinyGo test binary
Expand Down
Binary file added cmd/wazero/testdata/infinite_loop.wasm
Binary file not shown.
7 changes: 7 additions & 0 deletions cmd/wazero/testdata/infinite_loop.wat
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
(module $infinite_loop
(func $main (export "_start")
(loop
br 0
)
)
)
22 changes: 20 additions & 2 deletions cmd/wazero/wazero.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"os"
"path/filepath"
"strings"
"time"

"github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/api"
Expand Down Expand Up @@ -133,6 +134,11 @@ func doRun(args []string, stdOut io.Writer, stdErr logging.Writer, exit func(cod
"This may be specified multiple times. When <wasm path> is unset, <path> is used. "+
"For read-only mounts, append the suffix ':ro'.")

var timeout time.Duration
flags.DurationVar(&timeout, "timeout", 0*time.Second,
"if a wasm binary runs longer than the given duration, then panic. "+
"If the duration is 0, the timeout is disabled. The default is disabled.")

var hostlogging logScopesFlag
flags.Var(&hostlogging, "hostlogging",
"a comma-separated list of host function scopes to log to stderr. "+
Expand Down Expand Up @@ -195,7 +201,13 @@ func doRun(args []string, stdOut io.Writer, stdErr logging.Writer, exit func(cod
rtc = wazero.NewRuntimeConfig()
}
if cache := maybeUseCacheDir(cacheDir, stdErr, exit); cache != nil {
rtc.WithCompilationCache(cache)
rtc = rtc.WithCompilationCache(cache)
}
if timeout != 0 {
newCtx, cancel := context.WithTimeout(ctx, timeout)
ctx = newCtx
defer cancel()
rtc = rtc.WithCloseOnContextDone(true)
}

rt := wazero.NewRuntimeWithConfig(ctx, rtc)
Expand Down Expand Up @@ -231,11 +243,17 @@ func doRun(args []string, stdOut io.Writer, stdErr logging.Writer, exit func(cod
} else if needsGo {
gojs.MustInstantiate(ctx, rt)
err = gojs.Run(ctx, rt, code, conf)
} else {
_, err = rt.InstantiateModule(ctx, code, conf)
}

if err != nil {
if exitErr, ok := err.(*sys.ExitError); ok {
exit(int(exitErr.ExitCode()))
exitCode := exitErr.ExitCode()
if timeout > 0 && exitCode == sys.ExitCodeDeadlineExceeded {
fmt.Fprintf(stdErr, "canceled: wasm binary '%s' exceeded timeout (%v)\n", wasmExe, timeout)
}
exit(int(exitCode))
}
fmt.Fprintf(stdErr, "error instantiating wasm binary: %v\n", err)
exit(1)
Expand Down
22 changes: 22 additions & 0 deletions cmd/wazero/wazero_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
_ "embed"
"flag"
"fmt"
"github.com/tetratelabs/wazero/sys"
"log"
"os"
"os/exec"
Expand All @@ -22,6 +23,9 @@ import (
"github.com/tetratelabs/wazero/internal/version"
)

//go:embed testdata/infinite_loop.wasm
var wasmInfiniteLoop []byte

//go:embed testdata/wasi_arg.wasm
var wasmWasiArg []byte

Expand Down Expand Up @@ -426,6 +430,24 @@ func TestRun(t *testing.T) {
require.True(t, len(entries) > 0)
},
},
{
name: "timeout: a binary that exceeds the deadline should print an error",
wazeroOpts: []string{"-timeout=1ms"},
wasm: wasmInfiniteLoop,
expectedStderr: "canceled: wasm binary 'test.wasm' exceeded timeout (1ms)\n",
expectedExitCode: int(sys.ExitCodeDeadlineExceeded),
test: func(t *testing.T) {
require.NoError(t, err)
},
},
{
name: "timeout: a binary that ends before the deadline should not print a timeout error",
wazeroOpts: []string{"-timeout=10s"},
wasm: wasmWasiRandomGet,
test: func(t *testing.T) {
require.NoError(t, err)
},
},
}

cryptoTest := test{
Expand Down

0 comments on commit de39257

Please sign in to comment.