mirror of
https://github.com/golang/go.git
synced 2025-05-30 19:52:53 +00:00
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. Fixes #56243. 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>
168 lines
3.3 KiB
Go
168 lines
3.3 KiB
Go
// Copyright 2018 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
//go:build js && wasm
|
|
|
|
package runtime
|
|
|
|
import (
|
|
"runtime/internal/atomic"
|
|
"unsafe"
|
|
)
|
|
|
|
func exit(code int32)
|
|
|
|
func write1(fd uintptr, p unsafe.Pointer, n int32) int32 {
|
|
if fd > 2 {
|
|
throw("runtime.write to fd > 2 is unsupported")
|
|
}
|
|
wasmWrite(fd, p, n)
|
|
return n
|
|
}
|
|
|
|
// Stubs so tests can link correctly. These should never be called.
|
|
func open(name *byte, mode, perm int32) int32 { panic("not implemented") }
|
|
func closefd(fd int32) int32 { panic("not implemented") }
|
|
func read(fd int32, p unsafe.Pointer, n int32) int32 { panic("not implemented") }
|
|
|
|
//go:noescape
|
|
func wasmWrite(fd uintptr, p unsafe.Pointer, n int32)
|
|
|
|
func usleep(usec uint32)
|
|
|
|
//go:nosplit
|
|
func usleep_no_g(usec uint32) {
|
|
usleep(usec)
|
|
}
|
|
|
|
func exitThread(wait *atomic.Uint32)
|
|
|
|
type mOS struct{}
|
|
|
|
func osyield()
|
|
|
|
//go:nosplit
|
|
func osyield_no_g() {
|
|
osyield()
|
|
}
|
|
|
|
const _SIGSEGV = 0xb
|
|
|
|
func sigpanic() {
|
|
gp := getg()
|
|
if !canpanic() {
|
|
throw("unexpected signal during runtime execution")
|
|
}
|
|
|
|
// js only invokes the exception handler for memory faults.
|
|
gp.sig = _SIGSEGV
|
|
panicmem()
|
|
}
|
|
|
|
type sigset struct{}
|
|
|
|
// Called to initialize a new m (including the bootstrap m).
|
|
// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
|
|
func mpreinit(mp *m) {
|
|
mp.gsignal = malg(32 * 1024)
|
|
mp.gsignal.m = mp
|
|
}
|
|
|
|
//go:nosplit
|
|
func sigsave(p *sigset) {
|
|
}
|
|
|
|
//go:nosplit
|
|
func msigrestore(sigmask sigset) {
|
|
}
|
|
|
|
//go:nosplit
|
|
//go:nowritebarrierrec
|
|
func clearSignalHandlers() {
|
|
}
|
|
|
|
//go:nosplit
|
|
func sigblock(exiting bool) {
|
|
}
|
|
|
|
// Called to initialize a new m (including the bootstrap m).
|
|
// Called on the new thread, cannot allocate memory.
|
|
func minit() {
|
|
}
|
|
|
|
// Called from dropm to undo the effect of an minit.
|
|
func unminit() {
|
|
}
|
|
|
|
// Called from exitm, but not from drop, to undo the effect of thread-owned
|
|
// resources in minit, semacreate, or elsewhere. Do not take locks after calling this.
|
|
func mdestroy(mp *m) {
|
|
}
|
|
|
|
func osinit() {
|
|
ncpu = 1
|
|
getg().m.procid = 2
|
|
physPageSize = 64 * 1024
|
|
}
|
|
|
|
// wasm has no signals
|
|
const _NSIG = 0
|
|
|
|
func signame(sig uint32) string {
|
|
return ""
|
|
}
|
|
|
|
func crash() {
|
|
*(*int32)(nil) = 0
|
|
}
|
|
|
|
func getRandomData(r []byte)
|
|
|
|
func goenvs() {
|
|
goenvs_unix()
|
|
}
|
|
|
|
func initsig(preinit bool) {
|
|
}
|
|
|
|
// May run with m.p==nil, so write barriers are not allowed.
|
|
//
|
|
//go:nowritebarrier
|
|
func newosproc(mp *m) {
|
|
throw("newosproc: not implemented")
|
|
}
|
|
|
|
func setProcessCPUProfiler(hz int32) {}
|
|
func setThreadCPUProfiler(hz int32) {}
|
|
func sigdisable(uint32) {}
|
|
func sigenable(uint32) {}
|
|
func sigignore(uint32) {}
|
|
|
|
//go:linkname os_sigpipe os.sigpipe
|
|
func os_sigpipe() {
|
|
throw("too many writes on closed pipe")
|
|
}
|
|
|
|
//go:nosplit
|
|
func cputicks() int64 {
|
|
// Currently cputicks() is used in blocking profiler and to seed runtime·fastrand().
|
|
// runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
|
|
return nanotime()
|
|
}
|
|
|
|
//go:linkname syscall_now syscall.now
|
|
func syscall_now() (sec int64, nsec int32) {
|
|
sec, nsec, _ = time_now()
|
|
return
|
|
}
|
|
|
|
// gsignalStack is unused on js.
|
|
type gsignalStack struct{}
|
|
|
|
const preemptMSupported = false
|
|
|
|
func preemptM(mp *m) {
|
|
// No threads, so nothing to do.
|
|
}
|