Skip to content

Commit

Permalink
cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
mark-pictor-csec committed May 24, 2024
1 parent 8334fad commit 64a6bad
Show file tree
Hide file tree
Showing 8 changed files with 38 additions and 283 deletions.
48 changes: 6 additions & 42 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,8 @@ jobs:
include:
# x86_64 linux
- os: ubuntu-20.04
# artifact_name: linux-build-release
toolchain_target: x86_64-unknown-linux-gnu

# x86_64 macos
# - os: macos-latest
# # artifact_name: macos-build-release
# toolchain_target: x86_64-apple-darwin
#
# # arm64 macOS
# - os: macos-latest
# # artifact_name: macos-arm-build-release
# toolchain_target: aarch64-apple-darwin

steps:
- uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
targets: ${{ matrix.toolchain_target }} wasm32-wasi
- name: Rust Cache
uses: Swatinem/rust-cache@v2
- name: install Go
uses: actions/setup-go@v5
with:
Expand All @@ -49,25 +29,9 @@ jobs:
- name: build go runner
run: go build -o runner ./cmd

- name: build native release
run: cargo build --release --target ${{ matrix.toolchain_target }}
- name: build native debug
run: cargo build --target ${{ matrix.toolchain_target }}

- name: build wasm release
run: cargo build --release --target wasm32-wasi
- name: build wasm debug
run: cargo build --target wasm32-wasi

- name: run native release
run: ./target/${{ matrix.toolchain_target }}/release/wazero-crash-lib
- name: run native debug
run: ./target/${{ matrix.toolchain_target }}/debug/wazero-crash-lib

- name: run wasm release
run: ./runner -release -skipbuild
- name: run wasm debug
run: ./runner -skipbuild
- name: show files
run: |
ls target/${{ matrix.toolchain_target }}/release/ target/${{ matrix.toolchain_target }}/debug/ target/wasm32-wasi/release/ target/wasm32-wasi/debug/
- name: run interpreted, with extra memory
run: ./runner -release -interp
- name: run compiled, without extra memory
run: ./runner -release -nomem
- name: run compiled, with extra memory (crashes)
run: ./runner -release
55 changes: 0 additions & 55 deletions Cargo.lock

This file was deleted.

4 changes: 0 additions & 4 deletions Cargo.toml

This file was deleted.

21 changes: 16 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,25 @@
Just trying to get to the bottom of a crash in a wasm module built from rust, when run via wazero.

## quick start
```sh
go run ./cmd -release
```
- wasm is compiled, and additional memory is alloc'd for wasm
- wasm func exits with `unreachable` error and stack trace

go run ./cmd -skipbuild
- wasm crashes when regex() func called

go run ./cmd -release -skipbuild
- no crash
```sh
go run ./cmd -release -interp
```
- interpreted rather than compiled
- wasm func is successful
```sh
go run ./cmd -release -nomem
```
- no extra memory is allocated
- wasm func is successful

## versions
```
```
$ rustc --version
Expand Down
132 changes: 16 additions & 116 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"fmt"
"log"
"os"
"os/exec"
"strings"

"github.com/tetratelabs/wazero"
Expand All @@ -15,31 +14,13 @@ import (
)

