runtime: don't emit write barrier for code pointers in itabInit
itabInit filled m.Fun by storing code pointers through an
unsafe.Pointer slice, which makes the compiler emit a write barrier.
On wasm a code PC is a function index shifted left 16 bits, a small
value that can fall inside a live heap span, so the GC mistakes it
for a bad heap pointer and crashes.
Store through a uintptr slice instead so no write barrier is emitted,
and mark itabInit //go:nowritebarrier so the same mistake fails to
compile.
Fixes #80472
diff --git a/src/runtime/iface.go b/src/runtime/iface.go
index 009f104..e853625 100644
--- a/src/runtime/iface.go
+++ b/src/runtime/iface.go
@@ -201,6 +201,11 @@
// If !firstTime, itabInit will not write anything to m.Fun (see issue 65962).
// It is ok to call this multiple times on the same m, even concurrently
// (although it will only be called once with firstTime==true).
+//
+// itabInit stores only code pointers, so it must not emit a write barrier;
+// //go:nowritebarrier enforces that (see the methods store below).
+//
+//go:nowritebarrier
func itabInit(m *itab, firstTime bool) string {
inter := m.Inter
typ := m.Type
@@ -214,7 +219,10 @@
nt := int(x.Mcount)
xmhdr := unsafe.Slice((*abi.Method)(add(unsafe.Pointer(x), uintptr(x.Moff))), nt)
j := 0
- methods := unsafe.Slice((*unsafe.Pointer)(unsafe.Pointer(&m.Fun[0])), ni)
+ // These are code pointers, not heap pointers. Use a uintptr slice so the
+ // store emits no write barrier: on wasm a code pointer can look like a
+ // heap pointer and make the GC crash (see issue 80472).
+ methods := unsafe.Slice((*uintptr)(unsafe.Pointer(&m.Fun[0])), ni)
var fun0 unsafe.Pointer
imethods:
for k := 0; k < ni; k++ {
@@ -240,7 +248,7 @@
if k == 0 {
fun0 = ifn // we'll set m.Fun[0] at the end
} else if firstTime {
- methods[k] = ifn
+ methods[k] = uintptr(ifn)
}
continue imethods
}
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Auto-Submit | +1 |
| Code-Review | +2 |
| Commit-Queue | +1 |
methods := unsafe.Slice((*uintptr)(unsafe.Pointer(&m.Fun[0])), ni)This can all be just `&m.Fun[0]`, I think.
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Auto-Submit | +1 |
| Code-Review | +2 |
| Commit-Queue | +1 |
methods := unsafe.Slice((*uintptr)(unsafe.Pointer(&m.Fun[0])), ni)This can all be just `&m.Fun[0]`, I think.
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Code-Review | +1 |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
runtime: don't emit write barrier for code pointers in itabInit
itabInit filled m.Fun by storing code pointers through an
unsafe.Pointer slice, which makes the compiler emit a write barrier.
On wasm a code PC is a function index shifted left 16 bits, a small
value that can fall inside a live heap span, so the GC mistakes it
for a bad heap pointer and crashes.
Store through a uintptr slice instead so no write barrier is emitted,
and mark itabInit //go:nowritebarrier so the same mistake fails to
compile.
Fixes #80472
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
[release-branch.go1.27] runtime: don't emit write barrier for code pointers in itabInit
itabInit filled m.Fun by storing code pointers through an
unsafe.Pointer slice, which makes the compiler emit a write barrier.
On wasm a code PC is a function index shifted left 16 bits, a small
value that can fall inside a live heap span, so the GC mistakes it
for a bad heap pointer and crashes.
Store through a uintptr slice instead so no write barrier is emitted,
and mark itabInit //go:nowritebarrier so the same mistake fails to
compile.
Fixes #80498
Change-Id: If9532c01b66b8c4ceb47c932017569488b6143d5
GitHub-Last-Rev: 6e1374c083518bb9f994092acca4f5ea28b38dfa
GitHub-Pull-Request: golang/go#80487
Reviewed-on: https://go-review.googlesource.com/c/go/+/803460
Reviewed-by: Keith Randall <k...@google.com>
Auto-Submit: Keith Randall <k...@golang.org>
Reviewed-by: Carlos Amedee <car...@golang.org>
LUCI-TryBot-Result: golang...@luci-project-accounts.iam.gserviceaccount.com <golang...@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Keith Randall <k...@golang.org>
(cherry picked from commit 9d2ed75ac043fb1589082f51bc43d927d6c3f1c4)
diff --git a/src/runtime/iface.go b/src/runtime/iface.go
index 009f104..6385d1c 100644
--- a/src/runtime/iface.go
+++ b/src/runtime/iface.go
@@ -201,6 +201,11 @@
// If !firstTime, itabInit will not write anything to m.Fun (see issue 65962).
// It is ok to call this multiple times on the same m, even concurrently
// (although it will only be called once with firstTime==true).
+//
+// itabInit stores only code pointers, so it must not emit a write barrier;
+// //go:nowritebarrier enforces that (see the methods store below).
+//
+//go:nowritebarrier
func itabInit(m *itab, firstTime bool) string {
inter := m.Inter
typ := m.Type
@@ -214,7 +219,10 @@
nt := int(x.Mcount)
xmhdr := unsafe.Slice((*abi.Method)(add(unsafe.Pointer(x), uintptr(x.Moff))), nt)
j := 0
- methods := unsafe.Slice((*unsafe.Pointer)(unsafe.Pointer(&m.Fun[0])), ni)
+ // These are code pointers, not heap pointers. Use a uintptr slice so the
+ // store emits no write barrier: on wasm a code pointer can look like a
+ // heap pointer and make the GC crash (see issue 80472).
+ methods := unsafe.Slice(&m.Fun[0], ni)
var fun0 unsafe.Pointer
imethods:
for k := 0; k < ni; k++ {
@@ -240,7 +248,7 @@
if k == 0 {
fun0 = ifn // we'll set m.Fun[0] at the end
} else if firstTime {
- methods[k] = ifn
+ methods[k] = uintptr(ifn)
}
continue imethods
}
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
[release-branch.go1.25] runtime: don't emit write barrier for code pointers in itabInit
itabInit filled m.Fun by storing code pointers through an
unsafe.Pointer slice, which makes the compiler emit a write barrier.
On wasm a code PC is a function index shifted left 16 bits, a small
value that can fall inside a live heap span, so the GC mistakes it
for a bad heap pointer and crashes.
Store through a uintptr slice instead so no write barrier is emitted,
and mark itabInit //go:nowritebarrier so the same mistake fails to
compile.
Fixes #80500
diff --git a/src/runtime/iface.go b/src/runtime/iface.go
index 0665c4b..b810dae 100644
--- a/src/runtime/iface.go
+++ b/src/runtime/iface.go
@@ -201,6 +201,11 @@
// If !firstTime, itabInit will not write anything to m.Fun (see issue 65962).
// It is ok to call this multiple times on the same m, even concurrently
// (although it will only be called once with firstTime==true).
+//
+// itabInit stores only code pointers, so it must not emit a write barrier;
+// //go:nowritebarrier enforces that (see the methods store below).
+//
+//go:nowritebarrier
func itabInit(m *itab, firstTime bool) string {
inter := m.Inter
typ := m.Type
@@ -214,7 +219,10 @@
nt := int(x.Mcount)
xmhdr := (*[1 << 16]abi.Method)(add(unsafe.Pointer(x), uintptr(x.Moff)))[:nt:nt]
j := 0
- methods := (*[1 << 16]unsafe.Pointer)(unsafe.Pointer(&m.Fun[0]))[:ni:ni]
+ // These are code pointers, not heap pointers. Use a uintptr slice so the
+ // store emits no write barrier: on wasm a code pointer can look like a
+ // heap pointer and make the GC crash (see issue 80472).
+ methods := (*[1 << 16]uintptr)(unsafe.Pointer(&m.Fun[0]))[:ni:ni]
var fun0 unsafe.Pointer
imethods:
for k := 0; k < ni; k++ {
@@ -240,7 +248,7 @@
if k == 0 {
fun0 = ifn // we'll set m.Fun[0] at the end
} else if firstTime {
- methods[k] = ifn
+ methods[k] = uintptr(ifn)
}
continue imethods
}
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
[release-branch.go1.26] runtime: don't emit write barrier for code pointers in itabInit
itabInit filled m.Fun by storing code pointers through an
unsafe.Pointer slice, which makes the compiler emit a write barrier.
On wasm a code PC is a function index shifted left 16 bits, a small
value that can fall inside a live heap span, so the GC mistakes it
for a bad heap pointer and crashes.
Store through a uintptr slice instead so no write barrier is emitted,
and mark itabInit //go:nowritebarrier so the same mistake fails to
compile.
Fixes #80499