Skip to content

qjs panics on web-tooling dist/cli.js (wasm out of bounds) #43

@buke

Description

@buke

Hi, I am hitting a reproducible crash when running the QuickJS web-tooling benchmark bundle through qjs.

Environment

qjs: v0.0.6
wazero: v1.9.0
Go: go1.26.1 darwin/arm64
OS: macOS (Darwin Kernel 25.3.0, arm64)

What I run

Use cli.js from https://github.com/quickjs-ng/web-tooling-benchmark

I evaluate quickjs-ng/web-tooling-benchmark dist/cli.js through qjs.Context().Eval, with a small prelude that defines print and console.log and then returns JSON.stringify of captured output.

Minimal reproducer

Save as repro-qjs-webtooling.go and run go run repro-qjs-webtooling.go.

package main

import (
    "fmt"
    "os"

    qjs "github.com/fastschema/qjs"
)

func main() {
    content, err := os.ReadFile("cli.js")
    if err != nil {
        panic(err)
    }

    prelude := "var __bench_output = [];\n" +
        "function print(value) { __bench_output.push(String(value)); }\n" +
        "var console = {\n" +
        "  log: function(value) { __bench_output.push(String(value)); },\n" +
        "  error: function(value) { __bench_output.push(String(value)); }\n" +
        "};\n"

    script := prelude + string(content) + "\nJSON.stringify(__bench_output);"

    rt, err := qjs.New(qjs.Option{
        MemoryLimit:  1536 * 1024 * 1024,
        MaxStackSize: 8 * 1024 * 1024,
        GCThreshold:  128 * 1024 * 1024,
    })
    if err != nil {
        panic(err)
    }
    defer rt.Close()

    v, err := rt.Context().Eval("web-tooling.js", qjs.Code(script))
    if err != nil {
        panic(err)
    }
    defer v.Free()

    fmt.Println("ok", len(v.String()))
}

and the output :

