]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: reduce syscall.SyscallX stack usage
authorqmuntal <quimmuntal@gmail.com>
Tue, 8 Oct 2024 16:10:17 +0000 (18:10 +0200)
committerQuim Muntal <quimmuntal@gmail.com>
Fri, 11 Oct 2024 17:16:18 +0000 (17:16 +0000)
syscall.SyscallX consumes a lot of stack space, which is a problem
because they are nosplit functions. They used to use less stack space,
but CL 563315, that landed in Go 1.23, increased the stack usage by a
lot.

This CL reduces the stack usage back to the previous level.

Fixes #69813.

Change-Id: Iddedd28b693c66a258da687389768055c493fc2e
Reviewed-on: https://go-review.googlesource.com/c/go/+/618497
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>

src/runtime/syscall_windows.go
src/runtime/syscall_windows_test.go

index 69d720a395c48d5e2764a4b5bf0ac7b1bba11bcb..85b1b8c9024a73ad585c49fd0664148f691b2d8f 100644 (file)
@@ -454,43 +454,37 @@ func syscall_getprocaddress(handle uintptr, procname *byte) (outhandle, err uint
 //go:linkname syscall_Syscall syscall.Syscall
 //go:nosplit
 func syscall_Syscall(fn, nargs, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
-       args := [...]uintptr{a1, a2, a3}
-       return syscall_SyscallN(fn, args[:nargs]...)
+       return syscall_syscalln(fn, nargs, a1, a2, a3)
 }
 
 //go:linkname syscall_Syscall6 syscall.Syscall6
 //go:nosplit
 func syscall_Syscall6(fn, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
-       args := [...]uintptr{a1, a2, a3, a4, a5, a6}
-       return syscall_SyscallN(fn, args[:nargs]...)
+       return syscall_syscalln(fn, nargs, a1, a2, a3, a4, a5, a6)
 }
 
 //go:linkname syscall_Syscall9 syscall.Syscall9
 //go:nosplit
 func syscall_Syscall9(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr) {
-       args := [...]uintptr{a1, a2, a3, a4, a5, a6, a7, a8, a9}
-       return syscall_SyscallN(fn, args[:nargs]...)
+       return syscall_syscalln(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9)
 }
 
 //go:linkname syscall_Syscall12 syscall.Syscall12
 //go:nosplit
 func syscall_Syscall12(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2, err uintptr) {
-       args := [...]uintptr{a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12}
-       return syscall_SyscallN(fn, args[:nargs]...)
+       return syscall_syscalln(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12)
 }
 
 //go:linkname syscall_Syscall15 syscall.Syscall15
 //go:nosplit
 func syscall_Syscall15(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2, err uintptr) {
-       args := [...]uintptr{a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15}
-       return syscall_SyscallN(fn, args[:nargs]...)
+       return syscall_syscalln(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15)
 }
 
 //go:linkname syscall_Syscall18 syscall.Syscall18
 //go:nosplit
 func syscall_Syscall18(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18 uintptr) (r1, r2, err uintptr) {
-       args := [...]uintptr{a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18}
-       return syscall_SyscallN(fn, args[:nargs]...)
+       return syscall_syscalln(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18)
 }
 
 // maxArgs should be divisible by 2, as Windows stack
@@ -503,7 +497,15 @@ const maxArgs = 42
 //go:linkname syscall_SyscallN syscall.SyscallN
 //go:nosplit
 func syscall_SyscallN(fn uintptr, args ...uintptr) (r1, r2, err uintptr) {
-       if len(args) > maxArgs {
+       return syscall_syscalln(fn, uintptr(len(args)), args...)
+}
+
+//go:nosplit
+func syscall_syscalln(fn, n uintptr, args ...uintptr) (r1, r2, err uintptr) {
+       if n > uintptr(len(args)) {
+               panic("syscall: n > len(args)") // should not be reachable from user code
+       }
+       if n > maxArgs {
                panic("runtime: SyscallN has too many arguments")
        }
 
@@ -512,7 +514,7 @@ func syscall_SyscallN(fn uintptr, args ...uintptr) (r1, r2, err uintptr) {
        // calls back into Go.
        c := &getg().m.winsyscall
        c.fn = fn
-       c.n = uintptr(len(args))
+       c.n = n
        if c.n != 0 {
                c.args = uintptr(noescape(unsafe.Pointer(&args[0])))
        }
index 9ee06a7712503724d5641aadafe6709511282999..edbc453ec8d9bc94979703db29dc58070a8be490 100644 (file)
@@ -1206,6 +1206,13 @@ func TestBigStackCallbackSyscall(t *testing.T) {
        }
 }
 
+func TestSyscallStackUsage(t *testing.T) {
+       // Test that the stack usage of a syscall doesn't exceed the limit.
+       // See https://go.dev/issue/69813.
+       syscall.Syscall15(procSetEvent.Addr(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+       syscall.Syscall18(procSetEvent.Addr(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+}
+
 var (
        modwinmm    = syscall.NewLazyDLL("winmm.dll")
        modkernel32 = syscall.NewLazyDLL("kernel32.dll")