]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: initialize g0 stack bounds on Windows to full stack
authorAustin Clements <austin@google.com>
Wed, 20 Jun 2018 20:25:41 +0000 (16:25 -0400)
committerAustin Clements <austin@google.com>
Mon, 2 Jul 2018 15:18:24 +0000 (15:18 +0000)
Currently, we allocate 1MB or 2MB thread stacks on Windows, but in
non-cgo binaries still set the g0 stack bounds assuming only 64k is
available. While this is fine in pure Go binaries, a non-cgo Go binary
on Windows can use the syscall package to call arbitrary DLLs, which
may call back into Go. If a DLL function uses more than 64k of stack
and then calls back into Go, the Go runtime will believe that it's out
of stack space and crash.

Fix this by plumbing the correct stack size into the g0 stacks of
non-cgo binaries. Cgo binaries already use the correct size because
their g0 stack sizes are set by a different code path.

Fixes #20975.

Change-Id: Id6fb559cfe1e1ea0dfac56d4654865c20dccf68d
Reviewed-on: https://go-review.googlesource.com/120195
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/cmd/link/internal/ld/pe.go
src/runtime/cgo/gcc_windows_386.c
src/runtime/cgo/gcc_windows_amd64.c
src/runtime/os_windows.go
src/runtime/sys_windows_386.s
src/runtime/sys_windows_amd64.s

index 85acb7a11b0b4565b02d10c87b1d28604d2ae480..3b7df9aef863cbbb7aaeb1d14382d80351d66b72 100644 (file)
@@ -852,8 +852,8 @@ func (f *peFile) writeOptionalHeader(ctxt *Link) {
        //
        // For other threads we specify stack size in runtime explicitly.
        // For these, the reserve must match STACKSIZE in
-       // runtime/cgo/gcc_windows_{386,amd64}.c and the correspondent
-       // CreateThread parameter in runtime.newosproc.
+       // runtime/cgo/gcc_windows_{386,amd64}.c and osStackSize in
+       // runtime/os_windows.go.
        oh64.SizeOfStackReserve = 0x00200000
        if !iscgo {
                oh64.SizeOfStackCommit = 0x00001000
index fa0c69bc13804a0c2eee3d7e513a5da7868ff78a..e80a5649436b846f141cc3e9a3d873d6115e0569 100644 (file)
@@ -13,7 +13,7 @@ static void threadentry(void*);
 
 /* 1MB is default stack size for 32-bit Windows.
    Allocation granularity on Windows is typically 64 KB.
-   The constant is also hardcoded in cmd/ld/pe.c (keep synchronized). */
+   This constant must match SizeOfStackReserve in ../cmd/link/internal/ld/pe.go. */
 #define STACKSIZE (1*1024*1024)
 
 void
index a3c3896edfca5e5a480d76dfb34e302b817505da..75a7dc8ec2a236b37f99e8b2394102ec9e4366b8 100644 (file)
@@ -13,7 +13,7 @@ static void threadentry(void*);
 
 /* 2MB is default stack size for 64-bit Windows.
    Allocation granularity on Windows is typically 64 KB.
-   The constant is also hardcoded in cmd/ld/pe.c (keep synchronized). */
+   This constant must match SizeOfStackReserve in ../cmd/link/internal/ld/pe.go. */
 #define STACKSIZE (2*1024*1024)
 
 void
index 68e404e6759f898162053c07515715a9e92330b6..1f3ebf607244bf7e159af21c98ac922b39fb4def 100644 (file)
@@ -291,6 +291,9 @@ func osRelax(relax bool) uint32 {
        }
 }
 
+// osStackSize must match SizeOfStackReserve in ../cmd/link/internal/ld/pe.go.
+var osStackSize uintptr = 0x00200000*_64bit + 0x00100000*(1-_64bit)
+
 func osinit() {
        asmstdcallAddr = unsafe.Pointer(funcPC(asmstdcall))
        usleep2Addr = unsafe.Pointer(funcPC(usleep2))
@@ -319,6 +322,18 @@ func osinit() {
        // equivalent threads that all do a mix of GUI, IO, computations, etc.
        // In such context dynamic priority boosting does nothing but harm, so we turn it off.
        stdcall2(_SetProcessPriorityBoost, currentProcess, 1)
+
+       // Fix the entry thread's stack bounds, since runtime entry
+       // assumed we were on a tiny stack. If this is a cgo binary,
+       // x_cgo_init already fixed these.
+       if !iscgo {
+               // Leave 8K of slop for calling C functions that don't
+               // have stack checks. We shouldn't be anywhere near
+               // this bound anyway.
+               g0.stack.lo = g0.stack.hi - osStackSize + 8*1024
+               g0.stackguard0 = g0.stack.lo + _StackGuard
+               g0.stackguard1 = g0.stackguard0
+       }
 }
 
 func nanotime() int64
@@ -620,9 +635,7 @@ func semacreate(mp *m) {
 //go:nosplit
 func newosproc(mp *m) {
        const _STACK_SIZE_PARAM_IS_A_RESERVATION = 0x00010000
-       // stackSize must match SizeOfStackReserve in cmd/link/internal/ld/pe.go.
-       const stackSize = 0x00200000*_64bit + 0x00100000*(1-_64bit)
-       thandle := stdcall6(_CreateThread, 0, stackSize,
+       thandle := stdcall6(_CreateThread, 0, osStackSize,
                funcPC(tstart_stdcall), uintptr(unsafe.Pointer(mp)),
                _STACK_SIZE_PARAM_IS_A_RESERVATION, 0)
 
index 5f0d8b7c2a179c71768d425bfe2dfdeaecd5c308..56d5cfaa8238f0d8404955831df926e9150d5494 100644 (file)
@@ -315,7 +315,8 @@ TEXT runtime·tstart(SB),NOSPLIT,$0
        // Layout new m scheduler stack on os stack.
        MOVL    SP, AX
        MOVL    AX, (g_stack+stack_hi)(DX)
-       SUBL    $(64*1024), AX          // stack size
+       SUBL    runtime·osStackSize(SB), AX            // stack size
+       ADDL    $(8*1024), AX                           // slop for calling C
        MOVL    AX, (g_stack+stack_lo)(DX)
        ADDL    $const__StackGuard, AX
        MOVL    AX, g_stackguard0(DX)
index 2e5b29ba55f3a4c4d184895b8915e4d80adab7a3..119e04c70482a0e6bdf1125efaf1db5f533323e1 100644 (file)
@@ -363,7 +363,8 @@ TEXT runtime·tstart_stdcall(SB),NOSPLIT,$0
        // Layout new m scheduler stack on os stack.
        MOVQ    SP, AX
        MOVQ    AX, (g_stack+stack_hi)(DX)
-       SUBQ    $(64*1024), AX          // stack size
+       SUBQ    runtime·osStackSize(SB), AX            // stack size
+       ADDQ    $(8*1024), AX                           // slop for calling C
        MOVQ    AX, (g_stack+stack_lo)(DX)
        ADDQ    $const__StackGuard, AX
        MOVQ    AX, g_stackguard0(DX)