From 5351bcf8225747f0ef39afc44c0499822992ed11 Mon Sep 17 00:00:00 2001 From: qmuntal Date: Wed, 27 Sep 2023 11:53:30 +0200 Subject: [PATCH] syscall: simplify and optimize environment block creation on Windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit createEnvBlock currently allocates multiple times: at least one to convert the slice of strings into a NULL separated slice of bytes, and then again to encode it as UTF-16. The logic to do so is also quite complex. This CL simplifies the logic by allocating only once by encoding the slice of strings into UTF-16 directly using utf16.AppendRune. goos: windows goarch: amd64 pkg: syscall cpu: Intel(R) Core(TM) i7-10850H CPU @ 2.70GHz │ old.txt │ new.txt │ │ sec/op │ sec/op vs base │ CreateEnvBlock-12 37.92µ ± 24% 21.36µ ± 8% -43.66% (p=0.000 n=10) │ old.txt │ new.txt │ │ B/op │ B/op vs base │ CreateEnvBlock-12 109.12Ki ± 0% 26.62Ki ± 0% -75.60% (p=0.000 n=10) │ old.txt │ new.txt │ │ allocs/op │ allocs/op vs base │ CreateEnvBlock-12 4.000 ± 0% 1.000 ± 0% -75.00% (p=0.000 n=10) Change-Id: If35f62c3926b486d5253a9ae23a33b979b2f02c2 Reviewed-on: https://go-review.googlesource.com/c/go/+/531355 Reviewed-by: Bryan Mills Run-TryBot: Quim Muntal TryBot-Result: Gopher Robot LUCI-TryBot-Result: Go LUCI Reviewed-by: Than McIntosh --- src/syscall/exec_windows.go | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/syscall/exec_windows.go b/src/syscall/exec_windows.go index b311a5c746..1220de4cdf 100644 --- a/src/syscall/exec_windows.go +++ b/src/syscall/exec_windows.go @@ -118,11 +118,11 @@ func makeCmdLine(args []string) string { // terminated strings followed by a nil. // Last bytes are two UCS-2 NULs, or four NUL bytes. // If any string contains a NUL, it returns (nil, EINVAL). -func createEnvBlock(envv []string) (*uint16, error) { +func createEnvBlock(envv []string) ([]uint16, error) { if len(envv) == 0 { - return &utf16.Encode([]rune("\x00\x00"))[0], nil + return utf16.Encode([]rune("\x00\x00")), nil } - length := 0 + var length int for _, s := range envv { if bytealg.IndexByteString(s, 0) != -1 { return nil, EINVAL @@ -131,17 +131,15 @@ func createEnvBlock(envv []string) (*uint16, error) { } length += 1 - b := make([]byte, length) - i := 0 + b := make([]uint16, 0, length) for _, s := range envv { - l := len(s) - copy(b[i:i+l], []byte(s)) - copy(b[i+l:i+l+1], []byte{0}) - i = i + l + 1 + for _, c := range s { + b = utf16.AppendRune(b, c) + } + b = utf16.AppendRune(b, 0) } - copy(b[i:i+1], []byte{0}) - - return &utf16.Encode([]rune(string(b)))[0], nil + b = utf16.AppendRune(b, 0) + return b, nil } func CloseOnExec(fd Handle) { @@ -387,9 +385,9 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle pi := new(ProcessInformation) flags := sys.CreationFlags | CREATE_UNICODE_ENVIRONMENT | _EXTENDED_STARTUPINFO_PRESENT if sys.Token != 0 { - err = CreateProcessAsUser(sys.Token, argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, willInheritHandles, flags, envBlock, dirp, &si.StartupInfo, pi) + err = CreateProcessAsUser(sys.Token, argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, willInheritHandles, flags, &envBlock[0], dirp, &si.StartupInfo, pi) } else { - err = CreateProcess(argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, willInheritHandles, flags, envBlock, dirp, &si.StartupInfo, pi) + err = CreateProcess(argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, willInheritHandles, flags, &envBlock[0], dirp, &si.StartupInfo, pi) } if err != nil { return 0, 0, err