Skip to content

runtime, syscall/js: passing a JS pointer to Go-Wasm runtime causes memory leak #74342

Open
@kyoncal

Description

@kyoncal

Go version

go version go1.24.0 darwin/arm64

Output of go env in your module/workspace:

AR='ar'
CC='clang'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_ENABLED='1'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
CXX='clang++'
GCCGO='gccgo'
GO111MODULE=''
GOARCH='arm64'
GOARM64='v8.0'
GOAUTH='netrc'
GOBIN=''
GOCACHE='/Users/kyon/Library/Caches/go-build'
GOCACHEPROG=''
GODEBUG=''
GOENV='/Users/kyon/Library/Application Support/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -ffile-prefix-map=/var/folders/nm/73wzznv13ld2vcfxd12d24k40000gn/T/go-build1372434015=/tmp/go-build -gno-record-gcc-switches -fno-common'
GOHOSTARCH='arm64'
GOHOSTOS='darwin'
GOINSECURE=''
GOMOD='/Users/kyon/Code/Tiledmedia/core/go.mod'
GOMODCACHE='/Users/kyon/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='darwin'
GOPATH='/Users/kyon/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/Users/kyon/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.24.0.darwin-arm64'
GOSUMDB='sum.golang.org'
GOTELEMETRY='local'
GOTELEMETRYDIR='/Users/kyon/Library/Application Support/go/telemetry'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/Users/kyon/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.24.0.darwin-arm64/pkg/tool/darwin_arm64'
GOVCS=''
GOVERSION='go1.24.0'
GOWORK=''
PKG_CONFIG='pkg-config'

What did you do?

GOOS=js GOARCH=wasm go build -o main.wasm main.go && goexec 'http.ListenAndServe(\`:8080\`, http.FileServer(http.Dir(`.`)))'

A minimal repro is provided here: https://github.com/kyoncal/go-wasm-memory-leak

What did you see happen?

Running the sample program using the command provided leads to a memory leak in both Chrome and Firefox. The value of the pointer passed to the wasm function goFunction is never cleared. In the sample program provided, the memory usage will grow forever.

Image

What did you expect to see?

I expect to see the memory get cleared eventually, however it grows forever. There are work arounds that allow the memory to get garbage collected, such as wrapping the pointer in a JS object, and setting the field to undefined afterwards, however, this is certainly not intended behavior.

Metadata

Metadata

Assignees

Labels

BugReportIssues describing a possible bug in the Go implementation.NeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.OS-JSarch-wasmWebAssembly issuescompiler/runtimeIssues related to the Go compiler and/or runtime.

Type

No type

Projects

Status

Todo

Relationships

None yet

Development

No branches or pull requests

Issue actions