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.
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[]byteGo slice viaappend: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, souint32is 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.gousesunix.MmapwithMAP_PRIVATE|MAP_ANONandmem_windows.gouseswindows.VirtualAlloc, both of which allocate memory outside the Go heap so the GC never scans it.The crash stack trace shows:
The faulting goroutine is always a GC worker scanning the
Bufslice contents.The fix should allocate the wasm linear memory in
mem_other.goin 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.