From: Ian Lance Taylor Date: Tue, 6 Oct 2020 23:31:00 +0000 (-0700) Subject: syscall: rewrite Windows makeCmdLine to use []byte X-Git-Tag: go1.16beta1~817 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=492258549717d4e73a22170c507fb26a731c4aba;p=gostls13.git syscall: rewrite Windows makeCmdLine to use []byte It's faster to append to a []byte and only convert to string at the end then it is to build up a string by concatenating characters. Fixes #41825 Change-Id: I45ddf77dcc62726c919f0533c95d483cee8ba366 Reviewed-on: https://go-review.googlesource.com/c/go/+/259978 Trust: Ian Lance Taylor Trust: Alex Brainman Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Alex Brainman --- diff --git a/src/syscall/exec_windows.go b/src/syscall/exec_windows.go index 8d6141c0ca..500321ef0d 100644 --- a/src/syscall/exec_windows.go +++ b/src/syscall/exec_windows.go @@ -24,74 +24,87 @@ var ForkLock sync.RWMutex // - finally, s is wrapped with double quotes (arg -> "arg"), // but only if there is space or tab inside s. func EscapeArg(s string) string { + for i := 0; i < len(s); i++ { + switch s[i] { + case '"', '\\', ' ', '\t': + // Some escaping required. + b := make([]byte, 0, len(s)+2) + b = appendEscapeArg(b, s) + return string(b) + } + } + return s +} + +// appendEscapeArg escapes the string s, as per escapeArg, +// appends the result to b, and returns the updated slice. +func appendEscapeArg(b []byte, s string) []byte { if len(s) == 0 { - return "\"\"" + return append(b, `""`...) } - n := len(s) + + needsBackslash := false hasSpace := false for i := 0; i < len(s); i++ { switch s[i] { case '"', '\\': - n++ + needsBackslash = true case ' ', '\t': hasSpace = true } } - if hasSpace { - n += 2 + + if !needsBackslash && !hasSpace { + // No special handling required; normal case. + return append(b, s...) } - if n == len(s) { - return s + if !needsBackslash { + // hasSpace is true, so we need to quote the string. + b = append(b, '"') + b = append(b, s...) + return append(b, '"') } - qs := make([]byte, n) - j := 0 if hasSpace { - qs[j] = '"' - j++ + b = append(b, '"') } slashes := 0 for i := 0; i < len(s); i++ { - switch s[i] { + c := s[i] + switch c { default: slashes = 0 - qs[j] = s[i] case '\\': slashes++ - qs[j] = s[i] case '"': for ; slashes > 0; slashes-- { - qs[j] = '\\' - j++ + b = append(b, '\\') } - qs[j] = '\\' - j++ - qs[j] = s[i] + b = append(b, '\\') } - j++ + b = append(b, c) } if hasSpace { for ; slashes > 0; slashes-- { - qs[j] = '\\' - j++ + b = append(b, '\\') } - qs[j] = '"' - j++ + b = append(b, '"') } - return string(qs[:j]) + + return b } // makeCmdLine builds a command line out of args by escaping "special" // characters and joining the arguments with spaces. func makeCmdLine(args []string) string { - var s string + var b []byte for _, v := range args { - if s != "" { - s += " " + if len(b) > 0 { + b = append(b, ' ') } - s += EscapeArg(v) + b = appendEscapeArg(b, v) } - return s + return string(b) } // createEnvBlock converts an array of environment strings into