panic: failed to call QJS_Eval: wasm error: out of bounds memory access
        wasm stack trace:
                .$104(i32)
                .$610(i32,i32)
                .$346(i32,i32)
                .$308(i32,i32,i32,i32) i32
                .$414(i32,i64,i32,i64,i64,i32) i32
                .$266(i32,i64,i64,i64,i32,i32,i32) i64
                .$266(i32,i64,i64,i64,i32,i32,i32) i64
                .$266(i32,i64,i64,i64,i32,i32,i32) i64
                .$266(i32,i64,i64,i64,i32,i32,i32) i64
                .$266(i32,i64,i64,i64,i32,i32,i32) i64
                .$266(i32,i64,i64,i64,i32,i32,i32) i64
                .$266(i32,i64,i64,i64,i32,i32,i32) i64
                .$266(i32,i64,i64,i64,i32,i32,i32) i64
                .$266(i32,i64,i64,i64,i32,i32,i32) i64
                .$266(i32,i64,i64,i64,i32,i32,i32) i64
                .$266(i32,i64,i64,i64,i32,i32,i32) i64
                .$266(i32,i64,i64,i64,i32,i32,i32) i64
                .$266(i32,i64,i64,i64,i32,i32,i32) i64
                .$266(i32,i64,i64,i64,i32,i32,i32) i64
                .$266(i32,i64,i64,i64,i32,i32,i32) i64
                .$266(i32,i64,i64,i64,i32,i32,i32) i64
                .$266(i32,i64,i64,i64,i32,i32,i32) i64
                .$266(i32,i64,i64,i64,i32,i32,i32) i64
                .$266(i32,i64,i64,i64,i32,i32,i32) i64
                .$266(i32,i64,i64,i64,i32,i32,i32) i64
                .$266(i32,i64,i64,i64,i32,i32,i32) i64
                .$266(i32,i64,i64,i64,i32,i32,i32) i64
                .$266(i32,i64,i64,i64,i32,i32,i32) i64
                .$266(i32,i64,i64,i64,i32,i32,i32) i64
                .$266(i32,i64,i64,i64,i32,i32,i32) i64
                ... maybe followed by omitted frames
        stack: goroutine 1 [running]:
        runtime/debug.Stack()
                /opt/homebrew/Cellar/go/1.26.1/libexec/src/runtime/debug/stack.go:26 +0x64
        github.com/fastschema/qjs.(*Runtime).call(0x6d8f96392000, {0x104d89e93, 0x8}, {0x6d8f90a920f0, 0x2, 0x2})
                /Users/wangbuke/go/pkg/mod/github.com/fastschema/qjs@v0.0.6/runtime.go:320 +0xa0
        github.com/fastschema/qjs.(*Runtime).Call(0x6d8f96392000, {0x104d89e93?, 0x0?}, {0x6d8f90a920f0?, 0x60000000?, 0x800000?})
                /Users/wangbuke/go/pkg/mod/github.com/fastschema/qjs@v0.0.6/runtime.go:240 +0x28
        github.com/fastschema/qjs.(*Context).Call(...)
                /Users/wangbuke/go/pkg/mod/github.com/fastschema/qjs@v0.0.6/context.go:21
        github.com/fastschema/qjs.eval(0x6d8f96394000, {0x104d8c55c, 0xe}, {0x6d8f950f1e38, 0x1, 0x104d94261?})
                /Users/wangbuke/go/pkg/mod/github.com/fastschema/qjs@v0.0.6/eval.go:31 +0x170
        github.com/fastschema/qjs.(*Context).Eval(...)
                /Users/wangbuke/go/pkg/mod/github.com/fastschema/qjs@v0.0.6/context.go:90
        main.main()
                /tmp/repro-qjs-webtooling.go:35 +0x120

        panic: failed to call QJS_Free: wasm error: unreachable
        wasm stack trace:
                .$273(i32)
                .$272(i32)
                .$92(i32)
        stack: goroutine 1 [running]:
        runtime/debug.Stack()
                /opt/homebrew/Cellar/go/1.26.1/libexec/src/runtime/debug/stack.go:26 +0x64
        github.com/fastschema/qjs.(*Runtime).call(0x6d8f96392000, {0x104d89e9b, 0x8}, {0x6d8f90e0c380, 0x1, 0x1})
                /Users/wangbuke/go/pkg/mod/github.com/fastschema/qjs@v0.0.6/runtime.go:320 +0xa0
        github.com/fastschema/qjs.(*Runtime).Call(0x6d8f96392000, {0x104d89e9b?, 0x6d8f90c93ae8?}, {0x6d8f90e0c380?, 0x6d8f90c93b28?, 0x104bd1278?})
                /Users/wangbuke/go/pkg/mod/github.com/fastschema/qjs@v0.0.6/runtime.go:240 +0x28
        github.com/fastschema/qjs.(*Runtime).FreeQJSRuntime(0x6d8f96392000)
                /Users/wangbuke/go/pkg/mod/github.com/fastschema/qjs@v0.0.6/runtime.go:171 +0x74
        github.com/fastschema/qjs.(*Runtime).Close(0x6d8f96392000)
                /Users/wangbuke/go/pkg/mod/github.com/fastschema/qjs@v0.0.6/runtime.go:192 +0x2c
        panic({0x104fba3a0?, 0x6d8f90ab5cc0?})
                /opt/homebrew/Cellar/go/1.26.1/libexec/src/runtime/panic.go:860 +0x12c
        github.com/fastschema/qjs.(*Runtime).call(0x6d8f96392000, {0x104d89e93, 0x8}, {0x6d8f90a920f0, 0x2, 0x2})
                /Users/wangbuke/go/pkg/mod/github.com/fastschema/qjs@v0.0.6/runtime.go:321 +0x130
        github.com/fastschema/qjs.(*Runtime).Call(0x6d8f96392000, {0x104d89e93?, 0x0?}, {0x6d8f90a920f0?, 0x60000000?, 0x800000?})
                /Users/wangbuke/go/pkg/mod/github.com/fastschema/qjs@v0.0.6/runtime.go:240 +0x28
        github.com/fastschema/qjs.(*Context).Call(...)
                /Users/wangbuke/go/pkg/mod/github.com/fastschema/qjs@v0.0.6/context.go:21
        github.com/fastschema/qjs.eval(0x6d8f96394000, {0x104d8c55c, 0xe}, {0x6d8f950f1e38, 0x1, 0x104d94261?})
                /Users/wangbuke/go/pkg/mod/github.com/fastschema/qjs@v0.0.6/eval.go:31 +0x170
        github.com/fastschema/qjs.(*Context).Eval(...)
                /Users/wangbuke/go/pkg/mod/github.com/fastschema/qjs@v0.0.6/context.go:90
        main.main()
                /tmp/repro-qjs-webtooling.go:35 +0x120
         [recovered]
        panic: failed to free QJS runtime: failed to call QJS_Free: wasm error: unreachable
        wasm stack trace:
                .$273(i32)
                .$272(i32)
                .$92(i32)
        stack: goroutine 1 [running]:
        runtime/debug.Stack()
                /opt/homebrew/Cellar/go/1.26.1/libexec/src/runtime/debug/stack.go:26 +0x64
        github.com/fastschema/qjs.(*Runtime).call(0x6d8f96392000, {0x104d89e9b, 0x8}, {0x6d8f90e0c380, 0x1, 0x1})
                /Users/wangbuke/go/pkg/mod/github.com/fastschema/qjs@v0.0.6/runtime.go:320 +0xa0
        github.com/fastschema/qjs.(*Runtime).Call(0x6d8f96392000, {0x104d89e9b?, 0x6d8f90c93ae8?}, {0x6d8f90e0c380?, 0x6d8f90c93b28?, 0x104bd1278?})
                /Users/wangbuke/go/pkg/mod/github.com/fastschema/qjs@v0.0.6/runtime.go:240 +0x28
        github.com/fastschema/qjs.(*Runtime).FreeQJSRuntime(0x6d8f96392000)
                /Users/wangbuke/go/pkg/mod/github.com/fastschema/qjs@v0.0.6/runtime.go:171 +0x74
        github.com/fastschema/qjs.(*Runtime).Close(0x6d8f96392000)
                /Users/wangbuke/go/pkg/mod/github.com/fastschema/qjs@v0.0.6/runtime.go:192 +0x2c
        panic({0x104fba3a0?, 0x6d8f90ab5cc0?})
                /opt/homebrew/Cellar/go/1.26.1/libexec/src/runtime/panic.go:860 +0x12c
        github.com/fastschema/qjs.(*Runtime).call(0x6d8f96392000, {0x104d89e93, 0x8}, {0x6d8f90a920f0, 0x2, 0x2})
                /Users/wangbuke/go/pkg/mod/github.com/fastschema/qjs@v0.0.6/runtime.go:321 +0x130
        github.com/fastschema/qjs.(*Runtime).Call(0x6d8f96392000, {0x104d89e93?, 0x0?}, {0x6d8f90a920f0?, 0x60000000?, 0x800000?})
                /Users/wangbuke/go/pkg/mod/github.com/fastschema/qjs@v0.0.6/runtime.go:240 +0x28
        github.com/fastschema/qjs.(*Context).Call(...)
                /Users/wangbuke/go/pkg/mod/github.com/fastschema/qjs@v0.0.6/context.go:21
        github.com/fastschema/qjs.eval(0x6d8f96394000, {0x104d8c55c, 0xe}, {0x6d8f950f1e38, 0x1, 0x104d94261?})
                /Users/wangbuke/go/pkg/mod/github.com/fastschema/qjs@v0.0.6/eval.go:31 +0x170
        github.com/fastschema/qjs.(*Context).Eval(...)
                /Users/wangbuke/go/pkg/mod/github.com/fastschema/qjs@v0.0.6/context.go:90
        main.main()
                /tmp/repro-qjs-webtooling.go:35 +0x120


