[dev.boringcrypto.go1.17] all: merge go1.17.11 into dev.boringcrypto.go1.17

Change-Id: I563433b2d02a5abea610a1561139d0980d5c2102
diff --git a/misc/cgo/testsanitizers/testdata/tsan11.go b/misc/cgo/testsanitizers/testdata/tsan11.go
index 70ac9c8..189e10f 100644
--- a/misc/cgo/testsanitizers/testdata/tsan11.go
+++ b/misc/cgo/testsanitizers/testdata/tsan11.go
@@ -45,7 +45,7 @@
 import "C"
 
 func main() {
-	ch := make(chan os.Signal)
+	ch := make(chan os.Signal, 1)
 	signal.Notify(ch, syscall.SIGUSR2)
 
 	C.register_handler(C.int(syscall.SIGUSR1))
diff --git a/misc/cgo/testsanitizers/testdata/tsan12.go b/misc/cgo/testsanitizers/testdata/tsan12.go
index 3e767ee..0ef545d 100644
--- a/misc/cgo/testsanitizers/testdata/tsan12.go
+++ b/misc/cgo/testsanitizers/testdata/tsan12.go
@@ -22,7 +22,7 @@
 import "C"
 
 func main() {
-	ch := make(chan os.Signal)
+	ch := make(chan os.Signal, 1)
 	signal.Notify(ch, syscall.SIGUSR1)
 
 	if err := exec.Command("true").Run(); err != nil {
diff --git a/src/cmd/dist/exec.go b/src/cmd/dist/exec.go
new file mode 100644
index 0000000..6730553
--- /dev/null
+++ b/src/cmd/dist/exec.go
@@ -0,0 +1,53 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	"os"
+	"os/exec"
+	"strings"
+)
+
+// setDir sets cmd.Dir to dir, and also adds PWD=dir to cmd's environment.
+func setDir(cmd *exec.Cmd, dir string) {
+	cmd.Dir = dir
+	setEnv(cmd, "PWD", dir)
+}
+
+// setEnv sets cmd.Env so that key = value.
+//
+// It first removes any existing values for key, so it is safe to call
+// even from within cmdbootstrap.
+func setEnv(cmd *exec.Cmd, key, value string) {
+	kv := key + "=" + value
+	if cmd.Env == nil {
+		cmd.Env = os.Environ()
+	}
+
+	prefix := kv[:len(key)+1]
+	for i, entry := range cmd.Env {
+		if strings.HasPrefix(entry, prefix) {
+			cmd.Env[i] = kv
+			return
+		}
+	}
+
+	cmd.Env = append(cmd.Env, kv)
+}
+
+// unsetEnv sets cmd.Env so that key is not present in the environment.
+func unsetEnv(cmd *exec.Cmd, key string) {
+	if cmd.Env == nil {
+		cmd.Env = os.Environ()
+	}
+
+	prefix := key + "="
+	for i, entry := range cmd.Env {
+		if strings.HasPrefix(entry, prefix) {
+			cmd.Env = append(cmd.Env[:i], cmd.Env[i+1:]...)
+			return
+		}
+	}
+}
diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go
index f40fa92..beb7c46 100644
--- a/src/cmd/dist/test.go
+++ b/src/cmd/dist/test.go
@@ -522,7 +522,8 @@
 			heading: "GOOS=ios on darwin/amd64",
 			fn: func(dt *distTest) error {
 				cmd := t.addCmd(dt, "src", t.goTest(), t.timeout(300), "-run=SystemRoots", "crypto/x509")
-				cmd.Env = append(os.Environ(), "GOOS=ios", "CGO_ENABLED=1")
+				setEnv(cmd, "GOOS", "ios")
+				setEnv(cmd, "CGO_ENABLED", "1")
 				return nil
 			},
 		})
@@ -542,7 +543,7 @@
 				cmd := t.addCmd(dt, "src", t.goTest(), t.timeout(300), "runtime", "-cpu=1,2,4", "-quick")
 				// We set GOMAXPROCS=2 in addition to -cpu=1,2,4 in order to test runtime bootstrap code,
 				// creation of first goroutines and first garbage collections in the parallel setting.
-				cmd.Env = append(os.Environ(), "GOMAXPROCS=2")
+				setEnv(cmd, "GOMAXPROCS", "2")
 				return nil
 			},
 		})
@@ -563,7 +564,7 @@
 					return nil
 				}
 				cmd := exec.Command("go", "test")
-				cmd.Dir = filepath.Join(os.Getenv("GOROOT"), "src/cmd/go/testdata/testterminal18153")
+				setDir(cmd, filepath.Join(os.Getenv("GOROOT"), "src/cmd/go/testdata/testterminal18153"))
 				cmd.Stdout = os.Stdout
 				cmd.Stderr = os.Stderr
 				return cmd.Run()
@@ -600,16 +601,13 @@
 					return err
 				}
 
-				// Run `go test fmt` in the moved GOROOT.
+				// Run `go test fmt` in the moved GOROOT, without explicitly setting
+				// GOROOT in the environment. The 'go' command should find itself.
 				cmd := exec.Command(filepath.Join(moved, "bin", "go"), "test", "fmt")
 				cmd.Stdout = os.Stdout
 				cmd.Stderr = os.Stderr
-				// Don't set GOROOT in the environment.
-				for _, e := range os.Environ() {
-					if !strings.HasPrefix(e, "GOROOT=") && !strings.HasPrefix(e, "GOCACHE=") {
-						cmd.Env = append(cmd.Env, e)
-					}
-				}
+				unsetEnv(cmd, "GOROOT")
+				unsetEnv(cmd, "GOCACHE") // TODO(bcmills): ...why‽
 				err := cmd.Run()
 
 				if rerr := os.Rename(moved, goroot); rerr != nil {
@@ -736,11 +734,9 @@
 						heading: "../misc/swig/callback",
 						fn: func(dt *distTest) error {
 							cmd := t.addCmd(dt, "misc/swig/callback", t.goTest())
-							cmd.Env = append(os.Environ(),
-								"CGO_CFLAGS=-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option",
-								"CGO_CXXFLAGS=-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option",
-								"CGO_LDFLAGS=-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option",
-							)
+							setEnv(cmd, "CGO_CFLAGS", "-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option")
+							setEnv(cmd, "CGO_CXXFLAGS", "-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option")
+							setEnv(cmd, "CGO_LDFLAGS", "-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option")
 							return nil
 						},
 					},
@@ -892,9 +888,9 @@
 func (t *tester) bgDirCmd(dir, bin string, args ...string) *exec.Cmd {
 	cmd := exec.Command(bin, args...)
 	if filepath.IsAbs(dir) {
-		cmd.Dir = dir
+		setDir(cmd, dir)
 	} else {
-		cmd.Dir = filepath.Join(goroot, dir)
+		setDir(cmd, filepath.Join(goroot, dir))
 	}
 	return cmd
 }
@@ -1132,7 +1128,8 @@
 	defer os.Remove(f.Name())
 
 	cmd := t.dirCmd(dir, t.goTest(), "-c", "-o", f.Name(), pkg)
-	cmd.Env = append(os.Environ(), "GOARCH="+gohostarch, "GOOS="+gohostos)
+	setEnv(cmd, "GOARCH", gohostarch)
+	setEnv(cmd, "GOOS", gohostos)
 	if err := cmd.Run(); err != nil {
 		return err
 	}
@@ -1141,7 +1138,7 @@
 
 func (t *tester) cgoTest(dt *distTest) error {
 	cmd := t.addCmd(dt, "misc/cgo/test", t.goTest())
-	cmd.Env = append(os.Environ(), "GOFLAGS=-ldflags=-linkmode=auto")
+	setEnv(cmd, "GOFLAGS", "-ldflags=-linkmode=auto")
 
 	// Skip internal linking cases on linux/arm64 to support GCC-9.4 and above.
 	// See issue #39466.
@@ -1149,7 +1146,7 @@
 
 	if t.internalLink() && !skipInternalLink {
 		cmd := t.addCmd(dt, "misc/cgo/test", t.goTest(), "-tags=internal")
-		cmd.Env = append(os.Environ(), "GOFLAGS=-ldflags=-linkmode=internal")
+		setEnv(cmd, "GOFLAGS", "-ldflags=-linkmode=internal")
 	}
 
 	pair := gohostos + "-" + goarch
@@ -1161,9 +1158,9 @@
 			break
 		}
 		cmd := t.addCmd(dt, "misc/cgo/test", t.goTest())
-		cmd.Env = append(os.Environ(), "GOFLAGS=-ldflags=-linkmode=external")
+		setEnv(cmd, "GOFLAGS", "-ldflags=-linkmode=external")
 
-		cmd = t.addCmd(dt, "misc/cgo/test", t.goTest(), "-ldflags", "-linkmode=external -s")
+		t.addCmd(dt, "misc/cgo/test", t.goTest(), "-ldflags", "-linkmode=external -s")
 
 		if t.supportedBuildmode("pie") {
 			t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie")
@@ -1181,10 +1178,10 @@
 		"openbsd-386", "openbsd-amd64", "openbsd-arm", "openbsd-arm64", "openbsd-mips64":
 
 		cmd := t.addCmd(dt, "misc/cgo/test", t.goTest())
-		cmd.Env = append(os.Environ(), "GOFLAGS=-ldflags=-linkmode=external")
+		setEnv(cmd, "GOFLAGS", "-ldflags=-linkmode=external")
 		// cgo should be able to cope with both -g arguments and colored
 		// diagnostics.
-		cmd.Env = append(cmd.Env, "CGO_CFLAGS=-g0 -fdiagnostics-color")
+		setEnv(cmd, "CGO_CFLAGS", "-g0 -fdiagnostics-color")
 
 		t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-ldflags", "-linkmode=auto")
 		t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-ldflags", "-linkmode=external")
@@ -1217,7 +1214,7 @@
 					// than -static in -extldflags, so test both.
 					// See issue #16651.
 					cmd := t.addCmd(dt, "misc/cgo/test", t.goTest(), "-tags=static")
-					cmd.Env = append(os.Environ(), "CGO_LDFLAGS=-static -pthread")
+					setEnv(cmd, "CGO_LDFLAGS", "-static -pthread")
 				}
 			}
 
@@ -1456,7 +1453,7 @@
 		// We shouldn't need to redo all of misc/cgo/test too.
 		// The race buildler will take care of this.
 		// cmd := t.addCmd(dt, "misc/cgo/test", t.goTest(), "-race")
-		// cmd.Env = append(os.Environ(), "GOTRACEBACK=2")
+		// setEnv(cmd, "GOTRACEBACK", "2")
 	}
 	if t.extLink() {
 		// Test with external linking; see issue 9133.
@@ -1486,7 +1483,8 @@
 		})
 
 		cmd := t.dirCmd("test", "go", "build", "-o", runtest.exe, "run.go")
-		cmd.Env = append(os.Environ(), "GOOS="+gohostos, "GOARCH="+gohostarch)
+		setEnv(cmd, "GOOS", gohostos)
+		setEnv(cmd, "GOARCH", gohostarch)
 		runtest.err = cmd.Run()
 	})
 	if runtest.err != nil {
@@ -1650,7 +1648,7 @@
 	bin := t.prebuiltGoPackageTestBinary()
 	fmt.Fprintf(os.Stderr, "# %s: using pre-built %s...\n", stdMatches[0], bin)
 	cmd := exec.Command(bin, "-test.short="+short(), "-test.timeout="+timeout.String())
-	cmd.Dir = filepath.Dir(bin)
+	setDir(cmd, filepath.Dir(bin))
 	cmd.Stdout = os.Stdout
 	cmd.Stderr = os.Stderr
 	if err := cmd.Start(); err != nil {
diff --git a/src/cmd/dist/util.go b/src/cmd/dist/util.go
index df60145..28fe5e1 100644
--- a/src/cmd/dist/util.go
+++ b/src/cmd/dist/util.go
@@ -72,7 +72,7 @@
 	}
 
 	xcmd := exec.Command(cmd[0], cmd[1:]...)
-	xcmd.Dir = dir
+	setDir(xcmd, dir)
 	var data []byte
 	var err error
 
diff --git a/src/crypto/rand/rand.go b/src/crypto/rand/rand.go
index fddd114..f2c2760 100644
--- a/src/crypto/rand/rand.go
+++ b/src/crypto/rand/rand.go
@@ -23,3 +23,21 @@
 func Read(b []byte) (n int, err error) {
 	return io.ReadFull(Reader, b)
 }
+
+// batched returns a function that calls f to populate a []byte by chunking it
+// into subslices of, at most, readMax bytes.
+func batched(f func([]byte) error, readMax int) func([]byte) error {
+	return func(out []byte) error {
+		for len(out) > 0 {
+			read := len(out)
+			if read > readMax {
+				read = readMax
+			}
+			if err := f(out[:read]); err != nil {
+				return err
+			}
+			out = out[read:]
+		}
+		return nil
+	}
+}
diff --git a/src/crypto/rand/rand_batched.go b/src/crypto/rand/rand_batched.go
index d7c5bf3..8df715f 100644
--- a/src/crypto/rand/rand_batched.go
+++ b/src/crypto/rand/rand_batched.go
@@ -8,6 +8,7 @@
 package rand
 
 import (
+	"errors"
 	"internal/syscall/unix"
 )
 
@@ -16,20 +17,6 @@
 	altGetRandom = batched(getRandomBatch, maxGetRandomRead)
 }
 
-// batched returns a function that calls f to populate a []byte by chunking it
-// into subslices of, at most, readMax bytes.
-func batched(f func([]byte) bool, readMax int) func([]byte) bool {
-	return func(buf []byte) bool {
-		for len(buf) > readMax {
-			if !f(buf[:readMax]) {
-				return false
-			}
-			buf = buf[readMax:]
-		}
-		return len(buf) == 0 || f(buf)
-	}
-}
-
 // If the kernel is too old to support the getrandom syscall(),
 // unix.GetRandom will immediately return ENOSYS and we will then fall back to
 // reading from /dev/urandom in rand_unix.go. unix.GetRandom caches the ENOSYS
@@ -37,7 +24,10 @@
 // If the kernel supports the getrandom() syscall, unix.GetRandom will block
 // until the kernel has sufficient randomness (as we don't use GRND_NONBLOCK).
 // In this case, unix.GetRandom will not return an error.
-func getRandomBatch(p []byte) (ok bool) {
+func getRandomBatch(p []byte) error {
 	n, err := unix.GetRandom(p, 0)
-	return n == len(p) && err == nil
+	if n != len(p) {
+		return errors.New("short read")
+	}
+	return err
 }
diff --git a/src/crypto/rand/rand_batched_test.go b/src/crypto/rand/rand_batched_test.go
index 2d20922..b56345e 100644
--- a/src/crypto/rand/rand_batched_test.go
+++ b/src/crypto/rand/rand_batched_test.go
@@ -9,20 +9,21 @@
 
 import (
 	"bytes"
+	"errors"
 	"testing"
 )
 
 func TestBatched(t *testing.T) {
-	fillBatched := batched(func(p []byte) bool {
+	fillBatched := batched(func(p []byte) error {
 		for i := range p {
 			p[i] = byte(i)
 		}
-		return true
+		return nil
 	}, 5)
 
 	p := make([]byte, 13)
-	if !fillBatched(p) {
-		t.Fatal("batched function returned false")
+	if err := fillBatched(p); err != nil {
+		t.Fatalf("batched function returned error: %s", err)
 	}
 	expected := []byte{0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2}
 	if !bytes.Equal(expected, p) {
@@ -31,15 +32,15 @@
 }
 
 func TestBatchedError(t *testing.T) {
-	b := batched(func(p []byte) bool { return false }, 5)
-	if b(make([]byte, 13)) {
-		t.Fatal("batched function should have returned false")
+	b := batched(func(p []byte) error { return errors.New("") }, 5)
+	if b(make([]byte, 13)) == nil {
+		t.Fatal("batched function should have returned an error")
 	}
 }
 
 func TestBatchedEmpty(t *testing.T) {
-	b := batched(func(p []byte) bool { return false }, 5)
-	if !b(make([]byte, 0)) {
-		t.Fatal("empty slice should always return true")
+	b := batched(func(p []byte) error { return errors.New("") }, 5)
+	if err := b(make([]byte, 0)); err != nil {
+		t.Fatalf("empty slice should always return nil: %s", err)
 	}
 }
diff --git a/src/crypto/rand/rand_getentropy.go b/src/crypto/rand/rand_getentropy.go
index dd72537..b1c19f3 100644
--- a/src/crypto/rand/rand_getentropy.go
+++ b/src/crypto/rand/rand_getentropy.go
@@ -15,7 +15,7 @@
 	altGetRandom = getEntropy
 }
 
-func getEntropy(p []byte) (ok bool) {
+func getEntropy(p []byte) error {
 	// getentropy(2) returns a maximum of 256 bytes per call
 	for i := 0; i < len(p); i += 256 {
 		end := i + 256
@@ -24,8 +24,8 @@
 		}
 		err := unix.GetEntropy(p[i:end])
 		if err != nil {
-			return false
+			return err
 		}
 	}
-	return true
+	return nil
 }
diff --git a/src/crypto/rand/rand_unix.go b/src/crypto/rand/rand_unix.go
index 34f4481..526e54a 100644
--- a/src/crypto/rand/rand_unix.go
+++ b/src/crypto/rand/rand_unix.go
@@ -52,7 +52,7 @@
 
 // altGetRandom if non-nil specifies an OS-specific function to get
 // urandom-style randomness.
-var altGetRandom func([]byte) (ok bool)
+var altGetRandom func([]byte) (err error)
 
 func warnBlocked() {
 	println("crypto/rand: blocked for 60 seconds waiting to read random data from the kernel")
@@ -66,7 +66,7 @@
 		t := time.AfterFunc(60*time.Second, warnBlocked)
 		defer t.Stop()
 	}
-	if altGetRandom != nil && r.name == urandomDevice && altGetRandom(b) {
+	if altGetRandom != nil && r.name == urandomDevice && altGetRandom(b) == nil {
 		return len(b), nil
 	}
 	r.mu.Lock()
diff --git a/src/crypto/rand/rand_windows.go b/src/crypto/rand/rand_windows.go
index 7379f14..6c0655c 100644
--- a/src/crypto/rand/rand_windows.go
+++ b/src/crypto/rand/rand_windows.go
@@ -9,7 +9,6 @@
 
 import (
 	"internal/syscall/windows"
-	"os"
 )
 
 func init() { Reader = &rngReader{} }
@@ -17,16 +16,11 @@
 type rngReader struct{}
 
 func (r *rngReader) Read(b []byte) (n int, err error) {
-	// RtlGenRandom only accepts 2**32-1 bytes at a time, so truncate.
-	inputLen := uint32(len(b))
-
-	if inputLen == 0 {
-		return 0, nil
+	// RtlGenRandom only returns 1<<32-1 bytes at a time. We only read at
+	// most 1<<31-1 bytes at a time so that  this works the same on 32-bit
+	// and 64-bit systems.
+	if err := batched(windows.RtlGenRandom, 1<<31-1)(b); err != nil {
+		return 0, err
 	}
-
-	err = windows.RtlGenRandom(b)
-	if err != nil {
-		return 0, os.NewSyscallError("RtlGenRandom", err)
-	}
-	return int(inputLen), nil
+	return len(b), nil
 }
diff --git a/src/crypto/tls/conn.go b/src/crypto/tls/conn.go
index 969f357..d0a2550 100644
--- a/src/crypto/tls/conn.go
+++ b/src/crypto/tls/conn.go
@@ -32,6 +32,7 @@
 
 	// handshakeStatus is 1 if the connection is currently transferring
 	// application data (i.e. is not currently processing a handshake).
+	// handshakeStatus == 1 implies handshakeErr == nil.
 	// This field is only to be accessed with sync/atomic.
 	handshakeStatus uint32
 	// constant after handshake; protected by handshakeMutex
@@ -1396,6 +1397,13 @@
 }
 
 func (c *Conn) handshakeContext(ctx context.Context) (ret error) {
+	// Fast sync/atomic-based exit if there is no handshake in flight and the
+	// last one succeeded without an error. Avoids the expensive context setup
+	// and mutex for most Read and Write calls.
+	if c.handshakeComplete() {
+		return nil
+	}
+
 	handshakeCtx, cancel := context.WithCancel(ctx)
 	// Note: defer this before starting the "interrupter" goroutine
 	// so that we can tell the difference between the input being canceled and
@@ -1454,6 +1462,9 @@
 	if c.handshakeErr == nil && !c.handshakeComplete() {
 		c.handshakeErr = errors.New("tls: internal error: handshake should have had a result")
 	}
+	if c.handshakeErr != nil && c.handshakeComplete() {
+		panic("tls: internal error: handshake returned an error but is marked successful")
+	}
 
 	return c.handshakeErr
 }
diff --git a/src/crypto/tls/handshake_server_tls13.go b/src/crypto/tls/handshake_server_tls13.go
index 109ff7a..1b2bf4d 100644
--- a/src/crypto/tls/handshake_server_tls13.go
+++ b/src/crypto/tls/handshake_server_tls13.go
@@ -10,6 +10,7 @@
 	"crypto"
 	"crypto/hmac"
 	"crypto/rsa"
+	"encoding/binary"
 	"errors"
 	"hash"
 	"io"
@@ -745,6 +746,19 @@
 	}
 	m.lifetime = uint32(maxSessionTicketLifetime / time.Second)
 
+	// ticket_age_add is a random 32-bit value. See RFC 8446, section 4.6.1
+	// The value is not stored anywhere; we never need to check the ticket age
+	// because 0-RTT is not supported.
+	ageAdd := make([]byte, 4)
+	_, err = hs.c.config.rand().Read(ageAdd)
+	if err != nil {
+		return err
+	}
+	m.ageAdd = binary.LittleEndian.Uint32(ageAdd)
+
+	// ticket_nonce, which must be unique per connection, is always left at
+	// zero because we only ever send one ticket per connection.
+
 	if _, err := c.writeRecord(recordTypeHandshake, m.marshal()); err != nil {
 		return err
 	}
diff --git a/src/os/exec/exec.go b/src/os/exec/exec.go
index 0c49575..505de58 100644
--- a/src/os/exec/exec.go
+++ b/src/os/exec/exec.go
@@ -374,6 +374,9 @@
 // The Wait method will return the exit code and release associated resources
 // once the command exits.
 func (c *Cmd) Start() error {
+	if c.Path == "" && c.lookPathErr == nil {
+		c.lookPathErr = errors.New("exec: no command")
+	}
 	if c.lookPathErr != nil {
 		c.closeDescriptors(c.closeAfterStart)
 		c.closeDescriptors(c.closeAfterWait)
diff --git a/src/os/exec/exec_test.go b/src/os/exec/exec_test.go
index d854e0d..a951be7 100644
--- a/src/os/exec/exec_test.go
+++ b/src/os/exec/exec_test.go
@@ -1156,3 +1156,11 @@
 		t.Error("no SYSTEMROOT found")
 	}
 }
+
+func TestNoPath(t *testing.T) {
+	err := new(exec.Cmd).Start()
+	want := "exec: no command"
+	if err == nil || err.Error() != want {
+		t.Errorf("new(Cmd).Start() = %v, want %q", err, want)
+	}
+}
diff --git a/src/path/filepath/path.go b/src/path/filepath/path.go
index b56534d..8300a32 100644
--- a/src/path/filepath/path.go
+++ b/src/path/filepath/path.go
@@ -117,9 +117,21 @@
 		case os.IsPathSeparator(path[r]):
 			// empty path element
 			r++
-		case path[r] == '.' && (r+1 == n || os.IsPathSeparator(path[r+1])):
+		case path[r] == '.' && r+1 == n:
 			// . element
 			r++
+		case path[r] == '.' && os.IsPathSeparator(path[r+1]):
+			// ./ element
+			r++
+
+			for r < len(path) && os.IsPathSeparator(path[r]) {
+				r++
+			}
+			if out.w == 0 && volumeNameLen(path[r:]) > 0 {
+				// When joining prefix "." and an absolute path on Windows,
+				// the prefix should not be removed.
+				out.append('.')
+			}
 		case path[r] == '.' && path[r+1] == '.' && (r+2 == n || os.IsPathSeparator(path[r+2])):
 			// .. element: remove to last separator
 			r += 2
diff --git a/src/path/filepath/path_test.go b/src/path/filepath/path_test.go
index bc5509b..ed17a88 100644
--- a/src/path/filepath/path_test.go
+++ b/src/path/filepath/path_test.go
@@ -93,6 +93,9 @@
 	{`//host/share/foo/../baz`, `\\host\share\baz`},
 	{`\\a\b\..\c`, `\\a\b\c`},
 	{`\\a\b`, `\\a\b`},
+	{`.\c:`, `.\c:`},
+	{`.\c:\foo`, `.\c:\foo`},
+	{`.\c:foo`, `.\c:foo`},
 }
 
 func TestClean(t *testing.T) {
diff --git a/src/path/filepath/path_windows_test.go b/src/path/filepath/path_windows_test.go
index 76a459a..3edafb5 100644
--- a/src/path/filepath/path_windows_test.go
+++ b/src/path/filepath/path_windows_test.go
@@ -530,3 +530,29 @@
 		t.Errorf(`EvalSymlinks(%q): got %q, want %q`, filelink, got, want)
 	}
 }
+
+func TestIssue52476(t *testing.T) {
+	tests := []struct {
+		lhs, rhs string
+		want     string
+	}{
+		{`..\.`, `C:`, `..\C:`},
+		{`..`, `C:`, `..\C:`},
+		{`.`, `:`, `:`},
+		{`.`, `C:`, `.\C:`},
+		{`.`, `C:/a/b/../c`, `.\C:\a\c`},
+		{`.`, `\C:`, `.\C:`},
+		{`C:\`, `.`, `C:\`},
+		{`C:\`, `C:\`, `C:\C:`},
+		{`C`, `:`, `C\:`},
+		{`\.`, `C:`, `\C:`},
+		{`\`, `C:`, `\C:`},
+	}
+
+	for _, test := range tests {
+		got := filepath.Join(test.lhs, test.rhs)
+		if got != test.want {
+			t.Errorf(`Join(%q, %q): got %q, want %q`, test.lhs, test.rhs, got, test.want)
+		}
+	}
+}
diff --git a/src/runtime/gc_test.go b/src/runtime/gc_test.go
index 5e7c6c5..0ec5331 100644
--- a/src/runtime/gc_test.go
+++ b/src/runtime/gc_test.go
@@ -21,6 +21,7 @@
 )
 
 func TestGcSys(t *testing.T) {
+	t.Skip("skipping known-flaky test; golang.org/issue/37331")
 	if os.Getenv("GOGC") == "off" {
 		t.Skip("skipping test; GOGC=off in environment")
 	}
diff --git a/src/runtime/runtime-gdb_test.go b/src/runtime/runtime-gdb_test.go
index 8c76a91..097d1b5 100644
--- a/src/runtime/runtime-gdb_test.go
+++ b/src/runtime/runtime-gdb_test.go
@@ -427,6 +427,9 @@
 	got, err := exec.Command("gdb", args...).CombinedOutput()
 	t.Logf("gdb output:\n%s", got)
 	if err != nil {
+		if bytes.Contains(got, []byte("internal-error: wait returned unexpected status 0x0")) {
+			testenv.SkipFlaky(t, 43068)
+		}
 		t.Fatalf("gdb exited with error: %v", err)
 	}