Skip to content

Commit 31d2556

Browse files
committed
runtime: set up read-only dummy TLS space for needm on Windows
On Windows, TLS is uninitialized for C threads calling into Go code. In this path, before calling into user Go code, we call into needm which runs without an m, but whose purpose is to pick one up. While in Go code, we may occasionally restore the G register from TLS for a number of reasons. Rather than try to flag all these cases, given that needm (and its callees) are already somewhat special, just set up a dummy TLS space for it that's read-only. If it ever actually tries to write to this space (it shouldn't), it will fail loudly. Otherwise, code that restores the G register will simply load a zero value, but that's OK since needm is careful never to require the G at any point, because it doesn't yet have a valid G. Furthermore, by the time needm returns, it will have set up TLS properly for a Windows C thread, so there's no need to do anything extra afterwards. For #40724. Change-Id: I34e8095059817e4ee663505e89cda8785b634b98 Reviewed-on: https://go-review.googlesource.com/c/go/+/307872 Trust: Michael Knyszek <[email protected]> Run-TryBot: Michael Knyszek <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Cherry Zhang <[email protected]>
1 parent 283b020 commit 31d2556

File tree

2 files changed

+29
-5
lines changed

2 files changed

+29
-5
lines changed

src/runtime/asm_amd64.s

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,14 @@ nosave:
802802
MOVL AX, ret+16(FP)
803803
RET
804804

805+
#ifdef GOOS_windows
806+
// Dummy TLS that's used on Windows so that we don't crash trying
807+
// to restore the G register in needm. needm and its callees are
808+
// very careful never to actually use the G, the TLS just can't be
809+
// unset since we're in Go code.
810+
GLOBL zeroTLS<>(SB),RODATA,$const_tlsSize
811+
#endif
812+
805813
// func cgocallback(fn, frame unsafe.Pointer, ctxt uintptr)
806814
// See cgocall.go for more details.
807815
TEXT ·cgocallback(SB),NOSPLIT,$24-24
@@ -825,6 +833,15 @@ TEXT ·cgocallback(SB),NOSPLIT,$24-24
825833
MOVQ BX, savedm-8(SP) // saved copy of oldm
826834
JMP havem
827835
needm:
836+
#ifdef GOOS_windows
837+
// Set up a dummy TLS value. needm is careful not to use it,
838+
// but it needs to be there to prevent autogenerated code from
839+
// crashing when it loads from it.
840+
// We don't need to clear it or anything later because needm
841+
// will set up TLS properly.
842+
MOVQ $zeroTLS<>(SB), DI
843+
CALL runtime·settls(SB)
844+
#endif
828845
// On some platforms (Windows) we cannot call needm through
829846
// an ABI wrapper because there's no TLS set up, and the ABI
830847
// wrapper will try to restore the G register (R14) from TLS.

src/runtime/runtime2.go

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -482,17 +482,24 @@ type g struct {
482482
gcAssistBytes int64
483483
}
484484

485+
const (
486+
// tlsSlots is the number of pointer-sized slots reserved for TLS on some platforms,
487+
// like Windows.
488+
tlsSlots = 6
489+
tlsSize = tlsSlots * sys.PtrSize
490+
)
491+
485492
type m struct {
486493
g0 *g // goroutine with scheduling stack
487494
morebuf gobuf // gobuf arg to morestack
488495
divmod uint32 // div/mod denominator for arm - known to liblink
489496

490497
// Fields not known to debuggers.
491-
procid uint64 // for debuggers, but offset not hard-coded
492-
gsignal *g // signal-handling g
493-
goSigStack gsignalStack // Go-allocated signal handling stack
494-
sigmask sigset // storage for saved signal mask
495-
tls [6]uintptr // thread-local storage (for x86 extern register)
498+
procid uint64 // for debuggers, but offset not hard-coded
499+
gsignal *g // signal-handling g
500+
goSigStack gsignalStack // Go-allocated signal handling stack
501+
sigmask sigset // storage for saved signal mask
502+
tls [tlsSlots]uintptr // thread-local storage (for x86 extern register)
496503
mstartfn func()
497504
curg *g // current running goroutine
498505
caughtsig guintptr // goroutine running during fatal signal

0 commit comments

Comments
 (0)