Commit 52e782a2 authored by Austin Clements's avatar Austin Clements

runtime: initialize g0 stack bounds on Windows to full stack

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: default avatarAlex Brainman <alex.brainman@gmail.com>
Reviewed-by: default avatarIan Lance Taylor <iant@golang.org>
parent b55fe6a3
......@@ -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
......
......@@ -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
......
......@@ -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
......
......@@ -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)
......
......@@ -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)
......
......@@ -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)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment