[release] Snap to 85e6685445

Change-Id: I8ee7a2ec9aa2c0bdf7f919aa6d4d878fc86766f3
diff --git a/OWNERS b/OWNERS
index be2231d..157381a 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,5 +1,3 @@
-pascallouis@google.com
 maruel@google.com
-tamird@google.com
 
 # COMPONENT: Toolchain>Go
diff --git a/VERSION b/VERSION
index 0524870..03d7710 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-go1.20.5
\ No newline at end of file
+go1.20.6
\ No newline at end of file
diff --git a/api/fuchsia.txt b/api/fuchsia.txt
index 995935b..d32813a 100644
--- a/api/fuchsia.txt
+++ b/api/fuchsia.txt
@@ -1229,6 +1229,8 @@
 pkg syscall/zx/fidl, const ErrUnspecifiedHandleRights ErrorCode
 pkg syscall/zx/fidl, const ErrUnspecifiedHandleType = 35
 pkg syscall/zx/fidl, const ErrUnspecifiedHandleType ErrorCode
+pkg syscall/zx/fidl, const ErrUnsupportedWireFormatVersion = 39
+pkg syscall/zx/fidl, const ErrUnsupportedWireFormatVersion ErrorCode
 pkg syscall/zx/fidl, const ErrValueTypeHandles = 36
 pkg syscall/zx/fidl, const ErrValueTypeHandles ErrorCode
 pkg syscall/zx/fidl, const ErrVectorTooLong = 4
@@ -1263,6 +1265,7 @@
 pkg syscall/zx/fidl, method (*MessageHeader) IsSupportedVersion() bool
 pkg syscall/zx/fidl, method (*MessageHeader) Marshaler() Marshaler
 pkg syscall/zx/fidl, method (*MessageHeader) NewCtx() MarshalerContext
+pkg syscall/zx/fidl, method (*MessageHeader) ValidateWireFormat() error
 pkg syscall/zx/fidl, method (ErrorCode) Code() ErrorCode
 pkg syscall/zx/fidl, method (ErrorCode) Error() string
 pkg syscall/zx/fidl, method (ErrorCode) String() string
diff --git a/meta/go_net_test.cml b/meta/go_net_test.cml
index 44df54c..a94915c 100644
--- a/meta/go_net_test.cml
+++ b/meta/go_net_test.cml
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 {
     include: [
+        "//sdk/lib/inspect/offer.shard.cml",
         "//src/sys/test_runners/gotests/default.shard.cml",
         "//src/sys/test_runners/tmp_storage.shard.cml",
     ],
diff --git a/src/cmd/cgo/ast.go b/src/cmd/cgo/ast.go
index 81060c6..ba3c7da 100644
--- a/src/cmd/cgo/ast.go
+++ b/src/cmd/cgo/ast.go
@@ -80,6 +80,11 @@
 				cg = d.Doc
 			}
 			if cg != nil {
+				if strings.ContainsAny(abspath, "\r\n") {
+					// This should have been checked when the file path was first resolved,
+					// but we double check here just to be sure.
+					fatalf("internal error: ParseGo: abspath contains unexpected newline character: %q", abspath)
+				}
 				f.Preamble += fmt.Sprintf("#line %d %q\n", sourceLine(cg), abspath)
 				f.Preamble += commentText(cg) + "\n"
 				f.Preamble += "#line 1 \"cgo-generated-wrapper\"\n"
diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go
index f78969e..78020ae 100644
--- a/src/cmd/cgo/main.go
+++ b/src/cmd/cgo/main.go
@@ -363,6 +363,12 @@
 
 		// Apply trimpath to the file path. The path won't be read from after this point.
 		input, _ = objabi.ApplyRewrites(input, *trimpath)
+		if strings.ContainsAny(input, "\r\n") {
+			// ParseGo, (*Package).writeOutput, and printer.Fprint in SourcePos mode
+			// all emit line directives, which don't permit newlines in the file path.
+			// Bail early if we see anything newline-like in the trimmed path.
+			fatalf("input path contains newline character: %q", input)
+		}
 		goFiles[i] = input
 
 		f := new(File)
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
index d0c6fe3..b2933e2 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -48,7 +48,7 @@
 	fflg := creat(*objDir + "_cgo_flags")
 	for k, v := range p.CgoFlags {
 		for _, arg := range v {
-			fmt.Fprintf(fflg, "_CGO_%s=%s\n", arg)
+			fmt.Fprintf(fflg, "_CGO_%s=%s\n", k, arg)
 		}
 		if k == "LDFLAGS" && !*gccgo {
 			for _, arg := range v {
@@ -644,6 +644,11 @@
 
 	// Write Go output: Go input with rewrites of C.xxx to _C_xxx.
 	fmt.Fprintf(fgo1, "// Code generated by cmd/cgo; DO NOT EDIT.\n\n")
+	if strings.ContainsAny(srcfile, "\r\n") {
+		// This should have been checked when the file path was first resolved,
+		// but we double check here just to be sure.
+		fatalf("internal error: writeOutput: srcfile contains unexpected newline character: %q", srcfile)
+	}
 	fmt.Fprintf(fgo1, "//line %s:1:1\n", srcfile)
 	fgo1.Write(f.Edit.Bytes())
 
diff --git a/src/cmd/compile/internal/typecheck/const.go b/src/cmd/compile/internal/typecheck/const.go
index 6855f05..fd80d70 100644
--- a/src/cmd/compile/internal/typecheck/const.go
+++ b/src/cmd/compile/internal/typecheck/const.go
@@ -367,29 +367,7 @@
 		}
 
 	case ir.OADD, ir.OSUB, ir.OMUL, ir.ODIV, ir.OMOD, ir.OOR, ir.OXOR, ir.OAND, ir.OANDNOT:
-		n := n.(*ir.BinaryExpr)
-		nl, nr := n.X, n.Y
-		if nl.Op() == ir.OLITERAL && nr.Op() == ir.OLITERAL {
-			rval := nr.Val()
-
-			// check for divisor underflow in complex division (see issue 20227)
-			if n.Op() == ir.ODIV && n.Type().IsComplex() && constant.Sign(square(constant.Real(rval))) == 0 && constant.Sign(square(constant.Imag(rval))) == 0 {
-				base.Errorf("complex division by zero")
-				n.SetType(nil)
-				return n
-			}
-			if (n.Op() == ir.ODIV || n.Op() == ir.OMOD) && constant.Sign(rval) == 0 {
-				base.Errorf("division by zero")
-				n.SetType(nil)
-				return n
-			}
-
-			tok := tokenForOp[n.Op()]
-			if n.Op() == ir.ODIV && n.Type().IsInteger() {
-				tok = token.QUO_ASSIGN // integer division
-			}
-			return OrigConst(n, constant.BinaryOp(nl.Val(), tok, rval))
-		}
+		return n
 
 	case ir.OOROR, ir.OANDAND:
 		n := n.(*ir.LogicalExpr)
@@ -406,19 +384,7 @@
 		}
 
 	case ir.OLSH, ir.ORSH:
-		n := n.(*ir.BinaryExpr)
-		nl, nr := n.X, n.Y
-		if nl.Op() == ir.OLITERAL && nr.Op() == ir.OLITERAL {
-			// shiftBound from go/types; "so we can express smallestFloat64" (see issue #44057)
-			const shiftBound = 1023 - 1 + 52
-			s, ok := constant.Uint64Val(nr.Val())
-			if !ok || s > shiftBound {
-				base.Errorf("invalid shift count %v", nr)
-				n.SetType(nil)
-				break
-			}
-			return OrigConst(n, constant.Shift(toint(nl.Val()), tokenForOp[n.Op()], uint(s)))
-		}
+		return n
 
 	case ir.OCONV, ir.ORUNESTR:
 		n := n.(*ir.ConvExpr)
diff --git a/src/cmd/compile/internal/typecheck/expr.go b/src/cmd/compile/internal/typecheck/expr.go
index 0cd69ab..ef61b74 100644
--- a/src/cmd/compile/internal/typecheck/expr.go
+++ b/src/cmd/compile/internal/typecheck/expr.go
@@ -184,13 +184,6 @@
 		}
 	}
 
-	if (op == ir.ODIV || op == ir.OMOD) && ir.IsConst(r, constant.Int) {
-		if constant.Sign(r.Val()) == 0 {
-			base.Errorf("division by zero")
-			return l, r, nil
-		}
-	}
-
 	return l, r, t
 }
 
diff --git a/src/cmd/cover/cover.go b/src/cmd/cover/cover.go
index 74bb500..5fd8b95 100644
--- a/src/cmd/cover/cover.go
+++ b/src/cmd/cover/cover.go
@@ -568,6 +568,11 @@
 	}
 	// TODO: process files in parallel here if it matters.
 	for k, name := range names {
+		if strings.ContainsAny(name, "\r\n") {
+			// annotateFile uses '//line' directives, which don't permit newlines.
+			log.Fatalf("cover: input path contains newline character: %q", name)
+		}
+
 		last := false
 		if k == len(names)-1 {
 			last = true
@@ -645,6 +650,11 @@
 	}
 	newContent := file.edit.Bytes()
 
+	if strings.ContainsAny(name, "\r\n") {
+		// This should have been checked by the caller already, but we double check
+		// here just to be sure we haven't missed a caller somewhere.
+		panic(fmt.Sprintf("annotateFile: name contains unexpected newline character: %q", name))
+	}
 	fmt.Fprintf(fd, "//line %s:1:1\n", name)
 	fd.Write(newContent)
 
diff --git a/src/cmd/cover/cover_test.go b/src/cmd/cover/cover_test.go
index af266b5..6ed4ae4 100644
--- a/src/cmd/cover/cover_test.go
+++ b/src/cmd/cover/cover_test.go
@@ -574,3 +574,34 @@
 	}
 	return string(out)
 }
+
+func TestSrcPathWithNewline(t *testing.T) {
+	testenv.MustHaveExec(t)
+	t.Parallel()
+
+	// srcPath is intentionally not clean so that the path passed to testcover
+	// will not normalize the trailing / to a \ on Windows.
+	srcPath := t.TempDir() + string(filepath.Separator) + "\npackage main\nfunc main() { panic(string([]rune{'u', 'h', '-', 'o', 'h'}))\n/*/main.go"
+	mainSrc := ` package main
+
+func main() {
+	/* nothing here */
+	println("ok")
+}
+`
+	if err := os.MkdirAll(filepath.Dir(srcPath), 0777); err != nil {
+		t.Skipf("creating directory with bogus path: %v", err)
+	}
+	if err := os.WriteFile(srcPath, []byte(mainSrc), 0666); err != nil {
+		t.Skipf("writing file with bogus directory: %v", err)
+	}
+
+	cmd := testenv.Command(t, testcover(t), "-mode=atomic", srcPath)
+	cmd.Stderr = new(bytes.Buffer)
+	out, err := cmd.Output()
+	t.Logf("%v:\n%s", cmd, out)
+	t.Logf("stderr:\n%s", cmd.Stderr)
+	if err == nil {
+		t.Errorf("unexpected success; want failure due to newline in file path")
+	}
+}
diff --git a/src/cmd/go/go_unix_test.go b/src/cmd/go/go_unix_test.go
index bab9494..7cc6825 100644
--- a/src/cmd/go/go_unix_test.go
+++ b/src/cmd/go/go_unix_test.go
@@ -2,12 +2,18 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
+//go:build unix
 
 package main_test
 
 import (
+	"bufio"
+	"context"
+	"internal/testenv"
+	"io"
 	"os"
+	"os/exec"
+	"strings"
 	"syscall"
 	"testing"
 )
@@ -33,3 +39,80 @@
 		t.Fatalf("wrote x with mode=%v, wanted no 0077 bits", mode)
 	}
 }