func loadWasm(opts wasmOpts) []byte {
path := debugPath
if opts.release {
path = releasePath
path := dbgProprietary
if _, err := os.Stat(path); err != nil {
log.Printf("debug build not found, trying release")
opts.release = true
}
if opts.proprietary {
opts.skipBuild = true
path = dbgProprietary
if _, err := os.Stat(path); err != nil {
opts.release = true
log.Printf("debug build not found, trying release")
}
if opts.release {
path = relProprietary
}
}
if !opts.skipBuild {
cmd := exec.Command("cargo", "build", "--target=wasm32-wasi")
if opts.release {
cmd.Args = append(cmd.Args, "--release")
}
out, err := cmd.CombinedOutput()
if err != nil {
buildHelp := "========\ndo you have rust and its target wasm32-wasi installed?"
log.Fatalf("running %v: %s\noutput:\n%s\n%s", cmd.Args, err, string(out), buildHelp)
}
if opts.release {
path = relProprietary
}
wasm, err := os.ReadFile(path)
if err != nil {
Expand All @@ -66,7 +47,7 @@ func startWz(wasm []byte, ctx context.Context, interp bool) api.Module {
if err != nil {
log.Fatalf("compiling: %s", err)
}
modcfg := wazero.NewModuleConfig().WithName("") //.WithEnv("RUST_BACKTRACE", "full")
modcfg := wazero.NewModuleConfig().WithName("")

mod, err := wz.InstantiateModule(ctx, compiled, modcfg)
if err != nil {
Expand All @@ -76,58 +57,18 @@ func startWz(wasm []byte, ctx context.Context, interp bool) api.Module {
}

const (
debugPath = "target/wasm32-wasi/debug/wazero-crash-lib.wasm"
releasePath = "target/wasm32-wasi/release/wazero-crash-lib.wasm"
dbgProprietary = "./proprietary_dbg.wasm"
relProprietary = "./proprietary_rel.wasm"
)

func alloc(mod api.Module, ctx context.Context, n uint64) (ptr uint64, cleanup func()) {
alloc := auditedFn{Function: mod.ExportedFunction("allocate")}
if alloc.Function == nil {
log.Fatal("alloc not found")
}
dealloc := auditedFn{Function: mod.ExportedFunction("deallocate")}
if dealloc.Function == nil {
log.Fatal("dealloc not found")
}
res, err := alloc.Call(ctx, n)
if err != nil {
log.Fatalf("calling alloc: %s", err)
}
if len(res) != 1 || res[0] == 0 {
log.Fatalf("want pointer, got %v", res)
}
return res[0], func() {
dealloc.Call(ctx, ptr, n)
}
}

func writeData[T []byte | string](mod api.Module, ctx context.Context, data T) (ptr uint64, cleanup func()) {
ptr, cleanup = alloc(mod, ctx, uint64(len(data)))
if ok := mod.Memory().WriteString(uint32(ptr), string(data)); !ok {
log.Fatalf("failed writing %d bytes (%q) to wasm memory at %d; mem size %d", len(data), data, ptr, mod.Memory().Size())
}
return ptr, cleanup
}

var nocleanup bool

type wasmOpts struct {
release bool
skipBuild bool
proprietary bool
nomem bool
release bool
nomem bool
}

func main() {
s := "mello world vectors"
var wOpts wasmOpts
flag.BoolVar(&wOpts.release, "release", false, "use release build rather than debug")
flag.BoolVar(&wOpts.skipBuild, "skipbuild", false, "skip cargo wasm (re)build")
flag.BoolVar(&nocleanup, "nocleanup", false, "skips dealloc's")
flag.StringVar(&s, "str", s, "specify an arbitrary string to match re (orld) and/or ac (short, vectors)")
flag.BoolVar(&wOpts.proprietary, "proprietary", false, "if true, exercise fn in proprietary wasm. obviates -skipbuild, -str.")
flag.BoolVar(&wOpts.nomem, "nomem", false, "if true, do not grow memory")
interp := flag.Bool("interp", false, "if true, use interpreter rather than compiling")
flag.Parse()
Expand All @@ -145,53 +86,6 @@ func main() {
}

runInit(mod, ctx)

if !wOpts.proprietary {
listFns(mod)
reCheck(mod, ctx, s)
acCheck(mod, ctx, s)
}
}

func reCheck(mod api.Module, ctx context.Context, s string) {
m := auditedFn{Function: mod.ExportedFunction("regex")}
if m.Function == nil {
log.Fatal("no such exported function regex")
}
ptr, cleanup := writeData(mod, ctx, s)
if !nocleanup {
defer cleanup()
}
res, err := m.Call(ctx, ptr, uint64(len(s)))
if err != nil {
log.Fatalf("call regex(): %s", err)
}
log.Println(res)
}

func acCheck(mod api.Module, ctx context.Context, s string) {
m := auditedFn{Function: mod.ExportedFunction("ac")}
if m.Function == nil {
log.Fatal("no such exported function ac")
}
ptr, cleanup := writeData(mod, ctx, s)
if !nocleanup {
defer cleanup()
}

res, err := m.Call(ctx, ptr, uint64(len(s)))
if err != nil {
log.Fatalf("call ac(): %s", err)
}
log.Println(res)
}

func listFns(mod api.Module) {
fns := mod.ExportedFunctionDefinitions()
log.Printf("%d funcs exported:", len(fns))
for f, d := range fns {
log.Printf(" %s([%d]) -> %d", f, len(d.ParamTypes()), len(d.ResultTypes()))
}
}

type auditedFn struct {
Expand All @@ -201,17 +95,19 @@ type auditedFn struct {
// must implement api.Function
var _ api.Function = (*auditedFn)(nil)

// logs args and results for each call
func (af auditedFn) Call(ctx context.Context, params ...uint64) (res []uint64, err error) {
defer func() {
errstr := "(nil)"
if err != nil {
errstr = err.Error()
}
log.Printf("%s(%v)=%v,%s", af.Definition().Name(), params, res, errstr)
log.Printf("call %s(%v) ->\n res=%v\n err= \\\n%s", af.Definition().Name(), params, res, errstr)
}()
return af.Function.Call(ctx, params...)
}

// grows module memory to 8 mb
func growMemory(mod api.Module) {
const (
page = 65536 // page size from wazero documentation
Expand All @@ -222,6 +118,7 @@ func growMemory(mod api.Module) {
currentPgs := mod.Memory().Size() / page
delta := desiredPgs - currentPgs
if delta > 0 {
log.Printf("growing memory by %d pages", delta)
mod.Memory().Grow(delta)
}
}
Expand All @@ -238,16 +135,19 @@ func runInit(mod api.Module, ctx context.Context) {
if err != nil {
s := err.Error()
if !strings.HasPrefix(s, "wasm error: unreachable") {
// returned an error, but it differs from that expected
redfatal("error does not begin with unreachable")
os.Exit(1)
}
// actual error logged by auditedFn, no need to log again
log.Fatal("init() error")
}
if len(res) != 1 || res[0] != 0 {
log.Fatalf("init() did not succeed:\nres=%v", res)
}
}

// uses ansi escape sequences to color message
func redfatal(s string) {
blackOnRed := "\x1b[101m"
reset := "\x1b(B\x1b[m"
Expand Down
9 changes: 0 additions & 9 deletions crates/wazero-crash-lib/Cargo.toml

This file was deleted.

Loading

0 comments on commit 64a6bad

Please sign in to comment.