Repository: go
Issue: os: `Lstat` on `darwin` sometimes fails to expand symlinks in paths with trailing slashes
Labels: OS-Darwin,NeedsInvestigation

### What version of Go are you using (`go version`)?

<pre>
$ go version
go version devel go1.21-ebc13fb0b8 Wed Apr 12 16:09:24 2023 +0000 darwin/amd64

</pre>

### Does this issue reproduce with the latest release?

Yes


### What operating system and processor architecture are you using (`go env`)?

<details><summary><code>go env</code> Output</summary><br><pre>
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/gopher/Library/Caches/go-build"
GOENV="/Users/gopher/Library/Application Support/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/tmp/buildlet/gopath/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/tmp/buildlet/gopath"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/tmp/buildlet/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/tmp/buildlet/go/pkg/tool/darwin_amd64"
GOVCS=""
GOVERSION="devel gomote.XXXXX"
GCCGO="gccgo"
GOAMD64="v1"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/tmp/buildlet/go/src/go.mod"
GOWORK=""
CGO_CFLAGS="-O2 -g"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-O2 -g"
CGO_FFLAGS="-O2 -g"
CGO_LDFLAGS="-O2 -g"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch x86_64 -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -ffile-prefix-map=/var/folders/wh/9yc0j5w50z97w3528z_7qvr40000gn/T/go-build1774834589=/tmp/go-build -gno-record-gcc-switches -fno-common"

</pre></details>

### What did you do?

Extend `path/filepath.TestWalkSymlinkRoot` with the following test cases, inspired by `cmd/go.TestScript/list_goroot_symlink`:
```diff
diff --git i/src/path/filepath/path_test.go w/src/path/filepath/path_test.go
index cfc5cad863..4337bedda3 100644
--- i/src/path/filepath/path_test.go
+++ w/src/path/filepath/path_test.go
@@ -842,6 +842,16 @@ func TestWalkSymlinkRoot(t *testing.T) {
 		t.Fatal(err)
 	}

+	abslink := filepath.Join(td, "abslink")
+	if err := os.Symlink(dir, abslink); err != nil {
+		t.Fatal(err)
+	}
+
+	linklink := filepath.Join(td, "linklink")
+	if err := os.Symlink("link", linklink); err != nil {
+		t.Fatal(err)
+	}
+
 	// Per https://pubs.opengroup.org/onlinepubs/9699919799.2013edition/basedefs/V1_chap04.html#tag_04_12:
 	// “A pathname that contains at least one non- <slash> character and that ends
 	// with one or more trailing <slash> characters shall not be resolved
@@ -868,6 +878,26 @@ func TestWalkSymlinkRoot(t *testing.T) {
 			root: link + string(filepath.Separator),
 			want: []string{link, filepath.Join(link, "foo")},
 		},
+		{
+			desc: "abs no slash",
+			root: abslink,
+			want: []string{abslink},
+		},
+		{
+			desc: "abs with slash",
+			root: abslink + string(filepath.Separator),
+			want: []string{abslink, filepath.Join(abslink, "foo")},
+		},
+		{
+			desc: "double link no slash",
+			root: linklink,
+			want: []string{linklink},
+		},
+		{
+			desc: "double link with slash",
+			root: linklink + string(filepath.Separator),
+			want: []string{linklink, filepath.Join(linklink, "foo")},
+		},
 	} {
 		tt := tt
 		t.Run(tt.desc, func(t *testing.T) {
```


### What did you expect to see?

The additional tests should pass.
Per [POSIX pathname resolution](https://pubs.opengroup.org/onlinepubs/9699919799.2013edition/basedefs/V1_chap04.html#tag_04_12), pathname resolution should proceed as:
1. Any symlinks in the portion of the path in the `td` variable are resolved, giving a path of the form `$td/linklink/` (where `$td` is fully-resolved).
   - The “remaining pathname” after the `linklink` component is `/`.
2. `$td/linklink` resolves to `$td/link`, so `$td/link` should be prefixed to `/`, giving `$td/link/` for the next step.
   - Since the pathname `$td/link/` has a trailing slash and the path includes unresolved components, pathname resolution is _not_ yet complete.
3. `$td/link` resolves to `$td/dir`, so `$td/dir` should be prefixed to `/`, giving `$td/dir/`, which is fully resolved.

### What did you see instead?

The additional tests pass on `linux`, consistent with POSIX pathname resolution.

However, the `linklink` test fails on a `darwin-amd64-longtest` gomote instance:
```
--- FAIL: TestWalkSymlinkRoot (0.00s)
    --- FAIL: TestWalkSymlinkRoot/double_link_with_slash (0.00s)
        path_test.go:909: `/var/folders/wh/9yc0j5w50z97w3528z_7qvr40000gn/T/TestWalkSymlinkRoot3176243506/001/linklink/`: Lrwxr-xr-x
        path_test.go:918: Walk(`/var/folders/wh/9yc0j5w50z97w3528z_7qvr40000gn/T/TestWalkSymlinkRoot3176243506/001/linklink/`) visited [`/var/folders/wh/9yc0j5w50z97w3528z_7qvr40000gn/T/TestWalkSymlinkRoot3176243506/001/linklink`]; want [`/var/folders/wh/9yc0j5w50z97w3528z_7qvr40000gn/T/TestWalkSymlinkRoot3176243506/001/linklink` `/var/folders/wh/9yc0j5w50z97w3528z_7qvr40000gn/T/TestWalkSymlinkRoot3176243506/001/linklink/foo`]
FAIL
FAIL    path/filepath   0.104s
```

(CC @golang/darwin)