+
+// TestTestInterrupt verifies the fix for issue #60203.
+//
+// If the whole process group for a 'go test' invocation receives
+// SIGINT (as would be sent by pressing ^C on a console),
+// it should return quickly, not deadlock.
+func TestTestInterrupt(t *testing.T) {
+	if testing.Short() {
+		t.Skipf("skipping in short mode: test executes many subprocesses")
+	}
+	// Don't run this test in parallel, for the same reason.
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.setenv("GOROOT", testGOROOT)
+
+	ctx, cancel := context.WithCancel(context.Background())
+	cmd := testenv.CommandContext(t, ctx, tg.goTool(), "test", "std", "-short", "-count=1")
+	cmd.Dir = tg.execDir
+
+	// Override $TMPDIR when running the tests: since we're terminating the tests
+	// with a signal they might fail to clean up some temp files, and we don't
+	// want that to cause an "unexpected files" failure at the end of the run.
+	cmd.Env = append(tg.env[:len(tg.env):len(tg.env)], tempEnvName()+"="+t.TempDir())
+
+	cmd.SysProcAttr = &syscall.SysProcAttr{
+		Setpgid: true,
+	}
+	cmd.Cancel = func() error {
+		pgid := cmd.Process.Pid
+		return syscall.Kill(-pgid, syscall.SIGINT)
+	}
+
+	pipe, err := cmd.StdoutPipe()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	t.Logf("running %v", cmd)
+	if err := cmd.Start(); err != nil {
+		t.Fatal(err)
+	}
+
+	stdout := new(strings.Builder)
+	r := bufio.NewReader(pipe)
+	line, err := r.ReadString('\n')
+	if err != nil {
+		t.Fatal(err)
+	}
+	stdout.WriteString(line)
+
+	// The output line for some test was written, so we know things are in progress.
+	//
+	// Cancel the rest of the run by sending SIGINT to the process group:
+	// it should finish up and exit with a nonzero status,
+	// not have to be killed with SIGKILL.
+	cancel()
+
+	io.Copy(stdout, r)
+	if stdout.Len() > 0 {
+		t.Logf("stdout:\n%s", stdout)
+	}
+	err = cmd.Wait()
+
+	ee, _ := err.(*exec.ExitError)
+	if ee == nil {
+		t.Fatalf("unexpectedly finished with nonzero status")
+	}
+	if len(ee.Stderr) > 0 {
+		t.Logf("stderr:\n%s", ee.Stderr)
+	}
+	if !ee.Exited() {
+		t.Fatalf("'go test' did not exit after interrupt: %v", err)
+	}
+
+	t.Logf("interrupted tests without deadlocking")
+}
diff --git a/src/cmd/go/internal/modload/buildlist.go b/src/cmd/go/internal/modload/buildlist.go
index aa59611..29a80b5 100644
--- a/src/cmd/go/internal/modload/buildlist.go
+++ b/src/cmd/go/internal/modload/buildlist.go
@@ -10,6 +10,7 @@
 	"cmd/go/internal/mvs"
 	"cmd/go/internal/par"
 	"context"
+	"errors"
 	"fmt"
 	"os"
 	"reflect"
@@ -689,8 +690,8 @@
 // roots) until the set of roots has converged.
 func tidyPrunedRoots(ctx context.Context, mainModule module.Version, direct map[string]bool, pkgs []*loadPkg) (*Requirements, error) {
 	var (
-		roots        []module.Version
-		pathIncluded = map[string]bool{mainModule.Path: true}
+		roots      []module.Version
+		pathIsRoot = map[string]bool{mainModule.Path: true}
 	)
 	// We start by adding roots for every package in "all".
 	//
@@ -710,9 +711,9 @@
 		if !pkg.flags.has(pkgInAll) {
 			continue
 		}
-		if pkg.fromExternalModule() && !pathIncluded[pkg.mod.Path] {
+		if pkg.fromExternalModule() && !pathIsRoot[pkg.mod.Path] {
 			roots = append(roots, pkg.mod)
-			pathIncluded[pkg.mod.Path] = true
+			pathIsRoot[pkg.mod.Path] = true
 		}
 		queue = append(queue, pkg)
 		queued[pkg] = true
@@ -744,11 +745,12 @@
 				queue = append(queue, pkg.test)
 				queued[pkg.test] = true
 			}
-			if !pathIncluded[m.Path] {
+
+			if !pathIsRoot[m.Path] {
 				if s := mg.Selected(m.Path); cmpVersion(s, m.Version) < 0 {
 					roots = append(roots, m)
+					pathIsRoot[m.Path] = true
 				}
-				pathIncluded[m.Path] = true
 			}
 		}
 
@@ -758,10 +760,62 @@
 		}
 	}
 
+	roots = tidy.rootModules
 	_, err := tidy.Graph(ctx)
 	if err != nil {
 		return nil, err
 	}
+
+	// We try to avoid adding explicit requirements for test-only dependencies of
+	// packages in external modules. However, if we drop the explicit
+	// requirements, that may change an import from unambiguous (due to lazy
+	// module loading) to ambiguous (because lazy module loading no longer
+	// disambiguates it). For any package that has become ambiguous, we try
+	// to fix it by promoting its module to an explicit root.
+	// (See https://go.dev/issue/60313.)
+	q := par.NewQueue(runtime.GOMAXPROCS(0))
+	for {
+		var disambiguateRoot sync.Map
+		for _, pkg := range pkgs {
+			if pkg.mod.Path == "" || pathIsRoot[pkg.mod.Path] {
+				// Lazy module loading will cause pkg.mod to be checked before any other modules
+				// that are only indirectly required. It is as unambiguous as possible.
+				continue
+			}
+			pkg := pkg
+			q.Add(func() {
+				skipModFile := true
+				_, _, _, _, err := importFromModules(ctx, pkg.path, tidy, nil, skipModFile)
+				if aie := (*AmbiguousImportError)(nil); errors.As(err, &aie) {
+					disambiguateRoot.Store(pkg.mod, true)
+				}
+			})
+		}
+		<-q.Idle()
+
+		disambiguateRoot.Range(func(k, _ any) bool {
+			m := k.(module.Version)
+			roots = append(roots, m)
+			pathIsRoot[m.Path] = true
+			return true
+		})
+
+		if len(roots) > len(tidy.rootModules) {
+			module.Sort(roots)
+			tidy = newRequirements(pruned, roots, tidy.direct)
+			_, err = tidy.Graph(ctx)
+			if err != nil {
+				return nil, err
+			}
+			// Adding these roots may have pulled additional modules into the module
+			// graph, causing additional packages to become ambiguous. Keep iterating
+			// until we reach a fixed point.
+			continue
+		}
+
+		break
+	}
+
 	return tidy, nil
 }
 
diff --git a/src/cmd/go/internal/modload/init.go b/src/cmd/go/internal/modload/init.go
index 9f07658..58074bb 100644
--- a/src/cmd/go/internal/modload/init.go
+++ b/src/cmd/go/internal/modload/init.go
@@ -1597,7 +1597,17 @@
 	// paths of loaded packages. We need to retain sums for all of these modules —
 	// not just the modules containing the actual packages — in order to rule out
 	// ambiguous import errors the next time we load the package.
