summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCoprDistGit <infra@openeuler.org>2024-09-12 04:23:51 +0000
committerCoprDistGit <infra@openeuler.org>2024-09-12 04:23:51 +0000
commit86d143317839566c602c276fafb1a30ad469941e (patch)
tree4e895b6b563710cbc2cce86ead21f0a8d58cdcd3
parent2784bd2c52574b27d271d643816d481d9e4dfc8c (diff)
automatic import of golang
-rw-r--r--.gitignore1
-rw-r--r--backport-0001-release-branch.go1.21-crypto-x509-make-sure-pub-key-.patch78
-rw-r--r--backport-0002-release-branch.go1.21-html-template-escape-additiona.patch193
-rw-r--r--backport-0003-release-branch.go1.21-net-textproto-mime-multipart-a.patch266
-rw-r--r--backport-0004-release-branch.go1.21-net-http-net-http-cookiejar-av.patch117
-rw-r--r--backport-0005-release-branch.go1.21-net-mail-properly-handle-speci.patch204
-rw-r--r--backport-0006-Backport-net-http-update-bundled-golang.org-x-net-ht.patch82
-rw-r--r--backport-0007-Backport-cmd-go-disallow-lto_library-in-LDFLAGS.patch133
-rw-r--r--backport-0008-release-branch.go1.21-net-netip-check-if-address-is-v6.patch221
-rw-r--r--backport-0009-Backport-cmd-go-internal-vcs-error-out-if-the-reques.patch108
-rw-r--r--backport-0010-release-branch.go1.21-net-http-limit-chunked-data-ov.patch175
-rw-r--r--backport-0011-Backport-archive-zip-treat-truncated-EOCDR-comment-a.patch58
-rw-r--r--backport-0012-net-http-send-body-or-close-connection-on-expect-100.patch353
-rw-r--r--backport-0013-release-branch.go1.21-net-http-update-bundled-golang.patch98
-rw-r--r--backport-0014-cmd-compile-handle-constant-pointer-offsets-in-dead-.patch143
-rw-r--r--backport-0015-release-branch.go1.21-cmd-compile-ensure-pointer-ari.patch650
-rw-r--r--golang.spec444
-rw-r--r--sources1
18 files changed, 3325 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index e69de29..12fea7c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -0,0 +1 @@
+/go1.21.4.src.tar.gz
diff --git a/backport-0001-release-branch.go1.21-crypto-x509-make-sure-pub-key-.patch b/backport-0001-release-branch.go1.21-crypto-x509-make-sure-pub-key-.patch
new file mode 100644
index 0000000..7ee3178
--- /dev/null
+++ b/backport-0001-release-branch.go1.21-crypto-x509-make-sure-pub-key-.patch
@@ -0,0 +1,78 @@
+From 5dfc2e6c42724349a9e9ecbcc69be920c18d90e9 Mon Sep 17 00:00:00 2001
+From: Roland Shoemaker <bracewell@google.com>
+Date: Thu, 18 Jan 2024 12:51:13 -0800
+Subject: [PATCH 1/4] [release-branch.go1.21] crypto/x509: make sure pub key is
+ non-nil before interface conversion
+
+alreadyInChain assumes all keys fit a interface which contains the
+Equal method (which they do), but this ignores that certificates may
+have a nil key when PublicKeyAlgorithm is UnknownPublicKeyAlgorithm. In
+this case alreadyInChain panics.
+
+Check that the key is non-nil as part of considerCandidate (we are never
+going to build a chain containing UnknownPublicKeyAlgorithm anyway).
+
+For #65390
+Fixes #65392
+Fixes CVE-2024-24783
+
+Change-Id: Ibdccc0a487e3368b6812be35daad2512220243f3
+Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2137282
+Reviewed-by: Damien Neil <dneil@google.com>
+Run-TryBot: Roland Shoemaker <bracewell@google.com>
+Reviewed-by: Tatiana Bradley <tatianabradley@google.com>
+Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2173774
+Reviewed-by: Roland Shoemaker <bracewell@google.com>
+Reviewed-by: Carlos Amedee <amedee@google.com>
+Reviewed-on: https://go-review.googlesource.com/c/go/+/569238
+Auto-Submit: Michael Knyszek <mknyszek@google.com>
+LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
+Reviewed-by: Carlos Amedee <carlos@golang.org>
+---
+ src/crypto/x509/verify.go | 2 +-
+ src/crypto/x509/verify_test.go | 19 +++++++++++++++++++
+ 2 files changed, 20 insertions(+), 1 deletion(-)
+
+diff --git a/src/crypto/x509/verify.go b/src/crypto/x509/verify.go
+index 345d434453c..56a1a1725cc 100644
+--- a/src/crypto/x509/verify.go
++++ b/src/crypto/x509/verify.go
+@@ -899,7 +899,7 @@ func (c *Certificate) buildChains(currentChain []*Certificate, sigChecks *int, o
+ )
+
+ considerCandidate := func(certType int, candidate *Certificate) {
+- if alreadyInChain(candidate, currentChain) {
++ if candidate.PublicKey == nil || alreadyInChain(candidate, currentChain) {
+ return
+ }
+
+diff --git a/src/crypto/x509/verify_test.go b/src/crypto/x509/verify_test.go
+index 3551b470ced..d8678d03f93 100644
+--- a/src/crypto/x509/verify_test.go
++++ b/src/crypto/x509/verify_test.go
+@@ -2693,3 +2693,22 @@ func TestVerifyEKURootAsLeaf(t *testing.T) {
+ }
+
+ }
++
++func TestVerifyNilPubKey(t *testing.T) {
++ c := &Certificate{
++ RawIssuer: []byte{1, 2, 3},
++ AuthorityKeyId: []byte{1, 2, 3},
++ }
++ opts := &VerifyOptions{}
++ opts.Roots = NewCertPool()
++ r := &Certificate{
++ RawSubject: []byte{1, 2, 3},
++ SubjectKeyId: []byte{1, 2, 3},
++ }
++ opts.Roots.AddCert(r)
++
++ _, err := c.buildChains([]*Certificate{r}, nil, opts)
++ if _, ok := err.(UnknownAuthorityError); !ok {
++ t.Fatalf("buildChains returned unexpected error, got: %v, want %v", err, UnknownAuthorityError{})
++ }
++}
+--
+2.33.0
+
diff --git a/backport-0002-release-branch.go1.21-html-template-escape-additiona.patch b/backport-0002-release-branch.go1.21-html-template-escape-additiona.patch
new file mode 100644
index 0000000..403cf6b
--- /dev/null
+++ b/backport-0002-release-branch.go1.21-html-template-escape-additiona.patch
@@ -0,0 +1,193 @@
+From 0787ee55dd0d42dd8bef97d4e7ed7584f44c16e9 Mon Sep 17 00:00:00 2001
+From: Roland Shoemaker <roland@golang.org>
+Date: Wed, 14 Feb 2024 17:18:36 -0800
+Subject: [PATCH 2/4] [release-branch.go1.21] html/template: escape additional
+ tokens in MarshalJSON errors
+
+Escape "</script" and "<!--" in errors returned from MarshalJSON errors
+when attempting to marshal types in script blocks. This prevents any
+user controlled content from prematurely terminating the script block.
+
+Updates #65697
+Fixes #65968
+
+Change-Id: Icf0e26c54ea7d9c1deed0bff11b6506c99ddef1b
+Reviewed-on: https://go-review.googlesource.com/c/go/+/564196
+LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
+Reviewed-by: Damien Neil <dneil@google.com>
+(cherry picked from commit ccbc725f2d678255df1bd326fa511a492aa3a0aa)
+Reviewed-on: https://go-review.googlesource.com/c/go/+/567515
+Reviewed-by: Carlos Amedee <carlos@golang.org>
+---
+ src/html/template/js.go | 22 ++++++++-
+ src/html/template/js_test.go | 96 ++++++++++++++++++++----------------
+ 2 files changed, 74 insertions(+), 44 deletions(-)
+
+diff --git a/src/html/template/js.go b/src/html/template/js.go
+index 4e05c145572..f4d1303bebe 100644
+--- a/src/html/template/js.go
++++ b/src/html/template/js.go
+@@ -171,13 +171,31 @@ func jsValEscaper(args ...any) string {
+ // cyclic data. This may be an unacceptable DoS risk.
+ b, err := json.Marshal(a)
+ if err != nil {
+- // Put a space before comment so that if it is flush against
++ // While the standard JSON marshaller does not include user controlled
++ // information in the error message, if a type has a MarshalJSON method,
++ // the content of the error message is not guaranteed. Since we insert
++ // the error into the template, as part of a comment, we attempt to
++ // prevent the error from either terminating the comment, or the script
++ // block itself.
++ //
++ // In particular we:
++ // * replace "*/" comment end tokens with "* /", which does not
++ // terminate the comment
++ // * replace "</script" with "\x3C/script", and "<!--" with
++ // "\x3C!--", which prevents confusing script block termination
++ // semantics
++ //
++ // We also put a space before the comment so that if it is flush against
+ // a division operator it is not turned into a line comment:
+ // x/{{y}}
+ // turning into
+ // x//* error marshaling y:
+ // second line of error message */null
+- return fmt.Sprintf(" /* %s */null ", strings.ReplaceAll(err.Error(), "*/", "* /"))
++ errStr := err.Error()
++ errStr = strings.ReplaceAll(errStr, "*/", "* /")
++ errStr = strings.ReplaceAll(errStr, "</script", `\x3C/script`)
++ errStr = strings.ReplaceAll(errStr, "<!--", `\x3C!--`)
++ return fmt.Sprintf(" /* %s */null ", errStr)
+ }
+
+ // TODO: maybe post-process output to prevent it from containing
+diff --git a/src/html/template/js_test.go b/src/html/template/js_test.go
+index 259dcfbdc5b..17cedcec05f 100644
+--- a/src/html/template/js_test.go
++++ b/src/html/template/js_test.go
+@@ -5,6 +5,7 @@
+ package template
+
+ import (
++ "errors"
+ "math"
+ "strings"
+ "testing"
+@@ -103,61 +104,72 @@ func TestNextJsCtx(t *testing.T) {
+ }
+ }
+
++type jsonErrType struct{}
++
++func (e *jsonErrType) MarshalJSON() ([]byte, error) {
++ return nil, errors.New("beep */ boop </script blip <!--")
++}
++
+ func TestJSValEscaper(t *testing.T) {
+ tests := []struct {
+- x any
+- js string
++ x any
++ js string
++ skipNest bool
+ }{
+- {int(42), " 42 "},
+- {uint(42), " 42 "},
+- {int16(42), " 42 "},
+- {uint16(42), " 42 "},
+- {int32(-42), " -42 "},
+- {uint32(42), " 42 "},
+- {int16(-42), " -42 "},
+- {uint16(42), " 42 "},
+- {int64(-42), " -42 "},
+- {uint64(42), " 42 "},
+- {uint64(1) << 53, " 9007199254740992 "},
++ {int(42), " 42 ", false},
++ {uint(42), " 42 ", false},
++ {int16(42), " 42 ", false},
++ {uint16(42), " 42 ", false},
++ {int32(-42), " -42 ", false},
++ {uint32(42), " 42 ", false},
++ {int16(-42), " -42 ", false},
++ {uint16(42), " 42 ", false},
++ {int64(-42), " -42 ", false},
++ {uint64(42), " 42 ", false},
++ {uint64(1) << 53, " 9007199254740992 ", false},
+ // ulp(1 << 53) > 1 so this loses precision in JS
+ // but it is still a representable integer literal.
+- {uint64(1)<<53 + 1, " 9007199254740993 "},
+- {float32(1.0), " 1 "},
+- {float32(-1.0), " -1 "},
+- {float32(0.5), " 0.5 "},
+- {float32(-0.5), " -0.5 "},
+- {float32(1.0) / float32(256), " 0.00390625 "},
+- {float32(0), " 0 "},
+- {math.Copysign(0, -1), " -0 "},
+- {float64(1.0), " 1 "},
+- {float64(-1.0), " -1 "},
+- {float64(0.5), " 0.5 "},
+- {float64(-0.5), " -0.5 "},
+- {float64(0), " 0 "},
+- {math.Copysign(0, -1), " -0 "},
+- {"", `""`},
+- {"foo", `"foo"`},
++ {uint64(1)<<53 + 1, " 9007199254740993 ", false},
++ {float32(1.0), " 1 ", false},
++ {float32(-1.0), " -1 ", false},
++ {float32(0.5), " 0.5 ", false},
++ {float32(-0.5), " -0.5 ", false},
++ {float32(1.0) / float32(256), " 0.00390625 ", false},
++ {float32(0), " 0 ", false},
++ {math.Copysign(0, -1), " -0 ", false},
++ {float64(1.0), " 1 ", false},
++ {float64(-1.0), " -1 ", false},
++ {float64(0.5), " 0.5 ", false},
++ {float64(-0.5), " -0.5 ", false},
++ {float64(0), " 0 ", false},
++ {math.Copysign(0, -1), " -0 ", false},
++ {"", `""`, false},
++ {"foo", `"foo"`, false},
+ // Newlines.
+- {"\r\n\u2028\u2029", `"\r\n\u2028\u2029"`},
++ {"\r\n\u2028\u2029", `"\r\n\u2028\u2029"`, false},
+ // "\v" == "v" on IE 6 so use "\u000b" instead.
+- {"\t\x0b", `"\t\u000b"`},
+- {struct{ X, Y int }{1, 2}, `{"X":1,"Y":2}`},
+- {[]any{}, "[]"},
+- {[]any{42, "foo", nil}, `[42,"foo",null]`},
+- {[]string{"<!--", "</script>", "-->"}, `["\u003c!--","\u003c/script\u003e","--\u003e"]`},
+- {"<!--", `"\u003c!--"`},
+- {"-->", `"--\u003e"`},
+- {"<![CDATA[", `"\u003c![CDATA["`},
+- {"]]>", `"]]\u003e"`},
+- {"</script", `"\u003c/script"`},
+- {"\U0001D11E", "\"\U0001D11E\""}, // or "\uD834\uDD1E"
+- {nil, " null "},
++ {"\t\x0b", `"\t\u000b"`, false},
++ {struct{ X, Y int }{1, 2}, `{"X":1,"Y":2}`, false},
++ {[]any{}, "[]", false},
++ {[]any{42, "foo", nil}, `[42,"foo",null]`, false},
++ {[]string{"<!--", "</script>", "-->"}, `["\u003c!--","\u003c/script\u003e","--\u003e"]`, false},
++ {"<!--", `"\u003c!--"`, false},
++ {"-->", `"--\u003e"`, false},
++ {"<![CDATA[", `"\u003c![CDATA["`, false},
++ {"]]>", `"]]\u003e"`, false},
++ {"</script", `"\u003c/script"`, false},
++ {"\U0001D11E", "\"\U0001D11E\"", false}, // or "\uD834\uDD1E"
++ {nil, " null ", false},
++ {&jsonErrType{}, " /* json: error calling MarshalJSON for type *template.jsonErrType: beep * / boop \\x3C/script blip \\x3C!-- */null ", true},
+ }
+
+ for _, test := range tests {
+ if js := jsValEscaper(test.x); js != test.js {
+ t.Errorf("%+v: want\n\t%q\ngot\n\t%q", test.x, test.js, js)
+ }
++ if test.skipNest {
++ continue
++ }
+ // Make sure that escaping corner cases are not broken
+ // by nesting.
+ a := []any{test.x}
+--
+2.33.0
+
diff --git a/backport-0003-release-branch.go1.21-net-textproto-mime-multipart-a.patch b/backport-0003-release-branch.go1.21-net-textproto-mime-multipart-a.patch
new file mode 100644
index 0000000..a5d2254
--- /dev/null
+++ b/backport-0003-release-branch.go1.21-net-textproto-mime-multipart-a.patch
@@ -0,0 +1,266 @@
+From 1e8ba3a45a208d2d9838904e4ea8730d31f24d5b Mon Sep 17 00:00:00 2001
+From: Damien Neil <dneil@google.com>
+Date: Tue, 16 Jan 2024 15:37:52 -0800
+Subject: [PATCH 3/4] [release-branch.go1.21] net/textproto, mime/multipart:
+ avoid unbounded read in MIME header
+
+mime/multipart.Reader.ReadForm allows specifying the maximum amount
+of memory that will be consumed by the form. While this limit is
+correctly applied to the parsed form data structure, it was not
+being applied to individual header lines in a form.
+
+For example, when presented with a form containing a header line
+that never ends, ReadForm will continue to read the line until it
+runs out of memory.
+
+Limit the amount of data consumed when reading a header.
+
+Fixes CVE-2023-45290
+Fixes #65389
+For #65383
+
+Change-Id: I7f9264d25752009e95f6b2c80e3d76aaf321d658
+Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2134435
+Reviewed-by: Roland Shoemaker <bracewell@google.com>
+Reviewed-by: Tatiana Bradley <tatianabradley@google.com>
+Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2173776
+Reviewed-by: Carlos Amedee <amedee@google.com>
+Reviewed-on: https://go-review.googlesource.com/c/go/+/569240
+Auto-Submit: Michael Knyszek <mknyszek@google.com>
+LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
+Reviewed-by: Carlos Amedee <carlos@golang.org>
+---
+ src/mime/multipart/formdata_test.go | 42 +++++++++++++++++++++++++
+ src/net/textproto/reader.go | 48 ++++++++++++++++++++---------
+ src/net/textproto/reader_test.go | 12 ++++++++
+ 3 files changed, 87 insertions(+), 15 deletions(-)
+
+diff --git a/src/mime/multipart/formdata_test.go b/src/mime/multipart/formdata_test.go
+index d422729c96a..bfa9f683825 100644
+--- a/src/mime/multipart/formdata_test.go
++++ b/src/mime/multipart/formdata_test.go
+@@ -452,6 +452,48 @@ func TestReadFormLimits(t *testing.T) {
+ }
+ }
+
++func TestReadFormEndlessHeaderLine(t *testing.T) {
++ for _, test := range []struct {
++ name string
++ prefix string
++ }{{
++ name: "name",
++ prefix: "X-",
++ }, {
++ name: "value",
++ prefix: "X-Header: ",
++ }, {
++ name: "continuation",
++ prefix: "X-Header: foo\r\n ",
++ }} {
++ t.Run(test.name, func(t *testing.T) {
++ const eol = "\r\n"
++ s := `--boundary` + eol
++ s += `Content-Disposition: form-data; name="a"` + eol
++ s += `Content-Type: text/plain` + eol
++ s += test.prefix
++ fr := io.MultiReader(
++ strings.NewReader(s),
++ neverendingReader('X'),
++ )
++ r := NewReader(fr, "boundary")
++ _, err := r.ReadForm(1 << 20)
++ if err != ErrMessageTooLarge {
++ t.Fatalf("ReadForm(1 << 20): %v, want ErrMessageTooLarge", err)
++ }
++ })
++ }
++}
++
++type neverendingReader byte
++
++func (r neverendingReader) Read(p []byte) (n int, err error) {
++ for i := range p {
++ p[i] = byte(r)
++ }
++ return len(p), nil
++}
++
+ func BenchmarkReadForm(b *testing.B) {
+ for _, test := range []struct {
+ name string
+diff --git a/src/net/textproto/reader.go b/src/net/textproto/reader.go
+index fc2590b1cdc..fcd1a011ac7 100644
+--- a/src/net/textproto/reader.go
++++ b/src/net/textproto/reader.go
+@@ -16,6 +16,10 @@ import (
+ "sync"
+ )
+
++// TODO: This should be a distinguishable error (ErrMessageTooLarge)
++// to allow mime/multipart to detect it.
++var errMessageTooLarge = errors.New("message too large")
++
+ // A Reader implements convenience methods for reading requests
+ // or responses from a text protocol network connection.
+ type Reader struct {
+@@ -36,20 +40,23 @@ func NewReader(r *bufio.Reader) *Reader {
+ // ReadLine reads a single line from r,
+ // eliding the final \n or \r\n from the returned string.
+ func (r *Reader) ReadLine() (string, error) {
+- line, err := r.readLineSlice()
++ line, err := r.readLineSlice(-1)
+ return string(line), err
+ }
+
+ // ReadLineBytes is like ReadLine but returns a []byte instead of a string.
+ func (r *Reader) ReadLineBytes() ([]byte, error) {
+- line, err := r.readLineSlice()
++ line, err := r.readLineSlice(-1)
+ if line != nil {
+ line = bytes.Clone(line)
+ }
+ return line, err
+ }
+
+-func (r *Reader) readLineSlice() ([]byte, error) {
++// readLineSlice reads a single line from r,
++// up to lim bytes long (or unlimited if lim is less than 0),
++// eliding the final \r or \r\n from the returned string.
++func (r *Reader) readLineSlice(lim int64) ([]byte, error) {
+ r.closeDot()
+ var line []byte
+ for {
+@@ -57,6 +64,9 @@ func (r *Reader) readLineSlice() ([]byte, error) {
+ if err != nil {
+ return nil, err
+ }
++ if lim >= 0 && int64(len(line))+int64(len(l)) > lim {
++ return nil, errMessageTooLarge
++ }
+ // Avoid the copy if the first call produced a full line.
+ if line == nil && !more {
+ return l, nil
+@@ -88,7 +98,7 @@ func (r *Reader) readLineSlice() ([]byte, error) {
+ //
+ // Empty lines are never continued.
+ func (r *Reader) ReadContinuedLine() (string, error) {
+- line, err := r.readContinuedLineSlice(noValidation)
++ line, err := r.readContinuedLineSlice(-1, noValidation)
+ return string(line), err
+ }
+
+@@ -109,7 +119,7 @@ func trim(s []byte) []byte {
+ // ReadContinuedLineBytes is like ReadContinuedLine but
+ // returns a []byte instead of a string.
+ func (r *Reader) ReadContinuedLineBytes() ([]byte, error) {
+- line, err := r.readContinuedLineSlice(noValidation)
++ line, err := r.readContinuedLineSlice(-1, noValidation)
+ if line != nil {
+ line = bytes.Clone(line)
+ }
+@@ -120,13 +130,14 @@ func (r *Reader) ReadContinuedLineBytes() ([]byte, error) {
+ // returning a byte slice with all lines. The validateFirstLine function
+ // is run on the first read line, and if it returns an error then this
+ // error is returned from readContinuedLineSlice.
+-func (r *Reader) readContinuedLineSlice(validateFirstLine func([]byte) error) ([]byte, error) {
++// It reads up to lim bytes of data (or unlimited if lim is less than 0).
++func (r *Reader) readContinuedLineSlice(lim int64, validateFirstLine func([]byte) error) ([]byte, error) {
+ if validateFirstLine == nil {
+ return nil, fmt.Errorf("missing validateFirstLine func")
+ }
+
+ // Read the first line.
+- line, err := r.readLineSlice()
++ line, err := r.readLineSlice(lim)
+ if err != nil {
+ return nil, err
+ }
+@@ -154,13 +165,21 @@ func (r *Reader) readContinuedLineSlice(validateFirstLine func([]byte) error) ([
+ // copy the slice into buf.
+ r.buf = append(r.buf[:0], trim(line)...)
+
++ if lim < 0 {
++ lim = math.MaxInt64
++ }
++ lim -= int64(len(r.buf))
++
+ // Read continuation lines.
+ for r.skipSpace() > 0 {
+- line, err := r.readLineSlice()
++ r.buf = append(r.buf, ' ')
++ if int64(len(r.buf)) >= lim {
++ return nil, errMessageTooLarge
++ }
++ line, err := r.readLineSlice(lim - int64(len(r.buf)))
+ if err != nil {
+ break
+ }
+- r.buf = append(r.buf, ' ')
+ r.buf = append(r.buf, trim(line)...)
+ }
+ return r.buf, nil
+@@ -507,7 +526,8 @@ func readMIMEHeader(r *Reader, maxMemory, maxHeaders int64) (MIMEHeader, error)
+
+ // 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.readLineSlice()
++ const errorLimit = 80 // arbitrary limit on how much of the line we'll quote
++ line, err := r.readLineSlice(errorLimit)
+ if err != nil {
+ return m, err
+ }
+@@ -515,7 +535,7 @@ func readMIMEHeader(r *Reader, maxMemory, maxHeaders int64) (MIMEHeader, error)
+ }
+
+ for {
+- kv, err := r.readContinuedLineSlice(mustHaveFieldNameColon)
++ kv, err := r.readContinuedLineSlice(maxMemory, mustHaveFieldNameColon)
+ if len(kv) == 0 {
+ return m, err
+ }
+@@ -544,7 +564,7 @@ func readMIMEHeader(r *Reader, maxMemory, maxHeaders int64) (MIMEHeader, error)
+
+ maxHeaders--
+ if maxHeaders < 0 {
+- return nil, errors.New("message too large")
++ return nil, errMessageTooLarge
+ }
+
+ // Skip initial spaces in value.
+@@ -557,9 +577,7 @@ func readMIMEHeader(r *Reader, maxMemory, maxHeaders int64) (MIMEHeader, error)
+ }
+ maxMemory -= int64(len(value))
+ if maxMemory < 0 {
+- // TODO: This should be a distinguishable error (ErrMessageTooLarge)
+- // to allow mime/multipart to detect it.
+- return m, errors.New("message too large")
++ return m, errMessageTooLarge
+ }
+ if vv == nil && len(strs) > 0 {
+ // More than likely this will be a single-element key.
+diff --git a/src/net/textproto/reader_test.go b/src/net/textproto/reader_test.go
+index 696ae406f38..26ff617470b 100644
+--- a/src/net/textproto/reader_test.go
++++ b/src/net/textproto/reader_test.go
+@@ -36,6 +36,18 @@ func TestReadLine(t *testing.T) {
+ }
+ }
+
++func TestReadLineLongLine(t *testing.T) {
++ line := strings.Repeat("12345", 10000)
++ r := reader(line + "\r\n")
++ s, err := r.ReadLine()
++ if err != nil {
++ t.Fatalf("Line 1: %v", err)
++ }
++ if s != line {
++ t.Fatalf("%v-byte line does not match expected %v-byte line", len(s), len(line))
++ }
++}
++
+ func TestReadContinuedLine(t *testing.T) {
+ r := reader("line1\nline\n 2\nline3\n")
+ s, err := r.ReadContinuedLine()
+--
+2.33.0
+
diff --git a/backport-0004-release-branch.go1.21-net-http-net-http-cookiejar-av.patch b/backport-0004-release-branch.go1.21-net-http-net-http-cookiejar-av.patch
new file mode 100644
index 0000000..db25f1e
--- /dev/null
+++ b/backport-0004-release-branch.go1.21-net-http-net-http-cookiejar-av.patch
@@ -0,0 +1,117 @@
+From 6021dca711926c32959c2dc4c2a68c9494e9a4fc Mon Sep 17 00:00:00 2001
+From: Damien Neil <dneil@google.com>
+Date: Thu, 11 Jan 2024 11:31:57 -0800
+Subject: [PATCH 4/4] [release-branch.go1.21] net/http, net/http/cookiejar:
+ avoid subdomain matches on IPv6 zones
+
+When deciding whether to forward cookies or sensitive headers
+across a redirect, do not attempt to interpret an IPv6 address
+as a domain name.
+
+Avoids a case where a maliciously-crafted redirect to an
+IPv6 address with a scoped addressing zone could be
+misinterpreted as a within-domain redirect. For example,
+we could interpret "::1%.www.example.com" as a subdomain
+of "www.example.com".
+
+Thanks to Juho Nurminen of Mattermost for reporting this issue.
+
+Fixes CVE-2023-45289
+Fixes #65385
+For #65065
+
+Change-Id: I8f463f59f0e700c8a18733d2b264a8bcb3a19599
+Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2131938
+Reviewed-by: Tatiana Bradley <tatianabradley@google.com>
+Reviewed-by: Roland Shoemaker <bracewell@google.com>
+Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2173775
+Reviewed-by: Carlos Amedee <amedee@google.com>
+Reviewed-on: https://go-review.googlesource.com/c/go/+/569239
+Reviewed-by: Carlos Amedee <carlos@golang.org>
+Auto-Submit: Michael Knyszek <mknyszek@google.com>
+TryBot-Bypass: Michael Knyszek <mknyszek@google.com>
+---
+ src/net/http/client.go | 6 ++++++
+ src/net/http/client_test.go | 1 +
+ src/net/http/cookiejar/jar.go | 7 +++++++
+ src/net/http/cookiejar/jar_test.go | 10 ++++++++++
+ 4 files changed, 24 insertions(+)
+
+diff --git a/src/net/http/client.go b/src/net/http/client.go
+index 2cab53a585a..77a701b8061 100644
+--- a/src/net/http/client.go
++++ b/src/net/http/client.go
+@@ -1014,6 +1014,12 @@ func isDomainOrSubdomain(sub, parent string) bool {
+ if sub == parent {
+ return true
+ }
++ // If sub contains a :, it's probably an IPv6 address (and is definitely not a hostname).
++ // Don't check the suffix in this case, to avoid matching the contents of a IPv6 zone.
++ // For example, "::1%.www.example.com" is not a subdomain of "www.example.com".
++ if strings.ContainsAny(sub, ":%") {
++ return false
++ }
+ // If sub is "foo.example.com" and parent is "example.com",
+ // that means sub must end in "."+parent.
+ // Do it without allocating.
+diff --git a/src/net/http/client_test.go b/src/net/http/client_test.go
+index 0fe555af38f..fc1d7916124 100644
+--- a/src/net/http/client_test.go
++++ b/src/net/http/client_test.go
+@@ -1725,6 +1725,7 @@ func TestShouldCopyHeaderOnRedirect(t *testing.T) {
+ {"authorization", "http://foo.com/", "https://foo.com/", true},
+ {"authorization", "http://foo.com:1234/", "http://foo.com:4321/", true},
+ {"www-authenticate", "http://foo.com/", "http://bar.com/", false},
++ {"authorization", "http://foo.com/", "http://[::1%25.foo.com]/", false},
+
+ // But subdomains should work:
+ {"www-authenticate", "http://foo.com/", "http://foo.com/", true},
+diff --git a/src/net/http/cookiejar/jar.go b/src/net/http/cookiejar/jar.go
+index 273b54c84c7..4b16266057b 100644
+--- a/src/net/http/cookiejar/jar.go
++++ b/src/net/http/cookiejar/jar.go
+@@ -362,6 +362,13 @@ func jarKey(host string, psl PublicSuffixList) string {
+
+ // isIP reports whether host is an IP address.
+ func isIP(host string) bool {
++ if strings.ContainsAny(host, ":%") {
++ // Probable IPv6 address.
++ // Hostnames can't contain : or %, so this is definitely not a valid host.
++ // Treating it as an IP is the more conservative option, and avoids the risk
++ // of interpeting ::1%.www.example.com as a subtomain of www.example.com.
++ return true
++ }
+ return net.ParseIP(host) != nil
+ }
+
+diff --git a/src/net/http/cookiejar/jar_test.go b/src/net/http/cookiejar/jar_test.go
+index 56d0695a660..251f7c16171 100644
+--- a/src/net/http/cookiejar/jar_test.go
++++ b/src/net/http/cookiejar/jar_test.go
+@@ -252,6 +252,7 @@ var isIPTests = map[string]bool{
+ "127.0.0.1": true,
+ "1.2.3.4": true,
+ "2001:4860:0:2001::68": true,
++ "::1%zone": true,
+ "example.com": false,
+ "1.1.1.300": false,
+ "www.foo.bar.net": false,
+@@ -629,6 +630,15 @@ var basicsTests = [...]jarTest{
+ {"http://www.host.test:1234/", "a=1"},
+ },
+ },
++ {
++ "IPv6 zone is not treated as a host.",
++ "https://example.com/",
++ []string{"a=1"},
++ "a=1",
++ []query{
++ {"https://[::1%25.example.com]:80/", ""},
++ },
++ },
+ }
+
+ func TestBasics(t *testing.T) {
+--
+2.33.0
+
diff --git a/backport-0005-release-branch.go1.21-net-mail-properly-handle-speci.patch b/backport-0005-release-branch.go1.21-net-mail-properly-handle-speci.patch
new file mode 100644
index 0000000..fc7b26c
--- /dev/null
+++ b/backport-0005-release-branch.go1.21-net-mail-properly-handle-speci.patch
@@ -0,0 +1,204 @@
+From 11c0f19796e30484848a6c9c469364c0841c17ef Mon Sep 17 00:00:00 2001
+From: Roland Shoemaker <bracewell@google.com>
+Date: Wed, 10 Jan 2024 11:02:14 -0800
+Subject: [PATCH] [release-branch.go1.21] net/mail: properly handle special
+ characters in phrase and obs-phrase
+
+Fixes a couple of misalignments with RFC 5322 which introduce
+significant diffs between (mostly) conformant parsers.
+
+This change reverts the changes made in CL50911, which allowed certain
+special RFC 5322 characters to appear unquoted in the "phrase" syntax.
+It is unclear why this change was made in the first place, and created
+a divergence from comformant parsers. In particular this resulted in
+treating comments in display names incorrectly.
+
+Additionally properly handle trailing malformed comments in the group
+syntax.
+
+For #65083
+Fixes #65848
+
+Change-Id: I00dddc044c6ae3381154e43236632604c390f672
+Reviewed-on: https://go-review.googlesource.com/c/go/+/555596
+Reviewed-by: Damien Neil <dneil@google.com>
+LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
+Reviewed-on: https://go-review.googlesource.com/c/go/+/566195
+Reviewed-by: Carlos Amedee <carlos@golang.org>
+---
+ src/net/mail/message.go | 30 +++++++++++++++------------
+ src/net/mail/message_test.go | 40 ++++++++++++++++++++++++++----------
+ 2 files changed, 46 insertions(+), 24 deletions(-)
+
+diff --git a/src/net/mail/message.go b/src/net/mail/message.go
+index af516fc30f..fc2a9e46f8 100644
+--- a/src/net/mail/message.go
++++ b/src/net/mail/message.go
+@@ -280,7 +280,7 @@ func (a *Address) String() string {
+ // Add quotes if needed
+ quoteLocal := false
+ for i, r := range local {
+- if isAtext(r, false, false) {
++ if isAtext(r, false) {
+ continue
+ }
+ if r == '.' {
+@@ -444,7 +444,7 @@ func (p *addrParser) parseAddress(handleGroup bool) ([]*Address, error) {
+ if !p.consume('<') {
+ atext := true
+ for _, r := range displayName {
+- if !isAtext(r, true, false) {
++ if !isAtext(r, true) {
+ atext = false
+ break
+ }
+@@ -479,7 +479,9 @@ func (p *addrParser) consumeGroupList() ([]*Address, error) {
+ // handle empty group.
+ p.skipSpace()
+ if p.consume(';') {
+- p.skipCFWS()
++ if !p.skipCFWS() {
++ return nil, errors.New("mail: misformatted parenthetical comment")
++ }
+ return group, nil
+ }
+
+@@ -496,7 +498,9 @@ func (p *addrParser) consumeGroupList() ([]*Address, error) {
+ return nil, errors.New("mail: misformatted parenthetical comment")
+ }
+ if p.consume(';') {
+- p.skipCFWS()
++ if !p.skipCFWS() {
++ return nil, errors.New("mail: misformatted parenthetical comment")
++ }
+ break
+ }
+ if !p.consume(',') {
+@@ -566,6 +570,12 @@ func (p *addrParser) consumePhrase() (phrase string, err error) {
+ var words []string
+ var isPrevEncoded bool
+ for {
++ // obs-phrase allows CFWS after one word
++ if len(words) > 0 {
++ if !p.skipCFWS() {
++ return "", errors.New("mail: misformatted parenthetical comment")
++ }
++ }
+ // word = atom / quoted-string
+ var word string
+ p.skipSpace()
+@@ -661,7 +671,6 @@ Loop:
+ // If dot is true, consumeAtom parses an RFC 5322 dot-atom instead.
+ // If permissive is true, consumeAtom will not fail on:
+ // - leading/trailing/double dots in the atom (see golang.org/issue/4938)
+-// - special characters (RFC 5322 3.2.3) except '<', '>', ':' and '"' (see golang.org/issue/21018)
+ func (p *addrParser) consumeAtom(dot bool, permissive bool) (atom string, err error) {
+ i := 0
+
+@@ -672,7 +681,7 @@ Loop:
+ case size == 1 && r == utf8.RuneError:
+ return "", fmt.Errorf("mail: invalid utf-8 in address: %q", p.s)
+
+- case size == 0 || !isAtext(r, dot, permissive):
++ case size == 0 || !isAtext(r, dot):
+ break Loop
+
+ default:
+@@ -850,18 +859,13 @@ func (e charsetError) Error() string {
+
+ // isAtext reports whether r is an RFC 5322 atext character.
+ // If dot is true, period is included.
+-// If permissive is true, RFC 5322 3.2.3 specials is included,
+-// except '<', '>', ':' and '"'.
+-func isAtext(r rune, dot, permissive bool) bool {
++func isAtext(r rune, dot bool) bool {
+ switch r {
+ case '.':
+ return dot
+
+ // RFC 5322 3.2.3. specials
+- case '(', ')', '[', ']', ';', '@', '\\', ',':
+- return permissive
+-
+- case '<', '>', '"', ':':
++ case '(', ')', '<', '>', '[', ']', ':', ';', '@', '\\', ',', '"': // RFC 5322 3.2.3. specials
+ return false
+ }
+ return isVchar(r)
+diff --git a/src/net/mail/message_test.go b/src/net/mail/message_test.go
+index 1e1bb4092f..1f2f62afbf 100644
+--- a/src/net/mail/message_test.go
++++ b/src/net/mail/message_test.go
+@@ -385,8 +385,11 @@ func TestAddressParsingError(t *testing.T) {
+ 13: {"group not closed: null@example.com", "expected comma"},
+ 14: {"group: first@example.com, second@example.com;", "group with multiple addresses"},
+ 15: {"john.doe", "missing '@' or angle-addr"},
+- 16: {"john.doe@", "no angle-addr"},
++ 16: {"john.doe@", "missing '@' or angle-addr"},
+ 17: {"John Doe@foo.bar", "no angle-addr"},
++ 18: {" group: null@example.com; (asd", "misformatted parenthetical comment"},
++ 19: {" group: ; (asd", "misformatted parenthetical comment"},
++ 20: {`(John) Doe <jdoe@machine.example>`, "missing word in phrase:"},
+ }
+
+ for i, tc := range mustErrTestCases {
+@@ -436,24 +439,19 @@ func TestAddressParsing(t *testing.T) {
+ Address: "john.q.public@example.com",
+ }},
+ },
+- {
+- `"John (middle) Doe" <jdoe@machine.example>`,
+- []*Address{{
+- Name: "John (middle) Doe",
+- Address: "jdoe@machine.example",
+- }},
+- },
++ // Comment in display name
+ {
+ `John (middle) Doe <jdoe@machine.example>`,
+ []*Address{{
+- Name: "John (middle) Doe",
++ Name: "John Doe",
+ Address: "jdoe@machine.example",
+ }},
+ },
++ // Display name is quoted string, so comment is not a comment
+ {
+- `John !@M@! Doe <jdoe@machine.example>`,
++ `"John (middle) Doe" <jdoe@machine.example>`,
+ []*Address{{
+- Name: "John !@M@! Doe",
++ Name: "John (middle) Doe",
+ Address: "jdoe@machine.example",
+ }},
+ },
+@@ -788,6 +786,26 @@ func TestAddressParsing(t *testing.T) {
+ },
+ },
+ },
++ // Comment in group display name
++ {
++ `group (comment:): a@example.com, b@example.com;`,
++ []*Address{
++ {
++ Address: "a@example.com",
++ },
++ {
++ Address: "b@example.com",
++ },
++ },
++ },
++ {
++ `x(:"):"@a.example;("@b.example;`,
++ []*Address{
++ {
++ Address: `@a.example;(@b.example`,
++ },
++ },
++ },
+ }
+ for _, test := range tests {
+ if len(test.exp) == 1 {
+--
+2.33.0
+
diff --git a/backport-0006-Backport-net-http-update-bundled-golang.org-x-net-ht.patch b/backport-0006-Backport-net-http-update-bundled-golang.org-x-net-ht.patch
new file mode 100644
index 0000000..ab4dfb2
--- /dev/null
+++ b/backport-0006-Backport-net-http-update-bundled-golang.org-x-net-ht.patch
@@ -0,0 +1,82 @@
+From a65a2b54e18a7e269bff32526b4180ece22e9aa6 Mon Sep 17 00:00:00 2001
+From: Damien Neil <dneil@google.com>
+Date: Thu, 28 Mar 2024 16:57:51 -0700
+Subject: [PATCH] [Backport] net/http: update bundled golang.org/x/net/http2
+
+Offering: Cloud Core Network
+CVE: CVE-2023-45288
+Reference: https://go-review.googlesource.com/c/go/+/576076
+
+Disable cmd/internal/moddeps test, since this update includes PRIVATE
+track fixes.
+
+Fixes CVE-2023-45288
+For #65051
+Fixes #66298
+
+Change-Id: I5bbf774ebe7651e4bb7e55139d3794bd2b8e8fa8
+Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2197227
+Reviewed-by: Tatiana Bradley <tatianabradley@google.com>
+Run-TryBot: Damien Neil <dneil@google.com>
+Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
+Reviewed-on: https://go-review.googlesource.com/c/go/+/576076
+Auto-Submit: Dmitri Shuralyov <dmitshur@google.com>
+TryBot-Bypass: Dmitri Shuralyov <dmitshur@google.com>
+Reviewed-by: Than McIntosh <thanm@google.com>
+Signed-off-by: Ma Chang Wang machangwang@huawei.com
+---
+ src/net/http/h2_bundle.go | 31 +++++++++++++++++++++++++++++++
+ 1 file changed, 31 insertions(+)
+
+diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go
+index dd59e1f4f2..cd95f84269 100644
+--- a/src/net/http/h2_bundle.go
++++ b/src/net/http/h2_bundle.go
+@@ -2966,6 +2966,7 @@ func (fr *http2Framer) readMetaFrame(hf *http2HeadersFrame) (*http2MetaHeadersFr
+ if size > remainSize {
+ hdec.SetEmitEnabled(false)
+ mh.Truncated = true
++ remainSize = 0
+ return
+ }
+ remainSize -= size
+@@ -2978,6 +2979,36 @@ func (fr *http2Framer) readMetaFrame(hf *http2HeadersFrame) (*http2MetaHeadersFr
+ var hc http2headersOrContinuation = hf
+ for {
+ frag := hc.HeaderBlockFragment()
++
++ // Avoid parsing large amounts of headers that we will then discard.
++ // If the sender exceeds the max header list size by too much,
++ // skip parsing the fragment and close the connection.
++ //
++ // "Too much" is either any CONTINUATION frame after we've already
++ // exceeded the max header list size (in which case remainSize is 0),
++ // or a frame whose encoded size is more than twice the remaining
++ // header list bytes we're willing to accept.
++ if int64(len(frag)) > int64(2*remainSize) {
++ if http2VerboseLogs {
++ log.Printf("http2: header list too large")
++ }
++ // It would be nice to send a RST_STREAM before sending the GOAWAY,
++ // but the struture of the server's frame writer makes this difficult.
++ return nil, http2ConnectionError(http2ErrCodeProtocol)
++ }
++
++ // Also close the connection after any CONTINUATION frame following an
++ // invalid header, since we stop tracking the size of the headers after
++ // an invalid one.
++ if invalid != nil {
++ if http2VerboseLogs {
++ log.Printf("http2: invalid header: %v", invalid)
++ }
++ // It would be nice to send a RST_STREAM before sending the GOAWAY,
++ // but the struture of the server's frame writer makes this difficult.
++ return nil, http2ConnectionError(http2ErrCodeProtocol)
++ }
++
+ if _, err := hdec.Write(frag); err != nil {
+ return nil, http2ConnectionError(http2ErrCodeCompression)
+ }
+--
+2.33.0
+
diff --git a/backport-0007-Backport-cmd-go-disallow-lto_library-in-LDFLAGS.patch b/backport-0007-Backport-cmd-go-disallow-lto_library-in-LDFLAGS.patch
new file mode 100644
index 0000000..b1c16a5
--- /dev/null
+++ b/backport-0007-Backport-cmd-go-disallow-lto_library-in-LDFLAGS.patch
@@ -0,0 +1,133 @@
+From 7edadbad6c5ba7db3c4ab6925369096dedcf8e0b Mon Sep 17 00:00:00 2001
+From: Roland Shoemaker <bracewell@google.com>
+Date: Thu, 25 Apr 2024 13:09:54 -0700
+Subject: [PATCH] [Backport] cmd/go: disallow -lto_library in LDFLAGS
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Offering: Cloud Core Network
+CVE: CVE-2024-24787
+Reference: https://go-review.googlesource.com/c/go/+/583796
+
+The darwin linker allows setting the LTO library with the -lto_library
+flag. This wasn't caught by our "safe linker flags" check because it
+was covered by the -lx flag used for linking libraries. This change
+adds a specific check for excluded flags which otherwise satisfy our
+existing checks.
+
+Loading a mallicious LTO library would allow an attacker to cause the
+linker to execute abritrary code when "go build" was called.
+
+Thanks to Juho Forsén of Mattermost for reporting this issue.
+
+Fixes #67119
+Fixes #67122
+Fixes CVE-2024-24787
+
+Change-Id: I77ac8585efbdbdfd5f39c39ed623b9408a0f9eaf
+Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/1380
+Reviewed-by: Russ Cox <rsc@google.com>
+Reviewed-by: Damien Neil <dneil@google.com>
+(cherry picked from commit 9a79141fbbca1105e5c786f15e38741ca7843290)
+Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/1420
+Reviewed-by: Tatiana Bradley <tatianabradley@google.com>
+Reviewed-on: https://go-review.googlesource.com/c/go/+/583796
+Reviewed-by: David Chase <drchase@google.com>
+LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
+Signed-off-by: Ma Chang Wang machangwang@huawei.com
+---
+ src/cmd/go/internal/work/security.go | 19 +++++++++++++++----
+ .../script/darwin_lto_library_ldflag.txt | 17 +++++++++++++++++
+ 2 files changed, 32 insertions(+), 4 deletions(-)
+ create mode 100644 src/cmd/go/testdata/script/darwin_lto_library_ldflag.txt
+
+diff --git a/src/cmd/go/internal/work/security.go b/src/cmd/go/internal/work/security.go
+index 270a34e9c7..db49eb6488 100644
+--- a/src/cmd/go/internal/work/security.go
++++ b/src/cmd/go/internal/work/security.go
+@@ -141,6 +141,12 @@ var validCompilerFlagsWithNextArg = []string{
+ "-x",
+ }
+
++var invalidLinkerFlags = []*lazyregexp.Regexp{
++ // On macOS this means the linker loads and executes the next argument.
++ // Have to exclude separately because -lfoo is allowed in general.
++ re(`-lto_library`),
++}
++
+ var validLinkerFlags = []*lazyregexp.Regexp{
+ re(`-F([^@\-].*)`),
+ re(`-l([^@\-].*)`),
+@@ -231,12 +237,12 @@ var validLinkerFlagsWithNextArg = []string{
+
+ func checkCompilerFlags(name, source string, list []string) error {
+ checkOverrides := true
+- return checkFlags(name, source, list, validCompilerFlags, validCompilerFlagsWithNextArg, checkOverrides)
++ return checkFlags(name, source, list, nil, validCompilerFlags, validCompilerFlagsWithNextArg, checkOverrides)
+ }
+
+ func checkLinkerFlags(name, source string, list []string) error {
+ checkOverrides := true
+- return checkFlags(name, source, list, validLinkerFlags, validLinkerFlagsWithNextArg, checkOverrides)
++ return checkFlags(name, source, list, invalidLinkerFlags, validLinkerFlags, validLinkerFlagsWithNextArg, checkOverrides)
+ }
+
+ // checkCompilerFlagsForInternalLink returns an error if 'list'
+@@ -245,7 +251,7 @@ func checkLinkerFlags(name, source string, list []string) error {
+ // external linker).
+ func checkCompilerFlagsForInternalLink(name, source string, list []string) error {
+ checkOverrides := false
+- if err := checkFlags(name, source, list, validCompilerFlags, validCompilerFlagsWithNextArg, checkOverrides); err != nil {
++ if err := checkFlags(name, source, list, nil, validCompilerFlags, validCompilerFlagsWithNextArg, checkOverrides); err != nil {
+ return err
+ }
+ // Currently the only flag on the allow list that causes problems
+@@ -258,7 +264,7 @@ func checkCompilerFlagsForInternalLink(name, source string, list []string) error
+ return nil
+ }
+
+-func checkFlags(name, source string, list []string, valid []*lazyregexp.Regexp, validNext []string, checkOverrides bool) error {
++func checkFlags(name, source string, list []string, invalid, valid []*lazyregexp.Regexp, validNext []string, checkOverrides bool) error {
+ // Let users override rules with $CGO_CFLAGS_ALLOW, $CGO_CFLAGS_DISALLOW, etc.
+ var (
+ allow *regexp.Regexp
+@@ -290,6 +296,11 @@ Args:
+ if allow != nil && allow.FindString(arg) == arg {
+ continue Args
+ }
++ for _, re := range invalid {
++ if re.FindString(arg) == arg { // must be complete match
++ goto Bad
++ }
++ }
+ for _, re := range valid {
+ if re.FindString(arg) == arg { // must be complete match
+ continue Args
+diff --git a/src/cmd/go/testdata/script/darwin_lto_library_ldflag.txt b/src/cmd/go/testdata/script/darwin_lto_library_ldflag.txt
+new file mode 100644
+index 0000000000..d7acefdbad
+--- /dev/null
++++ b/src/cmd/go/testdata/script/darwin_lto_library_ldflag.txt
+@@ -0,0 +1,17 @@
++[!GOOS:darwin] skip
++[!cgo] skip
++
++! go build
++stderr 'invalid flag in #cgo LDFLAGS: -lto_library'
++
++-- go.mod --
++module ldflag
++
++-- main.go --
++package main
++
++// #cgo CFLAGS: -flto
++// #cgo LDFLAGS: -lto_library bad.dylib
++import "C"
++
++func main() {}
+\ No newline at end of file
+--
+2.33.0
+
diff --git a/backport-0008-release-branch.go1.21-net-netip-check-if-address-is-v6.patch b/backport-0008-release-branch.go1.21-net-netip-check-if-address-is-v6.patch
new file mode 100644
index 0000000..261dbe0
--- /dev/null
+++ b/backport-0008-release-branch.go1.21-net-netip-check-if-address-is-v6.patch
@@ -0,0 +1,221 @@
+From 051bdf3fd12a40307606ff9381138039c5f452f0 Mon Sep 17 00:00:00 2001
+From: Roland Shoemaker <bracewell@google.com>
+Date: Tue, 28 May 2024 13:26:31 -0700
+Subject: [PATCH] [release-branch.go1.21] net/netip: check if address is v6
+ mapped in Is methods
+
+In all of the Is* methods, check if the address is a v6 mapped v4
+address, and unmap it if so.
+
+Thanks to Enze Wang of Alioth (@zer0yu) and Jianjun Chen of Zhongguancun
+Lab (@chenjj) for reporting this issue.
+
+Fixes #67680
+Fixes #67681
+Fixes CVE-2024-24790
+
+Change-Id: I6bd03ca1a5d93a0b59027d861c84060967b265b0
+Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/1460
+Reviewed-by: Russ Cox <rsc@google.com>
+Reviewed-by: Damien Neil <dneil@google.com>
+(cherry picked from commit f7f270c1621fdc7ee48e0487b2fac0356947d19b)
+Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/1500
+Reviewed-by: Tatiana Bradley <tatianabradley@google.com>
+Reviewed-on: https://go-review.googlesource.com/c/go/+/590315
+Auto-Submit: Michael Knyszek <mknyszek@google.com>
+LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
+Reviewed-by: David Chase <drchase@google.com>
+---
+ src/net/netip/inlining_test.go | 2 --
+ src/net/netip/netip.go | 26 +++++++++++++++++-
+ src/net/netip/netip_test.go | 50 +++++++++++++++++++++++++++++++---
+ 3 files changed, 71 insertions(+), 7 deletions(-)
+
+diff --git a/src/net/netip/inlining_test.go b/src/net/netip/inlining_test.go
+index b521eeebfd8f3..98584b098df1b 100644
+--- a/src/net/netip/inlining_test.go
++++ b/src/net/netip/inlining_test.go
+@@ -36,8 +36,6 @@ func TestInlining(t *testing.T) {
+ "Addr.Is4",
+ "Addr.Is4In6",
+ "Addr.Is6",
+- "Addr.IsLoopback",
+- "Addr.IsMulticast",
+ "Addr.IsInterfaceLocalMulticast",
+ "Addr.IsValid",
+ "Addr.IsUnspecified",
+diff --git a/src/net/netip/netip.go b/src/net/netip/netip.go
+index a44b09495549d..9e4d41f8fb7b9 100644
+--- a/src/net/netip/netip.go
++++ b/src/net/netip/netip.go
+@@ -507,6 +507,10 @@ func (ip Addr) hasZone() bool {
+
+ // IsLinkLocalUnicast reports whether ip is a link-local unicast address.
+ func (ip Addr) IsLinkLocalUnicast() bool {
++ if ip.Is4In6() {
++ ip = ip.Unmap()
++ }
++
+ // Dynamic Configuration of IPv4 Link-Local Addresses
+ // https://datatracker.ietf.org/doc/html/rfc3927#section-2.1
+ if ip.Is4() {
+@@ -522,6 +526,10 @@ func (ip Addr) IsLinkLocalUnicast() bool {
+
+ // IsLoopback reports whether ip is a loopback address.
+ func (ip Addr) IsLoopback() bool {
++ if ip.Is4In6() {
++ ip = ip.Unmap()
++ }
++
+ // Requirements for Internet Hosts -- Communication Layers (3.2.1.3 Addressing)
+ // https://datatracker.ietf.org/doc/html/rfc1122#section-3.2.1.3
+ if ip.Is4() {
+@@ -537,6 +545,10 @@ func (ip Addr) IsLoopback() bool {
+
+ // IsMulticast reports whether ip is a multicast address.
+ func (ip Addr) IsMulticast() bool {
++ if ip.Is4In6() {
++ ip = ip.Unmap()
++ }
++
+ // Host Extensions for IP Multicasting (4. HOST GROUP ADDRESSES)
+ // https://datatracker.ietf.org/doc/html/rfc1112#section-4
+ if ip.Is4() {
+@@ -555,7 +567,7 @@ func (ip Addr) IsMulticast() bool {
+ func (ip Addr) IsInterfaceLocalMulticast() bool {
+ // IPv6 Addressing Architecture (2.7.1. Pre-Defined Multicast Addresses)
+ // https://datatracker.ietf.org/doc/html/rfc4291#section-2.7.1
+- if ip.Is6() {
++ if ip.Is6() && !ip.Is4In6() {
+ return ip.v6u16(0)&0xff0f == 0xff01
+ }
+ return false // zero value
+@@ -563,6 +575,10 @@ func (ip Addr) IsInterfaceLocalMulticast() bool {
+
+ // IsLinkLocalMulticast reports whether ip is a link-local multicast address.
+ func (ip Addr) IsLinkLocalMulticast() bool {
++ if ip.Is4In6() {
++ ip = ip.Unmap()
++ }
++
+ // IPv4 Multicast Guidelines (4. Local Network Control Block (224.0.0/24))
+ // https://datatracker.ietf.org/doc/html/rfc5771#section-4
+ if ip.Is4() {
+@@ -591,6 +607,10 @@ func (ip Addr) IsGlobalUnicast() bool {
+ return false
+ }
+
++ if ip.Is4In6() {
++ ip = ip.Unmap()
++ }
++
+ // Match package net's IsGlobalUnicast logic. Notably private IPv4 addresses
+ // and ULA IPv6 addresses are still considered "global unicast".
+ if ip.Is4() && (ip == IPv4Unspecified() || ip == AddrFrom4([4]byte{255, 255, 255, 255})) {
+@@ -608,6 +628,10 @@ func (ip Addr) IsGlobalUnicast() bool {
+ // ip is in 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, or fc00::/7. This is the
+ // same as net.IP.IsPrivate.
+ func (ip Addr) IsPrivate() bool {
++ if ip.Is4In6() {
++ ip = ip.Unmap()
++ }
++
+ // Match the stdlib's IsPrivate logic.
+ if ip.Is4() {
+ // RFC 1918 allocates 10.0.0.0/8, 172.16.0.0/12, and 192.168.0.0/16 as
+diff --git a/src/net/netip/netip_test.go b/src/net/netip/netip_test.go
+index 0f80bb0ab0e56..5c7ad14c5c702 100644
+--- a/src/net/netip/netip_test.go
++++ b/src/net/netip/netip_test.go
+@@ -589,10 +589,13 @@ func TestIPProperties(t *testing.T) {
+ ilm6 = mustIP("ff01::1")
+ ilmZone6 = mustIP("ff01::1%eth0")
+
+- private4a = mustIP("10.0.0.1")
+- private4b = mustIP("172.16.0.1")
+- private4c = mustIP("192.168.1.1")
+- private6 = mustIP("fd00::1")
++ private4a = mustIP("10.0.0.1")
++ private4b = mustIP("172.16.0.1")
++ private4c = mustIP("192.168.1.1")
++ private6 = mustIP("fd00::1")
++ private6mapped4a = mustIP("::ffff:10.0.0.1")
++ private6mapped4b = mustIP("::ffff:172.16.0.1")
++ private6mapped4c = mustIP("::ffff:192.168.1.1")
+ )
+
+ tests := []struct {
+@@ -616,6 +619,11 @@ func TestIPProperties(t *testing.T) {
+ ip: unicast4,
+ globalUnicast: true,
+ },
++ {
++ name: "unicast v6 mapped v4Addr",
++ ip: AddrFrom16(unicast4.As16()),
++ globalUnicast: true,
++ },
+ {
+ name: "unicast v6Addr",
+ ip: unicast6,
+@@ -637,6 +645,12 @@ func TestIPProperties(t *testing.T) {
+ linkLocalMulticast: true,
+ multicast: true,
+ },
++ {
++ name: "multicast v6 mapped v4Addr",
++ ip: AddrFrom16(multicast4.As16()),
++ linkLocalMulticast: true,
++ multicast: true,
++ },
+ {
+ name: "multicast v6Addr",
+ ip: multicast6,
+@@ -654,6 +668,11 @@ func TestIPProperties(t *testing.T) {
+ ip: llu4,
+ linkLocalUnicast: true,
+ },
++ {
++ name: "link-local unicast v6 mapped v4Addr",
++ ip: AddrFrom16(llu4.As16()),
++ linkLocalUnicast: true,
++ },
+ {
+ name: "link-local unicast v6Addr",
+ ip: llu6,
+@@ -679,6 +698,11 @@ func TestIPProperties(t *testing.T) {
+ ip: IPv6Loopback(),
+ loopback: true,
+ },
++ {
++ name: "loopback v6 mapped v4Addr",
++ ip: AddrFrom16(IPv6Loopback().As16()),
++ loopback: true,
++ },
+ {
+ name: "interface-local multicast v6Addr",
+ ip: ilm6,
+@@ -715,6 +739,24 @@ func TestIPProperties(t *testing.T) {
+ globalUnicast: true,
+ private: true,
+ },
++ {
++ name: "private v6 mapped v4Addr 10/8",
++ ip: private6mapped4a,
++ globalUnicast: true,
++ private: true,
++ },
++ {
++ name: "private v6 mapped v4Addr 172.16/12",
++ ip: private6mapped4b,
++ globalUnicast: true,
++ private: true,
++ },
++ {
++ name: "private v6 mapped v4Addr 192.168/16",
++ ip: private6mapped4c,
++ globalUnicast: true,
++ private: true,
++ },
+ {
+ name: "unspecified v4Addr",
+ ip: IPv4Unspecified(),
diff --git a/backport-0009-Backport-cmd-go-internal-vcs-error-out-if-the-reques.patch b/backport-0009-Backport-cmd-go-internal-vcs-error-out-if-the-reques.patch
new file mode 100644
index 0000000..fb5d4bb
--- /dev/null
+++ b/backport-0009-Backport-cmd-go-internal-vcs-error-out-if-the-reques.patch
@@ -0,0 +1,108 @@
+From 558cbc498c70278bea8297272f2d4fc50d67893b Mon Sep 17 00:00:00 2001
+From: "Bryan C. Mills" <bcmills@google.com>
+Date: Thu, 2 Nov 2023 15:06:35 -0400
+Subject: [PATCH] [Backport] cmd/go/internal/vcs: error out if the requested
+ repo does not support a secure protocol
+
+CVE: CVE-2023-45285
+Reference: https://go-review.googlesource.com/c/go/+/540335
+
+Updates #63845.
+Fixes #63972.
+
+Change-Id: If86d6b13d3b55877b35c087112bd76388c9404b8
+Reviewed-on: https://go-review.googlesource.com/c/go/+/539321
+Reviewed-by: Michael Matloob <matloob@golang.org>
+LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
+Reviewed-by: Roland Shoemaker <roland@golang.org>
+Auto-Submit: Bryan Mills <bcmills@google.com>
+(cherry picked from commit be26ae18caf7ddffca4073333f80d0d9e76483c3)
+Reviewed-on: https://go-review.googlesource.com/c/go/+/540335
+Auto-Submit: Dmitri Shuralyov <dmitshur@google.com>
+Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
+Signed-off-by: wangbingyao 00557526 <wangbingyao5@huawei.com>
+---
+ src/cmd/go/internal/vcs/vcs.go | 25 +++++++++++++----
+ .../script/mod_insecure_issue63845.txt | 28 +++++++++++++++++++
+ 2 files changed, 47 insertions(+), 6 deletions(-)
+ create mode 100644 src/cmd/go/testdata/script/mod_insecure_issue63845.txt
+
+diff --git a/src/cmd/go/internal/vcs/vcs.go b/src/cmd/go/internal/vcs/vcs.go
+index c65dd0f624..dbf16d1de7 100644
+--- a/src/cmd/go/internal/vcs/vcs.go
++++ b/src/cmd/go/internal/vcs/vcs.go
+@@ -1204,18 +1204,31 @@ func repoRootFromVCSPaths(importPath string, security web.SecurityMode, vcsPaths
+ var ok bool
+ repoURL, ok = interceptVCSTest(repo, vcs, security)
+ if !ok {
+- scheme := vcs.Scheme[0] // default to first scheme
+- if vcs.PingCmd != "" {
+- // If we know how to test schemes, scan to find one.
++ scheme, err := func() (string, error) {
+ for _, s := range vcs.Scheme {
+ if security == web.SecureOnly && !vcs.isSecureScheme(s) {
+ continue
+ }
+- if vcs.Ping(s, repo) == nil {
+- scheme = s
+- break
++
++ // If we know how to ping URL schemes for this VCS,
++ // check that this repo works.
++ // Otherwise, default to the first scheme
++ // that meets the requested security level.
++ if vcs.PingCmd == "" {
++ return s, nil
++ }
++ if err := vcs.Ping(s, repo); err == nil {
++ return s, nil
+ }
+ }
++ securityFrag := ""
++ if security == web.SecureOnly {
++ securityFrag = "secure "
++ }
++ return "", fmt.Errorf("no %sprotocol found for repository", securityFrag)
++ }()
++ if err != nil {
++ return nil, err
+ }
+ repoURL = scheme + "://" + repo
+ }
+diff --git a/src/cmd/go/testdata/script/mod_insecure_issue63845.txt b/src/cmd/go/testdata/script/mod_insecure_issue63845.txt
+new file mode 100644
+index 0000000000..5fa6a4f12b
+--- /dev/null
++++ b/src/cmd/go/testdata/script/mod_insecure_issue63845.txt
+@@ -0,0 +1,28 @@
++# Regression test for https://go.dev/issue/63845:
++# If 'git ls-remote' fails for all secure protocols,
++# we should fail instead of falling back to an arbitrary protocol.
++#
++# Note that this test does not use the local vcweb test server
++# (vcs-test.golang.org), because the hook for redirecting to that
++# server bypasses the "ping to determine protocol" logic
++# in cmd/go/internal/vcs.
++
++[!net] skip
++[!git] skip
++[short] skip 'tries to access a nonexistent external Git repo'
++
++env GOPRIVATE=golang.org
++env CURLOPT_TIMEOUT_MS=100
++env GIT_SSH_COMMAND=false
++
++! go get -x golang.org/nonexist.git@latest
++stderr '^git ls-remote https://golang.org/nonexist$'
++stderr '^git ls-remote git\+ssh://golang.org/nonexist'
++stderr '^git ls-remote ssh://golang.org/nonexist$'
++! stderr 'git://'
++stderr '^go: golang.org/nonexist.git@latest: no secure protocol found for repository$'
++
++-- go.mod --
++module example
++
++go 1.19
+--
+2.33.0
+
diff --git a/backport-0010-release-branch.go1.21-net-http-limit-chunked-data-ov.patch b/backport-0010-release-branch.go1.21-net-http-limit-chunked-data-ov.patch
new file mode 100644
index 0000000..67367a4
--- /dev/null
+++ b/backport-0010-release-branch.go1.21-net-http-limit-chunked-data-ov.patch
@@ -0,0 +1,175 @@
+From 43c0e9116f26416de7454855852eba9083d94d03 Mon Sep 17 00:00:00 2001
+From: Damien Neil <dneil@google.com>
+Date: Tue, 7 Nov 2023 10:47:56 -0800
+Subject: [PATCH 1/2] [release-branch.go1.21] net/http: limit chunked data
+ overhead
+
+The chunked transfer encoding adds some overhead to
+the content transferred. When writing one byte per
+chunk, for example, there are five bytes of overhead
+per byte of data transferred: "1\r\nX\r\n" to send "X".
+
+Chunks may include "chunk extensions",
+which we skip over and do not use.
+For example: "1;chunk extension here\r\nX\r\n".
+
+A malicious sender can use chunk extensions to add
+about 4k of overhead per byte of data.
+(The maximum chunk header line size we will accept.)
+
+Track the amount of overhead read in chunked data,
+and produce an error if it seems excessive.
+
+Updates #64433
+Fixes #64435
+Fixes CVE-2023-39326
+
+Change-Id: I40f8d70eb6f9575fb43f506eb19132ccedafcf39
+Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2076135
+Reviewed-by: Tatiana Bradley <tatianabradley@google.com>
+Reviewed-by: Roland Shoemaker <bracewell@google.com>
+(cherry picked from commit 3473ae72ee66c60744665a24b2fde143e8964d4f)
+Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2095408
+Run-TryBot: Roland Shoemaker <bracewell@google.com>
+Reviewed-by: Damien Neil <dneil@google.com>
+Reviewed-on: https://go-review.googlesource.com/c/go/+/547356
+Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
+LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
+---
+ src/net/http/internal/chunked.go | 34 ++++++++++++---
+ src/net/http/internal/chunked_test.go | 59 +++++++++++++++++++++++++++
+ 2 files changed, 87 insertions(+), 6 deletions(-)
+
+diff --git a/src/net/http/internal/chunked.go b/src/net/http/internal/chunked.go
+index 5a174415dc4..aad8e5aa09e 100644
+--- a/src/net/http/internal/chunked.go
++++ b/src/net/http/internal/chunked.go
+@@ -39,7 +39,8 @@ type chunkedReader struct {
+ n uint64 // unread bytes in chunk
+ err error
+ buf [2]byte
+- checkEnd bool // whether need to check for \r\n chunk footer
++ checkEnd bool // whether need to check for \r\n chunk footer
++ excess int64 // "excessive" chunk overhead, for malicious sender detection
+ }
+
+ func (cr *chunkedReader) beginChunk() {
+@@ -49,10 +50,36 @@ func (cr *chunkedReader) beginChunk() {
+ if cr.err != nil {
+ return
+ }
++ cr.excess += int64(len(line)) + 2 // header, plus \r\n after the chunk data
++ line = trimTrailingWhitespace(line)
++ line, cr.err = removeChunkExtension(line)
++ if cr.err != nil {
++ return
++ }
+ cr.n, cr.err = parseHexUint(line)
+ if cr.err != nil {
+ return
+ }
++ // A sender who sends one byte per chunk will send 5 bytes of overhead
++ // for every byte of data. ("1\r\nX\r\n" to send "X".)
++ // We want to allow this, since streaming a byte at a time can be legitimate.
++ //
++ // A sender can use chunk extensions to add arbitrary amounts of additional
++ // data per byte read. ("1;very long extension\r\nX\r\n" to send "X".)
++ // We don't want to disallow extensions (although we discard them),
++ // but we also don't want to allow a sender to reduce the signal/noise ratio
++ // arbitrarily.
++ //
++ // We track the amount of excess overhead read,
++ // and produce an error if it grows too large.
++ //
++ // Currently, we say that we're willing to accept 16 bytes of overhead per chunk,
++ // plus twice the amount of real data in the chunk.
++ cr.excess -= 16 + (2 * int64(cr.n))
++ cr.excess = max(cr.excess, 0)
++ if cr.excess > 16*1024 {
++ cr.err = errors.New("chunked encoding contains too much non-data")
++ }
+ if cr.n == 0 {
+ cr.err = io.EOF
+ }
+@@ -140,11 +167,6 @@ func readChunkLine(b *bufio.Reader) ([]byte, error) {
+ if len(p) >= maxLineLength {
+ return nil, ErrLineTooLong
+ }
+- p = trimTrailingWhitespace(p)
+- p, err = removeChunkExtension(p)
+- if err != nil {
+- return nil, err
+- }
+ return p, nil
+ }
+
+diff --git a/src/net/http/internal/chunked_test.go b/src/net/http/internal/chunked_test.go
+index 5e29a786dd6..b99090c1f8a 100644
+--- a/src/net/http/internal/chunked_test.go
++++ b/src/net/http/internal/chunked_test.go
+@@ -239,3 +239,62 @@ func TestChunkEndReadError(t *testing.T) {
+ t.Errorf("expected %v, got %v", readErr, err)
+ }
+ }
++
++func TestChunkReaderTooMuchOverhead(t *testing.T) {
++ // If the sender is sending 100x as many chunk header bytes as chunk data,
++ // we should reject the stream at some point.
++ chunk := []byte("1;")
++ for i := 0; i < 100; i++ {
++ chunk = append(chunk, 'a') // chunk extension
++ }
++ chunk = append(chunk, "\r\nX\r\n"...)
++ const bodylen = 1 << 20
++ r := NewChunkedReader(&funcReader{f: func(i int) ([]byte, error) {
++ if i < bodylen {
++ return chunk, nil
++ }
++ return []byte("0\r\n"), nil
++ }})
++ _, err := io.ReadAll(r)
++ if err == nil {
++ t.Fatalf("successfully read body with excessive overhead; want error")
++ }
++}
++
++func TestChunkReaderByteAtATime(t *testing.T) {
++ // Sending one byte per chunk should not trip the excess-overhead detection.
++ const bodylen = 1 << 20
++ r := NewChunkedReader(&funcReader{f: func(i int) ([]byte, error) {
++ if i < bodylen {
++ return []byte("1\r\nX\r\n"), nil
++ }
++ return []byte("0\r\n"), nil
++ }})
++ got, err := io.ReadAll(r)
++ if err != nil {
++ t.Errorf("unexpected error: %v", err)
++ }
++ if len(got) != bodylen {
++ t.Errorf("read %v bytes, want %v", len(got), bodylen)
++ }
++}
++
++type funcReader struct {
++ f func(iteration int) ([]byte, error)
++ i int
++ b []byte
++ err error
++}
++
++func (r *funcReader) Read(p []byte) (n int, err error) {
++ if len(r.b) == 0 && r.err == nil {
++ r.b, r.err = r.f(r.i)
++ r.i++
++ }
++ n = copy(p, r.b)
++ r.b = r.b[n:]
++ if len(r.b) > 0 {
++ return n, nil
++ }
++ return n, r.err
++}
+--
+2.33.0
+
diff --git a/backport-0011-Backport-archive-zip-treat-truncated-EOCDR-comment-a.patch b/backport-0011-Backport-archive-zip-treat-truncated-EOCDR-comment-a.patch
new file mode 100644
index 0000000..55beba5
--- /dev/null
+++ b/backport-0011-Backport-archive-zip-treat-truncated-EOCDR-comment-a.patch
@@ -0,0 +1,58 @@
+From c69c5c62775d84aa56a43bedaa4fcacbb73d403d Mon Sep 17 00:00:00 2001
+From: Damien Neil <dneil@google.com>
+Date: Tue, 14 May 2024 14:39:10 -0700
+Subject: [PATCH] [Backport] archive/zip: treat truncated EOCDR comment as an
+ error
+
+CVE: CVE-2024-24789
+Reference: https://go-review.googlesource.com/c/go/+/588796
+
+When scanning for an end of central directory record,
+treat an EOCDR signature with a record containing a truncated
+comment as an error. Previously, we would skip over the invalid
+record and look for another one. Other implementations do not
+do this (they either consider this a hard error, or just ignore
+the truncated comment). This parser misalignment allowed
+presenting entirely different archive contents to Go programs
+and other zip decoders.
+
+For #66869
+Fixes #67554
+Fixes CVE-2024-24789
+
+Change-Id: I94e5cb028534bb5704588b8af27f1e22ea49c7c6
+Reviewed-on: https://go-review.googlesource.com/c/go/+/585397
+Reviewed-by: Joseph Tsai <joetsai@digital-static.net>
+Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
+LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
+(cherry picked from commit 33d725e5758bf1fea62e6c77fc70b57a828a49f5)
+Reviewed-on: https://go-review.googlesource.com/c/go/+/588796
+Reviewed-by: Matthew Dempsky <mdempsky@google.com>
+Signed-off-by: Ma Chang Wang machangwang@huawei.com
+---
+ src/archive/zip/reader.go | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/src/archive/zip/reader.go b/src/archive/zip/reader.go
+index 1fde1decc4..20356bde0e 100644
+--- a/src/archive/zip/reader.go
++++ b/src/archive/zip/reader.go
+@@ -699,9 +699,13 @@ func findSignatureInBlock(b []byte) int {
+ if b[i] == 'P' && b[i+1] == 'K' && b[i+2] == 0x05 && b[i+3] == 0x06 {
+ // n is length of comment
+ n := int(b[i+directoryEndLen-2]) | int(b[i+directoryEndLen-1])<<8
+- if n+directoryEndLen+i <= len(b) {
+- return i
++ if n+directoryEndLen+i > len(b) {
++ // Truncated comment.
++ // Some parsers (such as Info-ZIP) ignore the truncated comment
++ // rather than treating it as a hard error.
++ return -1
+ }
++ return i
+ }
+ }
+ return -1
+--
+2.33.0
+
diff --git a/backport-0012-net-http-send-body-or-close-connection-on-expect-100.patch b/backport-0012-net-http-send-body-or-close-connection-on-expect-100.patch
new file mode 100644
index 0000000..30501ff
--- /dev/null
+++ b/backport-0012-net-http-send-body-or-close-connection-on-expect-100.patch
@@ -0,0 +1,353 @@
+From c9be6ae748b7679b644a38182d456cb5a6ac06ee Mon Sep 17 00:00:00 2001
+From: Damien Neil <dneil@google.com>
+Date: Thu, 6 Jun 2024 12:50:46 -0700
+Subject: [PATCH] [release-branch.go1.21] net/http: send body or close
+ connection on expect-100-continue requests
+
+When sending a request with an "Expect: 100-continue" header,
+we must send the request body before sending any further requests
+on the connection.
+
+When receiving a non-1xx response to an "Expect: 100-continue" request,
+send the request body if the connection isn't being closed after
+processing the response. In other words, if either the request
+or response contains a "Connection: close" header, then skip sending
+the request body (because the connection will not be used for
+further requests), but otherwise send it.
+
+Correct a comment on the server-side Expect: 100-continue handling
+that implied sending the request body is optional. It isn't.
+
+For #67555
+Fixes #68199
+
+Change-Id: Ia2f12091bee697771087f32ac347509ec5922d54
+Reviewed-on: https://go-review.googlesource.com/c/go/+/591255
+LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
+Reviewed-by: Jonathan Amsterdam <jba@google.com>
+(cherry picked from commit cf501e05e138e6911f759a5db786e90b295499b9)
+Reviewed-on: https://go-review.googlesource.com/c/go/+/595096
+Reviewed-by: Joedian Reid <joedian@google.com>
+Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
+---
+ src/net/http/server.go | 25 ++--
+ src/net/http/transport.go | 34 ++++--
+ src/net/http/transport_test.go | 202 ++++++++++++++++++++-------------
+ 3 files changed, 164 insertions(+), 97 deletions(-)
+
+diff --git a/src/net/http/server.go b/src/net/http/server.go
+index 8f63a90299..111adb0ecd 100644
+--- a/src/net/http/server.go
++++ b/src/net/http/server.go
+@@ -1352,16 +1352,21 @@ func (cw *chunkWriter) writeHeader(p []byte) {
+
+ // If the client wanted a 100-continue but we never sent it to
+ // them (or, more strictly: we never finished reading their
+- // request body), don't reuse this connection because it's now
+- // in an unknown state: we might be sending this response at
+- // the same time the client is now sending its request body
+- // after a timeout. (Some HTTP clients send Expect:
+- // 100-continue but knowing that some servers don't support
+- // it, the clients set a timer and send the body later anyway)
+- // If we haven't seen EOF, we can't skip over the unread body
+- // because we don't know if the next bytes on the wire will be
+- // the body-following-the-timer or the subsequent request.
+- // See Issue 11549.
++ // request body), don't reuse this connection.
++ //
++ // This behavior was first added on the theory that we don't know
++ // if the next bytes on the wire are going to be the remainder of
++ // the request body or the subsequent request (see issue 11549),
++ // but that's not correct: If we keep using the connection,
++ // the client is required to send the request body whether we
++ // asked for it or not.
++ //
++ // We probably do want to skip reusing the connection in most cases,
++ // however. If the client is offering a large request body that we
++ // don't intend to use, then it's better to close the connection
++ // than to read the body. For now, assume that if we're sending
++ // headers, the handler is done reading the body and we should
++ // drop the connection if we haven't seen EOF.
+ if ecr, ok := w.req.Body.(*expectContinueReader); ok && !ecr.sawEOF.Load() {
+ w.closeAfterReply = true
+ }
+diff --git a/src/net/http/transport.go b/src/net/http/transport.go
+index c07352b018..30bce98736 100644
+--- a/src/net/http/transport.go
++++ b/src/net/http/transport.go
+@@ -2313,17 +2313,12 @@ func (pc *persistConn) readResponse(rc requestAndChan, trace *httptrace.ClientTr
+ return
+ }
+ resCode := resp.StatusCode
+- if continueCh != nil {
+- if resCode == 100 {
+- if trace != nil && trace.Got100Continue != nil {
+- trace.Got100Continue()
+- }
+- continueCh <- struct{}{}
+- continueCh = nil
+- } else if resCode >= 200 {
+- close(continueCh)
+- continueCh = nil
++ if continueCh != nil && resCode == StatusContinue {
++ if trace != nil && trace.Got100Continue != nil {
++ trace.Got100Continue()
+ }
++ continueCh <- struct{}{}
++ continueCh = nil
+ }
+ is1xx := 100 <= resCode && resCode <= 199
+ // treat 101 as a terminal status, see issue 26161
+@@ -2346,6 +2341,25 @@ func (pc *persistConn) readResponse(rc requestAndChan, trace *httptrace.ClientTr
+ if resp.isProtocolSwitch() {
+ resp.Body = newReadWriteCloserBody(pc.br, pc.conn)
+ }
++ if continueCh != nil {
++ // We send an "Expect: 100-continue" header, but the server
++ // responded with a terminal status and no 100 Continue.
++ //
++ // If we're going to keep using the connection, we need to send the request body.
++ // Tell writeLoop to skip sending the body if we're going to close the connection,
++ // or to send it otherwise.
++ //
++ // The case where we receive a 101 Switching Protocols response is a bit
++ // ambiguous, since we don't know what protocol we're switching to.
++ // Conceivably, it's one that doesn't need us to send the body.
++ // Given that we'll send the body if ExpectContinueTimeout expires,
++ // be consistent and always send it if we aren't closing the connection.
++ if resp.Close || rc.req.Close {
++ close(continueCh) // don't send the body; the connection will close
++ } else {
++ continueCh <- struct{}{} // send the body
++ }
++ }
+
+ resp.TLS = pc.tlsState
+ return
+diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go
+index 028fecc961..b8c930ab8f 100644
+--- a/src/net/http/transport_test.go
++++ b/src/net/http/transport_test.go
+@@ -1135,94 +1135,142 @@ func testTransportGzip(t *testing.T, mode testMode) {
+ }
+ }
+
+-// If a request has Expect:100-continue header, the request blocks sending body until the first response.
+-// Premature consumption of the request body should not be occurred.
+-func TestTransportExpect100Continue(t *testing.T) {
+- run(t, testTransportExpect100Continue, []testMode{http1Mode})
++// A transport100Continue test exercises Transport behaviors when sending a
++// request with an Expect: 100-continue header.
++type transport100ContinueTest struct {
++ t *testing.T
++
++ reqdone chan struct{}
++ resp *Response
++ respErr error
++
++ conn net.Conn
++ reader *bufio.Reader
+ }
+-func testTransportExpect100Continue(t *testing.T, mode testMode) {
+- ts := newClientServerTest(t, mode, HandlerFunc(func(rw ResponseWriter, req *Request) {
+- switch req.URL.Path {
+- case "/100":
+- // This endpoint implicitly responds 100 Continue and reads body.
+- if _, err := io.Copy(io.Discard, req.Body); err != nil {
+- t.Error("Failed to read Body", err)
+- }
+- rw.WriteHeader(StatusOK)
+- case "/200":
+- // Go 1.5 adds Connection: close header if the client expect
+- // continue but not entire request body is consumed.
+- rw.WriteHeader(StatusOK)
+- case "/500":
+- rw.WriteHeader(StatusInternalServerError)
+- case "/keepalive":
+- // This hijacked endpoint responds error without Connection:close.
+- _, bufrw, err := rw.(Hijacker).Hijack()
+- if err != nil {
+- log.Fatal(err)
+- }
+- bufrw.WriteString("HTTP/1.1 500 Internal Server Error\r\n")
+- bufrw.WriteString("Content-Length: 0\r\n\r\n")
+- bufrw.Flush()
+- case "/timeout":
+- // This endpoint tries to read body without 100 (Continue) response.
+- // After ExpectContinueTimeout, the reading will be started.
+- conn, bufrw, err := rw.(Hijacker).Hijack()
+- if err != nil {
+- log.Fatal(err)
+- }
+- if _, err := io.CopyN(io.Discard, bufrw, req.ContentLength); err != nil {
+- t.Error("Failed to read Body", err)
+- }
+- bufrw.WriteString("HTTP/1.1 200 OK\r\n\r\n")
+- bufrw.Flush()
+- conn.Close()
+- }
+
+- })).ts
++const transport100ContinueTestBody = "request body"
+
+- tests := []struct {
+- path string
+- body []byte
+- sent int
+- status int
+- }{
+- {path: "/100", body: []byte("hello"), sent: 5, status: 200}, // Got 100 followed by 200, entire body is sent.
+- {path: "/200", body: []byte("hello"), sent: 0, status: 200}, // Got 200 without 100. body isn't sent.
+- {path: "/500", body: []byte("hello"), sent: 0, status: 500}, // Got 500 without 100. body isn't sent.
+- {path: "/keepalive", body: []byte("hello"), sent: 0, status: 500}, // Although without Connection:close, body isn't sent.
+- {path: "/timeout", body: []byte("hello"), sent: 5, status: 200}, // Timeout exceeded and entire body is sent.
++// newTransport100ContinueTest creates a Transport and sends an Expect: 100-continue
++// request on it.
++func newTransport100ContinueTest(t *testing.T, timeout time.Duration) *transport100ContinueTest {
++ ln := newLocalListener(t)
++ defer ln.Close()
++
++ test := &transport100ContinueTest{
++ t: t,
++ reqdone: make(chan struct{}),
+ }
+
+- c := ts.Client()
+- for i, v := range tests {
+- tr := &Transport{
+- ExpectContinueTimeout: 2 * time.Second,
+- }
+- defer tr.CloseIdleConnections()
+- c.Transport = tr
+- body := bytes.NewReader(v.body)
+- req, err := NewRequest("PUT", ts.URL+v.path, body)
+- if err != nil {
+- t.Fatal(err)
+- }
++ tr := &Transport{
++ ExpectContinueTimeout: timeout,
++ }
++ go func() {
++ defer close(test.reqdone)
++ body := strings.NewReader(transport100ContinueTestBody)
++ req, _ := NewRequest("PUT", "http://"+ln.Addr().String(), body)
+ req.Header.Set("Expect", "100-continue")
+- req.ContentLength = int64(len(v.body))
++ req.ContentLength = int64(len(transport100ContinueTestBody))
++ test.resp, test.respErr = tr.RoundTrip(req)
++ test.resp.Body.Close()
++ }()
+
+- resp, err := c.Do(req)
+- if err != nil {
+- t.Fatal(err)
++ c, err := ln.Accept()
++ if err != nil {
++ t.Fatalf("Accept: %v", err)
++ }
++ t.Cleanup(func() {
++ c.Close()
++ })
++ br := bufio.NewReader(c)
++ _, err = ReadRequest(br)
++ if err != nil {
++ t.Fatalf("ReadRequest: %v", err)
++ }
++ test.conn = c
++ test.reader = br
++ t.Cleanup(func() {
++ <-test.reqdone
++ tr.CloseIdleConnections()
++ got, _ := io.ReadAll(test.reader)
++ if len(got) > 0 {
++ t.Fatalf("Transport sent unexpected bytes: %q", got)
+ }
+- resp.Body.Close()
++ })
+
+- sent := len(v.body) - body.Len()
+- if v.status != resp.StatusCode {
+- t.Errorf("test %d: status code should be %d but got %d. (%s)", i, v.status, resp.StatusCode, v.path)
+- }
+- if v.sent != sent {
+- t.Errorf("test %d: sent body should be %d but sent %d. (%s)", i, v.sent, sent, v.path)
++ return test
++}
++
++// respond sends response lines from the server to the transport.
++func (test *transport100ContinueTest) respond(lines ...string) {
++ for _, line := range lines {
++ if _, err := test.conn.Write([]byte(line + "\r\n")); err != nil {
++ test.t.Fatalf("Write: %v", err)
+ }
+ }
++ if _, err := test.conn.Write([]byte("\r\n")); err != nil {
++ test.t.Fatalf("Write: %v", err)
++ }
++}
++
++// wantBodySent ensures the transport has sent the request body to the server.
++func (test *transport100ContinueTest) wantBodySent() {
++ got, err := io.ReadAll(io.LimitReader(test.reader, int64(len(transport100ContinueTestBody))))
++ if err != nil {
++ test.t.Fatalf("unexpected error reading body: %v", err)
++ }
++ if got, want := string(got), transport100ContinueTestBody; got != want {
++ test.t.Fatalf("unexpected body: got %q, want %q", got, want)
++ }
++}
++
++// wantRequestDone ensures the Transport.RoundTrip has completed with the expected status.
++func (test *transport100ContinueTest) wantRequestDone(want int) {
++ <-test.reqdone
++ if test.respErr != nil {
++ test.t.Fatalf("unexpected RoundTrip error: %v", test.respErr)
++ }
++ if got := test.resp.StatusCode; got != want {
++ test.t.Fatalf("unexpected response code: got %v, want %v", got, want)
++ }
++}
++
++func TestTransportExpect100ContinueSent(t *testing.T) {
++ test := newTransport100ContinueTest(t, 1*time.Hour)
++ // Server sends a 100 Continue response, and the client sends the request body.
++ test.respond("HTTP/1.1 100 Continue")
++ test.wantBodySent()
++ test.respond("HTTP/1.1 200", "Content-Length: 0")
++ test.wantRequestDone(200)
++}
++
++func TestTransportExpect100Continue200ResponseNoConnClose(t *testing.T) {
++ test := newTransport100ContinueTest(t, 1*time.Hour)
++ // No 100 Continue response, no Connection: close header.
++ test.respond("HTTP/1.1 200", "Content-Length: 0")
++ test.wantBodySent()
++ test.wantRequestDone(200)
++}
++
++func TestTransportExpect100Continue200ResponseWithConnClose(t *testing.T) {
++ test := newTransport100ContinueTest(t, 1*time.Hour)
++ // No 100 Continue response, Connection: close header set.
++ test.respond("HTTP/1.1 200", "Connection: close", "Content-Length: 0")
++ test.wantRequestDone(200)
++}
++
++func TestTransportExpect100Continue500ResponseNoConnClose(t *testing.T) {
++ test := newTransport100ContinueTest(t, 1*time.Hour)
++ // No 100 Continue response, no Connection: close header.
++ test.respond("HTTP/1.1 500", "Content-Length: 0")
++ test.wantBodySent()
++ test.wantRequestDone(500)
++}
++
++func TestTransportExpect100Continue500ResponseTimeout(t *testing.T) {
++ test := newTransport100ContinueTest(t, 5*time.Millisecond) // short timeout
++ test.wantBodySent() // after timeout
++ test.respond("HTTP/1.1 200", "Content-Length: 0")
++ test.wantRequestDone(200)
+ }
+
+ func TestSOCKS5Proxy(t *testing.T) {
+--
+2.41.0
+
diff --git a/backport-0013-release-branch.go1.21-net-http-update-bundled-golang.patch b/backport-0013-release-branch.go1.21-net-http-update-bundled-golang.patch
new file mode 100644
index 0000000..e6db274
--- /dev/null
+++ b/backport-0013-release-branch.go1.21-net-http-update-bundled-golang.patch
@@ -0,0 +1,98 @@
+From 0574d64ad35b51eb770d6cb59b46c9b3d8540999 Mon Sep 17 00:00:00 2001
+From: Dmitri Shuralyov <dmitshur@golang.org>
+Date: Fri, 12 Apr 2024 15:46:59 -0400
+Subject: [PATCH] [release-branch.go1.21] net/http: update bundled
+ golang.org/x/net/http2
+
+Reference:https://go-review.googlesource.com/c/go/+/578357
+Conflict:NA
+Pull in CL 578336:
+
+ ef58d90f http2: send correct LastStreamID in stream-caused GOAWAY
+
+For #66668.
+Fixes #66697.
+
+Change-Id: I91fc8a67f21fadcb1801ff29d5e2b0453db89617
+Reviewed-on: https://go-review.googlesource.com/c/go/+/578357
+Reviewed-by: Carlos Amedee <carlos@golang.org>
+Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
+LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
+---
+ src/net/http/h2_bundle.go | 22 +++++++++++++++-------
+ 1 file changed, 15 insertions(+), 7 deletions(-)
+
+diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go
+index cd95f84269..5ad0c2819b 100644
+--- a/src/net/http/h2_bundle.go
++++ b/src/net/http/h2_bundle.go
+@@ -1891,6 +1891,9 @@ func http2terminalReadFrameError(err error) bool {
+ // returned error is ErrFrameTooLarge. Other errors may be of type
+ // ConnectionError, StreamError, or anything else from the underlying
+ // reader.
++//
++// If ReadFrame returns an error and a non-nil Frame, the Frame's StreamID
++// indicates the stream responsible for the error.
+ func (fr *http2Framer) ReadFrame() (http2Frame, error) {
+ fr.errDetail = nil
+ if fr.lastFrame != nil {
+@@ -2923,7 +2926,7 @@ func (fr *http2Framer) maxHeaderStringLen() int {
+ // readMetaFrame returns 0 or more CONTINUATION frames from fr and
+ // merge them into the provided hf and returns a MetaHeadersFrame
+ // with the decoded hpack values.
+-func (fr *http2Framer) readMetaFrame(hf *http2HeadersFrame) (*http2MetaHeadersFrame, error) {
++func (fr *http2Framer) readMetaFrame(hf *http2HeadersFrame) (http2Frame, error) {
+ if fr.AllowIllegalReads {
+ return nil, errors.New("illegal use of AllowIllegalReads with ReadMetaHeaders")
+ }
+@@ -2993,8 +2996,8 @@ func (fr *http2Framer) readMetaFrame(hf *http2HeadersFrame) (*http2MetaHeadersFr
+ log.Printf("http2: header list too large")
+ }
+ // It would be nice to send a RST_STREAM before sending the GOAWAY,
+- // but the struture of the server's frame writer makes this difficult.
+- return nil, http2ConnectionError(http2ErrCodeProtocol)
++ // but the structure of the server's frame writer makes this difficult.
++ return mh, http2ConnectionError(http2ErrCodeProtocol)
+ }
+
+ // Also close the connection after any CONTINUATION frame following an
+@@ -3005,12 +3008,12 @@ func (fr *http2Framer) readMetaFrame(hf *http2HeadersFrame) (*http2MetaHeadersFr
+ log.Printf("http2: invalid header: %v", invalid)
+ }
+ // It would be nice to send a RST_STREAM before sending the GOAWAY,
+- // but the struture of the server's frame writer makes this difficult.
+- return nil, http2ConnectionError(http2ErrCodeProtocol)
++ // but the structure of the server's frame writer makes this difficult.
++ return mh, http2ConnectionError(http2ErrCodeProtocol)
+ }
+
+ if _, err := hdec.Write(frag); err != nil {
+- return nil, http2ConnectionError(http2ErrCodeCompression)
++ return mh, http2ConnectionError(http2ErrCodeCompression)
+ }
+
+ if hc.HeadersEnded() {
+@@ -3027,7 +3030,7 @@ func (fr *http2Framer) readMetaFrame(hf *http2HeadersFrame) (*http2MetaHeadersFr
+ mh.http2HeadersFrame.invalidate()
+
+ if err := hdec.Close(); err != nil {
+- return nil, http2ConnectionError(http2ErrCodeCompression)
++ return mh, http2ConnectionError(http2ErrCodeCompression)
+ }
+ if invalid != nil {
+ fr.errDetail = invalid
+@@ -5337,6 +5340,11 @@ func (sc *http2serverConn) processFrameFromReader(res http2readFrameResult) bool
+ sc.goAway(http2ErrCodeFlowControl)
+ return true
+ case http2ConnectionError:
++ if res.f != nil {
++ if id := res.f.Header().StreamID; id > sc.maxClientStreamID {
++ sc.maxClientStreamID = id
++ }
++ }
+ sc.logf("http2: server connection error from %v: %v", sc.conn.RemoteAddr(), ev)
+ sc.goAway(http2ErrCode(ev))
+ return true // goAway will handle shutdown
+--
+2.33.0
+
diff --git a/backport-0014-cmd-compile-handle-constant-pointer-offsets-in-dead-.patch b/backport-0014-cmd-compile-handle-constant-pointer-offsets-in-dead-.patch
new file mode 100644
index 0000000..80c9bbc
--- /dev/null
+++ b/backport-0014-cmd-compile-handle-constant-pointer-offsets-in-dead-.patch
@@ -0,0 +1,143 @@
+From 131f773664fa2d0dbc870e11c388a3131a3a2029 Mon Sep 17 00:00:00 2001
+From: Keith Randall <khr@golang.org>
+Date: Sun, 29 Oct 2023 21:00:29 -0700
+Subject: cmd/compile: handle constant pointer offsets in dead store elimination
+
+Conflict:NA
+Reference:https://go-review.googlesource.com/c/go/+/538595
+
+Update #63657
+Update #45573
+
+Change-Id: I163c6038c13d974dc0ca9f02144472bc05331826
+Reviewed-on: https://go-review.googlesource.com/c/go/+/538595
+LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
+Reviewed-by: David Chase <drchase@google.com>
+Reviewed-by: Keith Randall <khr@google.com>
+---
+ src/cmd/compile/internal/ssa/deadstore.go | 64 ++++++++++++++++++++---
+ src/cmd/compile/internal/ssa/rewrite.go | 6 +++
+ 2 files changed, 62 insertions(+), 8 deletions(-)
+
+diff --git a/src/cmd/compile/internal/ssa/deadstore.go b/src/cmd/compile/internal/ssa/deadstore.go
+index 648b68af78b1..7656e45cb9d5 100644
+--- a/src/cmd/compile/internal/ssa/deadstore.go
++++ b/src/cmd/compile/internal/ssa/deadstore.go
+@@ -73,9 +73,9 @@ func dse(f *Func) {
+ }
+
+ // Walk backwards looking for dead stores. Keep track of shadowed addresses.
+- // A "shadowed address" is a pointer and a size describing a memory region that
+- // is known to be written. We keep track of shadowed addresses in the shadowed
+- // map, mapping the ID of the address to the size of the shadowed region.
++ // A "shadowed address" is a pointer, offset, and size describing a memory region that
++ // is known to be written. We keep track of shadowed addresses in the shadowed map,
++ // mapping the ID of the address to a shadowRange where future writes will happen.
+ // Since we're walking backwards, writes to a shadowed region are useless,
+ // as they will be immediately overwritten.
+ shadowed.clear()
+@@ -88,13 +88,20 @@ func dse(f *Func) {
+ shadowed.clear()
+ }
+ if v.Op == OpStore || v.Op == OpZero {
++ ptr := v.Args[0]
++ var off int64
++ for ptr.Op == OpOffPtr { // Walk to base pointer
++ off += ptr.AuxInt
++ ptr = ptr.Args[0]
++ }
+ var sz int64
+ if v.Op == OpStore {
+ sz = v.Aux.(*types.Type).Size()
+ } else { // OpZero
+ sz = v.AuxInt
+ }
+- if shadowedSize := int64(shadowed.get(v.Args[0].ID)); shadowedSize != -1 && shadowedSize >= sz {
++ sr := shadowRange(shadowed.get(ptr.ID))
++ if sr.contains(off, off+sz) {
+ // Modify the store/zero into a copy of the memory state,
+ // effectively eliding the store operation.
+ if v.Op == OpStore {
+@@ -108,10 +115,8 @@ func dse(f *Func) {
+ v.AuxInt = 0
+ v.Op = OpCopy
+ } else {
+- if sz > 0x7fffffff { // work around sparseMap's int32 value type
+- sz = 0x7fffffff
+- }
+- shadowed.set(v.Args[0].ID, int32(sz))
++ // Extend shadowed region.
++ shadowed.set(ptr.ID, int32(sr.merge(off, off+sz)))
+ }
+ }
+ // walk to previous store
+@@ -131,6 +136,49 @@ func dse(f *Func) {
+ }
+ }
+
++// A shadowRange encodes a set of byte offsets [lo():hi()] from
++// a given pointer that will be written to later in the block.
++// A zero shadowRange encodes an empty shadowed range (and so
++// does a -1 shadowRange, which is what sparsemap.get returns
++// on a failed lookup).
++type shadowRange int32
++
++func (sr shadowRange) lo() int64 {
++ return int64(sr & 0xffff)
++}
++func (sr shadowRange) hi() int64 {
++ return int64((sr >> 16) & 0xffff)
++}
++
++// contains reports whether [lo:hi] is completely within sr.
++func (sr shadowRange) contains(lo, hi int64) bool {
++ return lo >= sr.lo() && hi <= sr.hi()
++}
++
++// merge returns the union of sr and [lo:hi].
++// merge is allowed to return something smaller than the union.
++func (sr shadowRange) merge(lo, hi int64) shadowRange {
++ if lo < 0 || hi > 0xffff {
++ // Ignore offsets that are too large or small.
++ return sr
++ }
++ if sr.lo() == sr.hi() {
++ // Old range is empty - use new one.
++ return shadowRange(lo + hi<<16)
++ }
++ if hi < sr.lo() || lo > sr.hi() {
++ // The two regions don't overlap or abut, so we would
++ // have to keep track of multiple disjoint ranges.
++ // Because we can only keep one, keep the larger one.
++ if sr.hi()-sr.lo() >= hi-lo {
++ return sr
++ }
++ return shadowRange(lo + hi<<16)
++ }
++ // Regions overlap or abut - compute the union.
++ return shadowRange(min(lo, sr.lo()) + max(hi, sr.hi())<<16)
++}
++
+ // elimDeadAutosGeneric deletes autos that are never accessed. To achieve this
+ // we track the operations that the address of each auto reaches and if it only
+ // reaches stores then we delete all the stores. The other operations will then
+diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go
+index 43843bda5536..5c7ed16f12be 100644
+--- a/src/cmd/compile/internal/ssa/rewrite.go
++++ b/src/cmd/compile/internal/ssa/rewrite.go
+@@ -1183,6 +1183,12 @@ func min(x, y int64) int64 {
+ }
+ return y
+ }
++func max(x, y int64) int64 {
++ if x > y {
++ return x
++ }
++ return y
++}
+
+ func isConstZero(v *Value) bool {
+ switch v.Op {
+--
+2.33.0
+
diff --git a/backport-0015-release-branch.go1.21-cmd-compile-ensure-pointer-ari.patch b/backport-0015-release-branch.go1.21-cmd-compile-ensure-pointer-ari.patch
new file mode 100644
index 0000000..19223d4
--- /dev/null
+++ b/backport-0015-release-branch.go1.21-cmd-compile-ensure-pointer-ari.patch
@@ -0,0 +1,650 @@
+From 8aa0b89560d65438d18fb8ed5ea90d7db2e18fa0 Mon Sep 17 00:00:00 2001
+From: Keith Randall <khr@golang.org>
+Date: Wed, 25 Oct 2023 13:35:13 -0700
+Subject: [release-branch.go1.21] cmd/compile: ensure pointer arithmetic
+ happens after the nil check
+
+Conflict:NA
+Reference:https://go-review.googlesource.com/c/go/+/537775
+
+Have nil checks return a pointer that is known non-nil. Users of
+that pointer can use the result, ensuring that they are ordered
+after the nil check itself.
+
+The order dependence goes away after scheduling, when we've fixed
+an order. At that point we move uses back to the original pointer
+so it doesn't change regalloc any.
+
+This prevents pointer arithmetic on nil from being spilled to the
+stack and then observed by a stack scan.
+
+Fixes #63743
+
+Change-Id: I1a5fa4f2e6d9000d672792b4f90dfc1b7b67f6ea
+Reviewed-on: https://go-review.googlesource.com/c/go/+/537775
+Reviewed-by: David Chase <drchase@google.com>
+LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
+Reviewed-by: Keith Randall <khr@google.com>
+(cherry picked from commit 962ccbef91057f91518443b648e02fc3afe8c764)
+Reviewed-on: https://go-review.googlesource.com/c/go/+/538717
+Auto-Submit: Heschi Kreinick <heschi@google.com>
+Reviewed-by: Heschi Kreinick <heschi@google.com>
+---
+ .../compile/internal/ssa/_gen/generic.rules | 14 ++--
+ .../compile/internal/ssa/_gen/genericOps.go | 2 +-
+ src/cmd/compile/internal/ssa/check.go | 23 ++++++-
+ src/cmd/compile/internal/ssa/deadcode.go | 7 +-
+ src/cmd/compile/internal/ssa/deadstore.go | 2 +-
+ src/cmd/compile/internal/ssa/fuse.go | 2 +-
+ src/cmd/compile/internal/ssa/fuse_test.go | 2 +-
+ src/cmd/compile/internal/ssa/nilcheck.go | 42 ++++++------
+ src/cmd/compile/internal/ssa/opGen.go | 7 +-
+ src/cmd/compile/internal/ssa/rewrite.go | 3 +
+ .../compile/internal/ssa/rewritegeneric.go | 67 ++++++++++---------
+ src/cmd/compile/internal/ssa/schedule.go | 18 ++++-
+ src/cmd/compile/internal/ssa/value.go | 6 +-
+ src/cmd/compile/internal/ssagen/ssa.go | 17 +++--
+ test/fixedbugs/issue63657.go | 48 +++++++++++++
+ 15 files changed, 179 insertions(+), 81 deletions(-)
+ create mode 100644 test/fixedbugs/issue63657.go
+
+diff --git a/src/cmd/compile/internal/ssa/_gen/generic.rules b/src/cmd/compile/internal/ssa/_gen/generic.rules
+index cdb346321e56..d3af465d0e0d 100644
+--- a/src/cmd/compile/internal/ssa/_gen/generic.rules
++++ b/src/cmd/compile/internal/ssa/_gen/generic.rules
+@@ -981,7 +981,7 @@
+ (ConstNil <typ.Uintptr>)
+ (ConstNil <typ.BytePtr>))
+
+-(NilCheck (GetG mem) mem) => mem
++(NilCheck ptr:(GetG mem) mem) => ptr
+
+ (If (Not cond) yes no) => (If cond no yes)
+ (If (ConstBool [c]) yes no) && c => (First yes no)
+@@ -2055,19 +2055,19 @@
+ && isSameCall(call.Aux, "runtime.newobject")
+ => mem
+
+-(NilCheck (SelectN [0] call:(StaticLECall _ _)) _)
++(NilCheck ptr:(SelectN [0] call:(StaticLECall _ _)) _)
+ && isSameCall(call.Aux, "runtime.newobject")
+ && warnRule(fe.Debug_checknil(), v, "removed nil check")
+- => (Invalid)
++ => ptr
+
+-(NilCheck (OffPtr (SelectN [0] call:(StaticLECall _ _))) _)
++(NilCheck ptr:(OffPtr (SelectN [0] call:(StaticLECall _ _))) _)
+ && isSameCall(call.Aux, "runtime.newobject")
+ && warnRule(fe.Debug_checknil(), v, "removed nil check")
+- => (Invalid)
++ => ptr
+
+ // Addresses of globals are always non-nil.
+-(NilCheck (Addr {_} (SB)) _) => (Invalid)
+-(NilCheck (Convert (Addr {_} (SB)) _) _) => (Invalid)
++(NilCheck ptr:(Addr {_} (SB)) _) => ptr
++(NilCheck ptr:(Convert (Addr {_} (SB)) _) _) => ptr
+
+ // for late-expanded calls, recognize memequal applied to a single constant byte
+ // Support is limited by 1, 2, 4, 8 byte sizes
+diff --git a/src/cmd/compile/internal/ssa/_gen/genericOps.go b/src/cmd/compile/internal/ssa/_gen/genericOps.go
+index 53ff57f6b12e..aa5fb0e03e66 100644
+--- a/src/cmd/compile/internal/ssa/_gen/genericOps.go
++++ b/src/cmd/compile/internal/ssa/_gen/genericOps.go
+@@ -471,7 +471,7 @@ var genericOps = []opData{
+ {name: "IsNonNil", argLength: 1, typ: "Bool"}, // arg0 != nil
+ {name: "IsInBounds", argLength: 2, typ: "Bool"}, // 0 <= arg0 < arg1. arg1 is guaranteed >= 0.
+ {name: "IsSliceInBounds", argLength: 2, typ: "Bool"}, // 0 <= arg0 <= arg1. arg1 is guaranteed >= 0.
+- {name: "NilCheck", argLength: 2, typ: "Void"}, // arg0=ptr, arg1=mem. Panics if arg0 is nil. Returns void.
++ {name: "NilCheck", argLength: 2, nilCheck: true}, // arg0=ptr, arg1=mem. Panics if arg0 is nil. Returns the ptr unmodified.
+
+ // Pseudo-ops
+ {name: "GetG", argLength: 1, zeroWidth: true}, // runtime.getg() (read g pointer). arg0=mem
+diff --git a/src/cmd/compile/internal/ssa/check.go b/src/cmd/compile/internal/ssa/check.go
+index f34b9074197b..bbfdaceaad90 100644
+--- a/src/cmd/compile/internal/ssa/check.go
++++ b/src/cmd/compile/internal/ssa/check.go
+@@ -317,7 +317,28 @@ func checkFunc(f *Func) {
+ if !v.Aux.(*ir.Name).Type().HasPointers() {
+ f.Fatalf("vardef must have pointer type %s", v.Aux.(*ir.Name).Type().String())
+ }
+-
++ case OpNilCheck:
++ // nil checks have pointer type before scheduling, and
++ // void type after scheduling.
++ if f.scheduled {
++ if v.Uses != 0 {
++ f.Fatalf("nilcheck must have 0 uses %s", v.Uses)
++ }
++ if !v.Type.IsVoid() {
++ f.Fatalf("nilcheck must have void type %s", v.Type.String())
++ }
++ } else {
++ if !v.Type.IsPtrShaped() && !v.Type.IsUintptr() {
++ f.Fatalf("nilcheck must have pointer type %s", v.Type.String())
++ }
++ }
++ if !v.Args[0].Type.IsPtrShaped() && !v.Args[0].Type.IsUintptr() {
++ f.Fatalf("nilcheck must have argument of pointer type %s", v.Args[0].Type.String())
++ }
++ if !v.Args[1].Type.IsMemory() {
++ f.Fatalf("bad arg 1 type to %s: want mem, have %s",
++ v.Op, v.Args[1].Type.String())
++ }
+ }
+
+ // TODO: check for cycles in values
+diff --git a/src/cmd/compile/internal/ssa/deadcode.go b/src/cmd/compile/internal/ssa/deadcode.go
+index 52cc7f2ca74d..ae9fd2ef2426 100644
+--- a/src/cmd/compile/internal/ssa/deadcode.go
++++ b/src/cmd/compile/internal/ssa/deadcode.go
+@@ -110,16 +110,15 @@ func liveValues(f *Func, reachable []bool) (live []bool, liveOrderStmts []*Value
+ }
+ }
+ for _, v := range b.Values {
+- if (opcodeTable[v.Op].call || opcodeTable[v.Op].hasSideEffects) && !live[v.ID] {
++ if (opcodeTable[v.Op].call || opcodeTable[v.Op].hasSideEffects || opcodeTable[v.Op].nilCheck) && !live[v.ID] {
+ live[v.ID] = true
+ q = append(q, v)
+ if v.Pos.IsStmt() != src.PosNotStmt {
+ liveOrderStmts = append(liveOrderStmts, v)
+ }
+ }
+- if v.Type.IsVoid() && !live[v.ID] {
+- // The only Void ops are nil checks and inline marks. We must keep these.
+- if v.Op == OpInlMark && !liveInlIdx[int(v.AuxInt)] {
++ if v.Op == OpInlMark {
++ if !liveInlIdx[int(v.AuxInt)] {
+ // We don't need marks for bodies that
+ // have been completely optimized away.
+ // TODO: save marks only for bodies which
+diff --git a/src/cmd/compile/internal/ssa/deadstore.go b/src/cmd/compile/internal/ssa/deadstore.go
+index 7656e45cb9d5..cb3427103c50 100644
+--- a/src/cmd/compile/internal/ssa/deadstore.go
++++ b/src/cmd/compile/internal/ssa/deadstore.go
+@@ -249,7 +249,7 @@ func elimDeadAutosGeneric(f *Func) {
+ }
+
+ if v.Uses == 0 && v.Op != OpNilCheck && !v.Op.IsCall() && !v.Op.HasSideEffects() || len(args) == 0 {
+- // Nil check has no use, but we need to keep it.
++ // We need to keep nil checks even if they have no use.
+ // Also keep calls and values that have side effects.
+ return
+ }
+diff --git a/src/cmd/compile/internal/ssa/fuse.go b/src/cmd/compile/internal/ssa/fuse.go
+index 6d3fb7078059..68defde7b4b9 100644
+--- a/src/cmd/compile/internal/ssa/fuse.go
++++ b/src/cmd/compile/internal/ssa/fuse.go
+@@ -169,7 +169,7 @@ func fuseBlockIf(b *Block) bool {
+ // There may be false positives.
+ func isEmpty(b *Block) bool {
+ for _, v := range b.Values {
+- if v.Uses > 0 || v.Op.IsCall() || v.Op.HasSideEffects() || v.Type.IsVoid() {
++ if v.Uses > 0 || v.Op.IsCall() || v.Op.HasSideEffects() || v.Type.IsVoid() || opcodeTable[v.Op].nilCheck {
+ return false
+ }
+ }
+diff --git a/src/cmd/compile/internal/ssa/fuse_test.go b/src/cmd/compile/internal/ssa/fuse_test.go
+index fa7921a18f6f..2f89938d1d92 100644
+--- a/src/cmd/compile/internal/ssa/fuse_test.go
++++ b/src/cmd/compile/internal/ssa/fuse_test.go
+@@ -254,7 +254,7 @@ func TestFuseSideEffects(t *testing.T) {
+ Valu("p", OpArg, c.config.Types.IntPtr, 0, nil),
+ If("c1", "z0", "exit")),
+ Bloc("z0",
+- Valu("nilcheck", OpNilCheck, types.TypeVoid, 0, nil, "p", "mem"),
++ Valu("nilcheck", OpNilCheck, c.config.Types.IntPtr, 0, nil, "p", "mem"),
+ Goto("exit")),
+ Bloc("exit",
+ Exit("mem"),
+diff --git a/src/cmd/compile/internal/ssa/nilcheck.go b/src/cmd/compile/internal/ssa/nilcheck.go
+index 4f797a473f71..c69cd8c32ed3 100644
+--- a/src/cmd/compile/internal/ssa/nilcheck.go
++++ b/src/cmd/compile/internal/ssa/nilcheck.go
+@@ -38,11 +38,14 @@ func nilcheckelim(f *Func) {
+ work := make([]bp, 0, 256)
+ work = append(work, bp{block: f.Entry})
+
+- // map from value ID to bool indicating if value is known to be non-nil
+- // in the current dominator path being walked. This slice is updated by
++ // map from value ID to known non-nil version of that value ID
++ // (in the current dominator path being walked). This slice is updated by
+ // walkStates to maintain the known non-nil values.
+- nonNilValues := f.Cache.allocBoolSlice(f.NumValues())
+- defer f.Cache.freeBoolSlice(nonNilValues)
++ // If there is extrinsic information about non-nil-ness, this map
++ // points a value to itself. If a value is known non-nil because we
++ // already did a nil check on it, it points to the nil check operation.
++ nonNilValues := f.Cache.allocValueSlice(f.NumValues())
++ defer f.Cache.freeValueSlice(nonNilValues)
+
+ // make an initial pass identifying any non-nil values
+ for _, b := range f.Blocks {
+@@ -54,7 +57,7 @@ func nilcheckelim(f *Func) {
+ // We assume that SlicePtr is non-nil because we do a bounds check
+ // before the slice access (and all cap>0 slices have a non-nil ptr). See #30366.
+ if v.Op == OpAddr || v.Op == OpLocalAddr || v.Op == OpAddPtr || v.Op == OpOffPtr || v.Op == OpAdd32 || v.Op == OpAdd64 || v.Op == OpSub32 || v.Op == OpSub64 || v.Op == OpSlicePtr {
+- nonNilValues[v.ID] = true
++ nonNilValues[v.ID] = v
+ }
+ }
+ }
+@@ -68,16 +71,16 @@ func nilcheckelim(f *Func) {
+ if v.Op == OpPhi {
+ argsNonNil := true
+ for _, a := range v.Args {
+- if !nonNilValues[a.ID] {
++ if nonNilValues[a.ID] == nil {
+ argsNonNil = false
+ break
+ }
+ }
+ if argsNonNil {
+- if !nonNilValues[v.ID] {
++ if nonNilValues[v.ID] == nil {
+ changed = true
+ }
+- nonNilValues[v.ID] = true
++ nonNilValues[v.ID] = v
+ }
+ }
+ }
+@@ -103,8 +106,8 @@ func nilcheckelim(f *Func) {
+ if len(b.Preds) == 1 {
+ p := b.Preds[0].b
+ if p.Kind == BlockIf && p.Controls[0].Op == OpIsNonNil && p.Succs[0].b == b {
+- if ptr := p.Controls[0].Args[0]; !nonNilValues[ptr.ID] {
+- nonNilValues[ptr.ID] = true
++ if ptr := p.Controls[0].Args[0]; nonNilValues[ptr.ID] == nil {
++ nonNilValues[ptr.ID] = ptr
+ work = append(work, bp{op: ClearPtr, ptr: ptr})
+ }
+ }
+@@ -117,14 +120,11 @@ func nilcheckelim(f *Func) {
+ pendingLines.clear()
+
+ // Next, process values in the block.
+- i := 0
+ for _, v := range b.Values {
+- b.Values[i] = v
+- i++
+ switch v.Op {
+ case OpIsNonNil:
+ ptr := v.Args[0]
+- if nonNilValues[ptr.ID] {
++ if nonNilValues[ptr.ID] != nil {
+ if v.Pos.IsStmt() == src.PosIsStmt { // Boolean true is a terrible statement boundary.
+ pendingLines.add(v.Pos)
+ v.Pos = v.Pos.WithNotStmt()
+@@ -135,7 +135,7 @@ func nilcheckelim(f *Func) {
+ }
+ case OpNilCheck:
+ ptr := v.Args[0]
+- if nonNilValues[ptr.ID] {
++ if nilCheck := nonNilValues[ptr.ID]; nilCheck != nil {
+ // This is a redundant implicit nil check.
+ // Logging in the style of the former compiler -- and omit line 1,
+ // which is usually in generated code.
+@@ -145,14 +145,13 @@ func nilcheckelim(f *Func) {
+ if v.Pos.IsStmt() == src.PosIsStmt { // About to lose a statement boundary
+ pendingLines.add(v.Pos)
+ }
+- v.reset(OpUnknown)
+- f.freeValue(v)
+- i--
++ v.Op = OpCopy
++ v.SetArgs1(nilCheck)
+ continue
+ }
+ // Record the fact that we know ptr is non nil, and remember to
+ // undo that information when this dominator subtree is done.
+- nonNilValues[ptr.ID] = true
++ nonNilValues[ptr.ID] = v
+ work = append(work, bp{op: ClearPtr, ptr: ptr})
+ fallthrough // a non-eliminated nil check might be a good place for a statement boundary.
+ default:
+@@ -163,7 +162,7 @@ func nilcheckelim(f *Func) {
+ }
+ }
+ // This reduces the lost statement count in "go" by 5 (out of 500 total).
+- for j := 0; j < i; j++ { // is this an ordering problem?
++ for j := range b.Values { // is this an ordering problem?
+ v := b.Values[j]
+ if v.Pos.IsStmt() != src.PosNotStmt && !isPoorStatementOp(v.Op) && pendingLines.contains(v.Pos) {
+ v.Pos = v.Pos.WithIsStmt()
+@@ -174,7 +173,6 @@ func nilcheckelim(f *Func) {
+ b.Pos = b.Pos.WithIsStmt()
+ pendingLines.remove(b.Pos)
+ }
+- b.truncateValues(i)
+
+ // Add all dominated blocks to the work list.
+ for w := sdom[node.block.ID].child; w != nil; w = sdom[w.ID].sibling {
+@@ -182,7 +180,7 @@ func nilcheckelim(f *Func) {
+ }
+
+ case ClearPtr:
+- nonNilValues[node.ptr.ID] = false
++ nonNilValues[node.ptr.ID] = nil
+ continue
+ }
+ }
+diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go
+index 1480fcf45bfd..e7caf9050c15 100644
+--- a/src/cmd/compile/internal/ssa/opGen.go
++++ b/src/cmd/compile/internal/ssa/opGen.go
+@@ -39373,9 +39373,10 @@ var opcodeTable = [...]opInfo{
+ generic: true,
+ },
+ {
+- name: "NilCheck",
+- argLen: 2,
+- generic: true,
++ name: "NilCheck",
++ argLen: 2,
++ nilCheck: true,
++ generic: true,
+ },
+ {
+ name: "GetG",
+diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go
+index 5c7ed16f12be..1cfdc3e10d10 100644
+--- a/src/cmd/compile/internal/ssa/rewrite.go
++++ b/src/cmd/compile/internal/ssa/rewrite.go
+@@ -859,6 +859,9 @@ func disjoint(p1 *Value, n1 int64, p2 *Value, n2 int64) bool {
+ offset += base.AuxInt
+ base = base.Args[0]
+ }
++ if opcodeTable[base.Op].nilCheck {
++ base = base.Args[0]
++ }
+ return base, offset
+ }
+ p1, off1 := baseAndOffset(p1)
+diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go
+index e5bd8bc36f7d..574ac7a1a3ab 100644
+--- a/src/cmd/compile/internal/ssa/rewritegeneric.go
++++ b/src/cmd/compile/internal/ssa/rewritegeneric.go
+@@ -18967,79 +18967,84 @@ func rewriteValuegeneric_OpNilCheck(v *Value) bool {
+ v_0 := v.Args[0]
+ b := v.Block
+ fe := b.Func.fe
+- // match: (NilCheck (GetG mem) mem)
+- // result: mem
++ // match: (NilCheck ptr:(GetG mem) mem)
++ // result: ptr
+ for {
+- if v_0.Op != OpGetG {
++ ptr := v_0
++ if ptr.Op != OpGetG {
+ break
+ }
+- mem := v_0.Args[0]
++ mem := ptr.Args[0]
+ if mem != v_1 {
+ break
+ }
+- v.copyOf(mem)
++ v.copyOf(ptr)
+ return true
+ }
+- // match: (NilCheck (SelectN [0] call:(StaticLECall _ _)) _)
++ // match: (NilCheck ptr:(SelectN [0] call:(StaticLECall _ _)) _)
+ // cond: isSameCall(call.Aux, "runtime.newobject") && warnRule(fe.Debug_checknil(), v, "removed nil check")
+- // result: (Invalid)
++ // result: ptr
+ for {
+- if v_0.Op != OpSelectN || auxIntToInt64(v_0.AuxInt) != 0 {
++ ptr := v_0
++ if ptr.Op != OpSelectN || auxIntToInt64(ptr.AuxInt) != 0 {
+ break
+ }
+- call := v_0.Args[0]
++ call := ptr.Args[0]
+ if call.Op != OpStaticLECall || len(call.Args) != 2 || !(isSameCall(call.Aux, "runtime.newobject") && warnRule(fe.Debug_checknil(), v, "removed nil check")) {
+ break
+ }
+- v.reset(OpInvalid)
++ v.copyOf(ptr)
+ return true
+ }
+- // match: (NilCheck (OffPtr (SelectN [0] call:(StaticLECall _ _))) _)
++ // match: (NilCheck ptr:(OffPtr (SelectN [0] call:(StaticLECall _ _))) _)
+ // cond: isSameCall(call.Aux, "runtime.newobject") && warnRule(fe.Debug_checknil(), v, "removed nil check")
+- // result: (Invalid)
++ // result: ptr
+ for {
+- if v_0.Op != OpOffPtr {
++ ptr := v_0
++ if ptr.Op != OpOffPtr {
+ break
+ }
+- v_0_0 := v_0.Args[0]
+- if v_0_0.Op != OpSelectN || auxIntToInt64(v_0_0.AuxInt) != 0 {
++ ptr_0 := ptr.Args[0]
++ if ptr_0.Op != OpSelectN || auxIntToInt64(ptr_0.AuxInt) != 0 {
+ break
+ }
+- call := v_0_0.Args[0]
++ call := ptr_0.Args[0]
+ if call.Op != OpStaticLECall || len(call.Args) != 2 || !(isSameCall(call.Aux, "runtime.newobject") && warnRule(fe.Debug_checknil(), v, "removed nil check")) {
+ break
+ }
+- v.reset(OpInvalid)
++ v.copyOf(ptr)
+ return true
+ }
+- // match: (NilCheck (Addr {_} (SB)) _)
+- // result: (Invalid)
++ // match: (NilCheck ptr:(Addr {_} (SB)) _)
++ // result: ptr
+ for {
+- if v_0.Op != OpAddr {
++ ptr := v_0
++ if ptr.Op != OpAddr {
+ break
+ }
+- v_0_0 := v_0.Args[0]
+- if v_0_0.Op != OpSB {
++ ptr_0 := ptr.Args[0]
++ if ptr_0.Op != OpSB {
+ break
+ }
+- v.reset(OpInvalid)
++ v.copyOf(ptr)
+ return true
+ }
+- // match: (NilCheck (Convert (Addr {_} (SB)) _) _)
+- // result: (Invalid)
++ // match: (NilCheck ptr:(Convert (Addr {_} (SB)) _) _)
++ // result: ptr
+ for {
+- if v_0.Op != OpConvert {
++ ptr := v_0
++ if ptr.Op != OpConvert {
+ break
+ }
+- v_0_0 := v_0.Args[0]
+- if v_0_0.Op != OpAddr {
++ ptr_0 := ptr.Args[0]
++ if ptr_0.Op != OpAddr {
+ break
+ }
+- v_0_0_0 := v_0_0.Args[0]
+- if v_0_0_0.Op != OpSB {
++ ptr_0_0 := ptr_0.Args[0]
++ if ptr_0_0.Op != OpSB {
+ break
+ }
+- v.reset(OpInvalid)
++ v.copyOf(ptr)
+ return true
+ }
+ return false
+diff --git a/src/cmd/compile/internal/ssa/schedule.go b/src/cmd/compile/internal/ssa/schedule.go
+index 19b98cc4b83b..0a7425c01729 100644
+--- a/src/cmd/compile/internal/ssa/schedule.go
++++ b/src/cmd/compile/internal/ssa/schedule.go
+@@ -312,14 +312,21 @@ func schedule(f *Func) {
+ }
+
+ // Remove SPanchored now that we've scheduled.
++ // Also unlink nil checks now that ordering is assured
++ // between the nil check and the uses of the nil-checked pointer.
+ for _, b := range f.Blocks {
+ for _, v := range b.Values {
+ for i, a := range v.Args {
+- if a.Op == OpSPanchored {
++ if a.Op == OpSPanchored || opcodeTable[a.Op].nilCheck {
+ v.SetArg(i, a.Args[0])
+ }
+ }
+ }
++ for i, c := range b.ControlValues() {
++ if c.Op == OpSPanchored || opcodeTable[c.Op].nilCheck {
++ b.ReplaceControl(i, c.Args[0])
++ }
++ }
+ }
+ for _, b := range f.Blocks {
+ i := 0
+@@ -332,6 +339,15 @@ func schedule(f *Func) {
+ v.resetArgs()
+ f.freeValue(v)
+ } else {
++ if opcodeTable[v.Op].nilCheck {
++ if v.Uses != 0 {
++ base.Fatalf("nilcheck still has %d uses", v.Uses)
++ }
++ // We can't delete the nil check, but we mark
++ // it as having void type so regalloc won't
++ // try to allocate a register for it.
++ v.Type = types.TypeVoid
++ }
+ b.Values[i] = v
+ i++
+ }
+diff --git a/src/cmd/compile/internal/ssa/value.go b/src/cmd/compile/internal/ssa/value.go
+index e89024b3c665..9b52da1c58a9 100644
+--- a/src/cmd/compile/internal/ssa/value.go
++++ b/src/cmd/compile/internal/ssa/value.go
+@@ -552,7 +552,11 @@ func (v *Value) LackingPos() bool {
+ // if its use count drops to 0.
+ func (v *Value) removeable() bool {
+ if v.Type.IsVoid() {
+- // Void ops, like nil pointer checks, must stay.
++ // Void ops (inline marks), must stay.
++ return false
++ }
++ if opcodeTable[v.Op].nilCheck {
++ // Nil pointer checks must stay.
+ return false
+ }
+ if v.Type.IsMemory() {
+diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go
+index 597a196ba8c4..e994577c641d 100644
+--- a/src/cmd/compile/internal/ssagen/ssa.go
++++ b/src/cmd/compile/internal/ssagen/ssa.go
+@@ -1991,7 +1991,8 @@ func (s *state) stmt(n ir.Node) {
+ case ir.OCHECKNIL:
+ n := n.(*ir.UnaryExpr)
+ p := s.expr(n.X)
+- s.nilCheck(p)
++ _ = s.nilCheck(p)
++ // TODO: check that throwing away the nilcheck result is ok.
+
+ case ir.OINLMARK:
+ n := n.(*ir.InlineMarkStmt)
+@@ -5621,18 +5622,20 @@ func (s *state) exprPtr(n ir.Node, bounded bool, lineno src.XPos) *ssa.Value {
+ }
+ return p
+ }
+- s.nilCheck(p)
++ p = s.nilCheck(p)
+ return p
+ }
+
+ // nilCheck generates nil pointer checking code.
+ // Used only for automatically inserted nil checks,
+ // not for user code like 'x != nil'.
+-func (s *state) nilCheck(ptr *ssa.Value) {
++// Returns a "definitely not nil" copy of x to ensure proper ordering
++// of the uses of the post-nilcheck pointer.
++func (s *state) nilCheck(ptr *ssa.Value) *ssa.Value {
+ if base.Debug.DisableNil != 0 || s.curfn.NilCheckDisabled() {
+- return
++ return ptr
+ }
+- s.newValue2(ssa.OpNilCheck, types.TypeVoid, ptr, s.mem())
++ return s.newValue2(ssa.OpNilCheck, ptr.Type, ptr, s.mem())
+ }
+
+ // boundsCheck generates bounds checking code. Checks if 0 <= idx <[=] len, branches to exit if not.
+@@ -5984,8 +5987,8 @@ func (s *state) slice(v, i, j, k *ssa.Value, bounded bool) (p, l, c *ssa.Value)
+ if !t.Elem().IsArray() {
+ s.Fatalf("bad ptr to array in slice %v\n", t)
+ }
+- s.nilCheck(v)
+- ptr = s.newValue1(ssa.OpCopy, types.NewPtr(t.Elem().Elem()), v)
++ nv := s.nilCheck(v)
++ ptr = s.newValue1(ssa.OpCopy, types.NewPtr(t.Elem().Elem()), nv)
+ len = s.constInt(types.Types[types.TINT], t.Elem().NumElem())
+ cap = len
+ default:
+diff --git a/test/fixedbugs/issue63657.go b/test/fixedbugs/issue63657.go
+new file mode 100644
+index 000000000000..e32a4a34fbb6
+--- /dev/null
++++ b/test/fixedbugs/issue63657.go
+@@ -0,0 +1,48 @@
++// 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.
++
++// Make sure address calculations don't float up before
++// the corresponding nil check.
++
++package main
++
++type T struct {
++ a, b int
++}
++
++//go:noinline
++func f(x *T, p *bool, n int) {
++ *p = n != 0
++ useStack(1000)
++ g(&x.b)
++}
++
++//go:noinline
++func g(p *int) {
++}
++
++func useStack(n int) {
++ if n == 0 {
++ return
++ }
++ useStack(n - 1)
++}
++
++func main() {
++ mustPanic(func() {
++ var b bool
++ f(nil, &b, 3)
++ })
++}
++
++func mustPanic(f func()) {
++ defer func() {
++ if recover() == nil {
++ panic("expected panic, got nil")
++ }
++ }()
++ f()
++}
+--
+2.33.0
+
diff --git a/golang.spec b/golang.spec
new file mode 100644
index 0000000..2af841f
--- /dev/null
+++ b/golang.spec
@@ -0,0 +1,444 @@
+%global debug_package %{nil}
+%global _binaries_in_noarch_packages_terminate_build 0
+%global golibdir %{_libdir}/golang
+%global goroot /usr/lib/%{name}
+%global go_api 1.20
+%global go_version 1.20
+%global __spec_install_post /usr/lib/rpm/check-rpaths /usr/lib/rpm/check-buildroot /usr/lib/rpm/brp-compress
+%global __requires_exclude_from ^(%{_datadir}|/usr/lib)/%{name}/(doc|src)/.*$
+%global __strip /bin/true
+%global vendor %{?_vendor:%{_vendor}}%{!?_vendor:openEuler}
+%define _use_internal_dependency_generator 0
+%define __find_requires %{nil}
+
+%bcond_with bootstrap
+%ifarch x86_64 aarch64 riscv64 loongarch64 ppc64le
+%bcond_without ignore_tests
+%else
+%bcond_with ignore_tests
+%endif
+
+%ifarch x86_64 aarch64 riscv64 loongarch64 ppc64le
+%global external_linker 1
+%else
+%global external_linker 0
+%endif
+
+%ifarch x86_64 aarch64 riscv64 loongarch64 ppc64le
+%global cgo_enabled 1
+%else
+%global cgo_enabled 0
+%endif
+
+%if %{with bootstrap}
+%global golang_bootstrap 0
+%else
+%global golang_bootstrap 1
+%endif
+
+%if %{with ignore_tests}
+%global fail_on_tests 0
+%else
+%global fail_on_tests 1
+%endif
+
+%global shared 0
+
+# Pre build std lib with -race enabled
+# Disabled due to 1.20 new cache usage, see 1.20 upstream release notes
+%global race 0
+
+%ifarch x86_64
+%global gohostarch amd64
+%endif
+%ifarch aarch64
+%global gohostarch arm64
+%endif
+%ifarch riscv64
+%global gohostarch riscv64
+%endif
+%ifarch ppc64le
+%global gohostarch ppc64le
+%endif
+%ifarch loongarch64
+%global gohostarch loong64
+%endif
+
+Name: golang
+Version: 1.21.4
+Release: 17
+Summary: The Go Programming Language
+License: BSD and Public Domain
+URL: https://golang.org/
+Source0: https://dl.google.com/go/go%{version}.src.tar.gz
+
+%if !%{golang_bootstrap}
+BuildRequires: gcc-go >= 5
+%else
+BuildRequires: golang > 1.4
+%endif
+BuildRequires: hostname
+# for tests
+BuildRequires: pcre-devel, glibc-static, perl-interpreter, procps-ng
+
+Provides: go = %{version}-%{release}
+Requires: %{name}-devel = %{version}-%{release}
+
+Obsoletes: %{name}-pkg-bin-linux-386 < 1.4.99
+Obsoletes: %{name}-pkg-bin-linux-amd64 < 1.4.99
+Obsoletes: %{name}-pkg-bin-linux-arm < 1.4.99
+Obsoletes: %{name}-pkg-linux-386 < 1.4.99
+Obsoletes: %{name}-pkg-linux-amd64 < 1.4.99
+Obsoletes: %{name}-pkg-linux-arm < 1.4.99
+Obsoletes: %{name}-vet < 0-12.1
+Obsoletes: %{name}-cover < 0-12.1
+
+Requires(post): %{_sbindir}/update-alternatives
+Requires(postun): %{_sbindir}/update-alternatives
+Recommends: glibc gcc git subversion
+
+# Bundled/Vendored provides generated by bundled-deps.sh based on the in tree module data
+# - in version filed substituted with . per versioning guidelines
+Provides: bundled(golang(github.com/google/pprof)) = 0.0.0.20221118152302.e6195bd50e26
+Provides: bundled(golang(github.com/ianlancetaylor/demangle)) = 0.0.0.20220319035150.800ac71e25c2
+Provides: bundled(golang(golang.org/x/arch)) = 0.4.0
+Provides: bundled(golang(golang.org/x/crypto)) = 0.11.1.0.20230711161743.2e82bdd1719d
+Provides: bundled(golang(golang.org/x/mod)) = 0.12.0
+Provides: bundled(golang(golang.org/x/net)) = 0.12.1.0.20231027154334.5ca955b1789c
+Provides: bundled(golang(golang.org/x/sync)) = 0.3.0
+Provides: bundled(golang(golang.org/x/sys)) = 0.10.0
+Provides: bundled(golang(golang.org/x/term)) = 0.10.0
+Provides: bundled(golang(golang.org/x/text)) = 0.11.0
+Provides: bundled(golang(golang.org/x/tools)) = 0.11.1.0.20230712164437.1ca21856af7b
+
+Provides: %{name}-bin = %{version}-%{release}
+Obsoletes: %{name}-bin
+Obsoletes: %{name}-shared
+Obsoletes: %{name}-docs
+Obsoletes: %{name}-data < 1.1.1-4
+Obsoletes: %{name}-vim < 1.4
+Obsoletes: emacs-%{name} < 1.4
+Requires: %{vendor}-rpm-config
+
+Patch6001: backport-0001-release-branch.go1.21-crypto-x509-make-sure-pub-key-.patch
+Patch6002: backport-0002-release-branch.go1.21-html-template-escape-additiona.patch
+Patch6003: backport-0003-release-branch.go1.21-net-textproto-mime-multipart-a.patch
+Patch6004: backport-0004-release-branch.go1.21-net-http-net-http-cookiejar-av.patch
+Patch6005: backport-0005-release-branch.go1.21-net-mail-properly-handle-speci.patch
+Patch6006: backport-0006-Backport-net-http-update-bundled-golang.org-x-net-ht.patch
+Patch6007: backport-0007-Backport-cmd-go-disallow-lto_library-in-LDFLAGS.patch
+
+Patch6008: backport-0008-release-branch.go1.21-net-netip-check-if-address-is-v6.patch
+Patch6009: backport-0009-Backport-cmd-go-internal-vcs-error-out-if-the-reques.patch
+Patch6010: backport-0010-release-branch.go1.21-net-http-limit-chunked-data-ov.patch
+Patch6011: backport-0011-Backport-archive-zip-treat-truncated-EOCDR-comment-a.patch
+Patch6012: backport-0012-net-http-send-body-or-close-connection-on-expect-100.patch
+Patch6013: backport-0013-release-branch.go1.21-net-http-update-bundled-golang.patch
+Patch6014: backport-0014-cmd-compile-handle-constant-pointer-offsets-in-dead-.patch
+Patch6015: backport-0015-release-branch.go1.21-cmd-compile-ensure-pointer-ari.patch
+
+ExclusiveArch: %{golang_arches}
+
+%description
+%{summary}.
+
+%package help
+Summary: Golang compiler helps and manual docs
+Requires: %{name} = %{version}-%{release}
+BuildArch: noarch
+Provides: %{name}-docs = %{version}-%{release}
+Obsoletes: %{name}-docs < %{version}-%{release}
+Provides: %{name}-shared = %{version}-%{release}
+Obsoletes: %{name}-shared < %{version}-%{release}
+
+%description help
+%{summary}.
+
+%package devel
+Summary: Golang compiler devel
+BuildArch: noarch
+Requires: %{name} = %{version}-%{release}
+Provides: %{name}-src = %{version}-%{release}
+Obsoletes: %{name}-src < %{version}-%{release}
+Provides: %{name}-tests = %{version}-%{release}
+Obsoletes: %{name}-tests < %{version}-%{release}
+Provides: %{name}-misc = %{version}-%{release}
+Obsoletes: %{name}-misc < %{version}-%{release}
+Obsoletes: %{name}-race = %{version}-%{release}
+
+%description devel
+%{summary}.
+
+# Workaround old RPM bug of symlink-replaced-with-dir failure
+%pretrans -p <lua>
+for _,d in pairs({"api", "doc", "include", "lib", "src"}) do
+ path = "%{goroot}/" .. d
+ if posix.stat(path, "type") == "link" then
+ os.remove(path)
+ posix.mkdir(path)
+ end
+end
+
+%prep
+%autosetup -n go -p1
+
+%build
+uname -a
+cat /proc/cpuinfo
+cat /proc/meminfo
+
+%if !%{golang_bootstrap}
+export GOROOT_BOOTSTRAP=/
+%else
+export GOROOT_BOOTSTRAP=%{goroot}
+%endif
+
+export GOROOT_FINAL=%{goroot}
+export GOHOSTOS=linux
+export GOHOSTARCH=%{gohostarch}
+
+pushd src
+export CFLAGS="$RPM_OPT_FLAGS"
+export LDFLAGS="$RPM_LD_FLAGS"
+export CC="gcc"
+export CC_FOR_TARGET="gcc"
+export GOOS=linux
+export GOARCH=%{gohostarch}
+%if !%{external_linker}
+export GO_LDFLAGS="-linkmode internal"
+%endif
+%if !%{cgo_enabled}
+export CGO_ENABLED=0
+%endif
+
+%ifarch aarch64
+export GO_LDFLAGS="-s -w"
+%endif
+
+./make.bash --no-clean -v
+popd
+
+%if %{shared}
+GOROOT=$(pwd) PATH=$(pwd)/bin:$PATH go install -buildmode=shared -v -x std
+%endif
+
+%if %{race}
+GOROOT=$(pwd) PATH=$(pwd)/bin:$PATH go install -race -v -x std
+%endif
+
+%install
+rm -rf %{buildroot}
+rm -rf pkg/obj/go-build/*
+
+mkdir -p %{buildroot}%{_bindir}
+mkdir -p %{buildroot}%{goroot}
+
+cp -apv api bin doc lib pkg src misc test go.env VERSION \
+ %{buildroot}%{goroot}
+
+# bz1099206
+find %{buildroot}%{goroot}/src -exec touch -r %{buildroot}%{goroot}/VERSION "{}" \;
+# and level out all the built archives
+touch %{buildroot}%{goroot}/pkg
+find %{buildroot}%{goroot}/pkg -exec touch -r %{buildroot}%{goroot}/pkg "{}" \;
+# generate the spec file ownership of this source tree and packages
+cwd=$(pwd)
+src_list=$cwd/go-src.list
+pkg_list=$cwd/go-pkg.list
+shared_list=$cwd/go-shared.list
+race_list=$cwd/go-race.list
+misc_list=$cwd/go-misc.list
+docs_list=$cwd/go-docs.list
+tests_list=$cwd/go-tests.list
+rm -f $src_list $pkg_list $docs_list $misc_list $tests_list $shared_list $race_list
+touch $src_list $pkg_list $docs_list $misc_list $tests_list $shared_list $race_list
+pushd %{buildroot}%{goroot}
+ find src/ -type d -a \( ! -name testdata -a ! -ipath '*/testdata/*' \) -printf '%%%dir %{goroot}/%p\n' >> $src_list
+ find src/ ! -type d -a \( ! -ipath '*/testdata/*' -a ! -name '*_test.go' \) -printf '%{goroot}/%p\n' >> $src_list
+
+ find bin/ pkg/ -type d -a ! -path '*_dynlink/*' -a ! -path '*_race/*' -printf '%%%dir %{goroot}/%p\n' >> $pkg_list
+ find bin/ pkg/ ! -type d -a ! -path '*_dynlink/*' -a ! -path '*_race/*' -printf '%{goroot}/%p\n' >> $pkg_list
+
+ find doc/ -type d -printf '%%%dir %{goroot}/%p\n' >> $docs_list
+ find doc/ ! -type d -printf '%{goroot}/%p\n' >> $docs_list
+
+ find misc/ -type d -printf '%%%dir %{goroot}/%p\n' >> $misc_list
+ find misc/ ! -type d -printf '%{goroot}/%p\n' >> $misc_list
+
+%if %{shared}
+ mkdir -p %{buildroot}/%{_libdir}/
+ mkdir -p %{buildroot}/%{golibdir}/
+ for file in $(find . -iname "*.so" ); do
+ chmod 755 $file
+ mv $file %{buildroot}/%{golibdir}
+ pushd $(dirname $file)
+ ln -fs %{golibdir}/$(basename $file) $(basename $file)
+ popd
+ echo "%%{goroot}/$file" >> $shared_list
+ echo "%%{golibdir}/$(basename $file)" >> $shared_list
+ done
+
+ find pkg/*_dynlink/ -type d -printf '%%%dir %{goroot}/%p\n' >> $shared_list
+ find pkg/*_dynlink/ ! -type d -printf '%{goroot}/%p\n' >> $shared_list
+%endif
+
+%if %{race}
+
+ find pkg/*_race/ -type d -printf '%%%dir %{goroot}/%p\n' >> $race_list
+ find pkg/*_race/ ! -type d -printf '%{goroot}/%p\n' >> $race_list
+
+%endif
+
+ find test/ -type d -printf '%%%dir %{goroot}/%p\n' >> $tests_list
+ find test/ ! -type d -printf '%{goroot}/%p\n' >> $tests_list
+ find src/ -type d -a \( -name testdata -o -ipath '*/testdata/*' \) -printf '%%%dir %{goroot}/%p\n' >> $tests_list
+ find src/ ! -type d -a \( -ipath '*/testdata/*' -o -name '*_test.go' \) -printf '%{goroot}/%p\n' >> $tests_list
+ # this is only the zoneinfo.zip
+ find lib/ -type d -printf '%%%dir %{goroot}/%p\n' >> $tests_list
+ find lib/ ! -type d -printf '%{goroot}/%p\n' >> $tests_list
+popd
+
+rm -rfv %{buildroot}%{goroot}/doc/Makefile
+
+mkdir -p %{buildroot}%{goroot}/bin/linux_%{gohostarch}
+ln -sf %{goroot}/bin/go %{buildroot}%{goroot}/bin/linux_%{gohostarch}/go
+ln -sf %{goroot}/bin/gofmt %{buildroot}%{goroot}/bin/linux_%{gohostarch}/gofmt
+
+mkdir -p %{buildroot}%{gopath}/src/github.com
+mkdir -p %{buildroot}%{gopath}/src/bitbucket.org
+mkdir -p %{buildroot}%{gopath}/src/code.google.com/p
+mkdir -p %{buildroot}%{gopath}/src/golang.org/x
+
+%check
+export GOROOT=$(pwd -P)
+export PATH="$GOROOT"/bin:"$PATH"
+cd src
+
+export CC="gcc"
+export CFLAGS="$RPM_OPT_FLAGS"
+export LDFLAGS="$RPM_LD_FLAGS"
+%if !%{external_linker}
+export GO_LDFLAGS="-linkmode internal"
+%endif
+%if !%{cgo_enabled} || !%{external_linker}
+export CGO_ENABLED=0
+%endif
+
+export GO_TEST_TIMEOUT_SCALE=2
+
+%if %{fail_on_tests}
+echo tests ignored
+%else
+./run.bash --no-rebuild -v -k -run='!(cmd/go|go/build|cmd/internal/testdir|cmd/link|cmd/nm|cmd/cgo/internal/testlife|cmd/cgo/internal/teststdio|cmd/cgo/internal/testerrors|tyepparams|race|flag|cgo_stdio|cgo_life|cgo_errors|test:0_1|api)'
+%endif
+cd ..
+
+%post
+%{_sbindir}/update-alternatives --install %{_bindir}/go \
+ go %{goroot}/bin/go 90 \
+ --slave %{_bindir}/gofmt gofmt %{goroot}/bin/gofmt
+
+%preun
+if [ $1 = 0 ]; then
+ %{_sbindir}/update-alternatives --remove go %{goroot}/bin/go
+fi
+
+%if %{shared}
+%files -f go-pkg.list -f go-shared.list
+%else
+%files -f go-pkg.list
+%endif
+
+%doc LICENSE PATENTS
+%doc %{goroot}/VERSION
+%dir %{goroot}/doc
+%doc %{goroot}/doc/*
+%dir %{goroot}
+%exclude %{goroot}/src/
+%exclude %{goroot}/doc/
+%exclude %{goroot}/misc/
+%exclude %{goroot}/test/
+%exclude %{goroot}/lib/
+%{goroot}/*
+%dir %{gopath}
+%dir %{gopath}/src
+%dir %{gopath}/src/github.com/
+%dir %{gopath}/src/bitbucket.org/
+%dir %{gopath}/src/code.google.com/
+%dir %{gopath}/src/code.google.com/p/
+%dir %{gopath}/src/golang.org
+%dir %{gopath}/src/golang.org/x
+
+%files help -f go-docs.list
+
+%files devel -f go-tests.list -f go-misc.list -f go-src.list
+
+%changelog
+* Mon Jul 30 2024 jingxiaolu <lujingxiao@huawei.com> - 1.21.4-17
+- cmd/compile: ensure pointer arithmetic happens after the nil check
+
+* Mon Jul 30 2024 jingxiaolu <lujingxiao@huawei.com> - 1.21.4-16
+- cmd/compile: handle constant pointer offsets in dead store elimination
+
+* Mon Jul 29 2024 EulerOSWander <314264452@qq.com> - 1.21.4-15
+- fix send correct lastStreamID in stream-caused GOAWAY
+
+* Wed Jul 03 2024 kywqs <weiqingsong@kylinos.cn.com> - 1.21.4-14
+- fix CVE-2024-24791
+
+* Sun Jun 23 2024 hanchao <hanchao63@huawei.com> - 1.21.4-13
+- Type:CVE
+- CVE:CVE-2023-39326,CVE-2024-24789
+- SUG:NA
+- DESC:fix CVE-2023-39326,CVE-2024-24789
+
+* Fri Jun 21 2024 EulerOSWander <314264452@qq.com> - 1.21.4-12
+- fix CVE-2023-45285
+
+* Thu May 23 2024 EulerOSWander <314264452@qq.com> - 1.21.4-11
+- fix CVE-2024-24787
+
+* Thu Jun 13 2024 Zhao Mengmeng <zhaomengmeng@kylinos.cn> - 1.21.4-10
+- fix CVE-2024-24790
+
+* Tue Jun 11 2024 chenguoqi <chenguoqi@loongson.cn> - 1.21.4-9
+- Fix missing go.env file
+
+* Thu Apr 18 2024 Huang Yang <huangyang@loongson.cn> - 1.21.4-8
+- enable external_linker and cgo on loongarch64
+
+* Tue Apr 16 2024 hanchao <hanchao63@huawei.com> - 1.21.4-7
+- fix CVE-2023-45288
+
+* Thu Mar 28 2024 hanchao <hanchao63@huawei.com> - 1.21.4-6
+- fix CVE-2024-24784
+
+* Thu Mar 28 2024 hanchao <hanchao63@huawei.com> - 1.21.4-5
+- enabling the patches
+
+* Tue Mar 26 2024 Wenlong Zhang <zhangwenlong@loongson.cn> - 1.21.4-4
+- fix build error for loongarch64
+
+* Fri Mar 15 2024 hanchao <hanchao63@huawei.com> - 1.21.4-3
+- fix CVE-2024-24783,CVE-2024-24785,CVE-2023-45290,CVE-2023-45289
+
+* Wed Dec 13 2023 jiahua.yu <jiahua.yu@shingroup.cn> - 1.21.4-2
+- init support for arch ppc64le
+
+* Tue Dec 5 2023 hanchao <hanchao63@huawei.com> - 1.21.4-1
+- upgrade to 1.21.4
+
+* Thu Aug 24 2023 wanglimin <wanglimin@xfusion.com> - 1.20.7-2
+- permit invalid host header for docker
+
+* Mon Aug 7 2023 Funda Wang <fundawang@yeah.net> - 1.20.7-1
+- New version 1.20.7
+
+* Sun Jul 30 2023 Funda Wang <fundawang@yeah.net> - 1.20.5-3
+- Use local proxy and sumdb for speed up
+
+* Tue Jul 11 2023 hanchao <sunchendong@xfusion.com> - 1.20.5-2
+- fix CVE-2023-29406
+
+* Wed Jun 21 2023 hanchao <hanchao63@huawei.com> - 1.20.5-1
+- upgrade to 1.20.5
diff --git a/sources b/sources
new file mode 100644
index 0000000..d90aa29
--- /dev/null
+++ b/sources
@@ -0,0 +1 @@
+92054b4df78d17ce035c9943a3ed1fec go1.21.4.src.tar.gz