Skip to content

GOOS=js GOARCH=wasm: found bad pointer in Go heap #370

@paralin

Description

@paralin

This crash occurs on GOOS=js GOARCH=wasm go test -v ./ with #369 applied.

Full trace: https://gist.github.com/paralin/80238f87edda717fd38fcc96d6e99c8f

GC crash on js/wasm: "found bad pointer in Go heap" due to scannable wasm linear memory

The problem is in internal/sqlite3_wrap/mem_other.go, which is the memory implementation used on js/wasm (gated by //go:build !unix && !windows). It allocates the wasm linear memory buffer as a plain []byte Go slice via append:

m.Buf = append(m.Buf, make([]byte, add)...)

This slice is on the Go heap and is scanned by the GC during mark phase. The generated wasm code writes SQLite internal data (page pointers, btree nodes, hash values, offsets, etc.) into this buffer using store32, which does *(*uint32)(unsafe.Pointer((*[4]byte)(b))) = v. On wasm, pointers are 32-bit, so uint32 is pointer-sized. The GC interprets these arbitrary uint32 values as potential Go pointers. When one of them happens to point into an unallocated or freed heap span, the GC panics.

The unix and windows implementations avoid this entirely: mem_unix.go uses unix.Mmap with MAP_PRIVATE|MAP_ANON and mem_windows.go uses windows.VirtualAlloc, both of which allocate memory outside the Go heap so the GC never scans it.

The crash stack trace shows:

    runtime: pointer 0x292e0000 to unallocated span span.base()=0x2dbe000 span.limit=0x2e3e000 span.state=0
    fatal error: found bad pointer in Go heap (incorrect use of unsafe or cgo?)
    
    runtime.wbBufFlush1 -> runtime.findObject -> runtime.badPointer

The faulting goroutine is always a GC worker scanning the Buf slice contents.

The fix should allocate the wasm linear memory in mem_other.go in a way that the GC does not scan it for pointers, similar to what mmap/VirtualAlloc achieve on other platforms.

Reproducible with: GOOS=js GOARCH=wasm go test -count=1 ./tests/

Go version: go1.27-devel (tip), tested with wasmbrowsertest.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions