From: Austin Clements Date: Wed, 20 Jun 2018 20:25:41 +0000 (-0400) Subject: runtime: initialize g0 stack bounds on Windows to full stack X-Git-Tag: go1.11beta2~233 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=52e782a2d6e83065e394d127ea5df20e4aaaa8af;p=gostls13.git 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 TryBot-Result: Gobot Gobot Reviewed-by: Alex Brainman Reviewed-by: Ian Lance Taylor --- diff --git a/src/cmd/link/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go index 85acb7a11b..3b7df9aef8 100644 --- a/src/cmd/link/internal/ld/pe.go +++ b/src/cmd/link/internal/ld/pe.go @@ -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 diff --git a/src/runtime/cgo/gcc_windows_386.c b/src/runtime/cgo/gcc_windows_386.c index fa0c69bc13..e80a564943 100644 --- a/src/runtime/cgo/gcc_windows_386.c +++ b/src/runtime/cgo/gcc_windows_386.c @@ -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 diff --git a/src/runtime/cgo/gcc_windows_amd64.c b/src/runtime/cgo/gcc_windows_amd64.c index a3c3896edf..75a7dc8ec2 100644 --- a/src/runtime/cgo/gcc_windows_amd64.c +++ b/src/runtime/cgo/gcc_windows_amd64.c @@ -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 diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go index 68e404e675..1f3ebf6072 100644 --- a/src/runtime/os_windows.go +++ b/src/runtime/os_windows.go @@ -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) diff --git a/src/runtime/sys_windows_386.s b/src/runtime/sys_windows_386.s index 5f0d8b7c2a..56d5cfaa82 100644 --- a/src/runtime/sys_windows_386.s +++ b/src/runtime/sys_windows_386.s @@ -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) diff --git a/src/runtime/sys_windows_amd64.s b/src/runtime/sys_windows_amd64.s index 2e5b29ba55..119e04c704 100644 --- a/src/runtime/sys_windows_amd64.s +++ b/src/runtime/sys_windows_amd64.s @@ -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)