-	if ld != nil {
+	keepModSumsForZipSums := true
+	if ld == nil {
+		if cfg.BuildMod != "mod" && semver.Compare("v"+MainModules.GoVersion(), tidyGoModSumVersionV) < 0 {
+			keepModSumsForZipSums = false
+		}
+	} else {
+		keepPkgGoModSums := true
+		if (ld.Tidy || cfg.BuildMod != "mod") && semver.Compare("v"+ld.GoVersion, tidyGoModSumVersionV) < 0 {
+			keepPkgGoModSums = false
+			keepModSumsForZipSums = false
+		}
 		for _, pkg := range ld.pkgs {
 			// We check pkg.mod.Path here instead of pkg.inStd because the
 			// pseudo-package "C" is not in std, but not provided by any module (and
@@ -1611,7 +1621,7 @@
 			// However, we didn't do so before Go 1.21, and the bug is relatively
 			// minor, so we maintain the previous (buggy) behavior in 'go mod tidy' to
 			// avoid introducing unnecessary churn.
-			if !ld.Tidy || semver.Compare("v"+ld.GoVersion, tidyGoModSumVersionV) >= 0 {
+			if keepPkgGoModSums {
 				r := resolveReplacement(pkg.mod)
 				keep[modkey(r)] = true
 			}
@@ -1671,7 +1681,9 @@
 		if which == addBuildListZipSums {
 			for _, m := range mg.BuildList() {
 				r := resolveReplacement(m)
-				keep[modkey(r)] = true // we need the go version from the go.mod file to do anything useful with the zipfile
+				if keepModSumsForZipSums {
+					keep[modkey(r)] = true // we need the go version from the go.mod file to do anything useful with the zipfile
+				}
 				keep[r] = true
 			}
 		}
diff --git a/src/cmd/go/internal/modload/query_test.go b/src/cmd/go/internal/modload/query_test.go
index fe9ae9f..93f8f0d 100644
--- a/src/cmd/go/internal/modload/query_test.go
+++ b/src/cmd/go/internal/modload/query_test.go
@@ -55,6 +55,7 @@
 	os.Setenv("GOPATH", dir)
 	cfg.BuildContext.GOPATH = dir
 	cfg.GOMODCACHE = filepath.Join(dir, "pkg/mod")
+	cfg.SumdbDir = filepath.Join(dir, "pkg/sumdb")
 	m.Run()
 	return nil
 }
diff --git a/src/cmd/go/internal/test/test.go b/src/cmd/go/internal/test/test.go
index 28bfabd..6815bbc 100644
--- a/src/cmd/go/internal/test/test.go
+++ b/src/cmd/go/internal/test/test.go
@@ -1148,7 +1148,15 @@
 
 func (r *runTestActor) Act(b *work.Builder, ctx context.Context, a *work.Action) error {
 	// Wait for previous test to get started and print its first json line.
-	<-r.prev
+	select {
+	case <-r.prev:
+	case <-base.Interrupted:
+		// We can't wait for the previous test action to complete: we don't start
+		// new actions after an interrupt, so if that action wasn't already running
+		// it might never happen. Instead, just don't log anything for this action.
+		base.SetExitStatus(1)
+		return nil
+	}
 
 	if a.Failed {
 		// We were unable to build the binary.
diff --git a/src/cmd/go/testdata/script/build_cwd_newline.txt b/src/cmd/go/testdata/script/build_cwd_newline.txt
index 574464c..91cb57f 100644
--- a/src/cmd/go/testdata/script/build_cwd_newline.txt
+++ b/src/cmd/go/testdata/script/build_cwd_newline.txt
@@ -11,29 +11,47 @@
 exec pwd
 cp $WORK/go.mod ./go.mod
 cp $WORK/main.go ./main.go
+cp $WORK/main_nocgo.go ./main_nocgo.go
 cp $WORK/main_test.go ./main_test.go
 
 ! go build -o $devnull .
 stderr 'package example: invalid package directory .*uh-oh'
 
-! go build -o $devnull main.go
+[cgo] ! go build -o $devnull main.go
+[!cgo] ! go build -o $devnull main_nocgo.go
 stderr 'package command-line-arguments: invalid package directory .*uh-oh'
 
 ! go run .
 stderr 'package example: invalid package directory .*uh-oh'
 
-! go run main.go
+[cgo] ! go run main.go
+[!cgo] ! go run main_nocgo.go
 stderr 'package command-line-arguments: invalid package directory .*uh-oh'
 
 ! go test .
 stderr 'package example: invalid package directory .*uh-oh'
 
-! go test -v main.go main_test.go
+[cgo] ! go test -v main.go main_test.go
+[!cgo] ! go test -v main_nocgo.go main_test.go
 stderr 'package command-line-arguments: invalid package directory .*uh-oh'
 
 go list -compiled -e -f '{{with .CompiledGoFiles}}{{.}}{{end}}' .
 ! stdout .
 ! stderr .
+! exists obj_
+
+
+# The cgo tool should only accept the source file if the working directory
+# is not written in line directives in the resulting files.
+
+[cgo] ! go tool cgo main.go
+[cgo] stderr 'cgo: input path contains newline character: .*uh-oh'
+[cgo] ! exists _obj
+
+[cgo] go tool cgo -trimpath=$PWD main.go
+[cgo] grep '//line main\.go:1:1' _obj/main.cgo1.go
+[cgo] ! grep 'uh-oh' _obj/main.cgo1.go
+[cgo] rm _obj
 
 
 # Since we do preserve $PWD (or set it appropriately) for commands, and we do
@@ -46,19 +64,22 @@
 
 symlink $WORK${/}link -> $DIR
 
-go run $WORK${/}link${/}main.go
+[cgo] go run $WORK${/}link${/}main.go
+[!cgo] go run $WORK${/}link${/}main_nocgo.go
 ! stdout panic
 ! stderr panic
 stderr '^ok$'
 
-go test -v $WORK${/}link${/}main.go $WORK${/}link${/}main_test.go
+[cgo] go test -v $WORK${/}link${/}main.go $WORK${/}link${/}main_test.go
+[!cgo] go test -v $WORK${/}link${/}main_nocgo.go $WORK${/}link${/}main_test.go
 ! stdout panic
 ! stderr panic
 stdout '^ok$'   # 'go test' combines the test's stdout into stderr
 
 cd $WORK/link
 
-! go run $DIR${/}main.go
+[cgo] ! go run $DIR${/}main.go
+[!cgo] ! go run $DIR${/}main_nocgo.go
 stderr 'package command-line-arguments: invalid package directory .*uh-oh'
 
 go run .
@@ -66,7 +87,8 @@
 ! stderr panic
 stderr '^ok$'
 
-go run main.go
+[cgo] go run main.go
+[!cgo] go run main_nocgo.go
 ! stdout panic
 ! stderr panic
 stderr '^ok$'
@@ -81,6 +103,9 @@
 ! stderr panic
 stdout '^ok$'  # 'go test' combines the test's stdout into stderr
 
+[cgo] go tool cgo main.go
+[cgo] grep '//line .*'${/}'link'${/}'main\.go:1:1' _obj/main.cgo1.go
+[cgo] ! grep 'uh-oh' _obj/main.cgo1.go
 
 -- $WORK/go.mod --
 module example
@@ -94,6 +119,15 @@
 	/* nothing here */
 	println("ok")
 }
+-- $WORK/main_nocgo.go --
+//go:build !cgo
+
+package main
+
+func main() {
+	/* nothing here */
+	println("ok")
+}
 -- $WORK/main_test.go --
 package main
 
diff --git a/src/cmd/go/testdata/script/gccgo_link_ldflags.txt b/src/cmd/go/testdata/script/gccgo_link_ldflags.txt
index 4e91ae5..80526c6 100644
--- a/src/cmd/go/testdata/script/gccgo_link_ldflags.txt
+++ b/src/cmd/go/testdata/script/gccgo_link_ldflags.txt
@@ -9,6 +9,9 @@
 
 [!exec:gccgo] skip
 
+# TODO: remove once gccgo on builder is updated
+[GOOS:aix] [GOARCH:ppc64] skip
+
 go build -compiler gccgo
 
 -- go.mod --
diff --git a/src/cmd/go/testdata/script/list_empty_import.txt b/src/cmd/go/testdata/script/list_empty_import.txt
new file mode 100644
index 0000000..4d76f09
--- /dev/null
+++ b/src/cmd/go/testdata/script/list_empty_import.txt
@@ -0,0 +1,9 @@
+! go list a.go
+! stdout .
+stderr 'invalid import path'
+! stderr panic
+
+-- a.go --
+package a
+
+import ""
diff --git a/src/cmd/go/testdata/script/mod_sum_issue56222.txt b/src/cmd/go/testdata/script/mod_sum_issue56222.txt
index 4c071c1..e4a468c 100644
--- a/src/cmd/go/testdata/script/mod_sum_issue56222.txt
+++ b/src/cmd/go/testdata/script/mod_sum_issue56222.txt
@@ -23,6 +23,10 @@
 go mod tidy -go=1.20
 go clean -modcache  # Remove checksums from the module cache, so that only go.sum is used.
 
+# Issue 60667: 'go list' without -mod=mod shouldn't report the checksums as
+# dirty either.
+go list -m -u all
+
 env OLDSUMDB=$GOSUMDB
 env GOSUMDB=bad
 go mod tidy
diff --git a/src/cmd/go/testdata/script/mod_tidy_issue60313.txt b/src/cmd/go/testdata/script/mod_tidy_issue60313.txt
new file mode 100644
index 0000000..c5cd6c7
--- /dev/null
+++ b/src/cmd/go/testdata/script/mod_tidy_issue60313.txt
@@ -0,0 +1,69 @@
+# Regression test for https://go.dev/issue/60313: 'go mod tidy' did not preserve
+# dependencies needed to prevent 'ambiguous import' errors in external test
+# dependencies.
+
+cp go.mod go.mod.orig
+go mod tidy
+cmp go.mod go.mod.orig
+
+-- go.mod --
+module example
+
+go 1.20
+
+require (
+	example.net/a v0.1.0
+	example.net/b v0.1.0
+)
+
+require example.net/outer/inner v0.1.0 // indirect
+
+replace (
+	example.net/a v0.1.0 => ./a
+	example.net/b v0.1.0 => ./b
+	example.net/outer v0.1.0 => ./outer
+	example.net/outer/inner v0.1.0 => ./inner
+)
+-- example.go --
+package example
+
+import (
+	_ "example.net/a"
+	_ "example.net/b"
+)
+-- a/go.mod --
+module example.net/a
+
+go 1.20
+
+require example.net/outer/inner v0.1.0
+-- a/a.go --
+package a
+-- a/a_test.go --
+package a_test
+
+import _ "example.net/outer/inner"
+-- b/go.mod --
+module example.net/b
+
+go 1.20
+
+require example.net/outer v0.1.0
+-- b/b.go --
+package b
+-- b/b_test.go --
+package b_test
+
+import _ "example.net/outer/inner"
+-- inner/go.mod --
+module example.net/outer/inner
+
+go 1.20
+-- inner/inner.go --
+package inner
+-- outer/go.mod --
+module example.net/outer
+
+go 1.20
+-- outer/inner/inner.go --
+package inner
diff --git a/src/cmd/go/testdata/script/test_flags.txt b/src/cmd/go/testdata/script/test_flags.txt
index 63385e6..3f7964b 100644
--- a/src/cmd/go/testdata/script/test_flags.txt
+++ b/src/cmd/go/testdata/script/test_flags.txt
@@ -15,8 +15,7 @@
 # Even though ./x looks like a package path, the real package should be
 # the implicit '.'.
 ! go test --answer=42 ./x
-stderr '^no Go files in .+$'
-! stderr '/x'
+stderr '^no Go files in '$PWD'$'
 
 # However, *flags* that appear after unrecognized flags should still be
 # interpreted as flags, under the (possibly-erroneous) assumption that
diff --git a/src/context/context_test.go b/src/context/context_test.go
index eb5a86b..1c770cd 100644
--- a/src/context/context_test.go
+++ b/src/context/context_test.go
@@ -670,26 +670,26 @@
 }
 
 func XTestWithValueChecksKey(t testingT) {
-	panicVal := recoveredValue(func() { WithValue(Background(), []byte("foo"), "bar") })
+	panicVal := recoveredValue(func() { _ = WithValue(Background(), []byte("foo"), "bar") })
 	if panicVal == nil {
 		t.Error("expected panic")
 	}
-	panicVal = recoveredValue(func() { WithValue(Background(), nil, "bar") })
+	panicVal = recoveredValue(func() { _ = WithValue(Background(), nil, "bar") })
 	if got, want := fmt.Sprint(panicVal), "nil key"; got != want {
 		t.Errorf("panic = %q; want %q", got, want)
 	}
 }
 
 func XTestInvalidDerivedFail(t testingT) {
-	panicVal := recoveredValue(func() { WithCancel(nil) })
+	panicVal := recoveredValue(func() { _, _ = WithCancel(nil) })
 	if panicVal == nil {
 		t.Error("expected panic")
 	}
-	panicVal = recoveredValue(func() { WithDeadline(nil, time.Now().Add(shortDuration)) })
+	panicVal = recoveredValue(func() { _, _ = WithDeadline(nil, time.Now().Add(shortDuration)) })
 	if panicVal == nil {
 		t.Error("expected panic")
 	}
-	panicVal = recoveredValue(func() { WithValue(nil, "foo", "bar") })
+	panicVal = recoveredValue(func() { _ = WithValue(nil, "foo", "bar") })
 	if panicVal == nil {
 		t.Error("expected panic")
 	}
diff --git a/src/crypto/ecdsa/ecdsa.go b/src/crypto/ecdsa/ecdsa.go
index 68272af..03a9a72 100644
--- a/src/crypto/ecdsa/ecdsa.go
+++ b/src/crypto/ecdsa/ecdsa.go
@@ -380,7 +380,7 @@
 	// an integer modulo N. This is the absolute worst of all worlds: we still
 	// have to reduce, because the result might still overflow N, but to take
 	// the left-most bits for P-521 we have to do a right shift.
-	if size := c.N.Size(); len(hash) > size {
+	if size := c.N.Size(); len(hash) >= size {
 		hash = hash[:size]
 		if excess := len(hash)*8 - c.N.BitLen(); excess > 0 {
 			hash = bytes.Clone(hash)
diff --git a/src/crypto/ecdsa/ecdsa_test.go b/src/crypto/ecdsa/ecdsa_test.go
index 95c78c8..08a0903 100644
--- a/src/crypto/ecdsa/ecdsa_test.go
+++ b/src/crypto/ecdsa/ecdsa_test.go
@@ -9,6 +9,7 @@
 	"bytes"
 	"compress/bzip2"
 	"crypto/elliptic"
+	"crypto/internal/bigmod"
 	"crypto/rand"
 	"crypto/sha1"
 	"crypto/sha256"
@@ -398,6 +399,20 @@
 	}
 }
 
+func TestHashToNat(t *testing.T) {
+	t.Run("P-224", func(t *testing.T) { testHashToNat(t, p224()) })
+	t.Run("P-256", func(t *testing.T) { testHashToNat(t, p256()) })
+	t.Run("P-384", func(t *testing.T) { testHashToNat(t, p384()) })
+	t.Run("P-521", func(t *testing.T) { testHashToNat(t, p521()) })
+}
+
+func testHashToNat[Point nistPoint[Point]](t *testing.T, c *nistCurve[Point]) {
+	for l := 0; l < 600; l++ {
+		h := bytes.Repeat([]byte{0xff}, l)
+		hashToNat(c, bigmod.NewNat(), h)
+	}
+}
+
 func TestZeroSignature(t *testing.T) {
 	testAllCurves(t, testZeroSignature)
 }
diff --git a/src/crypto/x509/verify_test.go b/src/crypto/x509/verify_test.go
index 164c47f..d4cbb82 100644
--- a/src/crypto/x509/verify_test.go
+++ b/src/crypto/x509/verify_test.go
@@ -500,22 +500,21 @@
 		return true
 	}
 
-	// Every expected chain should match 1 returned chain
+	// Every expected chain should match one (or more) returned chain. We tolerate multiple
+	// matches, as due to root store semantics it is plausible that (at least on the system
+	// verifiers) multiple identical (looking) chains may be returned when two roots with the
+	// same subject are present.
 	for _, expectedChain := range test.expectedChains {
-		nChainMatched := 0
+		var match bool
 		for _, chain := range chains {
 			if doesMatch(expectedChain, chain) {
-				nChainMatched++
+				match = true
+				break
 			}
 		}
 
-		if nChainMatched != 1 {
-			t.Errorf("Got %v matches instead of %v for expected chain %v", nChainMatched, 1, expectedChain)
-			for _, chain := range chains {
-				if doesMatch(expectedChain, chain) {
-					t.Errorf("\t matched %v", chainToDebugString(chain))
-				}
-			}
+		if !match {
+			t.Errorf("No match found for %v", expectedChain)
 		}
 	}
 
diff --git a/src/fmt/fmt_test.go b/src/fmt/fmt_test.go
index 37d82ac..6a79862 100644
--- a/src/fmt/fmt_test.go
+++ b/src/fmt/fmt_test.go
@@ -1238,7 +1238,7 @@
 func BenchmarkSprintfPadding(b *testing.B) {
 	b.RunParallel(func(pb *testing.PB) {
 		for pb.Next() {
-			Sprintf("%16f", 1.0)
+			_ = Sprintf("%16f", 1.0)
 		}
 	})
 }
@@ -1246,7 +1246,7 @@
 func BenchmarkSprintfEmpty(b *testing.B) {
 	b.RunParallel(func(pb *testing.PB) {
 		for pb.Next() {
-			Sprintf("")
+			_ = Sprintf("")
 		}
 	})
 }
@@ -1254,7 +1254,7 @@
 func BenchmarkSprintfString(b *testing.B) {
 	b.RunParallel(func(pb *testing.PB) {
 		for pb.Next() {
-			Sprintf("%s", "hello")
+			_ = Sprintf("%s", "hello")
 		}
 	})
 }
@@ -1262,7 +1262,7 @@
 func BenchmarkSprintfTruncateString(b *testing.B) {
 	b.RunParallel(func(pb *testing.PB) {
 		for pb.Next() {
-			Sprintf("%.3s", "日本語日本語日本語日本語")
+			_ = Sprintf("%.3s", "日本語日本語日本語日本語")
 		}
 	})
 }
@@ -1271,7 +1271,7 @@
 	var bytes any = []byte("日本語日本語日本語日本語")
 	b.RunParallel(func(pb *testing.PB) {
 		for pb.Next() {
-			Sprintf("%.3s", bytes)
+			_ = Sprintf("%.3s", bytes)
 		}
 	})
 }
@@ -1279,7 +1279,7 @@
 func BenchmarkSprintfSlowParsingPath(b *testing.B) {
 	b.RunParallel(func(pb *testing.PB) {
 		for pb.Next() {
-			Sprintf("%.v", nil)
+			_ = Sprintf("%.v", nil)
 		}
 	})
 }
@@ -1287,7 +1287,7 @@
 func BenchmarkSprintfQuoteString(b *testing.B) {
 	b.RunParallel(func(pb *testing.PB) {
 		for pb.Next() {
-			Sprintf("%q", "日本語日本語日本語")
+			_ = Sprintf("%q", "日本語日本語日本語")
 		}
 	})
 }
@@ -1295,7 +1295,7 @@
 func BenchmarkSprintfInt(b *testing.B) {
 	b.RunParallel(func(pb *testing.PB) {
 		for pb.Next() {
-			Sprintf("%d", 5)
+			_ = Sprintf("%d", 5)
 		}
 	})
 }
@@ -1303,7 +1303,7 @@
 func BenchmarkSprintfIntInt(b *testing.B) {
 	b.RunParallel(func(pb *testing.PB) {
 		for pb.Next() {
-			Sprintf("%d %d", 5, 6)
+			_ = Sprintf("%d %d", 5, 6)
 		}
 	})
 }
@@ -1311,7 +1311,7 @@
 func BenchmarkSprintfPrefixedInt(b *testing.B) {
 	b.RunParallel(func(pb *testing.PB) {
 		for pb.Next() {
-			Sprintf("This is some meaningless prefix text that needs to be scanned %d", 6)
+			_ = Sprintf("This is some meaningless prefix text that needs to be scanned %d", 6)
 		}
 	})
 }
@@ -1319,7 +1319,7 @@
 func BenchmarkSprintfFloat(b *testing.B) {
 	b.RunParallel(func(pb *testing.PB) {
 		for pb.Next() {
-			Sprintf("%g", 5.23184)
+			_ = Sprintf("%g", 5.23184)
 		}
 	})
 }
@@ -1327,7 +1327,7 @@
 func BenchmarkSprintfComplex(b *testing.B) {
 	b.RunParallel(func(pb *testing.PB) {
 		for pb.Next() {
-			Sprintf("%f", 5.23184+5.23184i)
+			_ = Sprintf("%f", 5.23184+5.23184i)
 		}
 	})
 }
@@ -1335,7 +1335,7 @@
 func BenchmarkSprintfBoolean(b *testing.B) {
 	b.RunParallel(func(pb *testing.PB) {
 		for pb.Next() {
-			Sprintf("%t", true)
+			_ = Sprintf("%t", true)
 		}
 	})
 }
@@ -1343,7 +1343,7 @@
 func BenchmarkSprintfHexString(b *testing.B) {
 	b.RunParallel(func(pb *testing.PB) {
 		for pb.Next() {
-			Sprintf("% #x", "0123456789abcdef")
+			_ = Sprintf("% #x", "0123456789abcdef")
 		}
 	})
 }
@@ -1352,7 +1352,7 @@
 	data := []byte("0123456789abcdef")
 	b.RunParallel(func(pb *testing.PB) {
 		for pb.Next() {
-			Sprintf("% #x", data)
+			_ = Sprintf("% #x", data)
 		}
 	})
 }
@@ -1361,7 +1361,7 @@
 	data := []byte("0123456789abcdef")
 	b.RunParallel(func(pb *testing.PB) {
 		for pb.Next() {
-			Sprintf("%v", data)
+			_ = Sprintf("%v", data)
 		}
 	})
 }
@@ -1370,7 +1370,7 @@
 	stringer := I(12345)
 	b.RunParallel(func(pb *testing.PB) {
 		for pb.Next() {
-			Sprintf("%v", stringer)
+			_ = Sprintf("%v", stringer)
 		}
 	})
 }
@@ -1379,7 +1379,7 @@
 	s := &[]any{SI{12345}, map[int]string{0: "hello"}}
 	b.RunParallel(func(pb *testing.PB) {
 		for pb.Next() {
-			Sprintf("%#v", s)
+			_ = Sprintf("%#v", s)
 		}
 	})
 }
@@ -1428,14 +1428,14 @@
 	desc  string
 	fn    func()
 }{
-	{0, `Sprintf("")`, func() { Sprintf("") }},
-	{1, `Sprintf("xxx")`, func() { Sprintf("xxx") }},
-	{0, `Sprintf("%x")`, func() { Sprintf("%x", 7) }},
-	{1, `Sprintf("%x")`, func() { Sprintf("%x", 1<<16) }},
-	{3, `Sprintf("%80000s")`, func() { Sprintf("%80000s", "hello") }}, // large buffer (>64KB)
-	{1, `Sprintf("%s")`, func() { Sprintf("%s", "hello") }},
-	{1, `Sprintf("%x %x")`, func() { Sprintf("%x %x", 7, 112) }},
-	{1, `Sprintf("%g")`, func() { Sprintf("%g", float32(3.14159)) }},
+	{0, `Sprintf("")`, func() { _ = Sprintf("") }},
+	{1, `Sprintf("xxx")`, func() { _ = Sprintf("xxx") }},
+	{0, `Sprintf("%x")`, func() { _ = Sprintf("%x", 7) }},
+	{1, `Sprintf("%x")`, func() { _ = Sprintf("%x", 1<<16) }},
+	{3, `Sprintf("%80000s")`, func() { _ = Sprintf("%80000s", "hello") }}, // large buffer (>64KB)
+	{1, `Sprintf("%s")`, func() { _ = Sprintf("%s", "hello") }},
+	{1, `Sprintf("%x %x")`, func() { _ = Sprintf("%x %x", 7, 112) }},
+	{1, `Sprintf("%g")`, func() { _ = Sprintf("%g", float32(3.14159)) }},
 	{0, `Fprintf(buf, "%s")`, func() { mallocBuf.Reset(); Fprintf(&mallocBuf, "%s", "hello") }},
 	{0, `Fprintf(buf, "%x")`, func() { mallocBuf.Reset(); Fprintf(&mallocBuf, "%x", 7) }},
 	{0, `Fprintf(buf, "%x")`, func() { mallocBuf.Reset(); Fprintf(&mallocBuf, "%x", 1<<16) }},
@@ -1773,13 +1773,13 @@
 func TestBadVerbRecursion(t *testing.T) {
 	failed := false
 	r := &Recur{3, &failed}
-	Sprintf("recur@%p value: %d\n", &r, r.i)
+	_ = Sprintf("recur@%p value: %d\n", &r, r.i)
 	if failed {
 		t.Error("fail with pointer")
 	}
 	failed = false
 	r = &Recur{4, &failed}
-	Sprintf("recur@%p, value: %d\n", r, r.i)
+	_ = Sprintf("recur@%p, value: %d\n", r, r.i)
 	if failed {
 		t.Error("fail with value")
 	}
diff --git a/src/go/build/read.go b/src/go/build/read.go
index 52adfea..adcf82f 100644
--- a/src/go/build/read.go
+++ b/src/go/build/read.go
@@ -11,6 +11,7 @@
 	"fmt"
 	"go/ast"
 	"go/parser"
+	"go/scanner"
 	"go/token"
 	"io"
 	"strconv"
@@ -459,6 +460,13 @@
 			if err != nil {
 				return fmt.Errorf("parser returned invalid quoted string: <%s>", quoted)
 			}
+			if !isValidImport(path) {
+				// The parser used to return a parse error for invalid import paths, but
+				// no longer does, so check for and create the error here instead.
+				info.parseErr = scanner.Error{Pos: info.fset.Position(spec.Pos()), Msg: "invalid import path: " + path}
+				info.imports = nil
+				return nil
+			}
 			if path == "embed" {
 				hasEmbed = true
 			}
@@ -504,6 +512,20 @@
 	return nil
 }
 
+// isValidImport checks if the import is a valid import using the more strict
+// checks allowed by the implementation restriction in https://go.dev/ref/spec#Import_declarations.
+// It was ported from the function of the same name that was removed from the
+// parser in CL 424855, when the parser stopped doing these checks.
+func isValidImport(s string) bool {
+	const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD"
+	for _, r := range s {
+		if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) {
+			return false
+		}
+	}
+	return s != ""
+}
+
 // parseGoEmbed parses the text following "//go:embed" to extract the glob patterns.
 // It accepts unquoted space-separated patterns as well as double-quoted and back-quoted Go strings.
 // This is based on a similar function in cmd/compile/internal/gc/noder.go;
diff --git a/src/go/printer/printer.go b/src/go/printer/printer.go
index 741e3f7..46131c6 100644
--- a/src/go/printer/printer.go
+++ b/src/go/printer/printer.go
@@ -75,10 +75,11 @@
 	// white space). If there's a difference and SourcePos is set in
 	// ConfigMode, //line directives are used in the output to restore
 	// original source positions for a reader.
-	pos     token.Position // current position in AST (source) space
-	out     token.Position // current position in output space
-	last    token.Position // value of pos after calling writeString
-	linePtr *int           // if set, record out.Line for the next token in *linePtr
+	pos          token.Position // current position in AST (source) space
+	out          token.Position // current position in output space
+	last         token.Position // value of pos after calling writeString
+	linePtr      *int           // if set, record out.Line for the next token in *linePtr
+	sourcePosErr error          // if non-nil, the first error emitting a //line directive
 
 	// The list of all source comments, in order of appearance.
 	comments        []*ast.CommentGroup // may be nil
@@ -196,6 +197,13 @@
 // writeLineDirective writes a //line directive if necessary.
 func (p *printer) writeLineDirective(pos token.Position) {
 	if pos.IsValid() && (p.out.Line != pos.Line || p.out.Filename != pos.Filename) {
+		if strings.ContainsAny(pos.Filename, "\r\n") {
+			if p.sourcePosErr == nil {
+				p.sourcePosErr = fmt.Errorf("go/printer: source filename contains unexpected newline character: %q", pos.Filename)
+			}
+			return
+		}
+
 		p.output = append(p.output, tabwriter.Escape) // protect '\n' in //line from tabwriter interpretation
 		p.output = append(p.output, fmt.Sprintf("//line %s:%d\n", pos.Filename, pos.Line)...)
 		p.output = append(p.output, tabwriter.Escape)
@@ -1169,7 +1177,7 @@
 		goto unsupported
 	}
 
-	return nil
+	return p.sourcePosErr
 
 unsupported:
 	return fmt.Errorf("go/printer: unsupported node type %T", node)
diff --git a/src/go/printer/printer_test.go b/src/go/printer/printer_test.go
index cb62b3e..3a8ce60 100644
--- a/src/go/printer/printer_test.go
+++ b/src/go/printer/printer_test.go
@@ -797,3 +797,31 @@
 		t.Fatalf("got %q, want %q", got, want)
 	}
 }
+
+func TestSourcePosNewline(t *testing.T) {
+	// We don't provide a syntax for escaping or unescaping characters in line
+	// directives (see https://go.dev/issue/24183#issuecomment-372449628).
+	// As a result, we cannot write a line directive with the correct path for a
+	// filename containing newlines. We should return an error rather than
+	// silently dropping or mangling it.
+
+	fname := "foo\nbar/bar.go"
+	src := `package bar`
+	fset := token.NewFileSet()
+	f, err := parser.ParseFile(fset, fname, src, parser.ParseComments|parser.AllErrors|parser.SkipObjectResolution)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	cfg := &Config{
+		Mode:     SourcePos, // emit line comments
+		Tabwidth: 8,
+	}
+	var buf bytes.Buffer
+	if err := cfg.Fprint(&buf, fset, f); err == nil {
+		t.Errorf("Fprint did not error for source file path containing newline")
+	}
+	if buf.Len() != 0 {
+		t.Errorf("unexpected Fprint output:\n%s", buf.Bytes())
+	}
+}
diff --git a/src/net/http/http_test.go b/src/net/http/http_test.go
index 0d92fe5..f03272a 100644
--- a/src/net/http/http_test.go
+++ b/src/net/http/http_test.go
@@ -48,35 +48,6 @@
 	}
 }
 
-func TestCleanHost(t *testing.T) {
-	tests := []struct {
-		in, want string
-	}{
-		{"www.google.com", "www.google.com"},
-		{"www.google.com foo", "www.google.com"},
-		{"www.google.com/foo", "www.google.com"},
-		{" first character is a space", ""},
-		{"[1::6]:8080", "[1::6]:8080"},
-
-		// Punycode:
-		{"гофер.рф/foo", "xn--c1ae0ajs.xn--p1ai"},
-		{"bücher.de", "xn--bcher-kva.de"},
-		{"bücher.de:8080", "xn--bcher-kva.de:8080"},
-		// Verify we convert to lowercase before punycode:
-		{"BÜCHER.de", "xn--bcher-kva.de"},
-		{"BÜCHER.de:8080", "xn--bcher-kva.de:8080"},
-		// Verify we normalize to NFC before punycode:
-		{"gophér.nfc", "xn--gophr-esa.nfc"},            // NFC input; no work needed
-		{"goph\u0065\u0301r.nfd", "xn--gophr-esa.nfd"}, // NFD input
-	}
-	for _, tt := range tests {
-		got := cleanHost(tt.in)
-		if tt.want != got {
-			t.Errorf("cleanHost(%q) = %q, want %q", tt.in, got, tt.want)
-		}
-	}
-}
-
 // Test that cmd/go doesn't link in the HTTP server.
 //
 // This catches accidental dependencies between the HTTP transport and
