aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Pratt <mpratt@google.com>2022-10-18 12:01:18 -0400
committerHeschi Kreinick <heschi@google.com>2022-10-24 17:28:39 +0000
commit0cc20ecc28d803776bdfd6ffba267b87b93b73bb (patch)
treefd72404eca4f762feae9ec966e54dd53e44a0dcb
parent8d10cc0261af3d782695b9ec68aa26214cdbcfc2 (diff)
downloadgo-0cc20ecc28d803776bdfd6ffba267b87b93b73bb.tar.gz
go-0cc20ecc28d803776bdfd6ffba267b87b93b73bb.zip
[release-branch.go1.19] runtime: always keep global reference to mp until mexit completes
Ms are allocated via standard heap allocation (`new(m)`), which means we must keep them alive (i.e., reachable by the GC) until we are completely done using them. Ms are primarily reachable through runtime.allm. However, runtime.mexit drops the M from allm fairly early, long before it is done using the M structure. If that was the last reference to the M, it is now at risk of being freed by the GC and used for some other allocation, leading to memory corruption. Ms with a Go-allocated stack coincidentally already keep a reference to the M in sched.freem, so that the stack can be freed lazily. This reference has the side effect of keeping this Ms reachable. However, Ms with an OS stack skip this and are at risk of corruption. Fix this lifetime by extending sched.freem use to all Ms, with the value of mp.freeWait determining whether the stack needs to be freed or not. For #56243. Fixes #56309. Change-Id: Ic0c01684775f5646970df507111c9abaac0ba52e Reviewed-on: https://go-review.googlesource.com/c/go/+/443716 TryBot-Result: Gopher Robot <gobot@golang.org> Run-TryBot: Michael Pratt <mpratt@google.com> Reviewed-by: Michael Knyszek <mknyszek@google.com> (cherry picked from commit e252dcf9d38ce9192bccacb7e33867cbfbd22b6c) Reviewed-on: https://go-review.googlesource.com/c/go/+/443815 Reviewed-by: Austin Clements <austin@google.com>
-rw-r--r--src/runtime/os3_solaris.go3
-rw-r--r--src/runtime/os_aix.go3
-rw-r--r--src/runtime/os_js.go3
-rw-r--r--src/runtime/os_openbsd_syscall2.go5
-rw-r--r--src/runtime/os_plan9.go2
-rw-r--r--src/runtime/os_windows.go2
-rw-r--r--src/runtime/proc.go48
-rw-r--r--src/runtime/runtime2.go9
-rw-r--r--src/runtime/stubs2.go9
-rw-r--r--src/runtime/sys_darwin.go3
-rw-r--r--src/runtime/sys_dragonfly_amd64.s2
-rw-r--r--src/runtime/sys_freebsd_386.s2
-rw-r--r--src/runtime/sys_freebsd_amd64.s2
-rw-r--r--src/runtime/sys_freebsd_arm.s2
-rw-r--r--src/runtime/sys_freebsd_arm64.s2
-rw-r--r--src/runtime/sys_linux_386.s2
-rw-r--r--src/runtime/sys_linux_amd64.s2
-rw-r--r--src/runtime/sys_linux_arm.s2
-rw-r--r--src/runtime/sys_linux_arm64.s2
-rw-r--r--src/runtime/sys_linux_loong64.s2
-rw-r--r--src/runtime/sys_linux_mips64x.s2
-rw-r--r--src/runtime/sys_linux_mipsx.s2
-rw-r--r--src/runtime/sys_linux_ppc64x.s2
-rw-r--r--src/runtime/sys_linux_riscv64.s2
-rw-r--r--src/runtime/sys_linux_s390x.s2
-rw-r--r--src/runtime/sys_netbsd_386.s2
-rw-r--r--src/runtime/sys_netbsd_amd64.s2
-rw-r--r--src/runtime/sys_netbsd_arm.s2
-rw-r--r--src/runtime/sys_netbsd_arm64.s2
-rw-r--r--src/runtime/sys_openbsd2.go3
-rw-r--r--src/runtime/sys_openbsd_mips64.s2
31 files changed, 77 insertions, 53 deletions
diff --git a/src/runtime/os3_solaris.go b/src/runtime/os3_solaris.go
index 8c85b71532..79f6b18c9a 100644
--- a/src/runtime/os3_solaris.go
+++ b/src/runtime/os3_solaris.go
@@ -7,6 +7,7 @@ package runtime
import (
"internal/abi"
"internal/goarch"
+ "runtime/internal/atomic"
"unsafe"
)
@@ -182,7 +183,7 @@ func newosproc(mp *m) {
}
}
-func exitThread(wait *uint32) {
+func exitThread(wait *atomic.Uint32) {
// We should never reach exitThread on Solaris because we let
// libc clean up threads.
throw("exitThread")
diff --git a/src/runtime/os_aix.go b/src/runtime/os_aix.go
index 15e4929779..104c397e8c 100644
--- a/src/runtime/os_aix.go
+++ b/src/runtime/os_aix.go
@@ -8,6 +8,7 @@ package runtime
import (
"internal/abi"
+ "runtime/internal/atomic"
"unsafe"
)
@@ -233,7 +234,7 @@ func newosproc(mp *m) {
}
-func exitThread(wait *uint32) {
+func exitThread(wait *atomic.Uint32) {
// We should never reach exitThread on AIX because we let
// libc clean up threads.
throw("exitThread")
diff --git a/src/runtime/os_js.go b/src/runtime/os_js.go
index 34cc0271f0..718e91e1d4 100644
--- a/src/runtime/os_js.go
+++ b/src/runtime/os_js.go
@@ -7,6 +7,7 @@
package runtime
import (
+ "runtime/internal/atomic"
"unsafe"
)
@@ -35,7 +36,7 @@ func usleep_no_g(usec uint32) {
usleep(usec)
}
-func exitThread(wait *uint32)
+func exitThread(wait *atomic.Uint32)
type mOS struct{}
diff --git a/src/runtime/os_openbsd_syscall2.go b/src/runtime/os_openbsd_syscall2.go
index e4c9d2fe89..ab6b181828 100644
--- a/src/runtime/os_openbsd_syscall2.go
+++ b/src/runtime/os_openbsd_syscall2.go
@@ -7,6 +7,7 @@
package runtime
import (
+ "runtime/internal/atomic"
"unsafe"
)
@@ -49,11 +50,11 @@ func open(name *byte, mode, perm int32) int32
// return value is only set on linux to be used in osinit()
func madvise(addr unsafe.Pointer, n uintptr, flags int32) int32
-// exitThread terminates the current thread, writing *wait = 0 when
+// exitThread terminates the current thread, writing *wait = freeMStack when
// the stack is safe to reclaim.
//
//go:noescape
-func exitThread(wait *uint32)
+func exitThread(wait *atomic.Uint32)
//go:noescape
func obsdsigprocmask(how int32, new sigset) sigset
diff --git a/src/runtime/os_plan9.go b/src/runtime/os_plan9.go
index f0e7c6ae70..1e8ef9c67b 100644
--- a/src/runtime/os_plan9.go
+++ b/src/runtime/os_plan9.go
@@ -461,7 +461,7 @@ func newosproc(mp *m) {
}
}
-func exitThread(wait *uint32) {
+func exitThread(wait *atomic.Uint32) {
// We should never reach exitThread on Plan 9 because we let
// the OS clean up threads.
throw("exitThread")
diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go
index 2f6ec75cf8..1ad7c8b790 100644
--- a/src/runtime/os_windows.go
+++ b/src/runtime/os_windows.go
@@ -941,7 +941,7 @@ func newosproc0(mp *m, stk unsafe.Pointer) {
throw("bad newosproc0")
}
-func exitThread(wait *uint32) {
+func exitThread(wait *atomic.Uint32) {
// We should never reach exitThread on Windows because we let
// the OS clean up threads.
throw("exitThread")
diff --git a/src/runtime/proc.go b/src/runtime/proc.go
index 3991a48b10..08fe441a0c 100644
--- a/src/runtime/proc.go
+++ b/src/runtime/proc.go
@@ -1516,19 +1516,18 @@ func mexit(osStack bool) {
}
throw("m not found in allm")
found:
- if !osStack {
- // Delay reaping m until it's done with the stack.
- //
- // If this is using an OS stack, the OS will free it
- // so there's no need for reaping.
- atomic.Store(&m.freeWait, 1)
- // Put m on the free list, though it will not be reaped until
- // freeWait is 0. Note that the free list must not be linked
- // through alllink because some functions walk allm without
- // locking, so may be using alllink.
- m.freelink = sched.freem
- sched.freem = m
- }
+ // Delay reaping m until it's done with the stack.
+ //
+ // Put mp on the free list, though it will not be reaped while freeWait
+ // is freeMWait. mp is no longer reachable via allm, so even if it is
+ // on an OS stack, we must keep a reference to mp alive so that the GC
+ // doesn't free mp while we are still using it.
+ //
+ // Note that the free list must not be linked through alllink because
+ // some functions walk allm without locking, so may be using alllink.
+ m.freeWait.Store(freeMWait)
+ m.freelink = sched.freem
+ sched.freem = m
unlock(&sched.lock)
atomic.Xadd64(&ncgocall, int64(m.ncgocall))
@@ -1558,6 +1557,9 @@ found:
mdestroy(m)
if osStack {
+ // No more uses of mp, so it is safe to drop the reference.
+ m.freeWait.Store(freeMRef)
+
// Return from mstart and let the system thread
// library free the g0 stack and terminate the thread.
return
@@ -1729,19 +1731,25 @@ func allocm(_p_ *p, fn func(), id int64) *m {
lock(&sched.lock)
var newList *m
for freem := sched.freem; freem != nil; {
- if freem.freeWait != 0 {
+ wait := freem.freeWait.Load()
+ if wait == freeMWait {
next := freem.freelink
freem.freelink = newList
newList = freem
freem = next
continue
}
- // stackfree must be on the system stack, but allocm is
- // reachable off the system stack transitively from
- // startm.
- systemstack(func() {
- stackfree(freem.g0.stack)
- })
+ // Free the stack if needed. For freeMRef, there is
+ // nothing to do except drop freem from the sched.freem
+ // list.
+ if wait == freeMStack {
+ // stackfree must be on the system stack, but allocm is
+ // reachable off the system stack transitively from
+ // startm.
+ systemstack(func() {
+ stackfree(freem.g0.stack)
+ })
+ }
freem = freem.freelink
}
sched.freem = newList
diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go
index e1788223e7..2a42809f0d 100644
--- a/src/runtime/runtime2.go
+++ b/src/runtime/runtime2.go
@@ -516,6 +516,13 @@ const (
tlsSize = tlsSlots * goarch.PtrSize
)
+// Values for m.freeWait.
+const (
+ freeMStack = 0 // M done, free stack and reference.
+ freeMRef = 1 // M done, free reference.
+ freeMWait = 2 // M still in use.
+)
+
type m struct {
g0 *g // goroutine with scheduling stack
morebuf gobuf // gobuf arg to morestack
@@ -546,7 +553,7 @@ type m struct {
newSigstack bool // minit on C thread called sigaltstack
printlock int8
incgo bool // m is executing a cgo call
- freeWait uint32 // if == 0, safe to free g0 and delete m (atomic)
+ freeWait atomic.Uint32 // Whether it is safe to free g0 and delete m (one of freeMRef, freeMStack, freeMWait)
fastrand uint64
needextram bool
traceback uint8
diff --git a/src/runtime/stubs2.go b/src/runtime/stubs2.go
index 94a888dec6..d2ad8d4ec8 100644
--- a/src/runtime/stubs2.go
+++ b/src/runtime/stubs2.go
@@ -6,7 +6,10 @@
package runtime
-import "unsafe"
+import (
+ "runtime/internal/atomic"
+ "unsafe"
+)
// read calls the read system call.
// It returns a non-negative number of bytes written or a negative errno value.
@@ -34,8 +37,8 @@ func open(name *byte, mode, perm int32) int32
// return value is only set on linux to be used in osinit()
func madvise(addr unsafe.Pointer, n uintptr, flags int32) int32
-// exitThread terminates the current thread, writing *wait = 0 when
+// exitThread terminates the current thread, writing *wait = freeMStack when
// the stack is safe to reclaim.
//
//go:noescape
-func exitThread(wait *uint32)
+func exitThread(wait *atomic.Uint32)
diff --git a/src/runtime/sys_darwin.go b/src/runtime/sys_darwin.go
index 1547fdceb0..88af894409 100644
--- a/src/runtime/sys_darwin.go
+++ b/src/runtime/sys_darwin.go
@@ -6,6 +6,7 @@ package runtime
import (
"internal/abi"
+ "runtime/internal/atomic"
"unsafe"
)
@@ -474,7 +475,7 @@ func pthread_cond_signal(c *pthreadcond) int32 {
func pthread_cond_signal_trampoline()
// Not used on Darwin, but must be defined.
-func exitThread(wait *uint32) {
+func exitThread(wait *atomic.Uint32) {
}
//go:nosplit
diff --git a/src/runtime/sys_dragonfly_amd64.s b/src/runtime/sys_dragonfly_amd64.s
index 602d5e9b76..0cf98219fb 100644
--- a/src/runtime/sys_dragonfly_amd64.s
+++ b/src/runtime/sys_dragonfly_amd64.s
@@ -65,7 +65,7 @@ TEXT runtime·exit(SB),NOSPLIT,$-8
MOVL $0xf1, 0xf1 // crash
RET
-// func exitThread(wait *uint32)
+// func exitThread(wait *atomic.Uint32)
TEXT runtime·exitThread(SB),NOSPLIT,$0-8
MOVQ wait+0(FP), AX
// We're done using the stack.
diff --git a/src/runtime/sys_freebsd_386.s b/src/runtime/sys_freebsd_386.s
index 9e5210b0db..d10eb3fa4b 100644
--- a/src/runtime/sys_freebsd_386.s
+++ b/src/runtime/sys_freebsd_386.s
@@ -63,7 +63,7 @@ GLOBL exitStack<>(SB),RODATA,$8
DATA exitStack<>+0x00(SB)/4, $0
DATA exitStack<>+0x04(SB)/4, $0
-// func exitThread(wait *uint32)
+// func exitThread(wait *atomic.Uint32)
TEXT runtime·exitThread(SB),NOSPLIT,$0-4
MOVL wait+0(FP), AX
// We're done using the stack.
diff --git a/src/runtime/sys_freebsd_amd64.s b/src/runtime/sys_freebsd_amd64.s
index 94341f6d4e..9f48d58514 100644
--- a/src/runtime/sys_freebsd_amd64.s
+++ b/src/runtime/sys_freebsd_amd64.s
@@ -60,7 +60,7 @@ TEXT runtime·exit(SB),NOSPLIT,$-8
MOVL $0xf1, 0xf1 // crash
RET
-// func exitThread(wait *uint32)
+// func exitThread(wait *atomic.uint32)
TEXT runtime·exitThread(SB),NOSPLIT,$0-8
MOVQ wait+0(FP), AX
// We're done using the stack.
diff --git a/src/runtime/sys_freebsd_arm.s b/src/runtime/sys_freebsd_arm.s
index cbee34d13b..a6099b465c 100644
--- a/src/runtime/sys_freebsd_arm.s
+++ b/src/runtime/sys_freebsd_arm.s
@@ -85,7 +85,7 @@ TEXT runtime·exit(SB),NOSPLIT|NOFRAME,$0
MOVW.CS R8, (R8)
RET
-// func exitThread(wait *uint32)
+// func exitThread(wait *atomic.Uint32)
TEXT runtime·exitThread(SB),NOSPLIT,$0-4
MOVW wait+0(FP), R0
// We're done using the stack.
diff --git a/src/runtime/sys_freebsd_arm64.s b/src/runtime/sys_freebsd_arm64.s
index 5dcdf375ab..4143a8f1eb 100644
--- a/src/runtime/sys_freebsd_arm64.s
+++ b/src/runtime/sys_freebsd_arm64.s
@@ -99,7 +99,7 @@ TEXT runtime·exit(SB),NOSPLIT|NOFRAME,$0-4
MOVD $0, R0
MOVD R0, (R0)
-// func exitThread(wait *uint32)
+// func exitThread(wait *atomic.Uint32)
TEXT runtime·exitThread(SB),NOSPLIT|NOFRAME,$0-8
MOVD wait+0(FP), R0
// We're done using the stack.
diff --git a/src/runtime/sys_linux_386.s b/src/runtime/sys_linux_386.s
index 4942f21e4f..e7d9198831 100644
--- a/src/runtime/sys_linux_386.s
+++ b/src/runtime/sys_linux_386.s
@@ -77,7 +77,7 @@ TEXT exit1<>(SB),NOSPLIT,$0
INT $3 // not reached
RET
-// func exitThread(wait *uint32)
+// func exitThread(wait *atomic.Uint32)
TEXT runtime·exitThread(SB),NOSPLIT,$0-4
MOVL wait+0(FP), AX
// We're done using the stack.
diff --git a/src/runtime/sys_linux_amd64.s b/src/runtime/sys_linux_amd64.s
index ca6ecb13eb..242517a863 100644
--- a/src/runtime/sys_linux_amd64.s
+++ b/src/runtime/sys_linux_amd64.s
@@ -59,7 +59,7 @@ TEXT runtime·exit(SB),NOSPLIT,$0-4
SYSCALL
RET
-// func exitThread(wait *uint32)
+// func exitThread(wait *atomic.Uint32)
TEXT runtime·exitThread(SB),NOSPLIT,$0-8
MOVQ wait+0(FP), AX
// We're done using the stack.
diff --git a/src/runtime/sys_linux_arm.s b/src/runtime/sys_linux_arm.s
index 66bf40328e..b0250936f4 100644
--- a/src/runtime/sys_linux_arm.s
+++ b/src/runtime/sys_linux_arm.s
@@ -122,7 +122,7 @@ TEXT exit1<>(SB),NOSPLIT|NOFRAME,$0
MOVW $1003, R1
MOVW R0, (R1) // fail hard
-// func exitThread(wait *uint32)
+// func exitThread(wait *atomic.Uint32)
TEXT runtime·exitThread(SB),NOSPLIT|NOFRAME,$0-4
MOVW wait+0(FP), R0
// We're done using the stack.
diff --git a/src/runtime/sys_linux_arm64.s b/src/runtime/sys_linux_arm64.s
index b47b6fd0a0..7cfd818efc 100644
--- a/src/runtime/sys_linux_arm64.s
+++ b/src/runtime/sys_linux_arm64.s
@@ -60,7 +60,7 @@ TEXT runtime·exit(SB),NOSPLIT|NOFRAME,$0-4
SVC
RET
-// func exitThread(wait *uint32)
+// func exitThread(wait *atomic.Uint32)
TEXT runtime·exitThread(SB),NOSPLIT|NOFRAME,$0-8
MOVD wait+0(FP), R0
// We're done using the stack.
diff --git a/src/runtime/sys_linux_loong64.s b/src/runtime/sys_linux_loong64.s
index 36a92df87c..1ebc77bff3 100644
--- a/src/runtime/sys_linux_loong64.s
+++ b/src/runtime/sys_linux_loong64.s
@@ -53,7 +53,7 @@ TEXT runtime·exit(SB),NOSPLIT|NOFRAME,$0-4
SYSCALL
RET
-// func exitThread(wait *uint32)
+// func exitThread(wait *atomic.Uint32)
TEXT runtime·exitThread(SB),NOSPLIT|NOFRAME,$0-8
MOVV wait+0(FP), R19
// We're done using the stack.
diff --git a/src/runtime/sys_linux_mips64x.s b/src/runtime/sys_linux_mips64x.s
index 06d54dff78..e38f444e28 100644
--- a/src/runtime/sys_linux_mips64x.s
+++ b/src/runtime/sys_linux_mips64x.s
@@ -56,7 +56,7 @@ TEXT runtime·exit(SB),NOSPLIT|NOFRAME,$0-4
SYSCALL
RET
-// func exitThread(wait *uint32)
+// func exitThread(wait *atomic.Uint32)
TEXT runtime·exitThread(SB),NOSPLIT|NOFRAME,$0-8
MOVV wait+0(FP), R1
// We're done using the stack.
diff --git a/src/runtime/sys_linux_mipsx.s b/src/runtime/sys_linux_mipsx.s
index e70edcc0e2..8f958193b6 100644
--- a/src/runtime/sys_linux_mipsx.s
+++ b/src/runtime/sys_linux_mipsx.s
@@ -55,7 +55,7 @@ TEXT runtime·exit(SB),NOSPLIT,$0-4
UNDEF
RET
-// func exitThread(wait *uint32)
+// func exitThread(wait *atomic.Uint32)
TEXT runtime·exitThread(SB),NOSPLIT,$0-4
MOVW wait+0(FP), R1
// We're done using the stack.
diff --git a/src/runtime/sys_linux_ppc64x.s b/src/runtime/sys_linux_ppc64x.s
index 2913a05f56..6e9d8f56f1 100644
--- a/src/runtime/sys_linux_ppc64x.s
+++ b/src/runtime/sys_linux_ppc64x.s
@@ -54,7 +54,7 @@ TEXT runtime·exit(SB),NOSPLIT|NOFRAME,$0-4
SYSCALL $SYS_exit_group
RET
-// func exitThread(wait *uint32)
+// func exitThread(wait *atomic.Uint32)
TEXT runtime·exitThread(SB),NOSPLIT|NOFRAME,$0-8
MOVD wait+0(FP), R1
// We're done using the stack.
diff --git a/src/runtime/sys_linux_riscv64.s b/src/runtime/sys_linux_riscv64.s
index afb2d11da9..8d922b3344 100644
--- a/src/runtime/sys_linux_riscv64.s
+++ b/src/runtime/sys_linux_riscv64.s
@@ -61,7 +61,7 @@ TEXT runtime·exit(SB),NOSPLIT|NOFRAME,$0-4
ECALL
RET
-// func exitThread(wait *uint32)
+// func exitThread(wait *atomic.Uint32)
TEXT runtime·exitThread(SB),NOSPLIT|NOFRAME,$0-8
MOV wait+0(FP), A0
// We're done using the stack.
diff --git a/src/runtime/sys_linux_s390x.s b/src/runtime/sys_linux_s390x.s
index c82cb9b4aa..a5fde911e6 100644
--- a/src/runtime/sys_linux_s390x.s
+++ b/src/runtime/sys_linux_s390x.s
@@ -51,7 +51,7 @@ TEXT runtime·exit(SB),NOSPLIT|NOFRAME,$0-4
SYSCALL
RET
-// func exitThread(wait *uint32)
+// func exitThread(wait *atomic.Uint32)
TEXT runtime·exitThread(SB),NOSPLIT|NOFRAME,$0-8
MOVD wait+0(FP), R1
// We're done using the stack.
diff --git a/src/runtime/sys_netbsd_386.s b/src/runtime/sys_netbsd_386.s
index 581b4fc9b6..7be18c61d8 100644
--- a/src/runtime/sys_netbsd_386.s
+++ b/src/runtime/sys_netbsd_386.s
@@ -53,7 +53,7 @@ TEXT runtime·exit(SB),NOSPLIT,$-4
MOVL $0xf1, 0xf1 // crash
RET
-// func exitThread(wait *uint32)
+// func exitThread(wait *atomic.Uint32)
TEXT runtime·exitThread(SB),NOSPLIT,$0-4
MOVL wait+0(FP), AX
// We're done using the stack.
diff --git a/src/runtime/sys_netbsd_amd64.s b/src/runtime/sys_netbsd_amd64.s
index ab11f6ff66..30f3f380b6 100644
--- a/src/runtime/sys_netbsd_amd64.s
+++ b/src/runtime/sys_netbsd_amd64.s
@@ -122,7 +122,7 @@ TEXT runtime·exit(SB),NOSPLIT,$-8
MOVL $0xf1, 0xf1 // crash
RET
-// func exitThread(wait *uint32)
+// func exitThread(wait *atomic.Uint32)
TEXT runtime·exitThread(SB),NOSPLIT,$0-8
MOVQ wait+0(FP), AX
// We're done using the stack.
diff --git a/src/runtime/sys_netbsd_arm.s b/src/runtime/sys_netbsd_arm.s
index dbe3dbcffc..62fa852add 100644
--- a/src/runtime/sys_netbsd_arm.s
+++ b/src/runtime/sys_netbsd_arm.s
@@ -56,7 +56,7 @@ TEXT runtime·exit(SB),NOSPLIT|NOFRAME,$0
MOVW.CS R8, (R8)
RET
-// func exitThread(wait *uint32)
+// func exitThread(wait *atomic.Uint32)
TEXT runtime·exitThread(SB),NOSPLIT,$0-4
MOVW wait+0(FP), R0
// We're done using the stack.
diff --git a/src/runtime/sys_netbsd_arm64.s b/src/runtime/sys_netbsd_arm64.s
index fc126cad7d..d57959f8d7 100644
--- a/src/runtime/sys_netbsd_arm64.s
+++ b/src/runtime/sys_netbsd_arm64.s
@@ -115,7 +115,7 @@ TEXT runtime·exit(SB),NOSPLIT,$-8
MOVD $0, R0 // If we're still running,
MOVD R0, (R0) // crash
-// func exitThread(wait *uint32)
+// func exitThread(wait *atomic.Uint32)
TEXT runtime·exitThread(SB),NOSPLIT,$0-8
MOVD wait+0(FP), R0
// We're done using the stack.
diff --git a/src/runtime/sys_openbsd2.go b/src/runtime/sys_openbsd2.go
index f936e0cfc3..f755cd528c 100644
--- a/src/runtime/sys_openbsd2.go
+++ b/src/runtime/sys_openbsd2.go
@@ -8,6 +8,7 @@ package runtime
import (
"internal/abi"
+ "runtime/internal/atomic"
"unsafe"
)
@@ -248,7 +249,7 @@ func sigaltstack(new *stackt, old *stackt) {
func sigaltstack_trampoline()
// Not used on OpenBSD, but must be defined.
-func exitThread(wait *uint32) {
+func exitThread(wait *atomic.Uint32) {
}
//go:nosplit
diff --git a/src/runtime/sys_openbsd_mips64.s b/src/runtime/sys_openbsd_mips64.s
index c2b2092053..cc37e52e16 100644
--- a/src/runtime/sys_openbsd_mips64.s
+++ b/src/runtime/sys_openbsd_mips64.s
@@ -24,7 +24,7 @@ TEXT runtime·exit(SB),NOSPLIT|NOFRAME,$0
MOVV R2, (R2)
RET
-// func exitThread(wait *uint32)
+// func exitThread(wait *atomic.Uint32)
TEXT runtime·exitThread(SB),NOSPLIT,$0
MOVV wait+0(FP), R4 // arg 1 - notdead
MOVV $302, R2 // sys___threxit