goroutine 1 [running]:
github.com/fastschema/qjs.(*Runtime).FreeQJSRuntime.func1()
        /Users/wangbuke/go/pkg/mod/github.com/fastschema/qjs@v0.0.6/runtime.go:167 +0x6c
panic({0x104fba3a0?, 0x6d8f90e263e0?})
        /opt/homebrew/Cellar/go/1.26.1/libexec/src/runtime/panic.go:860 +0x12c
github.com/fastschema/qjs.(*Runtime).call(0x6d8f96392000, {0x104d89e9b, 0x8}, {0x6d8f90e0c380, 0x1, 0x1})
        /Users/wangbuke/go/pkg/mod/github.com/fastschema/qjs@v0.0.6/runtime.go:321 +0x130
github.com/fastschema/qjs.(*Runtime).Call(0x6d8f96392000, {0x104d89e9b?, 0x6d8f90c93ae8?}, {0x6d8f90e0c380?, 0x6d8f90c93b28?, 0x104bd1278?})
        /Users/wangbuke/go/pkg/mod/github.com/fastschema/qjs@v0.0.6/runtime.go:240 +0x28
github.com/fastschema/qjs.(*Runtime).FreeQJSRuntime(0x6d8f96392000)
        /Users/wangbuke/go/pkg/mod/github.com/fastschema/qjs@v0.0.6/runtime.go:171 +0x74
github.com/fastschema/qjs.(*Runtime).Close(0x6d8f96392000)
        /Users/wangbuke/go/pkg/mod/github.com/fastschema/qjs@v0.0.6/runtime.go:192 +0x2c
panic({0x104fba3a0?, 0x6d8f90ab5cc0?})
        /opt/homebrew/Cellar/go/1.26.1/libexec/src/runtime/panic.go:860 +0x12c
github.com/fastschema/qjs.(*Runtime).call(0x6d8f96392000, {0x104d89e93, 0x8}, {0x6d8f90a920f0, 0x2, 0x2})
        /Users/wangbuke/go/pkg/mod/github.com/fastschema/qjs@v0.0.6/runtime.go:321 +0x130
github.com/fastschema/qjs.(*Runtime).Call(0x6d8f96392000, {0x104d89e93?, 0x0?}, {0x6d8f90a920f0?, 0x60000000?, 0x800000?})
        /Users/wangbuke/go/pkg/mod/github.com/fastschema/qjs@v0.0.6/runtime.go:240 +0x28
github.com/fastschema/qjs.(*Context).Call(...)
        /Users/wangbuke/go/pkg/mod/github.com/fastschema/qjs@v0.0.6/context.go:21
github.com/fastschema/qjs.eval(0x6d8f96394000, {0x104d8c55c, 0xe}, {0x6d8f950f1e38, 0x1, 0x104d94261?})
        /Users/wangbuke/go/pkg/mod/github.com/fastschema/qjs@v0.0.6/eval.go:31 +0x170
github.com/fastschema/qjs.(*Context).Eval(...)
        /Users/wangbuke/go/pkg/mod/github.com/fastschema/qjs@v0.0.6/context.go:90
main.main()
        /tmp/repro-qjs-webtooling.go:35 +0x120
exit status 2

Notes

I already tried increasing qjs runtime limits via qjs.Option:
MemoryLimit = 1536MB
MaxStackSize = 8MB
GCThreshold = 128MB
The crash still reproduces.

Thanks.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions