Skip to content

Commit 52e782a

Browse files
committed
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 <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Alex Brainman <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent b55fe6a commit 52e782a

File tree

6 files changed

+24
-9
lines changed

6 files changed

+24
-9
lines changed

src/cmd/link/internal/ld/pe.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -852,8 +852,8 @@ func (f *peFile) writeOptionalHeader(ctxt *Link) {
852852
//
853853
// For other threads we specify stack size in runtime explicitly.
854854
// For these, the reserve must match STACKSIZE in
855-
// runtime/cgo/gcc_windows_{386,amd64}.c and the correspondent
856-
// CreateThread parameter in runtime.newosproc.
855+
// runtime/cgo/gcc_windows_{386,amd64}.c and osStackSize in
856+
// runtime/os_windows.go.
857857
oh64.SizeOfStackReserve = 0x00200000
858858
if !iscgo {
859859
oh64.SizeOfStackCommit = 0x00001000

src/runtime/cgo/gcc_windows_386.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ static void threadentry(void*);
1313

1414
/* 1MB is default stack size for 32-bit Windows.
1515
Allocation granularity on Windows is typically 64 KB.
16-
The constant is also hardcoded in cmd/ld/pe.c (keep synchronized). */
16+
This constant must match SizeOfStackReserve in ../cmd/link/internal/ld/pe.go. */
1717
#define STACKSIZE (1*1024*1024)
1818

1919
void

src/runtime/cgo/gcc_windows_amd64.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ static void threadentry(void*);
1313

1414
/* 2MB is default stack size for 64-bit Windows.
1515
Allocation granularity on Windows is typically 64 KB.
16-
The constant is also hardcoded in cmd/ld/pe.c (keep synchronized). */
16+
This constant must match SizeOfStackReserve in ../cmd/link/internal/ld/pe.go. */
1717
#define STACKSIZE (2*1024*1024)
1818

1919
void

src/runtime/os_windows.go

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,9 @@ func osRelax(relax bool) uint32 {
291291
}
292292
}
293293

294+
// osStackSize must match SizeOfStackReserve in ../cmd/link/internal/ld/pe.go.
295+
var osStackSize uintptr = 0x00200000*_64bit + 0x00100000*(1-_64bit)
296+
294297
func osinit() {
295298
asmstdcallAddr = unsafe.Pointer(funcPC(asmstdcall))
296299
usleep2Addr = unsafe.Pointer(funcPC(usleep2))
@@ -319,6 +322,18 @@ func osinit() {
319322
// equivalent threads that all do a mix of GUI, IO, computations, etc.
320323
// In such context dynamic priority boosting does nothing but harm, so we turn it off.
321324
stdcall2(_SetProcessPriorityBoost, currentProcess, 1)
325+
326+
// Fix the entry thread's stack bounds, since runtime entry
327+
// assumed we were on a tiny stack. If this is a cgo binary,
328+
// x_cgo_init already fixed these.
329+
if !iscgo {
330+
// Leave 8K of slop for calling C functions that don't
331+
// have stack checks. We shouldn't be anywhere near
332+
// this bound anyway.
333+
g0.stack.lo = g0.stack.hi - osStackSize + 8*1024
334+
g0.stackguard0 = g0.stack.lo + _StackGuard
335+
g0.stackguard1 = g0.stackguard0
336+
}
322337
}
323338

324339
func nanotime() int64
@@ -620,9 +635,7 @@ func semacreate(mp *m) {
620635
//go:nosplit
621636
func newosproc(mp *m) {
622637
const _STACK_SIZE_PARAM_IS_A_RESERVATION = 0x00010000
623-
// stackSize must match SizeOfStackReserve in cmd/link/internal/ld/pe.go.
624-
const stackSize = 0x00200000*_64bit + 0x00100000*(1-_64bit)
625-
thandle := stdcall6(_CreateThread, 0, stackSize,
638+
thandle := stdcall6(_CreateThread, 0, osStackSize,
626639
funcPC(tstart_stdcall), uintptr(unsafe.Pointer(mp)),
627640
_STACK_SIZE_PARAM_IS_A_RESERVATION, 0)
628641

src/runtime/sys_windows_386.s

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,8 @@ TEXT runtime·tstart(SB),NOSPLIT,$0
315315
// Layout new m scheduler stack on os stack.
316316
MOVL SP, AX
317317
MOVL AX, (g_stack+stack_hi)(DX)
318-
SUBL $(64*1024), AX // stack size
318+
SUBL runtime·osStackSize(SB), AX // stack size
319+
ADDL $(8*1024), AX // slop for calling C
319320
MOVL AX, (g_stack+stack_lo)(DX)
320321
ADDL $const__StackGuard, AX
321322
MOVL AX, g_stackguard0(DX)

src/runtime/sys_windows_amd64.s

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,8 @@ TEXT runtime·tstart_stdcall(SB),NOSPLIT,$0
363363
// Layout new m scheduler stack on os stack.
364364
MOVQ SP, AX
365365
MOVQ AX, (g_stack+stack_hi)(DX)
366-
SUBQ $(64*1024), AX // stack size
366+
SUBQ runtime·osStackSize(SB), AX // stack size
367+
ADDQ $(8*1024), AX // slop for calling C
367368
MOVQ AX, (g_stack+stack_lo)(DX)
368369
ADDQ $const__StackGuard, AX
369370
MOVQ AX, g_stackguard0(DX)

0 commit comments

Comments
 (0)