Skip to content

Commit ba4c6d1

Browse files
Qi Xiaogopherbot
Qi Xiao
authored andcommitted
syscall: Fix Getwd on Windows to correctly handle long paths.
Fixes #60051. Change-Id: Ia68ca0493912cb09d8c1d36a144bf0725842af1d Reviewed-on: https://go-review.googlesource.com/c/go/+/502415 Auto-Submit: Bryan Mills <[email protected]> Run-TryBot: Quim Muntal <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Bryan Mills <[email protected]>
1 parent c3db64c commit ba4c6d1

File tree

2 files changed

+38
-4
lines changed

2 files changed

+38
-4
lines changed

src/syscall/syscall_windows.go

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -533,11 +533,21 @@ const ImplementsGetwd = true
533533

534534
func Getwd() (wd string, err error) {
535535
b := make([]uint16, 300)
536-
n, e := GetCurrentDirectory(uint32(len(b)), &b[0])
537-
if e != nil {
538-
return "", e
536+
// The path of the current directory may not fit in the initial 300-word
537+
// buffer when long path support is enabled. The current directory may also
538+
// change between subsequent calls of GetCurrentDirectory. As a result, we
539+
// need to retry the call in a loop until the current directory fits, each
540+
// time with a bigger buffer.
541+
for {
542+
n, e := GetCurrentDirectory(uint32(len(b)), &b[0])
543+
if e != nil {
544+
return "", e
545+
}
546+
if int(n) <= len(b) {
547+
return UTF16ToString(b[:n]), nil
548+
}
549+
b = make([]uint16, n)
539550
}
540-
return UTF16ToString(b[0:n]), nil
541551
}
542552

543553
func Chdir(path string) (err error) {

src/syscall/syscall_windows_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,30 @@ int main(int argc, char *argv[])
180180
}
181181
}
182182

183+
func TestGetwd_DoesNotPanicWhenPathIsLong(t *testing.T) {
184+
// Regression test for https://github.com/golang/go/issues/60051.
185+
186+
// The length of a filename is also limited, so we can't reproduce the
187+
// crash by creating a single directory with a very long name; we need two
188+
// layers.
189+
a200 := strings.Repeat("a", 200)
190+
dirname := filepath.Join(t.TempDir(), a200, a200)
191+
192+
err := os.MkdirAll(dirname, 0o700)
193+
if err != nil {
194+
t.Skipf("MkdirAll failed: %v", err)
195+
}
196+
err = os.Chdir(dirname)
197+
if err != nil {
198+
t.Skipf("Chdir failed: %v", err)
199+
}
200+
// Change out of the temporary directory so that we don't inhibit its
201+
// removal during test cleanup.
202+
defer os.Chdir(`\`)
203+
204+
syscall.Getwd()
205+
}
206+
183207
func FuzzUTF16FromString(f *testing.F) {
184208
f.Add("hi") // ASCII
185209
f.Add("â") // latin1

0 commit comments

Comments
 (0)