Skip to content

Commit 923299a

Browse files
committed
cmd/link: restore windows stack commit size back to 4KB
CL 49331 increased windows stack commit size to 2MB by mistake. Revert that change. Fixes #22439 Change-Id: I919e549e87da326f4ba45890b4d32f6d7046186f Reviewed-on: https://go-review.googlesource.com/74490 TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Austin Clements <austin@google.com>
1 parent 25159d3 commit 923299a

File tree

8 files changed

+164
-4
lines changed

8 files changed

+164
-4
lines changed

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

+9-2
Original file line numberDiff line numberDiff line change
@@ -848,7 +848,14 @@ func (f *peFile) writeOptionalHeader(ctxt *Link) {
848848
// runtime/cgo/gcc_windows_{386,amd64}.c and the correspondent
849849
// CreateThread parameter in runtime.newosproc.
850850
oh64.SizeOfStackReserve = 0x00200000
851-
oh64.SizeOfStackCommit = 0x00200000 - 0x2000 // account for 2 guard pages
851+
if !iscgo {
852+
oh64.SizeOfStackCommit = 0x00001000
853+
} else {
854+
// TODO(brainman): Maybe remove optional header writing altogether for cgo.
855+
// For cgo it is the external linker that is building final executable.
856+
// And it probably does not use any information stored in optional header.
857+
oh64.SizeOfStackCommit = 0x00200000 - 0x2000 // account for 2 guard pages
858+
}
852859

853860
// 32-bit is trickier since there much less address space to
854861
// work with. Here we use large stacks only in cgo binaries as
@@ -858,7 +865,7 @@ func (f *peFile) writeOptionalHeader(ctxt *Link) {
858865
oh.SizeOfStackCommit = 0x00001000
859866
} else {
860867
oh.SizeOfStackReserve = 0x00100000
861-
oh.SizeOfStackCommit = 0x00100000 - 0x2000
868+
oh.SizeOfStackCommit = 0x00100000 - 0x2000 // account for 2 guard pages
862869
}
863870

864871
oh64.SizeOfHeapReserve = 0x00100000

src/internal/syscall/windows/mksyscall.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44

55
package windows
66

7-
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go security_windows.go
7+
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go security_windows.go psapi_windows.go
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2017 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package windows
6+
7+
type PROCESS_MEMORY_COUNTERS struct {
8+
CB uint32
9+
PageFaultCount uint32
10+
PeakWorkingSetSize uintptr
11+
WorkingSetSize uintptr
12+
QuotaPeakPagedPoolUsage uintptr
13+
QuotaPagedPoolUsage uintptr
14+
QuotaPeakNonPagedPoolUsage uintptr
15+
QuotaNonPagedPoolUsage uintptr
16+
PagefileUsage uintptr
17+
PeakPagefileUsage uintptr
18+
}
19+
20+
//sys GetProcessMemoryInfo(handle syscall.Handle, memCounters *PROCESS_MEMORY_COUNTERS, cb uint32) (err error) = psapi.GetProcessMemoryInfo

src/internal/syscall/windows/zsyscall_windows.go

+14
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ var (
4040
modkernel32 = syscall.NewLazyDLL(sysdll.Add("kernel32.dll"))
4141
modnetapi32 = syscall.NewLazyDLL(sysdll.Add("netapi32.dll"))
4242
modadvapi32 = syscall.NewLazyDLL(sysdll.Add("advapi32.dll"))
43+
modpsapi = syscall.NewLazyDLL(sysdll.Add("psapi.dll"))
4344

4445
procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses")
4546
procGetComputerNameExW = modkernel32.NewProc("GetComputerNameExW")
@@ -57,6 +58,7 @@ var (
5758
procOpenThreadToken = modadvapi32.NewProc("OpenThreadToken")
5859
procLookupPrivilegeValueW = modadvapi32.NewProc("LookupPrivilegeValueW")
5960
procAdjustTokenPrivileges = modadvapi32.NewProc("AdjustTokenPrivileges")
61+
procGetProcessMemoryInfo = modpsapi.NewProc("GetProcessMemoryInfo")
6062
)
6163

6264
func GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizePointer *uint32) (errcode error) {
@@ -243,3 +245,15 @@ func adjustTokenPrivileges(token syscall.Token, disableAllPrivileges bool, newst
243245
}
244246
return
245247
}
248+
249+
func GetProcessMemoryInfo(handle syscall.Handle, memCounters *PROCESS_MEMORY_COUNTERS, cb uint32) (err error) {
250+
r1, _, e1 := syscall.Syscall(procGetProcessMemoryInfo.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(memCounters)), uintptr(cb))
251+
if r1 == 0 {
252+
if e1 != 0 {
253+
err = errnoErr(e1)
254+
} else {
255+
err = syscall.EINVAL
256+
}
257+
}
258+
return
259+
}