diff --git a/src/net/http/request.go b/src/net/http/request.go
index a45c9e3..9c888b3 100644
--- a/src/net/http/request.go
+++ b/src/net/http/request.go
@@ -17,7 +17,6 @@
 	"io"
 	"mime"
 	"mime/multipart"
-	"net"
 	"net/http/httptrace"
 	"net/http/internal/ascii"
 	"net/textproto"
@@ -27,6 +26,7 @@
 	"strings"
 	"sync"
 
+	"golang.org/x/net/http/httpguts"
 	"golang.org/x/net/idna"
 )
 
@@ -575,12 +575,19 @@
 	// is not given, use the host from the request URL.
 	//
 	// Clean the host, in case it arrives with unexpected stuff in it.
-	host := cleanHost(r.Host)
+	host := r.Host
 	if host == "" {
 		if r.URL == nil {
 			return errMissingHost
 		}
-		host = cleanHost(r.URL.Host)
+		host = r.URL.Host
+	}
+	host, err = httpguts.PunycodeHostPort(host)
+	if err != nil {
+		return err
+	}
+	if !httpguts.ValidHostHeader(host) {
+		return errors.New("http: invalid Host header")
 	}
 
 	// According to RFC 6874, an HTTP client, proxy, or other
@@ -737,40 +744,6 @@
 	return idna.Lookup.ToASCII(v)
 }
 
-// cleanHost cleans up the host sent in request's Host header.
-//
-// It both strips anything after '/' or ' ', and puts the value
-// into Punycode form, if necessary.
-//
-// Ideally we'd clean the Host header according to the spec:
-//
-//	https://tools.ietf.org/html/rfc7230#section-5.4 (Host = uri-host [ ":" port ]")
-//	https://tools.ietf.org/html/rfc7230#section-2.7 (uri-host -> rfc3986's host)
-//	https://tools.ietf.org/html/rfc3986#section-3.2.2 (definition of host)
-//
-// But practically, what we are trying to avoid is the situation in
-// issue 11206, where a malformed Host header used in the proxy context
-// would create a bad request. So it is enough to just truncate at the
-// first offending character.
-func cleanHost(in string) string {
-	if i := strings.IndexAny(in, " /"); i != -1 {
-		in = in[:i]
-	}
-	host, port, err := net.SplitHostPort(in)
-	if err != nil { // input was just a host
-		a, err := idnaASCII(in)
-		if err != nil {
-			return in // garbage in, garbage out
-		}
-		return a
-	}
-	a, err := idnaASCII(host)
-	if err != nil {
-		return in // garbage in, garbage out
-	}
-	return net.JoinHostPort(a, port)
-}
-
 // removeZone removes IPv6 zone identifier from host.
 // E.g., "[fe80::1%en0]:8080" to "[fe80::1]:8080"
 func removeZone(host string) string {
diff --git a/src/net/http/request_test.go b/src/net/http/request_test.go
index 23e49d6..86c68e4 100644
--- a/src/net/http/request_test.go
+++ b/src/net/http/request_test.go
@@ -774,15 +774,8 @@
 	}
 	req.Host = "foo.com with spaces"
 	req.URL.Host = "foo.com with spaces"
-	req.Write(logWrites{t, &got})
-	want := []string{
-		"GET /after HTTP/1.1\r\n",
-		"Host: foo.com\r\n",
-		"User-Agent: " + DefaultUserAgent + "\r\n",
-		"\r\n",
-	}
-	if !reflect.DeepEqual(got, want) {
-		t.Errorf("Writes = %q\n  Want = %q", got, want)
+	if err := req.Write(logWrites{t, &got}); err == nil {
+		t.Errorf("Writing request with invalid Host: succeded, want error")
 	}
 }
 
diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go
index 245f73b..f4896c5 100644
--- a/src/net/http/transport_test.go
+++ b/src/net/http/transport_test.go
@@ -6654,3 +6654,22 @@
 	}
 	wg.Wait()
 }
+
+func TestRequestSanitization(t *testing.T) { run(t, testRequestSanitization) }
+func testRequestSanitization(t *testing.T, mode testMode) {
+	if mode == http2Mode {
+		// Remove this after updating x/net.
+		t.Skip("https://go.dev/issue/60374 test fails when run with HTTP/2")
+	}
+	ts := newClientServerTest(t, mode, HandlerFunc(func(rw ResponseWriter, req *Request) {
+		if h, ok := req.Header["X-Evil"]; ok {
+			t.Errorf("request has X-Evil header: %q", h)
+		}
+	})).ts
+	req, _ := NewRequest("GET", ts.URL, nil)
+	req.Host = "go.dev\r\nX-Evil:evil"
+	resp, _ := ts.Client().Do(req)
+	if resp != nil {
+		resp.Body.Close()
+	}
+}
diff --git a/src/net/mail/message.go b/src/net/mail/message.go
index 6268c08..862f72d 100644
--- a/src/net/mail/message.go
+++ b/src/net/mail/message.go
@@ -14,6 +14,7 @@
     such as breaking addresses across lines.
   - No unicode normalization is performed.
   - The special characters ()[]:;@\, are allowed to appear unquoted in names.
+  - A leading From line is permitted, as in mbox format (RFC 4155).
 */
 package mail
 
@@ -53,7 +54,7 @@
 func ReadMessage(r io.Reader) (msg *Message, err error) {
 	tp := textproto.NewReader(bufio.NewReader(r))
 
-	hdr, err := tp.ReadMIMEHeader()
+	hdr, err := readHeader(tp)
 	if err != nil {
 		return nil, err
 	}
@@ -64,6 +65,54 @@
 	}, nil
 }
 
+// readHeader reads the message headers from r.
+// This is like textproto.ReadMIMEHeader, but doesn't validate.
+// The fix for issue #53188 tightened up net/textproto to enforce
+// restrictions of RFC 7230.
+// This package implements RFC 5322, which does not have those restrictions.
+// This function copies the relevant code from net/textproto,
+// simplified for RFC 5322.
+func readHeader(r *textproto.Reader) (map[string][]string, error) {
+	m := make(map[string][]string)
+
+	// The first line cannot start with a leading space.
+	if buf, err := r.R.Peek(1); err == nil && (buf[0] == ' ' || buf[0] == '\t') {
+		line, err := r.ReadLine()
+		if err != nil {
+			return m, err
+		}
+		return m, errors.New("malformed initial line: " + line)
+	}
+
+	for {
+		kv, err := r.ReadContinuedLine()
+		if kv == "" {
+			return m, err
+		}
+
+		// Key ends at first colon.
+		k, v, ok := strings.Cut(kv, ":")
+		if !ok {
+			return m, errors.New("malformed header line: " + kv)
+		}
+		key := textproto.CanonicalMIMEHeaderKey(k)
+
+		// Permit empty key, because that is what we did in the past.
+		if key == "" {
+			continue
+		}
+
+		// Skip initial spaces in value.
+		value := strings.TrimLeft(v, " \t")
+
+		m[key] = append(m[key], value)
+
+		if err != nil {
+			return m, err
+		}
+	}
+}
+
 // Layouts suitable for passing to time.Parse.
 // These are tried in order.
 var (
diff --git a/src/net/mail/message_test.go b/src/net/mail/message_test.go
index 61e50cc..c37f392 100644
--- a/src/net/mail/message_test.go
+++ b/src/net/mail/message_test.go
@@ -39,6 +39,34 @@
 		},
 		body: "This is a message just to say hello.\nSo, \"Hello\".\n",
 	},
+	{
+		// RFC 5322 permits any printable ASCII character,
+		// except colon, in a header key. Issue #58862.
+		in: `From: iant@golang.org
+Custom/Header: v
+
+Body
+`,
+		header: Header{
+			"From":          []string{"iant@golang.org"},
+			"Custom/Header": []string{"v"},
+		},
+		body: "Body\n",
+	},
+	{
+		// RFC 4155 mbox format. We've historically permitted this,
+		// so we continue to permit it. Issue #60332.
+		in: `From iant@golang.org Mon Jun 19 00:00:00 2023
+From: iant@golang.org
+
+Hello, gophers!
+`,
+		header: Header{
+			"From":                               []string{"iant@golang.org"},
+			"From iant@golang.org Mon Jun 19 00": []string{"00:00 2023"},
+		},
+		body: "Hello, gophers!\n",
+	},
 }
 
 func TestParsing(t *testing.T) {
diff --git a/src/runtime/proc.go b/src/runtime/proc.go
index 8d5456a..043f4f2 100644
--- a/src/runtime/proc.go
+++ b/src/runtime/proc.go
@@ -2351,10 +2351,15 @@
 // Callers passing a non-nil P must call from a non-preemptible context. See
 // comment on acquirem below.
 //
+// Argument lockheld indicates whether the caller already acquired the
+// scheduler lock. Callers holding the lock when making the call must pass
+// true. The lock might be temporarily dropped, but will be reacquired before
+// returning.
+//
 // Must not have write barriers because this may be called without a P.
 //
 //go:nowritebarrierrec
-func startm(pp *p, spinning bool) {
+func startm(pp *p, spinning, lockheld bool) {
 	// Disable preemption.
 	//
 	// Every owned P must have an owner that will eventually stop it in the
@@ -2372,7 +2377,9 @@
 	// startm. Callers passing a nil P may be preemptible, so we must
 	// disable preemption before acquiring a P from pidleget below.
 	mp := acquirem()
-	lock(&sched.lock)
+	if !lockheld {
+		lock(&sched.lock)
+	}
 	if pp == nil {
 		if spinning {
 			// TODO(prattmic): All remaining calls to this function
@@ -2382,7 +2389,9 @@
 		}
 		pp, _ = pidleget(0)
 		if pp == nil {
-			unlock(&sched.lock)
+			if !lockheld {
+				unlock(&sched.lock)
+			}
 			releasem(mp)
 			return
 		}
@@ -2396,6 +2405,8 @@
 		// could find no idle P while checkdead finds a runnable G but
 		// no running M's because this new M hasn't started yet, thus
 		// throwing in an apparent deadlock.
+		// This apparent deadlock is possible when startm is called
+		// from sysmon, which doesn't count as a running M.
 		//
 		// Avoid this situation by pre-allocating the ID for the new M,
 		// thus marking it as 'running' before we drop sched.lock. This
@@ -2410,12 +2421,18 @@
 			fn = mspinning
 		}
 		newm(fn, pp, id)
+
+		if lockheld {
+			lock(&sched.lock)
+		}
 		// Ownership transfer of pp committed by start in newm.
 		// Preemption is now safe.
 		releasem(mp)
 		return
 	}
-	unlock(&sched.lock)
+	if !lockheld {
+		unlock(&sched.lock)
+	}
 	if nmp.spinning {
 		throw("startm: m is spinning")
 	}
@@ -2444,24 +2461,24 @@
 
 	// if it has local work, start it straight away
 	if !runqempty(pp) || sched.runqsize != 0 {
-		startm(pp, false)
+		startm(pp, false, false)
 		return
 	}
 	// if there's trace work to do, start it straight away
 	if (trace.enabled || trace.shutdown) && traceReaderAvailable() != nil {
-		startm(pp, false)
+		startm(pp, false, false)
 		return
 	}
 	// if it has GC work, start it straight away
 	if gcBlackenEnabled != 0 && gcMarkWorkAvailable(pp) {
-		startm(pp, false)
+		startm(pp, false, false)
 		return
 	}
 	// no local work, check that there are no spinning/idle M's,
 	// otherwise our help is not required
 	if sched.nmspinning.Load()+sched.npidle.Load() == 0 && sched.nmspinning.CompareAndSwap(0, 1) { // TODO: fast atomic
 		sched.needspinning.Store(0)
-		startm(pp, true)
+		startm(pp, true, false)
 		return
 	}
 	lock(&sched.lock)
@@ -2483,14 +2500,14 @@
 	}
 	if sched.runqsize != 0 {
 		unlock(&sched.lock)
-		startm(pp, false)
+		startm(pp, false, false)
 		return
 	}
 	// If this is the last running P and nobody is polling network,
 	// need to wakeup another M to poll network.
 	if sched.npidle.Load() == gomaxprocs-1 && sched.lastpoll.Load() != 0 {
 		unlock(&sched.lock)
-		startm(pp, false)
+		startm(pp, false, false)
 		return
 	}
 
@@ -2539,7 +2556,7 @@
 	// see at least one running M (ours).
 	unlock(&sched.lock)
 
-	startm(pp, true)
+	startm(pp, true, false)
 
 	releasem(mp)
 }
@@ -3292,8 +3309,8 @@
 				break
 			}
 
+			startm(pp, false, true)
 			unlock(&sched.lock)
-			startm(pp, false)
 			releasem(mp)
 		}
 	}
@@ -4334,6 +4351,7 @@
 	pp.goidcache++
 	if raceenabled {
 		newg.racectx = racegostart(callerpc)
+		newg.raceignore = 0
 		if newg.labels != nil {
 			// See note in proflabel.go on labelSync's role in synchronizing
 			// with the reads in the signal handler.
@@ -5397,7 +5415,7 @@
 			// See issue 42515 and
 			// https://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=50094.
 			if next := timeSleepUntil(); next < now {
-				startm(nil, false)
+				startm(nil, false, false)
 			}
 		}
 		if scavenger.sysmonWake.Load() != 0 {
@@ -5669,7 +5687,7 @@
 		globrunqputbatch(&sched.disable.runnable, n)
 		unlock(&sched.lock)
 		for ; n != 0 && sched.npidle.Load() != 0; n-- {
-			startm(nil, false)
+			startm(nil, false, false)
 		}
 	} else {
 		unlock(&sched.lock)
diff --git a/src/runtime/race/race_linux_test.go b/src/runtime/race/race_linux_test.go
index e8a2d0f..947ed7c 100644
--- a/src/runtime/race/race_linux_test.go
+++ b/src/runtime/race/race_linux_test.go
@@ -35,3 +35,31 @@
 		t.Fatalf("bad atomic value: %v, want 2", *a)
 	}
 }
+
+func TestAtomicPageBoundary(t *testing.T) {
+	// Test that atomic access near (but not cross) a page boundary
+	// doesn't fault. See issue 60825.
+
+	// Mmap two pages of memory, and make the second page inaccessible,
+	// so we have an address at the end of a page.
+	pagesize := syscall.Getpagesize()
+	b, err := syscall.Mmap(0, 0, 2*pagesize, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_ANON|syscall.MAP_PRIVATE)
+	if err != nil {
+		t.Fatalf("mmap failed %s", err)
+	}
+	defer syscall.Munmap(b)
+	err = syscall.Mprotect(b[pagesize:], syscall.PROT_NONE)
+	if err != nil {
+		t.Fatalf("mprotect high failed %s\n", err)
+	}
+
+	// This should not fault.
+	a := (*uint32)(unsafe.Pointer(&b[pagesize-4]))
+	atomic.StoreUint32(a, 1)
+	if x := atomic.LoadUint32(a); x != 1 {
+		t.Fatalf("bad atomic value: %v, want 1", x)
+	}
+	if x := atomic.AddUint32(a, 1); x != 2 {
+		t.Fatalf("bad atomic value: %v, want 2", x)
+	}
+}
diff --git a/src/runtime/race/testdata/mop_test.go b/src/runtime/race/testdata/mop_test.go
index 0d79091..4a9ce26 100644
--- a/src/runtime/race/testdata/mop_test.go
+++ b/src/runtime/race/testdata/mop_test.go
@@ -2092,3 +2092,40 @@
 		<-done
 	}
 }
+
+func TestNoRaceIssue60934(t *testing.T) {
+	// Test that runtime.RaceDisable state doesn't accidentally get applied to
+	// new goroutines.
+
+	// Create several goroutines that end after calling runtime.RaceDisable.
+	var wg sync.WaitGroup
+	ready := make(chan struct{})
+	wg.Add(32)
+	for i := 0; i < 32; i++ {
+		go func() {
+			<-ready // ensure we have multiple goroutines running at the same time
+			runtime.RaceDisable()
+			wg.Done()
+		}()
+	}
+	close(ready)
+	wg.Wait()
+
+	// Make sure race detector still works. If the runtime.RaceDisable state
+	// leaks, the happens-before edges here will be ignored and a race on x will
+	// be reported.
+	var x int
+	ch := make(chan struct{}, 0)
+	wg.Add(2)
+	go func() {
+		x = 1
+		ch <- struct{}{}
+		wg.Done()
+	}()
+	go func() {
+		<-ch
+		_ = x
+		wg.Done()
+	}()
+	wg.Wait()
+}
diff --git a/src/runtime/race_amd64.s b/src/runtime/race_amd64.s
index c679a87..34ec200 100644
--- a/src/runtime/race_amd64.s
+++ b/src/runtime/race_amd64.s
@@ -333,7 +333,7 @@
 TEXT	racecallatomic<>(SB), NOSPLIT, $0-0
 	// Trigger SIGSEGV early.
 	MOVQ	16(SP), R12
-	MOVL	(R12), R13
+	MOVBLZX	(R12), R13
 	// Check that addr is within [arenastart, arenaend) or within [racedatastart, racedataend).
 	CMPQ	R12, runtime·racearenastart(SB)
 	JB	racecallatomic_data
diff --git a/src/runtime/race_arm64.s b/src/runtime/race_arm64.s
index edbb3b1..c818345 100644
--- a/src/runtime/race_arm64.s
+++ b/src/runtime/race_arm64.s
@@ -348,7 +348,7 @@
 
 	// Trigger SIGSEGV early.
 	MOVD	40(RSP), R3	// 1st arg is addr. after two times BL, get it at 40(RSP)
-	MOVD	(R3), R13	// segv here if addr is bad
+	MOVB	(R3), R13	// segv here if addr is bad
 	// Check that addr is within [arenastart, arenaend) or within [racedatastart, racedataend).
 	MOVD	runtime·racearenastart(SB), R10
 	CMP	R10, R3
diff --git a/src/runtime/race_ppc64le.s b/src/runtime/race_ppc64le.s
index ac335b1..2826501 100644
--- a/src/runtime/race_ppc64le.s
+++ b/src/runtime/race_ppc64le.s
@@ -362,7 +362,7 @@
 TEXT	racecallatomic<>(SB), NOSPLIT, $0-0
 	// Trigger SIGSEGV early if address passed to atomic function is bad.
 	MOVD	(R6), R7	// 1st arg is addr
-	MOVD	(R7), R9	// segv here if addr is bad
+	MOVB	(R7), R9	// segv here if addr is bad
 	// Check that addr is within [arenastart, arenaend) or within [racedatastart, racedataend).
 	MOVD	runtime·racearenastart(SB), R9
 	CMP	R7, R9
diff --git a/src/runtime/signal_windows_test.go b/src/runtime/signal_windows_test.go
index c9b8e90..4c7a476 100644
--- a/src/runtime/signal_windows_test.go
+++ b/src/runtime/signal_windows_test.go
@@ -254,3 +254,59 @@
 		t.Fatalf("Program exited with error: %v\n%s", err, &stderr)
 	}
 }
+
+func TestIssue59213(t *testing.T) {
+	if runtime.GOOS != "windows" {
+		t.Skip("skipping windows only test")
+	}
+	if *flagQuick {
+		t.Skip("-quick")
+	}
+	testenv.MustHaveGoBuild(t)
+	testenv.MustHaveCGO(t)
+
+	goEnv := func(arg string) string {
+		cmd := testenv.Command(t, testenv.GoToolPath(t), "env", arg)
+		cmd.Stderr = new(bytes.Buffer)
+
+		line, err := cmd.Output()
+		if err != nil {
+			t.Fatalf("%v: %v\n%s", cmd, err, cmd.Stderr)
+		}
+		out := string(bytes.TrimSpace(line))
+		t.Logf("%v: %q", cmd, out)
+		return out
+	}
+
+	cc := goEnv("CC")
+	cgoCflags := goEnv("CGO_CFLAGS")
+
+	t.Parallel()
+
+	tmpdir := t.TempDir()
+	dllfile := filepath.Join(tmpdir, "test.dll")
+	exefile := filepath.Join(tmpdir, "gotest.exe")
+
+	// build go dll
+	cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-o", dllfile, "-buildmode", "c-shared", "testdata/testwintls/main.go")
+	out, err := testenv.CleanCmdEnv(cmd).CombinedOutput()
+	if err != nil {
+		t.Fatalf("failed to build go library: %s\n%s", err, out)
+	}
+
+	// build c program
+	cmd = testenv.Command(t, cc, "-o", exefile, "testdata/testwintls/main.c")
+	testenv.CleanCmdEnv(cmd)
+	cmd.Env = append(cmd.Env, "CGO_CFLAGS="+cgoCflags)
+	out, err = cmd.CombinedOutput()
+	if err != nil {
+		t.Fatalf("failed to build c exe: %s\n%s", err, out)
+	}
+
+	// run test program
+	cmd = testenv.Command(t, exefile, dllfile, "GoFunc")
+	out, err = testenv.CleanCmdEnv(cmd).CombinedOutput()
+	if err != nil {
+		t.Fatalf("failed: %s\n%s", err, out)
+	}
+}
diff --git a/src/runtime/sys_windows_amd64.s b/src/runtime/sys_windows_amd64.s
index 777726f..4027770 100644
--- a/src/runtime/sys_windows_amd64.s
+++ b/src/runtime/sys_windows_amd64.s
@@ -10,6 +10,7 @@
 
 // Offsets into Thread Environment Block (pointer in GS)
 #define TEB_TlsSlots 0x1480
+#define TEB_ArbitraryPtr 0x28
 
 // void runtime·asmstdcall(void *c);
 TEXT runtime·asmstdcall(SB),NOSPLIT|NOFRAME,$0
@@ -427,7 +428,11 @@
 	// Assert that slot is less than 64 so we can use _TEB->TlsSlots
 	CMPQ	CX, $64
 	JB	ok
-	CALL	runtime·abort(SB)
+
+	// Fallback to the TEB arbitrary pointer.
+	// TODO: don't use the arbitrary pointer (see go.dev/issue/59824)
+	MOVQ	$TEB_ArbitraryPtr, CX
+	JMP	settls
 ok:
 	// Convert the TLS index at CX into
 	// an offset from TEB_TlsSlots.
@@ -435,5 +440,6 @@
 
 	// Save offset from TLS into tls_g.
 	ADDQ	$TEB_TlsSlots, CX
+settls:
 	MOVQ	CX, runtime·tls_g(SB)
 	RET
diff --git a/src/runtime/sys_windows_arm64.s b/src/runtime/sys_windows_arm64.s
index 4702a4d..e3082a1 100644
--- a/src/runtime/sys_windows_arm64.s
+++ b/src/runtime/sys_windows_arm64.s
@@ -12,6 +12,7 @@
 // Offsets into Thread Environment Block (pointer in R18)
 #define TEB_error 0x68
 #define TEB_TlsSlots 0x1480
+#define TEB_ArbitraryPtr 0x28
 
 // Note: R0-R7 are args, R8 is indirect return value address,
 // R9-R15 are caller-save, R19-R29 are callee-save.
@@ -415,12 +416,15 @@
 	// Assert that slot is less than 64 so we can use _TEB->TlsSlots
 	CMP	$64, R0
 	BLT	ok
-	MOVD	$runtime·abort(SB), R1
-	BL	(R1)
+	// Fallback to the TEB arbitrary pointer.
+	// TODO: don't use the arbitrary pointer (see go.dev/issue/59824)
+	MOVD	$TEB_ArbitraryPtr, R0
+	B	settls
 ok:
 
 	// Save offset from R18 into tls_g.
 	LSL	$3, R0
 	ADD	$TEB_TlsSlots, R0
+settls:
 	MOVD	R0, runtime·tls_g(SB)
 	RET
diff --git a/src/runtime/testdata/testprog/syscall_windows.go b/src/runtime/testdata/testprog/syscall_windows.go
index b4b6644..71bf384 100644
--- a/src/runtime/testdata/testprog/syscall_windows.go
+++ b/src/runtime/testdata/testprog/syscall_windows.go
@@ -66,5 +66,8 @@
 	if err != nil {
 		panic(err)
 	}
-	print((mem2 - mem1) / threadCount)
+	// assumes that this process creates 1 thread for each
+	// thread locked goroutine plus extra 5 threads
+	// like sysmon and others
+	print((mem2 - mem1) / (threadCount + 5))
 }
diff --git a/src/runtime/testdata/testprogcgo/stack_windows.go b/src/runtime/testdata/testprogcgo/stack_windows.go
index 846297a..0be1126 100644
--- a/src/runtime/testdata/testprogcgo/stack_windows.go
+++ b/src/runtime/testdata/testprogcgo/stack_windows.go
@@ -50,5 +50,8 @@
 	if err != nil {
 		panic(err)
 	}
-	print((mem2 - mem1) / threadCount)
+	// assumes that this process creates 1 thread for each
+	// thread locked goroutine plus extra 5 threads
+	// like sysmon and others
+	print((mem2 - mem1) / (threadCount + 5))
 }
