]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: set up read-only dummy TLS space for needm on Windows
authorMichael Anthony Knyszek <mknyszek@google.com>
Wed, 7 Apr 2021 19:58:01 +0000 (19:58 +0000)
committerMichael Knyszek <mknyszek@google.com>
Thu, 8 Apr 2021 16:37:24 +0000 (16:37 +0000)
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 <mknyszek@google.com>
Run-TryBot: Michael Knyszek <mknyszek@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
src/runtime/asm_amd64.s
src/runtime/runtime2.go

index c0bfcb7ade7778ae314602d6c45956e373677133..cc31e5c657619773946e4382c754dcaad016dde4 100644 (file)
@@ -802,6 +802,14 @@ nosave:
        MOVL    AX, ret+16(FP)
        RET
 
+#ifdef GOOS_windows
+// Dummy TLS that's used on Windows so that we don't crash trying
+// to restore the G register in needm. needm and its callees are
+// very careful never to actually use the G, the TLS just can't be
+// unset since we're in Go code.
+GLOBL zeroTLS<>(SB),RODATA,$const_tlsSize
+#endif
+
 // func cgocallback(fn, frame unsafe.Pointer, ctxt uintptr)
 // See cgocall.go for more details.
 TEXT ·cgocallback(SB),NOSPLIT,$24-24
@@ -825,6 +833,15 @@ TEXT ·cgocallback(SB),NOSPLIT,$24-24
        MOVQ    BX, savedm-8(SP)        // saved copy of oldm
        JMP     havem
 needm:
+#ifdef GOOS_windows
+       // Set up a dummy TLS value. needm is careful not to use it,
+       // but it needs to be there to prevent autogenerated code from
+       // crashing when it loads from it.
+       // We don't need to clear it or anything later because needm
+       // will set up TLS properly.
+       MOVQ    $zeroTLS<>(SB), DI
+       CALL    runtime·settls(SB)
+#endif
        // On some platforms (Windows) we cannot call needm through
        // an ABI wrapper because there's no TLS set up, and the ABI
        // wrapper will try to restore the G register (R14) from TLS.
index e5f948ec8612bfbc598272c6488bbce81b02c8c4..402d49ac820626cd761a96fef566c0e7d976d47b 100644 (file)
@@ -482,17 +482,24 @@ type g struct {
        gcAssistBytes int64
 }
 
+const (
+       // tlsSlots is the number of pointer-sized slots reserved for TLS on some platforms,
+       // like Windows.
+       tlsSlots = 6
+       tlsSize  = tlsSlots * sys.PtrSize
+)
+
 type m struct {
        g0      *g     // goroutine with scheduling stack
        morebuf gobuf  // gobuf arg to morestack
        divmod  uint32 // div/mod denominator for arm - known to liblink
 
        // Fields not known to debuggers.
-       procid        uint64       // for debuggers, but offset not hard-coded
-       gsignal       *g           // signal-handling g
-       goSigStack    gsignalStack // Go-allocated signal handling stack
-       sigmask       sigset       // storage for saved signal mask
-       tls           [6]uintptr   // thread-local storage (for x86 extern register)
+       procid        uint64            // for debuggers, but offset not hard-coded
+       gsignal       *g                // signal-handling g
+       goSigStack    gsignalStack      // Go-allocated signal handling stack
+       sigmask       sigset            // storage for saved signal mask
+       tls           [tlsSlots]uintptr // thread-local storage (for x86 extern register)
        mstartfn      func()
        curg          *g       // current running goroutine
        caughtsig     guintptr // goroutine running during fatal signal