src/runtime/crash_cgo_test.go

+18
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"os"
1414
"os/exec"
1515
"runtime"
16+
"strconv"
1617
"strings"
1718
"testing"
1819
"time"
@@ -452,3 +453,20 @@ func TestCgoLockOSThreadExit(t *testing.T) {
452453
t.Parallel()
453454
testLockOSThreadExit(t, "testprogcgo")
454455
}
456+
457+
func testWindowsStackMemory(t *testing.T, o string) {
458+
stackUsage, err := strconv.Atoi(o)
459+
if err != nil {
460+
t.Fatalf("Failed to read stack usage: %v", err)
461+
}
462+
if expected, got := 100<<10, stackUsage; got > expected {
463+
t.Fatalf("expected < %d bytes of memory per thread, got %d", expected, got)
464+
}
465+
}
466+
467+
func TestWindowsStackMemoryCgo(t *testing.T) {
468+
if runtime.GOOS != "windows" {
469+
t.Skip("skipping windows specific test")
470+
}
471+
testWindowsStackMemory(t, runTestProg(t, "testprogcgo", "StackMemory"))
472+
}

src/runtime/syscall_windows_test.go

+4
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,10 @@ func TestWERDialogue(t *testing.T) {
537537
cmd.CombinedOutput()
538538
}
539539

540+
func TestWindowsStackMemory(t *testing.T) {
541+
testWindowsStackMemory(t, runTestProg(t, "testprog", "StackMemory"))
542+
}
543+
540544
var used byte
541545

542546
func use(buf []byte) {

src/runtime/testdata/testprog/syscall_windows.go

+44-1
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,18 @@
44

55
package main
66

7-
import "syscall"
7+
import (
8+
"internal/syscall/windows"
9+
"runtime"
10+
"sync"
11+
"syscall"
12+
"unsafe"
13+
)
814

915
func init() {
1016
register("RaiseException", RaiseException)
1117
register("ZeroDivisionException", ZeroDivisionException)
18+
register("StackMemory", StackMemory)
1219
}
1320

1421
func RaiseException() {
@@ -25,3 +32,39 @@ func ZeroDivisionException() {
2532
z := x / y
2633
println(z)
2734
}
35+
36+
func getPagefileUsage() (uintptr, error) {
37+
p, err := syscall.GetCurrentProcess()
38+
if err != nil {
39+
return 0, err
40+
}
41+
var m windows.PROCESS_MEMORY_COUNTERS
42+
err = windows.GetProcessMemoryInfo(p, &m, uint32(unsafe.Sizeof(m)))
43+
if err != nil {
44+
return 0, err
45+
}
46+
return m.PagefileUsage, nil
47+
}
48+
49+
func StackMemory() {
50+
mem1, err := getPagefileUsage()
51+
if err != nil {
52+
panic(err)
53+
}
54+
const threadCount = 100
55+
var wg sync.WaitGroup
56+
for i := 0; i < threadCount; i++ {
57+
wg.Add(1)
58+
go func() {
59+
runtime.LockOSThread()
60+
wg.Done()
61+
select {}
62+
}()
63+
}
64+
wg.Wait()
65+
mem2, err := getPagefileUsage()
66+
if err != nil {
67+
panic(err)
68+
}
69+
print((mem2 - mem1) / threadCount)
70+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright 2015 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package main
6+
7+
import "C"
8+
import (
9+
"internal/syscall/windows"
10+
"runtime"
11+
"sync"
12+
"syscall"
13+
"unsafe"
14+
)
15+
16+
func init() {
17+
register("StackMemory", StackMemory)
18+
}
19+
20+
func getPagefileUsage() (uintptr, error) {
21+
p, err := syscall.GetCurrentProcess()
22+
if err != nil {
23+
return 0, err
24+
}
25+
var m windows.PROCESS_MEMORY_COUNTERS
26+
err = windows.GetProcessMemoryInfo(p, &m, uint32(unsafe.Sizeof(m)))
27+
if err != nil {
28+
return 0, err
29+
}
30+
return m.PagefileUsage, nil
31+
}
32+
33+
func StackMemory() {
34+
mem1, err := getPagefileUsage()
35+
if err != nil {
36+
panic(err)
37+
}
38+
const threadCount = 100
39+
var wg sync.WaitGroup
40+
for i := 0; i < threadCount; i++ {
41+
wg.Add(1)
42+
go func() {
43+
runtime.LockOSThread()
44+
wg.Done()
45+
select {}
46+
}()
47+
}
48+
wg.Wait()
49+
mem2, err := getPagefileUsage()
50+
if err != nil {
51+
panic(err)
52+
}
53+
print((mem2 - mem1) / threadCount)
54+
}

0 commit comments

Comments
 (0)