diff --git a/src/runtime/testdata/testwintls/main.c b/src/runtime/testdata/testwintls/main.c
new file mode 100644
index 0000000..6061828
--- /dev/null
+++ b/src/runtime/testdata/testwintls/main.c
@@ -0,0 +1,29 @@
+// Copyright 2023 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.
+
+#include <windows.h>
+
+int main(int argc, char **argv) {
+    if (argc < 3) {
+        return 1;
+    }
+    // Allocate more than 64 TLS indices
+    // so the Go runtime doesn't find
+    // enough space in the TEB TLS slots.
+    for (int i = 0; i < 65; i++) {
+        TlsAlloc();
+    }
+    HMODULE hlib = LoadLibrary(argv[1]);
+    if (hlib == NULL) {
+        return 2;
+    }
+    FARPROC proc = GetProcAddress(hlib, argv[2]);
+    if (proc == NULL) {
+        return 3;
+    }
+    if (proc() != 42) {
+        return 4;
+    }
+    return 0;
+}
\ No newline at end of file
diff --git a/src/runtime/testdata/testwintls/main.go b/src/runtime/testdata/testwintls/main.go
new file mode 100644
index 0000000..1cf296c
--- /dev/null
+++ b/src/runtime/testdata/testwintls/main.go
@@ -0,0 +1,12 @@
+// Copyright 2023 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 "C"
+
+//export GoFunc
+func GoFunc() int { return 42 }
+
+func main() {}
diff --git a/src/syscall/zx/fidl/ctx_and_header.go b/src/syscall/zx/fidl/ctx_and_header.go
index 45b2a53..7f79a5d 100644
--- a/src/syscall/zx/fidl/ctx_and_header.go
+++ b/src/syscall/zx/fidl/ctx_and_header.go
@@ -13,17 +13,14 @@
 // This is currently empty. We keep it around to ease the implementation of
 // context-dependent behavior for future migrations.
 type MarshalerContext struct {
+	// TODO(fxbug.dev/79584): This is now unused. Remove.
 	UseV2WireFormat bool
 }
 
-func (ctx MarshalerContext) isV2WireFormatDecodingEnabled() bool {
-	return ctx.UseV2WireFormat
-}
-
 // NewCtx returns the default context.
 // During migrations, this controls the default write path.
 func NewCtx() MarshalerContext {
-	return MarshalerContext{UseV2WireFormat: true}
+	return MarshalerContext{}
 }
 
 // MessageHeader represents a transactional message header.
@@ -35,14 +32,25 @@
 	Ordinal uint64   `fidl:"8" fidl_offset_v2:"8" fidl_bounds:""`
 }
 
+// TODO(fxbug.dev/79584): Remove in favor of ValidateWireFormat.
 func (msg *MessageHeader) IsSupportedVersion() bool {
 	return msg.Magic == FidlWireFormatMagicNumberInitial
 }
 
+func (msg *MessageHeader) ValidateWireFormat() error {
+	if msg.Magic != FidlWireFormatMagicNumberInitial {
+		return ErrUnknownMagic
+	}
+	if msg.Flags[0]&FidlV2WireFormatFlagMask == 0 {
+		return ErrUnsupportedWireFormatVersion
+	}
+	return nil
+}
+
 // NewCtx creates a new MarshalerContext for unmarshaling based on msg.Flags.
 // During migrations, this controls dynamic behavior in the read path.
 func (msg *MessageHeader) NewCtx() MarshalerContext {
-	return MarshalerContext{UseV2WireFormat: true}
+	return MarshalerContext{}
 }
 
 var mMessageHeader = MustCreateMarshaler(MessageHeader{})
@@ -57,12 +65,8 @@
 // set based on the MarshalerContext. It is the caller's responsibilty to set
 // the transaction ID and method ordinal
 func (ctx MarshalerContext) NewHeader() MessageHeader {
-	var flagByte0 uint8
-	if ctx.UseV2WireFormat {
-		flagByte0 = FidlV2WireFormatFlagMask
-	}
 	return MessageHeader{
-		Flags: [3]uint8{flagByte0, 0, 0},
+		Flags: [3]uint8{FidlV2WireFormatFlagMask, 0, 0},
 		Magic: FidlWireFormatMagicNumberInitial,
 	}
 }
diff --git a/src/syscall/zx/fidl/encoding_new.go b/src/syscall/zx/fidl/encoding_new.go
index 5a19b59..82aeb73 100644
--- a/src/syscall/zx/fidl/encoding_new.go
+++ b/src/syscall/zx/fidl/encoding_new.go
@@ -1224,10 +1224,7 @@
 }
 
 func envelopeSize(ctx MarshalerContext) int {
-	if ctx.UseV2WireFormat {
-		return 8
-	}
-	return 16
+	return 8
 }
 
 type envelopeState int
@@ -1252,7 +1249,7 @@
 func marshalEnvelopePresent(ctx MarshalerContext, m Marshaler, v unsafevalue.Value, out *encoder, offset int, depth int) error {
 	numHandleDispositions := len(out.handleDispositions)
 
-	if ctx.UseV2WireFormat && m.getMarshalSize(ctx) <= 4 {
+	if m.getMarshalSize(ctx) <= 4 {
 		if err := m.marshal(ctx, v, out, offset, depth+1); err != nil {
 			return err
 		}
@@ -1275,26 +1272,14 @@
 	numHandleDispositions = len(out.handleDispositions) - numHandleDispositions
 	numBytes = len(out.buffer) - numBytes
 
-	if ctx.UseV2WireFormat {
-		out.writeUint32(offset, uint32(numBytes))
-		out.writeUint16(offset+4, uint16(numHandleDispositions))
-		out.writeUint16(offset+6, 0)
-		return nil
-	}
-
 	out.writeUint32(offset, uint32(numBytes))
-	out.writeUint32(offset+4, uint32(numHandleDispositions))
-	out.writeUint64(offset+8, allocPresent)
+	out.writeUint16(offset+4, uint16(numHandleDispositions))
+	out.writeUint16(offset+6, 0)
 	return nil
 }
 
 func marshalEnvelopeAbsent(ctx MarshalerContext, out *encoder, offset int) {
-	if ctx.UseV2WireFormat {
-		out.writeUint64(offset, 0) // zero envelope
-	} else {
-		out.writeUint64(offset, 0) // both numBytes, and numHandleDispositions
-		out.writeUint64(offset+8, noAlloc)
-	}
+	out.writeUint64(offset, 0) // zero envelope
 }
 
 func marshalEnvelopeUnknown(ctx MarshalerContext, out *encoder, offset int, depth int, unknownData UnknownData) error {
@@ -1308,7 +1293,7 @@
 		})
 	}
 
-	if ctx.UseV2WireFormat && len(unknownData.Bytes) <= 4 {
+	if len(unknownData.Bytes) <= 4 {
 		copy(out.buffer[offset:], unknownData.Bytes)
 		out.writeUint16(offset+4, uint16(len(unknownData.Handles)))
 		out.writeUint16(offset+6, 1)
@@ -1322,16 +1307,9 @@
 
 	copy(out.buffer[outOfLineOffset:], unknownData.Bytes)
 
-	if ctx.UseV2WireFormat {
-		out.writeUint32(offset, uint32(len(unknownData.Bytes)))
-		out.writeUint16(offset+4, uint16(len(unknownData.Handles)))
-		out.writeUint16(offset+6, 0)
-		return nil
-	}
-
 	out.writeUint32(offset, uint32(len(unknownData.Bytes)))
-	out.writeUint32(offset+4, uint32(len(unknownData.Handles)))
-	out.writeUint64(offset+8, allocPresent)
+	out.writeUint16(offset+4, uint16(len(unknownData.Handles)))
+	out.writeUint16(offset+6, 0)
 	return nil
 }
 
@@ -1353,63 +1331,30 @@
 
 func unmarshalEnvelopeHeader(ctx MarshalerContext, in *decoder, offset int) (envelopeHeader, error) {
 	var h envelopeHeader
-	if ctx.isV2WireFormatDecodingEnabled() {
-		inlineIndicator := in.readUint16(offset + 6)
-		switch inlineIndicator {
-		case 1:
-			h = envelopeHeader{
-				byteValue:   in.buffer[offset : offset+4],
-				handleCount: uint32(in.readUint16(offset + 4)),
-				state:       inlineEnvelope,
-			}
-		case 0:
-			h = envelopeHeader{
-				byteCount:   in.readUint32(offset),
-				handleCount: uint32(in.readUint16(offset + 4)),
-			}
-			if h.byteCount == 0 && h.handleCount == 0 {
-				h.state = emptyEnvelope
-			} else {
-				h.state = outOfLineEnvelope
-			}
-			if h.byteCount%8 != 0 {
-				return h, newValueError(ErrInvalidNumBytesInEnvelope, h.byteCount)
-			}
-		default:
-			return h, newValueError(ErrBadInlineIndicatorEncoding, h)
+	inlineIndicator := in.readUint16(offset + 6)
+	switch inlineIndicator {
+	case 1:
+		h = envelopeHeader{
+			byteValue:   in.buffer[offset : offset+4],
+			handleCount: uint32(in.readUint16(offset + 4)),
+			state:       inlineEnvelope,
 		}
-
-	} else {
+	case 0:
 		h = envelopeHeader{
 			byteCount:   in.readUint32(offset),
-			handleCount: in.readUint32(offset + 4),
+			handleCount: uint32(in.readUint16(offset + 4)),
 		}
-		presence := in.readUint64(offset + 8)
-		switch presence {
-		case allocPresent:
-			h.state = outOfLineEnvelope
-			if h.byteCount == 0 {
-				return h, newValueError(ErrInvalidNumBytesInEnvelope, h.byteCount)
-			}
-			if h.byteCount%8 != 0 {
-				return h, newValueError(ErrInvalidNumBytesInEnvelope, h.byteCount)
-			}
-		case noAlloc:
+		if h.byteCount == 0 && h.handleCount == 0 {
 			h.state = emptyEnvelope
-			if h.byteCount != 0 {
-				return h, newValueError(ErrInvalidNumBytesInEnvelope, h.byteCount)
-			}
-			if h.handleCount != 0 {
-				return h, newValueError(ErrInvalidNumHandlesInEnvelope, h.handleCount)
-			}
-		default:
-			return h, newValueError(ErrBadRefEncoding, h)
+		} else {
+			h.state = outOfLineEnvelope
 		}
+		if h.byteCount%8 != 0 {
+			return h, newValueError(ErrInvalidNumBytesInEnvelope, h.byteCount)
+		}
+	default:
+		return h, newValueError(ErrBadInlineIndicatorEncoding, h)
 	}
-	if h.byteCount%8 != 0 {
-		return h, newValueError(ErrInvalidNumBytesInEnvelope, h.byteCount)
-	}
-
 	return h, nil
 }
 
@@ -1453,7 +1398,7 @@
 }
 
 func unmarshalEnvelopeContent(ctx MarshalerContext, header envelopeHeader, m Marshaler, in *decoder, depth int, v unsafevalue.Value, mode unmarshalEnvelopeMode) (bool, error) {
-	if ctx.isV2WireFormatDecodingEnabled() && header.state == inlineEnvelope {
+	if header.state == inlineEnvelope {
 		// Inline envelope.
 		var innerDecoderHandleInfos []zx.HandleInfo
 		if header.handleCount != 0 {
@@ -1500,13 +1445,11 @@
 		return false, err
 	}
 
-	if ctx.UseV2WireFormat {
-		if m.getUnmarshalSize(ctx) > 4 && header.state == inlineEnvelope {
-			return false, newExpectError(ErrInvalidInlineBitValueInEnvelope, header.state, outOfLineEnvelope)
-		}
-		if m.getUnmarshalSize(ctx) <= 4 && header.state == outOfLineEnvelope {
-			return false, newExpectError(ErrInvalidInlineBitValueInEnvelope, header.state, inlineEnvelope)
-		}
+	if m.getUnmarshalSize(ctx) > 4 && header.state == inlineEnvelope {
+		return false, newExpectError(ErrInvalidInlineBitValueInEnvelope, header.state, outOfLineEnvelope)
+	}
+	if m.getUnmarshalSize(ctx) <= 4 && header.state == outOfLineEnvelope {
+		return false, newExpectError(ErrInvalidInlineBitValueInEnvelope, header.state, inlineEnvelope)
 	}
 
 	if !header.isPresent(ctx) {
@@ -1632,11 +1575,7 @@
 		}
 
 		ordinal++
-		if ctx.UseV2WireFormat {
-			envelopeOffset += 8
-		} else {
-			envelopeOffset += 16
-		}
+		envelopeOffset += 8
 		if fieldKnown {
 			index++
 		}
diff --git a/src/syscall/zx/fidl/errors.go b/src/syscall/zx/fidl/errors.go
index 26acfe8..cbd9248 100644
--- a/src/syscall/zx/fidl/errors.go
+++ b/src/syscall/zx/fidl/errors.go
@@ -69,6 +69,7 @@
 	ErrValueTypeHandles
 	ErrExceededMaxOutOfLineDepth
 	ErrInvalidInlineBitValueInEnvelope
+	ErrUnsupportedWireFormatVersion
 )
 
 var errorCodeNames = []string{
@@ -111,6 +112,7 @@
 	ErrValueTypeHandles:                "ErrValueTypeHandles",
 	ErrExceededMaxOutOfLineDepth:       "ErrExceededMaxOutOfLineDepth",
 	ErrInvalidInlineBitValueInEnvelope: "ErrInvalidInlineBitValueInEnvelope",
+	ErrUnsupportedWireFormatVersion:    "ErrUnsupportedWireFormatVersion",
 }
 
 func (c ErrorCode) String() string {
@@ -197,6 +199,8 @@
 		return "exceeded maxOutOfLineDepth"
 	case ErrInvalidInlineBitValueInEnvelope:
 		return "invalid inline bit value in envelope"
+	case ErrUnsupportedWireFormatVersion:
+		return "wire format version is not supported"
 	default:
 		return e.String()
 	}
@@ -260,6 +264,10 @@
 	return e.ErrorCode.Error() + ": " + toString(e.value)
 }
 
+func (e valueError) Unwrap() error {
+	return e.ErrorCode
+}
+
 // expectError represents an error that refers to the expectation of a
 // certain value, and displays a comparison between the actual value and
 // the expected value.
@@ -280,3 +288,7 @@
 func (e expectError) Error() string {
 	return e.ErrorCode.Error() + ": expected " + toString(e.expect) + ", got " + toString(e.actual)
 }
+
+func (e expectError) Unwrap() error {
+	return e.ErrorCode
+}
diff --git a/src/syscall/zx/fidl/interface.go b/src/syscall/zx/fidl/interface.go
index 9497c42..46f1646 100644
--- a/src/syscall/zx/fidl/interface.go
+++ b/src/syscall/zx/fidl/interface.go
@@ -218,8 +218,8 @@
 	if err != nil {
 		return nil, nil, err
 	}
-	if !header.IsSupportedVersion() {
-		return nil, nil, ErrUnknownMagic
+	if err := header.ValidateWireFormat(); err != nil {
+		return nil, nil, err
 	}
 	return objBytes[MessageHeaderSize:], handleInfos, nil
 }
diff --git a/src/syscall/zx/zxwait/zxwait.go b/src/syscall/zx/zxwait/zxwait.go
index a7a7c4f..4d00f24 100644
--- a/src/syscall/zx/zxwait/zxwait.go
+++ b/src/syscall/zx/zxwait/zxwait.go
@@ -79,7 +79,36 @@
 	g uintptr
 
 	done chan<- struct{}
-	obs  zx.Signals
+	mu   struct {
+		sync.Mutex
+		// A canceled waitingG has had its pending waiters canceled. This
+		// prevents duplicate calls to `zx.Port.Cancel` when there is a race
+		// between handle closure, and context cancelation (which can lead to
+		// the port's packet queue being in an unknown state).
+		canceled bool
+	}
+	obs zx.Signals
+}
+
+// cancelPendingWait cancels any pending waiters associated with this waitingG.
+//
+// The returned boolean is true if a pending waiter was canceled and false if
+// there were no waiters to cancel.
+func (w *waitingG) cancelPendingWait(port zx.Port, handle zx.Handle) (bool, error) {
+	w.mu.Lock()
+	defer w.mu.Unlock()
+	if !w.mu.canceled {
+		w.mu.canceled = true
+		switch status := zx.Sys_port_cancel(zx.Handle(port), handle, w.key); status {
+		case zx.ErrOk:
+			return true, nil
+		case zx.ErrNotFound:
+			return false, nil
+		default:
+			return false, &zx.Error{Status: status, Text: "zx.Port.Cancel"}
+		}
+	}
+	return false, nil
 }
 
 // A waiter is a zircon port that parks goroutines waiting on signals.
@@ -157,18 +186,19 @@
 	w.mu.Lock()
 	defer w.mu.Unlock()
 	for waiting := range w.mu.allByHandle[handle] {
-		switch status := zx.Sys_port_cancel(zx.Handle(w.port), handle, waiting.key); status {
-		case zx.ErrOk:
+		canceled, err := waiting.cancelPendingWait(w.port, handle)
+		if err != nil {
+			return err
+		}
+		if canceled {
+			// The waiter was canceled. Artificially notify it to wake the
+			// `Dequeue` routine.
 			if err := w.port.Queue(zx.PortPacket{
 				Key:  waiting.key,
 				Type: zx.PortPacketTypeUser,
 			}); err != nil {
 				return err
 			}
-		case zx.ErrNotFound:
-			// Nobody is waiting, no need to notify.
-		default:
-			return &zx.Error{Status: status, Text: "zx.Port.Cancel"}
 		}
 	}
 	return cb(handle)
@@ -180,6 +210,14 @@
 func (w *waiter) Wait(ctx context.Context, handle zx.Handle, signals zx.Signals) (zx.Signals, error) {
 	var waiting *waitingG
 
+	// If we observe `zx.SignalHandleClosed`, generate a `zx.ErrCanceled` error.
+	errorFromSignals := func(obs zx.Signals) error {
+		if obs == zx.SignalHandleClosed {
+			return &zx.Error{Status: zx.ErrCanceled, Text: "zxwait.Wait"}
+		}
+		return nil
+	}
+
 	w.mu.Lock()
 	if len(w.mu.free) == 0 {
 		waiting = &waitingG{
@@ -204,18 +242,23 @@
 			select {
 			case <-ch:
 				// Wait complete.
-				return waiting.obs, nil
+				obs := waiting.obs
+				return obs, errorFromSignals(obs)
 			case <-done:
 				// Context canceled.
-				switch status := zx.Sys_port_cancel(zx.Handle(w.port), handle, waiting.key); status {
-				case zx.ErrOk:
+				canceled, err := waiting.cancelPendingWait(w.port, handle)
+				if err != nil {
+					return 0, err
+				}
+				if canceled {
 					return 0, ctx.Err()
-				case zx.ErrNotFound:
-					// We lost the race.
+				} else {
+					// We lost the race and didn't cancel the waiter in time.
+					// Observe channel closure to keep the `Dequeue` routine in
+					// sync.
 					<-ch
-					return waiting.obs, nil
-				default:
-					return 0, &zx.Error{Status: status, Text: "zx.Port.Cancel"}
+					obs := waiting.obs
+					return obs, errorFromSignals(obs)
 				}
 			}
 		}
@@ -235,6 +278,11 @@
 			delete(w.mu.allByHandle, handle)
 		}
 		w.mu.free = append(w.mu.free, waiting)
+
+		waiting.mu.Lock()
+		waiting.mu.canceled = false
+		waiting.mu.Unlock()
+
 		w.mu.Unlock()
 	}()
 
@@ -251,13 +299,7 @@
 	gopark(w.unlockf, waiting, waitReasonIOWait, traceEvGoBlockSelect, 0)
 
 	obs := waiting.obs
-
-	return obs, func() error {
-		if obs == zx.SignalHandleClosed {
-			return &zx.Error{Status: zx.ErrCanceled, Text: "zxwait.Wait"}
-		}
-		return nil
-	}()
+	return obs, errorFromSignals(obs)
 }
 
 // unlockf is passed as a callback to gopark.
diff --git a/src/syscall/zx/zxwait/zxwait_test.go b/src/syscall/zx/zxwait/zxwait_test.go
index 93a21e1..c4f7387 100644
--- a/src/syscall/zx/zxwait/zxwait_test.go
+++ b/src/syscall/zx/zxwait/zxwait_test.go
@@ -207,10 +207,13 @@
 func TestWaitContext_LocalCloseRace(t *testing.T) {
 	var wg sync.WaitGroup
 
-	for i := 0; i < 100; i++ {
-		// Start a wait, assert the signal, and close the handle. This is a
-		// regression test for an issue where internal state was reused without
-		// cancelling pending waits, causing future waits to catch stale wakeups.
+	for i := 0; i < 1000; i++ {
+		// Start a wait, assert the signal, close the handle, and cancel the
+		// context. This is a regression test for two issues:
+		//  1) internal state was reused without canceling pending waits, and
+		//  2) internal state was not flagged as defunct after failing to
+		//     cleanly cancel a pending wait,
+		// Both of which caused future waits to catch stale wakeups.
 		wg.Add(1)
 		go func() {
 			defer wg.Done()
@@ -224,14 +227,17 @@
 					_ = event.Close()
 				}()
 
+				ctx, cancel := context.WithCancel(context.Background())
+				defer cancel()
+
 				// Buffer the channel to avoid leaking a goroutine in case of error
 				// below.
 				ch := make(chan error, 1)
 				// Capture the event by value to avoid racing against the Close call,
 				// which resets its receiver.
-				go func(event zx.Handle) {
+				go func(event zx.Handle, ctx context.Context) {
 					ch <- func() error {
-						obs, err := zxwait.WaitContext(context.Background(), event, zx.SignalUser0)
+						obs, err := zxwait.WaitContext(ctx, event, zx.SignalUser0)
 						if err != nil {
 							if err, ok := err.(*zx.Error); ok {
 								switch err.Status {
@@ -252,7 +258,7 @@
 						}
 						return nil
 					}()
-				}(event)
+				}(event, ctx)
 
 				// Yield to allow the goroutine to be scheduled, beginning the wait.
 				runtime.Gosched()
@@ -263,6 +269,7 @@
 				if err := event.Close(); err != nil {
 					return fmt.Errorf("failed to close event: %w", err)
 				}
+				cancel()
 
 				return <-ch
 			}(); err != nil {
diff --git a/src/text/template/exec.go b/src/text/template/exec.go
index fb60c17..fd7db65 100644
--- a/src/text/template/exec.go
+++ b/src/text/template/exec.go
@@ -361,19 +361,27 @@
 	// mark top of stack before any variables in the body are pushed.
 	mark := s.mark()
 	oneIteration := func(index, elem reflect.Value) {
-		// Set top var (lexically the second if there are two) to the element.
 		if len(r.Pipe.Decl) > 0 {
 			if r.Pipe.IsAssign {
-				s.setVar(r.Pipe.Decl[0].Ident[0], elem)
+				// With two variables, index comes first.
+				// With one, we use the element.
+				if len(r.Pipe.Decl) > 1 {
+					s.setVar(r.Pipe.Decl[0].Ident[0], index)
+				} else {
+					s.setVar(r.Pipe.Decl[0].Ident[0], elem)
+				}
 			} else {
+				// Set top var (lexically the second if there
+				// are two) to the element.
 				s.setTopVar(1, elem)
 			}
 		}
-		// Set next var (lexically the first if there are two) to the index.
 		if len(r.Pipe.Decl) > 1 {
 			if r.Pipe.IsAssign {
-				s.setVar(r.Pipe.Decl[1].Ident[0], index)
+				s.setVar(r.Pipe.Decl[1].Ident[0], elem)
 			} else {
+				// Set next var (lexically the first if there
+				// are two) to the index.
 				s.setTopVar(2, index)
 			}
 		}
diff --git a/src/text/template/exec_test.go b/src/text/template/exec_test.go
index 6b163f0..a7c010d 100644
--- a/src/text/template/exec_test.go
+++ b/src/text/template/exec_test.go
@@ -694,6 +694,7 @@
 	{"bug18c", "{{eq . 'P'}}", "true", 'P', true},
 
 	{"issue56490", "{{$i := 0}}{{$x := 0}}{{range $i = .AI}}{{end}}{{$i}}", "5", tVal, true},
+	{"issue60801", "{{$k := 0}}{{$v := 0}}{{range $k, $v = .AI}}{{$k}}={{$v}} {{end}}", "0=3 1=4 2=5 ", tVal, true},
 }
 
 func zeroArgs() string {
diff --git a/test/fixedbugs/issue60601.go b/test/fixedbugs/issue60601.go
new file mode 100644
index 0000000..5308989
--- /dev/null
+++ b/test/fixedbugs/issue60601.go
@@ -0,0 +1,50 @@
+// run
+
+// Copyright 2023 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 (
+	"strings"
+	"unsafe"
+)
+
+func shift[T any]() int64 {
+	return 1 << unsafe.Sizeof(*new(T))
+}
+
+func div[T any]() uintptr {
+	return 1 / unsafe.Sizeof(*new(T))
+}
+
+func add[T any]() int64 {
+	return 1<<63 - 1 + int64(unsafe.Sizeof(*new(T)))
+}
+
+func main() {
+	shift[[62]byte]()
+	shift[[63]byte]()
+	shift[[64]byte]()
+	shift[[100]byte]()
+	shift[[1e6]byte]()
+
+	add[[1]byte]()
+	shouldPanic("divide by zero", func() { div[[0]byte]() })
+}
+
+func shouldPanic(str string, f func()) {
+	defer func() {
+		err := recover()
+		if err == nil {
+			panic("did not panic")
+		}
+		s := err.(error).Error()
+		if !strings.Contains(s, str) {
+			panic("got panic " + s + ", want " + str)
+		}
+	}()
+
+	f()
+}