From e0c76d95abfc1621259864adb3d101cf6f1f90fc Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Tue, 10 Dec 2024 12:10:13 -0800 Subject: [PATCH 001/397] syscall: remove a wrong comment in Clearenv The comment being removed was added by commit ff3173849e (which predates Gerrit and Rietveld, so no CL link), and at the time it made sense. Since CL 148370043 (and up to the current implementation of Clearenv) the env map, which is populated by copyenv, is actually used, so the comment is no longer valid. It is also misleading, so it's best to remove it. Change-Id: I8bd2e8bca6262759538e5bcbd396f0c71cca6a4c Reviewed-on: https://go-review.googlesource.com/c/go/+/635078 Reviewed-by: Carlos Amedee Reviewed-by: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Auto-Submit: Ian Lance Taylor --- src/syscall/env_unix.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/syscall/env_unix.go b/src/syscall/env_unix.go index 8e87e018e82de3..1144ed1416c0ee 100644 --- a/src/syscall/env_unix.go +++ b/src/syscall/env_unix.go @@ -124,7 +124,7 @@ func Setenv(key, value string) error { } func Clearenv() { - envOnce.Do(copyenv) // prevent copyenv in Getenv/Setenv + envOnce.Do(copyenv) envLock.Lock() defer envLock.Unlock() From 6c25cf1c5fc063cc9ea27aa850ef0c4345f3a5b4 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Tue, 10 Dec 2024 12:00:10 -0500 Subject: [PATCH 002/397] cmd/internal/objfile: break out dissassemblers to another package Currently, cmd/internal/objfile provides dissassembly routines for various architectures, which depend on dissassemblers from x/arch. cmd/internal/objfile is imported in tools that need dissassembly (objdump, pprof) and tools that don't need dissassembly (nm, addr2line). Adding/improving disassembly support for more architectures can cause binary size increase, and for some tools (nm, addr2line) it is not necessary. This CL breaks out dissassembly routines to a different package, which is only imported in tools that need dissassembly. Other tools can depend on cmd/internal/objfile without the disassembly code from x/arch. This reduces binary sizes for those tools. On darwin/arm64, old new cmd/addr2line 4554418 3648882 -20% cmd/addr2line (-ldflags=-w) 3464626 2641650 -24% cmd/nm 4503874 3616722 -20% cmd/nm (-ldflags=-w) 3430594 2609490 -24% For #70699. Change-Id: Ie45d5d5c5500c5f3882e8b3c4e6eb81f0d815292 Reviewed-on: https://go-review.googlesource.com/c/go/+/634916 LUCI-TryBot-Result: Go LUCI Reviewed-by: David Chase --- .../internal/{objfile => disasm}/disasm.go | 28 ++++++++++--------- src/cmd/internal/objfile/objfile.go | 10 ++++--- src/cmd/objdump/main.go | 3 +- src/cmd/pprof/pprof.go | 9 +++--- 4 files changed, 28 insertions(+), 22 deletions(-) rename src/cmd/internal/{objfile => disasm}/disasm.go (94%) diff --git a/src/cmd/internal/objfile/disasm.go b/src/cmd/internal/disasm/disasm.go similarity index 94% rename from src/cmd/internal/objfile/disasm.go rename to src/cmd/internal/disasm/disasm.go index 99f54143fa9863..c317effa900f60 100644 --- a/src/cmd/internal/objfile/disasm.go +++ b/src/cmd/internal/disasm/disasm.go @@ -2,13 +2,16 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package objfile +// Package disasm provides disassembly routines. +// +// It is broken out from cmd/internal/objfile so tools that don't need +// disassembling don't need to depend on x/arch disassembler code. +package disasm import ( "bufio" "bytes" "container/list" - "debug/gosym" "encoding/binary" "fmt" "io" @@ -19,6 +22,7 @@ import ( "strings" "text/tabwriter" + "cmd/internal/objfile" "cmd/internal/src" "golang.org/x/arch/arm/armasm" @@ -32,8 +36,8 @@ import ( // Disasm is a disassembler for a given File. type Disasm struct { - syms []Sym //symbols in file, sorted by address - pcln Liner // pcln table + syms []objfile.Sym // symbols in file, sorted by address + pcln objfile.Liner // pcln table text []byte // bytes of text segment (actual instructions) textStart uint64 // start PC of text textEnd uint64 // end PC of text @@ -42,8 +46,12 @@ type Disasm struct { byteOrder binary.ByteOrder // byte order for goarch } -// Disasm returns a disassembler for the file f. -func (e *Entry) Disasm() (*Disasm, error) { +// DisasmForFile returns a disassembler for the file f. +func DisasmForFile(f *objfile.File) (*Disasm, error) { + return disasmForEntry(f.Entries()[0]) +} + +func disasmForEntry(e *objfile.Entry) (*Disasm, error) { syms, err := e.Symbols() if err != nil { return nil, err @@ -269,7 +277,7 @@ func (d *Disasm) Print(w io.Writer, filter *regexp.Regexp, start, end uint64, pr } // Decode disassembles the text segment range [start, end), calling f for each instruction. -func (d *Disasm) Decode(start, end uint64, relocs []Reloc, gnuAsm bool, f func(pc, size uint64, file string, line int, text string)) { +func (d *Disasm) Decode(start, end uint64, relocs []objfile.Reloc, gnuAsm bool, f func(pc, size uint64, file string, line int, text string)) { if start < d.textStart { start = d.textStart } @@ -452,9 +460,3 @@ var byteOrders = map[string]binary.ByteOrder{ "riscv64": binary.LittleEndian, "s390x": binary.BigEndian, } - -type Liner interface { - // Given a pc, returns the corresponding file, line, and function data. - // If unknown, returns "",0,nil. - PCToLine(uint64) (string, int, *gosym.Func) -} diff --git a/src/cmd/internal/objfile/objfile.go b/src/cmd/internal/objfile/objfile.go index 2f2d7718132d57..ed9aae280e5579 100644 --- a/src/cmd/internal/objfile/objfile.go +++ b/src/cmd/internal/objfile/objfile.go @@ -119,10 +119,6 @@ func (f *File) DWARF() (*dwarf.Data, error) { return f.entries[0].DWARF() } -func (f *File) Disasm() (*Disasm, error) { - return f.entries[0].Disasm() -} - func (e *Entry) Name() string { return e.name } @@ -181,3 +177,9 @@ func (e *Entry) LoadAddress() (uint64, error) { func (e *Entry) DWARF() (*dwarf.Data, error) { return e.raw.dwarf() } + +type Liner interface { + // Given a pc, returns the corresponding file, line, and function data. + // If unknown, returns "",0,nil. + PCToLine(uint64) (string, int, *gosym.Func) +} diff --git a/src/cmd/objdump/main.go b/src/cmd/objdump/main.go index b5b0d7f5178d5b..c98551e6b857b0 100644 --- a/src/cmd/objdump/main.go +++ b/src/cmd/objdump/main.go @@ -40,6 +40,7 @@ import ( "strconv" "strings" + "cmd/internal/disasm" "cmd/internal/objfile" "cmd/internal/telemetry/counter" ) @@ -82,7 +83,7 @@ func main() { } defer f.Close() - dis, err := f.Disasm() + dis, err := disasm.DisasmForFile(f) if err != nil { log.Fatalf("disassemble %s: %v", flag.Arg(0), err) } diff --git a/src/cmd/pprof/pprof.go b/src/cmd/pprof/pprof.go index a1c2cd210f8dba..bfc2911b69cd39 100644 --- a/src/cmd/pprof/pprof.go +++ b/src/cmd/pprof/pprof.go @@ -24,6 +24,7 @@ import ( "sync" "time" + "cmd/internal/disasm" "cmd/internal/objfile" "cmd/internal/telemetry/counter" @@ -162,7 +163,7 @@ func adjustURL(source string, duration, timeout time.Duration) (string, time.Dur // (instead of invoking GNU binutils). type objTool struct { mu sync.Mutex - disasmCache map[string]*objfile.Disasm + disasmCache map[string]*disasm.Disasm } func (*objTool) Open(name string, start, limit, offset uint64, relocationSymbol string) (driver.ObjFile, error) { @@ -202,11 +203,11 @@ func (t *objTool) Disasm(file string, start, end uint64, intelSyntax bool) ([]dr return asm, nil } -func (t *objTool) cachedDisasm(file string) (*objfile.Disasm, error) { +func (t *objTool) cachedDisasm(file string) (*disasm.Disasm, error) { t.mu.Lock() defer t.mu.Unlock() if t.disasmCache == nil { - t.disasmCache = make(map[string]*objfile.Disasm) + t.disasmCache = make(map[string]*disasm.Disasm) } d := t.disasmCache[file] if d != nil { @@ -216,7 +217,7 @@ func (t *objTool) cachedDisasm(file string) (*objfile.Disasm, error) { if err != nil { return nil, err } - d, err = f.Disasm() + d, err = disasm.DisasmForFile(f) f.Close() if err != nil { return nil, err From e424d78c3da1732b72f9170e7c01f400926143ce Mon Sep 17 00:00:00 2001 From: zfdx123 <2915441170@qq.com> Date: Wed, 11 Dec 2024 04:17:11 +0000 Subject: [PATCH 003/397] internal/goos: fix bug in gengoos.go CL 601357 mistakenly added an extra period. Change-Id: I54db621663797f094059a4eb86bf5d9626fa59d6 GitHub-Last-Rev: c756e0a82427c44b00bd88547dc40bf88c85fc1f GitHub-Pull-Request: golang/go#70733 Reviewed-on: https://go-review.googlesource.com/c/go/+/634517 LUCI-TryBot-Result: Go LUCI Auto-Submit: Ian Lance Taylor Reviewed-by: Michael Pratt Reviewed-by: Ian Lance Taylor --- src/internal/goos/gengoos.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/internal/goos/gengoos.go b/src/internal/goos/gengoos.go index aba0d3c3356f4f..e0d4d38e898e89 100644 --- a/src/internal/goos/gengoos.go +++ b/src/internal/goos/gengoos.go @@ -17,7 +17,7 @@ import ( var gooses []string func main() { - data, err := os.ReadFile("../../internal/syslist/syslist..go") + data, err := os.ReadFile("../../internal/syslist/syslist.go") if err != nil { log.Fatal(err) } From 979c1cfbe8880e302d5a73df47f4efc3d34ee416 Mon Sep 17 00:00:00 2001 From: Antonio Ojea Date: Wed, 11 Dec 2024 15:03:59 +0000 Subject: [PATCH 004/397] net: avoid unnecessary interface lookup fetching all interface addresses InterfaceAddrs returns a list of the system's unicast interface addresses. In order to do so, the function reuses the existing helpers and list first all addresses with the netlink call RTM_GETADDR, then all interfaces with RTM_GETLINK, and later it merge both lists (each address references an interface). However, the list of interfaces and addresses are obtained at different times and there can be inconsistencies and, if an address references an interface that is not present in the list of interfaces, the function fails with an error. Since the function InterfaceAddress is only about the system addresses, there is no need to list all the interfaces, and we can obtain the list of addresses directly from the netlink call RTM_GETADDR. There is no need to correlate this list with the list of interfaces, as the OS is the source of truth and should be the one providing the consistency between addresses and interfaces. Fixes #51934 Change-Id: I3b816e8146b1c07fdfe1bf6af338f001ef75734f Reviewed-on: https://go-review.googlesource.com/c/go/+/635196 Reviewed-by: Ian Lance Taylor Commit-Queue: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Auto-Submit: Ian Lance Taylor --- src/net/interface_linux.go | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/src/net/interface_linux.go b/src/net/interface_linux.go index 9112ecc854c74c..7856dae8fc878b 100644 --- a/src/net/interface_linux.go +++ b/src/net/interface_linux.go @@ -129,22 +129,14 @@ func interfaceAddrTable(ifi *Interface) ([]Addr, error) { if err != nil { return nil, os.NewSyscallError("parsenetlinkmessage", err) } - var ift []Interface - if ifi == nil { - var err error - ift, err = interfaceTable(0) - if err != nil { - return nil, err - } - } - ifat, err := addrTable(ift, ifi, msgs) + ifat, err := addrTable(ifi, msgs) if err != nil { return nil, err } return ifat, nil } -func addrTable(ift []Interface, ifi *Interface, msgs []syscall.NetlinkMessage) ([]Addr, error) { +func addrTable(ifi *Interface, msgs []syscall.NetlinkMessage) ([]Addr, error) { var ifat []Addr loop: for _, m := range msgs { @@ -153,14 +145,7 @@ loop: break loop case syscall.RTM_NEWADDR: ifam := (*syscall.IfAddrmsg)(unsafe.Pointer(&m.Data[0])) - if len(ift) != 0 || ifi.Index == int(ifam.Index) { - if len(ift) != 0 { - var err error - ifi, err = interfaceByIndex(ift, int(ifam.Index)) - if err != nil { - return nil, err - } - } + if ifi == nil || ifi.Index == int(ifam.Index) { attrs, err := syscall.ParseNetlinkRouteAttr(&m) if err != nil { return nil, os.NewSyscallError("parsenetlinkrouteattr", err) From a7c4cadce0799a74e48d394ff662ed5128667621 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 11 Dec 2024 08:59:04 -0800 Subject: [PATCH 005/397] cmd/compile: update broken link Fixes #70778 Change-Id: Ie5ed53aa39446beb0316eb134cc705ea06b37435 Reviewed-on: https://go-review.googlesource.com/c/go/+/635295 Auto-Submit: Ian Lance Taylor Reviewed-by: Keith Randall Reviewed-by: Keith Randall Reviewed-by: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI --- src/cmd/compile/internal/ssa/_gen/rulegen.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/ssa/_gen/rulegen.go b/src/cmd/compile/internal/ssa/_gen/rulegen.go index b6356315014411..4374d3e153f69e 100644 --- a/src/cmd/compile/internal/ssa/_gen/rulegen.go +++ b/src/cmd/compile/internal/ssa/_gen/rulegen.go @@ -5,7 +5,8 @@ // This program generates Go code that applies rewrite rules to a Value. // The generated code implements a function of type func (v *Value) bool // which reports whether if did something. -// Ideas stolen from Swift: http://www.hpl.hp.com/techreports/Compaq-DEC/WRL-2000-2.html +// Ideas stolen from the Swift Java compiler: +// https://bitsavers.org/pdf/dec/tech_reports/WRL-2000-2.pdf package main From d5c1333eb452e37f80af797c6c26a93b00697f7f Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Wed, 11 Dec 2024 09:49:36 -0800 Subject: [PATCH 006/397] net/http: document zero value of Protocols For #67814 Change-Id: I182e9c7e720493adb9d2384336e757dace818525 Reviewed-on: https://go-review.googlesource.com/c/go/+/635335 LUCI-TryBot-Result: Go LUCI Auto-Submit: Damien Neil Reviewed-by: Austin Clements --- src/net/http/http.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/net/http/http.go b/src/net/http/http.go index 4da77889b1a341..32ff7e2008a845 100644 --- a/src/net/http/http.go +++ b/src/net/http/http.go @@ -17,6 +17,7 @@ import ( ) // Protocols is a set of HTTP protocols. +// The zero value is an empty set of protocols. // // The supported protocols are: // From 5424f2e200e022e5ddf95088118fb0914343492a Mon Sep 17 00:00:00 2001 From: Sam Thanawalla Date: Wed, 11 Dec 2024 15:41:05 +0000 Subject: [PATCH 007/397] cmd/go: add more tests for GOAUTH's user provided authenticator For #26232 Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest,gotip-windows-amd64-longtest Change-Id: I4b6eb63d4c1d71983e1ae764a6a38744a5f01317 Reviewed-on: https://go-review.googlesource.com/c/go/+/635255 Auto-Submit: Sam Thanawalla LUCI-TryBot-Result: Go LUCI Reviewed-by: Michael Matloob --- .../go/testdata/script/goauth_userauth.txt | 94 +++++++++++++++---- 1 file changed, 75 insertions(+), 19 deletions(-) diff --git a/src/cmd/go/testdata/script/goauth_userauth.txt b/src/cmd/go/testdata/script/goauth_userauth.txt index 8403c37125d050..036573e07a2a3f 100644 --- a/src/cmd/go/testdata/script/goauth_userauth.txt +++ b/src/cmd/go/testdata/script/goauth_userauth.txt @@ -3,13 +3,8 @@ env GOPROXY=direct env GOSUMDB=off - -# Use a custom authenticator to provide custom credentials mkdir $WORK/bin env PATH=$WORK/bin${:}$PATH -cd auth -go build -o $WORK/bin/my-auth$GOEXE . -cd .. # Without credentials, downloading a module from a path that requires HTTPS # basic auth should fail. @@ -21,8 +16,21 @@ stderr '^\tserver response: ACCESS DENIED, buddy$' ! go mod tidy stderr '^\tserver response: ACCESS DENIED, buddy$' -# With credentials from the my-auth binary, it should succeed. -env GOAUTH='my-auth'$GOEXE' --arg1 "value with spaces"' +# Initial invocation of authenticator is successful. +go build -o $WORK/bin/basic$GOEXE scripts/basic.go +# With credentials from the binary, it should succeed. +env GOAUTH='basic'$GOEXE +cp go.mod.orig go.mod +go get vcs-test.golang.org/auth/or401 +# go imports should resolve correctly as well. +go mod tidy +go list all +stdout vcs-test.golang.org/auth/or401 + +# Second invocation of authenticator is successful. +go build -o $WORK/bin/reinvocation$GOEXE scripts/reinvocation.go +# With credentials from the binary, it should succeed. +env GOAUTH='reinvocation'$GOEXE cp go.mod.orig go.mod go get vcs-test.golang.org/auth/or401 # go imports should resolve correctly as well. @@ -30,7 +38,43 @@ go mod tidy go list all stdout vcs-test.golang.org/auth/or401 --- auth/main.go -- +# Authenticator can parse arguments correctly. +go build -o $WORK/bin/arguments$GOEXE scripts/arguments.go +# With credentials from the binary, it should succeed. +env GOAUTH='arguments'$GOEXE' --arg1 "value with spaces"' +cp go.mod.orig go.mod +go get vcs-test.golang.org/auth/or401 +# go imports should resolve correctly as well. +go mod tidy +go list all +stdout vcs-test.golang.org/auth/or401 + +# Authenticator provides bad credentials. +go build -o $WORK/bin/invalid$GOEXE scripts/invalid.go +# With credentials from the binary, it should fail. +env GOAUTH='invalid'$GOEXE +cp go.mod.orig go.mod +! go get vcs-test.golang.org/auth/or401 +stderr '^\tserver response: ACCESS DENIED, buddy$' +# go imports should fail as well. +! go mod tidy +stderr '^\tserver response: ACCESS DENIED, buddy$' + +-- go.mod.orig -- +module private.example.com +-- main.go -- +package useprivate + +import "vcs-test.golang.org/auth/or401" +-- scripts/basic.go -- +package main + +import "fmt" + +func main() { + fmt.Printf("https://vcs-test.golang.org\n\nAuthorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l\n\n") +} +-- scripts/reinvocation.go -- package main import( @@ -45,11 +89,7 @@ import( ) func main() { - arg1 := flag.String("arg1", "", "") flag.Parse() - if *arg1 != "value with spaces" { - log.Fatal("argument with spaces does not work") - } // wait for re-invocation if !strings.HasPrefix(flag.Arg(0), "https://vcs-test.golang.org") { return @@ -68,12 +108,28 @@ func main() { } fmt.Printf("https://vcs-test.golang.org\n\nAuthorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l\n\n") } +-- scripts/arguments.go -- +package main --- auth/go.mod -- -module my-auth --- go.mod.orig -- -module private.example.com --- main.go -- -package useprivate +import( + "flag" + "fmt" + "log" +) -import "vcs-test.golang.org/auth/or401" +func main() { + arg1 := flag.String("arg1", "", "") + flag.Parse() + if *arg1 != "value with spaces" { + log.Fatal("argument with spaces does not work") + } + fmt.Printf("https://vcs-test.golang.org\n\nAuthorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l\n\n") +} +-- scripts/invalid.go -- +package main + +import "fmt" + +func main() { + fmt.Printf("https://vcs-test.golang.org\n\nAuthorization: Basic invalid\n\n") +} \ No newline at end of file From 3104b6adbb36a43284f51ab0cb67c44f8ba75fac Mon Sep 17 00:00:00 2001 From: Jonathan Amsterdam Date: Wed, 11 Dec 2024 14:38:57 -0500 Subject: [PATCH 008/397] log/slog: make DiscardHandler example package-level Fixes #70782. Change-Id: I8e8b763040bd10147eb7d1a30ac0774e28f90911 Reviewed-on: https://go-review.googlesource.com/c/go/+/635217 LUCI-TryBot-Result: Go LUCI Reviewed-by: Ian Lance Taylor --- src/log/slog/example_discard_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/log/slog/example_discard_test.go b/src/log/slog/example_discard_test.go index c0cc2a65aaf8c7..3e3e37b1890908 100644 --- a/src/log/slog/example_discard_test.go +++ b/src/log/slog/example_discard_test.go @@ -10,7 +10,7 @@ import ( "os" ) -func ExampleDiscardHandler() { +func Example_discardHandler() { // A slog.TextHandler can output log messages. logger1 := slog.New(slog.NewTextHandler( os.Stdout, From c93477b5e563dd0ed7b45fd519762f24b7cfa7b0 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Wed, 11 Dec 2024 14:50:00 +0100 Subject: [PATCH 009/397] crypto: use provided random Reader in FIPS mode This removes the difference in behavior between FIPS mode on and off. Instead of the sentinel type we could have moved the Reader to the drbg package and checked for equality, but then we would have locked the crypto/rand.Reader implementation to the one in the FIPS module (which we might have to support for years). In internal/ed25519.GenerateKey we remove the random parameter entirely, since that function is not actually used by crypto/ed25519.GenerateKey, which instead commits to being deterministic. Fixes #70772 Change-Id: Ic1c7ca2c1cd59eb9cd090a8b235c0ce218921ac5 Reviewed-on: https://go-review.googlesource.com/c/go/+/635195 Reviewed-by: Roland Shoemaker Auto-Submit: Filippo Valsorda Reviewed-by: Russ Cox LUCI-TryBot-Result: Go LUCI --- src/crypto/ecdh/nist.go | 5 +++ src/crypto/ecdsa/ecdsa.go | 7 ++++ src/crypto/internal/fips140/drbg/rand.go | 37 +++++++++++++++++++ src/crypto/internal/fips140/ecdh/ecdh.go | 20 +++------- src/crypto/internal/fips140/ecdsa/cast.go | 3 +- src/crypto/internal/fips140/ecdsa/ecdsa.go | 23 ++---------- .../internal/fips140/ed25519/ed25519.go | 19 ++-------- src/crypto/internal/fips140/rsa/keygen.go | 14 ++----- src/crypto/internal/fips140/rsa/pkcs1v22.go | 21 ++--------- .../internal/fips140only/fips140only.go | 7 ++++ src/crypto/internal/fips140test/cast_test.go | 2 +- src/crypto/rand/rand.go | 4 +- src/crypto/rsa/fips.go | 9 +++++ src/crypto/rsa/rsa.go | 3 ++ src/crypto/rsa/rsa_test.go | 4 -- 15 files changed, 94 insertions(+), 84 deletions(-) diff --git a/src/crypto/ecdh/nist.go b/src/crypto/ecdh/nist.go index 0f4a65e5affb80..acef8298943c2b 100644 --- a/src/crypto/ecdh/nist.go +++ b/src/crypto/ecdh/nist.go @@ -8,6 +8,7 @@ import ( "bytes" "crypto/internal/boring" "crypto/internal/fips140/ecdh" + "crypto/internal/fips140only" "errors" "io" ) @@ -43,6 +44,10 @@ func (c *nistCurve) GenerateKey(rand io.Reader) (*PrivateKey, error) { return k, nil } + if fips140only.Enabled && !fips140only.ApprovedRandomReader(rand) { + return nil, errors.New("crypto/ecdh: only crypto/rand.Reader is allowed in FIPS 140-only mode") + } + privateKey, err := c.generate(rand) if err != nil { return nil, err diff --git a/src/crypto/ecdsa/ecdsa.go b/src/crypto/ecdsa/ecdsa.go index 0ad669795c56b2..77727aaf96befb 100644 --- a/src/crypto/ecdsa/ecdsa.go +++ b/src/crypto/ecdsa/ecdsa.go @@ -21,6 +21,7 @@ import ( "crypto/internal/boring" "crypto/internal/boring/bbig" "crypto/internal/fips140/ecdsa" + "crypto/internal/fips140only" "crypto/internal/randutil" "crypto/sha512" "crypto/subtle" @@ -182,6 +183,9 @@ func GenerateKey(c elliptic.Curve, rand io.Reader) (*PrivateKey, error) { } func generateFIPS[P ecdsa.Point[P]](curve elliptic.Curve, c *ecdsa.Curve[P], rand io.Reader) (*PrivateKey, error) { + if fips140only.Enabled && fips140only.ApprovedRandomReader(rand) { + return nil, errors.New("crypto/ecdsa: only crypto/rand.Reader is allowed in FIPS 140-only mode") + } privateKey, err := ecdsa.GenerateKey(c, rand) if err != nil { return nil, err @@ -228,6 +232,9 @@ func SignASN1(rand io.Reader, priv *PrivateKey, hash []byte) ([]byte, error) { } func signFIPS[P ecdsa.Point[P]](c *ecdsa.Curve[P], priv *PrivateKey, rand io.Reader, hash []byte) ([]byte, error) { + if fips140only.Enabled && !fips140only.ApprovedRandomReader(rand) { + return nil, errors.New("crypto/ecdsa: only crypto/rand.Reader is allowed in FIPS 140-only mode") + } // privateKeyToFIPS is very slow in FIPS mode because it performs a // Sign+Verify cycle per FIPS 140-3 IG 10.3.A. We should find a way to cache // it or attach it to the PrivateKey. diff --git a/src/crypto/internal/fips140/drbg/rand.go b/src/crypto/internal/fips140/drbg/rand.go index 736a4b0cc0f4b3..967fb0673ef1a1 100644 --- a/src/crypto/internal/fips140/drbg/rand.go +++ b/src/crypto/internal/fips140/drbg/rand.go @@ -7,7 +7,9 @@ package drbg import ( "crypto/internal/entropy" "crypto/internal/fips140" + "crypto/internal/randutil" "crypto/internal/sysrand" + "io" "sync" ) @@ -56,3 +58,38 @@ func Read(b []byte) { b = b[size:] } } + +// DefaultReader is a sentinel type, embedded in the default +// [crypto/rand.Reader], used to recognize it when passed to +// APIs that accept a rand io.Reader. +type DefaultReader interface{ defaultReader() } + +// ReadWithReader uses Reader to fill b with cryptographically secure random +// bytes. It is intended for use in APIs that expose a rand io.Reader. +// +// If Reader is not the default Reader from crypto/rand, +// [randutil.MaybeReadByte] and [fips140.RecordNonApproved] are called. +func ReadWithReader(r io.Reader, b []byte) error { + if _, ok := r.(DefaultReader); ok { + Read(b) + return nil + } + + fips140.RecordNonApproved() + randutil.MaybeReadByte(r) + _, err := io.ReadFull(r, b) + return err +} + +// ReadWithReaderDeterministic is like ReadWithReader, but it doesn't call +// [randutil.MaybeReadByte] on non-default Readers. +func ReadWithReaderDeterministic(r io.Reader, b []byte) error { + if _, ok := r.(DefaultReader); ok { + Read(b) + return nil + } + + fips140.RecordNonApproved() + _, err := io.ReadFull(r, b) + return err +} diff --git a/src/crypto/internal/fips140/ecdh/ecdh.go b/src/crypto/internal/fips140/ecdh/ecdh.go index 19a45c00db9ce9..bf71c75a92c6eb 100644 --- a/src/crypto/internal/fips140/ecdh/ecdh.go +++ b/src/crypto/internal/fips140/ecdh/ecdh.go @@ -10,7 +10,6 @@ import ( "crypto/internal/fips140/drbg" "crypto/internal/fips140/nistec" "crypto/internal/fips140deps/byteorder" - "crypto/internal/randutil" "errors" "io" "math/bits" @@ -137,8 +136,6 @@ var p521Order = []byte{0x01, 0xff, } // GenerateKey generates a new ECDSA private key pair for the specified curve. -// -// In FIPS mode, rand is ignored. func GenerateKey[P Point[P]](c *Curve[P], rand io.Reader) (*PrivateKey, error) { fips140.RecordApproved() // This procedure is equivalent to Key Pair Generation by Testing @@ -146,18 +143,13 @@ func GenerateKey[P Point[P]](c *Curve[P], rand io.Reader) (*PrivateKey, error) { for { key := make([]byte, len(c.N)) - if fips140.Enabled { - drbg.Read(key) - } else { - randutil.MaybeReadByte(rand) - if _, err := io.ReadFull(rand, key); err != nil { - return nil, err - } - // In tests, rand will return all zeros and NewPrivateKey will reject - // the zero key as it generates the identity as a public key. This also - // makes this function consistent with crypto/elliptic.GenerateKey. - key[1] ^= 0x42 + if err := drbg.ReadWithReader(rand, key); err != nil { + return nil, err } + // In tests, rand will return all zeros and NewPrivateKey will reject + // the zero key as it generates the identity as a public key. This also + // makes this function consistent with crypto/elliptic.GenerateKey. + key[1] ^= 0x42 // Mask off any excess bits if the size of the underlying field is not a // whole number of bytes, which is only the case for P-521. diff --git a/src/crypto/internal/fips140/ecdsa/cast.go b/src/crypto/internal/fips140/ecdsa/cast.go index a324cf929d8bf2..219b7211e74e92 100644 --- a/src/crypto/internal/fips140/ecdsa/cast.go +++ b/src/crypto/internal/fips140/ecdsa/cast.go @@ -54,7 +54,8 @@ func testHash() []byte { func fipsPCT[P Point[P]](c *Curve[P], k *PrivateKey) error { return fips140.PCT("ECDSA PCT", func() error { hash := testHash() - sig, err := Sign(c, sha512.New, k, nil, hash) + drbg := newDRBG(sha512.New, k.d, bits2octets(P256(), hash), nil) + sig, err := sign(c, k, drbg, hash) if err != nil { return err } diff --git a/src/crypto/internal/fips140/ecdsa/ecdsa.go b/src/crypto/internal/fips140/ecdsa/ecdsa.go index 61b40122a0fab4..9459b03de76484 100644 --- a/src/crypto/internal/fips140/ecdsa/ecdsa.go +++ b/src/crypto/internal/fips140/ecdsa/ecdsa.go @@ -10,7 +10,6 @@ import ( "crypto/internal/fips140/bigmod" "crypto/internal/fips140/drbg" "crypto/internal/fips140/nistec" - "crypto/internal/randutil" "errors" "io" "sync" @@ -187,20 +186,11 @@ func NewPublicKey[P Point[P]](c *Curve[P], Q []byte) (*PublicKey, error) { } // GenerateKey generates a new ECDSA private key pair for the specified curve. -// -// In FIPS mode, rand is ignored. func GenerateKey[P Point[P]](c *Curve[P], rand io.Reader) (*PrivateKey, error) { fips140.RecordApproved() k, Q, err := randomPoint(c, func(b []byte) error { - if fips140.Enabled { - drbg.Read(b) - return nil - } else { - randutil.MaybeReadByte(rand) - _, err := io.ReadFull(rand, b) - return err - } + return drbg.ReadWithReader(rand, b) }) if err != nil { return nil, err @@ -281,8 +271,6 @@ type Signature struct { // the hash function H) using the private key, priv. If the hash is longer than // the bit-length of the private key's curve order, the hash will be truncated // to that length. -// -// The signature is randomized. If FIPS mode is enabled, rand is ignored. func Sign[P Point[P], H fips140.Hash](c *Curve[P], h func() H, priv *PrivateKey, rand io.Reader, hash []byte) (*Signature, error) { if priv.pub.curve != c.curve { return nil, errors.New("ecdsa: private key does not match curve") @@ -296,13 +284,8 @@ func Sign[P Point[P], H fips140.Hash](c *Curve[P], h func() H, priv *PrivateKey, // advantage of closely resembling Deterministic ECDSA. Z := make([]byte, len(priv.d)) - if fips140.Enabled { - drbg.Read(Z) - } else { - randutil.MaybeReadByte(rand) - if _, err := io.ReadFull(rand, Z); err != nil { - return nil, err - } + if err := drbg.ReadWithReader(rand, Z); err != nil { + return nil, err } // See https://github.com/cfrg/draft-irtf-cfrg-det-sigs-with-noise/issues/6 diff --git a/src/crypto/internal/fips140/ed25519/ed25519.go b/src/crypto/internal/fips140/ed25519/ed25519.go index 9824cbdf814926..bbdc5b4a8ba2f9 100644 --- a/src/crypto/internal/fips140/ed25519/ed25519.go +++ b/src/crypto/internal/fips140/ed25519/ed25519.go @@ -11,7 +11,6 @@ import ( "crypto/internal/fips140/edwards25519" "crypto/internal/fips140/sha512" "errors" - "io" "strconv" ) @@ -61,24 +60,14 @@ func (pub *PublicKey) Bytes() []byte { } // GenerateKey generates a new Ed25519 private key pair. -// -// In FIPS mode, rand is ignored. Otherwise, the output of this function is -// deterministic, and equivalent to reading 32 bytes from rand, and passing them -// to [NewKeyFromSeed]. -func GenerateKey(rand io.Reader) (*PrivateKey, error) { +func GenerateKey() (*PrivateKey, error) { priv := &PrivateKey{} - return generateKey(priv, rand) + return generateKey(priv) } -func generateKey(priv *PrivateKey, rand io.Reader) (*PrivateKey, error) { +func generateKey(priv *PrivateKey) (*PrivateKey, error) { fips140.RecordApproved() - if fips140.Enabled { - drbg.Read(priv.seed[:]) - } else { - if _, err := io.ReadFull(rand, priv.seed[:]); err != nil { - return nil, err - } - } + drbg.Read(priv.seed[:]) precomputePrivateKey(priv) if err := fipsPCT(priv); err != nil { // This clearly can't happen, but FIPS 140-3 requires that we check. diff --git a/src/crypto/internal/fips140/rsa/keygen.go b/src/crypto/internal/fips140/rsa/keygen.go index a9e12eb1e8e920..df76772ef5878d 100644 --- a/src/crypto/internal/fips140/rsa/keygen.go +++ b/src/crypto/internal/fips140/rsa/keygen.go @@ -8,15 +8,12 @@ import ( "crypto/internal/fips140" "crypto/internal/fips140/bigmod" "crypto/internal/fips140/drbg" - "crypto/internal/randutil" "errors" "io" ) // GenerateKey generates a new RSA key pair of the given bit size. // bits must be at least 128. -// -// When operating in FIPS mode, rand is ignored. func GenerateKey(rand io.Reader, bits int) (*PrivateKey, error) { if bits < 128 { return nil, errors.New("rsa: key too small") @@ -94,7 +91,7 @@ func GenerateKey(rand io.Reader, bits int) (*PrivateKey, error) { } // randomPrime returns a random prime number of the given bit size following -// the process in FIPS 186-5, Appendix A.1.3. rand is ignored in FIPS mode. +// the process in FIPS 186-5, Appendix A.1.3. func randomPrime(rand io.Reader, bits int) ([]byte, error) { if bits < 64 { return nil, errors.New("rsa: prime size must be at least 32-bit") @@ -102,13 +99,8 @@ func randomPrime(rand io.Reader, bits int) ([]byte, error) { b := make([]byte, (bits+7)/8) for { - if fips140.Enabled { - drbg.Read(b) - } else { - randutil.MaybeReadByte(rand) - if _, err := io.ReadFull(rand, b); err != nil { - return nil, err - } + if err := drbg.ReadWithReader(rand, b); err != nil { + return nil, err } if excess := len(b)*8 - bits; excess != 0 { b[0] >>= excess diff --git a/src/crypto/internal/fips140/rsa/pkcs1v22.go b/src/crypto/internal/fips140/rsa/pkcs1v22.go index a62d7e485f6df7..a5bc56dafcd9ff 100644 --- a/src/crypto/internal/fips140/rsa/pkcs1v22.go +++ b/src/crypto/internal/fips140/rsa/pkcs1v22.go @@ -264,8 +264,6 @@ func PSSMaxSaltLength(pub *PublicKey, hash fips140.Hash) (int, error) { } // SignPSS calculates the signature of hashed using RSASSA-PSS. -// -// In FIPS mode, rand is ignored and can be nil. func SignPSS(rand io.Reader, priv *PrivateKey, hash fips140.Hash, hashed []byte, saltLength int) ([]byte, error) { fipsSelfTest() fips140.RecordApproved() @@ -286,12 +284,8 @@ func SignPSS(rand io.Reader, priv *PrivateKey, hash fips140.Hash, hashed []byte, fips140.RecordNonApproved() } salt := make([]byte, saltLength) - if fips140.Enabled { - drbg.Read(salt) - } else { - if _, err := io.ReadFull(rand, salt); err != nil { - return nil, err - } + if err := drbg.ReadWithReaderDeterministic(rand, salt); err != nil { + return nil, err } emBits := priv.pub.N.BitLen() - 1 @@ -374,8 +368,6 @@ func checkApprovedHash(hash fips140.Hash) { } // EncryptOAEP encrypts the given message with RSAES-OAEP. -// -// In FIPS mode, random is ignored and can be nil. func EncryptOAEP(hash, mgfHash fips140.Hash, random io.Reader, pub *PublicKey, msg []byte, label []byte) ([]byte, error) { // Note that while we don't commit to deterministic execution with respect // to the random stream, we also don't apply MaybeReadByte, so per Hyrum's @@ -408,13 +400,8 @@ func EncryptOAEP(hash, mgfHash fips140.Hash, random io.Reader, pub *PublicKey, m db[len(db)-len(msg)-1] = 1 copy(db[len(db)-len(msg):], msg) - if fips140.Enabled { - drbg.Read(seed) - } else { - _, err := io.ReadFull(random, seed) - if err != nil { - return nil, err - } + if err := drbg.ReadWithReaderDeterministic(random, seed); err != nil { + return nil, err } mgf1XOR(db, mgfHash, seed) diff --git a/src/crypto/internal/fips140only/fips140only.go b/src/crypto/internal/fips140only/fips140only.go index 6ad97befbe06da..7126781af0d8bc 100644 --- a/src/crypto/internal/fips140only/fips140only.go +++ b/src/crypto/internal/fips140only/fips140only.go @@ -5,11 +5,13 @@ package fips140only import ( + "crypto/internal/fips140/drbg" "crypto/internal/fips140/sha256" "crypto/internal/fips140/sha3" "crypto/internal/fips140/sha512" "hash" "internal/godebug" + "io" ) // Enabled reports whether FIPS 140-only mode is enabled, in which non-approved @@ -24,3 +26,8 @@ func ApprovedHash(h hash.Hash) bool { return false } } + +func ApprovedRandomReader(r io.Reader) bool { + _, ok := r.(drbg.DefaultReader) + return ok +} diff --git a/src/crypto/internal/fips140test/cast_test.go b/src/crypto/internal/fips140test/cast_test.go index c6e3212f3f064f..b2aee15eab70f5 100644 --- a/src/crypto/internal/fips140test/cast_test.go +++ b/src/crypto/internal/fips140test/cast_test.go @@ -85,7 +85,7 @@ func TestConditionals(t *testing.T) { t.Fatal(err) } ecdsa.SignDeterministic(ecdsa.P256(), sha256.New, kDSA, make([]byte, 32)) - k25519, err := ed25519.GenerateKey(rand.Reader) + k25519, err := ed25519.GenerateKey() if err != nil { t.Fatal(err) } diff --git a/src/crypto/rand/rand.go b/src/crypto/rand/rand.go index 5dd875e6e72575..1ca16caa9563e6 100644 --- a/src/crypto/rand/rand.go +++ b/src/crypto/rand/rand.go @@ -38,7 +38,9 @@ func init() { Reader = &reader{} } -type reader struct{} +type reader struct { + drbg.DefaultReader +} func (r *reader) Read(b []byte) (n int, err error) { boring.Unreachable() diff --git a/src/crypto/rsa/fips.go b/src/crypto/rsa/fips.go index bc23d597098f0c..24dfb38cf625bd 100644 --- a/src/crypto/rsa/fips.go +++ b/src/crypto/rsa/fips.go @@ -17,6 +17,9 @@ import ( const ( // PSSSaltLengthAuto causes the salt in a PSS signature to be as large // as possible when signing, and to be auto-detected when verifying. + // + // When signing in FIPS 140-3 mode, the salt length is capped at the length + // of the hash function used in the signature. PSSSaltLengthAuto = 0 // PSSSaltLengthEqualsHash causes the salt length to equal the length // of the hash used in the signature. @@ -67,6 +70,9 @@ func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, digest []byte, if fips140only.Enabled && !fips140only.ApprovedHash(hash.New()) { return nil, errors.New("crypto/rsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode") } + if fips140only.Enabled && !fips140only.ApprovedRandomReader(rand) { + return nil, errors.New("crypto/rsa: only crypto/rand.Reader is allowed in FIPS 140-only mode") + } if opts != nil && opts.Hash != 0 { hash = opts.Hash @@ -188,6 +194,9 @@ func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, l if fips140only.Enabled && !fips140only.ApprovedHash(hash) { return nil, errors.New("crypto/rsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode") } + if fips140only.Enabled && !fips140only.ApprovedRandomReader(random) { + return nil, errors.New("crypto/rsa: only crypto/rand.Reader is allowed in FIPS 140-only mode") + } defer hash.Reset() diff --git a/src/crypto/rsa/rsa.go b/src/crypto/rsa/rsa.go index 0f58f2226f848e..fb23f003a6f217 100644 --- a/src/crypto/rsa/rsa.go +++ b/src/crypto/rsa/rsa.go @@ -322,6 +322,9 @@ func GenerateKey(random io.Reader, bits int) (*PrivateKey, error) { if fips140only.Enabled && bits%2 == 1 { return nil, errors.New("crypto/rsa: use of keys with odd size is not allowed in FIPS 140-only mode") } + if fips140only.Enabled && !fips140only.ApprovedRandomReader(random) { + return nil, errors.New("crypto/rsa: only crypto/rand.Reader is allowed in FIPS 140-only mode") + } k, err := rsa.GenerateKey(random, bits) if err != nil { diff --git a/src/crypto/rsa/rsa_test.go b/src/crypto/rsa/rsa_test.go index c395732c8b27b8..2474ab82dfa207 100644 --- a/src/crypto/rsa/rsa_test.go +++ b/src/crypto/rsa/rsa_test.go @@ -10,7 +10,6 @@ import ( "crypto" "crypto/internal/boring" "crypto/internal/cryptotest" - "crypto/internal/fips140" "crypto/rand" . "crypto/rsa" "crypto/sha1" @@ -782,9 +781,6 @@ type testEncryptOAEPStruct struct { } func TestEncryptOAEP(t *testing.T) { - if fips140.Enabled { - t.Skip("FIPS mode overrides the deterministic random source") - } sha1 := sha1.New() n := new(big.Int) for i, test := range testEncryptOAEPData { From 0ca521f9c1a6357578b501615f073adb2da6b527 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 10 Dec 2024 19:48:11 -0800 Subject: [PATCH 010/397] debug/elf: adjust version API per issue discussion This updates the new version API for the discussion on #63952. This change reveals that in fact none of the tests set the VERSYM_HIDDEN bit. The code before this CL set the hidden flag for symbols that appear in DynamicVersionNeed, but that is not an accurate representation of the ELF. The readelf program does print undefined symbols that way (with a single '@'), but that doesn't mean that the hidden flag is set. Leaving tests with the hidden bit set for later. For #63952 Change-Id: Ida60831e0c9922dfc10f10c7a64bc76a2b197537 Reviewed-on: https://go-review.googlesource.com/c/go/+/635079 Reviewed-by: Austin Clements Commit-Queue: Ian Lance Taylor Auto-Submit: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Reviewed-by: Ian Lance Taylor --- api/go1.24.txt | 27 +-- src/debug/elf/file.go | 178 ++++++++++------ src/debug/elf/file_test.go | 384 +++++++++++++++++----------------- src/debug/elf/symbols_test.go | 242 ++++++++++----------- 4 files changed, 440 insertions(+), 391 deletions(-) diff --git a/api/go1.24.txt b/api/go1.24.txt index 64ede33af25b7a..795a70e3547695 100644 --- a/api/go1.24.txt +++ b/api/go1.24.txt @@ -106,33 +106,34 @@ pkg debug/elf, const VER_FLG_INFO = 4 #63952 pkg debug/elf, const VER_FLG_INFO DynamicVersionFlag #63952 pkg debug/elf, const VER_FLG_WEAK = 2 #63952 pkg debug/elf, const VER_FLG_WEAK DynamicVersionFlag #63952 -pkg debug/elf, const VerFlagGlobal = 2 #63952 -pkg debug/elf, const VerFlagGlobal SymbolVersionFlag #63952 -pkg debug/elf, const VerFlagHidden = 4 #63952 -pkg debug/elf, const VerFlagHidden SymbolVersionFlag #63952 -pkg debug/elf, const VerFlagLocal = 1 #63952 -pkg debug/elf, const VerFlagLocal SymbolVersionFlag #63952 -pkg debug/elf, const VerFlagNone = 0 #63952 -pkg debug/elf, const VerFlagNone SymbolVersionFlag #63952 +pkg debug/elf, const VersionScopeGlobal = 2 #63952 +pkg debug/elf, const VersionScopeGlobal SymbolVersionScope #63952 +pkg debug/elf, const VersionScopeHidden = 4 #63952 +pkg debug/elf, const VersionScopeHidden SymbolVersionScope #63952 +pkg debug/elf, const VersionScopeLocal = 1 #63952 +pkg debug/elf, const VersionScopeLocal SymbolVersionScope #63952 +pkg debug/elf, const VersionScopeNone = 0 #63952 +pkg debug/elf, const VersionScopeNone SymbolVersionScope #63952 +pkg debug/elf, const VersionScopeSpecific = 3 #63952 +pkg debug/elf, const VersionScopeSpecific SymbolVersionScope #63952 pkg debug/elf, method (*File) DynamicVersionNeeds() ([]DynamicVersionNeed, error) #63952 pkg debug/elf, method (*File) DynamicVersions() ([]DynamicVersion, error) #63952 pkg debug/elf, type DynamicVersion struct #63952 pkg debug/elf, type DynamicVersion struct, Deps []string #63952 pkg debug/elf, type DynamicVersion struct, Flags DynamicVersionFlag #63952 +pkg debug/elf, type DynamicVersion struct, Name string #63952 pkg debug/elf, type DynamicVersion struct, Index uint16 #63952 -pkg debug/elf, type DynamicVersion struct, Version uint16 #63952 pkg debug/elf, type DynamicVersionDep struct #63952 pkg debug/elf, type DynamicVersionDep struct, Dep string #63952 pkg debug/elf, type DynamicVersionDep struct, Flags DynamicVersionFlag #63952 -pkg debug/elf, type DynamicVersionDep struct, Other uint16 #63952 +pkg debug/elf, type DynamicVersionDep struct, Index uint16 #63952 pkg debug/elf, type DynamicVersionFlag uint16 #63952 pkg debug/elf, type DynamicVersionNeed struct #63952 pkg debug/elf, type DynamicVersionNeed struct, Name string #63952 pkg debug/elf, type DynamicVersionNeed struct, Needs []DynamicVersionDep #63952 -pkg debug/elf, type DynamicVersionNeed struct, Version uint16 #63952 -pkg debug/elf, type Symbol struct, VersionFlags SymbolVersionFlag #63952 +pkg debug/elf, type Symbol struct, VersionScope SymbolVersionScope #63952 pkg debug/elf, type Symbol struct, VersionIndex int16 #63952 -pkg debug/elf, type SymbolVersionFlag uint8 #63952 +pkg debug/elf, type SymbolVersionScope uint8 #63952 pkg encoding, type BinaryAppender interface { AppendBinary } #62384 pkg encoding, type BinaryAppender interface, AppendBinary([]uint8) ([]uint8, error) #62384 pkg encoding, type TextAppender interface { AppendText } #62384 diff --git a/src/debug/elf/file.go b/src/debug/elf/file.go index aa523c3fae910c..958ed9971d070b 100644 --- a/src/debug/elf/file.go +++ b/src/debug/elf/file.go @@ -209,10 +209,22 @@ type Symbol struct { Name string Info, Other byte - // These fields are used for symbol versioning - // and are present only for the dynamic symbol table. + // VersionScope describes the version in which the symbol is defined. + // This is only set for the dynamic symbol table. + // When no symbol versioning information is available, + // this is VersionScopeNone. + VersionScope SymbolVersionScope + // VersionIndex is the version index. + // This is only set if VersionScope is VersionScopeSpecific or + // VersionScopeHidden. This is only set for the dynamic symbol table. + // This index will match either [DynamicVersion.Index] + // in the slice returned by [File.DynamicVersions], + // or [DynamicVersiondep.Index] in the Needs field + // of the elements of the slice returned by [File.DynamicVersionNeeds]. + // In general, a defined symbol will have an index referring + // to DynamicVersions, and an undefined symbol will have an index + // referring to some version in DynamicVersionNeeds. VersionIndex int16 - VersionFlags SymbolVersionFlag Section SectionIndex Value, Size uint64 @@ -1455,9 +1467,13 @@ func (f *File) DynamicSymbols() ([]Symbol, error) { if err != nil { return nil, err } - if f.gnuVersionInit(str) { + hasVersions, err := f.gnuVersionInit(str) + if err != nil { + return nil, err + } + if hasVersions { for i := range sym { - sym[i].VersionIndex, sym[i].Version, sym[i].Library, sym[i].VersionFlags = f.gnuVersion(i) + sym[i].VersionIndex, sym[i].Version, sym[i].Library, sym[i].VersionScope = f.gnuVersion(i) } } return sym, nil @@ -1478,7 +1494,9 @@ func (f *File) ImportedSymbols() ([]ImportedSymbol, error) { if err != nil { return nil, err } - f.gnuVersionInit(str) + if _, err := f.gnuVersionInit(str); err != nil { + return nil, err + } var all []ImportedSymbol for i, s := range sym { if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF { @@ -1490,46 +1508,57 @@ func (f *File) ImportedSymbols() ([]ImportedSymbol, error) { return all, nil } -type SymbolVersionFlag byte +// SymbolVersionScope describes the version in which a [Symbol] is defined. +// This is only used for the dynamic symbol table. +type SymbolVersionScope byte const ( - VerFlagNone SymbolVersionFlag = 0x0 // No flags. - VerFlagLocal SymbolVersionFlag = 0x1 // Symbol has local scope. - VerFlagGlobal SymbolVersionFlag = 0x2 // Symbol has global scope. - VerFlagHidden SymbolVersionFlag = 0x4 // Symbol is hidden. + VersionScopeNone SymbolVersionScope = iota // no symbol version available + VersionScopeLocal // symbol has local scope + VersionScopeGlobal // symbol has global scope and is in the base version + VersionScopeSpecific // symbol has global scope and is in the version given by VersionIndex + VersionScopeHidden // symbol is in the version given by VersionIndex, and is hidden ) // DynamicVersion is a version defined by a dynamic object. +// This describes entries in the ELF SHT_GNU_verdef section. +// We assume that the vd_version field is 1. +// Note that the name of the version appears here; +// it is not in the first Deps entry as it is in the ELF file. type DynamicVersion struct { - Version uint16 // Version of data structure. - Flags DynamicVersionFlag - Index uint16 // Version index. - Deps []string // Dependencies. + Name string // Name of version defined by this index. + Index uint16 // Version index. + Flags DynamicVersionFlag + Deps []string // Names of versions that this version depends upon. } +// DynamicVersionNeed describes a shared library needed by a dynamic object, +// with a list of the versions needed from that shared library. +// This describes entries in the ELF SHT_GNU_verneed section. +// We assume that the vn_version field is 1. type DynamicVersionNeed struct { - Version uint16 // Version of data structure. - Name string // Shared library name. - Needs []DynamicVersionDep // Dependencies. + Name string // Shared library name. + Needs []DynamicVersionDep // Dependencies. } +// DynamicVersionDep is a version needed from some shared library. type DynamicVersionDep struct { Flags DynamicVersionFlag - Other uint16 // Version index. + Index uint16 // Version index. Dep string // Name of required version. } // dynamicVersions returns version information for a dynamic object. -func (f *File) dynamicVersions(str []byte) bool { +func (f *File) dynamicVersions(str []byte) error { if f.dynVers != nil { // Already initialized. - return true + return nil } // Accumulate verdef information. vd := f.SectionByType(SHT_GNU_VERDEF) if vd == nil { - return false + return nil } d, _ := vd.Data() @@ -1540,12 +1569,20 @@ func (f *File) dynamicVersions(str []byte) bool { break } version := f.ByteOrder.Uint16(d[i : i+2]) + if version != 1 { + return &FormatError{int64(vd.Offset + uint64(i)), "unexpected dynamic version", version} + } flags := DynamicVersionFlag(f.ByteOrder.Uint16(d[i+2 : i+4])) ndx := f.ByteOrder.Uint16(d[i+4 : i+6]) cnt := f.ByteOrder.Uint16(d[i+6 : i+8]) aux := f.ByteOrder.Uint32(d[i+12 : i+16]) next := f.ByteOrder.Uint32(d[i+16 : i+20]) + if cnt == 0 { + return &FormatError{int64(vd.Offset + uint64(i)), "dynamic version has no name", nil} + } + + var name string var depName string var deps []string j := i + int(aux) @@ -1557,16 +1594,20 @@ func (f *File) dynamicVersions(str []byte) bool { vnext := f.ByteOrder.Uint32(d[j+4 : j+8]) depName, _ = getString(str, int(vname)) - deps = append(deps, depName) + if c == 0 { + name = depName + } else { + deps = append(deps, depName) + } j += int(vnext) } dynVers = append(dynVers, DynamicVersion{ - Version: version, - Flags: flags, - Index: ndx, - Deps: deps, + Name: name, + Index: ndx, + Flags: flags, + Deps: deps, }) if next == 0 { @@ -1577,7 +1618,7 @@ func (f *File) dynamicVersions(str []byte) bool { f.dynVers = dynVers - return true + return nil } // DynamicVersions returns version information for a dynamic object. @@ -1587,7 +1628,11 @@ func (f *File) DynamicVersions() ([]DynamicVersion, error) { if err != nil { return nil, err } - if !f.gnuVersionInit(str) { + hasVersions, err := f.gnuVersionInit(str) + if err != nil { + return nil, err + } + if !hasVersions { return nil, errors.New("DynamicVersions: missing version table") } } @@ -1596,16 +1641,16 @@ func (f *File) DynamicVersions() ([]DynamicVersion, error) { } // dynamicVersionNeeds returns version dependencies for a dynamic object. -func (f *File) dynamicVersionNeeds(str []byte) bool { +func (f *File) dynamicVersionNeeds(str []byte) error { if f.dynVerNeeds != nil { // Already initialized. - return true + return nil } // Accumulate verneed information. vn := f.SectionByType(SHT_GNU_VERNEED) if vn == nil { - return false + return nil } d, _ := vn.Data() @@ -1617,7 +1662,7 @@ func (f *File) dynamicVersionNeeds(str []byte) bool { } vers := f.ByteOrder.Uint16(d[i : i+2]) if vers != 1 { - break + return &FormatError{int64(vn.Offset + uint64(i)), "unexpected dynamic need version", vers} } cnt := f.ByteOrder.Uint16(d[i+2 : i+4]) fileoff := f.ByteOrder.Uint32(d[i+4 : i+8]) @@ -1632,14 +1677,14 @@ func (f *File) dynamicVersionNeeds(str []byte) bool { break } flags := DynamicVersionFlag(f.ByteOrder.Uint16(d[j+4 : j+6])) - other := f.ByteOrder.Uint16(d[j+6 : j+8]) + index := f.ByteOrder.Uint16(d[j+6 : j+8]) nameoff := f.ByteOrder.Uint32(d[j+8 : j+12]) next := f.ByteOrder.Uint32(d[j+12 : j+16]) depName, _ := getString(str, int(nameoff)) deps = append(deps, DynamicVersionDep{ Flags: flags, - Other: other, + Index: index, Dep: depName, }) @@ -1650,9 +1695,8 @@ func (f *File) dynamicVersionNeeds(str []byte) bool { } dynVerNeeds = append(dynVerNeeds, DynamicVersionNeed{ - Version: vers, - Name: file, - Needs: deps, + Name: file, + Needs: deps, }) if next == 0 { @@ -1663,7 +1707,7 @@ func (f *File) dynamicVersionNeeds(str []byte) bool { f.dynVerNeeds = dynVerNeeds - return true + return nil } // DynamicVersionNeeds returns version dependencies for a dynamic object. @@ -1673,7 +1717,11 @@ func (f *File) DynamicVersionNeeds() ([]DynamicVersionNeed, error) { if err != nil { return nil, err } - if !f.gnuVersionInit(str) { + hasVersions, err := f.gnuVersionInit(str) + if err != nil { + return nil, err + } + if !hasVersions { return nil, errors.New("DynamicVersionNeeds: missing version table") } } @@ -1683,66 +1731,66 @@ func (f *File) DynamicVersionNeeds() ([]DynamicVersionNeed, error) { // gnuVersionInit parses the GNU version tables // for use by calls to gnuVersion. -func (f *File) gnuVersionInit(str []byte) bool { +// It reports whether any version tables were found. +func (f *File) gnuVersionInit(str []byte) (bool, error) { // Versym parallels symbol table, indexing into verneed. vs := f.SectionByType(SHT_GNU_VERSYM) if vs == nil { - return false + return false, nil } d, _ := vs.Data() f.gnuVersym = d - f.dynamicVersions(str) - f.dynamicVersionNeeds(str) - return true + if err := f.dynamicVersions(str); err != nil { + return false, err + } + if err := f.dynamicVersionNeeds(str); err != nil { + return false, err + } + return true, nil } // gnuVersion adds Library and Version information to sym, // which came from offset i of the symbol table. -func (f *File) gnuVersion(i int) (versionIndex int16, version string, library string, versionFlags SymbolVersionFlag) { +func (f *File) gnuVersion(i int) (versionIndex int16, version string, library string, versionFlags SymbolVersionScope) { // Each entry is two bytes; skip undef entry at beginning. i = (i + 1) * 2 if i >= len(f.gnuVersym) { - return -1, "", "", VerFlagNone + return -1, "", "", VersionScopeNone } s := f.gnuVersym[i:] if len(s) < 2 { - return -1, "", "", VerFlagNone + return -1, "", "", VersionScopeNone } j := int32(f.ByteOrder.Uint16(s)) - var ndx = int16(j & 0x7fff) + ndx := int16(j & 0x7fff) - if ndx == 0 { - return ndx, "", "", VerFlagLocal - } else if ndx == 1 { - return ndx, "", "", VerFlagGlobal + if j == 0 { + return ndx, "", "", VersionScopeLocal + } else if j == 1 { + return ndx, "", "", VersionScopeGlobal } - if ndx < 2 { - return 0, "", "", VerFlagNone + scope := VersionScopeSpecific + if j&0x8000 != 0 { + scope = VersionScopeHidden } for _, v := range f.dynVerNeeds { for _, n := range v.Needs { - if uint16(ndx) == n.Other { - return ndx, n.Dep, v.Name, VerFlagHidden + if uint16(ndx) == n.Index { + return ndx, n.Dep, v.Name, scope } } } for _, v := range f.dynVers { if uint16(ndx) == v.Index { - if len(v.Deps) > 0 { - flags := VerFlagNone - if j&0x8000 != 0 { - flags = VerFlagHidden - } - return ndx, v.Deps[0], "", flags - } + return ndx, v.Name, "", scope } } - return -1, "", "", VerFlagNone + return -1, "", "", VersionScopeNone } // ImportedLibraries returns the names of all libraries diff --git a/src/debug/elf/file_test.go b/src/debug/elf/file_test.go index 55d58b323405cd..72e45588682b55 100644 --- a/src/debug/elf/file_test.go +++ b/src/debug/elf/file_test.go @@ -78,80 +78,80 @@ var fileTests = []fileTest{ }, []string{"libc.so.6"}, []Symbol{ - {"", 3, 0, -1, VerFlagNone, 1, 134512852, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 2, 134512876, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 3, 134513020, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 4, 134513292, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 5, 134513480, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 6, 134513512, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 7, 134513532, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 8, 134513612, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 9, 134513996, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 10, 134514008, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 11, 134518268, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 12, 134518280, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 13, 134518284, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 14, 134518436, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 15, 134518444, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 16, 134518452, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 17, 134518456, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 18, 134518484, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 19, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 20, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 21, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 22, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 23, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 24, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 25, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 26, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 27, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 28, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 29, 0, 0, "", ""}, - {"crt1.c", 4, 0, -1, VerFlagNone, 65521, 0, 0, "", ""}, - {"/usr/src/lib/csu/i386-elf/crti.S", 4, 0, -1, VerFlagNone, 65521, 0, 0, "", ""}, - {"", 4, 0, -1, VerFlagNone, 65521, 0, 0, "", ""}, - {"", 4, 0, -1, VerFlagNone, 65521, 0, 0, "", ""}, - {"/usr/src/lib/csu/i386-elf/crti.S", 4, 0, -1, VerFlagNone, 65521, 0, 0, "", ""}, - {"crtstuff.c", 4, 0, -1, VerFlagNone, 65521, 0, 0, "", ""}, - {"__CTOR_LIST__", 1, 0, -1, VerFlagNone, 14, 134518436, 0, "", ""}, - {"__DTOR_LIST__", 1, 0, -1, VerFlagNone, 15, 134518444, 0, "", ""}, - {"__EH_FRAME_BEGIN__", 1, 0, -1, VerFlagNone, 12, 134518280, 0, "", ""}, - {"__JCR_LIST__", 1, 0, -1, VerFlagNone, 16, 134518452, 0, "", ""}, - {"p.0", 1, 0, -1, VerFlagNone, 11, 134518276, 0, "", ""}, - {"completed.1", 1, 0, -1, VerFlagNone, 18, 134518484, 1, "", ""}, - {"__do_global_dtors_aux", 2, 0, -1, VerFlagNone, 8, 134513760, 0, "", ""}, - {"object.2", 1, 0, -1, VerFlagNone, 18, 134518488, 24, "", ""}, - {"frame_dummy", 2, 0, -1, VerFlagNone, 8, 134513836, 0, "", ""}, - {"crtstuff.c", 4, 0, -1, VerFlagNone, 65521, 0, 0, "", ""}, - {"__CTOR_END__", 1, 0, -1, VerFlagNone, 14, 134518440, 0, "", ""}, - {"__DTOR_END__", 1, 0, -1, VerFlagNone, 15, 134518448, 0, "", ""}, - {"__FRAME_END__", 1, 0, -1, VerFlagNone, 12, 134518280, 0, "", ""}, - {"__JCR_END__", 1, 0, -1, VerFlagNone, 16, 134518452, 0, "", ""}, - {"__do_global_ctors_aux", 2, 0, -1, VerFlagNone, 8, 134513960, 0, "", ""}, - {"/usr/src/lib/csu/i386-elf/crtn.S", 4, 0, -1, VerFlagNone, 65521, 0, 0, "", ""}, - {"", 4, 0, -1, VerFlagNone, 65521, 0, 0, "", ""}, - {"", 4, 0, -1, VerFlagNone, 65521, 0, 0, "", ""}, - {"/usr/src/lib/csu/i386-elf/crtn.S", 4, 0, -1, VerFlagNone, 65521, 0, 0, "", ""}, - {"hello.c", 4, 0, -1, VerFlagNone, 65521, 0, 0, "", ""}, - {"printf", 18, 0, -1, VerFlagNone, 0, 0, 44, "", ""}, - {"_DYNAMIC", 17, 0, -1, VerFlagNone, 65521, 134518284, 0, "", ""}, - {"__dso_handle", 17, 2, -1, VerFlagNone, 11, 134518272, 0, "", ""}, - {"_init", 18, 0, -1, VerFlagNone, 6, 134513512, 0, "", ""}, - {"environ", 17, 0, -1, VerFlagNone, 18, 134518512, 4, "", ""}, - {"__deregister_frame_info", 32, 0, -1, VerFlagNone, 0, 0, 0, "", ""}, - {"__progname", 17, 0, -1, VerFlagNone, 11, 134518268, 4, "", ""}, - {"_start", 18, 0, -1, VerFlagNone, 8, 134513612, 145, "", ""}, - {"__bss_start", 16, 0, -1, VerFlagNone, 65521, 134518484, 0, "", ""}, - {"main", 18, 0, -1, VerFlagNone, 8, 134513912, 46, "", ""}, - {"_init_tls", 18, 0, -1, VerFlagNone, 0, 0, 5, "", ""}, - {"_fini", 18, 0, -1, VerFlagNone, 9, 134513996, 0, "", ""}, - {"atexit", 18, 0, -1, VerFlagNone, 0, 0, 43, "", ""}, - {"_edata", 16, 0, -1, VerFlagNone, 65521, 134518484, 0, "", ""}, - {"_GLOBAL_OFFSET_TABLE_", 17, 0, -1, VerFlagNone, 65521, 134518456, 0, "", ""}, - {"_end", 16, 0, -1, VerFlagNone, 65521, 134518516, 0, "", ""}, - {"exit", 18, 0, -1, VerFlagNone, 0, 0, 68, "", ""}, - {"_Jv_RegisterClasses", 32, 0, -1, VerFlagNone, 0, 0, 0, "", ""}, - {"__register_frame_info", 32, 0, -1, VerFlagNone, 0, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 1, 134512852, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 2, 134512876, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 3, 134513020, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 4, 134513292, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 5, 134513480, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 6, 134513512, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 7, 134513532, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 8, 134513612, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 9, 134513996, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 10, 134514008, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 11, 134518268, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 12, 134518280, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 13, 134518284, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 14, 134518436, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 15, 134518444, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 16, 134518452, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 17, 134518456, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 18, 134518484, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 19, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 20, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 21, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 22, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 23, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 24, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 25, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 26, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 27, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 28, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 29, 0, 0, "", ""}, + {"crt1.c", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, + {"/usr/src/lib/csu/i386-elf/crti.S", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, + {"", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, + {"", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, + {"/usr/src/lib/csu/i386-elf/crti.S", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, + {"crtstuff.c", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, + {"__CTOR_LIST__", 1, 0, VersionScopeNone, -1, 14, 134518436, 0, "", ""}, + {"__DTOR_LIST__", 1, 0, VersionScopeNone, -1, 15, 134518444, 0, "", ""}, + {"__EH_FRAME_BEGIN__", 1, 0, VersionScopeNone, -1, 12, 134518280, 0, "", ""}, + {"__JCR_LIST__", 1, 0, VersionScopeNone, -1, 16, 134518452, 0, "", ""}, + {"p.0", 1, 0, VersionScopeNone, -1, 11, 134518276, 0, "", ""}, + {"completed.1", 1, 0, VersionScopeNone, -1, 18, 134518484, 1, "", ""}, + {"__do_global_dtors_aux", 2, 0, VersionScopeNone, -1, 8, 134513760, 0, "", ""}, + {"object.2", 1, 0, VersionScopeNone, -1, 18, 134518488, 24, "", ""}, + {"frame_dummy", 2, 0, VersionScopeNone, -1, 8, 134513836, 0, "", ""}, + {"crtstuff.c", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, + {"__CTOR_END__", 1, 0, VersionScopeNone, -1, 14, 134518440, 0, "", ""}, + {"__DTOR_END__", 1, 0, VersionScopeNone, -1, 15, 134518448, 0, "", ""}, + {"__FRAME_END__", 1, 0, VersionScopeNone, -1, 12, 134518280, 0, "", ""}, + {"__JCR_END__", 1, 0, VersionScopeNone, -1, 16, 134518452, 0, "", ""}, + {"__do_global_ctors_aux", 2, 0, VersionScopeNone, -1, 8, 134513960, 0, "", ""}, + {"/usr/src/lib/csu/i386-elf/crtn.S", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, + {"", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, + {"", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, + {"/usr/src/lib/csu/i386-elf/crtn.S", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, + {"hello.c", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, + {"printf", 18, 0, VersionScopeNone, -1, 0, 0, 44, "", ""}, + {"_DYNAMIC", 17, 0, VersionScopeNone, -1, 65521, 134518284, 0, "", ""}, + {"__dso_handle", 17, 2, VersionScopeNone, -1, 11, 134518272, 0, "", ""}, + {"_init", 18, 0, VersionScopeNone, -1, 6, 134513512, 0, "", ""}, + {"environ", 17, 0, VersionScopeNone, -1, 18, 134518512, 4, "", ""}, + {"__deregister_frame_info", 32, 0, VersionScopeNone, -1, 0, 0, 0, "", ""}, + {"__progname", 17, 0, VersionScopeNone, -1, 11, 134518268, 4, "", ""}, + {"_start", 18, 0, VersionScopeNone, -1, 8, 134513612, 145, "", ""}, + {"__bss_start", 16, 0, VersionScopeNone, -1, 65521, 134518484, 0, "", ""}, + {"main", 18, 0, VersionScopeNone, -1, 8, 134513912, 46, "", ""}, + {"_init_tls", 18, 0, VersionScopeNone, -1, 0, 0, 5, "", ""}, + {"_fini", 18, 0, VersionScopeNone, -1, 9, 134513996, 0, "", ""}, + {"atexit", 18, 0, VersionScopeNone, -1, 0, 0, 43, "", ""}, + {"_edata", 16, 0, VersionScopeNone, -1, 65521, 134518484, 0, "", ""}, + {"_GLOBAL_OFFSET_TABLE_", 17, 0, VersionScopeNone, -1, 65521, 134518456, 0, "", ""}, + {"_end", 16, 0, VersionScopeNone, -1, 65521, 134518516, 0, "", ""}, + {"exit", 18, 0, VersionScopeNone, -1, 0, 0, 68, "", ""}, + {"_Jv_RegisterClasses", 32, 0, VersionScopeNone, -1, 0, 0, 0, "", ""}, + {"__register_frame_info", 32, 0, VersionScopeNone, -1, 0, 0, 0, "", ""}, }, }, { @@ -208,79 +208,79 @@ var fileTests = []fileTest{ }, []string{"libc.so.6"}, []Symbol{ - {"", 3, 0, -1, VerFlagNone, 1, 4194816, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 2, 4194844, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 3, 4194880, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 4, 4194920, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 5, 4194952, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 6, 4195048, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 7, 4195110, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 8, 4195120, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 9, 4195152, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 10, 4195176, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 11, 4195224, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 12, 4195248, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 13, 4195296, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 14, 4195732, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 15, 4195748, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 16, 4195768, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 17, 4195808, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 18, 6293128, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 19, 6293144, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 20, 6293160, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 21, 6293168, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 22, 6293584, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 23, 6293592, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 24, 6293632, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 25, 6293656, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 26, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 27, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 28, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 29, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 30, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 31, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 32, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 33, 0, 0, "", ""}, - {"init.c", 4, 0, -1, VerFlagNone, 65521, 0, 0, "", ""}, - {"initfini.c", 4, 0, -1, VerFlagNone, 65521, 0, 0, "", ""}, - {"call_gmon_start", 2, 0, -1, VerFlagNone, 13, 4195340, 0, "", ""}, - {"crtstuff.c", 4, 0, -1, VerFlagNone, 65521, 0, 0, "", ""}, - {"__CTOR_LIST__", 1, 0, -1, VerFlagNone, 18, 6293128, 0, "", ""}, - {"__DTOR_LIST__", 1, 0, -1, VerFlagNone, 19, 6293144, 0, "", ""}, - {"__JCR_LIST__", 1, 0, -1, VerFlagNone, 20, 6293160, 0, "", ""}, - {"__do_global_dtors_aux", 2, 0, -1, VerFlagNone, 13, 4195376, 0, "", ""}, - {"completed.6183", 1, 0, -1, VerFlagNone, 25, 6293656, 1, "", ""}, - {"p.6181", 1, 0, -1, VerFlagNone, 24, 6293648, 0, "", ""}, - {"frame_dummy", 2, 0, -1, VerFlagNone, 13, 4195440, 0, "", ""}, - {"crtstuff.c", 4, 0, -1, VerFlagNone, 65521, 0, 0, "", ""}, - {"__CTOR_END__", 1, 0, -1, VerFlagNone, 18, 6293136, 0, "", ""}, - {"__DTOR_END__", 1, 0, -1, VerFlagNone, 19, 6293152, 0, "", ""}, - {"__FRAME_END__", 1, 0, -1, VerFlagNone, 17, 4195968, 0, "", ""}, - {"__JCR_END__", 1, 0, -1, VerFlagNone, 20, 6293160, 0, "", ""}, - {"__do_global_ctors_aux", 2, 0, -1, VerFlagNone, 13, 4195680, 0, "", ""}, - {"initfini.c", 4, 0, -1, VerFlagNone, 65521, 0, 0, "", ""}, - {"hello.c", 4, 0, -1, VerFlagNone, 65521, 0, 0, "", ""}, - {"_GLOBAL_OFFSET_TABLE_", 1, 2, -1, VerFlagNone, 23, 6293592, 0, "", ""}, - {"__init_array_end", 0, 2, -1, VerFlagNone, 18, 6293124, 0, "", ""}, - {"__init_array_start", 0, 2, -1, VerFlagNone, 18, 6293124, 0, "", ""}, - {"_DYNAMIC", 1, 2, -1, VerFlagNone, 21, 6293168, 0, "", ""}, - {"data_start", 32, 0, -1, VerFlagNone, 24, 6293632, 0, "", ""}, - {"__libc_csu_fini", 18, 0, -1, VerFlagNone, 13, 4195520, 2, "", ""}, - {"_start", 18, 0, -1, VerFlagNone, 13, 4195296, 0, "", ""}, - {"__gmon_start__", 32, 0, -1, VerFlagNone, 0, 0, 0, "", ""}, - {"_Jv_RegisterClasses", 32, 0, -1, VerFlagNone, 0, 0, 0, "", ""}, - {"puts@@GLIBC_2.2.5", 18, 0, -1, VerFlagNone, 0, 0, 396, "", ""}, - {"_fini", 18, 0, -1, VerFlagNone, 14, 4195732, 0, "", ""}, - {"__libc_start_main@@GLIBC_2.2.5", 18, 0, -1, VerFlagNone, 0, 0, 450, "", ""}, - {"_IO_stdin_used", 17, 0, -1, VerFlagNone, 15, 4195748, 4, "", ""}, - {"__data_start", 16, 0, -1, VerFlagNone, 24, 6293632, 0, "", ""}, - {"__dso_handle", 17, 2, -1, VerFlagNone, 24, 6293640, 0, "", ""}, - {"__libc_csu_init", 18, 0, -1, VerFlagNone, 13, 4195536, 137, "", ""}, - {"__bss_start", 16, 0, -1, VerFlagNone, 65521, 6293656, 0, "", ""}, - {"_end", 16, 0, -1, VerFlagNone, 65521, 6293664, 0, "", ""}, - {"_edata", 16, 0, -1, VerFlagNone, 65521, 6293656, 0, "", ""}, - {"main", 18, 0, -1, VerFlagNone, 13, 4195480, 27, "", ""}, - {"_init", 18, 0, -1, VerFlagNone, 11, 4195224, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 1, 4194816, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 2, 4194844, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 3, 4194880, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 4, 4194920, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 5, 4194952, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 6, 4195048, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 7, 4195110, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 8, 4195120, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 9, 4195152, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 10, 4195176, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 11, 4195224, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 12, 4195248, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 13, 4195296, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 14, 4195732, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 15, 4195748, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 16, 4195768, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 17, 4195808, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 18, 6293128, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 19, 6293144, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 20, 6293160, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 21, 6293168, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 22, 6293584, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 23, 6293592, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 24, 6293632, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 25, 6293656, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 26, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 27, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 28, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 29, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 30, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 31, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 32, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 33, 0, 0, "", ""}, + {"init.c", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, + {"initfini.c", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, + {"call_gmon_start", 2, 0, VersionScopeNone, -1, 13, 4195340, 0, "", ""}, + {"crtstuff.c", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, + {"__CTOR_LIST__", 1, 0, VersionScopeNone, -1, 18, 6293128, 0, "", ""}, + {"__DTOR_LIST__", 1, 0, VersionScopeNone, -1, 19, 6293144, 0, "", ""}, + {"__JCR_LIST__", 1, 0, VersionScopeNone, -1, 20, 6293160, 0, "", ""}, + {"__do_global_dtors_aux", 2, 0, VersionScopeNone, -1, 13, 4195376, 0, "", ""}, + {"completed.6183", 1, 0, VersionScopeNone, -1, 25, 6293656, 1, "", ""}, + {"p.6181", 1, 0, VersionScopeNone, -1, 24, 6293648, 0, "", ""}, + {"frame_dummy", 2, 0, VersionScopeNone, -1, 13, 4195440, 0, "", ""}, + {"crtstuff.c", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, + {"__CTOR_END__", 1, 0, VersionScopeNone, -1, 18, 6293136, 0, "", ""}, + {"__DTOR_END__", 1, 0, VersionScopeNone, -1, 19, 6293152, 0, "", ""}, + {"__FRAME_END__", 1, 0, VersionScopeNone, -1, 17, 4195968, 0, "", ""}, + {"__JCR_END__", 1, 0, VersionScopeNone, -1, 20, 6293160, 0, "", ""}, + {"__do_global_ctors_aux", 2, 0, VersionScopeNone, -1, 13, 4195680, 0, "", ""}, + {"initfini.c", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, + {"hello.c", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, + {"_GLOBAL_OFFSET_TABLE_", 1, 2, VersionScopeNone, -1, 23, 6293592, 0, "", ""}, + {"__init_array_end", 0, 2, VersionScopeNone, -1, 18, 6293124, 0, "", ""}, + {"__init_array_start", 0, 2, VersionScopeNone, -1, 18, 6293124, 0, "", ""}, + {"_DYNAMIC", 1, 2, VersionScopeNone, -1, 21, 6293168, 0, "", ""}, + {"data_start", 32, 0, VersionScopeNone, -1, 24, 6293632, 0, "", ""}, + {"__libc_csu_fini", 18, 0, VersionScopeNone, -1, 13, 4195520, 2, "", ""}, + {"_start", 18, 0, VersionScopeNone, -1, 13, 4195296, 0, "", ""}, + {"__gmon_start__", 32, 0, VersionScopeNone, -1, 0, 0, 0, "", ""}, + {"_Jv_RegisterClasses", 32, 0, VersionScopeNone, -1, 0, 0, 0, "", ""}, + {"puts@@GLIBC_2.2.5", 18, 0, VersionScopeNone, -1, 0, 0, 396, "", ""}, + {"_fini", 18, 0, VersionScopeNone, -1, 14, 4195732, 0, "", ""}, + {"__libc_start_main@@GLIBC_2.2.5", 18, 0, VersionScopeNone, -1, 0, 0, 450, "", ""}, + {"_IO_stdin_used", 17, 0, VersionScopeNone, -1, 15, 4195748, 4, "", ""}, + {"__data_start", 16, 0, VersionScopeNone, -1, 24, 6293632, 0, "", ""}, + {"__dso_handle", 17, 2, VersionScopeNone, -1, 24, 6293640, 0, "", ""}, + {"__libc_csu_init", 18, 0, VersionScopeNone, -1, 13, 4195536, 137, "", ""}, + {"__bss_start", 16, 0, VersionScopeNone, -1, 65521, 6293656, 0, "", ""}, + {"_end", 16, 0, VersionScopeNone, -1, 65521, 6293664, 0, "", ""}, + {"_edata", 16, 0, VersionScopeNone, -1, 65521, 6293656, 0, "", ""}, + {"main", 18, 0, VersionScopeNone, -1, 13, 4195480, 27, "", ""}, + {"_init", 18, 0, VersionScopeNone, -1, 11, 4195224, 0, "", ""}, }, }, { @@ -338,21 +338,21 @@ var fileTests = []fileTest{ []ProgHeader{}, nil, []Symbol{ - {"hello.c", 4, 0, -1, VerFlagNone, 65521, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 1, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 3, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 4, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 5, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 6, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 8, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 9, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 11, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 13, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 15, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 16, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 14, 0, 0, "", ""}, - {"main", 18, 0, -1, VerFlagNone, 1, 0, 23, "", ""}, - {"puts", 16, 0, -1, VerFlagNone, 0, 0, 0, "", ""}, + {"hello.c", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 1, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 3, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 4, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 5, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 6, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 8, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 9, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 11, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 13, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 15, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 16, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 14, 0, 0, "", ""}, + {"main", 18, 0, VersionScopeNone, -1, 1, 0, 23, "", ""}, + {"puts", 16, 0, VersionScopeNone, -1, 0, 0, 0, "", ""}, }, }, { @@ -384,21 +384,21 @@ var fileTests = []fileTest{ []ProgHeader{}, nil, []Symbol{ - {"hello.c", 4, 0, -1, VerFlagNone, 65521, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 1, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 3, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 4, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 5, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 6, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 8, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 9, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 11, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 13, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 15, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 16, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 14, 0, 0, "", ""}, - {"main", 18, 0, -1, VerFlagNone, 1, 0, 27, "", ""}, - {"puts", 16, 0, -1, VerFlagNone, 0, 0, 0, "", ""}, + {"hello.c", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 1, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 3, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 4, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 5, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 6, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 8, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 9, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 11, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 13, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 15, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 16, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 14, 0, 0, "", ""}, + {"main", 18, 0, VersionScopeNone, -1, 1, 0, 27, "", ""}, + {"puts", 16, 0, VersionScopeNone, -1, 0, 0, 0, "", ""}, }, }, { @@ -430,21 +430,21 @@ var fileTests = []fileTest{ []ProgHeader{}, nil, []Symbol{ - {"hello.c", 4, 0, -1, VerFlagNone, 65521, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 1, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 3, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 4, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 5, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 6, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 8, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 9, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 11, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 13, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 15, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 16, 0, 0, "", ""}, - {"", 3, 0, -1, VerFlagNone, 14, 0, 0, "", ""}, - {"main", 18, 0, -1, VerFlagNone, 1, 0, 44, "", ""}, - {"puts", 16, 0, -1, VerFlagNone, 0, 0, 0, "", ""}, + {"hello.c", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 1, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 3, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 4, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 5, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 6, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 8, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 9, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 11, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 13, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 15, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 16, 0, 0, "", ""}, + {"", 3, 0, VersionScopeNone, -1, 14, 0, 0, "", ""}, + {"main", 18, 0, VersionScopeNone, -1, 1, 0, 44, "", ""}, + {"puts", 16, 0, VersionScopeNone, -1, 0, 0, 0, "", ""}, }, }, } diff --git a/src/debug/elf/symbols_test.go b/src/debug/elf/symbols_test.go index ecc897b4a8aff6..8b6dac019b63a1 100644 --- a/src/debug/elf/symbols_test.go +++ b/src/debug/elf/symbols_test.go @@ -37,7 +37,7 @@ func TestSymbols(t *testing.T) { fs = []Symbol{} } if !reflect.DeepEqual(ts, fs) { - t.Errorf("%s: Symbols = %v, want %v", file, ts, fs) + t.Errorf("%s: Symbols = %v, want %v", file, fs, ts) } } for file, ts := range symbolsGolden { @@ -56,8 +56,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x1, Value: 0x400200, Size: 0x0, @@ -66,8 +66,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x2, Value: 0x40021C, Size: 0x0, @@ -76,8 +76,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x3, Value: 0x400240, Size: 0x0, @@ -86,8 +86,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x4, Value: 0x400268, Size: 0x0, @@ -96,8 +96,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x5, Value: 0x400288, Size: 0x0, @@ -106,8 +106,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x6, Value: 0x4002E8, Size: 0x0, @@ -116,8 +116,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x7, Value: 0x400326, Size: 0x0, @@ -126,8 +126,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x8, Value: 0x400330, Size: 0x0, @@ -136,8 +136,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x9, Value: 0x400350, Size: 0x0, @@ -146,8 +146,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0xA, Value: 0x400368, Size: 0x0, @@ -156,8 +156,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0xB, Value: 0x400398, Size: 0x0, @@ -166,8 +166,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0xC, Value: 0x4003B0, Size: 0x0, @@ -176,8 +176,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0xD, Value: 0x4003E0, Size: 0x0, @@ -186,8 +186,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0xE, Value: 0x400594, Size: 0x0, @@ -196,8 +196,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0xF, Value: 0x4005A4, Size: 0x0, @@ -206,8 +206,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x10, Value: 0x4005B8, Size: 0x0, @@ -216,8 +216,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x11, Value: 0x4005E0, Size: 0x0, @@ -226,8 +226,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x12, Value: 0x600688, Size: 0x0, @@ -236,8 +236,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x13, Value: 0x600698, Size: 0x0, @@ -246,8 +246,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x14, Value: 0x6006A8, Size: 0x0, @@ -256,8 +256,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x15, Value: 0x6006B0, Size: 0x0, @@ -266,8 +266,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x16, Value: 0x600850, Size: 0x0, @@ -276,8 +276,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x17, Value: 0x600858, Size: 0x0, @@ -286,8 +286,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x18, Value: 0x600880, Size: 0x0, @@ -296,8 +296,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x19, Value: 0x600898, Size: 0x0, @@ -306,8 +306,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x1A, Value: 0x0, Size: 0x0, @@ -316,8 +316,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x1B, Value: 0x0, Size: 0x0, @@ -326,8 +326,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x1C, Value: 0x0, Size: 0x0, @@ -336,8 +336,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x1D, Value: 0x0, Size: 0x0, @@ -346,8 +346,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x1E, Value: 0x0, Size: 0x0, @@ -356,8 +356,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x1F, Value: 0x0, Size: 0x0, @@ -366,8 +366,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x20, Value: 0x0, Size: 0x0, @@ -376,8 +376,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x21, Value: 0x0, Size: 0x0, @@ -386,8 +386,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "init.c", Info: 0x4, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0xFFF1, Value: 0x0, Size: 0x0, @@ -396,8 +396,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "initfini.c", Info: 0x4, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0xFFF1, Value: 0x0, Size: 0x0, @@ -406,8 +406,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "call_gmon_start", Info: 0x2, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0xD, Value: 0x40040C, Size: 0x0, @@ -416,8 +416,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "crtstuff.c", Info: 0x4, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0xFFF1, Value: 0x0, Size: 0x0, @@ -426,8 +426,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "__CTOR_LIST__", Info: 0x1, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x12, Value: 0x600688, Size: 0x0, @@ -436,8 +436,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "__DTOR_LIST__", Info: 0x1, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x13, Value: 0x600698, Size: 0x0, @@ -446,8 +446,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "__JCR_LIST__", Info: 0x1, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x14, Value: 0x6006A8, Size: 0x0, @@ -456,8 +456,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "__do_global_dtors_aux", Info: 0x2, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0xD, Value: 0x400430, Size: 0x0, @@ -466,8 +466,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "completed.6183", Info: 0x1, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x19, Value: 0x600898, Size: 0x1, @@ -476,8 +476,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "p.6181", Info: 0x1, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x18, Value: 0x600890, Size: 0x0, @@ -486,8 +486,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "frame_dummy", Info: 0x2, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0xD, Value: 0x400470, Size: 0x0, @@ -496,8 +496,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "crtstuff.c", Info: 0x4, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0xFFF1, Value: 0x0, Size: 0x0, @@ -506,8 +506,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "__CTOR_END__", Info: 0x1, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x12, Value: 0x600690, Size: 0x0, @@ -516,8 +516,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "__DTOR_END__", Info: 0x1, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x13, Value: 0x6006A0, Size: 0x0, @@ -526,8 +526,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "__FRAME_END__", Info: 0x1, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x11, Value: 0x400680, Size: 0x0, @@ -536,8 +536,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "__JCR_END__", Info: 0x1, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x14, Value: 0x6006A8, Size: 0x0, @@ -546,8 +546,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "__do_global_ctors_aux", Info: 0x2, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0xD, Value: 0x400560, Size: 0x0, @@ -556,8 +556,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "initfini.c", Info: 0x4, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0xFFF1, Value: 0x0, Size: 0x0, @@ -566,8 +566,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "hello.c", Info: 0x4, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0xFFF1, Value: 0x0, Size: 0x0, @@ -576,8 +576,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "_GLOBAL_OFFSET_TABLE_", Info: 0x1, Other: 0x2, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x17, Value: 0x600858, Size: 0x0, @@ -586,8 +586,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "__init_array_end", Info: 0x0, Other: 0x2, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x12, Value: 0x600684, Size: 0x0, @@ -596,8 +596,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "__init_array_start", Info: 0x0, Other: 0x2, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x12, Value: 0x600684, Size: 0x0, @@ -606,8 +606,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "_DYNAMIC", Info: 0x1, Other: 0x2, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x15, Value: 0x6006B0, Size: 0x0, @@ -616,8 +616,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "data_start", Info: 0x20, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x18, Value: 0x600880, Size: 0x0, @@ -626,8 +626,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "__libc_csu_fini", Info: 0x12, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0xD, Value: 0x4004C0, Size: 0x2, @@ -636,8 +636,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "_start", Info: 0x12, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0xD, Value: 0x4003E0, Size: 0x0, @@ -646,8 +646,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "__gmon_start__", Info: 0x20, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x0, Value: 0x0, Size: 0x0, @@ -656,8 +656,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "_Jv_RegisterClasses", Info: 0x20, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x0, Value: 0x0, Size: 0x0, @@ -666,8 +666,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "puts@@GLIBC_2.2.5", Info: 0x12, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x0, Value: 0x0, Size: 0x18C, @@ -676,8 +676,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "_fini", Info: 0x12, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0xE, Value: 0x400594, Size: 0x0, @@ -686,8 +686,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "__libc_start_main@@GLIBC_2.2.5", Info: 0x12, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x0, Value: 0x0, Size: 0x1C2, @@ -696,8 +696,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "_IO_stdin_used", Info: 0x11, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0xF, Value: 0x4005A4, Size: 0x4, @@ -706,8 +706,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "__data_start", Info: 0x10, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x18, Value: 0x600880, Size: 0x0, @@ -716,8 +716,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "__dso_handle", Info: 0x11, Other: 0x2, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x18, Value: 0x600888, Size: 0x0, @@ -726,8 +726,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "__libc_csu_init", Info: 0x12, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0xD, Value: 0x4004D0, Size: 0x89, @@ -736,8 +736,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "__bss_start", Info: 0x10, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0xFFF1, Value: 0x600898, Size: 0x0, @@ -746,8 +746,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "_end", Info: 0x10, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0xFFF1, Value: 0x6008A0, Size: 0x0, @@ -756,8 +756,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "_edata", Info: 0x10, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0xFFF1, Value: 0x600898, Size: 0x0, @@ -766,8 +766,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "main", Info: 0x12, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0xD, Value: 0x400498, Size: 0x1B, @@ -776,8 +776,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "_init", Info: 0x12, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0xB, Value: 0x400398, Size: 0x0, @@ -788,8 +788,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "go-relocation-test-clang.c", Info: 0x4, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0xFFF1, Value: 0x0, Size: 0x0, @@ -798,8 +798,8 @@ var symbolsGolden = map[string][]Symbol{ Name: ".Linfo_string0", Info: 0x0, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0xC, Value: 0x0, Size: 0x0, @@ -808,8 +808,8 @@ var symbolsGolden = map[string][]Symbol{ Name: ".Linfo_string1", Info: 0x0, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0xC, Value: 0x2C, Size: 0x0, @@ -818,8 +818,8 @@ var symbolsGolden = map[string][]Symbol{ Name: ".Linfo_string2", Info: 0x0, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0xC, Value: 0x47, Size: 0x0, @@ -828,8 +828,8 @@ var symbolsGolden = map[string][]Symbol{ Name: ".Linfo_string3", Info: 0x0, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0xC, Value: 0x4C, Size: 0x0, @@ -838,8 +838,8 @@ var symbolsGolden = map[string][]Symbol{ Name: ".Linfo_string4", Info: 0x0, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0xC, Value: 0x4E, Size: 0x0, @@ -848,8 +848,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x1, Value: 0x0, Size: 0x0, @@ -858,8 +858,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x2, Value: 0x0, Size: 0x0, @@ -868,8 +868,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x3, Value: 0x0, Size: 0x0, @@ -878,8 +878,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x4, Value: 0x0, Size: 0x0, @@ -888,8 +888,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x6, Value: 0x0, Size: 0x0, @@ -898,8 +898,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x7, Value: 0x0, Size: 0x0, @@ -908,8 +908,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x8, Value: 0x0, Size: 0x0, @@ -918,8 +918,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0xA, Value: 0x0, Size: 0x0, @@ -928,8 +928,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0xC, Value: 0x0, Size: 0x0, @@ -938,8 +938,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0xD, Value: 0x0, Size: 0x0, @@ -948,8 +948,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0xE, Value: 0x0, Size: 0x0, @@ -958,8 +958,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0xF, Value: 0x0, Size: 0x0, @@ -968,8 +968,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0x10, Value: 0x0, Size: 0x0, @@ -978,8 +978,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "v", Info: 0x11, Other: 0x0, + VersionScope: VersionScopeNone, VersionIndex: -1, - VersionFlags: VerFlagNone, Section: 0xFFF2, Value: 0x4, Size: 0x4, @@ -994,8 +994,8 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "__gmon_start__", Info: 0x20, Other: 0x0, + VersionScope: VersionScopeLocal, VersionIndex: 0x0, - VersionFlags: VerFlagLocal, Section: 0x0, Value: 0x0, Size: 0x0, @@ -1004,8 +1004,8 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "puts", Info: 0x12, Other: 0x0, + VersionScope: VersionScopeSpecific, VersionIndex: 0x2, - VersionFlags: VerFlagHidden, Section: 0x0, Value: 0x0, Size: 0x18C, @@ -1016,8 +1016,8 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "__libc_start_main", Info: 0x12, Other: 0x0, + VersionScope: VersionScopeSpecific, VersionIndex: 0x2, - VersionFlags: VerFlagHidden, Section: 0x0, Value: 0x0, Size: 0x1C2, @@ -1032,8 +1032,8 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "_ZNSo3putEc", Info: 0x12, Other: 0x0, + VersionScope: VersionScopeSpecific, VersionIndex: 0x3, - VersionFlags: VerFlagHidden, Section: 0x0, Value: 0x0, Size: 0x0, @@ -1044,8 +1044,8 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "strchr", Info: 0x12, Other: 0x0, + VersionScope: VersionScopeSpecific, VersionIndex: 0x4, - VersionFlags: VerFlagHidden, Section: 0x0, Value: 0x0, Size: 0x0, @@ -1056,8 +1056,8 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "__cxa_finalize", Info: 0x22, Other: 0x0, + VersionScope: VersionScopeSpecific, VersionIndex: 0x4, - VersionFlags: VerFlagHidden, Section: 0x0, Value: 0x0, Size: 0x0, @@ -1068,8 +1068,8 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "_ZNSo5tellpEv", Info: 0x12, Other: 0x0, + VersionScope: VersionScopeSpecific, VersionIndex: 0x3, - VersionFlags: VerFlagHidden, Section: 0x0, Value: 0x0, Size: 0x0, @@ -1080,8 +1080,8 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "_ZNSo5seekpElSt12_Ios_Seekdir", Info: 0x12, Other: 0x0, + VersionScope: VersionScopeSpecific, VersionIndex: 0x3, - VersionFlags: VerFlagHidden, Section: 0x0, Value: 0x0, Size: 0x0, @@ -1092,8 +1092,8 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "_Znwm", Info: 0x12, Other: 0x0, + VersionScope: VersionScopeSpecific, VersionIndex: 0x3, - VersionFlags: VerFlagHidden, Section: 0x0, Value: 0x0, Size: 0x0, @@ -1104,8 +1104,8 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "_ZdlPvm", Info: 0x12, Other: 0x0, + VersionScope: VersionScopeSpecific, VersionIndex: 0x5, - VersionFlags: VerFlagHidden, Section: 0x0, Value: 0x0, Size: 0x0, @@ -1116,8 +1116,8 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "__stack_chk_fail", Info: 0x12, Other: 0x0, + VersionScope: VersionScopeSpecific, VersionIndex: 0x6, - VersionFlags: VerFlagHidden, Section: 0x0, Value: 0x0, Size: 0x0, @@ -1128,8 +1128,8 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "_ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l", Info: 0x12, Other: 0x0, + VersionScope: VersionScopeSpecific, VersionIndex: 0x7, - VersionFlags: VerFlagHidden, Section: 0x0, Value: 0x0, Size: 0x0, @@ -1140,8 +1140,8 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "_ZNSo5seekpESt4fposI11__mbstate_tE", Info: 0x12, Other: 0x0, + VersionScope: VersionScopeSpecific, VersionIndex: 0x3, - VersionFlags: VerFlagHidden, Section: 0x0, Value: 0x0, Size: 0x0, @@ -1152,8 +1152,8 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "_ZNSi4readEPcl", Info: 0x12, Other: 0x0, + VersionScope: VersionScopeSpecific, VersionIndex: 0x3, - VersionFlags: VerFlagHidden, Section: 0x0, Value: 0x0, Size: 0x0, @@ -1164,8 +1164,8 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "_ZNSi5seekgESt4fposI11__mbstate_tE", Info: 0x12, Other: 0x0, + VersionScope: VersionScopeSpecific, VersionIndex: 0x3, - VersionFlags: VerFlagHidden, Section: 0x0, Value: 0x0, Size: 0x0, @@ -1176,8 +1176,8 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "_ZNSo5writeEPKcl", Info: 0x12, Other: 0x0, + VersionScope: VersionScopeSpecific, VersionIndex: 0x3, - VersionFlags: VerFlagHidden, Section: 0x0, Value: 0x0, Size: 0x0, @@ -1188,8 +1188,8 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "_ZNSi5seekgElSt12_Ios_Seekdir", Info: 0x12, Other: 0x0, + VersionScope: VersionScopeSpecific, VersionIndex: 0x3, - VersionFlags: VerFlagHidden, Section: 0x0, Value: 0x0, Size: 0x0, @@ -1200,8 +1200,8 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "_ZSt21ios_base_library_initv", Info: 0x12, Other: 0x0, + VersionScope: VersionScopeSpecific, VersionIndex: 0x8, - VersionFlags: VerFlagHidden, Section: 0x0, Value: 0x0, Size: 0x0, @@ -1212,8 +1212,8 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "TIFFClientOpen", Info: 0x12, Other: 0x0, + VersionScope: VersionScopeSpecific, VersionIndex: 0x9, - VersionFlags: VerFlagHidden, Section: 0x0, Value: 0x0, Size: 0x0, @@ -1224,8 +1224,8 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "_ZNSt9basic_iosIcSt11char_traitsIcEE5clearESt12_Ios_Iostate", Info: 0x12, Other: 0x0, + VersionScope: VersionScopeSpecific, VersionIndex: 0x3, - VersionFlags: VerFlagHidden, Section: 0x0, Value: 0x0, Size: 0x0, @@ -1236,8 +1236,8 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "_ZNSi5tellgEv", Info: 0x12, Other: 0x0, + VersionScope: VersionScopeSpecific, VersionIndex: 0x3, - VersionFlags: VerFlagHidden, Section: 0x0, Value: 0x0, Size: 0x0, @@ -1248,8 +1248,8 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "_ITM_deregisterTMCloneTable", Info: 0x20, Other: 0x0, + VersionScope: VersionScopeGlobal, VersionIndex: 0x1, - VersionFlags: VerFlagGlobal, Section: 0x0, Value: 0x0, Size: 0x0, @@ -1258,8 +1258,8 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "__gmon_start__", Info: 0x20, Other: 0x0, + VersionScope: VersionScopeGlobal, VersionIndex: 0x1, - VersionFlags: VerFlagGlobal, Section: 0x0, Value: 0x0, Size: 0x0, @@ -1268,8 +1268,8 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "_ITM_registerTMCloneTable", Info: 0x20, Other: 0x0, + VersionScope: VersionScopeGlobal, VersionIndex: 0x1, - VersionFlags: VerFlagGlobal, Section: 0x0, Value: 0x0, Size: 0x0, @@ -1278,8 +1278,8 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "LIBTIFFXX_4.0", Info: 0x11, Other: 0x0, + VersionScope: VersionScopeSpecific, VersionIndex: 0x2, - VersionFlags: VerFlagNone, Section: 0xFFF1, Value: 0x0, Size: 0x0, @@ -1290,8 +1290,8 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "_Z14TIFFStreamOpenPKcPSo", Info: 0x12, Other: 0x0, + VersionScope: VersionScopeSpecific, VersionIndex: 0x2, - VersionFlags: VerFlagNone, Section: 0xF, Value: 0x1860, Size: 0xB8, @@ -1302,8 +1302,8 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "_Z14TIFFStreamOpenPKcPSi", Info: 0x12, Other: 0x0, + VersionScope: VersionScopeSpecific, VersionIndex: 0x2, - VersionFlags: VerFlagNone, Section: 0xF, Value: 0x1920, Size: 0x13, From fafd4477f3d19f2c11a628e6e407ecf9924309c1 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 10 Dec 2024 20:05:06 -0800 Subject: [PATCH 011/397] cmd/cgo: use full prototype for main in C code Avoids pedantic errors from modern C compilers. Fixes #70769 Change-Id: Ibe0d9960e998eb0346b97d7bd69eb7de0d0e6c60 Reviewed-on: https://go-review.googlesource.com/c/go/+/635095 Reviewed-by: Robert Griesemer Reviewed-by: Mauri de Souza Meneguzzo Reviewed-by: Ian Lance Taylor Auto-Submit: Ian Lance Taylor Commit-Queue: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI --- src/cmd/cgo/doc.go | 2 +- src/cmd/cgo/out.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go index 9ff5fd41901c90..ef5272299bbf07 100644 --- a/src/cmd/cgo/doc.go +++ b/src/cmd/cgo/doc.go @@ -796,7 +796,7 @@ Instead, the build process generates an object file using dynamic linkage to the desired libraries. The main function is provided by _cgo_main.c: - int main() { return 0; } + int main(int argc, char **argv) { return 0; } void crosscall2(void(*fn)(void*), void *a, int c, uintptr_t ctxt) { } uintptr_t _cgo_wait_runtime_init_done(void) { return 0; } void _cgo_release_context(uintptr_t ctxt) { } diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index 954c4b70c954eb..5e67cc2d334598 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -59,7 +59,7 @@ func (p *Package) writeDefs() { // Write C main file for using gcc to resolve imports. fmt.Fprintf(fm, "#include \n") // For size_t below. - fmt.Fprintf(fm, "int main() { return 0; }\n") + fmt.Fprintf(fm, "int main(int argc __attribute__((unused)), char **argv __attribute__((unused))) { return 0; }\n") if *importRuntimeCgo { fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*) __attribute__((unused)), void *a __attribute__((unused)), int c __attribute__((unused)), size_t ctxt __attribute__((unused))) { }\n") fmt.Fprintf(fm, "size_t _cgo_wait_runtime_init_done(void) { return 0; }\n") From 077d51909d3d7bc2d52afd47c9be1de8ee4f0756 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 11 Dec 2024 14:02:28 -0800 Subject: [PATCH 012/397] internal/poll: in SendFile treat ENOTSUP like EOPNOTSUPP Fixes #70763 Change-Id: Ifb79b5b0529f7977df0fe1b59d224b8b31df2c9b Reviewed-on: https://go-review.googlesource.com/c/go/+/635396 Reviewed-by: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Reviewed-by: Damien Neil Auto-Submit: Ian Lance Taylor --- src/internal/poll/sendfile_unix.go | 10 +++- src/net/sendfile_unix_test.go | 86 ++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 src/net/sendfile_unix_test.go diff --git a/src/internal/poll/sendfile_unix.go b/src/internal/poll/sendfile_unix.go index f5aee38a054683..1105e0569110fb 100644 --- a/src/internal/poll/sendfile_unix.go +++ b/src/internal/poll/sendfile_unix.go @@ -110,12 +110,20 @@ func sendFile(dstFD *FD, src int, offset *int64, size int64) (written int64, err // Retry. case syscall.ENOSYS, syscall.EOPNOTSUPP, syscall.EINVAL: // ENOSYS indicates no kernel support for sendfile. - // EINVAL indicates a FD type which does not support sendfile. + // EINVAL indicates a FD type that does not support sendfile. // // On Linux, copy_file_range can return EOPNOTSUPP when copying // to a NFS file (issue #40731); check for it here just in case. return written, err, written > 0 default: + // We want to handle ENOTSUP like EOPNOTSUPP. + // It's a pain to put it as a switch case + // because on Linux systems ENOTSUP == EOPNOTSUPP, + // so the compiler complains about a duplicate case. + if err == syscall.ENOTSUP { + return written, err, written > 0 + } + // Not a retryable error. return written, err, true } diff --git a/src/net/sendfile_unix_test.go b/src/net/sendfile_unix_test.go new file mode 100644 index 00000000000000..79fb23b31010d5 --- /dev/null +++ b/src/net/sendfile_unix_test.go @@ -0,0 +1,86 @@ +// Copyright 2024 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. + +//go:build unix + +package net + +import ( + "internal/testpty" + "io" + "os" + "sync" + "syscall" + "testing" +) + +// Issue 70763: test that we don't fail on sendfile from a tty. +func TestCopyFromTTY(t *testing.T) { + pty, ttyName, err := testpty.Open() + if err != nil { + t.Skipf("skipping test because pty open failed: %v", err) + } + defer pty.Close() + + // Use syscall.Open so that the tty is blocking. + ttyFD, err := syscall.Open(ttyName, syscall.O_RDWR, 0) + if err != nil { + t.Skipf("skipping test because tty open failed: %v", err) + } + defer syscall.Close(ttyFD) + + tty := os.NewFile(uintptr(ttyFD), "tty") + defer tty.Close() + + ln := newLocalListener(t, "tcp") + defer ln.Close() + + ch := make(chan bool) + + const data = "data\n" + + var wg sync.WaitGroup + defer wg.Wait() + + wg.Add(1) + go func() { + defer wg.Done() + conn, err := ln.Accept() + if err != nil { + t.Error(err) + return + } + defer conn.Close() + + buf := make([]byte, len(data)) + if _, err := io.ReadFull(conn, buf); err != nil { + t.Error(err) + } + + ch <- true + }() + + conn, err := Dial("tcp", ln.Addr().String()) + if err != nil { + t.Fatal(err) + } + defer conn.Close() + + wg.Add(1) + go func() { + defer wg.Done() + if _, err := pty.Write([]byte(data)); err != nil { + t.Error(err) + } + <-ch + if err := pty.Close(); err != nil { + t.Error(err) + } + }() + + lr := io.LimitReader(tty, int64(len(data))) + if _, err := io.Copy(conn, lr); err != nil { + t.Error(err) + } +} From 9118060040ab7af4d384c2c1e2862673e2bbb8c3 Mon Sep 17 00:00:00 2001 From: apocelipes Date: Thu, 12 Dec 2024 09:45:09 +0000 Subject: [PATCH 013/397] builtin: document clear is a no-op if its argument's value is nil Just like the builtin function delete's comment does. Change-Id: Id94a3aaa03c7b09594bae2b1af901d9060d9e255 GitHub-Last-Rev: 30cbebca96d9099f67a7dfc7650357aa19d6b810 GitHub-Pull-Request: golang/go#70801 Reviewed-on: https://go-review.googlesource.com/c/go/+/635535 Reviewed-by: Carlos Amedee Reviewed-by: Keith Randall LUCI-TryBot-Result: Go LUCI Reviewed-by: Keith Randall Auto-Submit: Keith Randall --- src/builtin/builtin.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/builtin/builtin.go b/src/builtin/builtin.go index 215c59c4ae8156..af01aea5dd79f4 100644 --- a/src/builtin/builtin.go +++ b/src/builtin/builtin.go @@ -247,7 +247,7 @@ func imag(c ComplexType) FloatType // to the zero value of the respective element type. If the argument // type is a type parameter, the type parameter's type set must // contain only map or slice types, and clear performs the operation -// implied by the type argument. +// implied by the type argument. If t is nil, clear is a no-op. func clear[T ~[]Type | ~map[Type]Type1](t T) // The close built-in function closes a channel, which must be either From fb764cdad03ae2e500100b691f77cbd0d22b7d9c Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Thu, 12 Dec 2024 13:03:49 -0500 Subject: [PATCH 014/397] cmd/link: block new standard library linknames In Go 1.24 we added a number of new linknames for standard library internal uses. Add them to the linker's blocklist to keep them internal. Change-Id: Ibb7fa095506c161604e978ae196a7cf248475b2e Reviewed-on: https://go-review.googlesource.com/c/go/+/635676 LUCI-TryBot-Result: Go LUCI Reviewed-by: Michael Pratt --- src/cmd/link/internal/loader/loader.go | 39 ++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/cmd/link/internal/loader/loader.go b/src/cmd/link/internal/loader/loader.go index 6fe895a8409cc3..e7cc30ab0731c2 100644 --- a/src/cmd/link/internal/loader/loader.go +++ b/src/cmd/link/internal/loader/loader.go @@ -2338,6 +2338,45 @@ var blockedLinknames = map[string][]string{ "runtime.newcoro": {"iter"}, // fips info "go:fipsinfo": {"crypto/internal/fips140/check"}, + // New internal linknames in Go 1.24 + // Pushed from runtime + "crypto/internal/fips140.fatal": {"crypto/internal/fips140"}, + "crypto/internal/fips140.getIndicator": {"crypto/internal/fips140"}, + "crypto/internal/fips140.setIndicator": {"crypto/internal/fips140"}, + "crypto/internal/sysrand.fatal": {"crypto/internal/sysrand"}, + "crypto/rand.fatal": {"crypto/rand"}, + "internal/runtime/maps.errNilAssign": {"internal/runtime/maps"}, + "internal/runtime/maps.fatal": {"internal/runtime/maps"}, + "internal/runtime/maps.mapKeyError": {"internal/runtime/maps"}, + "internal/runtime/maps.newarray": {"internal/runtime/maps"}, + "internal/runtime/maps.newobject": {"internal/runtime/maps"}, + "internal/runtime/maps.typedmemclr": {"internal/runtime/maps"}, + "internal/runtime/maps.typedmemmove": {"internal/runtime/maps"}, + "internal/sync.fatal": {"internal/sync"}, + "internal/sync.runtime_canSpin": {"internal/sync"}, + "internal/sync.runtime_doSpin": {"internal/sync"}, + "internal/sync.runtime_nanotime": {"internal/sync"}, + "internal/sync.runtime_Semrelease": {"internal/sync"}, + "internal/sync.runtime_SemacquireMutex": {"internal/sync"}, + "internal/sync.throw": {"internal/sync"}, + "internal/synctest.Run": {"internal/synctest"}, + "internal/synctest.Wait": {"internal/synctest"}, + "internal/synctest.acquire": {"internal/synctest"}, + "internal/synctest.release": {"internal/synctest"}, + "internal/synctest.inBubble": {"internal/synctest"}, + "runtime.getStaticuint64s": {"reflect"}, + "sync.runtime_SemacquireWaitGroup": {"sync"}, + "time.runtimeNow": {"time"}, + "time.runtimeNano": {"time"}, + // Pushed to runtime from internal/runtime/maps + // (other map functions are already linknamed in Go 1.23) + "runtime.mapaccess1": {"runtime"}, + "runtime.mapaccess1_fast32": {"runtime"}, + "runtime.mapaccess1_fast64": {"runtime"}, + "runtime.mapaccess1_faststr": {"runtime"}, + "runtime.mapdelete_fast32": {"runtime"}, + "runtime.mapdelete_fast64": {"runtime"}, + "runtime.mapdelete_faststr": {"runtime"}, } // check if a linkname reference to symbol s from pkg is allowed From 14e5093ee56c7e3a807c8924fd2d425cd2b0f376 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Thu, 12 Dec 2024 14:31:45 -0500 Subject: [PATCH 015/397] cmd/internal/obj: disallow linknamed access to builtin symbols Currently, a symbol reference is counted as a reference to a builtin symbol if the name matches a builtin. Usually builtin references are generated by the compiler. But one could manually write one with linkname. Since the list of builtin functions are subject to change from time to time, we don't want users to depend on their names. So we don't count a linknamed reference as a builtin reference, and instead, count it as a named reference, so it is checked by the linker. Change-Id: Id3543295185c6bbd73a8cff82afb8f9cb4fd6f71 Reviewed-on: https://go-review.googlesource.com/c/go/+/635755 Reviewed-by: Michael Pratt LUCI-TryBot-Result: Go LUCI --- src/cmd/internal/obj/sym.go | 2 +- src/cmd/link/link_test.go | 2 ++ src/cmd/link/testdata/linkname/builtin.go | 17 +++++++++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 src/cmd/link/testdata/linkname/builtin.go diff --git a/src/cmd/internal/obj/sym.go b/src/cmd/internal/obj/sym.go index 4feccf54f6bc2a..887257905035fb 100644 --- a/src/cmd/internal/obj/sym.go +++ b/src/cmd/internal/obj/sym.go @@ -320,7 +320,7 @@ func (ctxt *Link) NumberSyms() { // Assign special index for builtin symbols. // Don't do it when linking against shared libraries, as the runtime // may be in a different library. - if i := goobj.BuiltinIdx(rs.Name, int(rs.ABI())); i != -1 { + if i := goobj.BuiltinIdx(rs.Name, int(rs.ABI())); i != -1 && !rs.IsLinkname() { rs.PkgIdx = goobj.PkgIdxBuiltin rs.SymIdx = int32(i) rs.Set(AttrIndexed, true) diff --git a/src/cmd/link/link_test.go b/src/cmd/link/link_test.go index f23951416ba8fd..ab56b49e15d3b1 100644 --- a/src/cmd/link/link_test.go +++ b/src/cmd/link/link_test.go @@ -1518,6 +1518,8 @@ func TestCheckLinkname(t *testing.T) { {"coro_asm", false}, // pull-only linkname is not ok {"coro2.go", false}, + // pull linkname of a builtin symbol is not ok + {"builtin.go", false}, // legacy bad linkname is ok, for now {"fastrand.go", true}, {"badlinkname.go", true}, diff --git a/src/cmd/link/testdata/linkname/builtin.go b/src/cmd/link/testdata/linkname/builtin.go new file mode 100644 index 00000000000000..a238c9b9679879 --- /dev/null +++ b/src/cmd/link/testdata/linkname/builtin.go @@ -0,0 +1,17 @@ +// Copyright 2024 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. + +// Linkname builtin symbols (that is not already linknamed, +// e.g. mapaccess1) is not allowed. + +package main + +import "unsafe" + +func main() { + mapaccess1(nil, nil, nil) +} + +//go:linkname mapaccess1 runtime.mapaccess1 +func mapaccess1(t, m, k unsafe.Pointer) unsafe.Pointer From 6f7a4540b13d6d3be997276178aed96fb0e8a9c2 Mon Sep 17 00:00:00 2001 From: Oleksandr Redko Date: Thu, 12 Dec 2024 20:08:35 +0200 Subject: [PATCH 016/397] net: fix example function name for IP.To4 Change-Id: Ia9a2c3a9f53792173cd1fb9f8e1a078fe3444945 Reviewed-on: https://go-review.googlesource.com/c/go/+/635136 Auto-Submit: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Reviewed-by: Carlos Amedee Reviewed-by: Ian Lance Taylor --- src/net/example_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/net/example_test.go b/src/net/example_test.go index 2c045d73a24bcb..12c83970940ab0 100644 --- a/src/net/example_test.go +++ b/src/net/example_test.go @@ -334,7 +334,7 @@ func ExampleIP_To16() { // 10.255.0.0 } -func ExampleIP_to4() { +func ExampleIP_To4() { ipv6 := net.IP{0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} ipv4 := net.IPv4(10, 255, 0, 0) From 38e9a671d7648227f4f5b133e2e6452491cccebf Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 12 Dec 2024 14:07:13 -0800 Subject: [PATCH 017/397] syscall: on freebsd-386 only update written for certain errors Testing on the freebsd-386 gomote seems to show that sendfile returns a non-zero number of bytes written even when it returns EINVAL. This confuses the caller. Change the Go code to only return non-zero on success or EINTR or EAGAIN, which are the only cases where the man page says that sendfile updates the number of bytes. For #70763 Change-Id: Icc04e6286b5b29a2029237711d50fe4973234f0a Reviewed-on: https://go-review.googlesource.com/c/go/+/635815 Reviewed-by: Ian Lance Taylor Commit-Queue: Ian Lance Taylor Reviewed-by: Damien Neil LUCI-TryBot-Result: Go LUCI Auto-Submit: Ian Lance Taylor --- src/syscall/syscall_freebsd_386.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/syscall/syscall_freebsd_386.go b/src/syscall/syscall_freebsd_386.go index 60359e38f6b50d..a217dc758b904f 100644 --- a/src/syscall/syscall_freebsd_386.go +++ b/src/syscall/syscall_freebsd_386.go @@ -36,7 +36,13 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e var writtenOut uint64 = 0 _, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr((*offset)>>32), uintptr(count), 0, uintptr(unsafe.Pointer(&writtenOut)), 0, 0) - written = int(writtenOut) + // For some reason on the freebsd-386 builder writtenOut + // is modified when the system call returns EINVAL. + // The man page says that the value is only written for + // success, EINTR, or EAGAIN, so only use those cases. + if e1 == 0 || e1 == EINTR || e1 == EAGAIN { + written = int(writtenOut) + } if e1 != 0 { err = e1 From 80a2982a801eaedc416d59801ac8fefcf1e4acf5 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 12 Dec 2024 11:28:09 -0800 Subject: [PATCH 018/397] spec: align EBNF rules consistently (cosmetic change) Change-Id: Ib1b14b8880c6de5606f7f425a5fc1c8749d8a4b7 Reviewed-on: https://go-review.googlesource.com/c/go/+/635799 TryBot-Bypass: Robert Griesemer Reviewed-by: Ian Lance Taylor Reviewed-by: Robert Griesemer Auto-Submit: Robert Griesemer --- doc/go_spec.html | 126 +++++++++++++++++++++++------------------------ 1 file changed, 62 insertions(+), 64 deletions(-) diff --git a/doc/go_spec.html b/doc/go_spec.html index 31bea3713a7c82..282f6cde0c80b3 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -1,6 +1,6 @@ @@ -810,12 +810,12 @@

Types

-Type      = TypeName [ TypeArgs ] | TypeLit | "(" Type ")" .
-TypeName  = identifier | QualifiedIdent .
-TypeArgs  = "[" TypeList [ "," ] "]" .
-TypeList  = Type { "," Type } .
-TypeLit   = ArrayType | StructType | PointerType | FunctionType | InterfaceType |
-            SliceType | MapType | ChannelType .
+Type     = TypeName [ TypeArgs ] | TypeLit | "(" Type ")" .
+TypeName = identifier | QualifiedIdent .
+TypeArgs = "[" TypeList [ "," ] "]" .
+TypeList = Type { "," Type } .
+TypeLit  = ArrayType | StructType | PointerType | FunctionType | InterfaceType |
+           SliceType | MapType | ChannelType .
 

@@ -1222,12 +1222,12 @@

Function types

-FunctionType   = "func" Signature .
-Signature      = Parameters [ Result ] .
-Result         = Parameters | Type .
-Parameters     = "(" [ ParameterList [ "," ] ] ")" .
-ParameterList  = ParameterDecl { "," ParameterDecl } .
-ParameterDecl  = [ IdentifierList ] [ "..." ] Type .
+FunctionType  = "func" Signature .
+Signature     = Parameters [ Result ] .
+Result        = Parameters | Type .
+Parameters    = "(" [ ParameterList [ "," ] ] ")" .
+ParameterList = ParameterDecl { "," ParameterDecl } .
+ParameterDecl = [ IdentifierList ] [ "..." ] Type .
 

@@ -1634,8 +1634,8 @@

Map types

-MapType     = "map" "[" KeyType "]" ElementType .
-KeyType     = Type .
+MapType = "map" "[" KeyType "]" ElementType .
+KeyType = Type .
 

@@ -2176,7 +2176,7 @@

Blocks

-Block = "{" StatementList "}" .
+Block         = "{" StatementList "}" .
 StatementList = { Statement ";" } .
 
@@ -2233,8 +2233,8 @@

Declarations and scope

-Declaration   = ConstDecl | TypeDecl | VarDecl .
-TopLevelDecl  = Declaration | FunctionDecl | MethodDecl .
+Declaration  = ConstDecl | TypeDecl | VarDecl .
+TopLevelDecl = Declaration | FunctionDecl | MethodDecl .
 

@@ -2679,9 +2679,9 @@

Type parameter declarations

-TypeParameters  = "[" TypeParamList [ "," ] "]" .
-TypeParamList   = TypeParamDecl { "," TypeParamDecl } .
-TypeParamDecl   = IdentifierList TypeConstraint .
+TypeParameters = "[" TypeParamList [ "," ] "]" .
+TypeParamList  = TypeParamDecl { "," TypeParamDecl } .
+TypeParamDecl  = IdentifierList TypeConstraint .
 

@@ -2869,8 +2869,8 @@

Variable declarations

-VarDecl     = "var" ( VarSpec | "(" { VarSpec ";" } ")" ) .
-VarSpec     = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList ) .
+VarDecl = "var" ( VarSpec | "(" { VarSpec ";" } ")" ) .
+VarSpec = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList ) .
 
@@ -3210,15 +3210,15 @@ 

Composite literals

-CompositeLit  = LiteralType LiteralValue .
-LiteralType   = StructType | ArrayType | "[" "..." "]" ElementType |
-                SliceType | MapType | TypeName [ TypeArgs ] .
-LiteralValue  = "{" [ ElementList [ "," ] ] "}" .
-ElementList   = KeyedElement { "," KeyedElement } .
-KeyedElement  = [ Key ":" ] Element .
-Key           = FieldName | Expression | LiteralValue .
-FieldName     = identifier .
-Element       = Expression | LiteralValue .
+CompositeLit = LiteralType LiteralValue .
+LiteralType  = StructType | ArrayType | "[" "..." "]" ElementType |
+               SliceType | MapType | TypeName [ TypeArgs ] .
+LiteralValue = "{" [ ElementList [ "," ] ] "}" .
+ElementList  = KeyedElement { "," KeyedElement } .
+KeyedElement = [ Key ":" ] Element .
+Key          = FieldName | Expression | LiteralValue .
+FieldName    = identifier .
+Element      = Expression | LiteralValue .
 

@@ -3450,22 +3450,21 @@

Primary expressions

-PrimaryExpr =
-	Operand |
-	Conversion |
-	MethodExpr |
-	PrimaryExpr Selector |
-	PrimaryExpr Index |
-	PrimaryExpr Slice |
-	PrimaryExpr TypeAssertion |
-	PrimaryExpr Arguments .
+PrimaryExpr   = Operand |
+                Conversion |
+                MethodExpr |
+                PrimaryExpr Selector |
+                PrimaryExpr Index |
+                PrimaryExpr Slice |
+                PrimaryExpr TypeAssertion |
+                PrimaryExpr Arguments .
 
-Selector       = "." identifier .
-Index          = "[" Expression [ "," ] "]" .
-Slice          = "[" [ Expression ] ":" [ Expression ] "]" |
-                 "[" [ Expression ] ":" Expression ":" Expression "]" .
-TypeAssertion  = "." "(" Type ")" .
-Arguments      = "(" [ ( ExpressionList | Type [ "," ExpressionList ] ) [ "..." ] [ "," ] ] ")" .
+Selector      = "." identifier .
+Index         = "[" Expression [ "," ] "]" .
+Slice         = "[" [ Expression ] ":" [ Expression ] "]" |
+                "[" [ Expression ] ":" Expression ":" Expression "]" .
+TypeAssertion = "." "(" Type ")" .
+Arguments     = "(" [ ( ExpressionList | Type [ "," ExpressionList ] ) [ "..." ] [ "," ] ] ")" .
 
@@ -3638,8 +3637,8 @@

Method expressions

-MethodExpr    = ReceiverType "." MethodName .
-ReceiverType  = Type .
+MethodExpr   = ReceiverType "." MethodName .
+ReceiverType = Type .
 

@@ -5916,11 +5915,10 @@

Statements

-Statement =
-	Declaration | LabeledStmt | SimpleStmt |
-	GoStmt | ReturnStmt | BreakStmt | ContinueStmt | GotoStmt |
-	FallthroughStmt | Block | IfStmt | SwitchStmt | SelectStmt | ForStmt |
-	DeferStmt .
+Statement  = Declaration | LabeledStmt | SimpleStmt |
+             GoStmt | ReturnStmt | BreakStmt | ContinueStmt | GotoStmt |
+             FallthroughStmt | Block | IfStmt | SwitchStmt | SelectStmt | ForStmt |
+             DeferStmt .
 
 SimpleStmt = EmptyStmt | ExpressionStmt | SendStmt | IncDecStmt | Assignment | ShortVarDecl .
 
@@ -6132,7 +6130,7 @@

Assignment statements

 Assignment = ExpressionList assign_op ExpressionList .
 
-assign_op = [ add_op | mul_op ] "=" .
+assign_op  = [ add_op | mul_op ] "=" .
 

@@ -6548,7 +6546,7 @@

For statements

-ForStmt = "for" [ Condition | ForClause | RangeClause ] Block .
+ForStmt   = "for" [ Condition | ForClause | RangeClause ] Block .
 Condition = Expression .
 
@@ -6580,8 +6578,8 @@

For statements with for clause

 ForClause = [ InitStmt ] ";" [ Condition ] ";" [ PostStmt ] .
-InitStmt = SimpleStmt .
-PostStmt = SimpleStmt .
+InitStmt  = SimpleStmt .
+PostStmt  = SimpleStmt .
 
@@ -7909,7 +7907,7 @@ 

Source file organization

-SourceFile       = PackageClause ";" { ImportDecl ";" } { TopLevelDecl ";" } .
+SourceFile = PackageClause ";" { ImportDecl ";" } { TopLevelDecl ";" } .
 

Package clause

@@ -7920,8 +7918,8 @@

Package clause

-PackageClause  = "package" PackageName .
-PackageName    = identifier .
+PackageClause = "package" PackageName .
+PackageName   = identifier .
 

@@ -7950,9 +7948,9 @@

Import declarations

-ImportDecl       = "import" ( ImportSpec | "(" { ImportSpec ";" } ")" ) .
-ImportSpec       = [ "." | PackageName ] ImportPath .
-ImportPath       = string_lit .
+ImportDecl = "import" ( ImportSpec | "(" { ImportSpec ";" } ")" ) .
+ImportSpec = [ "." | PackageName ] ImportPath .
+ImportPath = string_lit .
 

From 8391579ecea7dede2f2c1dc79954131e1eae1ade Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Fri, 13 Dec 2024 10:26:50 -0500 Subject: [PATCH 019/397] runtime: migrate missing map linkname allowlists The swissmap implementation forgot to copy some of the linkname allowlists from the old implementation. Copy them from map_noswiss.go. Some were missing linkname entirely; others were linknamed but missing the hall of shame comment. For #54766. Change-Id: Icc715384123e73d868b4cb729ab639abcd6bbfd7 Reviewed-on: https://go-review.googlesource.com/c/go/+/635995 Reviewed-by: Cherry Mui Auto-Submit: Michael Pratt LUCI-TryBot-Result: Go LUCI --- src/runtime/map_swiss.go | 158 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) diff --git a/src/runtime/map_swiss.go b/src/runtime/map_swiss.go index 75c72b20f5771c..e6e29bcfb800bb 100644 --- a/src/runtime/map_swiss.go +++ b/src/runtime/map_swiss.go @@ -39,6 +39,16 @@ func makemap64(t *abi.SwissMapType, hint int64, m *maps.Map) *maps.Map { // makemap_small implements Go map creation for make(map[k]v) and // make(map[k]v, hint) when hint is known to be at most abi.SwissMapGroupSlots // at compile time and the map needs to be allocated on the heap. +// +// makemap_small should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname makemap_small func makemap_small() *maps.Map { return maps.NewEmptyMap() } @@ -48,6 +58,16 @@ func makemap_small() *maps.Map { // can be created on the stack, m and optionally m.dirPtr may be non-nil. // If m != nil, the map can be created directly in m. // If m.dirPtr != nil, it points to a group usable for a small map. +// +// makemap should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/ugorji/go/codec +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname makemap func makemap(t *abi.SwissMapType, hint int, m *maps.Map) *maps.Map { if hint < 0 { hint = 0 @@ -68,6 +88,15 @@ func makemap(t *abi.SwissMapType, hint int, m *maps.Map) *maps.Map { //go:linkname mapaccess1 func mapaccess1(t *abi.SwissMapType, m *maps.Map, key unsafe.Pointer) unsafe.Pointer +// mapaccess2 should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/ugorji/go/codec +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mapaccess2 func mapaccess2(t *abi.SwissMapType, m *maps.Map, key unsafe.Pointer) (unsafe.Pointer, bool) func mapaccess1_fat(t *abi.SwissMapType, m *maps.Map, key, zero unsafe.Pointer) unsafe.Pointer { @@ -89,9 +118,29 @@ func mapaccess2_fat(t *abi.SwissMapType, m *maps.Map, key, zero unsafe.Pointer) // mapassign is pushed from internal/runtime/maps. We could just call it, but // we want to avoid one layer of call. // +// mapassign should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// - github.com/RomiChan/protobuf +// - github.com/segmentio/encoding +// - github.com/ugorji/go/codec +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname mapassign func mapassign(t *abi.SwissMapType, m *maps.Map, key unsafe.Pointer) unsafe.Pointer +// mapdelete should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/ugorji/go/codec +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mapdelete func mapdelete(t *abi.SwissMapType, m *maps.Map, key unsafe.Pointer) { if raceenabled && m != nil { callerpc := sys.GetCallerPC() @@ -113,6 +162,21 @@ func mapdelete(t *abi.SwissMapType, m *maps.Map, key unsafe.Pointer) { // The Iter struct pointed to by 'it' is allocated on the stack // by the compilers order pass or on the heap by reflect_mapiterinit. // Both need to have zeroed hiter since the struct contains pointers. +// +// mapiterinit should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// - github.com/goccy/go-json +// - github.com/RomiChan/protobuf +// - github.com/segmentio/encoding +// - github.com/ugorji/go/codec +// - github.com/wI2L/jettison +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mapiterinit func mapiterinit(t *abi.SwissMapType, m *maps.Map, it *maps.Iter) { if raceenabled && m != nil { callerpc := sys.GetCallerPC() @@ -123,6 +187,19 @@ func mapiterinit(t *abi.SwissMapType, m *maps.Map, it *maps.Iter) { it.Next() } +// mapiternext should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// - github.com/RomiChan/protobuf +// - github.com/segmentio/encoding +// - github.com/ugorji/go/codec +// - gonum.org/v1/gonum +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mapiternext func mapiternext(it *maps.Iter) { if raceenabled { callerpc := sys.GetCallerPC() @@ -145,6 +222,19 @@ func mapclear(t *abi.SwissMapType, m *maps.Map) { // Reflect stubs. Called from ../reflect/asm_*.s +// reflect_makemap is for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gitee.com/quant1x/gox +// - github.com/modern-go/reflect2 +// - github.com/goccy/go-json +// - github.com/RomiChan/protobuf +// - github.com/segmentio/encoding +// - github.com/v2pro/plz +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname reflect_makemap reflect.makemap func reflect_makemap(t *abi.SwissMapType, cap int) *maps.Map { // Check invariants and reflects math. @@ -156,6 +246,16 @@ func reflect_makemap(t *abi.SwissMapType, cap int) *maps.Map { return makemap(t, cap, nil) } +// reflect_mapaccess is for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gitee.com/quant1x/gox +// - github.com/modern-go/reflect2 +// - github.com/v2pro/plz +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname reflect_mapaccess reflect.mapaccess func reflect_mapaccess(t *abi.SwissMapType, m *maps.Map, key unsafe.Pointer) unsafe.Pointer { elem, ok := mapaccess2(t, m, key) @@ -176,6 +276,14 @@ func reflect_mapaccess_faststr(t *abi.SwissMapType, m *maps.Map, key string) uns return elem } +// reflect_mapassign is for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gitee.com/quant1x/gox +// - github.com/v2pro/plz +// +// Do not remove or change the type signature. +// //go:linkname reflect_mapassign reflect.mapassign0 func reflect_mapassign(t *abi.SwissMapType, m *maps.Map, key unsafe.Pointer, elem unsafe.Pointer) { p := mapassign(t, m, key) @@ -198,26 +306,76 @@ func reflect_mapdelete_faststr(t *abi.SwissMapType, m *maps.Map, key string) { mapdelete_faststr(t, m, key) } +// reflect_mapiterinit is for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/modern-go/reflect2 +// - gitee.com/quant1x/gox +// - github.com/v2pro/plz +// - github.com/wI2L/jettison +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname reflect_mapiterinit reflect.mapiterinit func reflect_mapiterinit(t *abi.SwissMapType, m *maps.Map, it *maps.Iter) { mapiterinit(t, m, it) } +// reflect_mapiternext is for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gitee.com/quant1x/gox +// - github.com/modern-go/reflect2 +// - github.com/goccy/go-json +// - github.com/v2pro/plz +// - github.com/wI2L/jettison +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname reflect_mapiternext reflect.mapiternext func reflect_mapiternext(it *maps.Iter) { mapiternext(it) } +// reflect_mapiterkey was for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/goccy/go-json +// - gonum.org/v1/gonum +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname reflect_mapiterkey reflect.mapiterkey func reflect_mapiterkey(it *maps.Iter) unsafe.Pointer { return it.Key() } +// reflect_mapiterelem was for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/goccy/go-json +// - gonum.org/v1/gonum +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname reflect_mapiterelem reflect.mapiterelem func reflect_mapiterelem(it *maps.Iter) unsafe.Pointer { return it.Elem() } +// reflect_maplen is for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/goccy/go-json +// - github.com/wI2L/jettison +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname reflect_maplen reflect.maplen func reflect_maplen(m *maps.Map) int { if m == nil { From 1cbfe8c482a0ca0eb59daa89b92a10b7052d1a0f Mon Sep 17 00:00:00 2001 From: thepudds Date: Tue, 19 Sep 2023 14:44:08 -0400 Subject: [PATCH 020/397] fmt: add more function and allocation tests This is part of a series of CLs that aim to reduce how often interface arguments escape for the print functions in fmt. Currently, method values are one of two reasons reflect.Value.Interface always escapes its reflect.Value. Our later CLs modify behavior around method values, so we add some tests of function formatting (including method values) to help reduce the chances of breaking behavior later. We also add in some allocation tests focused on interface arguments for the print functions. These currently do not show any improvements compared to Go 1.21. These tests were originally in a later CL in our stack (CL 528538), but we split them out into this CL and moved them earlier in the stack. Updates #8618 Change-Id: Iec51abc3b7f86a2711e7497fc2fb7a678b9f8f73 Reviewed-on: https://go-review.googlesource.com/c/go/+/529575 Reviewed-by: Carlos Amedee Auto-Submit: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Reviewed-by: Ian Lance Taylor --- src/fmt/fmt_test.go | 68 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 64 insertions(+), 4 deletions(-) diff --git a/src/fmt/fmt_test.go b/src/fmt/fmt_test.go index b7f9ccd494d099..82daf627717814 100644 --- a/src/fmt/fmt_test.go +++ b/src/fmt/fmt_test.go @@ -11,7 +11,6 @@ import ( "io" "math" "reflect" - "runtime" "strings" "testing" "time" @@ -112,6 +111,19 @@ func (p *P) String() string { return "String(p)" } +// Fn is a function type with a String method. +type Fn func() int + +func (fn Fn) String() string { return "String(fn)" } + +var fnValue Fn + +// U is a type with two unexported function fields. +type U struct { + u func() string + fn Fn +} + var barray = [5]renamedUint8{1, 2, 3, 4, 5} var bslice = barray[:] @@ -714,7 +726,6 @@ var fmtTests = []struct { // go syntax {"%#v", A{1, 2, "a", []int{1, 2}}, `fmt_test.A{i:1, j:0x2, s:"a", x:[]int{1, 2}}`}, {"%#v", new(byte), "(*uint8)(0xPTR)"}, - {"%#v", TestFmtInterface, "(func(*testing.T))(0xPTR)"}, {"%#v", make(chan int), "(chan int)(0xPTR)"}, {"%#v", uint64(1<<64 - 1), "0xffffffffffffffff"}, {"%#v", 1000000000, "1000000000"}, @@ -737,6 +748,54 @@ var fmtTests = []struct { {"%#v", 1.2345678, "1.2345678"}, {"%#v", float32(1.2345678), "1.2345678"}, + // functions + {"%v", TestFmtInterface, "0xPTR"}, // simple function + {"%v", reflect.ValueOf(TestFmtInterface), "0xPTR"}, + {"%v", G.GoString, "0xPTR"}, // method expression + {"%v", reflect.ValueOf(G.GoString), "0xPTR"}, + {"%v", G(23).GoString, "0xPTR"}, // method value + {"%v", reflect.ValueOf(G(23).GoString), "0xPTR"}, + {"%v", reflect.ValueOf(G(23)).Method(0), "0xPTR"}, + {"%v", Fn.String, "0xPTR"}, // method of function type + {"%v", reflect.ValueOf(Fn.String), "0xPTR"}, + {"%v", fnValue, "String(fn)"}, // variable of function type with String method + {"%v", reflect.ValueOf(fnValue), "String(fn)"}, + {"%v", [1]Fn{fnValue}, "[String(fn)]"}, // array of function type with String method + {"%v", reflect.ValueOf([1]Fn{fnValue}), "[String(fn)]"}, + {"%v", fnValue.String, "0xPTR"}, // method value from function type + {"%v", reflect.ValueOf(fnValue.String), "0xPTR"}, + {"%v", reflect.ValueOf(fnValue).Method(0), "0xPTR"}, + {"%v", U{}.u, ""}, // unexported function field + {"%v", reflect.ValueOf(U{}.u), ""}, + {"%v", reflect.ValueOf(U{}).Field(0), ""}, + {"%v", U{fn: fnValue}.fn, "String(fn)"}, // unexported field of function type with String method + {"%v", reflect.ValueOf(U{fn: fnValue}.fn), "String(fn)"}, + {"%v", reflect.ValueOf(U{fn: fnValue}).Field(1), ""}, + + // functions with go syntax + {"%#v", TestFmtInterface, "(func(*testing.T))(0xPTR)"}, // simple function + {"%#v", reflect.ValueOf(TestFmtInterface), "(func(*testing.T))(0xPTR)"}, + {"%#v", G.GoString, "(func(fmt_test.G) string)(0xPTR)"}, // method expression + {"%#v", reflect.ValueOf(G.GoString), "(func(fmt_test.G) string)(0xPTR)"}, + {"%#v", G(23).GoString, "(func() string)(0xPTR)"}, // method value + {"%#v", reflect.ValueOf(G(23).GoString), "(func() string)(0xPTR)"}, + {"%#v", reflect.ValueOf(G(23)).Method(0), "(func() string)(0xPTR)"}, + {"%#v", Fn.String, "(func(fmt_test.Fn) string)(0xPTR)"}, // method of function type + {"%#v", reflect.ValueOf(Fn.String), "(func(fmt_test.Fn) string)(0xPTR)"}, + {"%#v", fnValue, "(fmt_test.Fn)(nil)"}, // variable of function type with String method + {"%#v", reflect.ValueOf(fnValue), "(fmt_test.Fn)(nil)"}, + {"%#v", [1]Fn{fnValue}, "[1]fmt_test.Fn{(fmt_test.Fn)(nil)}"}, // array of function type with String method + {"%#v", reflect.ValueOf([1]Fn{fnValue}), "[1]fmt_test.Fn{(fmt_test.Fn)(nil)}"}, + {"%#v", fnValue.String, "(func() string)(0xPTR)"}, // method value from function type + {"%#v", reflect.ValueOf(fnValue.String), "(func() string)(0xPTR)"}, + {"%#v", reflect.ValueOf(fnValue).Method(0), "(func() string)(0xPTR)"}, + {"%#v", U{}.u, "(func() string)(nil)"}, // unexported function field + {"%#v", reflect.ValueOf(U{}.u), "(func() string)(nil)"}, + {"%#v", reflect.ValueOf(U{}).Field(0), "(func() string)(nil)"}, + {"%#v", U{fn: fnValue}.fn, "(fmt_test.Fn)(nil)"}, // unexported field of function type with String method + {"%#v", reflect.ValueOf(U{fn: fnValue}.fn), "(fmt_test.Fn)(nil)"}, + {"%#v", reflect.ValueOf(U{fn: fnValue}).Field(1), "(fmt_test.Fn)(nil)"}, + // Whole number floats are printed without decimals. See Issue 27634. {"%#v", 1.0, "1"}, {"%#v", 1000000.0, "1e+06"}, @@ -1438,6 +1497,9 @@ var mallocTest = []struct { {0, `Fprintf(buf, "%s")`, func() { mallocBuf.Reset(); Fprintf(&mallocBuf, "%s", "hello") }}, {0, `Fprintf(buf, "%x")`, func() { mallocBuf.Reset(); Fprintf(&mallocBuf, "%x", 7) }}, {0, `Fprintf(buf, "%x")`, func() { mallocBuf.Reset(); Fprintf(&mallocBuf, "%x", 1<<16) }}, + {1, `Fprintf(buf, "%x")`, func() { mallocBuf.Reset(); i := 1 << 16; Fprintf(&mallocBuf, "%x", i) }}, // not constant + {4, `Fprintf(buf, "%v")`, func() { mallocBuf.Reset(); s := []int{1, 2}; Fprintf(&mallocBuf, "%v", s) }}, + {1, `Fprintf(buf, "%v")`, func() { mallocBuf.Reset(); type P struct{ x, y int }; Fprintf(&mallocBuf, "%v", P{1, 2}) }}, {2, `Fprintf(buf, "%80000s")`, func() { mallocBuf.Reset(); Fprintf(&mallocBuf, "%80000s", "hello") }}, // large buffer (>64KB) // If the interface value doesn't need to allocate, amortized allocation overhead should be zero. {0, `Fprintf(buf, "%x %x %x")`, func() { @@ -1452,8 +1514,6 @@ func TestCountMallocs(t *testing.T) { switch { case testing.Short(): t.Skip("skipping malloc count in short mode") - case runtime.GOMAXPROCS(0) > 1: - t.Skip("skipping; GOMAXPROCS>1") case race.Enabled: t.Skip("skipping malloc count under race detector") } From 08725f9de28726b52c2e62a37cd378d10f10c110 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Fri, 13 Dec 2024 17:16:44 +0100 Subject: [PATCH 021/397] crypto/internal/cryptotest: skip TestAllocations on s390x TestXAESAllocations fails like #70448, and crypto/rand's fails in FIPS mode. We can't keep chasing these without even a LUCI builder. Updates #67307 Change-Id: I5d0edddf470180a321dec55cabfb018db62eb940 Reviewed-on: https://go-review.googlesource.com/c/go/+/636055 Auto-Submit: Filippo Valsorda Reviewed-by: Roland Shoemaker LUCI-TryBot-Result: Go LUCI Reviewed-by: Carlos Amedee --- src/crypto/internal/cryptotest/allocations.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/crypto/internal/cryptotest/allocations.go b/src/crypto/internal/cryptotest/allocations.go index 0194c2f89dc77e..70055af70b42ec 100644 --- a/src/crypto/internal/cryptotest/allocations.go +++ b/src/crypto/internal/cryptotest/allocations.go @@ -32,6 +32,12 @@ func SkipTestAllocations(t *testing.T) { t.Skip("skipping allocations test on plan9") } + // s390x deviates from other assembly implementations and is very hard to + // test due to the lack of LUCI builders. See #67307. + if runtime.GOARCH == "s390x" { + t.Skip("skipping allocations test on s390x") + } + // Some APIs rely on inliner and devirtualization to allocate on the stack. testenv.SkipIfOptimizationOff(t) } From c4f356dd863c449835248c24f6dc653323010a1c Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Fri, 13 Dec 2024 16:59:20 +0100 Subject: [PATCH 022/397] crypto/ecdsa: fix s390x assembly with P-521 I had incorrectly assumed that the blocksize was always the same as the curve field size. This is true of P-256 and P-384, but not P-521. Fixes #70660 Fixes #70771 Change-Id: Idb6b510fcd3dd42d9b1e6cf42c1bb92e0ce8bd07 Reviewed-on: https://go-review.googlesource.com/c/go/+/636015 Run-TryBot: Filippo Valsorda Reviewed-by: Carlos Amedee LUCI-TryBot-Result: Go LUCI Auto-Submit: Filippo Valsorda TryBot-Result: Gopher Robot Reviewed-by: Roland Shoemaker --- src/crypto/internal/fips140/ecdsa/ecdsa.go | 4 +- .../internal/fips140/ecdsa/ecdsa_s390x.go | 53 +++++++++++++++---- 2 files changed, 44 insertions(+), 13 deletions(-) diff --git a/src/crypto/internal/fips140/ecdsa/ecdsa.go b/src/crypto/internal/fips140/ecdsa/ecdsa.go index 9459b03de76484..11389e8210bc68 100644 --- a/src/crypto/internal/fips140/ecdsa/ecdsa.go +++ b/src/crypto/internal/fips140/ecdsa/ecdsa.go @@ -21,7 +21,7 @@ import ( type PrivateKey struct { pub PublicKey - d []byte // bigmod.(*Nat).Bytes output (fixed length) + d []byte // bigmod.(*Nat).Bytes output (same length as the curve order) } func (priv *PrivateKey) Bytes() []byte { @@ -262,7 +262,7 @@ func randomPoint[P Point[P]](c *Curve[P], generate func([]byte) error) (k *bigmo var testingOnlyRejectionSamplingLooped func() // Signature is an ECDSA signature, where r and s are represented as big-endian -// fixed-length byte slices. +// byte slices of the same length as the curve order. type Signature struct { R, S []byte } diff --git a/src/crypto/internal/fips140/ecdsa/ecdsa_s390x.go b/src/crypto/internal/fips140/ecdsa/ecdsa_s390x.go index 01379f998f10e2..271a35897f8c8f 100644 --- a/src/crypto/internal/fips140/ecdsa/ecdsa_s390x.go +++ b/src/crypto/internal/fips140/ecdsa/ecdsa_s390x.go @@ -47,15 +47,34 @@ func canUseKDSA(c curveID) (functionCode uint64, blockSize int, ok bool) { case p384: return 2, 48, true case p521: + // Note that the block size doesn't match the field size for P-521. return 3, 80, true } return 0, 0, false // A mismatch } -func hashToBytes[P Point[P]](c *Curve[P], dst, hash []byte) { +func hashToBytes[P Point[P]](c *Curve[P], hash []byte) []byte { e := bigmod.NewNat() hashToNat(c, e, hash) - copy(dst, e.Bytes(c.N)) + return e.Bytes(c.N) +} + +func appendBlock(p []byte, blocksize int, b []byte) []byte { + if len(b) > blocksize { + panic("ecdsa: internal error: appendBlock input larger than block") + } + padding := blocksize - len(b) + p = append(p, make([]byte, padding)...) + return append(p, b...) +} + +func trimBlock(p []byte, size int) ([]byte, error) { + for _, b := range p[:len(p)-size] { + if b != 0 { + return nil, errors.New("ecdsa: internal error: KDSA produced invalid signature") + } + } + return p[len(p)-size:], nil } func sign[P Point[P]](c *Curve[P], priv *PrivateKey, drbg *hmacDRBG, hash []byte) (*Signature, error) { @@ -95,17 +114,27 @@ func sign[P Point[P]](c *Curve[P], priv *PrivateKey, drbg *hmacDRBG, hash []byte // Copy content into the parameter block. In the sign case, // we copy hashed message, private key and random number into - // the parameter block. - hashToBytes(c, params[2*blockSize:3*blockSize], hash) - copy(params[3*blockSize+blockSize-len(priv.d):], priv.d) - copy(params[4*blockSize:5*blockSize], k.Bytes(c.N)) + // the parameter block. We skip the signature slots. + p := params[:2*blockSize] + p = appendBlock(p, blockSize, hashToBytes(c, hash)) + p = appendBlock(p, blockSize, priv.d) + p = appendBlock(p, blockSize, k.Bytes(c.N)) // Convert verify function code into a sign function code by adding 8. // We also need to set the 'deterministic' bit in the function code, by // adding 128, in order to stop the instruction using its own random number // generator in addition to the random number we supply. switch kdsa(functionCode+136, ¶ms) { case 0: // success - return &Signature{R: params[:blockSize], S: params[blockSize : 2*blockSize]}, nil + elementSize := (c.N.BitLen() + 7) / 8 + r, err := trimBlock(params[:blockSize], elementSize) + if err != nil { + return nil, err + } + s, err := trimBlock(params[blockSize:2*blockSize], elementSize) + if err != nil { + return nil, err + } + return &Signature{R: r, S: s}, nil case 1: // error return nil, errors.New("zero parameter") case 2: // retry @@ -149,10 +178,12 @@ func verify[P Point[P]](c *Curve[P], pub *PublicKey, hash []byte, sig *Signature // Copy content into the parameter block. In the verify case, // we copy signature (r), signature(s), hashed message, public key x component, // and public key y component into the parameter block. - copy(params[0*blockSize+blockSize-len(r):], r) - copy(params[1*blockSize+blockSize-len(s):], s) - hashToBytes(c, params[2*blockSize:3*blockSize], hash) - copy(params[3*blockSize:5*blockSize], pub.q[1:]) // strip 0x04 prefix + p := params[:0] + p = appendBlock(p, blockSize, r) + p = appendBlock(p, blockSize, s) + p = appendBlock(p, blockSize, hashToBytes(c, hash)) + p = appendBlock(p, blockSize, pub.q[1:1+len(pub.q)/2]) + p = appendBlock(p, blockSize, pub.q[1+len(pub.q)/2:]) if kdsa(functionCode, ¶ms) != 0 { return errors.New("invalid signature") } From 08770a5b944ba1cf4f62f075bfd94cd36a061bdb Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Fri, 13 Dec 2024 15:05:27 -0500 Subject: [PATCH 023/397] cmd/link: make dwarf name slice index self-describing cmd/compile/internal/dwarfgen.createComplexVar does it this way, which has the nice property of documenting the expected prefix. This is primarily for newtype, since defgotype checks for the prefix immediately prior, but I changed both for consistency. Change-Id: I49fa7c6166bdcbd19aaf91fe3dc20537080afcfc Reviewed-on: https://go-review.googlesource.com/c/go/+/635177 Reviewed-by: Michael Knyszek LUCI-TryBot-Result: Go LUCI Auto-Submit: Michael Pratt --- src/cmd/link/internal/ld/dwarf.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go index 14c0b687d853a3..b653e09a3c1b91 100644 --- a/src/cmd/link/internal/ld/dwarf.go +++ b/src/cmd/link/internal/ld/dwarf.go @@ -520,7 +520,7 @@ func (d *dwctxt) defgotype(gotype loader.Sym) loader.Sym { d.linkctxt.Errorf(gotype, "dwarf: type name doesn't start with \"type:\"") return d.mustFind("") } - name := sn[5:] // could also decode from Type.string + name := sn[len("type:"):] // could also decode from Type.string sdie := d.find(name) if sdie != 0 { @@ -534,7 +534,7 @@ func (d *dwctxt) defgotype(gotype loader.Sym) loader.Sym { func (d *dwctxt) newtype(gotype loader.Sym) *dwarf.DWDie { sn := d.ldr.SymName(gotype) - name := sn[5:] // could also decode from Type.string + name := sn[len("type:"):] // could also decode from Type.string tdata := d.ldr.Data(gotype) if len(tdata) == 0 { d.linkctxt.Errorf(gotype, "missing type") From e39e965e0e0cce65ca977fd0da35f5bfb68dc2b8 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 13 Dec 2024 15:36:47 -0500 Subject: [PATCH 024/397] cmd/go: drop FailedBuild field if gotestjsonbuildtext=1 go test -json has two new effects in Go 1.24: it implies go build -json, and it adds a FailedBuild field in test events. For compatibility, CL 629335 added gotestjsonbuildtext=1, which disables the implicit go build -json, but that CL didn't affect the FailedBuild field. In principle this shouldn't matter because it's just another JSON field, but just so we don't have to worry about some intermediate behavior, this CL makes gotestjsonbuildtext=1 disable the FailedBuild field as well. Updates #62067 Updates #70402 Change-Id: I006d1ea0468980ee2564495324e8b4ed082898af Reviewed-on: https://go-review.googlesource.com/c/go/+/635899 Auto-Submit: Austin Clements Reviewed-by: Dmitri Shuralyov LUCI-TryBot-Result: Go LUCI Reviewed-by: Dmitri Shuralyov --- src/cmd/go/internal/test/test.go | 14 ++++++++++++-- src/cmd/go/testdata/script/test_json_build.txt | 5 +++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/cmd/go/internal/test/test.go b/src/cmd/go/internal/test/test.go index 41ddb2f5d01e77..b530d027dff4e0 100644 --- a/src/cmd/go/internal/test/test.go +++ b/src/cmd/go/internal/test/test.go @@ -1009,7 +1009,13 @@ func runTest(ctx context.Context, cmd *base.Command, args []string) { json.Exited(err) json.Close() }() - json.SetFailedBuild(perr.Desc()) + if gotestjsonbuildtext.Value() == "1" { + // While this flag is about go build -json, the other effect + // of that change was to include "FailedBuild" in the test JSON. + gotestjsonbuildtext.IncNonDefault() + } else { + json.SetFailedBuild(perr.Desc()) + } stdout = json } fmt.Fprintf(stdout, "FAIL\t%s [setup failed]\n", p.ImportPath) @@ -1437,7 +1443,11 @@ func (r *runTestActor) Act(b *work.Builder, ctx context.Context, a *work.Action) if a.Failed != nil { // We were unable to build the binary. if json != nil && a.Failed.Package != nil { - json.SetFailedBuild(a.Failed.Package.Desc()) + if gotestjsonbuildtext.Value() == "1" { + gotestjsonbuildtext.IncNonDefault() + } else { + json.SetFailedBuild(a.Failed.Package.Desc()) + } } a.Failed = nil fmt.Fprintf(stdout, "FAIL\t%s [build failed]\n", a.Package.ImportPath) diff --git a/src/cmd/go/testdata/script/test_json_build.txt b/src/cmd/go/testdata/script/test_json_build.txt index a3f0c37923faf5..0a40649dcce8df 100644 --- a/src/cmd/go/testdata/script/test_json_build.txt +++ b/src/cmd/go/testdata/script/test_json_build.txt @@ -58,8 +58,9 @@ stderr '# m/builderror \[m/builderror.test\]\n' stderr 'builderror'${/}'main_test.go:3:11: undefined: y\n' stdout '"Action":"start","Package":"m/builderror"' stdout '"Action":"output","Package":"m/builderror","Output":"FAIL\\tm/builderror \[build failed\]\\n"' -stdout '"Action":"fail","Package":"m/builderror","Elapsed":.*,"FailedBuild":"m/builderror \[m/builderror\.test\]"' - +stdout '"Action":"fail","Package":"m/builderror","Elapsed":[0-9.]+\}' +# FailedBuild should NOT appear in the output in this mode. +! stdout '"FailedBuild"' -- go.mod -- module m From 090748d6c7973e9bb8f5efe069135c8ea0f0d89c Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Thu, 12 Dec 2024 15:43:37 -0500 Subject: [PATCH 025/397] testing: improve B.Loop docs, use B.Loop in examples This updates the testing documentation to frame B.Loop as the canonical way to write benchmarks. We retain documentation on b.N benchmarks because people will definitely continue to see them (and write them), but it's demoted to clearly second class. This also attempts to clarify and refine the B.Loop documentation itself. Updates #61515 Fixes #70787 Change-Id: If5123435bfe3a5883a753119ecdf7bbc41afd499 Reviewed-on: https://go-review.googlesource.com/c/go/+/635895 Reviewed-by: Junyang Shao Reviewed-by: Caleb Spare LUCI-TryBot-Result: Go LUCI Auto-Submit: Austin Clements --- src/testing/benchmark.go | 54 +++++++++++++++++++++-------------- src/testing/benchmark_test.go | 4 +-- src/testing/testing.go | 46 +++++++++++++++++++++++------ 3 files changed, 71 insertions(+), 33 deletions(-) diff --git a/src/testing/benchmark.go b/src/testing/benchmark.go index 78e1b2de6d1247..8b84444f3824f0 100644 --- a/src/testing/benchmark.go +++ b/src/testing/benchmark.go @@ -78,7 +78,7 @@ type InternalBenchmark struct { } // B is a type passed to [Benchmark] functions to manage benchmark -// timing and to specify the number of iterations to run. +// timing and control the number of iterations. // // A benchmark ends when its Benchmark function returns or calls any of the methods // FailNow, Fatal, Fatalf, SkipNow, Skip, or Skipf. Those methods must be called @@ -133,8 +133,7 @@ func (b *B) StartTimer() { } // StopTimer stops timing a test. This can be used to pause the timer -// while performing complex initialization that you don't -// want to measure. +// while performing steps that you don't want to measure. func (b *B) StopTimer() { if b.timerOn { b.duration += highPrecisionTimeSince(b.start) @@ -387,7 +386,7 @@ func (b *B) loopSlowPath() bool { b.ResetTimer() return true } - // Handles fixed time case + // Handles fixed iterations case if b.benchTime.n > 0 { if b.N < b.benchTime.n { b.N = b.benchTime.n @@ -396,31 +395,42 @@ func (b *B) loopSlowPath() bool { } return false } - // Handles fixed iteration count case + // Handles fixed time case return b.stopOrScaleBLoop() } -// Loop returns true until b.N calls has been made to it. -// -// A benchmark should either use Loop or contain an explicit loop from 0 to b.N, but not both. -// After the benchmark finishes, b.N will contain the total number of calls to op, so the benchmark -// may use b.N to compute other average metrics. +// Loop returns true as long as the benchmark should continue running. // -// The parameters and results of function calls inside the body of "for b.Loop() {...}" are guaranteed -// not to be optimized away. -// Also, the local loop scaling for b.Loop ensures the benchmark function containing the loop will only -// be executed once, i.e. for such construct: +// A typical benchmark is structured like: // -// testing.Benchmark(func(b *testing.B) { -// ...(setup) -// for b.Loop() { -// ...(benchmark logic) -// } -// ...(clean-up) +// func Benchmark(b *testing.B) { +// ... setup ... +// for b.Loop() { +// ... code to measure ... +// } +// ... cleanup ... // } // -// The ...(setup) and ...(clean-up) logic will only be executed once. -// Also benchtime=Nx (N>1) will result in exactly N executions instead of N+1 for b.N style loops. +// Loop resets the benchmark timer the first time it is called in a benchmark, +// so any setup performed prior to starting the benchmark loop does not count +// toward the benchmark measurement. +// +// The compiler never optimizes away calls to functions within the body of a +// "for b.Loop() { ... }" loop. This prevents surprises that can otherwise occur +// if the compiler determines that the result of a benchmarked function is +// unused. The loop must be written in exactly this form, and this only applies +// to calls syntactically between the curly braces of the loop. Optimizations +// are performed as usual in any functions called by the loop. +// +// After Loop returns false, b.N contains the total number of iterations that +// ran, so the benchmark may use b.N to compute other average metrics. +// +// Prior to the introduction of Loop, benchmarks were expected to contain an +// explicit loop from 0 to b.N. Benchmarks should either use Loop or contain a +// loop to b.N, but not both. Loop offers more automatic management of the +// benchmark timer, and runs each benchmark function only once per measurement, +// whereas b.N-based benchmarks must run the benchmark function (and any +// associated setup and cleanup) several times. func (b *B) Loop() bool { if b.loopN != 0 && b.loopN < b.N { b.loopN++ diff --git a/src/testing/benchmark_test.go b/src/testing/benchmark_test.go index 259b70ed4c95e0..b3089b311991c2 100644 --- a/src/testing/benchmark_test.go +++ b/src/testing/benchmark_test.go @@ -155,7 +155,7 @@ func ExampleB_Loop() { } n := 0 testing.Benchmark(func(b *testing.B) { - // Unlike "for i := range N {...}" style loops, this + // Unlike "for i := range b.N {...}" style loops, this // setup logic will only be executed once, so simpleFunc // will always get argument 1. n++ @@ -219,7 +219,7 @@ func ExampleB_ReportMetric() { // specific algorithm (in this case, sorting). testing.Benchmark(func(b *testing.B) { var compares int64 - for i := 0; i < b.N; i++ { + for b.Loop() { s := []int{5, 4, 3, 2, 1} slices.SortFunc(s, func(a, b int) int { compares++ diff --git a/src/testing/testing.go b/src/testing/testing.go index e353ceb74119a3..8b4bdfbc39828e 100644 --- a/src/testing/testing.go +++ b/src/testing/testing.go @@ -72,27 +72,24 @@ // A sample benchmark function looks like this: // // func BenchmarkRandInt(b *testing.B) { -// for range b.N { +// for b.Loop() { // rand.Int() // } // } // -// The benchmark function must run the target code b.N times. -// It is called multiple times with b.N adjusted until the -// benchmark function lasts long enough to be timed reliably. // The output // // BenchmarkRandInt-8 68453040 17.8 ns/op // -// means that the loop ran 68453040 times at a speed of 17.8 ns per loop. +// means that the body of the loop ran 68453040 times at a speed of 17.8 ns per loop. // -// If a benchmark needs some expensive setup before running, the timer -// may be reset: +// Only the body of the loop is timed, so benchmarks may do expensive +// setup before calling b.Loop, which will not be counted toward the +// benchmark measurement: // // func BenchmarkBigLen(b *testing.B) { // big := NewBig() -// b.ResetTimer() -// for range b.N { +// for b.Loop() { // big.Len() // } // } @@ -120,6 +117,37 @@ // In particular, https://golang.org/x/perf/cmd/benchstat performs // statistically robust A/B comparisons. // +// # b.N-style benchmarks +// +// Prior to the introduction of [B.Loop], benchmarks were written in a +// different style using [B.N]. For example: +// +// func BenchmarkRandInt(b *testing.B) { +// for range b.N { +// rand.Int() +// } +// } +// +// In this style of benchmark, the benchmark function must run +// the target code b.N times. The benchmark function is called +// multiple times with b.N adjusted until the benchmark function +// lasts long enough to be timed reliably. This also means any setup +// done before the loop may be run several times. +// +// If a benchmark needs some expensive setup before running, the timer +// should be explicitly reset: +// +// func BenchmarkBigLen(b *testing.B) { +// big := NewBig() +// b.ResetTimer() +// for range b.N { +// big.Len() +// } +// } +// +// New benchmarks should prefer using [B.Loop], which is more robust +// and more efficient. +// // # Examples // // The package also runs and verifies example code. Example functions may From 6bd56fcaebde61eb6bd21906a7d7136d009be4a6 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Thu, 12 Dec 2024 18:19:43 -0500 Subject: [PATCH 026/397] testing: improve b.Loop example The current b.Loop example doesn't focus on the basic usage of b.Loop. Replace this with a new example that uses (slightly) more realistic things to demonstrate the most salient points of b.Loop. We also move the example into an example file so that we can write a real Benchmark function and a real function to be benchmarks, which makes this much closer to what a user would actually write. Updates #61515. Change-Id: I4d830b3bfe3eb3cd8cdecef469fea0541baebb43 Reviewed-on: https://go-review.googlesource.com/c/go/+/635896 Auto-Submit: Austin Clements Reviewed-by: Junyang Shao Reviewed-by: Cherry Mui LUCI-TryBot-Result: Go LUCI --- src/testing/benchmark_test.go | 30 -------------------- src/testing/example_loop_test.go | 48 ++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 30 deletions(-) create mode 100644 src/testing/example_loop_test.go diff --git a/src/testing/benchmark_test.go b/src/testing/benchmark_test.go index b3089b311991c2..239e7300211f5e 100644 --- a/src/testing/benchmark_test.go +++ b/src/testing/benchmark_test.go @@ -149,36 +149,6 @@ func TestBLoopHasResults(t *testing.T) { } } -func ExampleB_Loop() { - simpleFunc := func(i int) int { - return i + 1 - } - n := 0 - testing.Benchmark(func(b *testing.B) { - // Unlike "for i := range b.N {...}" style loops, this - // setup logic will only be executed once, so simpleFunc - // will always get argument 1. - n++ - // It behaves just like "for i := range N {...}", except with keeping - // function call parameters and results alive. - for b.Loop() { - // This function call, if was in a normal loop, will be optimized away - // completely, first by inlining, then by dead code elimination. - // In a b.Loop loop, the compiler ensures that this function is not optimized away. - simpleFunc(n) - } - // This clean-up will only be executed once, so after the benchmark, the user - // will see n == 2. - n++ - // Use b.ReportMetric as usual just like what a user may do after - // b.N loop. - }) - // We can expect n == 2 here. - - // The return value of the above Benchmark could be used just like - // a b.N loop benchmark as well. -} - func ExampleB_RunParallel() { // Parallel benchmark for text/template.Template.Execute on a single object. testing.Benchmark(func(b *testing.B) { diff --git a/src/testing/example_loop_test.go b/src/testing/example_loop_test.go new file mode 100644 index 00000000000000..eff8bab352058f --- /dev/null +++ b/src/testing/example_loop_test.go @@ -0,0 +1,48 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package testing_test + +import ( + "math/rand/v2" + "testing" +) + +// ExBenchmark shows how to use b.Loop in a benchmark. +// +// (If this were a real benchmark, not an example, this would be named +// BenchmarkSomething.) +func ExBenchmark(b *testing.B) { + // Generate a large random slice to use as an input. + // Since this is done before the first call to b.Loop(), + // it doesn't count toward the benchmark time. + input := make([]int, 128<<10) + for i := range input { + input[i] = rand.Int() + } + + // Perform the benchmark. + for b.Loop() { + // Normally, the compiler would be allowed to optimize away the call + // to sum because it has no side effects and the result isn't used. + // However, inside a b.Loop loop, the compiler ensures function calls + // aren't optimized away. + sum(input) + } + + // Outside the loop, the timer is stopped, so we could perform + // cleanup if necessary without affecting the result. +} + +func sum(data []int) int { + total := 0 + for _, value := range data { + total += value + } + return total +} + +func ExampleB_Loop() { + testing.Benchmark(ExBenchmark) +} From c1f2542c8bef27872a95efd7904afeeee36fe976 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Thu, 12 Dec 2024 21:17:04 -0500 Subject: [PATCH 027/397] testing: improve B.Loop test This moves the B.Loop test from package testing_test to package testing, where it can check on more of the internals of the benchmark state. Updates #61515. Change-Id: Ia32d7104526125c5e8a1e35dab7660008afcbf80 Reviewed-on: https://go-review.googlesource.com/c/go/+/635897 Auto-Submit: Austin Clements LUCI-TryBot-Result: Go LUCI Reviewed-by: Junyang Shao --- src/testing/benchmark_test.go | 22 --------------- src/testing/loop_test.go | 51 +++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 22 deletions(-) create mode 100644 src/testing/loop_test.go diff --git a/src/testing/benchmark_test.go b/src/testing/benchmark_test.go index 239e7300211f5e..a195e4c5766813 100644 --- a/src/testing/benchmark_test.go +++ b/src/testing/benchmark_test.go @@ -127,28 +127,6 @@ func TestRunParallelSkipNow(t *testing.T) { }) } -func TestBLoopHasResults(t *testing.T) { - // Verify that b.N and the b.Loop() iteration count match. - var nIterated int - bRet := testing.Benchmark(func(b *testing.B) { - i := 0 - for b.Loop() { - i++ - } - nIterated = i - }) - if nIterated == 0 { - t.Fatalf("Iteration count zero") - } - if bRet.N != nIterated { - t.Fatalf("Benchmark result N incorrect, got %d want %d", bRet.N, nIterated) - } - // We only need to check duration to make sure benchmark result is written. - if bRet.T == 0 { - t.Fatalf("Benchmark result duration unset") - } -} - func ExampleB_RunParallel() { // Parallel benchmark for text/template.Template.Execute on a single object. testing.Benchmark(func(b *testing.B) { diff --git a/src/testing/loop_test.go b/src/testing/loop_test.go new file mode 100644 index 00000000000000..ae1a5e019b080d --- /dev/null +++ b/src/testing/loop_test.go @@ -0,0 +1,51 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package testing + +func TestBenchmarkBLoop(t *T) { + var initialStart highPrecisionTime + var firstStart highPrecisionTime + var lastStart highPrecisionTime + runs := 0 + iters := 0 + finalBN := 0 + bRet := Benchmark(func(b *B) { + initialStart = b.start + runs++ + for b.Loop() { + if iters == 0 { + firstStart = b.start + } + lastStart = b.start + iters++ + } + finalBN = b.N + }) + // Verify that a b.Loop benchmark is invoked just once. + if runs != 1 { + t.Errorf("want runs == 1, got %d", runs) + } + // Verify that at least one iteration ran. + if iters == 0 { + t.Fatalf("no iterations ran") + } + // Verify that b.N, bRet.N, and the b.Loop() iteration count match. + if finalBN != iters || bRet.N != iters { + t.Errorf("benchmark iterations mismatch: %d loop iterations, final b.N=%d, bRet.N=%d", iters, finalBN, bRet.N) + } + // Make sure the benchmark ran for an appropriate amount of time. + if bRet.T < benchTime.d { + t.Fatalf("benchmark ran for %s, want >= %s", bRet.T, benchTime.d) + } + // Verify that the timer is reset on the first loop, and then left alone. + if firstStart == initialStart { + t.Errorf("b.Loop did not reset the timer") + } + if lastStart != firstStart { + t.Errorf("timer was reset during iteration") + } +} + +// See also TestBenchmarkBLoop* in other files. From 18b5435fc84225ca303da7a110c7e8065dc4bbda Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Thu, 12 Dec 2024 21:18:44 -0500 Subject: [PATCH 028/397] testing: don't measure cleanup time after B.Loop B.Loop resets the timer on the first iteration so that setup code isn't measured, but it currently leaves the timer running after the last iteration, meaning that cleanup code will still be measured. Fix this by stopping the timer when B.Loop returns false to indicate the end of the benchmark. Updates #61515 Change-Id: I0e0502cb2ce3c24cf872682b88d74e8be2c4529b Reviewed-on: https://go-review.googlesource.com/c/go/+/635898 Reviewed-by: Junyang Shao Auto-Submit: Austin Clements LUCI-TryBot-Result: Go LUCI Reviewed-by: Cherry Mui --- src/testing/benchmark.go | 6 +++++- src/testing/loop_test.go | 6 ++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/testing/benchmark.go b/src/testing/benchmark.go index 8b84444f3824f0..2660c9bba06f3d 100644 --- a/src/testing/benchmark.go +++ b/src/testing/benchmark.go @@ -366,6 +366,8 @@ func (b *B) ReportMetric(n float64, unit string) { func (b *B) stopOrScaleBLoop() bool { timeElapsed := highPrecisionTimeSince(b.start) if timeElapsed >= b.benchTime.d { + // Stop the timer so we don't count cleanup time + b.StopTimer() return false } // Loop scaling @@ -393,6 +395,7 @@ func (b *B) loopSlowPath() bool { b.loopN++ return true } + b.StopTimer() return false } // Handles fixed time case @@ -413,7 +416,8 @@ func (b *B) loopSlowPath() bool { // // Loop resets the benchmark timer the first time it is called in a benchmark, // so any setup performed prior to starting the benchmark loop does not count -// toward the benchmark measurement. +// toward the benchmark measurement. Likewise, when it returns false, it stops +// the timer so cleanup code is not measured. // // The compiler never optimizes away calls to functions within the body of a // "for b.Loop() { ... }" loop. This prevents surprises that can otherwise occur diff --git a/src/testing/loop_test.go b/src/testing/loop_test.go index ae1a5e019b080d..7a1a93fceee7ea 100644 --- a/src/testing/loop_test.go +++ b/src/testing/loop_test.go @@ -8,6 +8,7 @@ func TestBenchmarkBLoop(t *T) { var initialStart highPrecisionTime var firstStart highPrecisionTime var lastStart highPrecisionTime + var runningEnd bool runs := 0 iters := 0 finalBN := 0 @@ -22,6 +23,7 @@ func TestBenchmarkBLoop(t *T) { iters++ } finalBN = b.N + runningEnd = b.timerOn }) // Verify that a b.Loop benchmark is invoked just once. if runs != 1 { @@ -46,6 +48,10 @@ func TestBenchmarkBLoop(t *T) { if lastStart != firstStart { t.Errorf("timer was reset during iteration") } + // Verify that it stopped the timer after the last loop. + if runningEnd { + t.Errorf("timer was still running after last iteration") + } } // See also TestBenchmarkBLoop* in other files. From 3bd08b97921826c1b0a5fbf0789f4b49d7619977 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Fri, 13 Dec 2024 23:18:59 +0000 Subject: [PATCH 029/397] runtime: usleep in TestWeakToStrongMarkTermination There's a subtle bug in this test (big surprise): time.Sleep allocates, so the time.Sleep(100*time.Millisecond) before unblocking gcMarkDone might itself end up in gcMarkDone. Work around this by using usleep here instead. Fixes #70532. Change-Id: I4c642ebb12f737cdb0d79ccff64b6059fc3d8b34 Reviewed-on: https://go-review.googlesource.com/c/go/+/636155 Reviewed-by: Cherry Mui LUCI-TryBot-Result: Go LUCI --- src/runtime/gc_test.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/runtime/gc_test.go b/src/runtime/gc_test.go index 35cb634936a91e..00280ed1b53cab 100644 --- a/src/runtime/gc_test.go +++ b/src/runtime/gc_test.go @@ -834,7 +834,11 @@ func TestWeakToStrongMarkTermination(t *testing.T) { done <- struct{}{} }() go func() { - time.Sleep(100 * time.Millisecond) + // Usleep here instead of time.Sleep. time.Sleep + // can allocate, and if we get unlucky, then it + // can end up stuck in gcMarkDone with nothing to + // wake it. + runtime.Usleep(100000) // 100ms // Let mark termination continue. runtime.SetSpinInGCMarkDone(false) From d92c34a3870bace34724e69ec2516d59ae432d32 Mon Sep 17 00:00:00 2001 From: Michael Matloob Date: Fri, 13 Dec 2024 17:33:16 -0500 Subject: [PATCH 030/397] cmd/go: don't create test actions for incomplete packages If a package is incomplete, don't create the actions for building and testing it. Instead report the errors for the package's dependencies and report a setup failed error (similar to what we'd to for a load error when producing the test packages). This produces similar errors to what were produced by load.CheckPackageErrors while still produing the test failure actions per package under test. (I wasn't sure what to do about the last test case in test_setup_error. I think it should be treated the same as other load errors?) Fixes #70820 Change-Id: Ie95e3c158c50ed35a1f27237ef3db40502719993 Reviewed-on: https://go-review.googlesource.com/c/go/+/635856 Reviewed-by: Sam Thanawalla LUCI-TryBot-Result: Go LUCI Auto-Submit: Michael Matloob Reviewed-by: Austin Clements --- src/cmd/go/internal/load/pkg.go | 21 ++++++++++--- src/cmd/go/internal/test/test.go | 22 ++++++++++++-- .../go/testdata/script/test_json_build.txt | 22 ++++++++++++++ .../go/testdata/script/test_setup_error.txt | 30 +++++++++++++++++-- 4 files changed, 86 insertions(+), 9 deletions(-) diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go index df790e1eaab616..15f6b2e87b916b 100644 --- a/src/cmd/go/internal/load/pkg.go +++ b/src/cmd/go/internal/load/pkg.go @@ -3068,7 +3068,15 @@ func setPGOProfilePath(pkgs []*Package) { // CheckPackageErrors prints errors encountered loading pkgs and their // dependencies, then exits with a non-zero status if any errors were found. func CheckPackageErrors(pkgs []*Package) { - var anyIncomplete bool + PackageErrors(pkgs, func(p *Package) { + DefaultPrinter().Errorf(p, "%v", p.Error) + }) + base.ExitIfErrors() +} + +// PackageErrors calls report for errors encountered loading pkgs and their dependencies. +func PackageErrors(pkgs []*Package, report func(*Package)) { + var anyIncomplete, anyErrors bool for _, pkg := range pkgs { if pkg.Incomplete { anyIncomplete = true @@ -3078,11 +3086,14 @@ func CheckPackageErrors(pkgs []*Package) { all := PackageList(pkgs) for _, p := range all { if p.Error != nil { - DefaultPrinter().Errorf(p, "%v", p.Error) + report(p) + anyErrors = true } } } - base.ExitIfErrors() + if anyErrors { + return + } // Check for duplicate loads of the same package. // That should be impossible, but if it does happen then @@ -3105,7 +3116,9 @@ func CheckPackageErrors(pkgs []*Package) { } seen[key] = true } - base.ExitIfErrors() + if len(reported) > 0 { + base.ExitIfErrors() + } } // mainPackagesOnly filters out non-main packages matched only by arguments diff --git a/src/cmd/go/internal/test/test.go b/src/cmd/go/internal/test/test.go index b530d027dff4e0..90f2d88d6b8a45 100644 --- a/src/cmd/go/internal/test/test.go +++ b/src/cmd/go/internal/test/test.go @@ -994,14 +994,15 @@ func runTest(ctx context.Context, cmd *base.Command, args []string) { // Prepare build + run + print actions for all packages being tested. for _, p := range pkgs { - buildTest, runTest, printTest, perr, err := builderTest(b, ctx, pkgOpts, p, allImports[p], writeCoverMetaAct) - if err != nil { + reportErr := func(perr *load.Package, err error) { str := err.Error() if p.ImportPath != "" { load.DefaultPrinter().Errorf(perr, "# %s\n%s", p.ImportPath, str) } else { load.DefaultPrinter().Errorf(perr, "%s", str) } + } + reportSetupFailed := func(perr *load.Package, err error) { var stdout io.Writer = os.Stdout if testJSON { json := test2json.NewConverter(stdout, p.ImportPath, test2json.Timestamp) @@ -1020,6 +1021,23 @@ func runTest(ctx context.Context, cmd *base.Command, args []string) { } fmt.Fprintf(stdout, "FAIL\t%s [setup failed]\n", p.ImportPath) base.SetExitStatus(1) + } + + var firstErrPkg *load.Package // arbitrarily report setup failed error for first error pkg reached in DFS + load.PackageErrors([]*load.Package{p}, func(p *load.Package) { + reportErr(p, p.Error) + if firstErrPkg == nil { + firstErrPkg = p + } + }) + if firstErrPkg != nil { + reportSetupFailed(firstErrPkg, firstErrPkg.Error) + continue + } + buildTest, runTest, printTest, perr, err := builderTest(b, ctx, pkgOpts, p, allImports[p], writeCoverMetaAct) + if err != nil { + reportErr(perr, err) + reportSetupFailed(perr, err) continue } builds = append(builds, buildTest) diff --git a/src/cmd/go/testdata/script/test_json_build.txt b/src/cmd/go/testdata/script/test_json_build.txt index 0a40649dcce8df..df8863ae03287f 100644 --- a/src/cmd/go/testdata/script/test_json_build.txt +++ b/src/cmd/go/testdata/script/test_json_build.txt @@ -40,6 +40,18 @@ stdout '"Action":"output","Package":"m/loaderror","Output":"FAIL\\tm/loaderror \ stdout '"Action":"fail","Package":"m/loaderror","Elapsed":.*,"FailedBuild":"x"' ! stderr '.' +# Test an import cycle loading error in a non test file. (#70820) +! go test -json -o=$devnull ./cycle/p +stdout '"ImportPath":"m/cycle/q","Action":"build-output","Output":"# m/cycle/p\\n"' +stdout '"ImportPath":"m/cycle/q","Action":"build-output","Output":"package m/cycle/p\\n"' +stdout '"ImportPath":"m/cycle/q","Action":"build-output","Output":"\\timports m/cycle/q from p.go\\n"' +stdout '"ImportPath":"m/cycle/q","Action":"build-output","Output":"\\timports m/cycle/q from q.go: import cycle not allowed\\n"' +stdout '"ImportPath":"m/cycle/q","Action":"build-fail"' +stdout '"Action":"start","Package":"m/cycle/p"' +stdout '"Action":"output","Package":"m/cycle/p","Output":"FAIL\\tm/cycle/p \[setup failed\]\\n"' +stdout '"Action":"fail","Package":"m/cycle/p","Elapsed":.*,"FailedBuild":"m/cycle/q"' +! stderr '.' + # Test a vet error ! go test -json -o=$devnull ./veterror stdout '"ImportPath":"m/veterror \[m/veterror.test\]","Action":"build-output","Output":"# m/veterror\\n"' @@ -99,3 +111,13 @@ import ( func TestVetError(t *testing.T) { fmt.Printf("%s") } +-- cycle/p/p.go -- +package p + +import "m/cycle/q" +-- cycle/q/q.go -- +package q + +import ( + "m/cycle/q" +) diff --git a/src/cmd/go/testdata/script/test_setup_error.txt b/src/cmd/go/testdata/script/test_setup_error.txt index 2999067f2c93f3..bf566d4621f1a5 100644 --- a/src/cmd/go/testdata/script/test_setup_error.txt +++ b/src/cmd/go/testdata/script/test_setup_error.txt @@ -33,10 +33,23 @@ stderr '# m/t2/p\n.*package x is not in std' stdout 'FAIL m/t2/p \[setup failed\]' stdout 'ok m/t' -# Finally, this one is a build error, but produced by cmd/go directly +# Test that an import cycle error is reported. Test for #70820 +! go test -o=$devnull ./cycle/p ./t +stderr '# m/cycle/p\n.*package m/cycle/p\n\timports m/cycle/p from p\.go: import cycle not allowed' +stdout 'FAIL m/cycle/p \[setup failed\]' +stdout 'ok m/t' + +# Test that multiple errors for the same package under test are reported. +! go test -o=$devnull ./cycle/q ./t +stderr '# m/cycle/q\n.*package m/cycle/q\n\timports m/cycle/p from q\.go\n\timports m/cycle/p from p\.go: import cycle not allowed' +stdout 'FAIL m/cycle/q \[setup failed\]' +stdout 'ok m/t' + +# Finally, this one is a non-import-cycle load error that +# is produced for the package under test. ! go test -o=$devnull . ./t -stderr '^\.: no Go files in '$PWD'$' -stdout 'FAIL . \[build failed\]' +stderr '# \.\n.*no Go files in '$PWD'$' +stdout 'FAIL . \[setup failed\]' stdout 'ok m/t' -- go.mod -- @@ -68,6 +81,17 @@ package p package p import "m/bad" +-- cycle/p/p.go -- +package p + +import "m/cycle/p" +-- cycle/q/q.go -- +package q + +import ( + "m/bad" + "m/cycle/p" +) -- bad/bad.go -- package bad From 1218566fe5c90e2bd39693566453828e6fbb4c12 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Mon, 16 Dec 2024 17:06:35 -0500 Subject: [PATCH 031/397] cmd/link: update runtime dependency list There have been a number of internal packages that the runtime package depends on. Update the list. We should stop using a hard- coded list. Change-Id: I6f9338d6690d955b8200f3301addd0e133a1bfe2 Reviewed-on: https://go-review.googlesource.com/c/go/+/636478 LUCI-TryBot-Result: Go LUCI Reviewed-by: Michael Pratt --- src/cmd/link/internal/ld/data.go | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index b6eaf69ca48a95..5c4497cdd75b0f 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -55,17 +55,31 @@ import ( ) // isRuntimeDepPkg reports whether pkg is the runtime package or its dependency. +// TODO: just compute from the runtime package, and remove this hardcoded list. func isRuntimeDepPkg(pkg string) bool { switch pkg { case "runtime", - "sync/atomic", // runtime may call to sync/atomic, due to go:linkname - "internal/abi", // used by reflectcall (and maybe more) - "internal/bytealg", // for IndexByte + "sync/atomic", // runtime may call to sync/atomic, due to go:linkname // TODO: this is not true? + "internal/abi", // used by reflectcall (and maybe more) + "internal/asan", + "internal/bytealg", // for IndexByte + "internal/byteorder", "internal/chacha8rand", // for rand - "internal/cpu": // for cpu features + "internal/coverage/rtcov", + "internal/cpu", // for cpu features + "internal/goarch", + "internal/godebugs", + "internal/goexperiment", + "internal/goos", + "internal/msan", + "internal/profilerecord", + "internal/race", + "internal/stringslite", + "unsafe": return true } - return strings.HasPrefix(pkg, "runtime/internal/") && !strings.HasSuffix(pkg, "_test") + return (strings.HasPrefix(pkg, "runtime/internal/") || strings.HasPrefix(pkg, "internal/runtime/")) && + !strings.HasSuffix(pkg, "_test") } // Estimate the max size needed to hold any new trampolines created for this function. This From 75736cc169631dfaaa48ad46a00e1bf31d830ec8 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 16 Dec 2024 15:38:43 -0800 Subject: [PATCH 032/397] fmt, strconv: document that exponent is always two digits Except for %b where it is only one. Fixes #70862 Change-Id: Ic423a799b73bfa534f4083f6544bb9cd639fef06 Reviewed-on: https://go-review.googlesource.com/c/go/+/636915 LUCI-TryBot-Result: Go LUCI Reviewed-by: David Chase Reviewed-by: Rob Pike Reviewed-by: Ian Lance Taylor Auto-Submit: Ian Lance Taylor --- src/fmt/doc.go | 3 +++ src/strconv/ftoa.go | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/fmt/doc.go b/src/fmt/doc.go index b90db7bedc684b..fa0ffa7f00ccc7 100644 --- a/src/fmt/doc.go +++ b/src/fmt/doc.go @@ -50,6 +50,9 @@ Floating-point and complex constituents: %x hexadecimal notation (with decimal power of two exponent), e.g. -0x1.23abcp+20 %X upper-case hexadecimal notation, e.g. -0X1.23ABCP+20 + The exponent is always a decimal integer. + For formats other than %b the exponent is at least two digits. + String and slice of bytes (treated equivalently with these verbs): %s the uninterpreted bytes of the string or slice diff --git a/src/strconv/ftoa.go b/src/strconv/ftoa.go index 6db0d47e0f7ae2..bfe26366e12c13 100644 --- a/src/strconv/ftoa.go +++ b/src/strconv/ftoa.go @@ -44,6 +44,8 @@ var float64info = floatInfo{52, 11, -1023} // zeros are removed). // The special precision -1 uses the smallest number of digits // necessary such that ParseFloat will return f exactly. +// The exponent is written as a decimal integer; +// for all formats other than 'b', it will be at least two digits. func FormatFloat(f float64, fmt byte, prec, bitSize int) string { return string(genericFtoa(make([]byte, 0, max(prec+4, 24)), f, fmt, prec, bitSize)) } From 427a2401af088716bf5b394156e45fb4de54dc5a Mon Sep 17 00:00:00 2001 From: Michael Matloob Date: Fri, 13 Dec 2024 17:33:16 -0500 Subject: [PATCH 033/397] cmd/go/testdata/script: update test_flags for new test output With CL 635856, an error for a package missing go files is now caught at load time rather than at build time, so it's reported differently. Update the test to check for the correct output unbreak the builders. For #70820 Change-Id: I91fcac17961635b9a92782caa58c9a6f057a7e02 Reviewed-on: https://go-review.googlesource.com/c/go/+/637115 Reviewed-by: Sam Thanawalla Auto-Submit: Michael Matloob LUCI-TryBot-Result: Go LUCI --- src/cmd/go/testdata/script/test_flags.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/go/testdata/script/test_flags.txt b/src/cmd/go/testdata/script/test_flags.txt index 7adf4e273c569a..afef08840df87a 100644 --- a/src/cmd/go/testdata/script/test_flags.txt +++ b/src/cmd/go/testdata/script/test_flags.txt @@ -15,8 +15,8 @@ stdout '\Aok\s+example.com/x\s+[0-9.s]+\n\z' # Even though ./x looks like a package path, the real package should be # the implicit '.'. ! go test --answer=42 ./x -stdout '^FAIL\t. \[build failed\]' -stderr '^\.: no Go files in '$PWD'$' +stdout '^FAIL\t. \[setup failed\]' +stderr '^# \.\nno Go files in '$PWD'$' # However, *flags* that appear after unrecognized flags should still be # interpreted as flags, under the (possibly-erroneous) assumption that From dd7a7ba38f36dd6abc1e14b8d0e8bf05a5383161 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Mon, 16 Dec 2024 19:24:20 +0100 Subject: [PATCH 034/397] crypto/internal/fips140/aes: mark AES-ECB as not approved NIST SP 800-131Ar3 ipd, scheduled for publication in 2025Q1, marks AES-ECB as disallowed for encryption, and legacy use for decryption. There are apparently no details on how the transition is going to work, so to avoid surprises we just mark direct use of the Block as non-approved. We need to use Encrypt from higher level modes without tripping the service indicator. Within the aes package, we just use the internal function. For the gcm package we could do something more clever, but this deep into the freeze, just make an exported function that we commit to use nowhere else. I could not figure out a decent way to block ECB on GODEBUG=fips140=only. For #69536 Change-Id: I972a4b5da8efd0a0ab68d7dd509bec73aa2d6b68 Reviewed-on: https://go-review.googlesource.com/c/go/+/636775 Reviewed-by: David Chase Reviewed-by: Roland Shoemaker Auto-Submit: Filippo Valsorda LUCI-TryBot-Result: Go LUCI --- src/crypto/internal/fips140/aes/aes.go | 13 +++++++++++-- src/crypto/internal/fips140/aes/cbc.go | 4 ++-- src/crypto/internal/fips140/aes/ctr.go | 2 +- src/crypto/internal/fips140/aes/gcm/cmac.go | 8 ++++---- src/crypto/internal/fips140/aes/gcm/gcm_asm.go | 4 ++-- src/crypto/internal/fips140/aes/gcm/gcm_generic.go | 8 ++++---- 6 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/crypto/internal/fips140/aes/aes.go b/src/crypto/internal/fips140/aes/aes.go index 739f1a3dbe6599..62f6919eda8178 100644 --- a/src/crypto/internal/fips140/aes/aes.go +++ b/src/crypto/internal/fips140/aes/aes.go @@ -94,6 +94,8 @@ func newBlockExpanded(c *blockExpanded, key []byte) { func (c *Block) BlockSize() int { return BlockSize } func (c *Block) Encrypt(dst, src []byte) { + // AES-ECB is not approved in FIPS 140-3 mode. + fips140.RecordNonApproved() if len(src) < BlockSize { panic("crypto/aes: input not full block") } @@ -103,11 +105,12 @@ func (c *Block) Encrypt(dst, src []byte) { if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { panic("crypto/aes: invalid buffer overlap") } - fips140.RecordApproved() encryptBlock(c, dst, src) } func (c *Block) Decrypt(dst, src []byte) { + // AES-ECB is not approved in FIPS 140-3 mode. + fips140.RecordNonApproved() if len(src) < BlockSize { panic("crypto/aes: input not full block") } @@ -117,6 +120,12 @@ func (c *Block) Decrypt(dst, src []byte) { if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { panic("crypto/aes: invalid buffer overlap") } - fips140.RecordApproved() decryptBlock(c, dst, src) } + +// EncryptBlockInternal applies the AES encryption function to one block. +// +// It is an internal function meant only for the gcm package. +func EncryptBlockInternal(c *Block, dst, src []byte) { + encryptBlock(c, dst, src) +} diff --git a/src/crypto/internal/fips140/aes/cbc.go b/src/crypto/internal/fips140/aes/cbc.go index c7837b9d87d102..f92af23a2a5561 100644 --- a/src/crypto/internal/fips140/aes/cbc.go +++ b/src/crypto/internal/fips140/aes/cbc.go @@ -50,7 +50,7 @@ func cryptBlocksEncGeneric(b *Block, civ *[BlockSize]byte, dst, src []byte) { for len(src) > 0 { // Write the xor to dst, then encrypt in place. subtle.XORBytes(dst[:BlockSize], src[:BlockSize], iv) - b.Encrypt(dst[:BlockSize], dst[:BlockSize]) + encryptBlock(b, dst[:BlockSize], dst[:BlockSize]) // Move to the next block with this block as the next iv. iv = dst[:BlockSize] @@ -111,7 +111,7 @@ func cryptBlocksDecGeneric(b *Block, civ *[BlockSize]byte, dst, src []byte) { copy(civ[:], src[start:end]) for start >= 0 { - b.Decrypt(dst[start:end], src[start:end]) + decryptBlock(b, dst[start:end], src[start:end]) if start > 0 { subtle.XORBytes(dst[start:end], dst[start:end], src[prev:start]) diff --git a/src/crypto/internal/fips140/aes/ctr.go b/src/crypto/internal/fips140/aes/ctr.go index f612034d85ff1a..2b0ee44cddb66c 100644 --- a/src/crypto/internal/fips140/aes/ctr.go +++ b/src/crypto/internal/fips140/aes/ctr.go @@ -132,7 +132,7 @@ func ctrBlocks(b *Block, dst, src []byte, ivlo, ivhi uint64) { byteorder.BEPutUint64(buf[i:], ivhi) byteorder.BEPutUint64(buf[i+8:], ivlo) ivlo, ivhi = add128(ivlo, ivhi, 1) - b.Encrypt(buf[i:], buf[i:]) + encryptBlock(b, buf[i:], buf[i:]) } // XOR into buf first, in case src and dst overlap (see above). subtle.XORBytes(buf, src, buf) diff --git a/src/crypto/internal/fips140/aes/gcm/cmac.go b/src/crypto/internal/fips140/aes/gcm/cmac.go index e0a9dc43dede7e..3a979a5c70870f 100644 --- a/src/crypto/internal/fips140/aes/gcm/cmac.go +++ b/src/crypto/internal/fips140/aes/gcm/cmac.go @@ -28,7 +28,7 @@ func NewCMAC(b *aes.Block) *CMAC { } func (c *CMAC) deriveSubkeys() { - c.b.Encrypt(c.k1[:], c.k1[:]) + aes.EncryptBlockInternal(&c.b, c.k1[:], c.k1[:]) msb := shiftLeft(&c.k1) c.k1[len(c.k1)-1] ^= msb * 0b10000111 @@ -45,7 +45,7 @@ func (c *CMAC) MAC(m []byte) [aes.BlockSize]byte { // Special-cased as a single empty partial final block. x = c.k2 x[len(m)] ^= 0b10000000 - c.b.Encrypt(x[:], x[:]) + aes.EncryptBlockInternal(&c.b, x[:], x[:]) return x } for len(m) >= aes.BlockSize { @@ -54,7 +54,7 @@ func (c *CMAC) MAC(m []byte) [aes.BlockSize]byte { // Final complete block. subtle.XORBytes(x[:], c.k1[:], x[:]) } - c.b.Encrypt(x[:], x[:]) + aes.EncryptBlockInternal(&c.b, x[:], x[:]) m = m[aes.BlockSize:] } if len(m) > 0 { @@ -62,7 +62,7 @@ func (c *CMAC) MAC(m []byte) [aes.BlockSize]byte { subtle.XORBytes(x[:], m, x[:]) subtle.XORBytes(x[:], c.k2[:], x[:]) x[len(m)] ^= 0b10000000 - c.b.Encrypt(x[:], x[:]) + aes.EncryptBlockInternal(&c.b, x[:], x[:]) } return x } diff --git a/src/crypto/internal/fips140/aes/gcm/gcm_asm.go b/src/crypto/internal/fips140/aes/gcm/gcm_asm.go index d513f77a2f342b..7924e457dee829 100644 --- a/src/crypto/internal/fips140/aes/gcm/gcm_asm.go +++ b/src/crypto/internal/fips140/aes/gcm/gcm_asm.go @@ -81,7 +81,7 @@ func seal(out []byte, g *GCM, nonce, plaintext, data []byte) { gcmAesFinish(&g.productTable, &tagMask, &counter, uint64(len(nonce)), uint64(0)) } - g.cipher.Encrypt(tagMask[:], counter[:]) + aes.EncryptBlockInternal(&g.cipher, tagMask[:], counter[:]) var tagOut [gcmTagSize]byte gcmAesData(&g.productTable, data, &tagOut) @@ -114,7 +114,7 @@ func open(out []byte, g *GCM, nonce, ciphertext, data []byte) error { gcmAesFinish(&g.productTable, &tagMask, &counter, uint64(len(nonce)), uint64(0)) } - g.cipher.Encrypt(tagMask[:], counter[:]) + aes.EncryptBlockInternal(&g.cipher, tagMask[:], counter[:]) var expectedTag [gcmTagSize]byte gcmAesData(&g.productTable, data, &expectedTag) diff --git a/src/crypto/internal/fips140/aes/gcm/gcm_generic.go b/src/crypto/internal/fips140/aes/gcm/gcm_generic.go index 778392661dae6e..385955ed77838b 100644 --- a/src/crypto/internal/fips140/aes/gcm/gcm_generic.go +++ b/src/crypto/internal/fips140/aes/gcm/gcm_generic.go @@ -12,7 +12,7 @@ import ( func sealGeneric(out []byte, g *GCM, nonce, plaintext, additionalData []byte) { var H, counter, tagMask [gcmBlockSize]byte - g.cipher.Encrypt(H[:], H[:]) + aes.EncryptBlockInternal(&g.cipher, H[:], H[:]) deriveCounterGeneric(&H, &counter, nonce) gcmCounterCryptGeneric(&g.cipher, tagMask[:], tagMask[:], &counter) @@ -25,7 +25,7 @@ func sealGeneric(out []byte, g *GCM, nonce, plaintext, additionalData []byte) { func openGeneric(out []byte, g *GCM, nonce, ciphertext, additionalData []byte) error { var H, counter, tagMask [gcmBlockSize]byte - g.cipher.Encrypt(H[:], H[:]) + aes.EncryptBlockInternal(&g.cipher, H[:], H[:]) deriveCounterGeneric(&H, &counter, nonce) gcmCounterCryptGeneric(&g.cipher, tagMask[:], tagMask[:], &counter) @@ -70,7 +70,7 @@ func gcmCounterCryptGeneric(b *aes.Block, out, src []byte, counter *[gcmBlockSiz var mask [gcmBlockSize]byte for len(src) >= gcmBlockSize { - b.Encrypt(mask[:], counter[:]) + aes.EncryptBlockInternal(b, mask[:], counter[:]) gcmInc32(counter) subtle.XORBytes(out, src, mask[:]) @@ -79,7 +79,7 @@ func gcmCounterCryptGeneric(b *aes.Block, out, src []byte, counter *[gcmBlockSiz } if len(src) > 0 { - b.Encrypt(mask[:], counter[:]) + aes.EncryptBlockInternal(b, mask[:], counter[:]) gcmInc32(counter) subtle.XORBytes(out, src, mask[:]) } From b47ce8b0e997f09abd6e1e5c23eb59d6e9d5be2c Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Mon, 16 Dec 2024 19:30:58 +0100 Subject: [PATCH 035/397] crypto/cipher: block non-AES CTR and CBC in fips140=only mode Somehow I had missed these. For #69536 Change-Id: I5e60b6f052bbfb707742ad15f663517c6c5f68d3 Reviewed-on: https://go-review.googlesource.com/c/go/+/636795 Auto-Submit: Filippo Valsorda Reviewed-by: Roland Shoemaker LUCI-TryBot-Result: Go LUCI Reviewed-by: David Chase --- src/crypto/cipher/cbc.go | 7 +++++++ src/crypto/cipher/ctr.go | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/src/crypto/cipher/cbc.go b/src/crypto/cipher/cbc.go index b4536aceb9c224..8e614062969954 100644 --- a/src/crypto/cipher/cbc.go +++ b/src/crypto/cipher/cbc.go @@ -15,6 +15,7 @@ import ( "bytes" "crypto/internal/fips140/aes" "crypto/internal/fips140/alias" + "crypto/internal/fips140only" "crypto/subtle" ) @@ -53,6 +54,9 @@ func NewCBCEncrypter(b Block, iv []byte) BlockMode { if b, ok := b.(*aes.Block); ok { return aes.NewCBCEncrypter(b, [16]byte(iv)) } + if fips140only.Enabled { + panic("crypto/cipher: use of CBC with non-AES ciphers is not allowed in FIPS 140-only mode") + } if cbc, ok := b.(cbcEncAble); ok { return cbc.NewCBCEncrypter(iv) } @@ -129,6 +133,9 @@ func NewCBCDecrypter(b Block, iv []byte) BlockMode { if b, ok := b.(*aes.Block); ok { return aes.NewCBCDecrypter(b, [16]byte(iv)) } + if fips140only.Enabled { + panic("crypto/cipher: use of CBC with non-AES ciphers is not allowed in FIPS 140-only mode") + } if cbc, ok := b.(cbcDecAble); ok { return cbc.NewCBCDecrypter(iv) } diff --git a/src/crypto/cipher/ctr.go b/src/crypto/cipher/ctr.go index c868635b8a7a86..49512ca5dd8b8e 100644 --- a/src/crypto/cipher/ctr.go +++ b/src/crypto/cipher/ctr.go @@ -16,6 +16,7 @@ import ( "bytes" "crypto/internal/fips140/aes" "crypto/internal/fips140/alias" + "crypto/internal/fips140only" "crypto/subtle" ) @@ -41,6 +42,9 @@ func NewCTR(block Block, iv []byte) Stream { if block, ok := block.(*aes.Block); ok { return aesCtrWrapper{aes.NewCTR(block, iv)} } + if fips140only.Enabled { + panic("crypto/cipher: use of CTR with non-AES ciphers is not allowed in FIPS 140-only mode") + } if ctr, ok := block.(ctrAble); ok { return ctr.NewCTR(iv) } From 31e50af5f3366a9fc4e91a589f91ad579b7cba56 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Mon, 16 Dec 2024 17:33:50 +0100 Subject: [PATCH 036/397] crypto/rsa: revert minimum GenerateKey size to 32 bits No point in causing breakage even with GODEBUG=rsa1024min=0. Change-Id: I923254a8c8afaca77be551b19e3555c44ebdbb67 Reviewed-on: https://go-review.googlesource.com/c/go/+/636557 Reviewed-by: Roland Shoemaker Reviewed-by: David Chase Auto-Submit: Filippo Valsorda LUCI-TryBot-Result: Go LUCI Reviewed-by: Daniel McCarney --- src/crypto/internal/fips140/rsa/keygen.go | 8 ++++---- src/crypto/rsa/rsa_test.go | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/crypto/internal/fips140/rsa/keygen.go b/src/crypto/internal/fips140/rsa/keygen.go index df76772ef5878d..d8a282bcd44634 100644 --- a/src/crypto/internal/fips140/rsa/keygen.go +++ b/src/crypto/internal/fips140/rsa/keygen.go @@ -13,9 +13,9 @@ import ( ) // GenerateKey generates a new RSA key pair of the given bit size. -// bits must be at least 128. +// bits must be at least 32. func GenerateKey(rand io.Reader, bits int) (*PrivateKey, error) { - if bits < 128 { + if bits < 32 { return nil, errors.New("rsa: key too small") } fips140.RecordApproved() @@ -93,8 +93,8 @@ func GenerateKey(rand io.Reader, bits int) (*PrivateKey, error) { // randomPrime returns a random prime number of the given bit size following // the process in FIPS 186-5, Appendix A.1.3. func randomPrime(rand io.Reader, bits int) ([]byte, error) { - if bits < 64 { - return nil, errors.New("rsa: prime size must be at least 32-bit") + if bits < 16 { + return nil, errors.New("rsa: prime size must be at least 16 bits") } b := make([]byte, (bits+7)/8) diff --git a/src/crypto/rsa/rsa_test.go b/src/crypto/rsa/rsa_test.go index 2474ab82dfa207..2535661040273a 100644 --- a/src/crypto/rsa/rsa_test.go +++ b/src/crypto/rsa/rsa_test.go @@ -101,7 +101,7 @@ func TestImpossibleKeyGeneration(t *testing.T) { // This test ensures that trying to generate or validate toy RSA keys // doesn't enter an infinite loop or panic. t.Setenv("GODEBUG", "rsa1024min=0") - for i := 0; i < 128; i++ { + for i := 0; i < 32; i++ { GenerateKey(rand.Reader, i) GenerateMultiPrimeKey(rand.Reader, 3, i) GenerateMultiPrimeKey(rand.Reader, 4, i) @@ -184,7 +184,7 @@ func TestEverything(t *testing.T) { } t.Setenv("GODEBUG", "rsa1024min=0") - min := 128 + min := 32 max := 560 // any smaller than this and not all tests will run if *allFlag { max = 2048 From 0cd833d19823f84a1da7552c63d1be5b7dba332a Mon Sep 17 00:00:00 2001 From: qmuntal Date: Mon, 16 Dec 2024 11:07:02 +0100 Subject: [PATCH 037/397] go/build: remove nonexistent package from TestDependencies crypto/internal/boring/fips140tls is not a package in the Go standard library, so it should not be listed in TestDependencies. Change-Id: I6476da397b0204fcbd0a11b27a29112fca4b6023 Reviewed-on: https://go-review.googlesource.com/c/go/+/636415 Reviewed-by: Filippo Valsorda Auto-Submit: Quim Muntal Reviewed-by: David Chase LUCI-TryBot-Result: Go LUCI Reviewed-by: Dmitri Shuralyov --- src/go/build/deps_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index cc7f4df7f388ea..15e2f1bbbf3ad3 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -498,7 +498,7 @@ var depsRules = ` FIPS, internal/godebug, hash < crypto/fips140, crypto/internal/fips140only; NONE < crypto/internal/boring/sig, crypto/internal/boring/syso; - sync/atomic < crypto/internal/boring/bcache, crypto/internal/boring/fips140tls; + sync/atomic < crypto/internal/boring/bcache; crypto/internal/boring/sig, crypto/tls/internal/fips140tls < crypto/tls/fipsonly; # CRYPTO is core crypto algorithms - no cgo, fmt, net. From 9f806bb76c8eec08cad07a2e859c8dd35103432e Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Mon, 16 Dec 2024 15:52:47 +0100 Subject: [PATCH 038/397] go/build: streamline the crypto package graph in TestDependencies Change-Id: I975243b4897d5161b839f142afbd2a46bfa1fab0 Reviewed-on: https://go-review.googlesource.com/c/go/+/636555 Reviewed-by: Daniel McCarney Auto-Submit: Filippo Valsorda Reviewed-by: David Chase TryBot-Bypass: Filippo Valsorda Reviewed-by: Roland Shoemaker --- src/go/build/deps_test.go | 89 +++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 46 deletions(-) diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index 15e2f1bbbf3ad3..d9d985dca4ade4 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -444,6 +444,10 @@ var depsRules = ` NET, log < net/mail; + # FIPS is the FIPS 140 module. + # It must not depend on external crypto packages. + # See also fips140deps.AllowedInternalPackages. + io, math/rand/v2 < crypto/internal/randutil; STR < crypto/internal/impl; @@ -455,8 +459,6 @@ var depsRules = ` internal/cpu, internal/goarch < crypto/internal/fips140deps/cpu; internal/godebug < crypto/internal/fips140deps/godebug; - # FIPS is the FIPS 140 module. - # It must not depend on external crypto packages. STR, crypto/internal/impl, crypto/internal/entropy, crypto/internal/randutil, @@ -491,63 +493,49 @@ var depsRules = ` < crypto/internal/fips140/rsa < FIPS; - FIPS < crypto/internal/fips140/check/checktest; + FIPS, internal/godebug < crypto/fips140; - FIPS, sync/atomic < crypto/tls/internal/fips140tls; + crypto, hash !< FIPS; - FIPS, internal/godebug, hash < crypto/fips140, crypto/internal/fips140only; + # CRYPTO is core crypto algorithms - no cgo, fmt, net. + # Mostly wrappers around the FIPS module. NONE < crypto/internal/boring/sig, crypto/internal/boring/syso; sync/atomic < crypto/internal/boring/bcache; - crypto/internal/boring/sig, crypto/tls/internal/fips140tls < crypto/tls/fipsonly; - # CRYPTO is core crypto algorithms - no cgo, fmt, net. - FIPS, crypto/internal/fips140only, + FIPS, internal/godebug, hash, embed, crypto/internal/boring/sig, crypto/internal/boring/syso, - golang.org/x/sys/cpu, - hash, embed + crypto/internal/boring/bcache + < crypto/internal/fips140only < crypto < crypto/subtle < crypto/cipher - < crypto/sha3; - - crypto/cipher, - crypto/internal/boring/bcache < crypto/internal/boring - < crypto/boring; - - crypto/boring - < crypto/aes, crypto/des, crypto/hmac, crypto/md5, crypto/rc4, - crypto/sha1, crypto/sha256, crypto/sha512, crypto/hkdf; - - crypto/boring, crypto/internal/fips140/edwards25519/field - < crypto/ecdh; - - crypto/hmac < crypto/pbkdf2; - - crypto/internal/fips140/mlkem < crypto/mlkem; - - crypto/aes, - crypto/des, - crypto/ecdh, - crypto/hmac, - crypto/md5, - crypto/rc4, - crypto/sha1, - crypto/sha256, - crypto/sha512, - crypto/sha3, - crypto/hkdf + < crypto/boring + < crypto/aes, + crypto/des, + crypto/rc4, + crypto/md5, + crypto/sha1, + crypto/sha256, + crypto/sha512, + crypto/sha3, + crypto/hmac, + crypto/hkdf, + crypto/pbkdf2, + crypto/ecdh, + crypto/mlkem < CRYPTO; CGO, fmt, net !< CRYPTO; - # CRYPTO-MATH is core bignum-based crypto - no cgo, net; fmt now ok. + # CRYPTO-MATH is crypto that exposes math/big APIs - no cgo, net; fmt now ok. + CRYPTO, FMT, math/big < crypto/internal/boring/bbig < crypto/rand - < crypto/ed25519 + < crypto/ed25519 # depends on crypto/rand.Reader < encoding/asn1 < golang.org/x/crypto/cryptobyte/asn1 < golang.org/x/crypto/cryptobyte @@ -558,17 +546,23 @@ var depsRules = ` CGO, net !< CRYPTO-MATH; # TLS, Prince of Dependencies. - CRYPTO-MATH, NET, container/list, encoding/hex, encoding/pem + + FIPS, sync/atomic < crypto/tls/internal/fips140tls; + + crypto/internal/boring/sig, crypto/tls/internal/fips140tls < crypto/tls/fipsonly; + + CRYPTO, golang.org/x/sys/cpu, encoding/binary, reflect < golang.org/x/crypto/internal/alias < golang.org/x/crypto/internal/subtle < golang.org/x/crypto/chacha20 < golang.org/x/crypto/internal/poly1305 - < golang.org/x/crypto/chacha20poly1305 + < golang.org/x/crypto/chacha20poly1305; + + CRYPTO-MATH, NET, container/list, encoding/hex, encoding/pem, + golang.org/x/crypto/chacha20poly1305, crypto/tls/internal/fips140tls < crypto/internal/hpke < crypto/x509/internal/macos - < crypto/x509/pkix; - - crypto/tls/internal/fips140tls, crypto/x509/pkix + < crypto/x509/pkix < crypto/x509 < crypto/tls; @@ -666,7 +660,7 @@ var depsRules = ` < testing/slogtest; FMT, crypto/sha256, encoding/json, go/ast, go/parser, go/token, - internal/godebug, math/rand, encoding/hex, crypto/sha256 + internal/godebug, math/rand, encoding/hex < internal/fuzz; OS, flag, testing, internal/cfg, internal/platform, internal/goroot @@ -696,6 +690,9 @@ var depsRules = ` CGO, FMT < crypto/internal/sysrand/internal/seccomp; + FIPS + < crypto/internal/fips140/check/checktest; + # v2 execution trace parser. FMT < internal/trace/event; From 236a0b4ffb79854546b9f437499092cec23a5725 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 12 Dec 2024 11:31:49 -0800 Subject: [PATCH 039/397] spec: explain function invocation and passing of parameters more precisely - Describe that function invocation allocates space for a functions' variables. - Explain parameter passing in terms of assignments. Change-Id: Ia693d73a570f7d1aa2ac05e6095b4e602e4e9bf2 Reviewed-on: https://go-review.googlesource.com/c/go/+/635800 Reviewed-by: Robert Griesemer Reviewed-by: Ian Lance Taylor TryBot-Bypass: Robert Griesemer Auto-Submit: Robert Griesemer Reviewed-by: Rob Pike --- doc/go_spec.html | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/doc/go_spec.html b/doc/go_spec.html index 282f6cde0c80b3..fff489c33ac55c 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -1,6 +1,6 @@ @@ -2819,7 +2819,7 @@

Satisfying a type constraint

A type argument T satisfies a type constraint C -if T is an element of the type set defined by C; i.e., +if T is an element of the type set defined by C; in other words, if T implements C. As an exception, a strictly comparable type constraint may also be satisfied by a comparable @@ -4229,8 +4229,7 @@

Calls

Except for one special case, arguments must be single-valued expressions assignable to the parameter types of F and are evaluated before the function is called. -The type of the expression is the result type -of F. +The type of the expression is the result type of F. A method invocation is similar but the method itself is specified as a selector upon a value of the receiver type for the method. @@ -4251,9 +4250,14 @@

Calls

In a function call, the function value and arguments are evaluated in the usual order. -After they are evaluated, the parameters of the call are passed by value to the function +After they are evaluated, new storage is allocated for the function's +variables, which includes its parameters +and results. +Then, the arguments of the call are passed to the function, +which means that they are assigned +to their corresponding function parameters, and the called function begins execution. -The return parameters of the function are passed by value +The return parameters of the function are passed back to the caller when the function returns.

@@ -4267,9 +4271,9 @@

Calls

g are equal in number and individually assignable to the parameters of another function or method f, then the call f(g(parameters_of_g)) -will invoke f after binding the return values of -g to the parameters of f in order. The call -of f must contain no parameters other than the call of g, +will invoke f after passing the return values of +g to the parameters of f in order. +The call of f must contain no parameters other than the call of g, and g must have at least one return value. If f has a final ... parameter, it is assigned the return values of g that remain after @@ -4315,7 +4319,7 @@

Passing arguments to ...p of type ...T, then within f the type of p is equivalent to type []T. If f is invoked with no actual arguments for p, -the value passed to p is nil. +the value passed to p is nil. Otherwise, the value passed is a new slice of type []T with a new underlying array whose successive elements are the actual arguments, which all must be assignable From 4ac8f552e95521d292cc18ccc546739d41283b31 Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Tue, 3 Dec 2024 12:22:49 -0800 Subject: [PATCH 040/397] syscall, internal/syscall/unix: fix fstatat on linux/mips64 On linux/mips64, the syscall.Stat_t struct does not match the kernel version of the struct. Functions that operate on a Stat_t translate between it and the kernel struct. The fstatat function was not doing this translation. Make it do so. Export a syscall.Fstatat on mips64 for usage by internal/syscall/unix. Perhaps we should just do this on all architectures, but this is the smaller change for now. Fixes #70659 Change-Id: I38e36473689be25861953b418c9abc5b270a7bcf Reviewed-on: https://go-review.googlesource.com/c/go/+/633280 LUCI-TryBot-Result: Go LUCI Reviewed-by: Ian Lance Taylor --- src/internal/syscall/unix/at_fstatat.go | 2 +- src/internal/syscall/unix/at_fstatat2.go | 2 +- src/syscall/syscall_linux_mips64x.go | 13 +++++++++- src/syscall/zsyscall_linux_mips64.go | 30 ++++++++++++------------ src/syscall/zsyscall_linux_mips64le.go | 30 ++++++++++++------------ 5 files changed, 44 insertions(+), 33 deletions(-) diff --git a/src/internal/syscall/unix/at_fstatat.go b/src/internal/syscall/unix/at_fstatat.go index 25de336a8041c4..217e19a776d2b2 100644 --- a/src/internal/syscall/unix/at_fstatat.go +++ b/src/internal/syscall/unix/at_fstatat.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build dragonfly || (linux && !loong64) || netbsd || (openbsd && mips64) +//go:build dragonfly || (linux && !(loong64 || mips64)) || netbsd || (openbsd && mips64) package unix diff --git a/src/internal/syscall/unix/at_fstatat2.go b/src/internal/syscall/unix/at_fstatat2.go index 8d20e1a885bd13..b18098b7d36eb0 100644 --- a/src/internal/syscall/unix/at_fstatat2.go +++ b/src/internal/syscall/unix/at_fstatat2.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build freebsd || (linux && loong64) +//go:build freebsd || (linux && (loong64 || mips64)) package unix diff --git a/src/syscall/syscall_linux_mips64x.go b/src/syscall/syscall_linux_mips64x.go index 51f5ead472ef4f..e826e08615e6d1 100644 --- a/src/syscall/syscall_linux_mips64x.go +++ b/src/syscall/syscall_linux_mips64x.go @@ -16,7 +16,6 @@ const ( //sys Dup2(oldfd int, newfd int) (err error) //sys Fchown(fd int, uid int, gid int) (err error) //sys Fstatfs(fd int, buf *Statfs_t) (err error) -//sys fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) = SYS_NEWFSTATAT //sys Ftruncate(fd int, length int64) (err error) //sysnb Getegid() (egid int) //sysnb Geteuid() (euid int) @@ -126,10 +125,22 @@ type stat_t struct { Blocks int64 } +//sys fstatatInternal(dirfd int, path string, stat *stat_t, flags int) (err error) = SYS_NEWFSTATAT //sys fstat(fd int, st *stat_t) (err error) //sys lstat(path string, st *stat_t) (err error) //sys stat(path string, st *stat_t) (err error) +func fstatat(fd int, path string, s *Stat_t, flags int) (err error) { + st := &stat_t{} + err = fstatatInternal(fd, path, st, flags) + fillStat_t(s, st) + return +} + +func Fstatat(fd int, path string, s *Stat_t, flags int) (err error) { + return fstatat(fd, path, s, flags) +} + func Fstat(fd int, s *Stat_t) (err error) { st := &stat_t{} err = fstat(fd, st) diff --git a/src/syscall/zsyscall_linux_mips64.go b/src/syscall/zsyscall_linux_mips64.go index 0352ea54202d1c..449088c815504a 100644 --- a/src/syscall/zsyscall_linux_mips64.go +++ b/src/syscall/zsyscall_linux_mips64.go @@ -1116,21 +1116,6 @@ func Fstatfs(fd int, buf *Statfs_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_NEWFSTATAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Ftruncate(fd int, length int64) (err error) { _, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), 0) if e1 != 0 { @@ -1638,6 +1623,21 @@ func utimes(path string, times *[2]Timeval) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func fstatatInternal(dirfd int, path string, stat *stat_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_NEWFSTATAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func fstat(fd int, st *stat_t) (err error) { _, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(st)), 0) if e1 != 0 { diff --git a/src/syscall/zsyscall_linux_mips64le.go b/src/syscall/zsyscall_linux_mips64le.go index 1338b8c1c351c4..048298a39c910d 100644 --- a/src/syscall/zsyscall_linux_mips64le.go +++ b/src/syscall/zsyscall_linux_mips64le.go @@ -1116,21 +1116,6 @@ func Fstatfs(fd int, buf *Statfs_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_NEWFSTATAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Ftruncate(fd int, length int64) (err error) { _, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), 0) if e1 != 0 { @@ -1638,6 +1623,21 @@ func utimes(path string, times *[2]Timeval) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func fstatatInternal(dirfd int, path string, stat *stat_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_NEWFSTATAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func fstat(fd int, st *stat_t) (err error) { _, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(st)), 0) if e1 != 0 { From e977b83b320b3aedca218566c42ee94c5fad6bb0 Mon Sep 17 00:00:00 2001 From: Oleksandr Redko Date: Tue, 17 Dec 2024 20:14:16 +0200 Subject: [PATCH 041/397] cmd/go/internal/help: use secure link to swig.org Change-Id: Ifd315128ceeddf92bc16647869c3ace77ed1f430 Reviewed-on: https://go-review.googlesource.com/c/go/+/637195 Reviewed-by: Michael Matloob Auto-Submit: Ian Lance Taylor Reviewed-by: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI --- src/cmd/go/alldocs.go | 2 +- src/cmd/go/internal/help/helpdoc.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index 3a4473902cb8f1..5edd93599e56d8 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -2250,7 +2250,7 @@ // // The second is the SWIG program, which is a general tool for // interfacing between languages. For information on SWIG see -// http://swig.org/. When running go build, any file with a .swig +// https://swig.org/. When running go build, any file with a .swig // extension will be passed to SWIG. Any file with a .swigcxx extension // will be passed to SWIG with the -c++ option. // diff --git a/src/cmd/go/internal/help/helpdoc.go b/src/cmd/go/internal/help/helpdoc.go index e1240de710b7a9..3db3ed06b2c9e3 100644 --- a/src/cmd/go/internal/help/helpdoc.go +++ b/src/cmd/go/internal/help/helpdoc.go @@ -17,7 +17,7 @@ information on how to use it see the cgo documentation (go doc cmd/cgo). The second is the SWIG program, which is a general tool for interfacing between languages. For information on SWIG see -http://swig.org/. When running go build, any file with a .swig +https://swig.org/. When running go build, any file with a .swig extension will be passed to SWIG. Any file with a .swigcxx extension will be passed to SWIG with the -c++ option. From b057b8872d8297ec9ccbfd9d29dad51dff795846 Mon Sep 17 00:00:00 2001 From: Oleksandr Redko Date: Tue, 17 Dec 2024 19:05:23 +0200 Subject: [PATCH 042/397] bytes, strings: add cross-references in docstrings For newly funcs SplitSeq, SplitAfterSeq, FieldsSeq, FieldsFuncSeq. Updates #61901. Change-Id: I3c97bfd9c2250de68aaea348c82a05635ee797af Reviewed-on: https://go-review.googlesource.com/c/go/+/637176 Auto-Submit: Ian Lance Taylor Reviewed-by: Robert Griesemer Reviewed-by: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI --- src/bytes/iter.go | 10 +++++----- src/strings/iter.go | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/bytes/iter.go b/src/bytes/iter.go index 1cf13a94ec263e..9890a478a8b2e8 100644 --- a/src/bytes/iter.go +++ b/src/bytes/iter.go @@ -68,7 +68,7 @@ func splitSeq(s, sep []byte, sepSave int) iter.Seq[[]byte] { } // SplitSeq returns an iterator over all substrings of s separated by sep. -// The iterator yields the same strings that would be returned by Split(s, sep), +// The iterator yields the same strings that would be returned by [Split](s, sep), // but without constructing the slice. // It returns a single-use iterator. func SplitSeq(s, sep []byte) iter.Seq[[]byte] { @@ -76,7 +76,7 @@ func SplitSeq(s, sep []byte) iter.Seq[[]byte] { } // SplitAfterSeq returns an iterator over substrings of s split after each instance of sep. -// The iterator yields the same strings that would be returned by SplitAfter(s, sep), +// The iterator yields the same strings that would be returned by [SplitAfter](s, sep), // but without constructing the slice. // It returns a single-use iterator. func SplitAfterSeq(s, sep []byte) iter.Seq[[]byte] { @@ -84,8 +84,8 @@ func SplitAfterSeq(s, sep []byte) iter.Seq[[]byte] { } // FieldsSeq returns an iterator over substrings of s split around runs of -// whitespace characters, as defined by unicode.IsSpace. -// The iterator yields the same strings that would be returned by Fields(s), +// whitespace characters, as defined by [unicode.IsSpace]. +// The iterator yields the same strings that would be returned by [Fields](s), // but without constructing the slice. func FieldsSeq(s []byte) iter.Seq[[]byte] { return func(yield func([]byte) bool) { @@ -118,7 +118,7 @@ func FieldsSeq(s []byte) iter.Seq[[]byte] { // FieldsFuncSeq returns an iterator over substrings of s split around runs of // Unicode code points satisfying f(c). -// The iterator yields the same strings that would be returned by FieldsFunc(s), +// The iterator yields the same strings that would be returned by [FieldsFunc](s), // but without constructing the slice. func FieldsFuncSeq(s []byte, f func(rune) bool) iter.Seq[[]byte] { return func(yield func([]byte) bool) { diff --git a/src/strings/iter.go b/src/strings/iter.go index b9620902bfedb7..3168e59687dc94 100644 --- a/src/strings/iter.go +++ b/src/strings/iter.go @@ -68,7 +68,7 @@ func splitSeq(s, sep string, sepSave int) iter.Seq[string] { } // SplitSeq returns an iterator over all substrings of s separated by sep. -// The iterator yields the same strings that would be returned by Split(s, sep), +// The iterator yields the same strings that would be returned by [Split](s, sep), // but without constructing the slice. // It returns a single-use iterator. func SplitSeq(s, sep string) iter.Seq[string] { @@ -76,7 +76,7 @@ func SplitSeq(s, sep string) iter.Seq[string] { } // SplitAfterSeq returns an iterator over substrings of s split after each instance of sep. -// The iterator yields the same strings that would be returned by SplitAfter(s, sep), +// The iterator yields the same strings that would be returned by [SplitAfter](s, sep), // but without constructing the slice. // It returns a single-use iterator. func SplitAfterSeq(s, sep string) iter.Seq[string] { @@ -84,8 +84,8 @@ func SplitAfterSeq(s, sep string) iter.Seq[string] { } // FieldsSeq returns an iterator over substrings of s split around runs of -// whitespace characters, as defined by unicode.IsSpace. -// The iterator yields the same strings that would be returned by Fields(s), +// whitespace characters, as defined by [unicode.IsSpace]. +// The iterator yields the same strings that would be returned by [Fields](s), // but without constructing the slice. func FieldsSeq(s string) iter.Seq[string] { return func(yield func(string) bool) { @@ -118,7 +118,7 @@ func FieldsSeq(s string) iter.Seq[string] { // FieldsFuncSeq returns an iterator over substrings of s split around runs of // Unicode code points satisfying f(c). -// The iterator yields the same strings that would be returned by FieldsFunc(s), +// The iterator yields the same strings that would be returned by [FieldsFunc](s), // but without constructing the slice. func FieldsFuncSeq(s string, f func(rune) bool) iter.Seq[string] { return func(yield func(string) bool) { From 8790372a8d7e777d23d6b77d248318d01f4d7c4d Mon Sep 17 00:00:00 2001 From: wangshuo Date: Tue, 17 Dec 2024 12:50:44 +0000 Subject: [PATCH 043/397] cmd, go: fix some typos Change-Id: I0fd54ae5294eb4ef30cdef05adb8825f69077b14 GitHub-Last-Rev: ccfa48cbe4525dc2bd60e9ac7e2c150e480ba13f GitHub-Pull-Request: golang/go#70823 Reviewed-on: https://go-review.googlesource.com/c/go/+/635915 Reviewed-by: Ian Lance Taylor Reviewed-by: Robert Griesemer Auto-Submit: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI --- src/cmd/compile/internal/types2/README.md | 2 +- src/cmd/compile/internal/types2/signature.go | 2 +- src/cmd/go/testdata/script/build_version_stamping_git.txt | 4 ++-- src/cmd/vet/vet_test.go | 2 +- src/go/types/signature.go | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/cmd/compile/internal/types2/README.md b/src/cmd/compile/internal/types2/README.md index 3d70cdbcf484dd..73253b49207aac 100644 --- a/src/cmd/compile/internal/types2/README.md +++ b/src/cmd/compile/internal/types2/README.md @@ -56,7 +56,7 @@ The tests are in: Tests are .go files annotated with `/* ERROR "msg" */` or `/* ERRORx "msg" */` comments (or the respective line comment form). For each such error comment, typechecking the respective file is expected to -report an error at the position of the syntactic token _immediately preceeding_ +report an error at the position of the syntactic token _immediately preceding_ the comment. For `ERROR`, the `"msg"` string must be a substring of the error message reported by the typechecker; diff --git a/src/cmd/compile/internal/types2/signature.go b/src/cmd/compile/internal/types2/signature.go index d3169630eaa0bd..de4f1eaa207fdc 100644 --- a/src/cmd/compile/internal/types2/signature.go +++ b/src/cmd/compile/internal/types2/signature.go @@ -174,7 +174,7 @@ func (check *Checker) collectRecv(rparam *syntax.Field, scopePos syntax.Pos) (*V } else { // If there are type parameters, rbase must denote a generic base type. // Important: rbase must be resolved before declaring any receiver type - // parameters (wich may have the same name, see below). + // parameters (which may have the same name, see below). var baseType *Named // nil if not valid var cause string if t := check.genericType(rbase, &cause); isValid(t) { diff --git a/src/cmd/go/testdata/script/build_version_stamping_git.txt b/src/cmd/go/testdata/script/build_version_stamping_git.txt index ed07e00c7b192a..db804b38479960 100644 --- a/src/cmd/go/testdata/script/build_version_stamping_git.txt +++ b/src/cmd/go/testdata/script/build_version_stamping_git.txt @@ -51,7 +51,7 @@ go version -m example$GOEXE stdout '\s+mod\s+example\s+v1.0.1\s+' rm example$GOEXE -# Use tag+dirty when there are uncomitted changes present. +# Use tag+dirty when there are uncommitted changes present. cp $WORK/copy/README $WORK/repo/README go build go version -m example$GOEXE @@ -82,7 +82,7 @@ go version -m example$GOEXE stdout '\s+mod\s+example\s+v1.0.3-0.20220719150702-deaeab06f7fe\s+' rm example$GOEXE -# Use pseudo+dirty when uncomitted changes are present. +# Use pseudo+dirty when uncommitted changes are present. mv README2 README3 go build go version -m example$GOEXE diff --git a/src/cmd/vet/vet_test.go b/src/cmd/vet/vet_test.go index f1450dcbd28d2c..3860895a0ae96c 100644 --- a/src/cmd/vet/vet_test.go +++ b/src/cmd/vet/vet_test.go @@ -108,7 +108,7 @@ func TestVet(t *testing.T) { // is a no-op for files whose version >= go1.22, so we use a // go.mod file in the rangeloop directory to "downgrade". // - // TOOD(adonovan): delete when go1.21 goes away. + // TODO(adonovan): delete when go1.21 goes away. t.Run("loopclosure", func(t *testing.T) { cmd := testenv.Command(t, testenv.GoToolPath(t), "vet", "-vettool="+vetPath(t), ".") cmd.Env = append(os.Environ(), "GOWORK=off") diff --git a/src/go/types/signature.go b/src/go/types/signature.go index 681eb85fd70b8f..ff405318ee4ca8 100644 --- a/src/go/types/signature.go +++ b/src/go/types/signature.go @@ -195,7 +195,7 @@ func (check *Checker) collectRecv(rparam *ast.Field, scopePos token.Pos) (*Var, } else { // If there are type parameters, rbase must denote a generic base type. // Important: rbase must be resolved before declaring any receiver type - // parameters (wich may have the same name, see below). + // parameters (which may have the same name, see below). var baseType *Named // nil if not valid var cause string if t := check.genericType(rbase, &cause); isValid(t) { From b9e2ffdcd2520c136c4e98f67f0c714f989d31ab Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Mon, 16 Dec 2024 17:44:21 +0100 Subject: [PATCH 044/397] crypto/internal/fips140: add Name and Version MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per ISO/IEC 19790:2012, Section 7.4.3.1. > A cryptographic module shall [04.12] provide the following services to > operators. > > a) Show module’s versioning information. The cryptographic module > shall [04.13] output the name or module identifier and the versioning > information that can be correlated with a validation record (e.g. > hardware, software and/or firmware versioning information)." For #69536 Change-Id: I8061f64e4ae60a4666f6abd892cb1301d6bf2452 Reviewed-on: https://go-review.googlesource.com/c/go/+/636558 Auto-Submit: Filippo Valsorda Reviewed-by: Daniel McCarney Reviewed-by: Roland Shoemaker Reviewed-by: David Chase LUCI-TryBot-Result: Go LUCI --- src/crypto/internal/fips140/fips140.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/crypto/internal/fips140/fips140.go b/src/crypto/internal/fips140/fips140.go index cec9d13e35bb82..d30433debfcd29 100644 --- a/src/crypto/internal/fips140/fips140.go +++ b/src/crypto/internal/fips140/fips140.go @@ -19,3 +19,11 @@ func init() { debug = true } } + +func Name() string { + return "Go Cryptographic Module" +} + +func Version() string { + return "v1.0" +} From b2c0168893a7f27927630198cdf63911374035c3 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Tue, 17 Dec 2024 17:55:01 +0100 Subject: [PATCH 045/397] crypto/internal/fips140/aes/gcm: use aes.EncryptBlockInternal on ppc64x and s390x Left them out of CL 636775 because I did a search by reference, which does not span architectures. Fixes crypto/cipher.TestFIPSServiceIndicator failure on ppc64x and s390x. For #69536 Change-Id: I34b49705a7099066e8c3871a7a34b394a9298e98 Reviewed-on: https://go-review.googlesource.com/c/go/+/637175 Reviewed-by: David Chase Reviewed-by: Roland Shoemaker Auto-Submit: Filippo Valsorda Reviewed-by: Daniel McCarney LUCI-TryBot-Result: Go LUCI --- src/crypto/internal/fips140/aes/gcm/gcm_ppc64x.go | 6 +++--- src/crypto/internal/fips140/aes/gcm/gcm_s390x.go | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/crypto/internal/fips140/aes/gcm/gcm_ppc64x.go b/src/crypto/internal/fips140/aes/gcm/gcm_ppc64x.go index 5084835e88d315..8d44c75745d9b8 100644 --- a/src/crypto/internal/fips140/aes/gcm/gcm_ppc64x.go +++ b/src/crypto/internal/fips140/aes/gcm/gcm_ppc64x.go @@ -51,7 +51,7 @@ func initGCM(g *GCM) { } hle := make([]byte, gcmBlockSize) - g.cipher.Encrypt(hle, hle) + aes.EncryptBlockInternal(&g.cipher, hle, hle) // Reverse the bytes in each 8 byte chunk // Load little endian, store big endian @@ -133,7 +133,7 @@ func seal(out []byte, g *GCM, nonce, plaintext, data []byte) { var counter, tagMask [gcmBlockSize]byte deriveCounter(&counter, nonce, &g.productTable) - g.cipher.Encrypt(tagMask[:], counter[:]) + aes.EncryptBlockInternal(&g.cipher, tagMask[:], counter[:]) gcmInc32(&counter) counterCrypt(&g.cipher, out, plaintext, &counter) @@ -151,7 +151,7 @@ func open(out []byte, g *GCM, nonce, ciphertext, data []byte) error { var counter, tagMask [gcmBlockSize]byte deriveCounter(&counter, nonce, &g.productTable) - g.cipher.Encrypt(tagMask[:], counter[:]) + aes.EncryptBlockInternal(&g.cipher, tagMask[:], counter[:]) gcmInc32(&counter) var expectedTag [gcmTagSize]byte diff --git a/src/crypto/internal/fips140/aes/gcm/gcm_s390x.go b/src/crypto/internal/fips140/aes/gcm/gcm_s390x.go index 6d88e1824083be..526f3f9d4a2019 100644 --- a/src/crypto/internal/fips140/aes/gcm/gcm_s390x.go +++ b/src/crypto/internal/fips140/aes/gcm/gcm_s390x.go @@ -55,7 +55,7 @@ func initGCM(g *GCM) { return } // Note that hashKey is also used in the KMA codepath to hash large nonces. - g.cipher.Encrypt(g.hashKey[:], g.hashKey[:]) + aes.EncryptBlockInternal(&g.cipher, g.hashKey[:], g.hashKey[:]) } // ghashAsm uses the GHASH algorithm to hash data with the given key. The initial @@ -115,7 +115,7 @@ func counterCrypt(g *GCM, dst, src []byte, cnt *[gcmBlockSize]byte) { } if len(src) > 0 { var x [16]byte - g.cipher.Encrypt(x[:], cnt[:]) + aes.EncryptBlockInternal(&g.cipher, x[:], cnt[:]) for i := range src { dst[i] = src[i] ^ x[i] } From 95b433eed428afbb4ab32f0f2541774e939989c7 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 17 Dec 2024 11:31:17 -0800 Subject: [PATCH 046/397] debug/elf: adjust version API per issue discussion This updates the new version API for the discussion on #63952. Note that the current tests do not have symbols with hidden versions. Leaving that for later. For #63952 Change-Id: I1ad4b1e485429a216ba8e5b68f7f4299d120628f Reviewed-on: https://go-review.googlesource.com/c/go/+/637235 Reviewed-by: Ian Lance Taylor Auto-Submit: Ian Lance Taylor Reviewed-by: Austin Clements LUCI-TryBot-Result: Go LUCI Commit-Queue: Ian Lance Taylor --- api/go1.24.txt | 18 +- src/debug/elf/file.go | 94 ++++---- src/debug/elf/file_test.go | 384 ++++++++++++++--------------- src/debug/elf/symbols_test.go | 439 +++++++++++++++++----------------- 4 files changed, 468 insertions(+), 467 deletions(-) diff --git a/api/go1.24.txt b/api/go1.24.txt index 795a70e3547695..05e2006e0747bb 100644 --- a/api/go1.24.txt +++ b/api/go1.24.txt @@ -106,16 +106,6 @@ pkg debug/elf, const VER_FLG_INFO = 4 #63952 pkg debug/elf, const VER_FLG_INFO DynamicVersionFlag #63952 pkg debug/elf, const VER_FLG_WEAK = 2 #63952 pkg debug/elf, const VER_FLG_WEAK DynamicVersionFlag #63952 -pkg debug/elf, const VersionScopeGlobal = 2 #63952 -pkg debug/elf, const VersionScopeGlobal SymbolVersionScope #63952 -pkg debug/elf, const VersionScopeHidden = 4 #63952 -pkg debug/elf, const VersionScopeHidden SymbolVersionScope #63952 -pkg debug/elf, const VersionScopeLocal = 1 #63952 -pkg debug/elf, const VersionScopeLocal SymbolVersionScope #63952 -pkg debug/elf, const VersionScopeNone = 0 #63952 -pkg debug/elf, const VersionScopeNone SymbolVersionScope #63952 -pkg debug/elf, const VersionScopeSpecific = 3 #63952 -pkg debug/elf, const VersionScopeSpecific SymbolVersionScope #63952 pkg debug/elf, method (*File) DynamicVersionNeeds() ([]DynamicVersionNeed, error) #63952 pkg debug/elf, method (*File) DynamicVersions() ([]DynamicVersion, error) #63952 pkg debug/elf, type DynamicVersion struct #63952 @@ -131,9 +121,11 @@ pkg debug/elf, type DynamicVersionFlag uint16 #63952 pkg debug/elf, type DynamicVersionNeed struct #63952 pkg debug/elf, type DynamicVersionNeed struct, Name string #63952 pkg debug/elf, type DynamicVersionNeed struct, Needs []DynamicVersionDep #63952 -pkg debug/elf, type Symbol struct, VersionScope SymbolVersionScope #63952 -pkg debug/elf, type Symbol struct, VersionIndex int16 #63952 -pkg debug/elf, type SymbolVersionScope uint8 #63952 +pkg debug/elf, type Symbol struct, HasVersion bool #63952 +pkg debug/elf, type Symbol struct, VersionIndex VersionIndex #63952 +pkg debug/elf, method (VersionIndex) Index() uint16 #63952 +pkg debug/elf, method (VersionIndex) IsHidden() bool #63952 +pkg debug/elf, type VersionIndex uint16 #63952 pkg encoding, type BinaryAppender interface { AppendBinary } #62384 pkg encoding, type BinaryAppender interface, AppendBinary([]uint8) ([]uint8, error) #62384 pkg encoding, type TextAppender interface { AppendText } #62384 diff --git a/src/debug/elf/file.go b/src/debug/elf/file.go index 958ed9971d070b..89bd70b5b2a87c 100644 --- a/src/debug/elf/file.go +++ b/src/debug/elf/file.go @@ -209,22 +209,13 @@ type Symbol struct { Name string Info, Other byte - // VersionScope describes the version in which the symbol is defined. - // This is only set for the dynamic symbol table. - // When no symbol versioning information is available, - // this is VersionScopeNone. - VersionScope SymbolVersionScope - // VersionIndex is the version index. - // This is only set if VersionScope is VersionScopeSpecific or - // VersionScopeHidden. This is only set for the dynamic symbol table. - // This index will match either [DynamicVersion.Index] - // in the slice returned by [File.DynamicVersions], - // or [DynamicVersiondep.Index] in the Needs field - // of the elements of the slice returned by [File.DynamicVersionNeeds]. - // In general, a defined symbol will have an index referring - // to DynamicVersions, and an undefined symbol will have an index - // referring to some version in DynamicVersionNeeds. - VersionIndex int16 + // HasVersion reports whether the symbol has any version information. + // This will only be true for the dynamic symbol table. + HasVersion bool + // VersionIndex is the symbol's version index. + // Use the methods of the [VersionIndex] type to access it. + // This field is only meaningful if HasVersion is true. + VersionIndex VersionIndex Section SectionIndex Value, Size uint64 @@ -678,7 +669,6 @@ func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) { symbols[i].Name = str symbols[i].Info = sym.Info symbols[i].Other = sym.Other - symbols[i].VersionIndex = -1 symbols[i].Section = SectionIndex(sym.Shndx) symbols[i].Value = uint64(sym.Value) symbols[i].Size = uint64(sym.Size) @@ -726,7 +716,6 @@ func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) { symbols[i].Name = str symbols[i].Info = sym.Info symbols[i].Other = sym.Other - symbols[i].VersionIndex = -1 symbols[i].Section = SectionIndex(sym.Shndx) symbols[i].Value = sym.Value symbols[i].Size = sym.Size @@ -1473,7 +1462,7 @@ func (f *File) DynamicSymbols() ([]Symbol, error) { } if hasVersions { for i := range sym { - sym[i].VersionIndex, sym[i].Version, sym[i].Library, sym[i].VersionScope = f.gnuVersion(i) + sym[i].HasVersion, sym[i].VersionIndex, sym[i].Version, sym[i].Library = f.gnuVersion(i) } } return sym, nil @@ -1502,23 +1491,37 @@ func (f *File) ImportedSymbols() ([]ImportedSymbol, error) { if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF { all = append(all, ImportedSymbol{Name: s.Name}) sym := &all[len(all)-1] - _, sym.Version, sym.Library, _ = f.gnuVersion(i) + _, _, sym.Version, sym.Library = f.gnuVersion(i) } } return all, nil } -// SymbolVersionScope describes the version in which a [Symbol] is defined. -// This is only used for the dynamic symbol table. -type SymbolVersionScope byte +// VersionIndex is the type of a [Symbol] version index. +type VersionIndex uint16 -const ( - VersionScopeNone SymbolVersionScope = iota // no symbol version available - VersionScopeLocal // symbol has local scope - VersionScopeGlobal // symbol has global scope and is in the base version - VersionScopeSpecific // symbol has global scope and is in the version given by VersionIndex - VersionScopeHidden // symbol is in the version given by VersionIndex, and is hidden -) +// IsHidden reports whether the symbol is hidden within the version. +// This means that the symbol can only be seen by specifying the exact version. +func (vi VersionIndex) IsHidden() bool { + return vi&0x8000 != 0 +} + +// Index returns the version index. +// If this is the value 0, it means that the symbol is local, +// and is not visible externally. +// If this is the value 1, it means that the symbol is in the base version, +// and has no specific version; it may or may not match a +// [DynamicVersion.Index] in the slice returned by [File.DynamicVersions]. +// Other values will match either [DynamicVersion.Index] +// in the slice returned by [File.DynamicVersions], +// or [DynamicVersionDep.Index] in the Needs field +// of the elements of the slice returned by [File.DynamicVersionNeeds]. +// In general, a defined symbol will have an index referring +// to DynamicVersions, and an undefined symbol will have an index +// referring to some version in DynamicVersionNeeds. +func (vi VersionIndex) Index() uint16 { + return uint16(vi & 0x7fff) +} // DynamicVersion is a version defined by a dynamic object. // This describes entries in the ELF SHT_GNU_verdef section. @@ -1752,45 +1755,38 @@ func (f *File) gnuVersionInit(str []byte) (bool, error) { // gnuVersion adds Library and Version information to sym, // which came from offset i of the symbol table. -func (f *File) gnuVersion(i int) (versionIndex int16, version string, library string, versionFlags SymbolVersionScope) { +func (f *File) gnuVersion(i int) (hasVersion bool, versionIndex VersionIndex, version string, library string) { // Each entry is two bytes; skip undef entry at beginning. i = (i + 1) * 2 if i >= len(f.gnuVersym) { - return -1, "", "", VersionScopeNone + return false, 0, "", "" } s := f.gnuVersym[i:] if len(s) < 2 { - return -1, "", "", VersionScopeNone - } - j := int32(f.ByteOrder.Uint16(s)) - ndx := int16(j & 0x7fff) - - if j == 0 { - return ndx, "", "", VersionScopeLocal - } else if j == 1 { - return ndx, "", "", VersionScopeGlobal + return false, 0, "", "" } + vi := VersionIndex(f.ByteOrder.Uint16(s)) + ndx := vi.Index() - scope := VersionScopeSpecific - if j&0x8000 != 0 { - scope = VersionScopeHidden + if ndx == 0 || ndx == 1 { + return true, vi, "", "" } for _, v := range f.dynVerNeeds { for _, n := range v.Needs { - if uint16(ndx) == n.Index { - return ndx, n.Dep, v.Name, scope + if ndx == n.Index { + return true, vi, n.Dep, v.Name } } } for _, v := range f.dynVers { - if uint16(ndx) == v.Index { - return ndx, v.Name, "", scope + if ndx == v.Index { + return true, vi, v.Name, "" } } - return -1, "", "", VersionScopeNone + return false, 0, "", "" } // ImportedLibraries returns the names of all libraries diff --git a/src/debug/elf/file_test.go b/src/debug/elf/file_test.go index 72e45588682b55..1fdbbad04df44f 100644 --- a/src/debug/elf/file_test.go +++ b/src/debug/elf/file_test.go @@ -78,80 +78,80 @@ var fileTests = []fileTest{ }, []string{"libc.so.6"}, []Symbol{ - {"", 3, 0, VersionScopeNone, -1, 1, 134512852, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 2, 134512876, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 3, 134513020, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 4, 134513292, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 5, 134513480, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 6, 134513512, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 7, 134513532, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 8, 134513612, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 9, 134513996, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 10, 134514008, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 11, 134518268, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 12, 134518280, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 13, 134518284, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 14, 134518436, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 15, 134518444, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 16, 134518452, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 17, 134518456, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 18, 134518484, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 19, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 20, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 21, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 22, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 23, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 24, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 25, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 26, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 27, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 28, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 29, 0, 0, "", ""}, - {"crt1.c", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, - {"/usr/src/lib/csu/i386-elf/crti.S", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, - {"", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, - {"", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, - {"/usr/src/lib/csu/i386-elf/crti.S", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, - {"crtstuff.c", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, - {"__CTOR_LIST__", 1, 0, VersionScopeNone, -1, 14, 134518436, 0, "", ""}, - {"__DTOR_LIST__", 1, 0, VersionScopeNone, -1, 15, 134518444, 0, "", ""}, - {"__EH_FRAME_BEGIN__", 1, 0, VersionScopeNone, -1, 12, 134518280, 0, "", ""}, - {"__JCR_LIST__", 1, 0, VersionScopeNone, -1, 16, 134518452, 0, "", ""}, - {"p.0", 1, 0, VersionScopeNone, -1, 11, 134518276, 0, "", ""}, - {"completed.1", 1, 0, VersionScopeNone, -1, 18, 134518484, 1, "", ""}, - {"__do_global_dtors_aux", 2, 0, VersionScopeNone, -1, 8, 134513760, 0, "", ""}, - {"object.2", 1, 0, VersionScopeNone, -1, 18, 134518488, 24, "", ""}, - {"frame_dummy", 2, 0, VersionScopeNone, -1, 8, 134513836, 0, "", ""}, - {"crtstuff.c", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, - {"__CTOR_END__", 1, 0, VersionScopeNone, -1, 14, 134518440, 0, "", ""}, - {"__DTOR_END__", 1, 0, VersionScopeNone, -1, 15, 134518448, 0, "", ""}, - {"__FRAME_END__", 1, 0, VersionScopeNone, -1, 12, 134518280, 0, "", ""}, - {"__JCR_END__", 1, 0, VersionScopeNone, -1, 16, 134518452, 0, "", ""}, - {"__do_global_ctors_aux", 2, 0, VersionScopeNone, -1, 8, 134513960, 0, "", ""}, - {"/usr/src/lib/csu/i386-elf/crtn.S", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, - {"", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, - {"", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, - {"/usr/src/lib/csu/i386-elf/crtn.S", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, - {"hello.c", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, - {"printf", 18, 0, VersionScopeNone, -1, 0, 0, 44, "", ""}, - {"_DYNAMIC", 17, 0, VersionScopeNone, -1, 65521, 134518284, 0, "", ""}, - {"__dso_handle", 17, 2, VersionScopeNone, -1, 11, 134518272, 0, "", ""}, - {"_init", 18, 0, VersionScopeNone, -1, 6, 134513512, 0, "", ""}, - {"environ", 17, 0, VersionScopeNone, -1, 18, 134518512, 4, "", ""}, - {"__deregister_frame_info", 32, 0, VersionScopeNone, -1, 0, 0, 0, "", ""}, - {"__progname", 17, 0, VersionScopeNone, -1, 11, 134518268, 4, "", ""}, - {"_start", 18, 0, VersionScopeNone, -1, 8, 134513612, 145, "", ""}, - {"__bss_start", 16, 0, VersionScopeNone, -1, 65521, 134518484, 0, "", ""}, - {"main", 18, 0, VersionScopeNone, -1, 8, 134513912, 46, "", ""}, - {"_init_tls", 18, 0, VersionScopeNone, -1, 0, 0, 5, "", ""}, - {"_fini", 18, 0, VersionScopeNone, -1, 9, 134513996, 0, "", ""}, - {"atexit", 18, 0, VersionScopeNone, -1, 0, 0, 43, "", ""}, - {"_edata", 16, 0, VersionScopeNone, -1, 65521, 134518484, 0, "", ""}, - {"_GLOBAL_OFFSET_TABLE_", 17, 0, VersionScopeNone, -1, 65521, 134518456, 0, "", ""}, - {"_end", 16, 0, VersionScopeNone, -1, 65521, 134518516, 0, "", ""}, - {"exit", 18, 0, VersionScopeNone, -1, 0, 0, 68, "", ""}, - {"_Jv_RegisterClasses", 32, 0, VersionScopeNone, -1, 0, 0, 0, "", ""}, - {"__register_frame_info", 32, 0, VersionScopeNone, -1, 0, 0, 0, "", ""}, + {"", 3, 0, false, 0, 1, 134512852, 0, "", ""}, + {"", 3, 0, false, 0, 2, 134512876, 0, "", ""}, + {"", 3, 0, false, 0, 3, 134513020, 0, "", ""}, + {"", 3, 0, false, 0, 4, 134513292, 0, "", ""}, + {"", 3, 0, false, 0, 5, 134513480, 0, "", ""}, + {"", 3, 0, false, 0, 6, 134513512, 0, "", ""}, + {"", 3, 0, false, 0, 7, 134513532, 0, "", ""}, + {"", 3, 0, false, 0, 8, 134513612, 0, "", ""}, + {"", 3, 0, false, 0, 9, 134513996, 0, "", ""}, + {"", 3, 0, false, 0, 10, 134514008, 0, "", ""}, + {"", 3, 0, false, 0, 11, 134518268, 0, "", ""}, + {"", 3, 0, false, 0, 12, 134518280, 0, "", ""}, + {"", 3, 0, false, 0, 13, 134518284, 0, "", ""}, + {"", 3, 0, false, 0, 14, 134518436, 0, "", ""}, + {"", 3, 0, false, 0, 15, 134518444, 0, "", ""}, + {"", 3, 0, false, 0, 16, 134518452, 0, "", ""}, + {"", 3, 0, false, 0, 17, 134518456, 0, "", ""}, + {"", 3, 0, false, 0, 18, 134518484, 0, "", ""}, + {"", 3, 0, false, 0, 19, 0, 0, "", ""}, + {"", 3, 0, false, 0, 20, 0, 0, "", ""}, + {"", 3, 0, false, 0, 21, 0, 0, "", ""}, + {"", 3, 0, false, 0, 22, 0, 0, "", ""}, + {"", 3, 0, false, 0, 23, 0, 0, "", ""}, + {"", 3, 0, false, 0, 24, 0, 0, "", ""}, + {"", 3, 0, false, 0, 25, 0, 0, "", ""}, + {"", 3, 0, false, 0, 26, 0, 0, "", ""}, + {"", 3, 0, false, 0, 27, 0, 0, "", ""}, + {"", 3, 0, false, 0, 28, 0, 0, "", ""}, + {"", 3, 0, false, 0, 29, 0, 0, "", ""}, + {"crt1.c", 4, 0, false, 0, 65521, 0, 0, "", ""}, + {"/usr/src/lib/csu/i386-elf/crti.S", 4, 0, false, 0, 65521, 0, 0, "", ""}, + {"", 4, 0, false, 0, 65521, 0, 0, "", ""}, + {"", 4, 0, false, 0, 65521, 0, 0, "", ""}, + {"/usr/src/lib/csu/i386-elf/crti.S", 4, 0, false, 0, 65521, 0, 0, "", ""}, + {"crtstuff.c", 4, 0, false, 0, 65521, 0, 0, "", ""}, + {"__CTOR_LIST__", 1, 0, false, 0, 14, 134518436, 0, "", ""}, + {"__DTOR_LIST__", 1, 0, false, 0, 15, 134518444, 0, "", ""}, + {"__EH_FRAME_BEGIN__", 1, 0, false, 0, 12, 134518280, 0, "", ""}, + {"__JCR_LIST__", 1, 0, false, 0, 16, 134518452, 0, "", ""}, + {"p.0", 1, 0, false, 0, 11, 134518276, 0, "", ""}, + {"completed.1", 1, 0, false, 0, 18, 134518484, 1, "", ""}, + {"__do_global_dtors_aux", 2, 0, false, 0, 8, 134513760, 0, "", ""}, + {"object.2", 1, 0, false, 0, 18, 134518488, 24, "", ""}, + {"frame_dummy", 2, 0, false, 0, 8, 134513836, 0, "", ""}, + {"crtstuff.c", 4, 0, false, 0, 65521, 0, 0, "", ""}, + {"__CTOR_END__", 1, 0, false, 0, 14, 134518440, 0, "", ""}, + {"__DTOR_END__", 1, 0, false, 0, 15, 134518448, 0, "", ""}, + {"__FRAME_END__", 1, 0, false, 0, 12, 134518280, 0, "", ""}, + {"__JCR_END__", 1, 0, false, 0, 16, 134518452, 0, "", ""}, + {"__do_global_ctors_aux", 2, 0, false, 0, 8, 134513960, 0, "", ""}, + {"/usr/src/lib/csu/i386-elf/crtn.S", 4, 0, false, 0, 65521, 0, 0, "", ""}, + {"", 4, 0, false, 0, 65521, 0, 0, "", ""}, + {"", 4, 0, false, 0, 65521, 0, 0, "", ""}, + {"/usr/src/lib/csu/i386-elf/crtn.S", 4, 0, false, 0, 65521, 0, 0, "", ""}, + {"hello.c", 4, 0, false, 0, 65521, 0, 0, "", ""}, + {"printf", 18, 0, false, 0, 0, 0, 44, "", ""}, + {"_DYNAMIC", 17, 0, false, 0, 65521, 134518284, 0, "", ""}, + {"__dso_handle", 17, 2, false, 0, 11, 134518272, 0, "", ""}, + {"_init", 18, 0, false, 0, 6, 134513512, 0, "", ""}, + {"environ", 17, 0, false, 0, 18, 134518512, 4, "", ""}, + {"__deregister_frame_info", 32, 0, false, 0, 0, 0, 0, "", ""}, + {"__progname", 17, 0, false, 0, 11, 134518268, 4, "", ""}, + {"_start", 18, 0, false, 0, 8, 134513612, 145, "", ""}, + {"__bss_start", 16, 0, false, 0, 65521, 134518484, 0, "", ""}, + {"main", 18, 0, false, 0, 8, 134513912, 46, "", ""}, + {"_init_tls", 18, 0, false, 0, 0, 0, 5, "", ""}, + {"_fini", 18, 0, false, 0, 9, 134513996, 0, "", ""}, + {"atexit", 18, 0, false, 0, 0, 0, 43, "", ""}, + {"_edata", 16, 0, false, 0, 65521, 134518484, 0, "", ""}, + {"_GLOBAL_OFFSET_TABLE_", 17, 0, false, 0, 65521, 134518456, 0, "", ""}, + {"_end", 16, 0, false, 0, 65521, 134518516, 0, "", ""}, + {"exit", 18, 0, false, 0, 0, 0, 68, "", ""}, + {"_Jv_RegisterClasses", 32, 0, false, 0, 0, 0, 0, "", ""}, + {"__register_frame_info", 32, 0, false, 0, 0, 0, 0, "", ""}, }, }, { @@ -208,79 +208,79 @@ var fileTests = []fileTest{ }, []string{"libc.so.6"}, []Symbol{ - {"", 3, 0, VersionScopeNone, -1, 1, 4194816, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 2, 4194844, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 3, 4194880, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 4, 4194920, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 5, 4194952, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 6, 4195048, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 7, 4195110, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 8, 4195120, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 9, 4195152, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 10, 4195176, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 11, 4195224, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 12, 4195248, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 13, 4195296, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 14, 4195732, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 15, 4195748, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 16, 4195768, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 17, 4195808, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 18, 6293128, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 19, 6293144, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 20, 6293160, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 21, 6293168, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 22, 6293584, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 23, 6293592, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 24, 6293632, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 25, 6293656, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 26, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 27, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 28, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 29, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 30, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 31, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 32, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 33, 0, 0, "", ""}, - {"init.c", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, - {"initfini.c", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, - {"call_gmon_start", 2, 0, VersionScopeNone, -1, 13, 4195340, 0, "", ""}, - {"crtstuff.c", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, - {"__CTOR_LIST__", 1, 0, VersionScopeNone, -1, 18, 6293128, 0, "", ""}, - {"__DTOR_LIST__", 1, 0, VersionScopeNone, -1, 19, 6293144, 0, "", ""}, - {"__JCR_LIST__", 1, 0, VersionScopeNone, -1, 20, 6293160, 0, "", ""}, - {"__do_global_dtors_aux", 2, 0, VersionScopeNone, -1, 13, 4195376, 0, "", ""}, - {"completed.6183", 1, 0, VersionScopeNone, -1, 25, 6293656, 1, "", ""}, - {"p.6181", 1, 0, VersionScopeNone, -1, 24, 6293648, 0, "", ""}, - {"frame_dummy", 2, 0, VersionScopeNone, -1, 13, 4195440, 0, "", ""}, - {"crtstuff.c", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, - {"__CTOR_END__", 1, 0, VersionScopeNone, -1, 18, 6293136, 0, "", ""}, - {"__DTOR_END__", 1, 0, VersionScopeNone, -1, 19, 6293152, 0, "", ""}, - {"__FRAME_END__", 1, 0, VersionScopeNone, -1, 17, 4195968, 0, "", ""}, - {"__JCR_END__", 1, 0, VersionScopeNone, -1, 20, 6293160, 0, "", ""}, - {"__do_global_ctors_aux", 2, 0, VersionScopeNone, -1, 13, 4195680, 0, "", ""}, - {"initfini.c", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, - {"hello.c", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, - {"_GLOBAL_OFFSET_TABLE_", 1, 2, VersionScopeNone, -1, 23, 6293592, 0, "", ""}, - {"__init_array_end", 0, 2, VersionScopeNone, -1, 18, 6293124, 0, "", ""}, - {"__init_array_start", 0, 2, VersionScopeNone, -1, 18, 6293124, 0, "", ""}, - {"_DYNAMIC", 1, 2, VersionScopeNone, -1, 21, 6293168, 0, "", ""}, - {"data_start", 32, 0, VersionScopeNone, -1, 24, 6293632, 0, "", ""}, - {"__libc_csu_fini", 18, 0, VersionScopeNone, -1, 13, 4195520, 2, "", ""}, - {"_start", 18, 0, VersionScopeNone, -1, 13, 4195296, 0, "", ""}, - {"__gmon_start__", 32, 0, VersionScopeNone, -1, 0, 0, 0, "", ""}, - {"_Jv_RegisterClasses", 32, 0, VersionScopeNone, -1, 0, 0, 0, "", ""}, - {"puts@@GLIBC_2.2.5", 18, 0, VersionScopeNone, -1, 0, 0, 396, "", ""}, - {"_fini", 18, 0, VersionScopeNone, -1, 14, 4195732, 0, "", ""}, - {"__libc_start_main@@GLIBC_2.2.5", 18, 0, VersionScopeNone, -1, 0, 0, 450, "", ""}, - {"_IO_stdin_used", 17, 0, VersionScopeNone, -1, 15, 4195748, 4, "", ""}, - {"__data_start", 16, 0, VersionScopeNone, -1, 24, 6293632, 0, "", ""}, - {"__dso_handle", 17, 2, VersionScopeNone, -1, 24, 6293640, 0, "", ""}, - {"__libc_csu_init", 18, 0, VersionScopeNone, -1, 13, 4195536, 137, "", ""}, - {"__bss_start", 16, 0, VersionScopeNone, -1, 65521, 6293656, 0, "", ""}, - {"_end", 16, 0, VersionScopeNone, -1, 65521, 6293664, 0, "", ""}, - {"_edata", 16, 0, VersionScopeNone, -1, 65521, 6293656, 0, "", ""}, - {"main", 18, 0, VersionScopeNone, -1, 13, 4195480, 27, "", ""}, - {"_init", 18, 0, VersionScopeNone, -1, 11, 4195224, 0, "", ""}, + {"", 3, 0, false, 0, 1, 4194816, 0, "", ""}, + {"", 3, 0, false, 0, 2, 4194844, 0, "", ""}, + {"", 3, 0, false, 0, 3, 4194880, 0, "", ""}, + {"", 3, 0, false, 0, 4, 4194920, 0, "", ""}, + {"", 3, 0, false, 0, 5, 4194952, 0, "", ""}, + {"", 3, 0, false, 0, 6, 4195048, 0, "", ""}, + {"", 3, 0, false, 0, 7, 4195110, 0, "", ""}, + {"", 3, 0, false, 0, 8, 4195120, 0, "", ""}, + {"", 3, 0, false, 0, 9, 4195152, 0, "", ""}, + {"", 3, 0, false, 0, 10, 4195176, 0, "", ""}, + {"", 3, 0, false, 0, 11, 4195224, 0, "", ""}, + {"", 3, 0, false, 0, 12, 4195248, 0, "", ""}, + {"", 3, 0, false, 0, 13, 4195296, 0, "", ""}, + {"", 3, 0, false, 0, 14, 4195732, 0, "", ""}, + {"", 3, 0, false, 0, 15, 4195748, 0, "", ""}, + {"", 3, 0, false, 0, 16, 4195768, 0, "", ""}, + {"", 3, 0, false, 0, 17, 4195808, 0, "", ""}, + {"", 3, 0, false, 0, 18, 6293128, 0, "", ""}, + {"", 3, 0, false, 0, 19, 6293144, 0, "", ""}, + {"", 3, 0, false, 0, 20, 6293160, 0, "", ""}, + {"", 3, 0, false, 0, 21, 6293168, 0, "", ""}, + {"", 3, 0, false, 0, 22, 6293584, 0, "", ""}, + {"", 3, 0, false, 0, 23, 6293592, 0, "", ""}, + {"", 3, 0, false, 0, 24, 6293632, 0, "", ""}, + {"", 3, 0, false, 0, 25, 6293656, 0, "", ""}, + {"", 3, 0, false, 0, 26, 0, 0, "", ""}, + {"", 3, 0, false, 0, 27, 0, 0, "", ""}, + {"", 3, 0, false, 0, 28, 0, 0, "", ""}, + {"", 3, 0, false, 0, 29, 0, 0, "", ""}, + {"", 3, 0, false, 0, 30, 0, 0, "", ""}, + {"", 3, 0, false, 0, 31, 0, 0, "", ""}, + {"", 3, 0, false, 0, 32, 0, 0, "", ""}, + {"", 3, 0, false, 0, 33, 0, 0, "", ""}, + {"init.c", 4, 0, false, 0, 65521, 0, 0, "", ""}, + {"initfini.c", 4, 0, false, 0, 65521, 0, 0, "", ""}, + {"call_gmon_start", 2, 0, false, 0, 13, 4195340, 0, "", ""}, + {"crtstuff.c", 4, 0, false, 0, 65521, 0, 0, "", ""}, + {"__CTOR_LIST__", 1, 0, false, 0, 18, 6293128, 0, "", ""}, + {"__DTOR_LIST__", 1, 0, false, 0, 19, 6293144, 0, "", ""}, + {"__JCR_LIST__", 1, 0, false, 0, 20, 6293160, 0, "", ""}, + {"__do_global_dtors_aux", 2, 0, false, 0, 13, 4195376, 0, "", ""}, + {"completed.6183", 1, 0, false, 0, 25, 6293656, 1, "", ""}, + {"p.6181", 1, 0, false, 0, 24, 6293648, 0, "", ""}, + {"frame_dummy", 2, 0, false, 0, 13, 4195440, 0, "", ""}, + {"crtstuff.c", 4, 0, false, 0, 65521, 0, 0, "", ""}, + {"__CTOR_END__", 1, 0, false, 0, 18, 6293136, 0, "", ""}, + {"__DTOR_END__", 1, 0, false, 0, 19, 6293152, 0, "", ""}, + {"__FRAME_END__", 1, 0, false, 0, 17, 4195968, 0, "", ""}, + {"__JCR_END__", 1, 0, false, 0, 20, 6293160, 0, "", ""}, + {"__do_global_ctors_aux", 2, 0, false, 0, 13, 4195680, 0, "", ""}, + {"initfini.c", 4, 0, false, 0, 65521, 0, 0, "", ""}, + {"hello.c", 4, 0, false, 0, 65521, 0, 0, "", ""}, + {"_GLOBAL_OFFSET_TABLE_", 1, 2, false, 0, 23, 6293592, 0, "", ""}, + {"__init_array_end", 0, 2, false, 0, 18, 6293124, 0, "", ""}, + {"__init_array_start", 0, 2, false, 0, 18, 6293124, 0, "", ""}, + {"_DYNAMIC", 1, 2, false, 0, 21, 6293168, 0, "", ""}, + {"data_start", 32, 0, false, 0, 24, 6293632, 0, "", ""}, + {"__libc_csu_fini", 18, 0, false, 0, 13, 4195520, 2, "", ""}, + {"_start", 18, 0, false, 0, 13, 4195296, 0, "", ""}, + {"__gmon_start__", 32, 0, false, 0, 0, 0, 0, "", ""}, + {"_Jv_RegisterClasses", 32, 0, false, 0, 0, 0, 0, "", ""}, + {"puts@@GLIBC_2.2.5", 18, 0, false, 0, 0, 0, 396, "", ""}, + {"_fini", 18, 0, false, 0, 14, 4195732, 0, "", ""}, + {"__libc_start_main@@GLIBC_2.2.5", 18, 0, false, 0, 0, 0, 450, "", ""}, + {"_IO_stdin_used", 17, 0, false, 0, 15, 4195748, 4, "", ""}, + {"__data_start", 16, 0, false, 0, 24, 6293632, 0, "", ""}, + {"__dso_handle", 17, 2, false, 0, 24, 6293640, 0, "", ""}, + {"__libc_csu_init", 18, 0, false, 0, 13, 4195536, 137, "", ""}, + {"__bss_start", 16, 0, false, 0, 65521, 6293656, 0, "", ""}, + {"_end", 16, 0, false, 0, 65521, 6293664, 0, "", ""}, + {"_edata", 16, 0, false, 0, 65521, 6293656, 0, "", ""}, + {"main", 18, 0, false, 0, 13, 4195480, 27, "", ""}, + {"_init", 18, 0, false, 0, 11, 4195224, 0, "", ""}, }, }, { @@ -338,21 +338,21 @@ var fileTests = []fileTest{ []ProgHeader{}, nil, []Symbol{ - {"hello.c", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 1, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 3, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 4, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 5, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 6, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 8, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 9, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 11, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 13, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 15, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 16, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 14, 0, 0, "", ""}, - {"main", 18, 0, VersionScopeNone, -1, 1, 0, 23, "", ""}, - {"puts", 16, 0, VersionScopeNone, -1, 0, 0, 0, "", ""}, + {"hello.c", 4, 0, false, 0, 65521, 0, 0, "", ""}, + {"", 3, 0, false, 0, 1, 0, 0, "", ""}, + {"", 3, 0, false, 0, 3, 0, 0, "", ""}, + {"", 3, 0, false, 0, 4, 0, 0, "", ""}, + {"", 3, 0, false, 0, 5, 0, 0, "", ""}, + {"", 3, 0, false, 0, 6, 0, 0, "", ""}, + {"", 3, 0, false, 0, 8, 0, 0, "", ""}, + {"", 3, 0, false, 0, 9, 0, 0, "", ""}, + {"", 3, 0, false, 0, 11, 0, 0, "", ""}, + {"", 3, 0, false, 0, 13, 0, 0, "", ""}, + {"", 3, 0, false, 0, 15, 0, 0, "", ""}, + {"", 3, 0, false, 0, 16, 0, 0, "", ""}, + {"", 3, 0, false, 0, 14, 0, 0, "", ""}, + {"main", 18, 0, false, 0, 1, 0, 23, "", ""}, + {"puts", 16, 0, false, 0, 0, 0, 0, "", ""}, }, }, { @@ -384,21 +384,21 @@ var fileTests = []fileTest{ []ProgHeader{}, nil, []Symbol{ - {"hello.c", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 1, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 3, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 4, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 5, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 6, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 8, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 9, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 11, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 13, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 15, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 16, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 14, 0, 0, "", ""}, - {"main", 18, 0, VersionScopeNone, -1, 1, 0, 27, "", ""}, - {"puts", 16, 0, VersionScopeNone, -1, 0, 0, 0, "", ""}, + {"hello.c", 4, 0, false, 0, 65521, 0, 0, "", ""}, + {"", 3, 0, false, 0, 1, 0, 0, "", ""}, + {"", 3, 0, false, 0, 3, 0, 0, "", ""}, + {"", 3, 0, false, 0, 4, 0, 0, "", ""}, + {"", 3, 0, false, 0, 5, 0, 0, "", ""}, + {"", 3, 0, false, 0, 6, 0, 0, "", ""}, + {"", 3, 0, false, 0, 8, 0, 0, "", ""}, + {"", 3, 0, false, 0, 9, 0, 0, "", ""}, + {"", 3, 0, false, 0, 11, 0, 0, "", ""}, + {"", 3, 0, false, 0, 13, 0, 0, "", ""}, + {"", 3, 0, false, 0, 15, 0, 0, "", ""}, + {"", 3, 0, false, 0, 16, 0, 0, "", ""}, + {"", 3, 0, false, 0, 14, 0, 0, "", ""}, + {"main", 18, 0, false, 0, 1, 0, 27, "", ""}, + {"puts", 16, 0, false, 0, 0, 0, 0, "", ""}, }, }, { @@ -430,21 +430,21 @@ var fileTests = []fileTest{ []ProgHeader{}, nil, []Symbol{ - {"hello.c", 4, 0, VersionScopeNone, -1, 65521, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 1, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 3, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 4, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 5, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 6, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 8, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 9, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 11, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 13, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 15, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 16, 0, 0, "", ""}, - {"", 3, 0, VersionScopeNone, -1, 14, 0, 0, "", ""}, - {"main", 18, 0, VersionScopeNone, -1, 1, 0, 44, "", ""}, - {"puts", 16, 0, VersionScopeNone, -1, 0, 0, 0, "", ""}, + {"hello.c", 4, 0, false, 0, 65521, 0, 0, "", ""}, + {"", 3, 0, false, 0, 1, 0, 0, "", ""}, + {"", 3, 0, false, 0, 3, 0, 0, "", ""}, + {"", 3, 0, false, 0, 4, 0, 0, "", ""}, + {"", 3, 0, false, 0, 5, 0, 0, "", ""}, + {"", 3, 0, false, 0, 6, 0, 0, "", ""}, + {"", 3, 0, false, 0, 8, 0, 0, "", ""}, + {"", 3, 0, false, 0, 9, 0, 0, "", ""}, + {"", 3, 0, false, 0, 11, 0, 0, "", ""}, + {"", 3, 0, false, 0, 13, 0, 0, "", ""}, + {"", 3, 0, false, 0, 15, 0, 0, "", ""}, + {"", 3, 0, false, 0, 16, 0, 0, "", ""}, + {"", 3, 0, false, 0, 14, 0, 0, "", ""}, + {"main", 18, 0, false, 0, 1, 0, 44, "", ""}, + {"puts", 16, 0, false, 0, 0, 0, 0, "", ""}, }, }, } diff --git a/src/debug/elf/symbols_test.go b/src/debug/elf/symbols_test.go index 8b6dac019b63a1..6053d99acc1a0b 100644 --- a/src/debug/elf/symbols_test.go +++ b/src/debug/elf/symbols_test.go @@ -39,6 +39,19 @@ func TestSymbols(t *testing.T) { if !reflect.DeepEqual(ts, fs) { t.Errorf("%s: Symbols = %v, want %v", file, fs, ts) } + + for i, s := range fs { + if s.HasVersion { + // No hidden versions here. + if s.VersionIndex.IsHidden() { + t.Errorf("%s: symbol %d: unexpected hidden version", file, i) + } + if got, want := s.VersionIndex.Index(), uint16(s.VersionIndex); got != want { + t.Errorf("%s: symbol %d: VersionIndex.Index() == %d, want %d", file, i, got, want) + } + } + } + } for file, ts := range symbolsGolden { do(file, ts, (*File).Symbols) @@ -56,8 +69,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x1, Value: 0x400200, Size: 0x0, @@ -66,8 +79,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x2, Value: 0x40021C, Size: 0x0, @@ -76,8 +89,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x3, Value: 0x400240, Size: 0x0, @@ -86,8 +99,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x4, Value: 0x400268, Size: 0x0, @@ -96,8 +109,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x5, Value: 0x400288, Size: 0x0, @@ -106,8 +119,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x6, Value: 0x4002E8, Size: 0x0, @@ -116,8 +129,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x7, Value: 0x400326, Size: 0x0, @@ -126,8 +139,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x8, Value: 0x400330, Size: 0x0, @@ -136,8 +149,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x9, Value: 0x400350, Size: 0x0, @@ -146,8 +159,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0xA, Value: 0x400368, Size: 0x0, @@ -156,8 +169,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0xB, Value: 0x400398, Size: 0x0, @@ -166,8 +179,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0xC, Value: 0x4003B0, Size: 0x0, @@ -176,8 +189,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0xD, Value: 0x4003E0, Size: 0x0, @@ -186,8 +199,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0xE, Value: 0x400594, Size: 0x0, @@ -196,8 +209,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0xF, Value: 0x4005A4, Size: 0x0, @@ -206,8 +219,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x10, Value: 0x4005B8, Size: 0x0, @@ -216,8 +229,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x11, Value: 0x4005E0, Size: 0x0, @@ -226,8 +239,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x12, Value: 0x600688, Size: 0x0, @@ -236,8 +249,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x13, Value: 0x600698, Size: 0x0, @@ -246,8 +259,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x14, Value: 0x6006A8, Size: 0x0, @@ -256,8 +269,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x15, Value: 0x6006B0, Size: 0x0, @@ -266,8 +279,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x16, Value: 0x600850, Size: 0x0, @@ -276,8 +289,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x17, Value: 0x600858, Size: 0x0, @@ -286,8 +299,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x18, Value: 0x600880, Size: 0x0, @@ -296,8 +309,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x19, Value: 0x600898, Size: 0x0, @@ -306,8 +319,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x1A, Value: 0x0, Size: 0x0, @@ -316,8 +329,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x1B, Value: 0x0, Size: 0x0, @@ -326,8 +339,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x1C, Value: 0x0, Size: 0x0, @@ -336,8 +349,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x1D, Value: 0x0, Size: 0x0, @@ -346,8 +359,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x1E, Value: 0x0, Size: 0x0, @@ -356,8 +369,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x1F, Value: 0x0, Size: 0x0, @@ -366,8 +379,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x20, Value: 0x0, Size: 0x0, @@ -376,8 +389,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x21, Value: 0x0, Size: 0x0, @@ -386,8 +399,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "init.c", Info: 0x4, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0xFFF1, Value: 0x0, Size: 0x0, @@ -396,8 +409,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "initfini.c", Info: 0x4, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0xFFF1, Value: 0x0, Size: 0x0, @@ -406,8 +419,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "call_gmon_start", Info: 0x2, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0xD, Value: 0x40040C, Size: 0x0, @@ -416,8 +429,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "crtstuff.c", Info: 0x4, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0xFFF1, Value: 0x0, Size: 0x0, @@ -426,8 +439,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "__CTOR_LIST__", Info: 0x1, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x12, Value: 0x600688, Size: 0x0, @@ -436,8 +449,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "__DTOR_LIST__", Info: 0x1, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x13, Value: 0x600698, Size: 0x0, @@ -446,8 +459,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "__JCR_LIST__", Info: 0x1, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x14, Value: 0x6006A8, Size: 0x0, @@ -456,8 +469,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "__do_global_dtors_aux", Info: 0x2, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0xD, Value: 0x400430, Size: 0x0, @@ -466,8 +479,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "completed.6183", Info: 0x1, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x19, Value: 0x600898, Size: 0x1, @@ -476,8 +489,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "p.6181", Info: 0x1, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x18, Value: 0x600890, Size: 0x0, @@ -486,8 +499,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "frame_dummy", Info: 0x2, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0xD, Value: 0x400470, Size: 0x0, @@ -496,8 +509,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "crtstuff.c", Info: 0x4, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0xFFF1, Value: 0x0, Size: 0x0, @@ -506,8 +519,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "__CTOR_END__", Info: 0x1, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x12, Value: 0x600690, Size: 0x0, @@ -516,8 +529,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "__DTOR_END__", Info: 0x1, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x13, Value: 0x6006A0, Size: 0x0, @@ -526,8 +539,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "__FRAME_END__", Info: 0x1, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x11, Value: 0x400680, Size: 0x0, @@ -536,8 +549,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "__JCR_END__", Info: 0x1, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x14, Value: 0x6006A8, Size: 0x0, @@ -546,8 +559,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "__do_global_ctors_aux", Info: 0x2, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0xD, Value: 0x400560, Size: 0x0, @@ -556,8 +569,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "initfini.c", Info: 0x4, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0xFFF1, Value: 0x0, Size: 0x0, @@ -566,8 +579,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "hello.c", Info: 0x4, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0xFFF1, Value: 0x0, Size: 0x0, @@ -576,8 +589,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "_GLOBAL_OFFSET_TABLE_", Info: 0x1, Other: 0x2, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x17, Value: 0x600858, Size: 0x0, @@ -586,8 +599,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "__init_array_end", Info: 0x0, Other: 0x2, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x12, Value: 0x600684, Size: 0x0, @@ -596,8 +609,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "__init_array_start", Info: 0x0, Other: 0x2, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x12, Value: 0x600684, Size: 0x0, @@ -606,8 +619,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "_DYNAMIC", Info: 0x1, Other: 0x2, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x15, Value: 0x6006B0, Size: 0x0, @@ -616,8 +629,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "data_start", Info: 0x20, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x18, Value: 0x600880, Size: 0x0, @@ -626,8 +639,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "__libc_csu_fini", Info: 0x12, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0xD, Value: 0x4004C0, Size: 0x2, @@ -636,8 +649,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "_start", Info: 0x12, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0xD, Value: 0x4003E0, Size: 0x0, @@ -646,8 +659,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "__gmon_start__", Info: 0x20, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x0, Value: 0x0, Size: 0x0, @@ -656,8 +669,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "_Jv_RegisterClasses", Info: 0x20, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x0, Value: 0x0, Size: 0x0, @@ -666,8 +679,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "puts@@GLIBC_2.2.5", Info: 0x12, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x0, Value: 0x0, Size: 0x18C, @@ -676,8 +689,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "_fini", Info: 0x12, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0xE, Value: 0x400594, Size: 0x0, @@ -686,8 +699,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "__libc_start_main@@GLIBC_2.2.5", Info: 0x12, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x0, Value: 0x0, Size: 0x1C2, @@ -696,8 +709,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "_IO_stdin_used", Info: 0x11, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0xF, Value: 0x4005A4, Size: 0x4, @@ -706,8 +719,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "__data_start", Info: 0x10, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x18, Value: 0x600880, Size: 0x0, @@ -716,8 +729,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "__dso_handle", Info: 0x11, Other: 0x2, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x18, Value: 0x600888, Size: 0x0, @@ -726,8 +739,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "__libc_csu_init", Info: 0x12, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0xD, Value: 0x4004D0, Size: 0x89, @@ -736,8 +749,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "__bss_start", Info: 0x10, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0xFFF1, Value: 0x600898, Size: 0x0, @@ -746,8 +759,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "_end", Info: 0x10, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0xFFF1, Value: 0x6008A0, Size: 0x0, @@ -756,8 +769,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "_edata", Info: 0x10, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0xFFF1, Value: 0x600898, Size: 0x0, @@ -766,8 +779,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "main", Info: 0x12, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0xD, Value: 0x400498, Size: 0x1B, @@ -776,8 +789,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "_init", Info: 0x12, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0xB, Value: 0x400398, Size: 0x0, @@ -788,8 +801,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "go-relocation-test-clang.c", Info: 0x4, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0xFFF1, Value: 0x0, Size: 0x0, @@ -798,8 +811,8 @@ var symbolsGolden = map[string][]Symbol{ Name: ".Linfo_string0", Info: 0x0, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0xC, Value: 0x0, Size: 0x0, @@ -808,8 +821,8 @@ var symbolsGolden = map[string][]Symbol{ Name: ".Linfo_string1", Info: 0x0, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0xC, Value: 0x2C, Size: 0x0, @@ -818,8 +831,8 @@ var symbolsGolden = map[string][]Symbol{ Name: ".Linfo_string2", Info: 0x0, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0xC, Value: 0x47, Size: 0x0, @@ -828,8 +841,8 @@ var symbolsGolden = map[string][]Symbol{ Name: ".Linfo_string3", Info: 0x0, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0xC, Value: 0x4C, Size: 0x0, @@ -838,8 +851,8 @@ var symbolsGolden = map[string][]Symbol{ Name: ".Linfo_string4", Info: 0x0, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0xC, Value: 0x4E, Size: 0x0, @@ -848,8 +861,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x1, Value: 0x0, Size: 0x0, @@ -858,8 +871,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x2, Value: 0x0, Size: 0x0, @@ -868,8 +881,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x3, Value: 0x0, Size: 0x0, @@ -878,8 +891,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x4, Value: 0x0, Size: 0x0, @@ -888,8 +901,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x6, Value: 0x0, Size: 0x0, @@ -898,8 +911,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x7, Value: 0x0, Size: 0x0, @@ -908,8 +921,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x8, Value: 0x0, Size: 0x0, @@ -918,8 +931,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0xA, Value: 0x0, Size: 0x0, @@ -928,8 +941,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0xC, Value: 0x0, Size: 0x0, @@ -938,8 +951,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0xD, Value: 0x0, Size: 0x0, @@ -948,8 +961,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0xE, Value: 0x0, Size: 0x0, @@ -958,8 +971,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0xF, Value: 0x0, Size: 0x0, @@ -968,8 +981,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "", Info: 0x3, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0x10, Value: 0x0, Size: 0x0, @@ -978,8 +991,8 @@ var symbolsGolden = map[string][]Symbol{ Name: "v", Info: 0x11, Other: 0x0, - VersionScope: VersionScopeNone, - VersionIndex: -1, + HasVersion: false, + VersionIndex: 0, Section: 0xFFF2, Value: 0x4, Size: 0x4, @@ -994,7 +1007,7 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "__gmon_start__", Info: 0x20, Other: 0x0, - VersionScope: VersionScopeLocal, + HasVersion: true, VersionIndex: 0x0, Section: 0x0, Value: 0x0, @@ -1004,7 +1017,7 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "puts", Info: 0x12, Other: 0x0, - VersionScope: VersionScopeSpecific, + HasVersion: true, VersionIndex: 0x2, Section: 0x0, Value: 0x0, @@ -1016,7 +1029,7 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "__libc_start_main", Info: 0x12, Other: 0x0, - VersionScope: VersionScopeSpecific, + HasVersion: true, VersionIndex: 0x2, Section: 0x0, Value: 0x0, @@ -1032,7 +1045,7 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "_ZNSo3putEc", Info: 0x12, Other: 0x0, - VersionScope: VersionScopeSpecific, + HasVersion: true, VersionIndex: 0x3, Section: 0x0, Value: 0x0, @@ -1044,7 +1057,7 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "strchr", Info: 0x12, Other: 0x0, - VersionScope: VersionScopeSpecific, + HasVersion: true, VersionIndex: 0x4, Section: 0x0, Value: 0x0, @@ -1056,7 +1069,7 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "__cxa_finalize", Info: 0x22, Other: 0x0, - VersionScope: VersionScopeSpecific, + HasVersion: true, VersionIndex: 0x4, Section: 0x0, Value: 0x0, @@ -1068,7 +1081,7 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "_ZNSo5tellpEv", Info: 0x12, Other: 0x0, - VersionScope: VersionScopeSpecific, + HasVersion: true, VersionIndex: 0x3, Section: 0x0, Value: 0x0, @@ -1080,7 +1093,7 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "_ZNSo5seekpElSt12_Ios_Seekdir", Info: 0x12, Other: 0x0, - VersionScope: VersionScopeSpecific, + HasVersion: true, VersionIndex: 0x3, Section: 0x0, Value: 0x0, @@ -1092,7 +1105,7 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "_Znwm", Info: 0x12, Other: 0x0, - VersionScope: VersionScopeSpecific, + HasVersion: true, VersionIndex: 0x3, Section: 0x0, Value: 0x0, @@ -1104,7 +1117,7 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "_ZdlPvm", Info: 0x12, Other: 0x0, - VersionScope: VersionScopeSpecific, + HasVersion: true, VersionIndex: 0x5, Section: 0x0, Value: 0x0, @@ -1116,7 +1129,7 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "__stack_chk_fail", Info: 0x12, Other: 0x0, - VersionScope: VersionScopeSpecific, + HasVersion: true, VersionIndex: 0x6, Section: 0x0, Value: 0x0, @@ -1128,7 +1141,7 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "_ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l", Info: 0x12, Other: 0x0, - VersionScope: VersionScopeSpecific, + HasVersion: true, VersionIndex: 0x7, Section: 0x0, Value: 0x0, @@ -1140,7 +1153,7 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "_ZNSo5seekpESt4fposI11__mbstate_tE", Info: 0x12, Other: 0x0, - VersionScope: VersionScopeSpecific, + HasVersion: true, VersionIndex: 0x3, Section: 0x0, Value: 0x0, @@ -1152,7 +1165,7 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "_ZNSi4readEPcl", Info: 0x12, Other: 0x0, - VersionScope: VersionScopeSpecific, + HasVersion: true, VersionIndex: 0x3, Section: 0x0, Value: 0x0, @@ -1164,7 +1177,7 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "_ZNSi5seekgESt4fposI11__mbstate_tE", Info: 0x12, Other: 0x0, - VersionScope: VersionScopeSpecific, + HasVersion: true, VersionIndex: 0x3, Section: 0x0, Value: 0x0, @@ -1176,7 +1189,7 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "_ZNSo5writeEPKcl", Info: 0x12, Other: 0x0, - VersionScope: VersionScopeSpecific, + HasVersion: true, VersionIndex: 0x3, Section: 0x0, Value: 0x0, @@ -1188,7 +1201,7 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "_ZNSi5seekgElSt12_Ios_Seekdir", Info: 0x12, Other: 0x0, - VersionScope: VersionScopeSpecific, + HasVersion: true, VersionIndex: 0x3, Section: 0x0, Value: 0x0, @@ -1200,7 +1213,7 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "_ZSt21ios_base_library_initv", Info: 0x12, Other: 0x0, - VersionScope: VersionScopeSpecific, + HasVersion: true, VersionIndex: 0x8, Section: 0x0, Value: 0x0, @@ -1212,7 +1225,7 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "TIFFClientOpen", Info: 0x12, Other: 0x0, - VersionScope: VersionScopeSpecific, + HasVersion: true, VersionIndex: 0x9, Section: 0x0, Value: 0x0, @@ -1224,7 +1237,7 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "_ZNSt9basic_iosIcSt11char_traitsIcEE5clearESt12_Ios_Iostate", Info: 0x12, Other: 0x0, - VersionScope: VersionScopeSpecific, + HasVersion: true, VersionIndex: 0x3, Section: 0x0, Value: 0x0, @@ -1236,7 +1249,7 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "_ZNSi5tellgEv", Info: 0x12, Other: 0x0, - VersionScope: VersionScopeSpecific, + HasVersion: true, VersionIndex: 0x3, Section: 0x0, Value: 0x0, @@ -1248,7 +1261,7 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "_ITM_deregisterTMCloneTable", Info: 0x20, Other: 0x0, - VersionScope: VersionScopeGlobal, + HasVersion: true, VersionIndex: 0x1, Section: 0x0, Value: 0x0, @@ -1258,7 +1271,7 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "__gmon_start__", Info: 0x20, Other: 0x0, - VersionScope: VersionScopeGlobal, + HasVersion: true, VersionIndex: 0x1, Section: 0x0, Value: 0x0, @@ -1268,7 +1281,7 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "_ITM_registerTMCloneTable", Info: 0x20, Other: 0x0, - VersionScope: VersionScopeGlobal, + HasVersion: true, VersionIndex: 0x1, Section: 0x0, Value: 0x0, @@ -1278,7 +1291,7 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "LIBTIFFXX_4.0", Info: 0x11, Other: 0x0, - VersionScope: VersionScopeSpecific, + HasVersion: true, VersionIndex: 0x2, Section: 0xFFF1, Value: 0x0, @@ -1290,7 +1303,7 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "_Z14TIFFStreamOpenPKcPSo", Info: 0x12, Other: 0x0, - VersionScope: VersionScopeSpecific, + HasVersion: true, VersionIndex: 0x2, Section: 0xF, Value: 0x1860, @@ -1302,7 +1315,7 @@ var dynamicSymbolsGolden = map[string][]Symbol{ Name: "_Z14TIFFStreamOpenPKcPSi", Info: 0x12, Other: 0x0, - VersionScope: VersionScopeSpecific, + HasVersion: true, VersionIndex: 0x2, Section: 0xF, Value: 0x1920, From 971448ddf8c55a5f4a829735a5a96cacf982f230 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 17 Dec 2024 15:31:10 -0800 Subject: [PATCH 047/397] testing: support B.Context and F.Context CL 603959 added T.Context for #36532. The discussion on the proposal only mentions t.Context. However, the implementation of CL 603959 also added B.Context and F.Context. They were added to the API listing, and B.Context was mentioned in the release notes. Unfortunately, the new B.Context and F.Context methods always returned nil, rather than a context.Context value. This change adds a working implementation of B.Context and F.Context. For #36532 Fixes #70866 Change-Id: I8a44e6649fb658e4f641ffb7efd08b4374f578ef Reviewed-on: https://go-review.googlesource.com/c/go/+/637236 LUCI-TryBot-Result: Go LUCI Reviewed-by: David Chase Reviewed-by: Damien Neil --- .../go/testdata/script/test_fuzz_context.txt | 47 ++++++++++++++++++ src/testing/benchmark.go | 4 ++ src/testing/benchmark_test.go | 30 ++++++++++++ src/testing/fuzz.go | 49 ++++++++++++------- src/testing/testing.go | 4 +- 5 files changed, 113 insertions(+), 21 deletions(-) create mode 100644 src/cmd/go/testdata/script/test_fuzz_context.txt diff --git a/src/cmd/go/testdata/script/test_fuzz_context.txt b/src/cmd/go/testdata/script/test_fuzz_context.txt new file mode 100644 index 00000000000000..a830684708e65b --- /dev/null +++ b/src/cmd/go/testdata/script/test_fuzz_context.txt @@ -0,0 +1,47 @@ +[!fuzz] skip +[short] skip +env GOCACHE=$WORK/cache + +# Test fuzz.Context. +go test -vet=off context_fuzz_test.go +stdout ^ok +! stdout FAIL + +go test -vet=off -fuzz=Fuzz -fuzztime=1x context_fuzz_test.go +stdout ok +! stdout FAIL + +-- context_fuzz_test.go -- +package context_fuzz + +import ( + "context" + "errors" + "testing" +) + +func Fuzz(f *testing.F) { + ctx := f.Context() + if err := ctx.Err(); err != nil { + f.Fatalf("expected non-canceled context, got %v", err) + } + + f.Fuzz(func(t *testing.T, data []byte) { + innerCtx := t.Context() + if err := innerCtx.Err(); err != nil { + t.Fatalf("expected inner test to not inherit canceled context, got %v", err) + } + + t.Cleanup(func() { + if !errors.Is(innerCtx.Err(), context.Canceled) { + t.Fatal("expected context of inner test to be canceled after its fuzz function finished") + } + }) + }) + + f.Cleanup(func() { + if !errors.Is(ctx.Err(), context.Canceled) { + f.Fatal("expected context canceled before cleanup") + } + }) +} diff --git a/src/testing/benchmark.go b/src/testing/benchmark.go index 2660c9bba06f3d..3a7da9e54012b7 100644 --- a/src/testing/benchmark.go +++ b/src/testing/benchmark.go @@ -5,6 +5,7 @@ package testing import ( + "context" "flag" "fmt" "internal/sysinfo" @@ -181,6 +182,7 @@ func (b *B) ReportAllocs() { func (b *B) runN(n int) { benchmarkLock.Lock() defer benchmarkLock.Unlock() + ctx, cancelCtx := context.WithCancel(context.Background()) defer func() { b.runCleanup(normalPanic) b.checkRaces() @@ -191,6 +193,8 @@ func (b *B) runN(n int) { b.resetRaces() b.N = n b.loopN = 0 + b.ctx = ctx + b.cancelCtx = cancelCtx b.parallelism = 1 b.ResetTimer() diff --git a/src/testing/benchmark_test.go b/src/testing/benchmark_test.go index a195e4c5766813..e2dd24c839d694 100644 --- a/src/testing/benchmark_test.go +++ b/src/testing/benchmark_test.go @@ -7,6 +7,8 @@ package testing_test import ( "bytes" "cmp" + "context" + "errors" "runtime" "slices" "strings" @@ -127,6 +129,34 @@ func TestRunParallelSkipNow(t *testing.T) { }) } +func TestBenchmarkContext(t *testing.T) { + testing.Benchmark(func(b *testing.B) { + ctx := b.Context() + if err := ctx.Err(); err != nil { + b.Fatalf("expected non-canceled context, got %v", err) + } + + var innerCtx context.Context + b.Run("inner", func(b *testing.B) { + innerCtx = b.Context() + if err := innerCtx.Err(); err != nil { + b.Fatalf("expected inner benchmark to not inherit canceled context, got %v", err) + } + }) + b.Run("inner2", func(b *testing.B) { + if !errors.Is(innerCtx.Err(), context.Canceled) { + t.Fatal("expected context of sibling benchmark to be canceled after its test function finished") + } + }) + + t.Cleanup(func() { + if !errors.Is(ctx.Err(), context.Canceled) { + t.Fatal("expected context canceled before cleanup") + } + }) + }) +} + func ExampleB_RunParallel() { // Parallel benchmark for text/template.Template.Execute on a single object. testing.Benchmark(func(b *testing.B) { diff --git a/src/testing/fuzz.go b/src/testing/fuzz.go index b41a07f88e0863..dceb786ae2829e 100644 --- a/src/testing/fuzz.go +++ b/src/testing/fuzz.go @@ -5,6 +5,7 @@ package testing import ( + "context" "errors" "flag" "fmt" @@ -293,6 +294,8 @@ func (f *F) Fuzz(ff any) { f.tstate.match.clearSubNames() } + ctx, cancelCtx := context.WithCancel(f.ctx) + // Record the stack trace at the point of this call so that if the subtest // function - which runs in a separate stack - is marked as a helper, we can // continue walking the stack into the parent test. @@ -300,13 +303,15 @@ func (f *F) Fuzz(ff any) { n := runtime.Callers(2, pc[:]) t := &T{ common: common{ - barrier: make(chan bool), - signal: make(chan bool), - name: testName, - parent: &f.common, - level: f.level + 1, - creator: pc[:n], - chatty: f.chatty, + barrier: make(chan bool), + signal: make(chan bool), + name: testName, + parent: &f.common, + level: f.level + 1, + creator: pc[:n], + chatty: f.chatty, + ctx: ctx, + cancelCtx: cancelCtx, }, tstate: f.tstate, } @@ -508,14 +513,17 @@ func runFuzzTests(deps testDeps, fuzzTests []InternalFuzzTarget, deadline time.T continue } } + ctx, cancelCtx := context.WithCancel(context.Background()) f := &F{ common: common{ - signal: make(chan bool), - barrier: make(chan bool), - name: testName, - parent: &root, - level: root.level + 1, - chatty: root.chatty, + signal: make(chan bool), + barrier: make(chan bool), + name: testName, + parent: &root, + level: root.level + 1, + chatty: root.chatty, + ctx: ctx, + cancelCtx: cancelCtx, }, tstate: tstate, fstate: fstate, @@ -590,14 +598,17 @@ func runFuzzing(deps testDeps, fuzzTests []InternalFuzzTarget) (ok bool) { return false } + ctx, cancelCtx := context.WithCancel(context.Background()) f := &F{ common: common{ - signal: make(chan bool), - barrier: nil, // T.Parallel has no effect when fuzzing. - name: testName, - parent: &root, - level: root.level + 1, - chatty: root.chatty, + signal: make(chan bool), + barrier: nil, // T.Parallel has no effect when fuzzing. + name: testName, + parent: &root, + level: root.level + 1, + chatty: root.chatty, + ctx: ctx, + cancelCtx: cancelCtx, }, fstate: fstate, tstate: tstate, diff --git a/src/testing/testing.go b/src/testing/testing.go index 8b4bdfbc39828e..be6391b0ab15ce 100644 --- a/src/testing/testing.go +++ b/src/testing/testing.go @@ -1385,10 +1385,10 @@ func (c *common) Chdir(dir string) { } // Context returns a context that is canceled just before -// [T.Cleanup]-registered functions are called. +// Cleanup-registered functions are called. // // Cleanup functions can wait for any resources -// that shut down on Context.Done before the test completes. +// that shut down on Context.Done before the test or benchmark completes. func (c *common) Context() context.Context { c.checkFuzzFn("Context") return c.ctx From 8ff4cee56491eeb3ce146974109cb4893ef5cbd6 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Tue, 17 Dec 2024 19:57:54 +0100 Subject: [PATCH 048/397] cmd/go,crypto: reject using Go+BoringCrypto and fips140 together The combination is untested and nonsensical. Both are solutions to the same problem. For #69536 Change-Id: I95cc3baaf03b64ce08096e304e311a29e9577385 Reviewed-on: https://go-review.googlesource.com/c/go/+/637177 LUCI-TryBot-Result: Go LUCI Reviewed-by: Russ Cox Auto-Submit: Filippo Valsorda Reviewed-by: David Chase --- src/cmd/go/internal/fips140/fips140.go | 4 ++++ src/cmd/go/testdata/script/env_changed.txt | 3 +++ src/cmd/go/testdata/script/fips.txt | 3 +++ src/cmd/go/testdata/script/fipssnap.txt | 3 +++ src/crypto/internal/boring/boring.go | 7 +++++++ src/crypto/internal/fips140test/check_test.go | 5 +++++ 6 files changed, 25 insertions(+) diff --git a/src/cmd/go/internal/fips140/fips140.go b/src/cmd/go/internal/fips140/fips140.go index 7c04a94dd1fea3..1dad8e0bbf96e8 100644 --- a/src/cmd/go/internal/fips140/fips140.go +++ b/src/cmd/go/internal/fips140/fips140.go @@ -119,6 +119,10 @@ func Init() { if Snapshot() { fsys.Bind(Dir(), filepath.Join(cfg.GOROOT, "src/crypto/internal/fips140")) } + + if cfg.Experiment.BoringCrypto && Enabled() { + base.Fatalf("go: cannot use GOFIPS140 with GOEXPERIMENT=boringcrypto") + } } var initDone bool diff --git a/src/cmd/go/testdata/script/env_changed.txt b/src/cmd/go/testdata/script/env_changed.txt index f57f69bfd78ca0..10db7654070615 100644 --- a/src/cmd/go/testdata/script/env_changed.txt +++ b/src/cmd/go/testdata/script/env_changed.txt @@ -1,5 +1,8 @@ # Test query for non-defaults in the env +# Go+BoringCrypto conflicts with GOFIPS140. +[GOEXPERIMENT:boringcrypto] skip + env GOROOT=./a env GOTOOLCHAIN=local env GOSUMDB=nodefault diff --git a/src/cmd/go/testdata/script/fips.txt b/src/cmd/go/testdata/script/fips.txt index fd791d39903e88..fe096ea0c3a2f0 100644 --- a/src/cmd/go/testdata/script/fips.txt +++ b/src/cmd/go/testdata/script/fips.txt @@ -1,3 +1,6 @@ +# Go+BoringCrypto conflicts with GOFIPS140. +[GOEXPERIMENT:boringcrypto] skip + # list with GOFIPS140=off env GOFIPS140=off go list -f '{{.DefaultGODEBUG}}' diff --git a/src/cmd/go/testdata/script/fipssnap.txt b/src/cmd/go/testdata/script/fipssnap.txt index 17a9d647a1845b..0bf46c56e292a4 100644 --- a/src/cmd/go/testdata/script/fipssnap.txt +++ b/src/cmd/go/testdata/script/fipssnap.txt @@ -7,6 +7,9 @@ env alias=inprocess skip 'no snapshots yet' env GOFIPS140=$snap +# Go+BoringCrypto conflicts with GOFIPS140. +[GOEXPERIMENT:boringcrypto] skip + # default GODEBUG includes fips140=on go list -f '{{.DefaultGODEBUG}}' stdout fips140=on diff --git a/src/crypto/internal/boring/boring.go b/src/crypto/internal/boring/boring.go index 90cf1edb75bbad..6dfc6ed5f50207 100644 --- a/src/crypto/internal/boring/boring.go +++ b/src/crypto/internal/boring/boring.go @@ -16,6 +16,7 @@ import "C" import ( "crypto/internal/boring/sig" _ "crypto/internal/boring/syso" + "crypto/internal/fips140" "internal/stringslite" "math/bits" "unsafe" @@ -31,6 +32,12 @@ func init() { sig.BoringCrypto() } +func init() { + if fips140.Enabled { + panic("boringcrypto: cannot use GODEBUG=fips140 with GOEXPERIMENT=boringcrypto") + } +} + // Unreachable marks code that should be unreachable // when BoringCrypto is in use. It panics. func Unreachable() { diff --git a/src/crypto/internal/fips140test/check_test.go b/src/crypto/internal/fips140test/check_test.go index b156de2cbbab6c..cf42dbfa7823f9 100644 --- a/src/crypto/internal/fips140test/check_test.go +++ b/src/crypto/internal/fips140test/check_test.go @@ -5,6 +5,7 @@ package fipstest import ( + "crypto/internal/boring" . "crypto/internal/fips140/check" "crypto/internal/fips140/check/checktest" "fmt" @@ -22,6 +23,10 @@ import ( const enableFIPSTest = true func TestFIPSCheckVerify(t *testing.T) { + if boring.Enabled { + t.Skip("not testing fips140 with boringcrypto enabled") + } + if Verified { t.Logf("verified") return From 10ca5ba4ffecb58028e301904f943a66110966ba Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Tue, 17 Dec 2024 20:39:24 +0100 Subject: [PATCH 049/397] crypto/pbkdf2: update RFC reference in package doc Now that it's published, we don't need to explain how we diverge from the old one. Change-Id: If2c22e89dd1b9fc531a363b5fb7b1eb5720eb84e Reviewed-on: https://go-review.googlesource.com/c/go/+/637215 Auto-Submit: Filippo Valsorda Reviewed-by: Daniel McCarney Reviewed-by: David Chase Reviewed-by: Roland Shoemaker LUCI-TryBot-Result: Go LUCI --- src/crypto/pbkdf2/pbkdf2.go | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/src/crypto/pbkdf2/pbkdf2.go b/src/crypto/pbkdf2/pbkdf2.go index 0fdd9e822d40a5..d40daab5e5b879 100644 --- a/src/crypto/pbkdf2/pbkdf2.go +++ b/src/crypto/pbkdf2/pbkdf2.go @@ -2,20 +2,12 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -/* -Package pbkdf2 implements the key derivation function PBKDF2 as defined in RFC -2898 / PKCS #5 v2.0. - -A key derivation function is useful when encrypting data based on a password -or any other not-fully-random data. It uses a pseudorandom function to derive -a secure encryption key based on the password. - -While v2.0 of the standard defines only one pseudorandom function to use, -HMAC-SHA1, the drafted v2.1 specification allows use of all five FIPS Approved -Hash Functions SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512 for HMAC. To -choose, you can pass the `New` functions from the different SHA packages to -pbkdf2.Key. -*/ +// Package pbkdf2 implements the key derivation function PBKDF2 as defined in +// RFC 8018 (PKCS #5 v2.1). +// +// A key derivation function is useful when encrypting data based on a password +// or any other not-fully-random data. It uses a pseudorandom function to derive +// a secure encryption key based on the password. package pbkdf2 import ( From 6aa46eb75005c87ab4d44d989e1688362991c731 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Tue, 17 Dec 2024 20:47:17 +0100 Subject: [PATCH 050/397] crypto/tls: normalize spelling of "ClientHello" in comments Change-Id: I2b62fb37ae390c42682354eaa2a9d03159563b6d Reviewed-on: https://go-review.googlesource.com/c/go/+/637179 Reviewed-by: Daniel McCarney Reviewed-by: Roland Shoemaker LUCI-TryBot-Result: Go LUCI Auto-Submit: Filippo Valsorda Reviewed-by: David Chase --- src/crypto/tls/common.go | 4 ++-- src/crypto/tls/handshake_client.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/crypto/tls/common.go b/src/crypto/tls/common.go index f98d24b879b889..d6942d2ef14a27 100644 --- a/src/crypto/tls/common.go +++ b/src/crypto/tls/common.go @@ -456,7 +456,7 @@ type ClientHelloInfo struct { SupportedVersions []uint16 // Extensions lists the IDs of the extensions presented by the client - // in the client hello. + // in the ClientHello. Extensions []uint16 // Conn is the underlying net.Conn for the connection. Do not read @@ -821,7 +821,7 @@ type Config struct { // EncryptedClientHelloRejectionVerify, if not nil, is called when ECH is // rejected by the remote server, in order to verify the ECH provider - // certificate in the outer Client Hello. If it returns a non-nil error, the + // certificate in the outer ClientHello. If it returns a non-nil error, the // handshake is aborted and that error results. // // On the server side this field is not used. diff --git a/src/crypto/tls/handshake_client.go b/src/crypto/tls/handshake_client.go index ecc62ff2edefc0..3bf703e4b93b22 100644 --- a/src/crypto/tls/handshake_client.go +++ b/src/crypto/tls/handshake_client.go @@ -944,7 +944,7 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) { } // checkALPN ensure that the server's choice of ALPN protocol is compatible with -// the protocols that we advertised in the Client Hello. +// the protocols that we advertised in the ClientHello. func checkALPN(clientProtos []string, serverProto string, quic bool) error { if serverProto == "" { if quic && len(clientProtos) > 0 { From f4e3ec3dbe3b8e04a058d266adf8e048bab563f2 Mon Sep 17 00:00:00 2001 From: Mauri de Souza Meneguzzo Date: Wed, 18 Dec 2024 16:19:24 +0000 Subject: [PATCH 051/397] crypto/ecdsa: fix condition for fips140=only check Fixes #70894 Change-Id: I78c9f2e46006ffc5f1d2886218f8aaaf3f1b59eb GitHub-Last-Rev: 11f0b452f57aacc40139eab557a8bed1386ad07b GitHub-Pull-Request: golang/go#70904 Reviewed-on: https://go-review.googlesource.com/c/go/+/637455 Reviewed-by: Filippo Valsorda LUCI-TryBot-Result: Go LUCI Reviewed-by: Carlos Amedee Reviewed-by: David Chase --- src/crypto/ecdsa/ecdsa.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crypto/ecdsa/ecdsa.go b/src/crypto/ecdsa/ecdsa.go index 77727aaf96befb..0f9749975ffba9 100644 --- a/src/crypto/ecdsa/ecdsa.go +++ b/src/crypto/ecdsa/ecdsa.go @@ -183,7 +183,7 @@ func GenerateKey(c elliptic.Curve, rand io.Reader) (*PrivateKey, error) { } func generateFIPS[P ecdsa.Point[P]](curve elliptic.Curve, c *ecdsa.Curve[P], rand io.Reader) (*PrivateKey, error) { - if fips140only.Enabled && fips140only.ApprovedRandomReader(rand) { + if fips140only.Enabled && !fips140only.ApprovedRandomReader(rand) { return nil, errors.New("crypto/ecdsa: only crypto/rand.Reader is allowed in FIPS 140-only mode") } privateKey, err := ecdsa.GenerateKey(c, rand) From 87dbfb9fa73c335fd0014445bd34135365c21b84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Bohusl=C3=A1vek?= Date: Wed, 18 Dec 2024 13:32:37 +0100 Subject: [PATCH 052/397] weak: improve grammar in doc comments Change-Id: I577b8a6bf2b7d899cc7ff7211c73549c90db9d94 Reviewed-on: https://go-review.googlesource.com/c/go/+/637355 Reviewed-by: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Auto-Submit: Ian Lance Taylor Reviewed-by: Michael Knyszek --- src/weak/pointer.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/weak/pointer.go b/src/weak/pointer.go index fb10bc2d699ab3..d8be4093492149 100644 --- a/src/weak/pointer.go +++ b/src/weak/pointer.go @@ -13,9 +13,9 @@ import ( // Pointer is a weak pointer to a value of type T. // // Just like regular pointers, Pointer may reference any part of an -// object, such as the field of a struct or an element of an array. +// object, such as a field of a struct or an element of an array. // Objects that are only pointed to by weak pointers are not considered -// reachable and once the object becomes unreachable [Pointer.Value] +// reachable, and once the object becomes unreachable, [Pointer.Value] // may return nil. // // The primary use-cases for weak pointers are for implementing caches, @@ -23,19 +23,19 @@ import ( // the lifetimes of separate values (for example, through a map with weak // keys). // -// Two Pointer values always compare equal if the pointers that they were -// created from compare equal. This property is retained even after the +// Two Pointer values always compare equal if the pointers from which they were +// created compare equal. This property is retained even after the // object referenced by the pointer used to create a weak reference is // reclaimed. -// If multiple weak pointers are made to different offsets within same object +// If multiple weak pointers are made to different offsets within the same object // (for example, pointers to different fields of the same struct), those pointers // will not compare equal. // If a weak pointer is created from an object that becomes unreachable, but is // then resurrected due to a finalizer, that weak pointer will not compare equal -// with weak pointers created after resurrection. +// with weak pointers created after the resurrection. // // Calling [Make] with a nil pointer returns a weak pointer whose [Pointer.Value] -// always returns nil. The zero value of a Pointer behaves as if it was created +// always returns nil. The zero value of a Pointer behaves as if it were created // by passing nil to [Make] and compares equal with such pointers. // // [Pointer.Value] is not guaranteed to eventually return nil. From 4f0561f9d354233787de7aa9eff8119a2d4cd5c6 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Wed, 18 Dec 2024 11:28:18 -0500 Subject: [PATCH 053/397] cmd/dist: skip fips140test in exe mode on Android Android does not support non-PIE linking. Skip the test. Change-Id: I53071538c82f1e1f96eed1a2619f92eacd18d263 Reviewed-on: https://go-review.googlesource.com/c/go/+/637495 Run-TryBot: Cherry Mui LUCI-TryBot-Result: Go LUCI Reviewed-by: Dmitri Shuralyov Reviewed-by: Dmitri Shuralyov TryBot-Result: Gopher Robot --- src/cmd/dist/test.go | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index 5a981f8bc147de..06bd01bc5bb995 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -876,16 +876,18 @@ func (t *tester) registerTests() { } if t.extLink() && !t.compileOnly { - t.registerTest("external linking, -buildmode=exe", - &goTest{ - variant: "exe_external", - timeout: 60 * time.Second, - buildmode: "exe", - ldflags: "-linkmode=external", - env: []string{"CGO_ENABLED=1"}, - pkg: "crypto/internal/fips140test", - runTests: "TestFIPSCheck", - }) + if goos != "android" { // Android does not support non-PIE linking + t.registerTest("external linking, -buildmode=exe", + &goTest{ + variant: "exe_external", + timeout: 60 * time.Second, + buildmode: "exe", + ldflags: "-linkmode=external", + env: []string{"CGO_ENABLED=1"}, + pkg: "crypto/internal/fips140test", + runTests: "TestFIPSCheck", + }) + } if t.externalLinkPIE() && !disablePIE { t.registerTest("external linking, -buildmode=pie", &goTest{ From cb72406c36e5c39c049fd150d65be67372ba60e2 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 18 Dec 2024 15:42:48 -0500 Subject: [PATCH 054/397] cmd/go: fix two-step toolchain upgrade through go install, GOTOOLCHAIN If we do one upgrade because of a go install target's go.mod file, we still might need a second upgrade to implement the GOTOOLCHAIN minimum. Instead of allowing a two-step switch (which we were cutting off anyway), skip the first step and go straight to the GOTOOLCHAIN min upgrade. Fixes #69051. Change-Id: I16f060f473574d8b8f84c55fae2fd0cdabc8aa19 Reviewed-on: https://go-review.googlesource.com/c/go/+/637496 Reviewed-by: Michael Matloob LUCI-TryBot-Result: Go LUCI --- src/cmd/go/internal/toolchain/select.go | 10 +++++++--- src/cmd/go/testdata/script/gotoolchain_local.txt | 11 +++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/cmd/go/internal/toolchain/select.go b/src/cmd/go/internal/toolchain/select.go index cbdd7a2418e1f0..aeab59519c7e6d 100644 --- a/src/cmd/go/internal/toolchain/select.go +++ b/src/cmd/go/internal/toolchain/select.go @@ -169,7 +169,7 @@ func Select() { } gotoolchain = minToolchain - if (mode == "auto" || mode == "path") && !goInstallVersion() { + if (mode == "auto" || mode == "path") && !goInstallVersion(minVers) { // Read go.mod to find new minimum and suggested toolchain. file, goVers, toolchain := modGoToolchain() gover.Startup.AutoFile = file @@ -549,7 +549,7 @@ func modGoToolchain() (file, goVers, toolchain string) { // goInstallVersion reports whether the command line is go install m@v or go run m@v. // If so, Select must not read the go.mod or go.work file in "auto" or "path" mode. -func goInstallVersion() bool { +func goInstallVersion(minVers string) bool { // Note: We assume there are no flags between 'go' and 'install' or 'run'. // During testing there are some debugging flags that are accepted // in that position, but in production go binaries there are not. @@ -708,7 +708,11 @@ func goInstallVersion() bool { if errors.Is(err, gover.ErrTooNew) { // Run early switch, same one go install or go run would eventually do, // if it understood all the command-line flags. - SwitchOrFatal(ctx, err) + var s Switcher + s.Error(err) + if s.TooNew != nil && gover.Compare(s.TooNew.GoVersion, minVers) > 0 { + SwitchOrFatal(ctx, err) + } } return true // pkg@version found diff --git a/src/cmd/go/testdata/script/gotoolchain_local.txt b/src/cmd/go/testdata/script/gotoolchain_local.txt index db7e082db96749..8bece6ebd8439b 100644 --- a/src/cmd/go/testdata/script/gotoolchain_local.txt +++ b/src/cmd/go/testdata/script/gotoolchain_local.txt @@ -197,6 +197,17 @@ go mod edit -go=1.501 -toolchain=none go version stdout go1.501 +# avoid two-step switch, first from install target requirement, then from GOTOOLCHAIN min +# instead, just jump directly to GOTOOLCHAIN min +env TESTGO_VERSION=go1.2.3 +env GODEBUG=toolchaintrace=1 +env GOTOOLCHAIN=go1.23.0+auto +! go install rsc.io/fortune/nonexist@v0.0.1 +! stderr 'switching to go1.22.9' +stderr 'using go1.23.0' +env GODEBUG= +env GOTOOLCHAIN=auto + # go install m@v and go run m@v should ignore go.mod and use m@v env TESTGO_VERSION=go1.2.3 go mod edit -go=1.999 -toolchain=go1.998 From 7b6c94dd037b5d78afca70975109294d7439517c Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 17 Dec 2024 10:40:41 -0500 Subject: [PATCH 055/397] cmd/go: drop fips140 build ID hacks We were trying to keep all binaries stale in fips140 mode so that every build would write and leave behind a fips.o in the work directory for use by validating labs. That breaks various staleness checks, including the one in cmd/dist during GOFIPS140=latest ./make.bash. Revert the fips140 hack. Validating labs will still be able to find the fips.o when building against a clean cache. Add the default godebug to the link hash though, so that it is clear that GOFIPS140=latest and GOFIPS140=off binaries have different hashes. (The only effect is the default GODEBUG setting.) They already had different hashes, because the default GODEBUG ends up in p.Internal.BuildInfo, and that gets hashed in a "modinfo" line, but better to be explicit. Fixes #70873. Change-Id: I49a38c180208098c2b6720facef48f4e96d44c54 Reviewed-on: https://go-review.googlesource.com/c/go/+/637116 Reviewed-by: Michael Matloob Reviewed-by: Filippo Valsorda Reviewed-by: Sam Thanawalla LUCI-TryBot-Result: Go LUCI --- src/cmd/go/internal/fips140/fips140.go | 10 ++-------- src/cmd/go/internal/work/buildid.go | 16 +--------------- src/cmd/go/internal/work/exec.go | 1 + src/cmd/go/testdata/script/fips.txt | 6 ++---- src/cmd/go/testdata/script/fipssnap.txt | 4 ++-- 5 files changed, 8 insertions(+), 29 deletions(-) diff --git a/src/cmd/go/internal/fips140/fips140.go b/src/cmd/go/internal/fips140/fips140.go index 1dad8e0bbf96e8..328e06088e3d47 100644 --- a/src/cmd/go/internal/fips140/fips140.go +++ b/src/cmd/go/internal/fips140/fips140.go @@ -40,14 +40,8 @@ // // GOFIPS140=latest go build -work my/binary // -// will leave fips.o behind in $WORK/b001. Auditors like to be able to -// see that file. Accordingly, when [Enabled] returns true, -// [cmd/go/internal/work.Builder.useCache] arranges never to cache linker -// output, so that the link step always runs, and fips.o is always left -// behind in the link step. If this proves too slow, we could always -// cache fips.o as an extra link output and then restore it when -work is -// set, but we went a very long time never caching link steps at all, so -// not caching them in FIPS mode seems perfectly fine. +// will leave fips.o behind in $WORK/b001 +// (unless the build result is cached, of course). // // When GOFIPS140 is set to something besides off and latest, [Snapshot] // returns true, indicating that the build should replace the latest copy diff --git a/src/cmd/go/internal/work/buildid.go b/src/cmd/go/internal/work/buildid.go index 55b3190300ff60..cab722c28a8396 100644 --- a/src/cmd/go/internal/work/buildid.go +++ b/src/cmd/go/internal/work/buildid.go @@ -15,7 +15,6 @@ import ( "cmd/go/internal/base" "cmd/go/internal/cache" "cmd/go/internal/cfg" - "cmd/go/internal/fips140" "cmd/go/internal/fsys" "cmd/go/internal/str" "cmd/internal/buildid" @@ -447,19 +446,6 @@ func (b *Builder) useCache(a *Action, actionHash cache.ActionID, target string, a.buildID = actionID + buildIDSeparator + mainpkg.buildID + buildIDSeparator + contentID } - // In FIPS mode, we disable any link caching, - // so that we always leave fips.o in $WORK/b001. - // This makes sure that labs validating the FIPS - // implementation can always run 'go build -work' - // and then find fips.o in $WORK/b001/fips.o. - // We could instead also save the fips.o and restore it - // to $WORK/b001 from the cache, - // but we went years without caching binaries anyway, - // so not caching them for FIPS will be fine, at least to start. - if a.Mode == "link" && fips140.Enabled() && a.Package != nil && !strings.HasSuffix(a.Package.ImportPath, ".test") { - return false - } - // If user requested -a, we force a rebuild, so don't use the cache. if cfg.BuildA { if p := a.Package; p != nil && !p.Stale { @@ -519,7 +505,7 @@ func (b *Builder) useCache(a *Action, actionHash cache.ActionID, target string, oldBuildID := a.buildID a.buildID = id[1] + buildIDSeparator + id[2] linkID := buildid.HashToString(b.linkActionID(a.triggers[0])) - if id[0] == linkID && !fips140.Enabled() { + if id[0] == linkID { // Best effort attempt to display output from the compile and link steps. // If it doesn't work, it doesn't work: reusing the cached binary is more // important than reprinting diagnostic information. diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go index 2538fae52f2d8e..7b073165d5fe25 100644 --- a/src/cmd/go/internal/work/exec.go +++ b/src/cmd/go/internal/work/exec.go @@ -1374,6 +1374,7 @@ func (b *Builder) linkActionID(a *Action) cache.ActionID { fmt.Fprintf(h, "buildmode %s goos %s goarch %s\n", cfg.BuildBuildmode, cfg.Goos, cfg.Goarch) fmt.Fprintf(h, "import %q\n", p.ImportPath) fmt.Fprintf(h, "omitdebug %v standard %v local %v prefix %q\n", p.Internal.OmitDebug, p.Standard, p.Internal.Local, p.Internal.LocalPrefix) + fmt.Fprintf(h, "defaultgodebug %q\n", p.DefaultGODEBUG) if cfg.BuildTrimpath { fmt.Fprintln(h, "trimpath") } diff --git a/src/cmd/go/testdata/script/fips.txt b/src/cmd/go/testdata/script/fips.txt index fe096ea0c3a2f0..374902eb702a2e 100644 --- a/src/cmd/go/testdata/script/fips.txt +++ b/src/cmd/go/testdata/script/fips.txt @@ -20,12 +20,12 @@ go build -x -o x.exe go build -x -o x.exe ! stderr link -# build with GOFIPS140=latest is NOT cached (need fipso) +# build with GOFIPS140=latest is cached too env GOFIPS140=latest go build -x -o x.exe stderr link.*-fipso go build -x -o x.exe -stderr link.*-fipso +! stderr link.*-fipso # build test with GOFIPS140=off is cached env GOFIPS140=off @@ -41,8 +41,6 @@ stderr link.*-fipso go test -x -c ! stderr link - - -- go.mod -- module m -- x.go -- diff --git a/src/cmd/go/testdata/script/fipssnap.txt b/src/cmd/go/testdata/script/fipssnap.txt index 0bf46c56e292a4..465f304c46c126 100644 --- a/src/cmd/go/testdata/script/fipssnap.txt +++ b/src/cmd/go/testdata/script/fipssnap.txt @@ -47,11 +47,11 @@ stdout crypto/internal/fips140/$snap/sha256 [short] skip -# build with GOFIPS140=snap is NOT cached (need fipso) +# build with GOFIPS140=snap is cached go build -x -o x.exe stderr link.*-fipso go build -x -o x.exe -stderr link.*-fipso +! stderr link.*-fipso # build test with GOFIPS140=snap is cached go test -x -c From e63eb98e98709a68bf7781a34a3297b72521826e Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 19 Dec 2024 13:35:34 -0500 Subject: [PATCH 056/397] net/http: fix nil panic in test Observed on a builder in an unrelated CL. https://logs.chromium.org/logs/golang/buildbucket/cr-buildbucket/8728107031663629713/+/u/step/11/log/2 goroutine 27937 gp=0xc00000f6c0 m=20 mp=0xc000085008 [running]: panic({0x560ac0?, 0xa1f400?}) C:/b/s/w/ir/x/w/goroot/src/runtime/panic.go:806 +0x168 fp=0xc00043fac8 sp=0xc00043fa18 pc=0xa5f88 testing.tRunner.func1.2({0x560ac0, 0xa1f400}) C:/b/s/w/ir/x/w/goroot/src/testing/testing.go:1734 +0x219 fp=0xc00043fb78 sp=0xc00043fac8 pc=0x1537f9 testing.tRunner.func1() C:/b/s/w/ir/x/w/goroot/src/testing/testing.go:1737 +0x359 fp=0xc00043fce0 sp=0xc00043fb78 pc=0x153259 panic({0x560ac0?, 0xa1f400?}) C:/b/s/w/ir/x/w/goroot/src/runtime/panic.go:787 +0x132 fp=0xc00043fd90 sp=0xc00043fce0 pc=0xa5f52 runtime.panicmem(...) C:/b/s/w/ir/x/w/goroot/src/runtime/panic.go:262 runtime.sigpanic() C:/b/s/w/ir/x/w/goroot/src/runtime/signal_windows.go:401 +0x198 fp=0xc00043fdd8 sp=0xc00043fd90 pc=0x87938 net/http_test.testTransportIdleConnTimeout.func3(...) C:/b/s/w/ir/x/w/goroot/src/net/http/transport_test.go:5503 net/http_test.testTransportIdleConnTimeout(0xc000e83340, {0x5ec863, 0x2}) C:/b/s/w/ir/x/w/goroot/src/net/http/transport_test.go:5522 +0x4c1 fp=0xc00043ff20 sp=0xc00043fdd8 pc=0x47a841 net/http_test.run[...].func1() C:/b/s/w/ir/x/w/goroot/src/net/http/clientserver_test.go:93 +0xfe fp=0xc00043ff70 sp=0xc00043ff20 pc=0x49a21e testing.tRunner(0xc000e83340, 0xc0004687b0) C:/b/s/w/ir/x/w/goroot/src/testing/testing.go:1792 +0xcb fp=0xc00043ffc0 sp=0xc00043ff70 pc=0x152e4b testing.(*T).Run.gowrap1() C:/b/s/w/ir/x/w/goroot/src/testing/testing.go:1851 +0x25 fp=0xc00043ffe0 sp=0xc00043ffc0 pc=0x153e65 runtime.goexit({}) C:/b/s/w/ir/x/w/goroot/src/runtime/asm_amd64.s:1700 +0x1 fp=0xc00043ffe8 sp=0xc00043ffe0 pc=0xadfe1 created by testing.(*T).Run in goroutine 27899 C:/b/s/w/ir/x/w/goroot/src/testing/testing.go:1851 +0x3f6 Change-Id: I3f8bd7c7863b5031ff43d4837dfe11d26ac75652 Reviewed-on: https://go-review.googlesource.com/c/go/+/637897 Reviewed-by: Damien Neil Auto-Submit: Russ Cox LUCI-TryBot-Result: Go LUCI --- src/net/http/transport_test.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go index 2963255b874378..a454db5e034ff0 100644 --- a/src/net/http/transport_test.go +++ b/src/net/http/transport_test.go @@ -5500,7 +5500,9 @@ timeoutLoop: return false } } - res.Body.Close() + if err == nil { + res.Body.Close() + } conns := idleConns() if len(conns) != 1 { if len(conns) == 0 { From 45f49139f5c0c4921239b7f0865c4041e663b1d0 Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Thu, 19 Dec 2024 20:58:19 -0500 Subject: [PATCH 057/397] runtime: test trap panic parsing in TestTracebackSystem This mirrors https://go.dev/cl/637755, as x/telemetry is now aware of sigpanic preceding trap frames. For #70637. Change-Id: I13a775f25e89047702d4f2d463ce3210bcf192d9 Reviewed-on: https://go-review.googlesource.com/c/go/+/638015 Reviewed-by: Cherry Mui LUCI-TryBot-Result: Go LUCI --- src/runtime/crash_test.go | 7 +- src/runtime/traceback_system_test.go | 249 +++++++++++++++++++++------ 2 files changed, 202 insertions(+), 54 deletions(-) diff --git a/src/runtime/crash_test.go b/src/runtime/crash_test.go index 268ddb59c9e4c1..236c32ea34f7de 100644 --- a/src/runtime/crash_test.go +++ b/src/runtime/crash_test.go @@ -32,8 +32,11 @@ const entrypointVar = "RUNTIME_TEST_ENTRYPOINT" func TestMain(m *testing.M) { switch entrypoint := os.Getenv(entrypointVar); entrypoint { - case "crash": - crash() + case "panic": + crashViaPanic() + panic("unreachable") + case "trap": + crashViaTrap() panic("unreachable") default: log.Fatalf("invalid %s: %q", entrypointVar, entrypoint) diff --git a/src/runtime/traceback_system_test.go b/src/runtime/traceback_system_test.go index ece58e806d51c1..af20f54a0946fc 100644 --- a/src/runtime/traceback_system_test.go +++ b/src/runtime/traceback_system_test.go @@ -23,8 +23,8 @@ import ( ) // This is the entrypoint of the child process used by -// TestTracebackSystem. It prints a crash report to stdout. -func crash() { +// TestTracebackSystem/panic. It prints a crash report to stdout. +func crashViaPanic() { // Ensure that we get pc=0x%x values in the traceback. debug.SetTraceback("system") writeSentinel(os.Stdout) @@ -37,6 +37,21 @@ func crash() { select {} } +// This is the entrypoint of the child process used by +// TestTracebackSystem/trap. It prints a crash report to stdout. +func crashViaTrap() { + // Ensure that we get pc=0x%x values in the traceback. + debug.SetTraceback("system") + writeSentinel(os.Stdout) + debug.SetCrashOutput(os.Stdout, debug.CrashOptions{}) + + go func() { + // This call is typically inlined. + trap1() + }() + select {} +} + func child1() { child2() } @@ -85,6 +100,20 @@ func child7() { panic("oops") } +func trap1() { + trap2() +} + +var sinkPtr *int + +func trap2() { + trap3(sinkPtr) +} + +func trap3(i *int) { + *i = 42 +} + // TestTracebackSystem tests that the syntax of crash reports produced // by GOTRACEBACK=system (see traceback2) contains a complete, // parseable list of program counters for the running goroutine that @@ -100,46 +129,75 @@ func TestTracebackSystem(t *testing.T) { t.Skip("Can't read source code for this file on Android") } - // Fork+exec the crashing process. - exe, err := os.Executable() - if err != nil { - t.Fatal(err) - } - cmd := testenv.Command(t, exe) - cmd.Env = append(cmd.Environ(), entrypointVar+"=crash") - var stdout, stderr bytes.Buffer - cmd.Stdout = &stdout - cmd.Stderr = &stderr - cmd.Run() // expected to crash - t.Logf("stderr:\n%s\nstdout: %s\n", stderr.Bytes(), stdout.Bytes()) - crash := stdout.String() - - // If the only line is the sentinel, it wasn't a crash. - if strings.Count(crash, "\n") < 2 { - t.Fatalf("child process did not produce a crash report") + tests := []struct{ + name string + want string + }{ + { + name: "panic", + want: `redacted.go:0: runtime.gopanic +traceback_system_test.go:100: runtime_test.child7: panic("oops") +traceback_system_test.go:83: runtime_test.child6: child7() // appears in stack trace +traceback_system_test.go:74: runtime_test.child5: child6() // appears in stack trace +traceback_system_test.go:68: runtime_test.child4: child5() +traceback_system_test.go:64: runtime_test.child3: child4() +traceback_system_test.go:60: runtime_test.child2: child3() +traceback_system_test.go:56: runtime_test.child1: child2() +traceback_system_test.go:35: runtime_test.crashViaPanic.func1: child1() +redacted.go:0: runtime.goexit +`, + }, + { + // Test panic via trap. x/telemetry is aware that trap + // PCs follow runtime.sigpanic and need to be + // incremented to offset the decrement done by + // CallersFrames. + name: "trap", + want: `redacted.go:0: runtime.gopanic +redacted.go:0: runtime.panicmem +redacted.go:0: runtime.sigpanic +traceback_system_test.go:114: runtime_test.trap3: *i = 42 +traceback_system_test.go:110: runtime_test.trap2: trap3(sinkPtr) +traceback_system_test.go:104: runtime_test.trap1: trap2() +traceback_system_test.go:50: runtime_test.crashViaTrap.func1: trap1() +redacted.go:0: runtime.goexit +`, + }, } - // Parse the PCs out of the child's crash report. - pcs, err := parseStackPCs(crash) - if err != nil { - t.Fatal(err) - } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + // Fork+exec the crashing process. + exe, err := os.Executable() + if err != nil { + t.Fatal(err) + } + cmd := testenv.Command(t, exe) + cmd.Env = append(cmd.Environ(), entrypointVar+"="+tc.name) + var stdout, stderr bytes.Buffer + cmd.Stdout = &stdout + cmd.Stderr = &stderr + cmd.Run() // expected to crash + t.Logf("stderr:\n%s\nstdout: %s\n", stderr.Bytes(), stdout.Bytes()) + crash := stdout.String() + + // If the only line is the sentinel, it wasn't a crash. + if strings.Count(crash, "\n") < 2 { + t.Fatalf("child process did not produce a crash report") + } - // Unwind the stack using this executable's symbol table. - got := formatStack(pcs) - want := `redacted.go:0: runtime.gopanic -traceback_system_test.go:85: runtime_test.child7: panic("oops") -traceback_system_test.go:68: runtime_test.child6: child7() // appears in stack trace -traceback_system_test.go:59: runtime_test.child5: child6() // appears in stack trace -traceback_system_test.go:53: runtime_test.child4: child5() -traceback_system_test.go:49: runtime_test.child3: child4() -traceback_system_test.go:45: runtime_test.child2: child3() -traceback_system_test.go:41: runtime_test.child1: child2() -traceback_system_test.go:35: runtime_test.crash.func1: child1() -redacted.go:0: runtime.goexit -` - if strings.TrimSpace(got) != strings.TrimSpace(want) { - t.Errorf("got:\n%swant:\n%s", got, want) + // Parse the PCs out of the child's crash report. + pcs, err := parseStackPCs(crash) + if err != nil { + t.Fatal(err) + } + + // Unwind the stack using this executable's symbol table. + got := formatStack(pcs) + if strings.TrimSpace(got) != strings.TrimSpace(tc.want) { + t.Errorf("got:\n%swant:\n%s", got, tc.want) + } + }) } } @@ -154,6 +212,35 @@ redacted.go:0: runtime.goexit // // (Copied from golang.org/x/telemetry/crashmonitor.parseStackPCs.) func parseStackPCs(crash string) ([]uintptr, error) { + // getSymbol parses the symbol name out of a line of the form: + // SYMBOL(ARGS) + // + // Note: SYMBOL may contain parens "pkg.(*T).method". However, type + // parameters are always replaced with ..., so they cannot introduce + // more parens. e.g., "pkg.(*T[...]).method". + // + // ARGS can contain parens. We want the first paren that is not + // immediately preceded by a ".". + // + // TODO(prattmic): This is mildly complicated and is only used to find + // runtime.sigpanic, so perhaps simplify this by checking explicitly + // for sigpanic. + getSymbol := func(line string) (string, error) { + var prev rune + for i, c := range line { + if line[i] != '(' { + prev = c + continue + } + if prev == '.' { + prev = c + continue + } + return line[:i], nil + } + return "", fmt.Errorf("no symbol for stack frame: %s", line) + } + // getPC parses the PC out of a line of the form: // \tFILE:LINE +0xRELPC sp=... fp=... pc=... getPC := func(line string) (uint64, error) { @@ -170,6 +257,9 @@ func parseStackPCs(crash string) ([]uintptr, error) { childSentinel = sentinel() on = false // are we in the first running goroutine? lines = strings.Split(crash, "\n") + symLine = true // within a goroutine, every other line is a symbol or file/line/pc location, starting with symbol. + currSymbol string + prevSymbol string // symbol of the most recent previous frame with a PC. ) for i := 0; i < len(lines); i++ { line := lines[i] @@ -212,21 +302,76 @@ func parseStackPCs(crash string) ([]uintptr, error) { // Note: SYMBOL may contain parens "pkg.(*T).method" // The RELPC is sometimes missing. - // Skip the symbol(args) line. - i++ - if i == len(lines) { - break - } - line = lines[i] + if symLine { + var err error + currSymbol, err = getSymbol(line) + if err != nil { + return nil, fmt.Errorf("error extracting symbol: %v", err) + } - // Parse the PC, and correct for the parent and child's - // different mappings of the text section. - pc, err := getPC(line) - if err != nil { - // Inlined frame, perhaps; skip it. - continue + symLine = false // Next line is FILE:LINE. + } else { + // Parse the PC, and correct for the parent and child's + // different mappings of the text section. + pc, err := getPC(line) + if err != nil { + // Inlined frame, perhaps; skip it. + + // Done with this frame. Next line is a new frame. + // + // Don't update prevSymbol; we only want to + // track frames with a PC. + currSymbol = "" + symLine = true + continue + } + + pc = pc-parentSentinel+childSentinel + + // If the previous frame was sigpanic, then this frame + // was a trap (e.g., SIGSEGV). + // + // Typically all middle frames are calls, and report + // the "return PC". That is, the instruction following + // the CALL where the callee will eventually return to. + // + // runtime.CallersFrames is aware of this property and + // will decrement each PC by 1 to "back up" to the + // location of the CALL, which is the actual line + // number the user expects. + // + // This does not work for traps, as a trap is not a + // call, so the reported PC is not the return PC, but + // the actual PC of the trap. + // + // runtime.Callers is aware of this and will + // intentionally increment trap PCs in order to correct + // for the decrement performed by + // runtime.CallersFrames. See runtime.tracebackPCs and + // runtume.(*unwinder).symPC. + // + // We must emulate the same behavior, otherwise we will + // report the location of the instruction immediately + // prior to the trap, which may be on a different line, + // or even a different inlined functions. + // + // TODO(prattmic): The runtime applies the same trap + // behavior for other "injected calls", see injectCall + // in runtime.(*unwinder).next. Do we want to handle + // those as well? I don't believe we'd ever see + // runtime.asyncPreempt or runtime.debugCallV2 in a + // typical crash. + if prevSymbol == "runtime.sigpanic" { + pc++ + } + + pcs = append(pcs, uintptr(pc)) + + // Done with this frame. Next line is a new frame. + prevSymbol = currSymbol + currSymbol = "" + symLine = true } - pcs = append(pcs, uintptr(pc-parentSentinel+childSentinel)) } return pcs, nil } From 669d87a935536eb14cb2db311a83345359189924 Mon Sep 17 00:00:00 2001 From: Cosmos Nicolaou Date: Thu, 19 Dec 2024 15:55:05 -0800 Subject: [PATCH 058/397] runtime/pprof: continued attempt to deflake the VMInfo test. This change catches an additional error message to trigger skipping the test when the underlying system is failing. Fixes #62352 Change-Id: I5c12b20f3e9023597ff89fc905c0646a80ec4811 Reviewed-on: https://go-review.googlesource.com/c/go/+/637995 Reviewed-by: Cherry Mui Auto-Submit: Michael Pratt Reviewed-by: Michael Pratt LUCI-TryBot-Result: Go LUCI --- src/runtime/pprof/vminfo_darwin_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/pprof/vminfo_darwin_test.go b/src/runtime/pprof/vminfo_darwin_test.go index 4c0a0fefd87600..6d375c5d53368a 100644 --- a/src/runtime/pprof/vminfo_darwin_test.go +++ b/src/runtime/pprof/vminfo_darwin_test.go @@ -97,7 +97,7 @@ func useVMMap(t *testing.T) (hi, lo uint64, retryable bool, err error) { t.Logf("vmmap output: %s", out) if ee, ok := cmdErr.(*exec.ExitError); ok && len(ee.Stderr) > 0 { t.Logf("%v: %v\n%s", cmd, cmdErr, ee.Stderr) - if testing.Short() && strings.Contains(string(ee.Stderr), "No process corpse slots currently available, waiting to get one") { + if testing.Short() && (strings.Contains(string(ee.Stderr), "No process corpse slots currently available, waiting to get one") || strings.Contains(string(ee.Stderr), "Failed to generate corpse from the process")) { t.Skipf("Skipping knwn flake in short test mode") } retryable = bytes.Contains(ee.Stderr, []byte("resource shortage")) From 110ab1aaf4b0055027b86ff564b66a47e0f37b58 Mon Sep 17 00:00:00 2001 From: Alan Donovan Date: Fri, 20 Dec 2024 09:28:55 -0500 Subject: [PATCH 059/397] slices: document two oddities Fixes #70935 Change-Id: Idf4a38a05ba595d616b6469a14419ff873bbd354 Reviewed-on: https://go-review.googlesource.com/c/go/+/638095 Reviewed-by: Keith Randall LUCI-TryBot-Result: Go LUCI Reviewed-by: Keith Randall Reviewed-by: Ian Lance Taylor --- src/slices/slices.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/slices/slices.go b/src/slices/slices.go index 40b4d088b06e39..32029cd8ed297c 100644 --- a/src/slices/slices.go +++ b/src/slices/slices.go @@ -414,6 +414,7 @@ func Grow[S ~[]E, E any](s S, n int) S { panic("cannot be negative") } if n -= cap(s) - len(s); n > 0 { + // This expression allocates only once (see test). s = append(s[:cap(s)], make([]E, n)...)[:len(s)] } return s @@ -483,6 +484,9 @@ func Concat[S ~[]E, E any](slices ...S) S { panic("len out of range") } } + // Use Grow, not make, to round up to the size class: + // the extra space is otherwise unused and helps + // callers that append a few elements to the result. newslice := Grow[S](nil, size) for _, s := range slices { newslice = append(newslice, s...) From 06b191e11f6f78b19e5c5a43b3d0c461226c7084 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Sat, 21 Dec 2024 00:07:34 -0500 Subject: [PATCH 060/397] internal/syscall/unix: apply fstatat fix to linux/mips64le Apply CL 633280 to linux/mips64le, as it has the same struct as mips64. Updates #70659. Change-Id: Ibab635e69e44682eb214bf6a00f4cd75816b2d34 Reviewed-on: https://go-review.googlesource.com/c/go/+/637739 TryBot-Result: Gopher Robot Reviewed-by: Ian Lance Taylor Run-TryBot: Cherry Mui LUCI-TryBot-Result: Go LUCI --- src/internal/syscall/unix/at_fstatat.go | 2 +- src/internal/syscall/unix/at_fstatat2.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/internal/syscall/unix/at_fstatat.go b/src/internal/syscall/unix/at_fstatat.go index 217e19a776d2b2..18cd62be203556 100644 --- a/src/internal/syscall/unix/at_fstatat.go +++ b/src/internal/syscall/unix/at_fstatat.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build dragonfly || (linux && !(loong64 || mips64)) || netbsd || (openbsd && mips64) +//go:build dragonfly || (linux && !(loong64 || mips64 || mips64le)) || netbsd || (openbsd && mips64) package unix diff --git a/src/internal/syscall/unix/at_fstatat2.go b/src/internal/syscall/unix/at_fstatat2.go index b18098b7d36eb0..b09aecbcdda4dd 100644 --- a/src/internal/syscall/unix/at_fstatat2.go +++ b/src/internal/syscall/unix/at_fstatat2.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build freebsd || (linux && (loong64 || mips64)) +//go:build freebsd || (linux && (loong64 || mips64 || mips64le)) package unix From 500675a7c8c72bd6b1054a7eb4daaf61970f5ad7 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Sat, 21 Dec 2024 15:54:34 -0500 Subject: [PATCH 061/397] cmd/compile: load map length with the right type len(map) is lowered to loading the first field of the map structure, which is the length. Currently it is a load of an int. With the old map, the first field is indeed an int. With Swiss map, however, it is a uint64. On big-endian 32-bit machine, loading an (32-bit) int from a uint64 would load just the high bits, which are (probably) all 0. Change to a load with the proper type. Fixes #70248. Change-Id: I39cf2d1e6658dac5a8de25c858e1580e2a14b894 Reviewed-on: https://go-review.googlesource.com/c/go/+/638375 Run-TryBot: Cherry Mui LUCI-TryBot-Result: Go LUCI TryBot-Result: Gopher Robot Reviewed-by: Keith Randall Reviewed-by: Keith Randall --- src/cmd/compile/internal/ssagen/ssa.go | 13 +++++++++---- src/internal/runtime/maps/map.go | 1 + 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index dc9b508c01ed12..edd1ffb0c915e8 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -5452,12 +5452,15 @@ func (s *state) referenceTypeBuiltin(n *ir.UnaryExpr, x *ssa.Value) *ssa.Value { if n.X.Type().IsChan() && n.Op() == ir.OCAP { s.Fatalf("cannot inline cap(chan)") // must use runtime.chancap now } + if n.X.Type().IsMap() && n.Op() == ir.OCAP { + s.Fatalf("cannot inline cap(map)") // cap(map) does not exist + } // if n == nil { // return 0 // } else { - // // len - // return *((*int)n) - // // cap + // // len, the actual loadType depends + // return int(*((*loadType)n)) + // // cap (chan only, not used for now) // return *(((*int)n)+1) // } lenType := n.Type() @@ -5485,7 +5488,9 @@ func (s *state) referenceTypeBuiltin(n *ir.UnaryExpr, x *ssa.Value) *ssa.Value { case ir.OLEN: if buildcfg.Experiment.SwissMap && n.X.Type().IsMap() { // length is stored in the first word. - s.vars[n] = s.load(lenType, x) + loadType := reflectdata.SwissMapType().Field(0).Type // uint64 + load := s.load(loadType, x) + s.vars[n] = s.conv(nil, load, loadType, lenType) // integer conversion doesn't need Node } else { // length is stored in the first word for map/chan s.vars[n] = s.load(lenType, x) diff --git a/src/internal/runtime/maps/map.go b/src/internal/runtime/maps/map.go index ffafcacdea1bc7..62463351c7d2de 100644 --- a/src/internal/runtime/maps/map.go +++ b/src/internal/runtime/maps/map.go @@ -194,6 +194,7 @@ func h2(h uintptr) uintptr { type Map struct { // The number of filled slots (i.e. the number of elements in all // tables). Excludes deleted slots. + // Must be first (known by the compiler, for len() builtin). used uint64 // seed is the hash seed, computed as a unique random number per map. From 05d8984781f7cf2f0f39b53699a558b6a1965c6c Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 22 Dec 2024 23:51:26 +0000 Subject: [PATCH 062/397] net: document LookupTXT behavior with multiple strings per record CL 8966 ("net: allow a dns TXT record to contain more than one ") concatenates strings in a TXT record. Document that behavior, since it's not obvious whether the strings will be concatenated or accumulated in the returned slice. Change-Id: I6acb27b296290361a95a6058a056f8e7c2df9a2b GitHub-Last-Rev: ec0726c7b83a56773d0ac4a86cbfc89c6f4884c9 GitHub-Pull-Request: golang/go#65233 Reviewed-on: https://go-review.googlesource.com/c/go/+/557695 Auto-Submit: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Reviewed-by: Damien Neil Reviewed-by: Ian Lance Taylor --- src/net/lookup.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/net/lookup.go b/src/net/lookup.go index b04dfa23b9877b..f94fd8cefaab18 100644 --- a/src/net/lookup.go +++ b/src/net/lookup.go @@ -614,6 +614,9 @@ func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) { // LookupTXT returns the DNS TXT records for the given domain name. // +// If a DNS TXT record holds multiple strings, they are concatenated as a +// single string. +// // LookupTXT uses [context.Background] internally; to specify the context, use // [Resolver.LookupTXT]. func LookupTXT(name string) ([]string, error) { @@ -621,6 +624,9 @@ func LookupTXT(name string) ([]string, error) { } // LookupTXT returns the DNS TXT records for the given domain name. +// +// If a DNS TXT record holds multiple strings, they are concatenated as a +// single string. func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, error) { return r.lookupTXT(ctx, name) } From 9f6c80a76ad56f653b743fe2df3f2296210c90d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20T=C3=B4rres?= Date: Fri, 20 Dec 2024 06:45:52 +0000 Subject: [PATCH 063/397] cmd/go/internal/work: allow single character values in -Wl, linker flags Allow single character values in -Wl, linker flags by modifying the regular expressions to use the star operator instead of the plus operator. Fixes #70924 Change-Id: Ie7940197cc8503440a87c6b29409a13377a20534 GitHub-Last-Rev: 42e8ac87d600239ceff434eb202e2747f2cceb3c GitHub-Pull-Request: golang/go#70937 Reviewed-on: https://go-review.googlesource.com/c/go/+/638035 Auto-Submit: Ian Lance Taylor Reviewed-by: David Chase LUCI-TryBot-Result: Go LUCI Reviewed-by: Ian Lance Taylor --- src/cmd/go/internal/work/security.go | 12 ++++++------ src/cmd/go/internal/work/security_test.go | 7 +++++++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/cmd/go/internal/work/security.go b/src/cmd/go/internal/work/security.go index 1e2f81b2d4d23e..50bfd0ab705383 100644 --- a/src/cmd/go/internal/work/security.go +++ b/src/cmd/go/internal/work/security.go @@ -201,23 +201,23 @@ var validLinkerFlags = []*lazyregexp.Regexp{ re(`-Wl,--end-group`), re(`-Wl,--(no-)?export-dynamic`), re(`-Wl,-E`), - re(`-Wl,-framework,[^,@\-][^,]+`), + re(`-Wl,-framework,[^,@\-][^,]*`), re(`-Wl,--hash-style=(sysv|gnu|both)`), re(`-Wl,-headerpad_max_install_names`), re(`-Wl,--no-undefined`), re(`-Wl,--pop-state`), re(`-Wl,--push-state`), re(`-Wl,-R,?([^@\-,][^,@]*$)`), - re(`-Wl,--just-symbols[=,]([^,@\-][^,@]+)`), - re(`-Wl,-rpath(-link)?[=,]([^,@\-][^,]+)`), + re(`-Wl,--just-symbols[=,]([^,@\-][^,@]*)`), + re(`-Wl,-rpath(-link)?[=,]([^,@\-][^,]*)`), re(`-Wl,-s`), re(`-Wl,-search_paths_first`), - re(`-Wl,-sectcreate,([^,@\-][^,]+),([^,@\-][^,]+),([^,@\-][^,]+)`), + re(`-Wl,-sectcreate,([^,@\-][^,]*),([^,@\-][^,]*),([^,@\-][^,]*)`), re(`-Wl,--start-group`), re(`-Wl,-?-static`), re(`-Wl,-?-subsystem,(native|windows|console|posix|xbox)`), - re(`-Wl,-syslibroot[=,]([^,@\-][^,]+)`), - re(`-Wl,-undefined[=,]([^,@\-][^,]+)`), + re(`-Wl,-syslibroot[=,]([^,@\-][^,]*)`), + re(`-Wl,-undefined[=,]([^,@\-][^,]*)`), re(`-Wl,-?-unresolved-symbols=[^,]+`), re(`-Wl,--(no-)?warn-([^,]+)`), re(`-Wl,-?-wrap[=,][^,@\-][^,]*`), diff --git a/src/cmd/go/internal/work/security_test.go b/src/cmd/go/internal/work/security_test.go index 63dd569f7d3964..35af62176472b4 100644 --- a/src/cmd/go/internal/work/security_test.go +++ b/src/cmd/go/internal/work/security_test.go @@ -182,6 +182,13 @@ var goodLinkerFlags = [][]string{ {"-Wl,--pop-state"}, {"-Wl,--push-state,--as-needed"}, {"-Wl,--push-state,--no-as-needed,-Bstatic"}, + {"-Wl,--just-symbols,."}, + {"-Wl,-framework,."}, + {"-Wl,-rpath,."}, + {"-Wl,-rpath-link,."}, + {"-Wl,-sectcreate,.,.,."}, + {"-Wl,-syslibroot,."}, + {"-Wl,-undefined,."}, } var badLinkerFlags = [][]string{ From eef35e3bd989afcbf4141a570d933ff05b866504 Mon Sep 17 00:00:00 2001 From: Jorropo Date: Sat, 21 Dec 2024 20:32:42 +0100 Subject: [PATCH 064/397] internal/goexperiment: run go generate for synctest Updates #70954 Change-Id: If5f9c8b8b820b1cc4e41e76b50038c6155b575a8 Reviewed-on: https://go-review.googlesource.com/c/go/+/638355 Reviewed-by: David Chase LUCI-TryBot-Result: Go LUCI Reviewed-by: Michael Pratt --- src/internal/goexperiment/exp_synctest_off.go | 8 ++++++++ src/internal/goexperiment/exp_synctest_on.go | 8 ++++++++ 2 files changed, 16 insertions(+) create mode 100644 src/internal/goexperiment/exp_synctest_off.go create mode 100644 src/internal/goexperiment/exp_synctest_on.go diff --git a/src/internal/goexperiment/exp_synctest_off.go b/src/internal/goexperiment/exp_synctest_off.go new file mode 100644 index 00000000000000..fade13f89ca79c --- /dev/null +++ b/src/internal/goexperiment/exp_synctest_off.go @@ -0,0 +1,8 @@ +// Code generated by mkconsts.go. DO NOT EDIT. + +//go:build !goexperiment.synctest + +package goexperiment + +const Synctest = false +const SynctestInt = 0 diff --git a/src/internal/goexperiment/exp_synctest_on.go b/src/internal/goexperiment/exp_synctest_on.go new file mode 100644 index 00000000000000..9c44be7276138b --- /dev/null +++ b/src/internal/goexperiment/exp_synctest_on.go @@ -0,0 +1,8 @@ +// Code generated by mkconsts.go. DO NOT EDIT. + +//go:build goexperiment.synctest + +package goexperiment + +const Synctest = true +const SynctestInt = 1 From b9955f0ad952a22388eead15e3d15610a29e03a0 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Fri, 20 Dec 2024 22:33:15 -0500 Subject: [PATCH 065/397] cmd/link, runtime: apply a delta to RODATA->DATA relocations On AIX, an R_ADDR relocation from an RODATA symbol to a DATA symbol does not work, as the dynamic loader can change the address of the data section, and it is not possible to apply a dynamic relocation to RODATA. In order to get the correct address, we apply the delta between unrelocated and relocated data section addresses at run time. The linker saves both the unrelocated and the relocated addresses, so we can compute the delta. This is possible because RODATA symbols are generated by the compiler and so we have full control of. On AIX, the only case is the on-demand GC pointer masks from the type descriptors, for very large types. Perhaps there is a better way. Fixes #70483. Change-Id: I2664c0a813b38f7b146794cb1e73ccf5e238ca65 Reviewed-on: https://go-review.googlesource.com/c/go/+/638016 Reviewed-by: Keith Randall Reviewed-by: Keith Randall LUCI-TryBot-Result: Go LUCI --- src/cmd/link/internal/ld/data.go | 3 +++ src/cmd/link/internal/ld/symtab.go | 11 +++++++++++ src/runtime/symtab.go | 12 ++++++++++++ src/runtime/type.go | 4 ++++ 4 files changed, 30 insertions(+) diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index 5c4497cdd75b0f..a6b94a829f1442 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -424,6 +424,9 @@ func (st *relocSymState) relocsym(s loader.Sym, P []byte) { // FIXME: It should be forbidden to have R_ADDR from a // symbol which isn't in .data. However, as .text has the // same address once loaded, this is possible. + // TODO: .text (including rodata) to .data relocation + // doesn't work correctly, so we should really disallow it. + // See also aixStaticDataBase in symtab.go and in runtime. if ldr.SymSect(s).Seg == &Segdata { Xcoffadddynrel(target, ldr, syms, s, r, ri) } diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go index 8156f83a7a3267..b89a7802a2c62a 100644 --- a/src/cmd/link/internal/ld/symtab.go +++ b/src/cmd/link/internal/ld/symtab.go @@ -707,6 +707,17 @@ func (ctxt *Link) symtab(pcln *pclntab) []sym.SymKind { // except go:buildid which is generated late and not used by the program. addRef("go:buildid") } + if ctxt.IsAIX() { + // On AIX, an R_ADDR relocation from an RODATA symbol to a DATA symbol + // does not work. See data.go:relocsym, case R_ADDR. + // Here we record the unrelocated address in aixStaticDataBase (it is + // unrelocated as it is in RODATA) so we can compute the delta at + // run time. + sb := ldr.CreateSymForUpdate("runtime.aixStaticDataBase", 0) + sb.SetSize(0) + sb.AddAddr(ctxt.Arch, ldr.Lookup("runtime.data", 0)) + sb.SetType(sym.SRODATA) + } // text section information slice(textsectionmapSym, uint64(nsections)) diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go index c78b044264742d..c3bd5103205cf6 100644 --- a/src/runtime/symtab.go +++ b/src/runtime/symtab.go @@ -468,6 +468,18 @@ type modulehash struct { // To make sure the map isn't collected, we keep a second reference here. var pinnedTypemaps []map[typeOff]*_type +// aixStaticDataBase (used only on AIX) holds the unrelocated address +// of the data section, set by the linker. +// +// On AIX, an R_ADDR relocation from an RODATA symbol to a DATA symbol +// does not work, as the dynamic loader can change the address of the +// data section, and it is not possible to apply a dynamic relocation +// to RODATA. In order to get the correct address, we need to apply +// the delta between unrelocated and relocated data section addresses. +// aixStaticDataBase is the unrelocated address, and moduledata.data is +// the relocated one. +var aixStaticDataBase uintptr // linker symbol + var firstmoduledata moduledata // linker symbol var lastmoduledatap *moduledata // linker symbol diff --git a/src/runtime/type.go b/src/runtime/type.go index 9702164b1a261a..1edf9c9dd6d85c 100644 --- a/src/runtime/type.go +++ b/src/runtime/type.go @@ -104,6 +104,10 @@ func getGCMaskOnDemand(t *_type) *byte { // in read-only memory currently. addr := unsafe.Pointer(t.GCData) + if GOOS == "aix" { + addr = add(addr, firstmoduledata.data-aixStaticDataBase) + } + for { p := (*byte)(atomic.Loadp(addr)) switch p { From 772f024c615ec13c6cd28bf024e9d6be852201b6 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Mon, 23 Dec 2024 20:42:42 +0000 Subject: [PATCH 066/397] weak: fix typo in warning about tiny allocator optimization Fixes #70972. Change-Id: Ib04c2a3129a1da651a0b4674b372aec73966115a Reviewed-on: https://go-review.googlesource.com/c/go/+/638377 LUCI-TryBot-Result: Go LUCI Reviewed-by: Ian Lance Taylor --- src/weak/pointer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/weak/pointer.go b/src/weak/pointer.go index d8be4093492149..50af0c2fdc0a16 100644 --- a/src/weak/pointer.go +++ b/src/weak/pointer.go @@ -52,7 +52,7 @@ import ( // nil, even after an object is no longer referenced, the runtime is allowed to // perform a space-saving optimization that batches objects together in a single // allocation slot. The weak pointer for an unreferenced object in such an -// allocation may never be called if it always exists in the same batch as a +// allocation may never become nil if it always exists in the same batch as a // referenced object. Typically, this batching only happens for tiny // (on the order of 16 bytes or less) and pointer-free objects. type Pointer[T any] struct { From cce75da30b6a1a58f7265401279cab707d403dcf Mon Sep 17 00:00:00 2001 From: Alec Bakholdin Date: Sun, 22 Dec 2024 20:36:59 -0500 Subject: [PATCH 067/397] crypto/mlkem: swap order of return values of Encapsulate Per FIPS 203 (https://csrc.nist.gov/pubs/fips/203/final), the order of return values should be sharedKey, ciphertext. This commit simply swaps those return values and updates any consumers of the Encapsulate() method to respect the new order. Fixes #70950 Change-Id: I2a0d605e3baf7fe69510d60d3d35bbac18f883c9 Reviewed-on: https://go-review.googlesource.com/c/go/+/638376 LUCI-TryBot-Result: Go LUCI Reviewed-by: Austin Clements Auto-Submit: Ian Lance Taylor Reviewed-by: Filippo Valsorda Reviewed-by: Cherry Mui --- src/crypto/internal/fips140/mlkem/cast.go | 2 +- src/crypto/internal/fips140/mlkem/mlkem1024.go | 12 ++++++------ src/crypto/internal/fips140/mlkem/mlkem768.go | 12 ++++++------ src/crypto/mlkem/mlkem1024.go | 2 +- src/crypto/mlkem/mlkem768.go | 2 +- src/crypto/mlkem/mlkem_test.go | 18 +++++++++--------- src/crypto/tls/handshake_server_tls13.go | 2 +- 7 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/crypto/internal/fips140/mlkem/cast.go b/src/crypto/internal/fips140/mlkem/cast.go index d3ae84ec3f1122..a432d1fdab0e2b 100644 --- a/src/crypto/internal/fips140/mlkem/cast.go +++ b/src/crypto/internal/fips140/mlkem/cast.go @@ -40,7 +40,7 @@ func init() { dk := &DecapsulationKey768{} kemKeyGen(dk, d, z) ek := dk.EncapsulationKey() - c, Ke := ek.EncapsulateInternal(m) + Ke, c := ek.EncapsulateInternal(m) Kd, err := dk.Decapsulate(c) if err != nil { return err diff --git a/src/crypto/internal/fips140/mlkem/mlkem1024.go b/src/crypto/internal/fips140/mlkem/mlkem1024.go index 5aa3c69243b346..c924c382933c5f 100644 --- a/src/crypto/internal/fips140/mlkem/mlkem1024.go +++ b/src/crypto/internal/fips140/mlkem/mlkem1024.go @@ -189,7 +189,7 @@ func kemKeyGen1024(dk *DecapsulationKey1024, d, z *[32]byte) { // the first operational use (if not exported before the first use)." func kemPCT1024(dk *DecapsulationKey1024) error { ek := dk.EncapsulationKey() - c, K := ek.Encapsulate() + K, c := ek.Encapsulate() K1, err := dk.Decapsulate(c) if err != nil { return err @@ -204,13 +204,13 @@ func kemPCT1024(dk *DecapsulationKey1024) error { // encapsulation key, drawing random bytes from a DRBG. // // The shared key must be kept secret. -func (ek *EncapsulationKey1024) Encapsulate() (ciphertext, sharedKey []byte) { +func (ek *EncapsulationKey1024) Encapsulate() (sharedKey, ciphertext []byte) { // The actual logic is in a separate function to outline this allocation. var cc [CiphertextSize1024]byte return ek.encapsulate(&cc) } -func (ek *EncapsulationKey1024) encapsulate(cc *[CiphertextSize1024]byte) (ciphertext, sharedKey []byte) { +func (ek *EncapsulationKey1024) encapsulate(cc *[CiphertextSize1024]byte) (sharedKey, ciphertext []byte) { var m [messageSize]byte drbg.Read(m[:]) // Note that the modulus check (step 2 of the encapsulation key check from @@ -221,7 +221,7 @@ func (ek *EncapsulationKey1024) encapsulate(cc *[CiphertextSize1024]byte) (ciphe // EncapsulateInternal is a derandomized version of Encapsulate, exclusively for // use in tests. -func (ek *EncapsulationKey1024) EncapsulateInternal(m *[32]byte) (ciphertext, sharedKey []byte) { +func (ek *EncapsulationKey1024) EncapsulateInternal(m *[32]byte) (sharedKey, ciphertext []byte) { cc := &[CiphertextSize1024]byte{} return kemEncaps1024(cc, ek, m) } @@ -229,14 +229,14 @@ func (ek *EncapsulationKey1024) EncapsulateInternal(m *[32]byte) (ciphertext, sh // kemEncaps1024 generates a shared key and an associated ciphertext. // // It implements ML-KEM.Encaps_internal according to FIPS 203, Algorithm 17. -func kemEncaps1024(cc *[CiphertextSize1024]byte, ek *EncapsulationKey1024, m *[messageSize]byte) (c, K []byte) { +func kemEncaps1024(cc *[CiphertextSize1024]byte, ek *EncapsulationKey1024, m *[messageSize]byte) (K, c []byte) { g := sha3.New512() g.Write(m[:]) g.Write(ek.h[:]) G := g.Sum(nil) K, r := G[:SharedKeySize], G[SharedKeySize:] c = pkeEncrypt1024(cc, &ek.encryptionKey1024, m, r) - return c, K + return K, c } // NewEncapsulationKey1024 parses an encapsulation key from its encoded form. diff --git a/src/crypto/internal/fips140/mlkem/mlkem768.go b/src/crypto/internal/fips140/mlkem/mlkem768.go index 0c91ceadc4284e..2c1cb5c33fcdd1 100644 --- a/src/crypto/internal/fips140/mlkem/mlkem768.go +++ b/src/crypto/internal/fips140/mlkem/mlkem768.go @@ -246,7 +246,7 @@ func kemKeyGen(dk *DecapsulationKey768, d, z *[32]byte) { // the first operational use (if not exported before the first use)." func kemPCT(dk *DecapsulationKey768) error { ek := dk.EncapsulationKey() - c, K := ek.Encapsulate() + K, c := ek.Encapsulate() K1, err := dk.Decapsulate(c) if err != nil { return err @@ -261,13 +261,13 @@ func kemPCT(dk *DecapsulationKey768) error { // encapsulation key, drawing random bytes from a DRBG. // // The shared key must be kept secret. -func (ek *EncapsulationKey768) Encapsulate() (ciphertext, sharedKey []byte) { +func (ek *EncapsulationKey768) Encapsulate() (sharedKey, ciphertext []byte) { // The actual logic is in a separate function to outline this allocation. var cc [CiphertextSize768]byte return ek.encapsulate(&cc) } -func (ek *EncapsulationKey768) encapsulate(cc *[CiphertextSize768]byte) (ciphertext, sharedKey []byte) { +func (ek *EncapsulationKey768) encapsulate(cc *[CiphertextSize768]byte) (sharedKey, ciphertext []byte) { var m [messageSize]byte drbg.Read(m[:]) // Note that the modulus check (step 2 of the encapsulation key check from @@ -278,7 +278,7 @@ func (ek *EncapsulationKey768) encapsulate(cc *[CiphertextSize768]byte) (ciphert // EncapsulateInternal is a derandomized version of Encapsulate, exclusively for // use in tests. -func (ek *EncapsulationKey768) EncapsulateInternal(m *[32]byte) (ciphertext, sharedKey []byte) { +func (ek *EncapsulationKey768) EncapsulateInternal(m *[32]byte) (sharedKey, ciphertext []byte) { cc := &[CiphertextSize768]byte{} return kemEncaps(cc, ek, m) } @@ -286,14 +286,14 @@ func (ek *EncapsulationKey768) EncapsulateInternal(m *[32]byte) (ciphertext, sha // kemEncaps generates a shared key and an associated ciphertext. // // It implements ML-KEM.Encaps_internal according to FIPS 203, Algorithm 17. -func kemEncaps(cc *[CiphertextSize768]byte, ek *EncapsulationKey768, m *[messageSize]byte) (c, K []byte) { +func kemEncaps(cc *[CiphertextSize768]byte, ek *EncapsulationKey768, m *[messageSize]byte) (K, c []byte) { g := sha3.New512() g.Write(m[:]) g.Write(ek.h[:]) G := g.Sum(nil) K, r := G[:SharedKeySize], G[SharedKeySize:] c = pkeEncrypt(cc, &ek.encryptionKey, m, r) - return c, K + return K, c } // NewEncapsulationKey768 parses an encapsulation key from its encoded form. diff --git a/src/crypto/mlkem/mlkem1024.go b/src/crypto/mlkem/mlkem1024.go index 530aacf00ff716..05bad1eb2aa42c 100644 --- a/src/crypto/mlkem/mlkem1024.go +++ b/src/crypto/mlkem/mlkem1024.go @@ -91,6 +91,6 @@ func (ek *EncapsulationKey1024) Bytes() []byte { // encapsulation key, drawing random bytes from crypto/rand. // // The shared key must be kept secret. -func (ek *EncapsulationKey1024) Encapsulate() (ciphertext, sharedKey []byte) { +func (ek *EncapsulationKey1024) Encapsulate() (sharedKey, ciphertext []byte) { return ek.key.Encapsulate() } diff --git a/src/crypto/mlkem/mlkem768.go b/src/crypto/mlkem/mlkem768.go index d6f5c94171e947..c367c551e6fc02 100644 --- a/src/crypto/mlkem/mlkem768.go +++ b/src/crypto/mlkem/mlkem768.go @@ -101,6 +101,6 @@ func (ek *EncapsulationKey768) Bytes() []byte { // encapsulation key, drawing random bytes from crypto/rand. // // The shared key must be kept secret. -func (ek *EncapsulationKey768) Encapsulate() (ciphertext, sharedKey []byte) { +func (ek *EncapsulationKey768) Encapsulate() (sharedKey, ciphertext []byte) { return ek.key.Encapsulate() } diff --git a/src/crypto/mlkem/mlkem_test.go b/src/crypto/mlkem/mlkem_test.go index ddc52dab975d32..207d6d48c3cb0b 100644 --- a/src/crypto/mlkem/mlkem_test.go +++ b/src/crypto/mlkem/mlkem_test.go @@ -43,7 +43,7 @@ func testRoundTrip[E encapsulationKey, D decapsulationKey[E]]( t.Fatal(err) } ek := dk.EncapsulationKey() - c, Ke := ek.Encapsulate() + Ke, c := ek.Encapsulate() Kd, err := dk.Decapsulate(c) if err != nil { t.Fatal(err) @@ -66,7 +66,7 @@ func testRoundTrip[E encapsulationKey, D decapsulationKey[E]]( if !bytes.Equal(dk.Bytes(), dk1.Bytes()) { t.Fail() } - c1, Ke1 := ek1.Encapsulate() + Ke1, c1 := ek1.Encapsulate() Kd1, err := dk1.Decapsulate(c1) if err != nil { t.Fatal(err) @@ -86,7 +86,7 @@ func testRoundTrip[E encapsulationKey, D decapsulationKey[E]]( t.Fail() } - c2, Ke2 := dk.EncapsulationKey().Encapsulate() + Ke2, c2 := dk.EncapsulationKey().Encapsulate() if bytes.Equal(c, c2) { t.Fail() } @@ -115,7 +115,7 @@ func testBadLengths[E encapsulationKey, D decapsulationKey[E]]( } ek := dk.EncapsulationKey() ekBytes := dk.EncapsulationKey().Bytes() - c, _ := ek.Encapsulate() + _, c := ek.Encapsulate() for i := 0; i < len(dkBytes)-1; i++ { if _, err := newDecapsulationKey(dkBytes[:i]); err == nil { @@ -189,7 +189,7 @@ func TestAccumulated(t *testing.T) { o.Write(ek.Bytes()) s.Read(msg[:]) - ct, k := ek.key.EncapsulateInternal(&msg) + k, ct := ek.key.EncapsulateInternal(&msg) o.Write(ct) o.Write(k) @@ -244,7 +244,7 @@ func BenchmarkEncaps(b *testing.B) { if err != nil { b.Fatal(err) } - c, K := ek.key.EncapsulateInternal(&m) + K, c := ek.key.EncapsulateInternal(&m) sink ^= c[0] ^ K[0] } } @@ -255,7 +255,7 @@ func BenchmarkDecaps(b *testing.B) { b.Fatal(err) } ek := dk.EncapsulationKey() - c, _ := ek.Encapsulate() + _, c := ek.Encapsulate() b.ResetTimer() for i := 0; i < b.N; i++ { K, _ := dk.Decapsulate(c) @@ -270,7 +270,7 @@ func BenchmarkRoundTrip(b *testing.B) { } ek := dk.EncapsulationKey() ekBytes := ek.Bytes() - c, _ := ek.Encapsulate() + _, c := ek.Encapsulate() if err != nil { b.Fatal(err) } @@ -296,7 +296,7 @@ func BenchmarkRoundTrip(b *testing.B) { if err != nil { b.Fatal(err) } - cS, Ks := ek.Encapsulate() + Ks, cS := ek.Encapsulate() if err != nil { b.Fatal(err) } diff --git a/src/crypto/tls/handshake_server_tls13.go b/src/crypto/tls/handshake_server_tls13.go index 3552d89ba3bc6f..76fff6974e7403 100644 --- a/src/crypto/tls/handshake_server_tls13.go +++ b/src/crypto/tls/handshake_server_tls13.go @@ -280,7 +280,7 @@ func (hs *serverHandshakeStateTLS13) processClientHello() error { c.sendAlert(alertIllegalParameter) return errors.New("tls: invalid X25519MLKEM768 client key share") } - ciphertext, mlkemSharedSecret := k.Encapsulate() + mlkemSharedSecret, ciphertext := k.Encapsulate() // draft-kwiatkowski-tls-ecdhe-mlkem-02, Section 3.1.3: "For // X25519MLKEM768, the shared secret is the concatenation of the ML-KEM // shared secret and the X25519 shared secret. The shared secret is 64 From d7c3e93c16eeb328e9d943aa4fbd5ec8c793ec1b Mon Sep 17 00:00:00 2001 From: Harald Albrecht Date: Thu, 26 Dec 2024 21:27:33 +0100 Subject: [PATCH 068/397] iter: improve documentation with iterator example In introducing iterators, package iter gives an example of how to use an iterator in a range-over-func loop, but currently does not give an example of what an iterator implementation might look like. This change adds the example of map.Keys() before the usage example. Additionally, it references to the Go blog for further examples, as well as the language spec about for-range loops. Fixes #70986 Change-Id: I7108d341d314d7de146b4c221700736c943a9f5d Reviewed-on: https://go-review.googlesource.com/c/go/+/638895 Reviewed-by: Cherry Mui Reviewed-by: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Auto-Submit: Ian Lance Taylor --- src/iter/iter.go | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/iter/iter.go b/src/iter/iter.go index 14fd8f8115f3f6..e765378ef25f45 100644 --- a/src/iter/iter.go +++ b/src/iter/iter.go @@ -28,7 +28,22 @@ or index-value pairs. Yield returns true if the iterator should continue with the next element in the sequence, false if it should stop. -Iterator functions are most often called by a range loop, as in: +For instance, [maps.Keys] returns an iterator that produces the sequence +of keys of the map m, implemented as follows: + + func Keys[Map ~map[K]V, K comparable, V any](m Map) iter.Seq[K] { + return func(yield func(K) bool) { + for k := range m { + if !yield(k) { + return + } + } + } + } + +Further examples can be found in [The Go Blog: Range Over Function Types]. + +Iterator functions are most often called by a [range loop], as in: func PrintAll[V any](seq iter.Seq[V]) { for v := range seq { @@ -187,6 +202,9 @@ And then a client could delete boring values from the tree using: p.Delete() } } + +[The Go Blog: Range Over Function Types]: https://go.dev/blog/range-functions +[range loop]: https://go.dev/ref/spec#For_range */ package iter From 7c03fe70b897581aacc0092315f75abd08ebeeee Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 27 Dec 2024 10:48:22 -0500 Subject: [PATCH 069/397] cmd/compile: improve compiler directive docs This section has gotten long enough that it deserves to be multiple sections. This also allows us to better structure information shared by subsets of directives. In particular, this enables a self-contained section on the wasm directives. Updates #66984. Change-Id: I062081d46c6b0aef7887fdaf9efae80f32ad4b21 Reviewed-on: https://go-review.googlesource.com/c/go/+/638881 LUCI-TryBot-Result: Go LUCI Auto-Submit: Austin Clements Reviewed-by: Cherry Mui --- src/cmd/compile/doc.go | 69 ++++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 29 deletions(-) diff --git a/src/cmd/compile/doc.go b/src/cmd/compile/doc.go index f45df3f86a671d..49abb857adfe13 100644 --- a/src/cmd/compile/doc.go +++ b/src/cmd/compile/doc.go @@ -15,7 +15,7 @@ the package and about types used by symbols imported by the package from other packages. It is therefore not necessary when compiling client C of package P to read the files of P's dependencies, only the compiled output of P. -Command Line +# Command Line Usage: @@ -150,14 +150,21 @@ Flags to debug the compiler itself: -w Debug type checking. -Compiler Directives +# Compiler Directives The compiler accepts directives in the form of comments. -To distinguish them from non-directive comments, directives -require no space between the comment opening and the name of the directive. However, since -they are comments, tools unaware of the directive convention or of a particular +Each directive must be placed its own line, with only leading spaces and tabs +allowed before the comment, and there must be no space between the comment +opening and the name of the directive, to distinguish it from a regular comment. +Tools unaware of the directive convention or of a particular directive can skip over a directive like any other comment. + +Other than the line directive, which is a historical special case; +all other compiler directives are of the form +//go:name, indicating that they are defined by the Go toolchain. */ +// # Line Directives +// // Line directives come in several forms: // // //line :line @@ -197,12 +204,9 @@ directive can skip over a directive like any other comment. // Line directives typically appear in machine-generated code, so that compilers and debuggers // will report positions in the original input to the generator. /* -The line directive is a historical special case; all other directives are of the form -//go:name, indicating that they are defined by the Go toolchain. -Each directive must be placed its own line, with only leading spaces and tabs -allowed before the comment. -Each directive applies to the Go code that immediately follows it, -which typically must be a declaration. +# Function Directives + +A function directive applies to the Go function that immediately follows it. //go:noescape @@ -245,6 +249,8 @@ It specifies that the function must omit its usual stack overflow check. This is most commonly used by low-level runtime code invoked at times when it is unsafe for the calling goroutine to be preempted. +# Linkname Directive + //go:linkname localname [importpath.name] The //go:linkname directive conventionally precedes the var or func @@ -295,17 +301,34 @@ The declaration of lower.f may also have a linkname directive with a single argument, f. This is optional, but helps alert the reader that the function is accessed from outside the package. +# WebAssembly Directives + //go:wasmimport importmodule importname The //go:wasmimport directive is wasm-only and must be followed by a -function declaration. +function declaration with no body. It specifies that the function is provided by a wasm module identified -by ``importmodule`` and ``importname``. +by ``importmodule'' and ``importname''. For example, //go:wasmimport a_module f func g() -The types of parameters and return values to the Go function are translated to +causes g to refer to the WebAssembly function f from module a_module. + + //go:wasmexport exportname + +The //go:wasmexport directive is wasm-only and must be followed by a +function definition. +It specifies that the function is exported to the wasm host as ``exportname''. +For example, + + //go:wasmexport h + func hWasm() { ... } + +make Go function hWasm available outside this WebAssembly module as h. + +For both go:wasmimport and go:wasmexport, +the types of parameters and return values to the Go function are translated to Wasm according to the following table: Go types Wasm types @@ -318,24 +341,12 @@ Wasm according to the following table: pointer i32 (more restrictions below) string (i32, i32) (only permitted as a parameters, not a result) +Any other parameter types are disallowed by the compiler. + For a pointer type, its element type must be a bool, int8, uint8, int16, uint16, int32, uint32, int64, uint64, float32, float64, an array whose element type is a permitted pointer element type, or a struct, which, if non-empty, embeds -structs.HostLayout, and contains only fields whose types are permitted pointer +[structs.HostLayout], and contains only fields whose types are permitted pointer element types. - -Any other parameter types are disallowed by the compiler. - - //go:wasmexport exportname - -The //go:wasmexport directive is wasm-only and must be followed by a -function definition. -It specifies that the function is exported to the wasm host as ``exportname``. - - //go:wasmexport f - func g() - -The types of parameters and return values to the Go function are permitted and -translated to Wasm in the same way as //go:wasmimport functions. */ package main From 39794819aa0950f143fa59c41b577bf6a2f81455 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 27 Dec 2024 11:25:06 -0500 Subject: [PATCH 070/397] doc/initial: remove fixed-width spacing notice Ever since CL 362015 in 2021 it hasn't been necessary to set "fixed-width phrases with non-fixed-width spaces" because the site CSS now takes care of this typesetting convention. Change-Id: Id84f711b65cddf389dc485aa362b23c9c531cbfd Reviewed-on: https://go-review.googlesource.com/c/go/+/638565 Reviewed-by: Jonathan Amsterdam Auto-Submit: Austin Clements Reviewed-by: Dmitri Shuralyov LUCI-TryBot-Result: Go LUCI --- doc/initial/1-intro.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/doc/initial/1-intro.md b/doc/initial/1-intro.md index 8c9948ddf607ae..84ffee855a4095 100644 --- a/doc/initial/1-intro.md +++ b/doc/initial/1-intro.md @@ -1,9 +1,3 @@ - - From e3cd55e9d293d519e622e788e902f372dc30338a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20T=C3=B4rres?= Date: Fri, 27 Dec 2024 07:21:53 +0000 Subject: [PATCH 071/397] cmd/go/internal/work: allow @ character in some -Wl, linker flags on darwin The GNU linker interprets @file as "read command-line options from file". Thus, we forbid values starting with @ on linker flags. However, this causes a problem when targeting Darwin. @executable_path, @loader_path, and @rpath are special values used in Mach-O to change the library search path and can be used in conjunction with the -install_name and -rpath linker flags. Since the GNU linker does not support Mach-O, targeting Darwin implies not using the GNU linker. Therefore, we allow @ in the linker flags if and only if cfg.Goos == "darwin". Fixes #40559 Change-Id: I0896758f0835e444ea0d501ea3fd8423cff97a27 GitHub-Last-Rev: 2b81dcd12e7ae0bbb77deccc9973f84a3aa6d750 GitHub-Pull-Request: golang/go#70939 Reviewed-on: https://go-review.googlesource.com/c/go/+/638075 Auto-Submit: Ian Lance Taylor Reviewed-by: Ian Lance Taylor Reviewed-by: Cherry Mui LUCI-TryBot-Result: Go LUCI --- src/cmd/go/internal/work/security.go | 22 +++++++++++- src/cmd/go/internal/work/security_test.go | 44 +++++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/src/cmd/go/internal/work/security.go b/src/cmd/go/internal/work/security.go index 50bfd0ab705383..33341a4f4dde09 100644 --- a/src/cmd/go/internal/work/security.go +++ b/src/cmd/go/internal/work/security.go @@ -227,6 +227,21 @@ var validLinkerFlags = []*lazyregexp.Regexp{ re(`\./.*\.(a|o|obj|dll|dylib|so|tbd)`), } +var validLinkerFlagsOnDarwin = []*lazyregexp.Regexp{ + // The GNU linker interprets `@file` as "read command-line options from + // file". Thus, we forbid values starting with `@` on linker flags. + // However, this causes a problem when targeting Darwin. + // `@executable_path`, `@loader_path`, and `@rpath` are special values + // used in Mach-O to change the library search path and can be used in + // conjunction with the `-install_name` and `-rpath` linker flags. + // Since the GNU linker does not support Mach-O, targeting Darwin + // implies not using the GNU linker. Therefore, we allow @ in the linker + // flags if and only if cfg.Goos == "darwin" || cfg.Goos == "ios". + re(`-Wl,-dylib_install_name,@rpath(/[^,]*)?`), + re(`-Wl,-install_name,@rpath(/[^,]*)?`), + re(`-Wl,-rpath,@(executable_path|loader_path)(/[^,]*)?`), +} + var validLinkerFlagsWithNextArg = []string{ "-arch", "-F", @@ -249,8 +264,13 @@ func checkCompilerFlags(name, source string, list []string) error { } func checkLinkerFlags(name, source string, list []string) error { + validLinkerFlagsForPlatform := validLinkerFlags + if cfg.Goos == "darwin" || cfg.Goos == "ios" { + validLinkerFlagsForPlatform = append(validLinkerFlags, validLinkerFlagsOnDarwin...) + } + checkOverrides := true - return checkFlags(name, source, list, invalidLinkerFlags, validLinkerFlags, validLinkerFlagsWithNextArg, checkOverrides) + return checkFlags(name, source, list, invalidLinkerFlags, validLinkerFlagsForPlatform, validLinkerFlagsWithNextArg, checkOverrides) } // checkCompilerFlagsForInternalLink returns an error if 'list' diff --git a/src/cmd/go/internal/work/security_test.go b/src/cmd/go/internal/work/security_test.go index 35af62176472b4..52e54e25e4a293 100644 --- a/src/cmd/go/internal/work/security_test.go +++ b/src/cmd/go/internal/work/security_test.go @@ -8,6 +8,8 @@ import ( "os" "strings" "testing" + + "cmd/go/internal/cfg" ) var goodCompilerFlags = [][]string{ @@ -245,6 +247,8 @@ var badLinkerFlags = [][]string{ {"-Wl,--hash-style=foo"}, {"-x", "--c"}, {"-x", "@obj"}, + {"-Wl,-dylib_install_name,@foo"}, + {"-Wl,-install_name,@foo"}, {"-Wl,-rpath,@foo"}, {"-Wl,-R,foo,bar"}, {"-Wl,-R,@foo"}, @@ -261,6 +265,21 @@ var badLinkerFlags = [][]string{ {"./-Wl,--push-state,-R.c"}, } +var goodLinkerFlagsOnDarwin = [][]string{ + {"-Wl,-dylib_install_name,@rpath"}, + {"-Wl,-dylib_install_name,@rpath/"}, + {"-Wl,-dylib_install_name,@rpath/foo"}, + {"-Wl,-install_name,@rpath"}, + {"-Wl,-install_name,@rpath/"}, + {"-Wl,-install_name,@rpath/foo"}, + {"-Wl,-rpath,@executable_path"}, + {"-Wl,-rpath,@executable_path/"}, + {"-Wl,-rpath,@executable_path/foo"}, + {"-Wl,-rpath,@loader_path"}, + {"-Wl,-rpath,@loader_path/"}, + {"-Wl,-rpath,@loader_path/foo"}, +} + func TestCheckLinkerFlags(t *testing.T) { for _, f := range goodLinkerFlags { if err := checkLinkerFlags("test", "test", f); err != nil { @@ -272,6 +291,31 @@ func TestCheckLinkerFlags(t *testing.T) { t.Errorf("missing error for %q", f) } } + + goos := cfg.Goos + + cfg.Goos = "darwin" + for _, f := range goodLinkerFlagsOnDarwin { + if err := checkLinkerFlags("test", "test", f); err != nil { + t.Errorf("unexpected error for %q: %v", f, err) + } + } + + cfg.Goos = "ios" + for _, f := range goodLinkerFlagsOnDarwin { + if err := checkLinkerFlags("test", "test", f); err != nil { + t.Errorf("unexpected error for %q: %v", f, err) + } + } + + cfg.Goos = "linux" + for _, f := range goodLinkerFlagsOnDarwin { + if err := checkLinkerFlags("test", "test", f); err == nil { + t.Errorf("missing error for %q", f) + } + } + + cfg.Goos = goos } func TestCheckFlagAllowDisallow(t *testing.T) { From 2b794ed86cb1b718bc212ee90fecbb8f3b28a744 Mon Sep 17 00:00:00 2001 From: Joe Tsai Date: Mon, 23 Dec 2024 10:35:24 -0800 Subject: [PATCH 072/397] encoding/json: expand and modernize TestInterfaceSet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add more test cases to cover a wider range of edge cases. Use a generic addr function to take the address of a value. Even though redudant, explicitly include a cast to the top-level Go type so that it is more readable what the expected input and ouput types are. Change-Id: I3ef68df6f1beb903ae237cd49f3dcb91e5270fe7 Reviewed-on: https://go-review.googlesource.com/c/go/+/638256 Reviewed-by: Daniel Martí Reviewed-by: Damien Neil Reviewed-by: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI --- src/encoding/json/decode_test.go | 65 ++++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 19 deletions(-) diff --git a/src/encoding/json/decode_test.go b/src/encoding/json/decode_test.go index de09fae50f09d1..a2b462af775e3a 100644 --- a/src/encoding/json/decode_test.go +++ b/src/encoding/json/decode_test.go @@ -1797,19 +1797,12 @@ func TestNullString(t *testing.T) { } } -func intp(x int) *int { - p := new(int) - *p = x - return p -} - -func intpp(x *int) **int { - pp := new(*int) - *pp = x - return pp +func addr[T any](v T) *T { + return &v } func TestInterfaceSet(t *testing.T) { + errUnmarshal := &UnmarshalTypeError{Value: "object", Offset: 6, Type: reflect.TypeFor[int](), Field: "X"} tests := []struct { CaseName pre any @@ -1820,21 +1813,55 @@ func TestInterfaceSet(t *testing.T) { {Name(""), "foo", `2`, 2.0}, {Name(""), "foo", `true`, true}, {Name(""), "foo", `null`, nil}, - - {Name(""), nil, `null`, nil}, - {Name(""), new(int), `null`, nil}, - {Name(""), (*int)(nil), `null`, nil}, - {Name(""), new(*int), `null`, new(*int)}, - {Name(""), (**int)(nil), `null`, nil}, - {Name(""), intp(1), `null`, nil}, - {Name(""), intpp(nil), `null`, intpp(nil)}, - {Name(""), intpp(intp(1)), `null`, intpp(nil)}, + {Name(""), map[string]any{}, `true`, true}, + {Name(""), []string{}, `true`, true}, + + {Name(""), any(nil), `null`, any(nil)}, + {Name(""), (*int)(nil), `null`, any(nil)}, + {Name(""), (*int)(addr(0)), `null`, any(nil)}, + {Name(""), (*int)(addr(1)), `null`, any(nil)}, + {Name(""), (**int)(nil), `null`, any(nil)}, + {Name(""), (**int)(addr[*int](nil)), `null`, (**int)(addr[*int](nil))}, + {Name(""), (**int)(addr(addr(1))), `null`, (**int)(addr[*int](nil))}, + {Name(""), (***int)(nil), `null`, any(nil)}, + {Name(""), (***int)(addr[**int](nil)), `null`, (***int)(addr[**int](nil))}, + {Name(""), (***int)(addr(addr[*int](nil))), `null`, (***int)(addr[**int](nil))}, + {Name(""), (***int)(addr(addr(addr(1)))), `null`, (***int)(addr[**int](nil))}, + + {Name(""), any(nil), `2`, float64(2)}, + {Name(""), (int)(1), `2`, float64(2)}, + {Name(""), (*int)(nil), `2`, float64(2)}, + {Name(""), (*int)(addr(0)), `2`, (*int)(addr(2))}, + {Name(""), (*int)(addr(1)), `2`, (*int)(addr(2))}, + {Name(""), (**int)(nil), `2`, float64(2)}, + {Name(""), (**int)(addr[*int](nil)), `2`, (**int)(addr(addr(2)))}, + {Name(""), (**int)(addr(addr(1))), `2`, (**int)(addr(addr(2)))}, + {Name(""), (***int)(nil), `2`, float64(2)}, + {Name(""), (***int)(addr[**int](nil)), `2`, (***int)(addr(addr(addr(2))))}, + {Name(""), (***int)(addr(addr[*int](nil))), `2`, (***int)(addr(addr(addr(2))))}, + {Name(""), (***int)(addr(addr(addr(1)))), `2`, (***int)(addr(addr(addr(2))))}, + + {Name(""), any(nil), `{}`, map[string]any{}}, + {Name(""), (int)(1), `{}`, map[string]any{}}, + {Name(""), (*int)(nil), `{}`, map[string]any{}}, + {Name(""), (*int)(addr(0)), `{}`, errUnmarshal}, + {Name(""), (*int)(addr(1)), `{}`, errUnmarshal}, + {Name(""), (**int)(nil), `{}`, map[string]any{}}, + {Name(""), (**int)(addr[*int](nil)), `{}`, errUnmarshal}, + {Name(""), (**int)(addr(addr(1))), `{}`, errUnmarshal}, + {Name(""), (***int)(nil), `{}`, map[string]any{}}, + {Name(""), (***int)(addr[**int](nil)), `{}`, errUnmarshal}, + {Name(""), (***int)(addr(addr[*int](nil))), `{}`, errUnmarshal}, + {Name(""), (***int)(addr(addr(addr(1)))), `{}`, errUnmarshal}, } for _, tt := range tests { t.Run(tt.Name, func(t *testing.T) { b := struct{ X any }{tt.pre} blob := `{"X":` + tt.json + `}` if err := Unmarshal([]byte(blob), &b); err != nil { + if wantErr, _ := tt.post.(error); equalError(err, wantErr) { + return + } t.Fatalf("%s: Unmarshal(%#q) error: %v", tt.Where, blob, err) } if !reflect.DeepEqual(b.X, tt.post) { From a785d11ac47560c12202a79a25ddd6ba610976e9 Mon Sep 17 00:00:00 2001 From: Koichi Shiraishi Date: Sat, 28 Dec 2024 14:05:38 +0900 Subject: [PATCH 073/397] unique: fix typo Change-Id: I9f66e3d7aa7b546ebf34d6aa8c7a6558bf35ca82 Reviewed-on: https://go-review.googlesource.com/c/go/+/639055 LUCI-TryBot-Result: Go LUCI Reviewed-by: Ian Lance Taylor Auto-Submit: Ian Lance Taylor Reviewed-by: Dmitri Shuralyov --- src/unique/handle.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unique/handle.go b/src/unique/handle.go index 46f2da3ddcbd95..520ab70f8c7d83 100644 --- a/src/unique/handle.go +++ b/src/unique/handle.go @@ -89,7 +89,7 @@ func Make[T comparable](value T) Handle[T] { } var ( - // uniqueMaps is an index of type-specific sync maps used for unique.Make. + // uniqueMaps is an index of type-specific concurrent maps used for unique.Make. // // The two-level map might seem odd at first since the HashTrieMap could have "any" // as its key type, but the issue is escape analysis. We do not want to force lookups From fd5e0d26d9383ff80fd365bdfcb50d6c8a97e44c Mon Sep 17 00:00:00 2001 From: Sean Liao Date: Sat, 28 Dec 2024 14:50:11 -0500 Subject: [PATCH 074/397] go/doc: resolve imports before predeclared identifiers in examples Fixes #70611 Fixes #70630 Change-Id: I868e68dbdf50ce34259eeef7b3d7985ede1f4c0b Reviewed-on: https://go-review.googlesource.com/c/go/+/639175 Reviewed-by: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Reviewed-by: Dmitri Shuralyov Auto-Submit: Ian Lance Taylor --- src/go/doc/example.go | 14 +++++++------- .../testdata/examples/shadow_predeclared.go | 19 +++++++++++++++++++ .../examples/shadow_predeclared.golden | 16 ++++++++++++++++ 3 files changed, 42 insertions(+), 7 deletions(-) create mode 100644 src/go/doc/testdata/examples/shadow_predeclared.go create mode 100644 src/go/doc/testdata/examples/shadow_predeclared.golden diff --git a/src/go/doc/example.go b/src/go/doc/example.go index 0618f2bd9b8bab..7a8c26291db1f2 100644 --- a/src/go/doc/example.go +++ b/src/go/doc/example.go @@ -192,13 +192,6 @@ func playExample(file *ast.File, f *ast.FuncDecl) *ast.File { // Find unresolved identifiers and uses of top-level declarations. depDecls, unresolved := findDeclsAndUnresolved(body, topDecls, typMethods) - // Remove predeclared identifiers from unresolved list. - for n := range unresolved { - if predeclaredTypes[n] || predeclaredConstants[n] || predeclaredFuncs[n] { - delete(unresolved, n) - } - } - // Use unresolved identifiers to determine the imports used by this // example. The heuristic assumes package names match base import // paths for imports w/o renames (should be good enough most of the time). @@ -251,6 +244,13 @@ func playExample(file *ast.File, f *ast.FuncDecl) *ast.File { } } + // Remove predeclared identifiers from unresolved list. + for n := range unresolved { + if predeclaredTypes[n] || predeclaredConstants[n] || predeclaredFuncs[n] { + delete(unresolved, n) + } + } + // If there are other unresolved identifiers, give up because this // synthesized file is not going to build. if len(unresolved) > 0 { diff --git a/src/go/doc/testdata/examples/shadow_predeclared.go b/src/go/doc/testdata/examples/shadow_predeclared.go new file mode 100644 index 00000000000000..7e9f30d9b4e322 --- /dev/null +++ b/src/go/doc/testdata/examples/shadow_predeclared.go @@ -0,0 +1,19 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package foo_test + +import ( + "fmt" + + "example.com/error" +) + +func Print(s string) { + fmt.Println(s) +} + +func Example() { + Print(error.Hello) +} diff --git a/src/go/doc/testdata/examples/shadow_predeclared.golden b/src/go/doc/testdata/examples/shadow_predeclared.golden new file mode 100644 index 00000000000000..65598bed62d500 --- /dev/null +++ b/src/go/doc/testdata/examples/shadow_predeclared.golden @@ -0,0 +1,16 @@ +-- .Play -- +package main + +import ( + "fmt" + + "example.com/error" +) + +func Print(s string) { + fmt.Println(s) +} + +func main() { + Print(error.Hello) +} From ba1deb1ceef956bdb3ca5a9570f132cf19ccc9f6 Mon Sep 17 00:00:00 2001 From: willboland Date: Sun, 29 Dec 2024 02:37:06 +0000 Subject: [PATCH 075/397] cmd/link: document that -s implies -w Existing documentation does not reference implicit behavior. Updates the documentation to reflect that -s implies -w. Fixes #71051 Change-Id: I5c139c37f5f78596365e38479be4c865a4d4dd62 GitHub-Last-Rev: a3e462c4168284529ea1b0d03bc25fb1c12f1da5 GitHub-Pull-Request: golang/go#71053 Reviewed-on: https://go-review.googlesource.com/c/go/+/638976 LUCI-TryBot-Result: Go LUCI Reviewed-by: Dmitri Shuralyov Auto-Submit: Ian Lance Taylor Reviewed-by: Cherry Mui --- src/cmd/link/doc.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cmd/link/doc.go b/src/cmd/link/doc.go index 9ec2c002f40e28..7b548f960fd86d 100644 --- a/src/cmd/link/doc.go +++ b/src/cmd/link/doc.go @@ -118,6 +118,7 @@ Flags: Link with race detection libraries. -s Omit the symbol table and debug information. + Implies the -w flag, which can be negated with -w=0. -tmpdir dir Write temporary files to dir. Temporary files are only used in external linking mode. From 15f232456a8741c84ee0bd38dce28978eab6a491 Mon Sep 17 00:00:00 2001 From: Joe Tsai Date: Fri, 27 Dec 2024 17:24:30 -0800 Subject: [PATCH 076/397] encoding/json: remove suggestion on Unmarshaler with JSON null It is not true that Unmarshal always treats a JSON null as being equivalent to a no-op. For bools, ints, uints, floats, strings, arrays, and structs, it treats a JSON null as a no-op. However, for []byte, slice, map, pointer, or interface, it zeros the underlying value. Remove this suggestion as the actual behavior is inconsistent. Note that the proposed behavior in v2 Unmarshal is to consistently zero out the underlying value. Change-Id: I02cef0bf7919f25cfd0aceb04486d37498761181 Reviewed-on: https://go-review.googlesource.com/c/go/+/638416 Reviewed-by: Dmitri Shuralyov TryBot-Result: Gopher Robot LUCI-TryBot-Result: Go LUCI Reviewed-by: Ian Lance Taylor Run-TryBot: Joseph Tsai --- src/encoding/json/decode.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/encoding/json/decode.go b/src/encoding/json/decode.go index 98102291ab8036..3b398c9fc323f5 100644 --- a/src/encoding/json/decode.go +++ b/src/encoding/json/decode.go @@ -113,9 +113,6 @@ func Unmarshal(data []byte, v any) error { // The input can be assumed to be a valid encoding of // a JSON value. UnmarshalJSON must copy the JSON data // if it wishes to retain the data after returning. -// -// By convention, to approximate the behavior of [Unmarshal] itself, -// Unmarshalers implement UnmarshalJSON([]byte("null")) as a no-op. type Unmarshaler interface { UnmarshalJSON([]byte) error } From b702a26cf8f2298de6d264c1cbc09042e2b0ac22 Mon Sep 17 00:00:00 2001 From: Sean Liao Date: Sat, 28 Dec 2024 15:10:21 -0500 Subject: [PATCH 077/397] os: mention fsys modifications during CopyFS Fixes #70465 Change-Id: I47055df9ca5b1df21a361b0b8eea4c7d157e6403 Reviewed-on: https://go-review.googlesource.com/c/go/+/639156 Commit-Queue: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Reviewed-by: Ian Lance Taylor Auto-Submit: Ian Lance Taylor Reviewed-by: Dmitri Shuralyov --- src/os/dir.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/os/dir.go b/src/os/dir.go index 04392193aa6b03..939b208d8c0a2b 100644 --- a/src/os/dir.go +++ b/src/os/dir.go @@ -145,6 +145,9 @@ func ReadDir(name string) ([]DirEntry, error) { // // Symbolic links in dir are followed. // +// New files added to fsys (including if dir is a subdirectory of fsys) +// while CopyFS is running are not guaranteed to be copied. +// // Copying stops at and returns the first error encountered. func CopyFS(dir string, fsys fs.FS) error { return fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error { From 3c4102bfd4dc87cba19152af834754170b863b39 Mon Sep 17 00:00:00 2001 From: willboland Date: Mon, 30 Dec 2024 20:00:43 +0000 Subject: [PATCH 078/397] encoding/binary: add documentation for endian methods While the comments are on an unexported type, gopls correctly shows them when using the exported vars LittleEndian and BigEndian. Fixes #68083 Change-Id: I53668c3140ad00f7b58437be74e6df773e2916f1 GitHub-Last-Rev: cef717123cdc632b59683f4ce55aee6c286ca4c7 GitHub-Pull-Request: golang/go#71058 Reviewed-on: https://go-review.googlesource.com/c/go/+/638936 LUCI-TryBot-Result: Go LUCI Auto-Submit: Ian Lance Taylor Reviewed-by: Dmitri Shuralyov Reviewed-by: Ian Lance Taylor Reviewed-by: Jorropo --- src/encoding/binary/binary.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/encoding/binary/binary.go b/src/encoding/binary/binary.go index d80aa8e11a5638..c92dfded272798 100644 --- a/src/encoding/binary/binary.go +++ b/src/encoding/binary/binary.go @@ -65,17 +65,20 @@ var BigEndian bigEndian type littleEndian struct{} +// Uint16 returns the uint16 representation of b[0:2]. func (littleEndian) Uint16(b []byte) uint16 { _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 return uint16(b[0]) | uint16(b[1])<<8 } +// PutUint16 stores v into b[0:2]. func (littleEndian) PutUint16(b []byte, v uint16) { _ = b[1] // early bounds check to guarantee safety of writes below b[0] = byte(v) b[1] = byte(v >> 8) } +// AppendUint16 appends the bytes of v to b and returns the appended slice. func (littleEndian) AppendUint16(b []byte, v uint16) []byte { return append(b, byte(v), @@ -83,11 +86,13 @@ func (littleEndian) AppendUint16(b []byte, v uint16) []byte { ) } +// Uint32 returns the uint32 representation of b[0:4]. func (littleEndian) Uint32(b []byte) uint32 { _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 } +// PutUint32 stores v into b[0:4]. func (littleEndian) PutUint32(b []byte, v uint32) { _ = b[3] // early bounds check to guarantee safety of writes below b[0] = byte(v) @@ -96,6 +101,7 @@ func (littleEndian) PutUint32(b []byte, v uint32) { b[3] = byte(v >> 24) } +// AppendUint32 appends the bytes of v to b and returns the appended slice. func (littleEndian) AppendUint32(b []byte, v uint32) []byte { return append(b, byte(v), @@ -105,12 +111,14 @@ func (littleEndian) AppendUint32(b []byte, v uint32) []byte { ) } +// Uint64 returns the uint64 representation of b[0:8]. func (littleEndian) Uint64(b []byte) uint64 { _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 } +// PutUint64 stores v into b[0:8]. func (littleEndian) PutUint64(b []byte, v uint64) { _ = b[7] // early bounds check to guarantee safety of writes below b[0] = byte(v) @@ -123,6 +131,7 @@ func (littleEndian) PutUint64(b []byte, v uint64) { b[7] = byte(v >> 56) } +// AppendUint64 appends the bytes of v to b and returns the appended slice. func (littleEndian) AppendUint64(b []byte, v uint64) []byte { return append(b, byte(v), @@ -142,17 +151,20 @@ func (littleEndian) GoString() string { return "binary.LittleEndian" } type bigEndian struct{} +// Uint16 returns the uint16 representation of b[0:2]. func (bigEndian) Uint16(b []byte) uint16 { _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 return uint16(b[1]) | uint16(b[0])<<8 } +// PutUint16 stores v into b[0:2]. func (bigEndian) PutUint16(b []byte, v uint16) { _ = b[1] // early bounds check to guarantee safety of writes below b[0] = byte(v >> 8) b[1] = byte(v) } +// AppendUint16 appends the bytes of v to b and returns the appended slice. func (bigEndian) AppendUint16(b []byte, v uint16) []byte { return append(b, byte(v>>8), @@ -160,11 +172,13 @@ func (bigEndian) AppendUint16(b []byte, v uint16) []byte { ) } +// Uint32 returns the uint32 representation of b[0:4]. func (bigEndian) Uint32(b []byte) uint32 { _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 } +// PutUint32 stores v into b[0:4]. func (bigEndian) PutUint32(b []byte, v uint32) { _ = b[3] // early bounds check to guarantee safety of writes below b[0] = byte(v >> 24) @@ -173,6 +187,7 @@ func (bigEndian) PutUint32(b []byte, v uint32) { b[3] = byte(v) } +// AppendUint32 appends the bytes of v to b and returns the appended slice. func (bigEndian) AppendUint32(b []byte, v uint32) []byte { return append(b, byte(v>>24), @@ -182,12 +197,14 @@ func (bigEndian) AppendUint32(b []byte, v uint32) []byte { ) } +// Uint64 returns the uint64 representation of b[0:8]. func (bigEndian) Uint64(b []byte) uint64 { _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 } +// PutUint64 stores v into b[0:8]. func (bigEndian) PutUint64(b []byte, v uint64) { _ = b[7] // early bounds check to guarantee safety of writes below b[0] = byte(v >> 56) @@ -200,6 +217,7 @@ func (bigEndian) PutUint64(b []byte, v uint64) { b[7] = byte(v) } +// AppendUint64 appends the bytes of v to b and returns the appended slice. func (bigEndian) AppendUint64(b []byte, v uint64) []byte { return append(b, byte(v>>56), From 8857a5a33ffaff475abd6e4364d2c5a0f53c2baf Mon Sep 17 00:00:00 2001 From: thekuwayama Date: Mon, 30 Dec 2024 20:00:49 +0000 Subject: [PATCH 079/397] crypto/tls: fix misspelling in comment Change-Id: Ie36a19ed6d6922e68f98e43745a417a24f8a7828 GitHub-Last-Rev: 6fb32e3d1d4f35704d466b53796e8ddeaf936d72 GitHub-Pull-Request: golang/go#71060 Reviewed-on: https://go-review.googlesource.com/c/go/+/639215 Auto-Submit: Ian Lance Taylor Reviewed-by: Roland Shoemaker LUCI-TryBot-Result: Go LUCI Reviewed-by: Ian Lance Taylor --- src/crypto/tls/handshake_messages.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crypto/tls/handshake_messages.go b/src/crypto/tls/handshake_messages.go index fa00d7b741100e..6c6141c421ea34 100644 --- a/src/crypto/tls/handshake_messages.go +++ b/src/crypto/tls/handshake_messages.go @@ -97,7 +97,7 @@ type clientHelloMsg struct { pskBinders [][]byte quicTransportParameters []byte encryptedClientHello []byte - // extensions are only populated on the servers-ide of a handshake + // extensions are only populated on the server-side of a handshake extensions []uint16 } From 0d8aa8cce69f97747e7ce69b8416c1cfca5d939f Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 12 Dec 2024 15:26:54 -0800 Subject: [PATCH 080/397] spec: describe representation of values Add a section on the representation of values: distinguish between values that are self-contained and values that contain references while avoiding the notion of "reference types" which is misleading. Also, use "predeclared identifier nil" rather than "predeclared value nil" because it is the identifier that is predeclared. Fixes #5083. Change-Id: I2235673c6404f2c055f195e879f198c7ab246d58 Reviewed-on: https://go-review.googlesource.com/c/go/+/635801 Reviewed-by: Rob Pike Reviewed-by: David Chase Auto-Submit: Robert Griesemer Reviewed-by: Ian Lance Taylor TryBot-Bypass: Robert Griesemer Reviewed-by: Robert Griesemer --- doc/go_spec.html | 91 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 81 insertions(+), 10 deletions(-) diff --git a/doc/go_spec.html b/doc/go_spec.html index fff489c33ac55c..8ff178e28105b9 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -1,6 +1,6 @@ @@ -798,7 +798,6 @@

Variables

zero value for its type.

-

Types

@@ -1200,7 +1199,7 @@

Pointer types

A pointer type denotes the set of all pointers to variables of a given type, called the base type of the pointer. -The value of an uninitialized pointer is nil. +The value of an uninitialized pointer is nil.

@@ -1216,9 +1215,9 @@ 

Pointer types

Function types

-A function type denotes the set of all functions with the same parameter -and result types. The value of an uninitialized variable of function type -is nil. +A function type denotes the set of all functions with the same parameter and result types. +The value of an uninitialized variable of function +type is nil.

@@ -1267,7 +1266,8 @@ 

Interface types

A variable of interface type can store a value of any type that is in the type set of the interface. Such a type is said to implement the interface. -The value of an uninitialized variable of interface type is nil. +The value of an uninitialized variable of +interface type is nil.

@@ -1630,7 +1630,7 @@ 

Map types

A map is an unordered group of elements of one type, called the element type, indexed by a set of unique keys of another type, called the key type. -The value of an uninitialized map is nil. +The value of an uninitialized map is nil.

@@ -1693,7 +1693,7 @@ 

Channel types

sending and receiving values of a specified element type. -The value of an uninitialized channel is nil. +The value of an uninitialized channel is nil.

@@ -1772,6 +1772,57 @@ 

Channel types

Properties of types and values

+

Representation of values

+ +

+Values of predeclared types (see below for the interfaces any +and error), arrays, and structs are self-contained: +Each such value contains a complete copy of all its data, +and variables of such types store the entire value. +For instance, an array variable provides the storage (the variables) +for all elements of the array. +The respective zero values are specific to the +value's types; they are never nil. +

+ +

+Non-nil pointer, function, slice, map, and channel values contain references +to underlying data which may be shared by multiple values: +

+ +
    +
  • + A pointer value is a reference to the variable holding + the pointer base type value. +
  • +
  • + A function value contains references to the (possibly + anonymous) function + and enclosed variables. +
  • +
  • + A slice value contains the slice length, capacity, and + a reference to its underlying array. +
  • +
  • + A map or channel value is a reference to the implementation-specific + data structure of the map or channel. +
  • +
+ +

+An interface value may be self-contained or contain references to underlying data +depending on the interface's dynamic type. +The predeclared identifier nil is the zero value for types whose values +can contain references. +

+ +

+When multiple values share underlying data, changing one value may change another. +For instance, changing an element of a slice will change +that element in the underlying array for all slices that share the array. +

+

Underlying types

@@ -2899,7 +2950,7 @@

Variable declarations

If that value is an untyped constant, it is first implicitly converted to its default type; if it is an untyped boolean value, it is first implicitly converted to type bool. -The predeclared value nil cannot be used to initialize a variable +The predeclared identifier nil cannot be used to initialize a variable with no explicit type.

@@ -6263,6 +6314,26 @@

Assignment statements

+

+When a value is assigned to a variable, only the data that is stored in the variable +is replaced. If the value contains a reference, +the assignment copies the reference but does not make a copy of the referenced data +(such as the underlying array of a slice). +

+ +
+var s1 = []int{1, 2, 3}
+var s2 = s1                    // s2 stores the slice descriptor of s1
+s1 = s1[:1]                    // s1's length is 1 but it still shares its underlying array with s2
+s2[0] = 42                     // setting s2[0] changes s1[0] as well
+fmt.Println(s1, s2)            // prints [42] [42 2 3]
+
+var m1 = make(map[string]int)
+var m2 = m1                    // m2 stores the map descriptor of m1
+m1["foo"] = 42                 // setting m1["foo"] changes m2["foo"] as well
+fmt.Println(m2["foo"])         // prints 42
+
+

If statements

From 5efb4239c6627e81e82b88377b9eb947f7f253d4 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 18 Dec 2024 14:15:48 -0800 Subject: [PATCH 081/397] spec: document that string conversions don't guarantee result slice capacity Fixes #24163. Change-Id: If389c4abf3b9b6e4eba6f31c3c12779329456df6 Reviewed-on: https://go-review.googlesource.com/c/go/+/637655 Reviewed-by: Robert Griesemer Reviewed-by: Ian Lance Taylor Auto-Submit: Robert Griesemer TryBot-Bypass: Robert Griesemer --- doc/go_spec.html | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/go_spec.html b/doc/go_spec.html index 8ff178e28105b9..c6c4b30b04e279 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -5686,6 +5686,8 @@

Conversions to and from a string
  • Converting a value of a string type to a slice of bytes type yields a non-nil slice whose successive elements are the bytes of the string. +The capacity of the resulting slice is +implementation-specific and may be larger than the slice length.
     []byte("hellø")             // []byte{'h', 'e', 'l', 'l', '\xc3', '\xb8'}
    @@ -5701,6 +5703,8 @@ 

    Conversions to and from a string
  • Converting a value of a string type to a slice of runes type yields a slice containing the individual Unicode code points of the string. +The capacity of the resulting slice is +implementation-specific and may be larger than the slice length.
     []rune(myString("白鵬翔"))   // []rune{0x767d, 0x9d6c, 0x7fd4}
    
    From 856a7bc8e975d29b7c221264f8b0c62df2d60e42 Mon Sep 17 00:00:00 2001
    From: Shulhan 
    Date: Mon, 30 Dec 2024 17:10:57 +0700
    Subject: [PATCH 082/397] builtin: use list instead of indentation for comments
     in cap, len, and make
    
    Using list make the document more readable in HTML and CLI.
    
    Change-Id: Ib84c84656f32806e8612b1ca13938d93f618e27f
    Reviewed-on: https://go-review.googlesource.com/c/go/+/639315
    Reviewed-by: Dmitri Shuralyov 
    LUCI-TryBot-Result: Go LUCI 
    Reviewed-by: Ian Lance Taylor 
    Auto-Submit: Ian Lance Taylor 
    ---
     src/builtin/builtin.go | 48 +++++++++++++++++++++---------------------
     1 file changed, 24 insertions(+), 24 deletions(-)
    
    diff --git a/src/builtin/builtin.go b/src/builtin/builtin.go
    index af01aea5dd79f4..afa2a10f9091dc 100644
    --- a/src/builtin/builtin.go
    +++ b/src/builtin/builtin.go
    @@ -162,12 +162,12 @@ func delete(m map[Type]Type1, key Type)
     
     // The len built-in function returns the length of v, according to its type:
     //
    -//	Array: the number of elements in v.
    -//	Pointer to array: the number of elements in *v (even if v is nil).
    -//	Slice, or map: the number of elements in v; if v is nil, len(v) is zero.
    -//	String: the number of bytes in v.
    -//	Channel: the number of elements queued (unread) in the channel buffer;
    -//	         if v is nil, len(v) is zero.
    +//   - Array: the number of elements in v.
    +//   - Pointer to array: the number of elements in *v (even if v is nil).
    +//   - Slice, or map: the number of elements in v; if v is nil, len(v) is zero.
    +//   - String: the number of bytes in v.
    +//   - Channel: the number of elements queued (unread) in the channel buffer;
    +//     if v is nil, len(v) is zero.
     //
     // For some arguments, such as a string literal or a simple array expression, the
     // result can be a constant. See the Go language specification's "Length and
    @@ -176,12 +176,12 @@ func len(v Type) int
     
     // The cap built-in function returns the capacity of v, according to its type:
     //
    -//	Array: the number of elements in v (same as len(v)).
    -//	Pointer to array: the number of elements in *v (same as len(v)).
    -//	Slice: the maximum length the slice can reach when resliced;
    -//	if v is nil, cap(v) is zero.
    -//	Channel: the channel buffer capacity, in units of elements;
    -//	if v is nil, cap(v) is zero.
    +//   - Array: the number of elements in v (same as len(v)).
    +//   - Pointer to array: the number of elements in *v (same as len(v)).
    +//   - Slice: the maximum length the slice can reach when resliced;
    +//     if v is nil, cap(v) is zero.
    +//   - Channel: the channel buffer capacity, in units of elements;
    +//     if v is nil, cap(v) is zero.
     //
     // For some arguments, such as a simple array expression, the result can be a
     // constant. See the Go language specification's "Length and capacity" section for
    @@ -194,18 +194,18 @@ func cap(v Type) int
     // argument, not a pointer to it. The specification of the result depends on
     // the type:
     //
    -//	Slice: The size specifies the length. The capacity of the slice is
    -//	equal to its length. A second integer argument may be provided to
    -//	specify a different capacity; it must be no smaller than the
    -//	length. For example, make([]int, 0, 10) allocates an underlying array
    -//	of size 10 and returns a slice of length 0 and capacity 10 that is
    -//	backed by this underlying array.
    -//	Map: An empty map is allocated with enough space to hold the
    -//	specified number of elements. The size may be omitted, in which case
    -//	a small starting size is allocated.
    -//	Channel: The channel's buffer is initialized with the specified
    -//	buffer capacity. If zero, or the size is omitted, the channel is
    -//	unbuffered.
    +//   - Slice: The size specifies the length. The capacity of the slice is
    +//     equal to its length. A second integer argument may be provided to
    +//     specify a different capacity; it must be no smaller than the
    +//     length. For example, make([]int, 0, 10) allocates an underlying array
    +//     of size 10 and returns a slice of length 0 and capacity 10 that is
    +//     backed by this underlying array.
    +//   - Map: An empty map is allocated with enough space to hold the
    +//     specified number of elements. The size may be omitted, in which case
    +//     a small starting size is allocated.
    +//   - Channel: The channel's buffer is initialized with the specified
    +//     buffer capacity. If zero, or the size is omitted, the channel is
    +//     unbuffered.
     func make(t Type, size ...IntegerType) Type
     
     // The max built-in function returns the largest value of a fixed number of
    
    From 94f15810e6beadf21f3363d3ae17d83abfd3ae74 Mon Sep 17 00:00:00 2001
    From: Ian Lance Taylor 
    Date: Mon, 30 Dec 2024 14:35:24 -0800
    Subject: [PATCH 083/397] cmd/go: document default GOARM value
    
    For #24904
    For #58884
    
    Change-Id: I0fc61f1a0bc6ebb22bdfd7a7b13ef36c68879384
    Reviewed-on: https://go-review.googlesource.com/c/go/+/639276
    Reviewed-by: Dmitri Shuralyov 
    Reviewed-by: Ian Lance Taylor 
    LUCI-TryBot-Result: Go LUCI 
    Commit-Queue: Ian Lance Taylor 
    Auto-Submit: Ian Lance Taylor 
    Reviewed-by: Dmitri Shuralyov 
    ---
     src/cmd/go/alldocs.go               | 5 +++++
     src/cmd/go/internal/help/helpdoc.go | 5 +++++
     2 files changed, 10 insertions(+)
    
    diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go
    index 5edd93599e56d8..548cf171ca7840 100644
    --- a/src/cmd/go/alldocs.go
    +++ b/src/cmd/go/alldocs.go
    @@ -2448,6 +2448,11 @@
     //	GOARM
     //		For GOARCH=arm, the ARM architecture for which to compile.
     //		Valid values are 5, 6, 7.
    +//		When the Go tools are built on an arm system,
    +//		the default value is set based on what the build system supports.
    +//		When the Go tools are not built on an arm system
    +//		(that is, when building a cross-compiler),
    +//		the default value is 7.
     //		The value can be followed by an option specifying how to implement floating point instructions.
     //		Valid options are ,softfloat (default for 5) and ,hardfloat (default for 6 and 7).
     //	GOARM64
    diff --git a/src/cmd/go/internal/help/helpdoc.go b/src/cmd/go/internal/help/helpdoc.go
    index 3db3ed06b2c9e3..3e7a1cbc75dd43 100644
    --- a/src/cmd/go/internal/help/helpdoc.go
    +++ b/src/cmd/go/internal/help/helpdoc.go
    @@ -620,6 +620,11 @@ Architecture-specific environment variables:
     	GOARM
     		For GOARCH=arm, the ARM architecture for which to compile.
     		Valid values are 5, 6, 7.
    +		When the Go tools are built on an arm system,
    +		the default value is set based on what the build system supports.
    +		When the Go tools are not built on an arm system
    +		(that is, when building a cross-compiler),
    +		the default value is 7.
     		The value can be followed by an option specifying how to implement floating point instructions.
     		Valid options are ,softfloat (default for 5) and ,hardfloat (default for 6 and 7).
     	GOARM64
    
    From d1d93129506c78cc8ee25644384286822d93c81a Mon Sep 17 00:00:00 2001
    From: Filippo Valsorda 
    Date: Thu, 2 Jan 2025 01:34:40 +0100
    Subject: [PATCH 084/397] crypto/tls: fix Config.Time in tests using expired
     certificates
    
    Fixes #71077
    
    Change-Id: I6a6a465685f3bd50a5bb35a160f87b59b74fa6af
    Reviewed-on: https://go-review.googlesource.com/c/go/+/639655
    Auto-Submit: Ian Lance Taylor 
    Reviewed-by: Damien Neil 
    LUCI-TryBot-Result: Go LUCI 
    Auto-Submit: Filippo Valsorda 
    Auto-Submit: Damien Neil 
    Reviewed-by: Joel Sing 
    Reviewed-by: Ian Lance Taylor 
    ---
     src/crypto/tls/handshake_client_test.go | 30 +++++++++++++++----------
     src/crypto/tls/handshake_server_test.go |  2 ++
     src/crypto/tls/handshake_test.go        |  5 +++++
     src/crypto/tls/tls_test.go              |  6 ++---
     4 files changed, 27 insertions(+), 16 deletions(-)
    
    diff --git a/src/crypto/tls/handshake_client_test.go b/src/crypto/tls/handshake_client_test.go
    index bb164bba553f43..bc54475fa4b6d2 100644
    --- a/src/crypto/tls/handshake_client_test.go
    +++ b/src/crypto/tls/handshake_client_test.go
    @@ -856,6 +856,7 @@ func testResumption(t *testing.T, version uint16) {
     		MaxVersion:   version,
     		CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384},
     		Certificates: testCertificates,
    +		Time:         testTime,
     	}
     
     	issuer, err := x509.ParseCertificate(testRSA2048CertificateIssuer)
    @@ -872,6 +873,7 @@ func testResumption(t *testing.T, version uint16) {
     		ClientSessionCache: NewLRUClientSessionCache(32),
     		RootCAs:            rootCAs,
     		ServerName:         "example.golang",
    +		Time:               testTime,
     	}
     
     	testResumeState := func(test string, didResume bool) {
    @@ -918,7 +920,7 @@ func testResumption(t *testing.T, version uint16) {
     
     	// An old session ticket is replaced with a ticket encrypted with a fresh key.
     	ticket = getTicket()
    -	serverConfig.Time = func() time.Time { return time.Now().Add(24*time.Hour + time.Minute) }
    +	serverConfig.Time = func() time.Time { return testTime().Add(24*time.Hour + time.Minute) }
     	testResumeState("ResumeWithOldTicket", true)
     	if bytes.Equal(ticket, getTicket()) {
     		t.Fatal("old first ticket matches the fresh one")
    @@ -926,13 +928,13 @@ func testResumption(t *testing.T, version uint16) {
     
     	// Once the session master secret is expired, a full handshake should occur.
     	ticket = getTicket()
    -	serverConfig.Time = func() time.Time { return time.Now().Add(24*8*time.Hour + time.Minute) }
    +	serverConfig.Time = func() time.Time { return testTime().Add(24*8*time.Hour + time.Minute) }
     	testResumeState("ResumeWithExpiredTicket", false)
     	if bytes.Equal(ticket, getTicket()) {
     		t.Fatal("expired first ticket matches the fresh one")
     	}
     
    -	serverConfig.Time = func() time.Time { return time.Now() } // reset the time back
    +	serverConfig.Time = testTime // reset the time back
     	key1 := randomKey()
     	serverConfig.SetSessionTicketKeys([][32]byte{key1})
     
    @@ -949,11 +951,11 @@ func testResumption(t *testing.T, version uint16) {
     	testResumeState("KeyChangeFinish", true)
     
     	// Age the session ticket a bit, but not yet expired.
    -	serverConfig.Time = func() time.Time { return time.Now().Add(24*time.Hour + time.Minute) }
    +	serverConfig.Time = func() time.Time { return testTime().Add(24*time.Hour + time.Minute) }
     	testResumeState("OldSessionTicket", true)
     	ticket = getTicket()
     	// Expire the session ticket, which would force a full handshake.
    -	serverConfig.Time = func() time.Time { return time.Now().Add(24*8*time.Hour + time.Minute) }
    +	serverConfig.Time = func() time.Time { return testTime().Add(24*8*time.Hour + 2*time.Minute) }
     	testResumeState("ExpiredSessionTicket", false)
     	if bytes.Equal(ticket, getTicket()) {
     		t.Fatal("new ticket wasn't provided after old ticket expired")
    @@ -961,7 +963,7 @@ func testResumption(t *testing.T, version uint16) {
     
     	// Age the session ticket a bit at a time, but don't expire it.
     	d := 0 * time.Hour
    -	serverConfig.Time = func() time.Time { return time.Now().Add(d) }
    +	serverConfig.Time = func() time.Time { return testTime().Add(d) }
     	deleteTicket()
     	testResumeState("GetFreshSessionTicket", false)
     	for i := 0; i < 13; i++ {
    @@ -972,7 +974,7 @@ func testResumption(t *testing.T, version uint16) {
     	// handshake occurs for TLS 1.2. Resumption should still occur for
     	// TLS 1.3 since the client should be using a fresh ticket sent over
     	// by the server.
    -	d += 12 * time.Hour
    +	d += 12*time.Hour + time.Minute
     	if version == VersionTLS13 {
     		testResumeState("ExpiredSessionTicket", true)
     	} else {
    @@ -988,6 +990,7 @@ func testResumption(t *testing.T, version uint16) {
     		MaxVersion:   version,
     		CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384},
     		Certificates: testCertificates,
    +		Time:         testTime,
     	}
     	serverConfig.SetSessionTicketKeys([][32]byte{key2})
     
    @@ -1013,6 +1016,7 @@ func testResumption(t *testing.T, version uint16) {
     			CurvePreferences: []CurveID{CurveP521, CurveP384, CurveP256},
     			MaxVersion:       version,
     			Certificates:     testCertificates,
    +			Time:             testTime,
     		}
     		testResumeState("InitialHandshake", false)
     		testResumeState("WithHelloRetryRequest", true)
    @@ -1022,6 +1026,7 @@ func testResumption(t *testing.T, version uint16) {
     			MaxVersion:   version,
     			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384},
     			Certificates: testCertificates,
    +			Time:         testTime,
     		}
     	}
     
    @@ -1743,6 +1748,7 @@ func testVerifyConnection(t *testing.T, version uint16) {
     		serverConfig := &Config{
     			MaxVersion:   version,
     			Certificates: testCertificates,
    +			Time:         testTime,
     			ClientCAs:    rootCAs,
     			NextProtos:   []string{"protocol1"},
     		}
    @@ -1756,6 +1762,7 @@ func testVerifyConnection(t *testing.T, version uint16) {
     			RootCAs:            rootCAs,
     			ServerName:         "example.golang",
     			Certificates:       testCertificates,
    +			Time:               testTime,
     			NextProtos:         []string{"protocol1"},
     		}
     		test.configureClient(clientConfig, &clientCalled)
    @@ -1799,8 +1806,6 @@ func testVerifyPeerCertificate(t *testing.T, version uint16) {
     	rootCAs := x509.NewCertPool()
     	rootCAs.AddCert(issuer)
     
    -	now := func() time.Time { return time.Unix(1476984729, 0) }
    -
     	sentinelErr := errors.New("TestVerifyPeerCertificate")
     
     	verifyPeerCertificateCallback := func(called *bool, rawCerts [][]byte, validatedChains [][]*x509.Certificate) error {
    @@ -2046,7 +2051,7 @@ func testVerifyPeerCertificate(t *testing.T, version uint16) {
     			config.ServerName = "example.golang"
     			config.ClientAuth = RequireAndVerifyClientCert
     			config.ClientCAs = rootCAs
    -			config.Time = now
    +			config.Time = testTime
     			config.MaxVersion = version
     			config.Certificates = make([]Certificate, 1)
     			config.Certificates[0].Certificate = [][]byte{testRSA2048Certificate}
    @@ -2064,7 +2069,7 @@ func testVerifyPeerCertificate(t *testing.T, version uint16) {
     		config.Certificates = []Certificate{{Certificate: [][]byte{testRSA2048Certificate}, PrivateKey: testRSA2048PrivateKey}}
     		config.ServerName = "example.golang"
     		config.RootCAs = rootCAs
    -		config.Time = now
    +		config.Time = testTime
     		config.MaxVersion = version
     		test.configureClient(config, &clientCalled)
     		clientErr := Client(c, config).Handshake()
    @@ -2379,7 +2384,7 @@ func testGetClientCertificate(t *testing.T, version uint16) {
     		serverConfig.RootCAs = x509.NewCertPool()
     		serverConfig.RootCAs.AddCert(issuer)
     		serverConfig.ClientCAs = serverConfig.RootCAs
    -		serverConfig.Time = func() time.Time { return time.Unix(1476984729, 0) }
    +		serverConfig.Time = testTime
     		serverConfig.MaxVersion = version
     
     		clientConfig := testConfig.Clone()
    @@ -2562,6 +2567,7 @@ func testResumptionKeepsOCSPAndSCT(t *testing.T, ver uint16) {
     		ClientSessionCache: NewLRUClientSessionCache(32),
     		ServerName:         "example.golang",
     		RootCAs:            roots,
    +		Time:               testTime,
     	}
     	serverConfig := testConfig.Clone()
     	serverConfig.Certificates = []Certificate{{Certificate: [][]byte{testRSA2048Certificate}, PrivateKey: testRSA2048PrivateKey}}
    diff --git a/src/crypto/tls/handshake_server_test.go b/src/crypto/tls/handshake_server_test.go
    index 29a802d54b2dda..f533023afba5b9 100644
    --- a/src/crypto/tls/handshake_server_test.go
    +++ b/src/crypto/tls/handshake_server_test.go
    @@ -519,6 +519,7 @@ func testCrossVersionResume(t *testing.T, version uint16) {
     	serverConfig := &Config{
     		CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
     		Certificates: testConfig.Certificates,
    +		Time:         testTime,
     	}
     	clientConfig := &Config{
     		CipherSuites:       []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
    @@ -526,6 +527,7 @@ func testCrossVersionResume(t *testing.T, version uint16) {
     		ClientSessionCache: NewLRUClientSessionCache(1),
     		ServerName:         "servername",
     		MinVersion:         VersionTLS12,
    +		Time:               testTime,
     	}
     
     	// Establish a session at TLS 1.3.
    diff --git a/src/crypto/tls/handshake_test.go b/src/crypto/tls/handshake_test.go
    index 5a9c24fb83ee6a..ea8ac6fc837ae7 100644
    --- a/src/crypto/tls/handshake_test.go
    +++ b/src/crypto/tls/handshake_test.go
    @@ -522,6 +522,11 @@ func fromHex(s string) []byte {
     	return b
     }
     
    +// testTime is 2016-10-20T17:32:09.000Z, which is within the validity period of
    +// [testRSACertificate], [testRSACertificateIssuer], [testRSA2048Certificate],
    +// [testRSA2048CertificateIssuer], and [testECDSACertificate].
    +var testTime = func() time.Time { return time.Unix(1476984729, 0) }
    +
     var testRSACertificate = fromHex("3082024b308201b4a003020102020900e8f09d3fe25beaa6300d06092a864886f70d01010b0500301f310b3009060355040a1302476f3110300e06035504031307476f20526f6f74301e170d3136303130313030303030305a170d3235303130313030303030305a301a310b3009060355040a1302476f310b300906035504031302476f30819f300d06092a864886f70d010101050003818d0030818902818100db467d932e12270648bc062821ab7ec4b6a25dfe1e5245887a3647a5080d92425bc281c0be97799840fb4f6d14fd2b138bc2a52e67d8d4099ed62238b74a0b74732bc234f1d193e596d9747bf3589f6c613cc0b041d4d92b2b2423775b1c3bbd755dce2054cfa163871d1e24c4f31d1a508baab61443ed97a77562f414c852d70203010001a38193308190300e0603551d0f0101ff0404030205a0301d0603551d250416301406082b0601050507030106082b06010505070302300c0603551d130101ff0402300030190603551d0e041204109f91161f43433e49a6de6db680d79f60301b0603551d230414301280104813494d137e1631bba301d5acab6e7b30190603551d1104123010820e6578616d706c652e676f6c616e67300d06092a864886f70d01010b0500038181009d30cc402b5b50a061cbbae55358e1ed8328a9581aa938a495a1ac315a1a84663d43d32dd90bf297dfd320643892243a00bccf9c7db74020015faad3166109a276fd13c3cce10c5ceeb18782f16c04ed73bbb343778d0c1cf10fa1d8408361c94c722b9daedb4606064df4c1b33ec0d1bd42d4dbfe3d1360845c21d33be9fae7")
     
     var testRSACertificateIssuer = fromHex("3082021930820182a003020102020900ca5e4e811a965964300d06092a864886f70d01010b0500301f310b3009060355040a1302476f3110300e06035504031307476f20526f6f74301e170d3136303130313030303030305a170d3235303130313030303030305a301f310b3009060355040a1302476f3110300e06035504031307476f20526f6f7430819f300d06092a864886f70d010101050003818d0030818902818100d667b378bb22f34143b6cd2008236abefaf2852adf3ab05e01329e2c14834f5105df3f3073f99dab5442d45ee5f8f57b0111c8cb682fbb719a86944eebfffef3406206d898b8c1b1887797c9c5006547bb8f00e694b7a063f10839f269f2c34fff7a1f4b21fbcd6bfdfb13ac792d1d11f277b5c5b48600992203059f2a8f8cc50203010001a35d305b300e0603551d0f0101ff040403020204301d0603551d250416301406082b0601050507030106082b06010505070302300f0603551d130101ff040530030101ff30190603551d0e041204104813494d137e1631bba301d5acab6e7b300d06092a864886f70d01010b050003818100c1154b4bab5266221f293766ae4138899bd4c5e36b13cee670ceeaa4cbdf4f6679017e2fe649765af545749fe4249418a56bd38a04b81e261f5ce86b8d5c65413156a50d12449554748c59a30c515bc36a59d38bddf51173e899820b282e40aa78c806526fd184fb6b4cf186ec728edffa585440d2b3225325f7ab580e87dd76")
    diff --git a/src/crypto/tls/tls_test.go b/src/crypto/tls/tls_test.go
    index 51cd2b91bdb754..76a9a222a94bd7 100644
    --- a/src/crypto/tls/tls_test.go
    +++ b/src/crypto/tls/tls_test.go
    @@ -1158,8 +1158,6 @@ func TestConnectionState(t *testing.T) {
     	rootCAs := x509.NewCertPool()
     	rootCAs.AddCert(issuer)
     
    -	now := func() time.Time { return time.Unix(1476984729, 0) }
    -
     	const alpnProtocol = "golang"
     	const serverName = "example.golang"
     	var scts = [][]byte{[]byte("dummy sct 1"), []byte("dummy sct 2")}
    @@ -1175,7 +1173,7 @@ func TestConnectionState(t *testing.T) {
     		}
     		t.Run(name, func(t *testing.T) {
     			config := &Config{
    -				Time:         now,
    +				Time:         testTime,
     				Rand:         zeroSource{},
     				Certificates: make([]Certificate, 1),
     				MaxVersion:   v,
    @@ -1810,7 +1808,7 @@ func testVerifyCertificates(t *testing.T, version uint16) {
     			var serverVerifyPeerCertificates, clientVerifyPeerCertificates bool
     
     			clientConfig := testConfig.Clone()
    -			clientConfig.Time = func() time.Time { return time.Unix(1476984729, 0) }
    +			clientConfig.Time = testTime
     			clientConfig.MaxVersion = version
     			clientConfig.MinVersion = version
     			clientConfig.RootCAs = rootCAs
    
    From 847c357bbb819f8f042b715d6ccdaa8fd89c305d Mon Sep 17 00:00:00 2001
    From: Sean Liao 
    Date: Sat, 28 Dec 2024 14:25:08 -0500
    Subject: [PATCH 085/397] cmd/go: remove references to gopath-get
    
    Fixes #70912
    
    Change-Id: Id87a13f7c9bf972502d14c9674a27f743b849715
    Reviewed-on: https://go-review.googlesource.com/c/go/+/639155
    Reviewed-by: Sam Thanawalla 
    Reviewed-by: Michael Matloob 
    LUCI-TryBot-Result: Go LUCI 
    Auto-Submit: Sam Thanawalla 
    ---
     src/cmd/go/alldocs.go                   | 11 +----------
     src/cmd/go/internal/help/helpdoc.go     |  6 +-----
     src/cmd/go/internal/modget/get.go       |  5 -----
     src/cmd/go/testdata/script/mod_help.txt |  2 +-
     4 files changed, 3 insertions(+), 21 deletions(-)
    
    diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go
    index 548cf171ca7840..910699caced7e8 100644
    --- a/src/cmd/go/alldocs.go
    +++ b/src/cmd/go/alldocs.go
    @@ -739,11 +739,6 @@
     //
     // For more about specifying packages, see 'go help packages'.
     //
    -// This text describes the behavior of get using modules to manage source
    -// code and dependencies. If instead the go command is running in GOPATH
    -// mode, the details of get's flags and effects change, as does 'go help get'.
    -// See 'go help gopath-get'.
    -//
     // See also: go build, go install, go clean, go mod.
     //
     // # Compile and install packages and dependencies
    @@ -2974,11 +2969,7 @@
     // same meta tag and then git clone https://code.org/r/p/exproj into
     // GOPATH/src/example.org.
     //
    -// When using GOPATH, downloaded packages are written to the first directory
    -// listed in the GOPATH environment variable.
    -// (See 'go help gopath-get' and 'go help gopath'.)
    -//
    -// When using modules, downloaded packages are stored in the module cache.
    +// Downloaded packages are stored in the module cache.
     // See https://golang.org/ref/mod#module-cache.
     //
     // When using modules, an additional variant of the go-import meta tag is
    diff --git a/src/cmd/go/internal/help/helpdoc.go b/src/cmd/go/internal/help/helpdoc.go
    index 3e7a1cbc75dd43..7e19ba93d2a83d 100644
    --- a/src/cmd/go/internal/help/helpdoc.go
    +++ b/src/cmd/go/internal/help/helpdoc.go
    @@ -270,11 +270,7 @@ the go tool will verify that https://example.org/?go-get=1 contains the
     same meta tag and then git clone https://code.org/r/p/exproj into
     GOPATH/src/example.org.
     
    -When using GOPATH, downloaded packages are written to the first directory
    -listed in the GOPATH environment variable.
    -(See 'go help gopath-get' and 'go help gopath'.)
    -
    -When using modules, downloaded packages are stored in the module cache.
    +Downloaded packages are stored in the module cache.
     See https://golang.org/ref/mod#module-cache.
     
     When using modules, an additional variant of the go-import meta tag is
    diff --git a/src/cmd/go/internal/modget/get.go b/src/cmd/go/internal/modget/get.go
    index 159a8569114207..48ae12fe53a783 100644
    --- a/src/cmd/go/internal/modget/get.go
    +++ b/src/cmd/go/internal/modget/get.go
    @@ -125,11 +125,6 @@ suggested Go toolchain, see https://go.dev/doc/toolchain.
     
     For more about specifying packages, see 'go help packages'.
     
    -This text describes the behavior of get using modules to manage source
    -code and dependencies. If instead the go command is running in GOPATH
    -mode, the details of get's flags and effects change, as does 'go help get'.
    -See 'go help gopath-get'.
    -
     See also: go build, go install, go clean, go mod.
     	`,
     }
    diff --git a/src/cmd/go/testdata/script/mod_help.txt b/src/cmd/go/testdata/script/mod_help.txt
    index b5cd30c5219e88..7cb808ff237500 100644
    --- a/src/cmd/go/testdata/script/mod_help.txt
    +++ b/src/cmd/go/testdata/script/mod_help.txt
    @@ -3,4 +3,4 @@ env GO111MODULE=on
     # go help get shows usage for get
     go help get
     stdout 'usage: go get'
    -stdout 'get using modules to manage source'
    \ No newline at end of file
    +stdout 'updates go.mod to require those versions'
    
    From a63aee4955d8236f657a94101d6a703be97e98ec Mon Sep 17 00:00:00 2001
    From: Austin Clements 
    Date: Fri, 27 Dec 2024 13:09:25 -0500
    Subject: [PATCH 086/397] cmd/go: improve GOCACHEPROG types documentation
    
    This is in preparation for adding a "go help" topic for GOCACHEPROG.
    
    Updates #71032
    Updates #59719
    
    Change-Id: I9dbbe56fa328dffe89207b5b41a0f37afd51e2b5
    Reviewed-on: https://go-review.googlesource.com/c/go/+/638566
    LUCI-TryBot-Result: Go LUCI 
    Auto-Submit: Austin Clements 
    Reviewed-by: Michael Matloob 
    ---
     src/cmd/go/internal/cache/cache.go | 12 ++--
     src/cmd/go/internal/cache/prog.go  | 89 ++++++++++++++++++++++--------
     2 files changed, 72 insertions(+), 29 deletions(-)
    
    diff --git a/src/cmd/go/internal/cache/cache.go b/src/cmd/go/internal/cache/cache.go
    index 98bed2a595e1ba..c9acd8782db964 100644
    --- a/src/cmd/go/internal/cache/cache.go
    +++ b/src/cmd/go/internal/cache/cache.go
    @@ -38,8 +38,8 @@ type Cache interface {
     	// Get returns the cache entry for the provided ActionID.
     	// On miss, the error type should be of type *entryNotFoundError.
     	//
    -	// After a success call to Get, OutputFile(Entry.OutputID) must
    -	// exist on disk for until Close is called (at the end of the process).
    +	// After a successful call to Get, OutputFile(Entry.OutputID) must
    +	// exist on disk until Close is called (at the end of the process).
     	Get(ActionID) (Entry, error)
     
     	// Put adds an item to the cache.
    @@ -50,14 +50,14 @@ type Cache interface {
     	// As a special case, if the ReadSeeker is of type noVerifyReadSeeker,
     	// the verification from GODEBUG=goverifycache=1 is skipped.
     	//
    -	// After a success call to Get, OutputFile(Entry.OutputID) must
    -	// exist on disk for until Close is called (at the end of the process).
    +	// After a successful call to Put, OutputFile(OutputID) must
    +	// exist on disk until Close is called (at the end of the process).
     	Put(ActionID, io.ReadSeeker) (_ OutputID, size int64, _ error)
     
     	// Close is called at the end of the go process. Implementations can do
     	// cache cleanup work at this phase, or wait for and report any errors from
    -	// background cleanup work started earlier. Any cache trimming should in one
    -	// process should not violate cause the invariants of this interface to be
    +	// background cleanup work started earlier. Any cache trimming in one
    +	// process should not cause the invariants of this interface to be
     	// violated in another process. Namely, a cache trim from one process should
     	// not delete an ObjectID from disk that was recently Get or Put from
     	// another process. As a rule of thumb, don't trim things used in the last
    diff --git a/src/cmd/go/internal/cache/prog.go b/src/cmd/go/internal/cache/prog.go
    index e09620bac86c48..b657497417b3d0 100644
    --- a/src/cmd/go/internal/cache/prog.go
    +++ b/src/cmd/go/internal/cache/prog.go
    @@ -63,36 +63,74 @@ type ProgCache struct {
     	writeMu sync.Mutex
     }
     
    +// The following types define the protocol for a GOCACHEPROG program.
    +//
    +// By default, the go command manages a build cache stored in the file system
    +// itself. GOCACHEPROG can be set to the name of a command (with optional
    +// space-separated flags) that implements the go command build cache externally.
    +// This permits defining a different cache policy.
    +//
    +// The go command will start the GOCACHEPROG as a subprocess and communicate
    +// with it via JSON messages over stdin/stdout. The subprocess's stderr will be
    +// connected to the go command's stderr.
    +//
    +// The subprocess should immediately send a [ProgResponse] with its capabilities.
    +// After that, the go command will send a stream of [ProgRequest] messages and the
    +// subprocess should reply to each [ProgRequest] with a [ProgResponse] message.
    +
     // ProgCmd is a command that can be issued to a child process.
     //
    -// If the interface needs to grow, we can add new commands or new versioned
    -// commands like "get2".
    +// If the interface needs to grow, the go command can add new commands or new
    +// versioned commands like "get2" in the future. The initial [ProgResponse] from
    +// the child process indicates which commands it supports.
     type ProgCmd string
     
     const (
    -	cmdGet   = ProgCmd("get")
    -	cmdPut   = ProgCmd("put")
    +	// cmdPut tells the cache program to store an object in the cache.
    +	//
    +	// [ProgRequest.ActionID] is the cache key of this object. The cache should
    +	// store [ProgRequest.OutputID] and [ProgRequest.Body] under this key for a
    +	// later "get" request. It must also store the Body in a file in the local
    +	// file system and return the path to that file in [ProgResponse.DiskPath],
    +	// which must exist at least until a "close" request.
    +	cmdPut = ProgCmd("put")
    +
    +	// cmdGet tells the cache program to retrieve an object from the cache.
    +	//
    +	// [ProgRequest.ActionID] specifies the key of the object to get. If the
    +	// cache does not contain this object, it should set [ProgResponse.Miss] to
    +	// true. Otherwise, it should populate the fields of [ProgResponse],
    +	// including setting [ProgResponse.OutputID] to the OutputID of the original
    +	// "put" request and [ProgResponse.DiskPath] to the path of a local file
    +	// containing the Body of the original "put" request. That file must
    +	// continue to exist at least until a "close" request.
    +	cmdGet = ProgCmd("get")
    +
    +	// cmdClose requests that the cache program exit gracefully.
    +	//
    +	// The cache program should reply to this request and then exit
    +	// (thus closing its stdout).
     	cmdClose = ProgCmd("close")
     )
     
    -// ProgRequest is the JSON-encoded message that's sent from cmd/go to
    -// the GOCACHEPROG child process over stdin. Each JSON object is on its
    -// own line. A ProgRequest of Type "put" with BodySize > 0 will be followed
    -// by a line containing a base64-encoded JSON string literal of the body.
    +// ProgRequest is the JSON-encoded message that's sent from the go command to
    +// the GOCACHEPROG child process over stdin. Each JSON object is on its own
    +// line. A ProgRequest of Type "put" with BodySize > 0 will be followed by a
    +// line containing a base64-encoded JSON string literal of the body.
     type ProgRequest struct {
     	// ID is a unique number per process across all requests.
     	// It must be echoed in the ProgResponse from the child.
     	ID int64
     
     	// Command is the type of request.
    -	// The cmd/go tool will only send commands that were declared
    +	// The go command will only send commands that were declared
     	// as supported by the child.
     	Command ProgCmd
     
    -	// ActionID is non-nil for get and puts.
    +	// ActionID is the cache key for "put" and "get" requests.
     	ActionID []byte `json:",omitempty"` // or nil if not used
     
    -	// OutputID is set for Type "put".
    +	// OutputID is stored with the body for "put" requests.
     	//
     	// Prior to Go 1.24, when GOCACHEPROG was still an experiment, this was
     	// accidentally named ObjectID. It was renamed to OutputID in Go 1.24.
    @@ -118,11 +156,11 @@ type ProgRequest struct {
     	ObjectID []byte `json:",omitempty"`
     }
     
    -// ProgResponse is the JSON response from the child process to cmd/go.
    +// ProgResponse is the JSON response from the child process to the go command.
     //
     // With the exception of the first protocol message that the child writes to its
     // stdout with ID==0 and KnownCommands populated, these are only sent in
    -// response to a ProgRequest from cmd/go.
    +// response to a ProgRequest from the go command.
     //
     // ProgResponses can be sent in any order. The ID must match the request they're
     // replying to.
    @@ -134,21 +172,22 @@ type ProgResponse struct {
     	// writes to stdout on startup (with ID==0). It includes the
     	// ProgRequest.Command types that are supported by the program.
     	//
    -	// This lets us extend the protocol gracefully over time (adding "get2",
    -	// etc), or fail gracefully when needed. It also lets us verify the program
    -	// wants to be a cache helper.
    +	// This lets the go command extend the protocol gracefully over time (adding
    +	// "get2", etc), or fail gracefully when needed. It also lets the go command
    +	// verify the program wants to be a cache helper.
     	KnownCommands []ProgCmd `json:",omitempty"`
     
    -	// For Get requests.
    +	// For "get" requests.
     
     	Miss     bool       `json:",omitempty"` // cache miss
    -	OutputID []byte     `json:",omitempty"`
    -	Size     int64      `json:",omitempty"` // in bytes
    -	Time     *time.Time `json:",omitempty"` // an Entry.Time; when the object was added to the docs
    +	OutputID []byte     `json:",omitempty"` // the ObjectID stored with the body
    +	Size     int64      `json:",omitempty"` // body size in bytes
    +	Time     *time.Time `json:",omitempty"` // when the object was put in the cache (optional; used for cache expiration)
    +
    +	// For "get" and "put" requests.
     
    -	// DiskPath is the absolute path on disk of the ObjectID corresponding
    -	// a "get" request's ActionID (on cache hit) or a "put" request's
    -	// provided ObjectID.
    +	// DiskPath is the absolute path on disk of the body corresponding to a
    +	// "get" (on cache hit) or "put" request's ActionID.
     	DiskPath string `json:",omitempty"`
     }
     
    @@ -183,6 +222,8 @@ func startCacheProg(progAndArgs string, fuzzDirCache Cache) Cache {
     		base.Fatalf("StdinPipe to GOCACHEPROG: %v", err)
     	}
     	cmd.Stderr = os.Stderr
    +	// On close, we cancel the context. Rather than killing the helper,
    +	// close its stdin.
     	cmd.Cancel = in.Close
     
     	if err := cmd.Start(); err != nil {
    @@ -435,7 +476,9 @@ func (c *ProgCache) Close() error {
     	if c.can[cmdClose] {
     		_, err = c.send(c.ctx, &ProgRequest{Command: cmdClose})
     	}
    +	// Cancel the context, which will close the helper's stdin.
     	c.ctxCancel()
    +	// Wait until the helper closes its stdout.
     	<-c.readLoopDone
     	return err
     }
    
    From 858a0e9dfd10ac94a0b9de4429749f0cb99e8cb8 Mon Sep 17 00:00:00 2001
    From: Roland Shoemaker 
    Date: Mon, 30 Dec 2024 10:36:55 -0800
    Subject: [PATCH 087/397] crypto/tls: properly return ECH retry configs
    
    When ECH is rejected, properly take retry configs from the encrypted
    extensions message. Also fix the bogo shim to properly test for this
    behavior.
    
    We should properly map the full BoringSSL -> Go errors so that we don't
    run into a similar failure in the future, but this is left for a follow
    up CL.
    
    Fixes #70915
    
    Change-Id: Icc1878ff6f87df059e7b83e0a431f50f1fea833c
    Reviewed-on: https://go-review.googlesource.com/c/go/+/638583
    Reviewed-by: Damien Neil 
    Reviewed-by: Filippo Valsorda 
    LUCI-TryBot-Result: Go LUCI 
    ---
     src/crypto/tls/bogo_config.json          |  5 ++++-
     src/crypto/tls/handshake_client.go       |  1 +
     src/crypto/tls/handshake_client_tls13.go | 16 ++++++++--------
     3 files changed, 13 insertions(+), 9 deletions(-)
    
    diff --git a/src/crypto/tls/bogo_config.json b/src/crypto/tls/bogo_config.json
    index 1c313ec81e160f..32969a3fb5a865 100644
    --- a/src/crypto/tls/bogo_config.json
    +++ b/src/crypto/tls/bogo_config.json
    @@ -246,5 +246,8 @@
             25,
             29,
             4588
    -    ]
    +    ],
    +    "ErrorMap": {
    +        ":ECH_REJECTED:": "tls: server rejected ECH"
    +    }
     }
    diff --git a/src/crypto/tls/handshake_client.go b/src/crypto/tls/handshake_client.go
    index 3bf703e4b93b22..38bd417a0dca72 100644
    --- a/src/crypto/tls/handshake_client.go
    +++ b/src/crypto/tls/handshake_client.go
    @@ -260,6 +260,7 @@ type echClientContext struct {
     	kdfID           uint16
     	aeadID          uint16
     	echRejected     bool
    +	retryConfigs    []byte
     }
     
     func (c *Conn) clientHandshake(ctx context.Context) (err error) {
    diff --git a/src/crypto/tls/handshake_client_tls13.go b/src/crypto/tls/handshake_client_tls13.go
    index 38c6025db74ee8..c0396e75796add 100644
    --- a/src/crypto/tls/handshake_client_tls13.go
    +++ b/src/crypto/tls/handshake_client_tls13.go
    @@ -85,7 +85,6 @@ func (hs *clientHandshakeStateTLS13) handshake() error {
     		}
     	}
     
    -	var echRetryConfigList []byte
     	if hs.echContext != nil {
     		confTranscript := cloneHash(hs.echContext.innerTranscript, hs.suite.hash)
     		confTranscript.Write(hs.serverHello.original[:30])
    @@ -114,9 +113,6 @@ func (hs *clientHandshakeStateTLS13) handshake() error {
     			}
     		} else {
     			hs.echContext.echRejected = true
    -			// If the server sent us retry configs, we'll return these to
    -			// the user so they can update their Config.
    -			echRetryConfigList = hs.serverHello.encryptedClientHello
     		}
     	}
     
    @@ -155,7 +151,7 @@ func (hs *clientHandshakeStateTLS13) handshake() error {
     
     	if hs.echContext != nil && hs.echContext.echRejected {
     		c.sendAlert(alertECHRequired)
    -		return &ECHRejectionError{echRetryConfigList}
    +		return &ECHRejectionError{hs.echContext.retryConfigs}
     	}
     
     	c.isHandshakeComplete.Store(true)
    @@ -601,9 +597,13 @@ func (hs *clientHandshakeStateTLS13) readServerParameters() error {
     			return errors.New("tls: server accepted 0-RTT with the wrong ALPN")
     		}
     	}
    -	if hs.echContext != nil && !hs.echContext.echRejected && encryptedExtensions.echRetryConfigs != nil {
    -		c.sendAlert(alertUnsupportedExtension)
    -		return errors.New("tls: server sent encrypted client hello retry configs after accepting encrypted client hello")
    +	if hs.echContext != nil {
    +		if hs.echContext.echRejected {
    +			hs.echContext.retryConfigs = encryptedExtensions.echRetryConfigs
    +		} else if encryptedExtensions.echRetryConfigs != nil {
    +			c.sendAlert(alertUnsupportedExtension)
    +			return errors.New("tls: server sent encrypted client hello retry configs after accepting encrypted client hello")
    +		}
     	}
     
     	return nil
    
    From 20da34c6d2f6a4d03304f55a6d6f1418ca11b091 Mon Sep 17 00:00:00 2001
    From: Austin Clements 
    Date: Fri, 27 Dec 2024 13:27:21 -0500
    Subject: [PATCH 088/397] cmd/go: move GOCACHEPROG protocol types to their own
     package
    
    This is a step toward making it easy to point to them in
    documentation. The other option is that we copy-paste all of these
    type definitions wholesale, which seems ridiculous.
    
    Updates #71032
    Updates #59719
    
    Change-Id: I7117e03308ae0adc721ed7a57792c33ba68ce827
    Reviewed-on: https://go-review.googlesource.com/c/go/+/638995
    Auto-Submit: Austin Clements 
    LUCI-TryBot-Result: Go LUCI 
    Reviewed-by: Michael Matloob 
    ---
     src/cmd/go/internal/cache/prog.go          | 163 +++------------------
     src/cmd/go/internal/cacheprog/cacheprog.go | 137 +++++++++++++++++
     2 files changed, 155 insertions(+), 145 deletions(-)
     create mode 100644 src/cmd/go/internal/cacheprog/cacheprog.go
    
    diff --git a/src/cmd/go/internal/cache/prog.go b/src/cmd/go/internal/cache/prog.go
    index b657497417b3d0..124128d172f107 100644
    --- a/src/cmd/go/internal/cache/prog.go
    +++ b/src/cmd/go/internal/cache/prog.go
    @@ -7,6 +7,7 @@ package cache
     import (
     	"bufio"
     	"cmd/go/internal/base"
    +	"cmd/go/internal/cacheprog"
     	"cmd/internal/quoted"
     	"context"
     	"crypto/sha256"
    @@ -38,7 +39,7 @@ type ProgCache struct {
     
     	// can are the commands that the child process declared that it supports.
     	// This is effectively the versioning mechanism.
    -	can map[ProgCmd]bool
    +	can map[cacheprog.ProgCmd]bool
     
     	// fuzzDirCache is another Cache implementation to use for the FuzzDir
     	// method. In practice this is the default GOCACHE disk-based
    @@ -55,7 +56,7 @@ type ProgCache struct {
     
     	mu         sync.Mutex // guards following fields
     	nextID     int64
    -	inFlight   map[int64]chan<- *ProgResponse
    +	inFlight   map[int64]chan<- *cacheprog.ProgResponse
     	outputFile map[OutputID]string // object => abs path on disk
     
     	// writeMu serializes writing to the child process.
    @@ -63,134 +64,6 @@ type ProgCache struct {
     	writeMu sync.Mutex
     }
     
    -// The following types define the protocol for a GOCACHEPROG program.
    -//
    -// By default, the go command manages a build cache stored in the file system
    -// itself. GOCACHEPROG can be set to the name of a command (with optional
    -// space-separated flags) that implements the go command build cache externally.
    -// This permits defining a different cache policy.
    -//
    -// The go command will start the GOCACHEPROG as a subprocess and communicate
    -// with it via JSON messages over stdin/stdout. The subprocess's stderr will be
    -// connected to the go command's stderr.
    -//
    -// The subprocess should immediately send a [ProgResponse] with its capabilities.
    -// After that, the go command will send a stream of [ProgRequest] messages and the
    -// subprocess should reply to each [ProgRequest] with a [ProgResponse] message.
    -
    -// ProgCmd is a command that can be issued to a child process.
    -//
    -// If the interface needs to grow, the go command can add new commands or new
    -// versioned commands like "get2" in the future. The initial [ProgResponse] from
    -// the child process indicates which commands it supports.
    -type ProgCmd string
    -
    -const (
    -	// cmdPut tells the cache program to store an object in the cache.
    -	//
    -	// [ProgRequest.ActionID] is the cache key of this object. The cache should
    -	// store [ProgRequest.OutputID] and [ProgRequest.Body] under this key for a
    -	// later "get" request. It must also store the Body in a file in the local
    -	// file system and return the path to that file in [ProgResponse.DiskPath],
    -	// which must exist at least until a "close" request.
    -	cmdPut = ProgCmd("put")
    -
    -	// cmdGet tells the cache program to retrieve an object from the cache.
    -	//
    -	// [ProgRequest.ActionID] specifies the key of the object to get. If the
    -	// cache does not contain this object, it should set [ProgResponse.Miss] to
    -	// true. Otherwise, it should populate the fields of [ProgResponse],
    -	// including setting [ProgResponse.OutputID] to the OutputID of the original
    -	// "put" request and [ProgResponse.DiskPath] to the path of a local file
    -	// containing the Body of the original "put" request. That file must
    -	// continue to exist at least until a "close" request.
    -	cmdGet = ProgCmd("get")
    -
    -	// cmdClose requests that the cache program exit gracefully.
    -	//
    -	// The cache program should reply to this request and then exit
    -	// (thus closing its stdout).
    -	cmdClose = ProgCmd("close")
    -)
    -
    -// ProgRequest is the JSON-encoded message that's sent from the go command to
    -// the GOCACHEPROG child process over stdin. Each JSON object is on its own
    -// line. A ProgRequest of Type "put" with BodySize > 0 will be followed by a
    -// line containing a base64-encoded JSON string literal of the body.
    -type ProgRequest struct {
    -	// ID is a unique number per process across all requests.
    -	// It must be echoed in the ProgResponse from the child.
    -	ID int64
    -
    -	// Command is the type of request.
    -	// The go command will only send commands that were declared
    -	// as supported by the child.
    -	Command ProgCmd
    -
    -	// ActionID is the cache key for "put" and "get" requests.
    -	ActionID []byte `json:",omitempty"` // or nil if not used
    -
    -	// OutputID is stored with the body for "put" requests.
    -	//
    -	// Prior to Go 1.24, when GOCACHEPROG was still an experiment, this was
    -	// accidentally named ObjectID. It was renamed to OutputID in Go 1.24.
    -	OutputID []byte `json:",omitempty"` // or nil if not used
    -
    -	// Body is the body for "put" requests. It's sent after the JSON object
    -	// as a base64-encoded JSON string when BodySize is non-zero.
    -	// It's sent as a separate JSON value instead of being a struct field
    -	// send in this JSON object so large values can be streamed in both directions.
    -	// The base64 string body of a ProgRequest will always be written
    -	// immediately after the JSON object and a newline.
    -	Body io.Reader `json:"-"`
    -
    -	// BodySize is the number of bytes of Body. If zero, the body isn't written.
    -	BodySize int64 `json:",omitempty"`
    -
    -	// ObjectID is the accidental spelling of OutputID that was used prior to Go
    -	// 1.24.
    -	//
    -	// Deprecated: use OutputID. This field is only populated temporarily for
    -	// backwards compatibility with Go 1.23 and earlier when
    -	// GOEXPERIMENT=gocacheprog is set. It will be removed in Go 1.25.
    -	ObjectID []byte `json:",omitempty"`
    -}
    -
    -// ProgResponse is the JSON response from the child process to the go command.
    -//
    -// With the exception of the first protocol message that the child writes to its
    -// stdout with ID==0 and KnownCommands populated, these are only sent in
    -// response to a ProgRequest from the go command.
    -//
    -// ProgResponses can be sent in any order. The ID must match the request they're
    -// replying to.
    -type ProgResponse struct {
    -	ID  int64  // that corresponds to ProgRequest; they can be answered out of order
    -	Err string `json:",omitempty"` // if non-empty, the error
    -
    -	// KnownCommands is included in the first message that cache helper program
    -	// writes to stdout on startup (with ID==0). It includes the
    -	// ProgRequest.Command types that are supported by the program.
    -	//
    -	// This lets the go command extend the protocol gracefully over time (adding
    -	// "get2", etc), or fail gracefully when needed. It also lets the go command
    -	// verify the program wants to be a cache helper.
    -	KnownCommands []ProgCmd `json:",omitempty"`
    -
    -	// For "get" requests.
    -
    -	Miss     bool       `json:",omitempty"` // cache miss
    -	OutputID []byte     `json:",omitempty"` // the ObjectID stored with the body
    -	Size     int64      `json:",omitempty"` // body size in bytes
    -	Time     *time.Time `json:",omitempty"` // when the object was put in the cache (optional; used for cache expiration)
    -
    -	// For "get" and "put" requests.
    -
    -	// DiskPath is the absolute path on disk of the body corresponding to a
    -	// "get" (on cache hit) or "put" request's ActionID.
    -	DiskPath string `json:",omitempty"`
    -}
    -
     // startCacheProg starts the prog binary (with optional space-separated flags)
     // and returns a Cache implementation that talks to it.
     //
    @@ -238,14 +111,14 @@ func startCacheProg(progAndArgs string, fuzzDirCache Cache) Cache {
     		stdout:       out,
     		stdin:        in,
     		bw:           bufio.NewWriter(in),
    -		inFlight:     make(map[int64]chan<- *ProgResponse),
    +		inFlight:     make(map[int64]chan<- *cacheprog.ProgResponse),
     		outputFile:   make(map[OutputID]string),
     		readLoopDone: make(chan struct{}),
     	}
     
     	// Register our interest in the initial protocol message from the child to
     	// us, saying what it can do.
    -	capResc := make(chan *ProgResponse, 1)
    +	capResc := make(chan *cacheprog.ProgResponse, 1)
     	pc.inFlight[0] = capResc
     
     	pc.jenc = json.NewEncoder(pc.bw)
    @@ -260,7 +133,7 @@ func startCacheProg(progAndArgs string, fuzzDirCache Cache) Cache {
     		case <-timer.C:
     			log.Printf("# still waiting for GOCACHEPROG %v ...", prog)
     		case capRes := <-capResc:
    -			can := map[ProgCmd]bool{}
    +			can := map[cacheprog.ProgCmd]bool{}
     			for _, cmd := range capRes.KnownCommands {
     				can[cmd] = true
     			}
    @@ -277,7 +150,7 @@ func (c *ProgCache) readLoop(readLoopDone chan<- struct{}) {
     	defer close(readLoopDone)
     	jd := json.NewDecoder(c.stdout)
     	for {
    -		res := new(ProgResponse)
    +		res := new(cacheprog.ProgResponse)
     		if err := jd.Decode(res); err != nil {
     			if c.closing.Load() {
     				return // quietly
    @@ -302,8 +175,8 @@ func (c *ProgCache) readLoop(readLoopDone chan<- struct{}) {
     	}
     }
     
    -func (c *ProgCache) send(ctx context.Context, req *ProgRequest) (*ProgResponse, error) {
    -	resc := make(chan *ProgResponse, 1)
    +func (c *ProgCache) send(ctx context.Context, req *cacheprog.ProgRequest) (*cacheprog.ProgResponse, error) {
    +	resc := make(chan *cacheprog.ProgResponse, 1)
     	if err := c.writeToChild(req, resc); err != nil {
     		return nil, err
     	}
    @@ -318,7 +191,7 @@ func (c *ProgCache) send(ctx context.Context, req *ProgRequest) (*ProgResponse,
     	}
     }
     
    -func (c *ProgCache) writeToChild(req *ProgRequest, resc chan<- *ProgResponse) (err error) {
    +func (c *ProgCache) writeToChild(req *cacheprog.ProgRequest, resc chan<- *cacheprog.ProgResponse) (err error) {
     	c.mu.Lock()
     	c.nextID++
     	req.ID = c.nextID
    @@ -369,7 +242,7 @@ func (c *ProgCache) writeToChild(req *ProgRequest, resc chan<- *ProgResponse) (e
     }
     
     func (c *ProgCache) Get(a ActionID) (Entry, error) {
    -	if !c.can[cmdGet] {
    +	if !c.can[cacheprog.CmdGet] {
     		// They can't do a "get". Maybe they're a write-only cache.
     		//
     		// TODO(bradfitz,bcmills): figure out the proper error type here. Maybe
    @@ -379,8 +252,8 @@ func (c *ProgCache) Get(a ActionID) (Entry, error) {
     		// error types on the Cache interface.
     		return Entry{}, &entryNotFoundError{}
     	}
    -	res, err := c.send(c.ctx, &ProgRequest{
    -		Command:  cmdGet,
    +	res, err := c.send(c.ctx, &cacheprog.ProgRequest{
    +		Command:  cacheprog.CmdGet,
     		ActionID: a[:],
     	})
     	if err != nil {
    @@ -436,7 +309,7 @@ func (c *ProgCache) Put(a ActionID, file io.ReadSeeker) (_ OutputID, size int64,
     		return OutputID{}, 0, err
     	}
     
    -	if !c.can[cmdPut] {
    +	if !c.can[cacheprog.CmdPut] {
     		// Child is a read-only cache. Do nothing.
     		return out, size, nil
     	}
    @@ -448,8 +321,8 @@ func (c *ProgCache) Put(a ActionID, file io.ReadSeeker) (_ OutputID, size int64,
     		deprecatedValue = out[:]
     	}
     
    -	res, err := c.send(c.ctx, &ProgRequest{
    -		Command:  cmdPut,
    +	res, err := c.send(c.ctx, &cacheprog.ProgRequest{
    +		Command:  cacheprog.CmdPut,
     		ActionID: a[:],
     		OutputID: out[:],
     		ObjectID: deprecatedValue, // TODO(bradfitz): remove in Go 1.25
    @@ -473,8 +346,8 @@ func (c *ProgCache) Close() error {
     	// First write a "close" message to the child so it can exit nicely
     	// and clean up if it wants. Only after that exchange do we cancel
     	// the context that kills the process.
    -	if c.can[cmdClose] {
    -		_, err = c.send(c.ctx, &ProgRequest{Command: cmdClose})
    +	if c.can[cacheprog.CmdClose] {
    +		_, err = c.send(c.ctx, &cacheprog.ProgRequest{Command: cacheprog.CmdClose})
     	}
     	// Cancel the context, which will close the helper's stdin.
     	c.ctxCancel()
    diff --git a/src/cmd/go/internal/cacheprog/cacheprog.go b/src/cmd/go/internal/cacheprog/cacheprog.go
    new file mode 100644
    index 00000000000000..41b1b0d79f94fe
    --- /dev/null
    +++ b/src/cmd/go/internal/cacheprog/cacheprog.go
    @@ -0,0 +1,137 @@
    +// Copyright 2024 The Go Authors. All rights reserved.
    +// Use of this source code is governed by a BSD-style
    +// license that can be found in the LICENSE file.
    +
    +// Package cacheprog defines the protocol for a GOCACHEPROG program.
    +//
    +// By default, the go command manages a build cache stored in the file system
    +// itself. GOCACHEPROG can be set to the name of a command (with optional
    +// space-separated flags) that implements the go command build cache externally.
    +// This permits defining a different cache policy.
    +//
    +// The go command will start the GOCACHEPROG as a subprocess and communicate
    +// with it via JSON messages over stdin/stdout. The subprocess's stderr will be
    +// connected to the go command's stderr.
    +//
    +// The subprocess should immediately send a [ProgResponse] with its capabilities.
    +// After that, the go command will send a stream of [ProgRequest] messages and the
    +// subprocess should reply to each [ProgRequest] with a [ProgResponse] message.
    +package cacheprog
    +
    +import (
    +	"io"
    +	"time"
    +)
    +
    +// ProgCmd is a command that can be issued to a child process.
    +//
    +// If the interface needs to grow, the go command can add new commands or new
    +// versioned commands like "get2" in the future. The initial [ProgResponse] from
    +// the child process indicates which commands it supports.
    +type ProgCmd string
    +
    +const (
    +	// CmdPut tells the cache program to store an object in the cache.
    +	//
    +	// [ProgRequest.ActionID] is the cache key of this object. The cache should
    +	// store [ProgRequest.OutputID] and [ProgRequest.Body] under this key for a
    +	// later "get" request. It must also store the Body in a file in the local
    +	// file system and return the path to that file in [ProgResponse.DiskPath],
    +	// which must exist at least until a "close" request.
    +	CmdPut = ProgCmd("put")
    +
    +	// CmdGet tells the cache program to retrieve an object from the cache.
    +	//
    +	// [ProgRequest.ActionID] specifies the key of the object to get. If the
    +	// cache does not contain this object, it should set [ProgResponse.Miss] to
    +	// true. Otherwise, it should populate the fields of [ProgResponse],
    +	// including setting [ProgResponse.OutputID] to the OutputID of the original
    +	// "put" request and [ProgResponse.DiskPath] to the path of a local file
    +	// containing the Body of the original "put" request. That file must
    +	// continue to exist at least until a "close" request.
    +	CmdGet = ProgCmd("get")
    +
    +	// CmdClose requests that the cache program exit gracefully.
    +	//
    +	// The cache program should reply to this request and then exit
    +	// (thus closing its stdout).
    +	CmdClose = ProgCmd("close")
    +)
    +
    +// ProgRequest is the JSON-encoded message that's sent from the go command to
    +// the GOCACHEPROG child process over stdin. Each JSON object is on its own
    +// line. A ProgRequest of Type "put" with BodySize > 0 will be followed by a
    +// line containing a base64-encoded JSON string literal of the body.
    +type ProgRequest struct {
    +	// ID is a unique number per process across all requests.
    +	// It must be echoed in the ProgResponse from the child.
    +	ID int64
    +
    +	// Command is the type of request.
    +	// The go command will only send commands that were declared
    +	// as supported by the child.
    +	Command ProgCmd
    +
    +	// ActionID is the cache key for "put" and "get" requests.
    +	ActionID []byte `json:",omitempty"` // or nil if not used
    +
    +	// OutputID is stored with the body for "put" requests.
    +	//
    +	// Prior to Go 1.24, when GOCACHEPROG was still an experiment, this was
    +	// accidentally named ObjectID. It was renamed to OutputID in Go 1.24.
    +	OutputID []byte `json:",omitempty"` // or nil if not used
    +
    +	// Body is the body for "put" requests. It's sent after the JSON object
    +	// as a base64-encoded JSON string when BodySize is non-zero.
    +	// It's sent as a separate JSON value instead of being a struct field
    +	// send in this JSON object so large values can be streamed in both directions.
    +	// The base64 string body of a ProgRequest will always be written
    +	// immediately after the JSON object and a newline.
    +	Body io.Reader `json:"-"`
    +
    +	// BodySize is the number of bytes of Body. If zero, the body isn't written.
    +	BodySize int64 `json:",omitempty"`
    +
    +	// ObjectID is the accidental spelling of OutputID that was used prior to Go
    +	// 1.24.
    +	//
    +	// Deprecated: use OutputID. This field is only populated temporarily for
    +	// backwards compatibility with Go 1.23 and earlier when
    +	// GOEXPERIMENT=gocacheprog is set. It will be removed in Go 1.25.
    +	ObjectID []byte `json:",omitempty"`
    +}
    +
    +// ProgResponse is the JSON response from the child process to the go command.
    +//
    +// With the exception of the first protocol message that the child writes to its
    +// stdout with ID==0 and KnownCommands populated, these are only sent in
    +// response to a ProgRequest from the go command.
    +//
    +// ProgResponses can be sent in any order. The ID must match the request they're
    +// replying to.
    +type ProgResponse struct {
    +	ID  int64  // that corresponds to ProgRequest; they can be answered out of order
    +	Err string `json:",omitempty"` // if non-empty, the error
    +
    +	// KnownCommands is included in the first message that cache helper program
    +	// writes to stdout on startup (with ID==0). It includes the
    +	// ProgRequest.Command types that are supported by the program.
    +	//
    +	// This lets the go command extend the protocol gracefully over time (adding
    +	// "get2", etc), or fail gracefully when needed. It also lets the go command
    +	// verify the program wants to be a cache helper.
    +	KnownCommands []ProgCmd `json:",omitempty"`
    +
    +	// For "get" requests.
    +
    +	Miss     bool       `json:",omitempty"` // cache miss
    +	OutputID []byte     `json:",omitempty"` // the ObjectID stored with the body
    +	Size     int64      `json:",omitempty"` // body size in bytes
    +	Time     *time.Time `json:",omitempty"` // when the object was put in the cache (optional; used for cache expiration)
    +
    +	// For "get" and "put" requests.
    +
    +	// DiskPath is the absolute path on disk of the body corresponding to a
    +	// "get" (on cache hit) or "put" request's ActionID.
    +	DiskPath string `json:",omitempty"`
    +}
    
    From 3c8e5b13df931e88fde51ff09b27cceeaab9f6c4 Mon Sep 17 00:00:00 2001
    From: Austin Clements 
    Date: Fri, 27 Dec 2024 13:27:21 -0500
    Subject: [PATCH 089/397] cmd/go/internal/cacheprog: drop redundant Prog
     prefixes
    
    Now that these types are in their own package, drop the unnecessary
    Prog prefixes from everything.
    
    Updates #71032
    Updates #59719
    
    Change-Id: Id54edf0473754e3b21a71beb72803fb5481206c1
    Reviewed-on: https://go-review.googlesource.com/c/go/+/638996
    Reviewed-by: Mauri de Souza Meneguzzo 
    Reviewed-by: Michael Matloob 
    Reviewed-by: Brad Fitzpatrick 
    Reviewed-by: Dmitri Shuralyov 
    Auto-Submit: Austin Clements 
    LUCI-TryBot-Result: Go LUCI 
    ---
     src/cmd/go/internal/cache/prog.go          | 24 ++++-----
     src/cmd/go/internal/cacheprog/cacheprog.go | 58 +++++++++++-----------
     2 files changed, 41 insertions(+), 41 deletions(-)
    
    diff --git a/src/cmd/go/internal/cache/prog.go b/src/cmd/go/internal/cache/prog.go
    index 124128d172f107..01ed9438e3978d 100644
    --- a/src/cmd/go/internal/cache/prog.go
    +++ b/src/cmd/go/internal/cache/prog.go
    @@ -39,7 +39,7 @@ type ProgCache struct {
     
     	// can are the commands that the child process declared that it supports.
     	// This is effectively the versioning mechanism.
    -	can map[cacheprog.ProgCmd]bool
    +	can map[cacheprog.Cmd]bool
     
     	// fuzzDirCache is another Cache implementation to use for the FuzzDir
     	// method. In practice this is the default GOCACHE disk-based
    @@ -56,7 +56,7 @@ type ProgCache struct {
     
     	mu         sync.Mutex // guards following fields
     	nextID     int64
    -	inFlight   map[int64]chan<- *cacheprog.ProgResponse
    +	inFlight   map[int64]chan<- *cacheprog.Response
     	outputFile map[OutputID]string // object => abs path on disk
     
     	// writeMu serializes writing to the child process.
    @@ -111,14 +111,14 @@ func startCacheProg(progAndArgs string, fuzzDirCache Cache) Cache {
     		stdout:       out,
     		stdin:        in,
     		bw:           bufio.NewWriter(in),
    -		inFlight:     make(map[int64]chan<- *cacheprog.ProgResponse),
    +		inFlight:     make(map[int64]chan<- *cacheprog.Response),
     		outputFile:   make(map[OutputID]string),
     		readLoopDone: make(chan struct{}),
     	}
     
     	// Register our interest in the initial protocol message from the child to
     	// us, saying what it can do.
    -	capResc := make(chan *cacheprog.ProgResponse, 1)
    +	capResc := make(chan *cacheprog.Response, 1)
     	pc.inFlight[0] = capResc
     
     	pc.jenc = json.NewEncoder(pc.bw)
    @@ -133,7 +133,7 @@ func startCacheProg(progAndArgs string, fuzzDirCache Cache) Cache {
     		case <-timer.C:
     			log.Printf("# still waiting for GOCACHEPROG %v ...", prog)
     		case capRes := <-capResc:
    -			can := map[cacheprog.ProgCmd]bool{}
    +			can := map[cacheprog.Cmd]bool{}
     			for _, cmd := range capRes.KnownCommands {
     				can[cmd] = true
     			}
    @@ -150,7 +150,7 @@ func (c *ProgCache) readLoop(readLoopDone chan<- struct{}) {
     	defer close(readLoopDone)
     	jd := json.NewDecoder(c.stdout)
     	for {
    -		res := new(cacheprog.ProgResponse)
    +		res := new(cacheprog.Response)
     		if err := jd.Decode(res); err != nil {
     			if c.closing.Load() {
     				return // quietly
    @@ -175,8 +175,8 @@ func (c *ProgCache) readLoop(readLoopDone chan<- struct{}) {
     	}
     }
     
    -func (c *ProgCache) send(ctx context.Context, req *cacheprog.ProgRequest) (*cacheprog.ProgResponse, error) {
    -	resc := make(chan *cacheprog.ProgResponse, 1)
    +func (c *ProgCache) send(ctx context.Context, req *cacheprog.Request) (*cacheprog.Response, error) {
    +	resc := make(chan *cacheprog.Response, 1)
     	if err := c.writeToChild(req, resc); err != nil {
     		return nil, err
     	}
    @@ -191,7 +191,7 @@ func (c *ProgCache) send(ctx context.Context, req *cacheprog.ProgRequest) (*cach
     	}
     }
     
    -func (c *ProgCache) writeToChild(req *cacheprog.ProgRequest, resc chan<- *cacheprog.ProgResponse) (err error) {
    +func (c *ProgCache) writeToChild(req *cacheprog.Request, resc chan<- *cacheprog.Response) (err error) {
     	c.mu.Lock()
     	c.nextID++
     	req.ID = c.nextID
    @@ -252,7 +252,7 @@ func (c *ProgCache) Get(a ActionID) (Entry, error) {
     		// error types on the Cache interface.
     		return Entry{}, &entryNotFoundError{}
     	}
    -	res, err := c.send(c.ctx, &cacheprog.ProgRequest{
    +	res, err := c.send(c.ctx, &cacheprog.Request{
     		Command:  cacheprog.CmdGet,
     		ActionID: a[:],
     	})
    @@ -321,7 +321,7 @@ func (c *ProgCache) Put(a ActionID, file io.ReadSeeker) (_ OutputID, size int64,
     		deprecatedValue = out[:]
     	}
     
    -	res, err := c.send(c.ctx, &cacheprog.ProgRequest{
    +	res, err := c.send(c.ctx, &cacheprog.Request{
     		Command:  cacheprog.CmdPut,
     		ActionID: a[:],
     		OutputID: out[:],
    @@ -347,7 +347,7 @@ func (c *ProgCache) Close() error {
     	// and clean up if it wants. Only after that exchange do we cancel
     	// the context that kills the process.
     	if c.can[cacheprog.CmdClose] {
    -		_, err = c.send(c.ctx, &cacheprog.ProgRequest{Command: cacheprog.CmdClose})
    +		_, err = c.send(c.ctx, &cacheprog.Request{Command: cacheprog.CmdClose})
     	}
     	// Cancel the context, which will close the helper's stdin.
     	c.ctxCancel()
    diff --git a/src/cmd/go/internal/cacheprog/cacheprog.go b/src/cmd/go/internal/cacheprog/cacheprog.go
    index 41b1b0d79f94fe..a2796592df5fd3 100644
    --- a/src/cmd/go/internal/cacheprog/cacheprog.go
    +++ b/src/cmd/go/internal/cacheprog/cacheprog.go
    @@ -13,9 +13,9 @@
     // with it via JSON messages over stdin/stdout. The subprocess's stderr will be
     // connected to the go command's stderr.
     //
    -// The subprocess should immediately send a [ProgResponse] with its capabilities.
    -// After that, the go command will send a stream of [ProgRequest] messages and the
    -// subprocess should reply to each [ProgRequest] with a [ProgResponse] message.
    +// The subprocess should immediately send a [Response] with its capabilities.
    +// After that, the go command will send a stream of [Request] messages and the
    +// subprocess should reply to each [Request] with a [Response] message.
     package cacheprog
     
     import (
    @@ -23,54 +23,54 @@ import (
     	"time"
     )
     
    -// ProgCmd is a command that can be issued to a child process.
    +// Cmd is a command that can be issued to a child process.
     //
     // If the interface needs to grow, the go command can add new commands or new
    -// versioned commands like "get2" in the future. The initial [ProgResponse] from
    +// versioned commands like "get2" in the future. The initial [Response] from
     // the child process indicates which commands it supports.
    -type ProgCmd string
    +type Cmd string
     
     const (
     	// CmdPut tells the cache program to store an object in the cache.
     	//
    -	// [ProgRequest.ActionID] is the cache key of this object. The cache should
    -	// store [ProgRequest.OutputID] and [ProgRequest.Body] under this key for a
    +	// [Request.ActionID] is the cache key of this object. The cache should
    +	// store [Request.OutputID] and [Request.Body] under this key for a
     	// later "get" request. It must also store the Body in a file in the local
    -	// file system and return the path to that file in [ProgResponse.DiskPath],
    +	// file system and return the path to that file in [Response.DiskPath],
     	// which must exist at least until a "close" request.
    -	CmdPut = ProgCmd("put")
    +	CmdPut = Cmd("put")
     
     	// CmdGet tells the cache program to retrieve an object from the cache.
     	//
    -	// [ProgRequest.ActionID] specifies the key of the object to get. If the
    -	// cache does not contain this object, it should set [ProgResponse.Miss] to
    -	// true. Otherwise, it should populate the fields of [ProgResponse],
    -	// including setting [ProgResponse.OutputID] to the OutputID of the original
    -	// "put" request and [ProgResponse.DiskPath] to the path of a local file
    +	// [Request.ActionID] specifies the key of the object to get. If the
    +	// cache does not contain this object, it should set [Response.Miss] to
    +	// true. Otherwise, it should populate the fields of [Response],
    +	// including setting [Response.OutputID] to the OutputID of the original
    +	// "put" request and [Response.DiskPath] to the path of a local file
     	// containing the Body of the original "put" request. That file must
     	// continue to exist at least until a "close" request.
    -	CmdGet = ProgCmd("get")
    +	CmdGet = Cmd("get")
     
     	// CmdClose requests that the cache program exit gracefully.
     	//
     	// The cache program should reply to this request and then exit
     	// (thus closing its stdout).
    -	CmdClose = ProgCmd("close")
    +	CmdClose = Cmd("close")
     )
     
    -// ProgRequest is the JSON-encoded message that's sent from the go command to
    +// Request is the JSON-encoded message that's sent from the go command to
     // the GOCACHEPROG child process over stdin. Each JSON object is on its own
     // line. A ProgRequest of Type "put" with BodySize > 0 will be followed by a
     // line containing a base64-encoded JSON string literal of the body.
    -type ProgRequest struct {
    +type Request struct {
     	// ID is a unique number per process across all requests.
    -	// It must be echoed in the ProgResponse from the child.
    +	// It must be echoed in the Response from the child.
     	ID int64
     
     	// Command is the type of request.
     	// The go command will only send commands that were declared
     	// as supported by the child.
    -	Command ProgCmd
    +	Command Cmd
     
     	// ActionID is the cache key for "put" and "get" requests.
     	ActionID []byte `json:",omitempty"` // or nil if not used
    @@ -85,7 +85,7 @@ type ProgRequest struct {
     	// as a base64-encoded JSON string when BodySize is non-zero.
     	// It's sent as a separate JSON value instead of being a struct field
     	// send in this JSON object so large values can be streamed in both directions.
    -	// The base64 string body of a ProgRequest will always be written
    +	// The base64 string body of a Request will always be written
     	// immediately after the JSON object and a newline.
     	Body io.Reader `json:"-"`
     
    @@ -101,26 +101,26 @@ type ProgRequest struct {
     	ObjectID []byte `json:",omitempty"`
     }
     
    -// ProgResponse is the JSON response from the child process to the go command.
    +// Response is the JSON response from the child process to the go command.
     //
     // With the exception of the first protocol message that the child writes to its
     // stdout with ID==0 and KnownCommands populated, these are only sent in
    -// response to a ProgRequest from the go command.
    +// response to a Request from the go command.
     //
    -// ProgResponses can be sent in any order. The ID must match the request they're
    +// Responses can be sent in any order. The ID must match the request they're
     // replying to.
    -type ProgResponse struct {
    -	ID  int64  // that corresponds to ProgRequest; they can be answered out of order
    +type Response struct {
    +	ID  int64  // that corresponds to Request; they can be answered out of order
     	Err string `json:",omitempty"` // if non-empty, the error
     
     	// KnownCommands is included in the first message that cache helper program
     	// writes to stdout on startup (with ID==0). It includes the
    -	// ProgRequest.Command types that are supported by the program.
    +	// Request.Command types that are supported by the program.
     	//
     	// This lets the go command extend the protocol gracefully over time (adding
     	// "get2", etc), or fail gracefully when needed. It also lets the go command
     	// verify the program wants to be a cache helper.
    -	KnownCommands []ProgCmd `json:",omitempty"`
    +	KnownCommands []Cmd `json:",omitempty"`
     
     	// For "get" requests.
     
    
    From 0afd7e85e5d7154161770f06a17d09bf1ffa3e94 Mon Sep 17 00:00:00 2001
    From: Austin Clements 
    Date: Fri, 27 Dec 2024 13:11:02 -0500
    Subject: [PATCH 090/397] cmd/go: document GOCACHEPROG in go help environment
    
    This adds GOCACHEPROG to the list of environment variables in "go help
    environment" and points to the cacheprog package documentation for
    details of the protocol.
    
    Fixes #71032
    Updates #59719
    
    Change-Id: Ib8f5804926a8fa59237661076d129c2852665ac3
    Reviewed-on: https://go-review.googlesource.com/c/go/+/638997
    Auto-Submit: Austin Clements 
    Reviewed-by: Mauri de Souza Meneguzzo 
    Reviewed-by: Michael Matloob 
    LUCI-TryBot-Result: Go LUCI 
    Reviewed-by: Brad Fitzpatrick 
    ---
     src/cmd/go/alldocs.go               | 4 ++++
     src/cmd/go/internal/help/helpdoc.go | 4 ++++
     2 files changed, 8 insertions(+)
    
    diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go
    index 910699caced7e8..88f2e21f822d1a 100644
    --- a/src/cmd/go/alldocs.go
    +++ b/src/cmd/go/alldocs.go
    @@ -2333,6 +2333,10 @@
     //	GOCACHE
     //		The directory where the go command will store cached
     //		information for reuse in future builds.
    +//	GOCACHEPROG
    +//		A command (with optional space-separated flags) that implements an
    +//		external go command build cache.
    +//		See 'go doc cmd/go/internal/cacheprog'.
     //	GODEBUG
     //		Enable various debugging facilities. See https://go.dev/doc/godebug
     //		for details.
    diff --git a/src/cmd/go/internal/help/helpdoc.go b/src/cmd/go/internal/help/helpdoc.go
    index 7e19ba93d2a83d..311584d4f0f1f3 100644
    --- a/src/cmd/go/internal/help/helpdoc.go
    +++ b/src/cmd/go/internal/help/helpdoc.go
    @@ -506,6 +506,10 @@ General-purpose environment variables:
     	GOCACHE
     		The directory where the go command will store cached
     		information for reuse in future builds.
    +	GOCACHEPROG
    +		A command (with optional space-separated flags) that implements an
    +		external go command build cache.
    +		See 'go doc cmd/go/internal/cacheprog'.
     	GODEBUG
     		Enable various debugging facilities. See https://go.dev/doc/godebug
     		for details.
    
    From 4b652e9f5f5c0793f2e41cd2876bce5a241b2c95 Mon Sep 17 00:00:00 2001
    From: linmaolin 
    Date: Thu, 2 Jan 2025 21:05:21 +0000
    Subject: [PATCH 091/397] cmd/go: fix two typos in helpdoc.go
    
    Change-Id: Ib750438107db6c82020cfb4abbab52435012b7fc
    GitHub-Last-Rev: 3fa9b8c7bc70965c1ec9082b00c9b5a7af9751ef
    GitHub-Pull-Request: golang/go#71082
    Reviewed-on: https://go-review.googlesource.com/c/go/+/639217
    Auto-Submit: Ian Lance Taylor 
    Reviewed-by: Michael Matloob 
    LUCI-TryBot-Result: Go LUCI 
    Reviewed-by: Sam Thanawalla 
    ---
     src/cmd/go/alldocs.go               | 4 ++--
     src/cmd/go/internal/help/helpdoc.go | 4 ++--
     2 files changed, 4 insertions(+), 4 deletions(-)
    
    diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go
    index 88f2e21f822d1a..20d76de0c742e1 100644
    --- a/src/cmd/go/alldocs.go
    +++ b/src/cmd/go/alldocs.go
    @@ -2181,7 +2181,7 @@
     // fields of all events to reconstruct the text format output, as it would
     // have appeared from go build without the -json flag.
     //
    -// Note that there may also be non-JSON error text on stdnard error, even
    +// Note that there may also be non-JSON error text on standard error, even
     // with the -json flag. Typically, this indicates an early, serious error.
     // Consumers should be robust to this.
     //
    @@ -2616,7 +2616,7 @@
     //		Example: Data
     //
     //	If the server responds with any 4xx code, the go command will write the
    -//	following to the programs' stdin:
    +//	following to the program's stdin:
     //		Response      = StatusLine { HeaderLine } BlankLine .
     //		StatusLine    = Protocol Space Status '\n' .
     //		Protocol      = /* HTTP protocol */ .
    diff --git a/src/cmd/go/internal/help/helpdoc.go b/src/cmd/go/internal/help/helpdoc.go
    index 311584d4f0f1f3..65d0f1a45c0c17 100644
    --- a/src/cmd/go/internal/help/helpdoc.go
    +++ b/src/cmd/go/internal/help/helpdoc.go
    @@ -1034,7 +1034,7 @@ command
     		Example: Data
     
     	If the server responds with any 4xx code, the go command will write the
    -	following to the programs' stdin:
    +	following to the program's stdin:
     		Response      = StatusLine { HeaderLine } BlankLine .
     		StatusLine    = Protocol Space Status '\n' .
     		Protocol      = /* HTTP protocol */ .
    @@ -1102,7 +1102,7 @@ Furthermore, as with TestEvent, parsers can simply concatenate the Output
     fields of all events to reconstruct the text format output, as it would
     have appeared from go build without the -json flag.
     
    -Note that there may also be non-JSON error text on stdnard error, even
    +Note that there may also be non-JSON error text on standard error, even
     with the -json flag. Typically, this indicates an early, serious error.
     Consumers should be robust to this.
     	`,
    
    From e7a8bd5d8bd950764cbc48656fcc5456df7b1e9a Mon Sep 17 00:00:00 2001
    From: Filippo Valsorda 
    Date: Tue, 17 Dec 2024 20:03:22 +0100
    Subject: [PATCH 092/397] crypto/internal/fips140/check: remove Enabled
    
    check.Enabled, internal/fips140.Enabled, and crypto/fips140.Enabled were
    redundant. Package check can just use internal/fips140.Enabled.
    
    check.Verified is still there for the tests and belt-and-suspenders
    assurance in crypto/fips140.Enabled, although it's implied by Enabled.
    
    For #69536
    
    Change-Id: I83921cc925da841aba4da79a9a5e9ac526a3f2bf
    Reviewed-on: https://go-review.googlesource.com/c/go/+/638855
    Reviewed-by: Roland Shoemaker 
    Reviewed-by: Daniel McCarney 
    Reviewed-by: Dmitri Shuralyov 
    LUCI-TryBot-Result: Go LUCI 
    Auto-Submit: Filippo Valsorda 
    ---
     src/crypto/fips140/fips140.go              |  2 +-
     src/crypto/internal/fips140/check/check.go | 28 ++++++----------------
     src/crypto/internal/fips140/fips140.go     |  6 ++++-
     3 files changed, 13 insertions(+), 23 deletions(-)
    
    diff --git a/src/crypto/fips140/fips140.go b/src/crypto/fips140/fips140.go
    index 9fd8fe76e5efd3..41d0d170cf9fc8 100644
    --- a/src/crypto/fips140/fips140.go
    +++ b/src/crypto/fips140/fips140.go
    @@ -26,7 +26,7 @@ func Enabled() bool {
     	if currentlyEnabled != fips140.Enabled {
     		panic("crypto/fips140: GODEBUG setting changed after program start")
     	}
    -	if fips140.Enabled && !check.Enabled() {
    +	if fips140.Enabled && !check.Verified {
     		panic("crypto/fips140: FIPS 140-3 mode enabled, but integrity check didn't pass")
     	}
     	return fips140.Enabled
    diff --git a/src/crypto/internal/fips140/check/check.go b/src/crypto/internal/fips140/check/check.go
    index ff61b80cb37ed2..cf33a1efbee0ce 100644
    --- a/src/crypto/internal/fips140/check/check.go
    +++ b/src/crypto/internal/fips140/check/check.go
    @@ -2,7 +2,7 @@
     // Use of this source code is governed by a BSD-style
     // license that can be found in the LICENSE file.
     
    -// Package check implements the FIPS-140 load-time code+data verification.
    +// Package check implements the FIPS 140 load-time code+data verification.
     // Every FIPS package providing cryptographic functionality except hmac and sha256
     // must import crypto/internal/fips140/check, so that the verification happens
     // before initialization of package global variables.
    @@ -13,6 +13,7 @@
     package check
     
     import (
    +	"crypto/internal/fips140"
     	"crypto/internal/fips140/hmac"
     	"crypto/internal/fips140/sha256"
     	"crypto/internal/fips140deps/byteorder"
    @@ -22,15 +23,9 @@ import (
     	"unsafe"
     )
     
    -// Enabled reports whether verification was enabled.
    -// If Enabled returns true, then verification succeeded,
    -// because if it failed the binary would have panicked at init time.
    -func Enabled() bool {
    -	return enabled
    -}
    -
    -var enabled bool  // set when verification is enabled
    -var Verified bool // set when verification succeeds, for testing
    +// Verified is set when verification succeeded. It can be expected to always be
    +// true when [fips140.Enabled] is true, or init would have panicked.
    +var Verified bool
     
     // Supported reports whether the current GOOS/GOARCH is Supported at all.
     func Supported() bool {
    @@ -71,9 +66,7 @@ const fipsMagic = " Go fipsinfo \xff\x00"
     var zeroSum [32]byte
     
     func init() {
    -	v := godebug.Value("#fips140")
    -	enabled = v != "" && v != "off"
    -	if !enabled {
    +	if !fips140.Enabled {
     		return
     	}
     
    @@ -88,13 +81,6 @@ func init() {
     		panic("fips140: cannot verify in asan mode")
     	}
     
    -	switch v {
    -	case "on", "only", "debug":
    -		// ok
    -	default:
    -		panic("fips140: unknown GODEBUG setting fips140=" + v)
    -	}
    -
     	if !Supported() {
     		panic("fips140: unavailable on " + runtime.GOOS + "-" + runtime.GOARCH)
     	}
    @@ -132,7 +118,7 @@ func init() {
     		panic("fips140: verification mismatch")
     	}
     
    -	if v == "debug" {
    +	if godebug.Value("#fips140") == "debug" {
     		println("fips140: verified code+data")
     	}
     
    diff --git a/src/crypto/internal/fips140/fips140.go b/src/crypto/internal/fips140/fips140.go
    index d30433debfcd29..55b5dd43ce9539 100644
    --- a/src/crypto/internal/fips140/fips140.go
    +++ b/src/crypto/internal/fips140/fips140.go
    @@ -11,12 +11,16 @@ var Enabled bool
     var debug bool
     
     func init() {
    -	switch godebug.Value("#fips140") {
    +	v := godebug.Value("#fips140")
    +	switch v {
     	case "on", "only":
     		Enabled = true
     	case "debug":
     		Enabled = true
     		debug = true
    +	case "off", "":
    +	default:
    +		panic("fips140: unknown GODEBUG setting fips140=" + v)
     	}
     }
     
    
    From 81566aff3a1787fc81d320be5c1b3cb7da081936 Mon Sep 17 00:00:00 2001
    From: Mateusz Poliwczak 
    Date: Thu, 2 Jan 2025 18:22:34 +0000
    Subject: [PATCH 093/397] internal/exportdata: add missing return
    
    Change-Id: I9703c6a4a2ae4a608d33cf706106c92e9bd2aef7
    GitHub-Last-Rev: 3eee41957d8a2d9908519c798f30d5ccc90c53fb
    GitHub-Pull-Request: golang/go#71096
    Reviewed-on: https://go-review.googlesource.com/c/go/+/637962
    Reviewed-by: Dmitri Shuralyov 
    Auto-Submit: Ian Lance Taylor 
    LUCI-TryBot-Result: Go LUCI 
    Reviewed-by: Ian Lance Taylor 
    ---
     src/internal/exportdata/exportdata.go | 1 +
     1 file changed, 1 insertion(+)
    
    diff --git a/src/internal/exportdata/exportdata.go b/src/internal/exportdata/exportdata.go
    index 27675923b528d8..861a47f49f94f9 100644
    --- a/src/internal/exportdata/exportdata.go
    +++ b/src/internal/exportdata/exportdata.go
    @@ -85,6 +85,7 @@ func ReadUnified(r *bufio.Reader) (data []byte, err error) {
     
     	if n < 0 {
     		err = fmt.Errorf("invalid size (%d) in the archive file: %d bytes remain without section headers (recompile package)", size, n)
    +		return
     	}
     
     	// Read n bytes from buf.
    
    From 5d626c49ec0b43c1703d16967f0351eae13e7cb8 Mon Sep 17 00:00:00 2001
    From: yaxum62 
    Date: Thu, 2 Jan 2025 20:49:07 +0000
    Subject: [PATCH 094/397] spec: fix a dead link
    
    Change-Id: If99aa8073cc0e7fe36d3775c635eaaab230fcd04
    GitHub-Last-Rev: 06dbd990c72ee0e9c08254addd5ce669bfbe1883
    GitHub-Pull-Request: golang/go#71083
    Reviewed-on: https://go-review.googlesource.com/c/go/+/638638
    Reviewed-by: Dmitri Shuralyov 
    Auto-Submit: Jorropo 
    Reviewed-by: Jorropo 
    LUCI-TryBot-Result: Go LUCI 
    Reviewed-by: Ian Lance Taylor 
    ---
     doc/go_spec.html | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/doc/go_spec.html b/doc/go_spec.html
    index c6c4b30b04e279..ab90c420fd359c 100644
    --- a/doc/go_spec.html
    +++ b/doc/go_spec.html
    @@ -5906,7 +5906,7 @@ 

    Order of evaluation

    expression, assignment, or return statement, all function calls, method calls, -receive operations, +receive operations, and binary logical operations are evaluated in lexical left-to-right order.

    From f0a9b6df4551cb9559e2012d154972981df9fd4b Mon Sep 17 00:00:00 2001 From: Jakub Ciolek Date: Fri, 3 Jan 2025 17:23:05 +0100 Subject: [PATCH 095/397] internal/fuzz: remove the exp2 method It's not being used anywhere, remove it. Change-Id: I9c3eecacd4e5d44b18243bdec24ad88bc38c82bf Reviewed-on: https://go-review.googlesource.com/c/go/+/639957 Reviewed-by: Roland Shoemaker Reviewed-by: Dmitri Shuralyov LUCI-TryBot-Result: Go LUCI Auto-Submit: Roland Shoemaker --- src/internal/fuzz/mutators_byteslice_test.go | 6 ------ src/internal/fuzz/pcg.go | 6 ------ 2 files changed, 12 deletions(-) diff --git a/src/internal/fuzz/mutators_byteslice_test.go b/src/internal/fuzz/mutators_byteslice_test.go index 56adca25372ed6..b12ef6cbcdd0bd 100644 --- a/src/internal/fuzz/mutators_byteslice_test.go +++ b/src/internal/fuzz/mutators_byteslice_test.go @@ -34,12 +34,6 @@ func (mr *mockRand) uint32n(n uint32) uint32 { return uint32(c) % n } -func (mr *mockRand) exp2() int { - c := mr.values[mr.counter] - mr.counter++ - return c -} - func (mr *mockRand) bool() bool { b := mr.b mr.b = !mr.b diff --git a/src/internal/fuzz/pcg.go b/src/internal/fuzz/pcg.go index dc07b9f5bdc437..b8251043f1c129 100644 --- a/src/internal/fuzz/pcg.go +++ b/src/internal/fuzz/pcg.go @@ -17,7 +17,6 @@ type mutatorRand interface { uint32() uint32 intn(int) int uint32n(uint32) uint32 - exp2() int bool() bool save(randState, randInc *uint64) @@ -123,11 +122,6 @@ func (r *pcgRand) uint32n(n uint32) uint32 { return uint32(prod >> 32) } -// exp2 generates n with probability 1/2^(n+1). -func (r *pcgRand) exp2() int { - return bits.TrailingZeros32(r.uint32()) -} - // bool generates a random bool. func (r *pcgRand) bool() bool { return r.uint32()&1 == 0 From eb0c2b2f96d9590631c0fd502a6c570635399f0a Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Fri, 27 Dec 2024 11:13:42 +0100 Subject: [PATCH 096/397] crypto/internal/fips140: add Supported Move the logic duplicated in multiple places to a central function. Change-Id: I6a6a4656469c91dd62b0be716ec8367358f4a3e1 Reviewed-on: https://go-review.googlesource.com/c/go/+/639336 LUCI-TryBot-Result: Go LUCI Reviewed-by: Dmitri Shuralyov Auto-Submit: Filippo Valsorda Reviewed-by: Daniel McCarney Reviewed-by: Roland Shoemaker --- src/cmd/dist/test.go | 2 ++ .../internal/fips140/{check => }/asan.go | 2 +- src/crypto/internal/fips140/boring.go | 10 ++++++ src/crypto/internal/fips140/check/check.go | 29 ++------------- src/crypto/internal/fips140/fips140.go | 35 ++++++++++++++++++- .../fips140/{check/noasan.go => notasan.go} | 2 +- src/crypto/internal/fips140/notboring.go | 9 +++++ src/crypto/internal/fips140test/check_test.go | 20 +++-------- 8 files changed, 64 insertions(+), 45 deletions(-) rename src/crypto/internal/fips140/{check => }/asan.go (92%) create mode 100644 src/crypto/internal/fips140/boring.go rename src/crypto/internal/fips140/{check/noasan.go => notasan.go} (92%) create mode 100644 src/crypto/internal/fips140/notboring.go diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index 06bd01bc5bb995..bfed14c9152a26 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -1797,6 +1797,8 @@ func isEnvSet(evar string) bool { } func (t *tester) fipsSupported() bool { + // Keep this in sync with [crypto/internal/fips140.Supported]. + // Use GOFIPS140 or GOEXPERIMENT=boringcrypto, but not both. if strings.Contains(goexperiment, "boringcrypto") { return false diff --git a/src/crypto/internal/fips140/check/asan.go b/src/crypto/internal/fips140/asan.go similarity index 92% rename from src/crypto/internal/fips140/check/asan.go rename to src/crypto/internal/fips140/asan.go index 2c783483548344..af8f24df8117d2 100644 --- a/src/crypto/internal/fips140/check/asan.go +++ b/src/crypto/internal/fips140/asan.go @@ -4,6 +4,6 @@ //go:build asan -package check +package fips140 const asanEnabled = true diff --git a/src/crypto/internal/fips140/boring.go b/src/crypto/internal/fips140/boring.go new file mode 100644 index 00000000000000..d627bc68903308 --- /dev/null +++ b/src/crypto/internal/fips140/boring.go @@ -0,0 +1,10 @@ +// Copyright 2024 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. + +// Keep in sync with notboring.go and crypto/internal/boring/boring.go. +//go:build boringcrypto && linux && (amd64 || arm64) && !android && !msan && cgo + +package fips140 + +const boringEnabled = true diff --git a/src/crypto/internal/fips140/check/check.go b/src/crypto/internal/fips140/check/check.go index cf33a1efbee0ce..9d2e5d5cf6db68 100644 --- a/src/crypto/internal/fips140/check/check.go +++ b/src/crypto/internal/fips140/check/check.go @@ -19,7 +19,6 @@ import ( "crypto/internal/fips140deps/byteorder" "crypto/internal/fips140deps/godebug" "io" - "runtime" "unsafe" ) @@ -27,19 +26,6 @@ import ( // true when [fips140.Enabled] is true, or init would have panicked. var Verified bool -// Supported reports whether the current GOOS/GOARCH is Supported at all. -func Supported() bool { - // See cmd/internal/obj/fips.go's EnableFIPS for commentary. - switch { - case runtime.GOARCH == "wasm", - runtime.GOOS == "windows" && runtime.GOARCH == "386", - runtime.GOOS == "windows" && runtime.GOARCH == "arm", - runtime.GOOS == "aix": - return false - } - return true -} - // Linkinfo holds the go:fipsinfo symbol prepared by the linker. // See cmd/link/internal/ld/fips.go for details. // @@ -70,19 +56,8 @@ func init() { return } - if asanEnabled { - // ASAN disapproves of reading swaths of global memory below. - // One option would be to expose runtime.asanunpoison through - // crypto/internal/fips140deps and then call it to unpoison the range - // before reading it, but it is unclear whether that would then cause - // false negatives. For now, FIPS+ASAN doesn't need to work. - // If this is made to work, also re-enable the test in check_test.go - // and in cmd/dist/test.go. - panic("fips140: cannot verify in asan mode") - } - - if !Supported() { - panic("fips140: unavailable on " + runtime.GOOS + "-" + runtime.GOARCH) + if err := fips140.Supported(); err != nil { + panic("fips140: " + err.Error()) } if Linkinfo.Magic[0] != 0xff || string(Linkinfo.Magic[1:]) != fipsMagic || Linkinfo.Sum == zeroSum { diff --git a/src/crypto/internal/fips140/fips140.go b/src/crypto/internal/fips140/fips140.go index 55b5dd43ce9539..cf015db644738f 100644 --- a/src/crypto/internal/fips140/fips140.go +++ b/src/crypto/internal/fips140/fips140.go @@ -4,7 +4,11 @@ package fips140 -import "crypto/internal/fips140deps/godebug" +import ( + "crypto/internal/fips140deps/godebug" + "errors" + "runtime" +) var Enabled bool @@ -24,6 +28,35 @@ func init() { } } +// Supported returns an error if FIPS 140-3 mode can't be enabled. +func Supported() error { + // Keep this in sync with fipsSupported in cmd/dist/test.go. + + // ASAN disapproves of reading swaths of global memory in fips140/check. + // One option would be to expose runtime.asanunpoison through + // crypto/internal/fips140deps and then call it to unpoison the range + // before reading it, but it is unclear whether that would then cause + // false negatives. For now, FIPS+ASAN doesn't need to work. + if asanEnabled { + return errors.New("FIPS 140-3 mode is incompatible with ASAN") + } + + // See EnableFIPS in cmd/internal/obj/fips.go for commentary. + switch { + case runtime.GOARCH == "wasm", + runtime.GOOS == "windows" && runtime.GOARCH == "386", + runtime.GOOS == "windows" && runtime.GOARCH == "arm", + runtime.GOOS == "aix": + return errors.New("FIPS 140-3 mode is not supported on " + runtime.GOOS + "-" + runtime.GOARCH) + } + + if boringEnabled { + return errors.New("FIPS 140-3 mode is incompatible with GOEXPERIMENT=boringcrypto") + } + + return nil +} + func Name() string { return "Go Cryptographic Module" } diff --git a/src/crypto/internal/fips140/check/noasan.go b/src/crypto/internal/fips140/notasan.go similarity index 92% rename from src/crypto/internal/fips140/check/noasan.go rename to src/crypto/internal/fips140/notasan.go index 876d726f989096..639d419ef9c7b1 100644 --- a/src/crypto/internal/fips140/check/noasan.go +++ b/src/crypto/internal/fips140/notasan.go @@ -4,6 +4,6 @@ //go:build !asan -package check +package fips140 const asanEnabled = false diff --git a/src/crypto/internal/fips140/notboring.go b/src/crypto/internal/fips140/notboring.go new file mode 100644 index 00000000000000..681521c687c7c6 --- /dev/null +++ b/src/crypto/internal/fips140/notboring.go @@ -0,0 +1,9 @@ +// Copyright 2024 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. + +//go:build !(boringcrypto && linux && (amd64 || arm64) && !android && !msan && cgo) + +package fips140 + +const boringEnabled = false diff --git a/src/crypto/internal/fips140test/check_test.go b/src/crypto/internal/fips140test/check_test.go index cf42dbfa7823f9..6b0cd3f39e1695 100644 --- a/src/crypto/internal/fips140test/check_test.go +++ b/src/crypto/internal/fips140test/check_test.go @@ -5,16 +5,14 @@ package fipstest import ( - "crypto/internal/boring" + "crypto/internal/fips140" . "crypto/internal/fips140/check" "crypto/internal/fips140/check/checktest" "fmt" "internal/abi" - "internal/asan" "internal/godebug" "internal/testenv" "os" - "runtime" "testing" "unicode" "unsafe" @@ -23,10 +21,6 @@ import ( const enableFIPSTest = true func TestFIPSCheckVerify(t *testing.T) { - if boring.Enabled { - t.Skip("not testing fips140 with boringcrypto enabled") - } - if Verified { t.Logf("verified") return @@ -40,12 +34,8 @@ func TestFIPSCheckVerify(t *testing.T) { return } - if !Supported() { - t.Skipf("skipping on %s-%s", runtime.GOOS, runtime.GOARCH) - } - if asan.Enabled { - // Verification panics with asan; don't bother. - t.Skipf("skipping with -asan") + if err := fips140.Supported(); err != nil { + t.Skipf("skipping: %v", err) } cmd := testenv.Command(t, os.Args[0], "-test.v", "-test.run=TestFIPSCheck") @@ -62,8 +52,8 @@ func TestFIPSCheckInfo(t *testing.T) { return } - if !Supported() { - t.Skipf("skipping on %s-%s", runtime.GOOS, runtime.GOARCH) + if err := fips140.Supported(); err != nil { + t.Skipf("skipping: %v", err) } // Check that the checktest symbols are initialized properly. From 31cabcf08429be71299975f7961822d26f8ea389 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Wed, 1 Jan 2025 15:08:28 +0100 Subject: [PATCH 097/397] crypto/internal/fips140: mark OpenBSD unsupported MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since OpenBSD 7.3, external linking uses -fexecute-only, which breaks the integrity check. Since we are not validating on OpenBSD anyway, mark it as unsupported at least for now. Fixes #70880 Change-Id: I6a6a4656b6c7a97c0962b4158d920f9e6b19678e Reviewed-on: https://go-review.googlesource.com/c/go/+/639337 Auto-Submit: Filippo Valsorda Reviewed-by: Daniel McCarney Reviewed-by: Roland Shoemaker Reviewed-by: Dmitri Shuralyov Reviewed-by: Joel Sing Reviewed-by: صادق LUCI-TryBot-Result: Go LUCI --- src/cmd/dist/test.go | 1 + src/crypto/internal/fips140/fips140.go | 1 + 2 files changed, 2 insertions(+) diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index bfed14c9152a26..0c992118f4287b 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -1812,6 +1812,7 @@ func (t *tester) fipsSupported() bool { case goarch == "wasm", goos == "windows" && goarch == "386", goos == "windows" && goarch == "arm", + goos == "openbsd", goos == "aix": return false } diff --git a/src/crypto/internal/fips140/fips140.go b/src/crypto/internal/fips140/fips140.go index cf015db644738f..c7b167b82a1412 100644 --- a/src/crypto/internal/fips140/fips140.go +++ b/src/crypto/internal/fips140/fips140.go @@ -46,6 +46,7 @@ func Supported() error { case runtime.GOARCH == "wasm", runtime.GOOS == "windows" && runtime.GOARCH == "386", runtime.GOOS == "windows" && runtime.GOARCH == "arm", + runtime.GOOS == "openbsd", // due to -fexecute-only, see #70880 runtime.GOOS == "aix": return errors.New("FIPS 140-3 mode is not supported on " + runtime.GOOS + "-" + runtime.GOARCH) } From 5da026354c0229c5a61dbe907c080cef7adc11bc Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 3 Jan 2025 13:49:20 -0800 Subject: [PATCH 098/397] cmd/go/internal/vcweb: close the .access file For #71112 Change-Id: Ifda4fc8de148c42a2154da54b53d7215b9a6faa0 Reviewed-on: https://go-review.googlesource.com/c/go/+/640175 LUCI-TryBot-Result: Go LUCI Auto-Submit: Ian Lance Taylor Auto-Submit: Ian Lance Taylor Reviewed-by: Michael Matloob Reviewed-by: Ian Lance Taylor --- src/cmd/go/internal/vcweb/auth.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cmd/go/internal/vcweb/auth.go b/src/cmd/go/internal/vcweb/auth.go index 383bf759ffcdc1..e7c7c6ca265758 100644 --- a/src/cmd/go/internal/vcweb/auth.go +++ b/src/cmd/go/internal/vcweb/auth.go @@ -63,6 +63,7 @@ func (h *authHandler) Handler(dir string, env []string, logger *log.Logger) (htt var err error accessFile, err = fs.Open(path.Join(accessDir, ".access")) if err == nil { + defer accessFile.Close() break } From f966695ccea356e4e4e8cc0328276e2d00c9fc1e Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Fri, 3 Jan 2025 11:47:39 -0800 Subject: [PATCH 099/397] context: use "canceled" in docs to refer to timed-out contexts In documentation, we've usually but not always referred to a context with a closed Done channel as "done" rather than "canceled", to avoid ambiguity between a context canceled by calling a CancelFunc and one past its deadline. This actually adds ambiguity, however, since it's common to see references to a "canceled context" that are intended to cover contexts past their deadline. If you see "function F returns if its context is canceled", you can reasonably assume that F will return if its context passes its deadline, unless something says otherwise. Update the context package docs to explicitly state that a context is canceled when its deadline passes. Drop references to contexts becoming "done" and just use "canceled" throughout. Fixes #70945 Change-Id: I99fbd800c6049deaa37015a304f7f9d9a84100e1 Reviewed-on: https://go-review.googlesource.com/c/go/+/640095 Reviewed-by: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Auto-Submit: Damien Neil --- src/context/context.go | 42 +++++++++++++++++++------------------ src/context/example_test.go | 4 ++-- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/context/context.go b/src/context/context.go index db8bc69553ebe8..bef9e8aab054d6 100644 --- a/src/context/context.go +++ b/src/context/context.go @@ -10,23 +10,25 @@ // calls to servers should accept a Context. The chain of function // calls between them must propagate the Context, optionally replacing // it with a derived Context created using [WithCancel], [WithDeadline], -// [WithTimeout], or [WithValue]. When a Context is canceled, all -// Contexts derived from it are also canceled. +// [WithTimeout], or [WithValue]. +// +// A Context may be canceled to indicate that work done on its behalf should stop. +// A Context with a deadline is canceled after the deadline passes. +// When a Context is canceled, all Contexts derived from it are also canceled. // // The [WithCancel], [WithDeadline], and [WithTimeout] functions take a // Context (the parent) and return a derived Context (the child) and a -// [CancelFunc]. Calling the CancelFunc cancels the child and its +// [CancelFunc]. Calling the CancelFunc directly cancels the child and its // children, removes the parent's reference to the child, and stops // any associated timers. Failing to call the CancelFunc leaks the -// child and its children until the parent is canceled or the timer -// fires. The go vet tool checks that CancelFuncs are used on all -// control-flow paths. +// child and its children until the parent is canceled. The go vet tool +// checks that CancelFuncs are used on all control-flow paths. // -// The [WithCancelCause] function returns a [CancelCauseFunc], which -// takes an error and records it as the cancellation cause. Calling -// [Cause] on the canceled context or any of its children retrieves -// the cause. If no cause is specified, Cause(ctx) returns the same -// value as ctx.Err(). +// The [WithCancelCause], [WithDeadlineCause], and [WithTimeoutCause] functions +// return a [CancelCauseFunc], which takes an error and records it as +// the cancellation cause. Calling [Cause] on the canceled context +// or any of its children retrieves the cause. If no cause is specified, +// Cause(ctx) returns the same value as ctx.Err(). // // Programs that use Contexts should follow these rules to keep interfaces // consistent across packages and enable static analysis tools to check context @@ -107,8 +109,8 @@ type Context interface { // If Done is not yet closed, Err returns nil. // If Done is closed, Err returns a non-nil error explaining why: - // Canceled if the context was canceled - // or DeadlineExceeded if the context's deadline passed. + // DeadlineExceeded if the context's deadline passed, + // or Canceled if the context was canceled for some other reason. // After Err returns a non-nil error, successive calls to Err return the same error. Err() error @@ -160,11 +162,12 @@ type Context interface { Value(key any) any } -// Canceled is the error returned by [Context.Err] when the context is canceled. +// Canceled is the error returned by [Context.Err] when the context is canceled +// for some reason other than its deadline passing. var Canceled = errors.New("context canceled") -// DeadlineExceeded is the error returned by [Context.Err] when the context's -// deadline passes. +// DeadlineExceeded is the error returned by [Context.Err] when the context is canceled +// due to its deadline passing. var DeadlineExceeded error = deadlineExceededError{} type deadlineExceededError struct{} @@ -296,9 +299,8 @@ func Cause(c Context) error { return c.Err() } -// AfterFunc arranges to call f in its own goroutine after ctx is done -// (canceled or timed out). -// If ctx is already done, AfterFunc calls f immediately in its own goroutine. +// AfterFunc arranges to call f in its own goroutine after ctx is canceled. +// If ctx is already canceled, AfterFunc calls f immediately in its own goroutine. // // Multiple calls to AfterFunc on a context operate independently; // one does not replace another. @@ -306,7 +308,7 @@ func Cause(c Context) error { // Calling the returned stop function stops the association of ctx with f. // It returns true if the call stopped f from being run. // If stop returns false, -// either the context is done and f has been started in its own goroutine; +// either the context is canceled and f has been started in its own goroutine; // or f was already stopped. // The stop function does not wait for f to complete before returning. // If the caller needs to know whether f is completed, diff --git a/src/context/example_test.go b/src/context/example_test.go index b597b09f16e525..be8cd8376e1736 100644 --- a/src/context/example_test.go +++ b/src/context/example_test.go @@ -146,8 +146,8 @@ func ExampleAfterFunc_cond() { defer stopf() // Since the wakeups are using Broadcast instead of Signal, this call to - // Wait may unblock due to some other goroutine's context becoming done, - // so to be sure that ctx is actually done we need to check it in a loop. + // Wait may unblock due to some other goroutine's context being canceled, + // so to be sure that ctx is actually canceled we need to check it in a loop. for !conditionMet() { cond.Wait() if ctx.Err() != nil { From 705b5a569acb9207fda8ea469387d88346b6817a Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Wed, 24 Aug 2022 12:32:51 +0200 Subject: [PATCH 100/397] crypto/ecdsa: drop SEC 1 reference from package doc FIPS 186-4 used to defer to ANSI X9.62-2005, which is not freely available, so we were referring to SEC 1 instead. Our new reference, FIPS 186-5, actually specifies the full algorithm, so there is no need to refer to SEC 1 anymore. Change-Id: Ief499d0f7778f3221547993e9e8951ae873aacef Reviewed-on: https://go-review.googlesource.com/c/go/+/640115 Reviewed-by: Daniel McCarney Reviewed-by: Dmitri Shuralyov Auto-Submit: Filippo Valsorda LUCI-TryBot-Result: Go LUCI Reviewed-by: Roland Shoemaker --- src/crypto/ecdsa/ecdsa.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/crypto/ecdsa/ecdsa.go b/src/crypto/ecdsa/ecdsa.go index 0f9749975ffba9..f682e6b1c6cfa6 100644 --- a/src/crypto/ecdsa/ecdsa.go +++ b/src/crypto/ecdsa/ecdsa.go @@ -3,7 +3,7 @@ // license that can be found in the LICENSE file. // Package ecdsa implements the Elliptic Curve Digital Signature Algorithm, as -// defined in FIPS 186-5 and SEC 1, Version 2.0. +// defined in [FIPS 186-5]. // // Signatures generated by this package are not deterministic, but entropy is // mixed with the private key and the message, achieving the same level of @@ -12,6 +12,8 @@ // Operations involving private keys are implemented using constant-time // algorithms, as long as an [elliptic.Curve] returned by [elliptic.P224], // [elliptic.P256], [elliptic.P384], or [elliptic.P521] is used. +// +// [FIPS 186-5]: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-5.pdf package ecdsa import ( From c112c0af1328ef0aae989ae20d27359a18f72543 Mon Sep 17 00:00:00 2001 From: Michael Knyszek Date: Mon, 23 Dec 2024 17:59:28 -0800 Subject: [PATCH 101/397] Revert "internal/sync: optimize CompareAndSwap and Swap" This reverts CL 606462. Reason for revert: Breaks atomicity between operations. See #70970. Change-Id: I1a899f2784da5a0f9da3193e3267275c23aea661 Reviewed-on: https://go-review.googlesource.com/c/go/+/638615 Auto-Submit: Michael Knyszek Commit-Queue: Michael Knyszek LUCI-TryBot-Result: Go LUCI Reviewed-by: David Chase --- src/internal/sync/hashtriemap.go | 171 +++++++++++++------------------ 1 file changed, 69 insertions(+), 102 deletions(-) diff --git a/src/internal/sync/hashtriemap.go b/src/internal/sync/hashtriemap.go index d31d81df39ca19..defcd0b793947f 100644 --- a/src/internal/sync/hashtriemap.go +++ b/src/internal/sync/hashtriemap.go @@ -219,22 +219,12 @@ func (ht *HashTrieMap[K, V]) Swap(key K, new V) (previous V, loaded bool) { slot = &i.children[(hash>>hashShift)&nChildrenMask] n = slot.Load() - if n == nil { + if n == nil || n.isEntry { // We found a nil slot which is a candidate for insertion, // or an existing entry that we'll replace. haveInsertPoint = true break } - if n.isEntry { - // Swap if the keys compare. - old, swapped := n.entry().swap(key, new) - if swapped { - return old, true - } - // If we fail, that means we should try to insert. - haveInsertPoint = true - break - } i = n.indirect() } if !haveInsertPoint { @@ -261,10 +251,11 @@ func (ht *HashTrieMap[K, V]) Swap(key K, new V) (previous V, loaded bool) { var zero V var oldEntry *entry[K, V] if n != nil { - // Between before and now, something got inserted. Swap if the keys compare. + // Swap if the keys compare. oldEntry = n.entry() - old, swapped := oldEntry.swap(key, new) + newEntry, old, swapped := oldEntry.swap(key, new) if swapped { + slot.Store(&newEntry.node) return old, true } } @@ -292,30 +283,25 @@ func (ht *HashTrieMap[K, V]) CompareAndSwap(key K, old, new V) (swapped bool) { panic("called CompareAndSwap when value is not of comparable type") } hash := ht.keyHash(abi.NoEscape(unsafe.Pointer(&key)), ht.seed) - for { - // Find the key or return if it's not there. - i := ht.root.Load() - hashShift := 8 * goarch.PtrSize - found := false - for hashShift != 0 { - hashShift -= nChildrenLog2 - slot := &i.children[(hash>>hashShift)&nChildrenMask] - n := slot.Load() - if n == nil { - // Nothing to compare with. Give up. - return false - } - if n.isEntry { - // We found an entry. Try to compare and swap directly. - return n.entry().compareAndSwap(key, old, new, ht.valEqual) - } - i = n.indirect() - } - if !found { - panic("internal/concurrent.HashMapTrie: ran out of hash bits while iterating") - } + // Find a node with the key and compare with it. n != nil if we found the node. + i, _, slot, n := ht.find(key, hash, ht.valEqual, old) + if i != nil { + defer i.mu.Unlock() } + if n == nil { + return false + } + + // Try to swap the entry. + e, swapped := n.entry().compareAndSwap(key, old, new, ht.valEqual) + if !swapped { + // Nothing was actually swapped, which means the node is no longer there. + return false + } + // Store the entry back because it changed. + slot.Store(&e.node) + return true } // LoadAndDelete deletes the value for a key, returning the previous value if any. @@ -523,7 +509,7 @@ func (ht *HashTrieMap[K, V]) iter(i *indirect[K, V], yield func(key K, value V) } e := n.entry() for e != nil { - if !yield(e.key, *e.value.Load()) { + if !yield(e.key, e.value) { return false } e = e.overflow.Load() @@ -579,22 +565,21 @@ type entry[K comparable, V any] struct { node[K, V] overflow atomic.Pointer[entry[K, V]] // Overflow for hash collisions. key K - value atomic.Pointer[V] + value V } func newEntryNode[K comparable, V any](key K, value V) *entry[K, V] { - e := &entry[K, V]{ - node: node[K, V]{isEntry: true}, - key: key, + return &entry[K, V]{ + node: node[K, V]{isEntry: true}, + key: key, + value: value, } - e.value.Store(&value) - return e } func (e *entry[K, V]) lookup(key K) (V, bool) { for e != nil { if e.key == key { - return *e.value.Load(), true + return e.value, true } e = e.overflow.Load() } @@ -603,87 +588,69 @@ func (e *entry[K, V]) lookup(key K) (V, bool) { func (e *entry[K, V]) lookupWithValue(key K, value V, valEqual equalFunc) (V, bool) { for e != nil { - oldp := e.value.Load() - if e.key == key && (valEqual == nil || valEqual(unsafe.Pointer(oldp), abi.NoEscape(unsafe.Pointer(&value)))) { - return *oldp, true + if e.key == key && (valEqual == nil || valEqual(unsafe.Pointer(&e.value), abi.NoEscape(unsafe.Pointer(&value)))) { + return e.value, true } e = e.overflow.Load() } return *new(V), false } -// swap replaces a value in the overflow chain if keys compare equal. -// Returns the old value, and whether or not anything was swapped. +// swap replaces an entry in the overflow chain if keys compare equal. Returns the new entry chain, +// the old value, and whether or not anything was swapped. // // swap must be called under the mutex of the indirect node which e is a child of. -func (head *entry[K, V]) swap(key K, newv V) (V, bool) { +func (head *entry[K, V]) swap(key K, new V) (*entry[K, V], V, bool) { if head.key == key { - vp := new(V) - *vp = newv - oldp := head.value.Swap(vp) - return *oldp, true + // Return the new head of the list. + e := newEntryNode(key, new) + if chain := head.overflow.Load(); chain != nil { + e.overflow.Store(chain) + } + return e, head.value, true } i := &head.overflow e := i.Load() for e != nil { if e.key == key { - vp := new(V) - *vp = newv - oldp := e.value.Swap(vp) - return *oldp, true + eNew := newEntryNode(key, new) + eNew.overflow.Store(e.overflow.Load()) + i.Store(eNew) + return head, e.value, true } i = &e.overflow e = e.overflow.Load() } var zero V - return zero, false + return head, zero, false } -// compareAndSwap replaces a value for a matching key and existing value in the overflow chain. -// Returns whether or not anything was swapped. +// compareAndSwap replaces an entry in the overflow chain if both the key and value compare +// equal. Returns the new entry chain and whether or not anything was swapped. // // compareAndSwap must be called under the mutex of the indirect node which e is a child of. -func (head *entry[K, V]) compareAndSwap(key K, oldv, newv V, valEqual equalFunc) bool { - var vbox *V -outerLoop: - for { - oldvp := head.value.Load() - if head.key == key && valEqual(unsafe.Pointer(oldvp), abi.NoEscape(unsafe.Pointer(&oldv))) { - // Return the new head of the list. - if vbox == nil { - // Delay explicit creation of a new value to hold newv. If we just pass &newv - // to CompareAndSwap, then newv will unconditionally escape, even if the CAS fails. - vbox = new(V) - *vbox = newv - } - if head.value.CompareAndSwap(oldvp, vbox) { - return true - } - // We need to restart from the head of the overflow list in case, due to a removal, a node - // is moved up the list and we miss it. - continue outerLoop +func (head *entry[K, V]) compareAndSwap(key K, old, new V, valEqual equalFunc) (*entry[K, V], bool) { + if head.key == key && valEqual(unsafe.Pointer(&head.value), abi.NoEscape(unsafe.Pointer(&old))) { + // Return the new head of the list. + e := newEntryNode(key, new) + if chain := head.overflow.Load(); chain != nil { + e.overflow.Store(chain) } - i := &head.overflow - e := i.Load() - for e != nil { - oldvp := e.value.Load() - if e.key == key && valEqual(unsafe.Pointer(oldvp), abi.NoEscape(unsafe.Pointer(&oldv))) { - if vbox == nil { - // Delay explicit creation of a new value to hold newv. If we just pass &newv - // to CompareAndSwap, then newv will unconditionally escape, even if the CAS fails. - vbox = new(V) - *vbox = newv - } - if e.value.CompareAndSwap(oldvp, vbox) { - return true - } - continue outerLoop - } - i = &e.overflow - e = e.overflow.Load() + return e, true + } + i := &head.overflow + e := i.Load() + for e != nil { + if e.key == key && valEqual(unsafe.Pointer(&e.value), abi.NoEscape(unsafe.Pointer(&old))) { + eNew := newEntryNode(key, new) + eNew.overflow.Store(e.overflow.Load()) + i.Store(eNew) + return head, true } - return false + i = &e.overflow + e = e.overflow.Load() } + return head, false } // loadAndDelete deletes an entry in the overflow chain by key. Returns the value for the key, the new @@ -693,14 +660,14 @@ outerLoop: func (head *entry[K, V]) loadAndDelete(key K) (V, *entry[K, V], bool) { if head.key == key { // Drop the head of the list. - return *head.value.Load(), head.overflow.Load(), true + return head.value, head.overflow.Load(), true } i := &head.overflow e := i.Load() for e != nil { if e.key == key { i.Store(e.overflow.Load()) - return *e.value.Load(), head, true + return e.value, head, true } i = &e.overflow e = e.overflow.Load() @@ -713,14 +680,14 @@ func (head *entry[K, V]) loadAndDelete(key K) (V, *entry[K, V], bool) { // // compareAndDelete must be called under the mutex of the indirect node which e is a child of. func (head *entry[K, V]) compareAndDelete(key K, value V, valEqual equalFunc) (*entry[K, V], bool) { - if head.key == key && valEqual(unsafe.Pointer(head.value.Load()), abi.NoEscape(unsafe.Pointer(&value))) { + if head.key == key && valEqual(unsafe.Pointer(&head.value), abi.NoEscape(unsafe.Pointer(&value))) { // Drop the head of the list. return head.overflow.Load(), true } i := &head.overflow e := i.Load() for e != nil { - if e.key == key && valEqual(unsafe.Pointer(e.value.Load()), abi.NoEscape(unsafe.Pointer(&value))) { + if e.key == key && valEqual(unsafe.Pointer(&e.value), abi.NoEscape(unsafe.Pointer(&value))) { i.Store(e.overflow.Load()) return head, true } From 7a2e88e9117e838f258b175fa535f671396d13da Mon Sep 17 00:00:00 2001 From: yincong Date: Mon, 6 Jan 2025 02:10:08 +0000 Subject: [PATCH 102/397] net/http: update NewRequestWithContext wrong link to NewRequest Fixes #70874 Change-Id: Icbcfc95e6b45521880287dcc3bc8609461a3b401 GitHub-Last-Rev: 05276c56b019d8774e8eee881101509cf83c0f3d GitHub-Pull-Request: golang/go#70877 Reviewed-on: https://go-review.googlesource.com/c/go/+/637035 Reviewed-by: qiu laidongfeng2 <2645477756@qq.com> Reviewed-by: Damien Neil Reviewed-by: David Chase Auto-Submit: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Reviewed-by: Ian Lance Taylor --- src/net/http/request.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/net/http/request.go b/src/net/http/request.go index 686d53345aebd9..434c1640f3941d 100644 --- a/src/net/http/request.go +++ b/src/net/http/request.go @@ -873,9 +873,9 @@ func NewRequest(method, url string, body io.Reader) (*Request, error) { // // NewRequestWithContext returns a Request suitable for use with // [Client.Do] or [Transport.RoundTrip]. To create a request for use with -// testing a Server Handler, either use the [NewRequest] function in the -// net/http/httptest package, use [ReadRequest], or manually update the -// Request fields. For an outgoing client request, the context +// testing a Server Handler, either use the [net/http/httptest.NewRequest] function, +// use [ReadRequest], or manually update the Request fields. +// For an outgoing client request, the context // controls the entire lifetime of a request and its response: // obtaining a connection, sending the request, and reading the // response headers and body. See the Request type's documentation for From 3f002abb60b86a851e190d9246278aa53db11f87 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Mon, 6 Jan 2025 18:23:21 +0000 Subject: [PATCH 103/397] internal/sync: add test from issue 70970 This test checks a use-case of sync.Map that's expected to be more common in Go 1.24 and beyond, as a concurrent weak cache. The test will also fail if CompareAndSwap is not properly atomic with CompareAndDelete, which is what #70970 is actually about. We should have more explicit tests checking mutual atomicity of operations, but for now this is OK, and still useful. For #70970. Change-Id: I6db508660691586a8af9ad511c9a96432d333343 Reviewed-on: https://go-review.googlesource.com/c/go/+/640737 Reviewed-by: David Chase Auto-Submit: Michael Knyszek LUCI-TryBot-Result: Go LUCI --- src/internal/sync/hashtriemap_test.go | 59 +++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/src/internal/sync/hashtriemap_test.go b/src/internal/sync/hashtriemap_test.go index 5476add8803681..d9219f841a8bdf 100644 --- a/src/internal/sync/hashtriemap_test.go +++ b/src/internal/sync/hashtriemap_test.go @@ -12,6 +12,7 @@ import ( "strconv" "sync" "testing" + "weak" ) func TestHashTrieMap(t *testing.T) { @@ -921,3 +922,61 @@ func init() { testDataLarge[i] = fmt.Sprintf("%b", i) } } + +// TestConcurrentCache tests HashTrieMap in a scenario where it is used as +// the basis of a memory-efficient concurrent cache. We're specifically +// looking to make sure that CompareAndSwap and CompareAndDelete are +// atomic with respect to one another. When competing for the same +// key-value pair, they must not both succeed. +// +// This test is a regression test for issue #70970. +func TestConcurrentCache(t *testing.T) { + type dummy [32]byte + + var m isync.HashTrieMap[int, weak.Pointer[dummy]] + + type cleanupArg struct { + key int + value weak.Pointer[dummy] + } + cleanup := func(arg cleanupArg) { + m.CompareAndDelete(arg.key, arg.value) + } + get := func(m *isync.HashTrieMap[int, weak.Pointer[dummy]], key int) *dummy { + nv := new(dummy) + nw := weak.Make(nv) + for { + w, loaded := m.LoadOrStore(key, nw) + if !loaded { + runtime.AddCleanup(nv, cleanup, cleanupArg{key, nw}) + return nv + } + if v := w.Value(); v != nil { + return v + } + + // Weak pointer was reclaimed, try to replace it with nw. + if m.CompareAndSwap(key, w, nw) { + runtime.AddCleanup(nv, cleanup, cleanupArg{key, nw}) + return nv + } + } + } + + const N = 100_000 + const P = 5_000 + + var wg sync.WaitGroup + wg.Add(N) + for i := range N { + go func() { + defer wg.Done() + a := get(&m, i%P) + b := get(&m, i%P) + if a != b { + t.Errorf("consecutive cache reads returned different values: a != b (%p vs %p)\n", a, b) + } + }() + } + wg.Wait() +} From a76cc5a4ecb004616404cac5bb756da293818469 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Sat, 28 Dec 2024 22:32:59 +0100 Subject: [PATCH 104/397] =?UTF-8?q?crypto/rsa:=20use=20=CE=BB(N)=20instead?= =?UTF-8?q?=20of=20=CF=86(N)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This has no practical advantage, and requires extra variable time code, but is an explicit FIPS 186-5 requirement. Note that the new behavior is consistent with Go+BoringCrypto, but not with Go 1.23. The resulting keys are essentially interchangeable, but it's not impossible for applications to notice (google/go-tpm#383). gcd_lcm_tests.txt is from BoringSSL. Change-Id: I6a6a4656fd5e92912c87bedc667456d0e8787023 Reviewed-on: https://go-review.googlesource.com/c/go/+/639936 Reviewed-by: Russ Cox LUCI-TryBot-Result: Go LUCI Reviewed-by: Roland Shoemaker Auto-Submit: Filippo Valsorda --- src/crypto/internal/fips140/bigmod/nat.go | 85 ++++-- src/crypto/internal/fips140/rsa/keygen.go | 77 ++++- .../internal/fips140/rsa/keygen_test.go | 88 ++++++ src/crypto/internal/fips140/rsa/rsa.go | 2 +- .../fips140/rsa/testdata/gcd_lcm_tests.txt | 279 ++++++++++++++++++ 5 files changed, 506 insertions(+), 25 deletions(-) create mode 100644 src/crypto/internal/fips140/rsa/testdata/gcd_lcm_tests.txt diff --git a/src/crypto/internal/fips140/bigmod/nat.go b/src/crypto/internal/fips140/bigmod/nat.go index 2f17f896b3a52f..6757cccd026b11 100644 --- a/src/crypto/internal/fips140/bigmod/nat.go +++ b/src/crypto/internal/fips140/bigmod/nat.go @@ -134,6 +134,13 @@ func (x *Nat) set(y *Nat) *Nat { return x } +// Bits returns x as a little-endian slice of uint. The length of the slice +// matches the announced length of x. The result and x share the same underlying +// array. +func (x *Nat) Bits() []uint { + return x.limbs +} + // Bytes returns x as a zero-extended big-endian byte slice. The size of the // slice will match the size of m. // @@ -1058,6 +1065,34 @@ func (out *Nat) ExpShortVarTime(x *Nat, e uint, m *Modulus) *Nat { // //go:norace func (x *Nat) InverseVarTime(a *Nat, m *Modulus) (*Nat, bool) { + u, A, err := extendedGCD(a, m.nat) + if err != nil { + return x, false + } + if u.IsOne() == no { + return x, false + } + return x.set(A), true +} + +// GCDVarTime calculates x = GCD(a, b) where at least one of a or b is odd, and +// both are non-zero. If GCDVarTime returns an error, x is not modified. +// +// The output will be resized to the size of the larger of a and b. +func (x *Nat) GCDVarTime(a, b *Nat) (*Nat, error) { + u, _, err := extendedGCD(a, b) + if err != nil { + return nil, err + } + return x.set(u), nil +} + +// extendedGCD computes u and A such that a = GCD(a, m) and u = A*a - B*m. +// +// u will have the size of the larger of a and m, and A will have the size of m. +// +// It is an error if either a or m is zero, or if they are both even. +func extendedGCD(a, m *Nat) (u, A *Nat, err error) { // This is the extended binary GCD algorithm described in the Handbook of // Applied Cryptography, Algorithm 14.61, adapted by BoringSSL to bound // coefficients and avoid negative numbers. For more details and proof of @@ -1068,7 +1103,7 @@ func (x *Nat) InverseVarTime(a *Nat, m *Modulus) (*Nat, bool) { // 1. Negate [B] and [C] so they are positive. The invariant now involves a // subtraction. // 2. If step 2 (both [x] and [y] are even) runs, abort immediately. This - // algorithm only cares about [x] and [y] relatively prime. + // case needs to be handled by the caller. // 3. Subtract copies of [x] and [y] as needed in step 6 (both [u] and [v] // are odd) so coefficients stay in bounds. // 4. Replace the [u >= v] check with [u > v]. This changes the end @@ -1082,21 +1117,21 @@ func (x *Nat) InverseVarTime(a *Nat, m *Modulus) (*Nat, bool) { // // Note this algorithm does not handle either input being zero. - if a.IsZero() == yes { - return x, false + if a.IsZero() == yes || m.IsZero() == yes { + return nil, nil, errors.New("extendedGCD: a or m is zero") } - if a.IsOdd() == no && !m.odd { - // a and m are not coprime, as they are both even. - return x, false + if a.IsOdd() == no && m.IsOdd() == no { + return nil, nil, errors.New("extendedGCD: both a and m are even") } - u := NewNat().set(a).ExpandFor(m) - v := m.Nat() + size := max(len(a.limbs), len(m.limbs)) + u = NewNat().set(a).expand(size) + v := NewNat().set(m).expand(size) - A := NewNat().reset(len(m.nat.limbs)) + A = NewNat().reset(len(m.limbs)) A.limbs[0] = 1 B := NewNat().reset(len(a.limbs)) - C := NewNat().reset(len(m.nat.limbs)) + C := NewNat().reset(len(m.limbs)) D := NewNat().reset(len(a.limbs)) D.limbs[0] = 1 @@ -1119,11 +1154,11 @@ func (x *Nat) InverseVarTime(a *Nat, m *Modulus) (*Nat, bool) { if u.IsOdd() == yes && v.IsOdd() == yes { if v.cmpGeq(u) == no { u.sub(v) - A.Add(C, m) + A.Add(C, &Modulus{nat: m}) B.Add(D, &Modulus{nat: a}) } else { v.sub(u) - C.Add(A, m) + C.Add(A, &Modulus{nat: m}) D.Add(B, &Modulus{nat: a}) } } @@ -1137,7 +1172,7 @@ func (x *Nat) InverseVarTime(a *Nat, m *Modulus) (*Nat, bool) { if u.IsOdd() == no { rshift1(u, 0) if A.IsOdd() == yes || B.IsOdd() == yes { - rshift1(A, A.add(m.nat)) + rshift1(A, A.add(m)) rshift1(B, B.add(a)) } else { rshift1(A, 0) @@ -1146,7 +1181,7 @@ func (x *Nat) InverseVarTime(a *Nat, m *Modulus) (*Nat, bool) { } else { // v.IsOdd() == no rshift1(v, 0) if C.IsOdd() == yes || D.IsOdd() == yes { - rshift1(C, C.add(m.nat)) + rshift1(C, C.add(m)) rshift1(D, D.add(a)) } else { rshift1(C, 0) @@ -1155,10 +1190,7 @@ func (x *Nat) InverseVarTime(a *Nat, m *Modulus) (*Nat, bool) { } if v.IsZero() == yes { - if u.IsOne() == no { - return x, false - } - return x.set(A), true + return u, A, nil } } } @@ -1177,3 +1209,20 @@ func rshift1(a *Nat, carry uint) { } } } + +// DivShortVarTime calculates x = x / y and returns the remainder. +// +// It panics if y is zero. +// +//go:norace +func (x *Nat) DivShortVarTime(y uint) uint { + if y == 0 { + panic("bigmod: division by zero") + } + + var r uint + for i := len(x.limbs) - 1; i >= 0; i-- { + x.limbs[i], r = bits.Div(r, x.limbs[i], y) + } + return r +} diff --git a/src/crypto/internal/fips140/rsa/keygen.go b/src/crypto/internal/fips140/rsa/keygen.go index d8a282bcd44634..658eb9ab2458aa 100644 --- a/src/crypto/internal/fips140/rsa/keygen.go +++ b/src/crypto/internal/fips140/rsa/keygen.go @@ -54,23 +54,42 @@ func GenerateKey(rand io.Reader, bits int) (*PrivateKey, error) { return nil, errors.New("rsa: internal error: modulus size incorrect") } - φ, err := bigmod.NewModulusProduct(P.Nat().SubOne(P).Bytes(P), - Q.Nat().SubOne(Q).Bytes(Q)) + // d can be safely computed as e⁻¹ mod φ(N) where φ(N) = (p-1)(q-1), and + // indeed that's what both the original RSA paper and the pre-FIPS + // crypto/rsa implementation did. + // + // However, FIPS 186-5, A.1.1(3) requires computing it as e⁻¹ mod λ(N) + // where λ(N) = lcm(p-1, q-1). + // + // This makes d smaller by 1.5 bits on average, which is irrelevant both + // because we exclusively use the CRT for private operations and because + // we use constant time windowed exponentiation. On the other hand, it + // requires computing a GCD of two values that are not coprime, and then + // a division, both complex variable-time operations. + λ, err := totient(P, Q) + if err == errDivisorTooLarge { + // The divisor is too large, try again with different primes. + continue + } if err != nil { return nil, err } e := bigmod.NewNat().SetUint(65537) - d, ok := bigmod.NewNat().InverseVarTime(e, φ) + d, ok := bigmod.NewNat().InverseVarTime(e, λ) if !ok { - // This checks that GCD(e, (p-1)(q-1)) = 1, which is equivalent + // This checks that GCD(e, lcm(p-1, q-1)) = 1, which is equivalent // to checking GCD(e, p-1) = 1 and GCD(e, q-1) = 1 separately in // FIPS 186-5, Appendix A.1.3, steps 4.5 and 5.6. + // + // We waste a prime by retrying the whole process, since 65537 is + // probably only a factor of one of p-1 or q-1, but the probability + // of this check failing is only 1/65537, so it doesn't matter. continue } - if e.ExpandFor(φ).Mul(d, φ).IsOne() == 0 { - return nil, errors.New("rsa: internal error: e*d != 1 mod φ(N)") + if e.ExpandFor(λ).Mul(d, λ).IsOne() == 0 { + return nil, errors.New("rsa: internal error: e*d != 1 mod λ(N)") } // FIPS 186-5, A.1.1(3) requires checking that d > 2^(nlen / 2). @@ -90,6 +109,52 @@ func GenerateKey(rand io.Reader, bits int) (*PrivateKey, error) { } } +// errDivisorTooLarge is returned by [totient] when gcd(p-1, q-1) is too large. +var errDivisorTooLarge = errors.New("divisor too large") + +// totient computes the Carmichael totient function λ(N) = lcm(p-1, q-1). +func totient(p, q *bigmod.Modulus) (*bigmod.Modulus, error) { + a, b := p.Nat().SubOne(p), q.Nat().SubOne(q) + + // lcm(a, b) = a×b / gcd(a, b) = a × (b / gcd(a, b)) + + // Our GCD requires at least one of the numbers to be odd. For LCM we only + // need to preserve the larger prime power of each prime factor, so we can + // right-shift the number with the fewest trailing zeros until it's odd. + // For odd a, b and m >= n, lcm(a×2ᵐ, b×2ⁿ) = lcm(a×2ᵐ, b). + az, bz := a.TrailingZeroBitsVarTime(), b.TrailingZeroBitsVarTime() + if az < bz { + a = a.ShiftRightVarTime(az) + } else { + b = b.ShiftRightVarTime(bz) + } + + gcd, err := bigmod.NewNat().GCDVarTime(a, b) + if err != nil { + return nil, err + } + if gcd.IsOdd() == 0 { + return nil, errors.New("rsa: internal error: gcd(a, b) is even") + } + + // To avoid implementing multiple-precision division, we just try again if + // the divisor doesn't fit in a single word. This would have a chance of + // 2⁻⁶⁴ on 64-bit platforms, and 2⁻³² on 32-bit platforms, but testing 2⁻⁶⁴ + // edge cases is impractical, and we'd rather not behave differently on + // different platforms, so we reject divisors above 2³²-1. + if gcd.BitLenVarTime() > 32 { + return nil, errDivisorTooLarge + } + if gcd.IsZero() == 1 || gcd.Bits()[0] == 0 { + return nil, errors.New("rsa: internal error: gcd(a, b) is zero") + } + if rem := b.DivShortVarTime(gcd.Bits()[0]); rem != 0 { + return nil, errors.New("rsa: internal error: b is not divisible by gcd(a, b)") + } + + return bigmod.NewModulusProduct(a.Bytes(p), b.Bytes(q)) +} + // randomPrime returns a random prime number of the given bit size following // the process in FIPS 186-5, Appendix A.1.3. func randomPrime(rand io.Reader, bits int) ([]byte, error) { diff --git a/src/crypto/internal/fips140/rsa/keygen_test.go b/src/crypto/internal/fips140/rsa/keygen_test.go index 7d613e6ddfd1c8..9104a9dfd85fc8 100644 --- a/src/crypto/internal/fips140/rsa/keygen_test.go +++ b/src/crypto/internal/fips140/rsa/keygen_test.go @@ -6,8 +6,10 @@ package rsa import ( "bufio" + "crypto/internal/fips140/bigmod" "encoding/hex" "fmt" + "math/big" "os" "strings" "testing" @@ -83,8 +85,94 @@ func TestMillerRabin(t *testing.T) { } } +func TestTotient(t *testing.T) { + f, err := os.Open("testdata/gcd_lcm_tests.txt") + if err != nil { + t.Fatal(err) + } + + var GCD, A, B, LCM string + var lineNum int + scanner := bufio.NewScanner(f) + for scanner.Scan() { + lineNum++ + line := scanner.Text() + if len(line) == 0 || line[0] == '#' { + continue + } + + k, v, _ := strings.Cut(line, " = ") + switch k { + case "GCD": + GCD = v + case "A": + A = v + case "B": + B = v + case "LCM": + LCM = v + + t.Run(fmt.Sprintf("line %d", lineNum), func(t *testing.T) { + if A == "0" || B == "0" { + t.Skip("skipping test with zero input") + } + if LCM == "1" { + t.Skip("skipping test with LCM=1") + } + + p, _ := bigmod.NewModulus(addOne(decodeHex(t, A))) + a, _ := bigmod.NewNat().SetBytes(decodeHex(t, A), p) + q, _ := bigmod.NewModulus(addOne(decodeHex(t, B))) + b, _ := bigmod.NewNat().SetBytes(decodeHex(t, B), q) + + gcd, err := bigmod.NewNat().GCDVarTime(a, b) + // GCD doesn't work if a and b are both even, but LCM handles it. + if err == nil { + if got := strings.TrimLeft(hex.EncodeToString(gcd.Bytes(p)), "0"); got != GCD { + t.Fatalf("unexpected GCD: got %s, want %s", got, GCD) + } + } + + lcm, err := totient(p, q) + if oddDivisorLargerThan32Bits(decodeHex(t, GCD)) { + if err != errDivisorTooLarge { + t.Fatalf("expected divisor too large error, got %v", err) + } + t.Skip("GCD too large") + } + if err != nil { + t.Fatalf("failed to calculate totient: %v", err) + } + if got := strings.TrimLeft(hex.EncodeToString(lcm.Nat().Bytes(lcm)), "0"); got != LCM { + t.Fatalf("unexpected LCM: got %s, want %s", got, LCM) + } + }) + default: + t.Fatalf("unknown key %q on line %d", k, lineNum) + } + } + if err := scanner.Err(); err != nil { + t.Fatal(err) + } +} + +func oddDivisorLargerThan32Bits(b []byte) bool { + x := new(big.Int).SetBytes(b) + x.Rsh(x, x.TrailingZeroBits()) + return x.BitLen() > 32 +} + +func addOne(b []byte) []byte { + x := new(big.Int).SetBytes(b) + x.Add(x, big.NewInt(1)) + return x.Bytes() +} + func decodeHex(t *testing.T, s string) []byte { t.Helper() + if len(s)%2 != 0 { + s = "0" + s + } b, err := hex.DecodeString(s) if err != nil { t.Fatalf("failed to decode hex %q: %v", s, err) diff --git a/src/crypto/internal/fips140/rsa/rsa.go b/src/crypto/internal/fips140/rsa/rsa.go index 7f759cff640e35..0bbf7010506107 100644 --- a/src/crypto/internal/fips140/rsa/rsa.go +++ b/src/crypto/internal/fips140/rsa/rsa.go @@ -229,7 +229,7 @@ func checkPrivateKey(priv *PrivateKey) error { // Check that de ≡ 1 mod p-1, and de ≡ 1 mod q-1. // // This implies that e is coprime to each p-1 as e has a multiplicative - // inverse. Therefore e is coprime to lcm(p-1,q-1,r-1,...) = exponent(ℤ/nℤ). + // inverse. Therefore e is coprime to lcm(p-1,q-1) = λ(N). // It also implies that a^de ≡ a mod p as a^(p-1) ≡ 1 mod p. Thus a^de ≡ a // mod n for all a coprime to n, as required. // diff --git a/src/crypto/internal/fips140/rsa/testdata/gcd_lcm_tests.txt b/src/crypto/internal/fips140/rsa/testdata/gcd_lcm_tests.txt new file mode 100644 index 00000000000000..b5a0c17ed2a204 --- /dev/null +++ b/src/crypto/internal/fips140/rsa/testdata/gcd_lcm_tests.txt @@ -0,0 +1,279 @@ +# GCD tests. +# +# These test vectors satisfy gcd(A, B) = GCD and lcm(A, B) = LCM. + +GCD = 0 +A = 0 +B = 0 +# Just to appease the syntax-checker. +LCM = 0 + +GCD = 1 +A = 92ff140ac8a659b31dd904161f9213706a08a817ae845e522c3af0c9096699e059b47c8c2f16434b1c5766ebb384b79190f2b2a62c2378f45e116890e7bb407a +B = 2f532c9e5902b0d68cd2ed69b2083bc226e8b04c549212c425a5287bb171c6a47fcb926c70cc0d34b8d6201c617aee66af865d31fdc8a2eeb986c19da8bb0897 +LCM = 1b2c97003e520b0bdd59d8c35a180b4aa36bce14211590435b990ad8f4c034ce3c77899581cb4ee1a022874203459b6d53859ab1d99ff755efa253fc0e5d8487bb000c13c566e8937f0fe90b95b68bc278610d4f232770b08d1f31bee55a03da47f2d0ebb9e7861c4f16cc22168b68593e9efcde00f54104b4c3e1a0b294d7f6 + +GCD = a +A = faaffa431343074f5c5d6f5788500d7bc68b86eb37edf166f699b4d75b76dae2cb7c8f6eccae8f18f6d510ef72f0b9633d5740c0bebb934d3be796bd9a53808e +B = 2f48ec5aa5511283c2935b15725d30f62244185573203b48c7eb135b2e6db5c115c9446ac78b020574665b06a75eb287e0dbeb5da7c193294699b4c2129d2ac4 +LCM = 4a15f305e9622aa19bd8f39e968bfc16d527a47f7a5219d7b02c242c77ef8b608a4a6141f643ca97cedf07c0f1f3e8879d2568b056718aa15c0756899a08ccbe0a658bae67face96fa110edb91757bfa4828e8ff7c5d71b204f36238b12dd26f17be8ba9771f7068d63e41d423671f898f054b1187605754bc5546f2b02c5ac + +GCD = 16 +A = cf0b21bde98b41b479ac8071086687a6707e9efaacd4e5299668ce1be8b13290f27fd32ae68df87c292e8583a09d73ec8e8a04a65a487380dcd7dacca3b6e692 +B = 3be3f563f81d5ad5c1211db7eff430aa345e830ce07b4bde7d4d32dba3ac618d2034351e5435fd6c7f077971fb4a1e83a7396a74fdff7fce1267112851db2582 +LCM = 233a2188de2c017235024b182286f17562b2ee5ab9fdfe4efa2f61c4ff99fa44e1ead5bf6cde05bd7502ce78373c83e3f9dbab0c9bb8620a87c2640bce5d12c685af656df789bb3d0ba1edbaa98cf4f0166d422ab17aa6706f8132264d45b72827d6671a00a9186e723379e3a3bb7902d08865f357c74100059f83800241976 + +GCD = 1 +A = dd7b7597d7c1eb399b1cea9b3042c14bd6022d31b1d2642a8f82fc32de6eadaf012fbbf349eaec4922a8468740ca73c6090833d6a69a380ed947b39c2f9b0b76 +B = 8e0dc8654e70eec55496038a8d3fff3c2086bc6dbfc0e2dbdf5bd7de03c5aef01a3982556ac3fc34fd5f13368be6cdc252c82367b7462e210f940f847d382dd9 +LCM = 7ae667df4bd4dd35bbec28719a9f1b5e1f396a9ab386c086742a6ab3014a3386d39f35b50624d0c5b4e6b206c2635c7de5ea69e2faa85dd616a7e36622962a07632839857aa49332942feccff2aee1c962e2f4e8ccfd738a5da5bf528b4c5a2440409350f5a17a39d234403e8482ccf838e0d2758ccfb8018198a51dbb407506 + +GCD = 1 +A = 0 +B = 1 +LCM = 0 + +GCD = 1 +A = 1 +B = 0 +LCM = 0 + +GCD = 1 +A = 1 +B = 1 +LCM = 1 + +GCD = 2b2 +A = dfccaa3549c1b59ab3e114fe87dc5d187719abad58c51724e972741eb895ab79a49f385f61d531ec5c88dbb505ae375093fa848165f71a5ed65e7832a42ade191a +B = fa58a81f43088da45e659fc1117d0f1cd015aa096c8e5377cf1832191baf7cc28b5c24998b93b64f8900a0973faedb9babaaf1854345f011739da8f1175d9684c +LCM = 5132f7ab7a982b9dc55114bd96800b7637f9742cf8a7a00a0d69d5e4574fc85792c89a1c52bcfc74b9d7f3f6164819466c46b2d622e280ced7ad1211604084a15dc1fd1951a05c8ce37122c0ec15891d818a70d3763670ea3195098de9b1ca50ea89893a9753fb9ea801541058f44801f7f50967124abfc864a2b01c41f94193c + +GCD = 8e +A = 248d96a8a4cab0a1b194e08c1146868b094597cadbc35531f0ed2d77cba9f15cb5cc7c10e64ce054bf93396d25259d750b3de3aba65073db1fd2b852a6454ac1a +B = 4c7bad8e1844901fd6a2ce2edc82e698d28ec95d6672ca148d85b49ecc78dd0a8b870e202244210bc98592b99ff6abbd20630f9eee7d46b15ccfae8d08b86799de +LCM = 13b01f9d9c6c13e90c97e3d95bbce5a835c631b3de3bd4ff5df13ad850f5223dbdf71c53912275d0397df9335ef3a3ba8e4684c6b25962bb7b18bc74144cb5edf0196f79863a7ff032619a71646a92281f7baace7f223d254cb4d05ec19bf8d4c8ce4455a9d770daec89c0d3cf338cbdae39cf982b3c4568f5c9def4e1133d28a + +GCD = 3e55 +A = 2fa97382f46676b7a4cc2b8153f17b58792d24660e187d33ce55c81cc193ccb6e1e2b89feea1d5fd8faa36e13bf947fb48635e450a4d1488d0978324194a1f43c6 +B = ab08ad074139963bc18e5d87ba68db64ca6f4c279616c64039b02c55f2375b3bc04114e8e05e1ba92fb6470768f61d123845aea36774c18612736a220934561faf +LCM = 82c7c377ecda2cb9228604cd287df5eff94edd4a539c3eb3b3fdd4b4a79d2f4eaf2b22f8286272d3dad2e370cfcd9ea4d93ebb3f049c52b8fa23b68a5bf79af989822e2cfb978f68c6a5058f47319dffcb455b089b06ae6db9e5c8a2b6e951d6e118bd2b4cd08b6e5733476a446a57387d940d1289ec00e24315821ed3a5daf2 + +GCD = a7a +A = 923706dfed67834a1e7e6c8e8e9f93bfbc0b43ca1f324886cf1f1380fb9b77109275d4b50af1b7689802fe9b3623ac46c7ba0e17e908c20278127b07a5c12d86ec +B = 64473e878a29021fac1c1ce34a63eae1f4f83ee6851333b67213278b9a4a16f005cba0e8cdb410035bb580062f0e486c1a3a01f4a4edf782495f1dc3ebfa837d86 +LCM = 57785ca45b8873032f1709331436995525eed815c55140582ce57fd852116835deac7ca9d95ce9f280e246ea4d4f1b7140ab7e0dd6dc869de87f1b27372098b155ad0a1828fd387dff514acc92eae708609285edaab900583a786caf95153f71e6e6092c8c5ee727346567e6f58d60a5e01c2fa8ebcf86da9ea46876ecc58e914 + +GCD = 42 +A = 0 +B = 42 +LCM = 0 + +GCD = 42 +A = 42 +B = 0 +LCM = 0 + +GCD = 42 +A = 42 +B = 42 +LCM = 42 + +GCD = f60d +A = ef7886c3391407529d5cf2e75ed53e5c3f74439ad2e2dc48a79bc1a5322789b4ced2914b97f8ff4b9910d212243b54001eb8b375365b9a87bd022dd3772c78a9fd63 +B = d1d3ec32fa3103911830d4ec9f629c5f75af7039e307e05bc2977d01446cd2cbeeb8a8435b2170cf4d9197d83948c7b8999d901fe47d3ce7e4d30dc1b2de8af0c6e4 +LCM = cc376ed2dc362c38a45a719b2ed48201dab3e5506e3f1314e57af229dc7f3a6a0dad3d21cfb148c23a0bbb0092d667051aa0b35cff5b5cc61a7c52dec4ed72f6783edf181b3bf0500b79f87bb95abc66e4055f259791e4e5eb897d82de0e128ecf8a091119475351d65b7f320272db190898a02d33f45f03e27c36cb1c45208037dc + +GCD = 9370 +A = 1ee02fb1c02100d1937f9749f628c65384ff822e638fdb0f42e27b10ee36e380564d6e861fcad0518f4da0f8636c1b9f5124c0bc2beb3ca891004a14cd7b118ddfe0 +B = 67432fd1482d19c4a1c2a4997eab5dbf9c5421977d1de60b739af94c41a5ad384cd339ebfaa43e5ad6441d5b9aaed5a9f7485025f4b4d5014e1e406d5bd838a44e50 +LCM = 159ff177bdb0ffbd09e2aa7d86de266c5de910c12a48cbe61f6fa446f63a2151194777555cd59903d24cb30965973571fb1f89c26f2b760526f73ded7ee8a34ebcecd1a3374a7559bcdb9ac6e78be17a62b830d6bb3982afdf10cf83d61fd0d588eab17d6abef8e6a7a5763fcb766d9a4d86adf5bb904f2dd6b528b9faec603987a0 + +GCD = c5f +A = 5a3a2088b5c759420ed0fb9c4c7685da3725b659c132a710ef01e79435e63d009d2931ea0a9ed9432f3d6b8851730c323efb9db686486614332c6e6ba54d597cf98 +B = 1b1eb33b006a98178bb35bbcf09c5bebd92d9ace79fa34c1567efa8d6cf6361547807cd3f8e7b8cd3ddb6209dccbae4b4c16c8c1ec19741a3a57f61571882b7aed7 +LCM = c5cbbbe9532d30d2a7dd7c1c8a6e69fd4fa4828a844d6afb44f3747fef584f7f1f3b835b006f8747d84f7699e88f6267b634e7aef78d6c7584829537d79514eec7d11219721f91015f5cefdc296261d85dba388729438991a8027de4827cd9eb575622e2912b28c9ce26d441e97880d18db025812cef5de01adeaec1322a9c9858 + +GCD = e052 +A = 67429f79b2ec3847cfc7e662880ab1d94acdf04284260fcfffd67c2862d59704ed45bcc53700c88a5eea023bc09029e9fd114fc94c227fd47a1faa1a5ef117b09bd2 +B = 39faa7cbdeb78f9028c1d50ab34fbe6924c83a1262596f6b85865d4e19cc258b3c3af1ee2898e39e5bee5839e92eac6753bbbb0253bd576d1839a59748b778846a86 +LCM = 1ab071fb733ef142e94def10b26d69982128561669e58b20b80d39cf7c2759d26b4a65d73b7f940c6e8fc417180ef62d7e52ac24678137bd927cd8d004ad52b02affe176a1ecde903dbc26dcc705678f76dd8cd874c0c3fe737474309767507bbe70dd7fb671bbb3694cedf0dcdaa0c716250ddd6dfec525261572fa3e1387f7b906 + +GCD = 3523 +A = 0 +B = 3523 +LCM = 0 + +GCD = 3523 +A = 3523 +B = 0 +LCM = 0 + +GCD = 3523 +A = 3523 +B = 3523 +LCM = 3523 + +GCD = f035a941 +A = 16cd5745464dfc426726359312398f3c4486ed8aaeea6386a67598b10f744f336c89cdafcb18e643d55c3a62f4ab2c658a0d19ea3967ea1af3aee22e11f12c6df6e886f7 +B = 74df09f309541d26b4b39e0c01152b8ad05ad2dfe9dd2b6706240e9d9f0c530bfb9e4b1cad3d4a94342aab309e66dd42d9df01b47a45173b507e41826f24eb1e8bcc4459 +LCM = b181771d0e9d6b36fdfcbf01d349c7de6b7e305e1485ea2aa32938aa919a3eee9811e1c3c649068a7572f5d251b424308da31400d81ac4078463f9f71d7efd2e681f92b13a6ab3ca5c9063032dcbdf3d3a9940ce65e54786463bbc06544e1280f25bc7579d264f6f1590cf09d1badbf542ce435a14ab04d25d88ddbac7d22e8cae1c91f + +GCD = 33ad1b8f +A = 1af010429a74e1b612c2fc4d7127436f2a5dafda99015ad15385783bd3af8d81798a57d85038bcf09a2a9e99df713b4d6fc1e3926910fbbf1f006133cb27dc5ebb9cca85 +B = 92a4f45a90965a4ef454f1cdd883d20f0f3be34d43588b5914677c39d577a052d1b25a522be1a656860a540970f99cbc8a3adf3e2139770f664b4b7b9379e13daf7d26c +LCM = 4c715520ed920718c3b2f62821bc75e3ff9fd184f76c60faf2906ef68d28cd540d3d6c071fa8704edd519709c3b09dfaee12cb02ab01ad0f3af4f5923d5705ce6d18bcab705a97e21896bb5dd8acb36ee8ec98c254a4ddc744297827a33c241f09016a5f109248c83dd41e4cea73ce3eabb28d76678b7e15545b96d22da83c111b6b624 + +GCD = dc0429aa +A = ccb423cfb78d7150201a97114b6644e8e0bbbb33cadb0ef5da5d3c521a244ec96e6d1538c64c10c85b2089bdd702d74c505adce9235aa4195068c9077217c0d431de7f96 +B = 710786f3d9022fc3acbf47ac901f62debcfda684a39234644bac630ab2d211111df71c0844b02c969fc5b4c5a15b785c96efd1e403514235dc9356f7faf75a0888de5e5a +LCM = 6929af911850c55450e2f2c4c9a72adf284fe271cf26e41c66e1a2ee19e30d928ae824f13d4e2a6d7bb12d10411573e04011725d3b6089c28d87738749107d990162b485805f5eedc8f788345bcbb5963641f73c303b2d92f80529902d3c2d7899623958499c8a9133aae49a616c96a2c5482a37947f23af18c3247203ac2d0e760340e6 + +GCD = 743166058 +A = 16cd476e8031d4624716238a3f85badd97f274cdfd9d53e0bd74de2a6c46d1827cc83057f3889588b6b7ca0640e7d743ed4a6eaf6f9b8df130011ecc72f56ef0af79680 +B = 86eba1fc8d761f22e0f596a03fcb6fe53ad15a03f5b4e37999f60b20966f78ba3280f02d3853f9ace40438ccfaf8faed7ace2f2bf089b2cdd4713f3f293bf602666c39f8 +LCM = 1a7a1b38727324d6ba0290f259b8e2b89c339b2445cada38a5a00ded1468ab069f40678ce76f7f78c7c6f97783cc8a49ef7e2a0c73abbac3abc66d1ce99566ce7f874a8949ca3442051e71967695dc65361184748c1908e1b587dc02ed899a524b34eb30b6f8db302432cfa1a8fbf2c46591e0ab3db7fd32c01b1f86c39832ee9f0c80 + +GCD = 6612ba2c +A = 0 +B = 6612ba2c +LCM = 0 + +GCD = 6612ba2c +A = 6612ba2c +B = 0 +LCM = 0 + +GCD = 6612ba2c +A = 6612ba2c +B = 6612ba2c +LCM = 6612ba2c + +GCD = 2272525aa08ccb20 +A = 11b9e23001e7446f6483fc9977140d91c3d82568dabb1f043a5620544fc3dda233b51009274cdb004fdff3f5c4267d34181d543d913553b6bdb11ce2a9392365fec8f9a3797e1200 +B = 11295529342bfb795f0611d03afb873c70bd16322b2cf9483f357f723b5b19f796a6206cf3ae3982daaeafcd9a68f0ce3355a7eba3fe4e743683709a2dd4b2ff46158bd99ff4d5a0 +LCM = 8d4cbf00d02f6adbaa70484bcd42ea932000843dcb667c69b75142426255f79b6c3b6bf22572597100c06c3277e40bf60c14c1f4a6822d86167812038cf1eefec2b0b19981ad99ad3125ff4a455a4a8344cbc609e1b3a173533db432bd717c72be25e05ed488d3970e7ed17a46353c5e0d91c8428d2fec7a93210759589df042cab028f545e3a00 + +GCD = 3480bf145713d56f9 +A = 8cf8ef1d4f216c6bcec673208fd93b7561b0eb8303af57113edc5c6ff4e1eeae9ddc3112b943d947653ba2179b7f63505465126d88ad0a0a15b682f5c89aa4a2a51c768cd9fdeaa9 +B = a6fd114023e7d79017c552a9051ca827f3ffa9f31e2ee9d78f8408967064fcdc9466e95cc8fac9a4fa88248987caf7cf57af58400d27abd60d9b79d2fe03fad76b879eceb504d7f +LCM = 1c05eee73a4f0db210a9007f94a5af88c1cdd2cba456061fd41de1e746d836fa4e0e972812842e0f44f10a61505f5d55760c48ba0d06af78bb6bde7da8b0080b29f82b1161e9c0b5458e05ac090b00f4d78b1cc10cf065124ba610e3acab092a36fe408525e21c0ddc7c9696ed4e48bd2f70423deecfe62cecc865c6088f265da0e5961d3f3a84f + +GCD = 917e74ae941fcaae +A = 652f8a92d96cbf0a309629011d0fbaceb1266bc2e8243d9e494eead4cf7100c661b537a8bea93dec88cfc68597d88a976c125c3b4de19aba38d4ea9578202e59848d42652518348a +B = 32e07b71979d57e8344e97c39680a61e07d692d824ae26b682156890792d8a766ee29a4968f461aaced5bf049044fba2f4120b1c1f05985676f975d4582e9e82750d73c532cd07b2 +LCM = 23620c7b897dc26c7717e32f3517ac70bf09fbe08f7255ab010cf4cf946f4e96304c425043452c5d5a0e841d3a3cfd9c2d84d9256f3b5974fe3ebfa9255fe20a710d3e6511606c0d85970381101c7f4986d65ad6a73a71507f146b11f903043cfa805cc0b14d4f3072da98bf22282f7762040406c02d5b3ef9e7587f63bab8b29c61d8e30911aa96 + +GCD = 2b9adc82005b2697 +A = 19764a84f46045ef1bca571d3cbf49b4545998e64d2e564cc343a53bc7a0bcfbe0baa5383f2b346e224eb9ce1137d9a4f79e8e19f946a493ff08c9b423574d56cbe053155177c37 +B = 1bbd489ad2ab825885cdac571a95ab4924e7446ce06c0f77cf29666a1e20ed5d9bc65e4102e11131d824acad1592075e13024e11f12f8210d86ab52aa60deb250b3930aabd960e5a +LCM = 1032a0c5fffc0425e6478185db0e5985c645dd929c7ebfeb5c1ee12ee3d7b842cfab8c9aa7ff3131ac41d4988fb928c0073103cea6bb2cc39808f1b0ad79a6d080eac5a0fc6e3853d43f903729549e03dba0a4405500e0096b9c8e00510c1852982baec441ed94efb80a78ed28ed526d055ad34751b831b8749b7c19728bf229357cc5e17eb8e1a + +GCD = 8d9d4f30773c4edf +A = 0 +B = 8d9d4f30773c4edf +LCM = 0 + +GCD = 8d9d4f30773c4edf +A = 8d9d4f30773c4edf +B = 0 +LCM = 0 + +GCD = 8d9d4f30773c4edf +A = 8d9d4f30773c4edf +B = 8d9d4f30773c4edf +LCM = 8d9d4f30773c4edf + +GCD = 6ebd8eafb9a957a6c3d3d5016be604f9624b0debf04d19cdabccf3612bbd59e00 +A = 34dc66a0ffd5b8b5e0ffc858dfc4655753e59247c4f82a4d2543b1f7bb7be0e24d2bbf27bb0b2b7e56ee22b29bbde7baf0d7bfb96331e27ba029de9ffdff7bdb7dc4da836d0e58a0829367ec84ea256833fd4fe1456ad4dd920557a345e12000 +B = 1f3406a20e20ebf96ccb765f898889a19b7636608fd7dc7c212607b641399543f71111d60e42989de01eaa6ff19a86ea8fbde1a3d368c0d86dc899e8e250fc764090f337958ca493119cbb4ad70cbfae7097d06d4f90ec62fbdd3f0a4496e600 +LCM = ee502c50e3667946e9089d0a9a0382e7fd0b75a17db23b56a0eec997a112c4dbd56d188808f76fe90451e5605550c9559ef14a95014c6eb97e9c1c659b98515c41470142843de60f72fb4c235faa55b0a97d943221003d44e2c28928f0b84bf071256254897ed31a7fd8d174fc962bc1311f67900ac3abcad83a28e259812f1ee229511ab1d82d41f5add34693ba7519babd52eb4ec9de31581f5f2e40a000 + +GCD = ef7399b217fc6a62b90461e58a44b22e5280d480b148ec4e3b4d106583f8e428 +A = 7025e2fe5f00aec73d90f5ad80d99ca873f71997d58e59937423a5e6ddeb5e1925ed2fd2c36a5a9fc560c9023d6332c5d8a4b333d3315ed419d60b2f98ccf28bbf5bf539284fd070d2690aeaac747a3d6384ee6450903a64c3017de33c969c98 +B = df0ac41dbabce1deeb0bceb1b65b1079850052ecf6534d0cff84a5a7fb5e63baee028d240f4419925154b96eaa69e8fbb1aae5102db7916234f290aa60c5d7e69406f02aeea9fe9384afbff7d878c9ac87cd31f7c35dff243b1441e09baff478 +LCM = 687669343f5208a6b2bb2e2efcac41ec467a438fde288cc5ef7157d130139ba65db9eb53e86a30c870bd769c0e0ab15a50f656cd9626621ae68d85eaff491b98da3ea5812062e4145af11ea5e1da457084911961ef2cd2ac45715f885ba94b4082aa76ffd1f32461f47c845b229d350bf36514c5ce3a7c782418746be342eca2721346ade73a59475f178c4f2448e1326110f5d26a0fef1a7a0c9288489e4dc8 + +GCD = 84b917557acf24dff70cb282a07fc52548b6fbbe96ca8c46d0397c8e44d30573 +A = 81dbb771713342b33912b03f08649fb2506874b96125a1ac712bc94bfd09b679db7327a824f0a5837046f58af3a8365c89e06ff4d48784f60086a99816e0065a5f6f0f49066b0ff4c972a6b837b63373ca4bb04dcc21e5effb6dfe38271cb0fa +B = 1da91553c0a2217442f1c502a437bb14d8c385aa595db47b23a97b53927b4493dd19f1bc8baf145bc10052394243089a7b88d19b6f106e64a5ab34acad94538ab504d1c8ebf22ac42048bbd1d4b0294a2e12c09fe2a3bd92756ba7578cb34b39 +LCM = 1d0530f8142754d1ee0249b0c3968d0ae7570e37dadbe4824ab966d655abf04cd6de5eb700eba89d8352dec3ae51f2a10267c32fbd39b788c7c5047fe69da3d7ad505435a6212f44899ba7e983bb780f62bcdee6f94b7dba8af7070a4cc008f351ae8be4579bc4a2e5c659ce000ad9c8cdc83723b32c96aeb0f5f4127f6347353d05525f559a8543cd389ad0af6f9d08a75b8c0b32419c097e6efe8746aee92e + +GCD = 66091477ea3b37f115038095814605896e845b20259a772f09405a8818f644aa +A = cedac27069a68edfd49bd5a859173c8e318ba8be65673d9d2ba13c717568754ed9cbc10bb6c32da3b7238cff8c1352d6325668fd21b4e82620c2e75ee0c4b1aff6fb1e9b948bbdb1af83cecdf356299b50543b72f801b6a58444b176e4369e0 +B = 5f64ca1ba481f42c4c9cf1ffa0e515b52aa9d69ceb97c4a2897f2e9fa87f72bae56ee6c5227f354304994c6a5cc742d9f09b2c058521975f69ca5835bce898cf22b28457cd7e28870df14e663bb46c9be8f6662f4ff34d5c4ae17a888eba504e +LCM = c163cb28642e19a40aa77887c63180c2c49fc10cda98f6f929c8131752ea30b5283a814a81681b69b9d1762e6c1a9db85f480bc17f998d235fd7e64c1caa70ef170c9e816d3e80f516b29f2c80cfb68bf208b4d5082ef078da4314b3f20c7d6c54b0aeb378096b029a7b61c0a4cd14aeddc01004c53915a4f692d2291752e5af46b23d7fa6dd61f2d56c6f4bf8e6119688abac8fd7aba80e846a7764bb3fca0 + +GCD = bb80bf51757ba696c700fa4e4c0132b3151d2bf9ebff8382f808ded78be67182 +A = 0 +B = bb80bf51757ba696c700fa4e4c0132b3151d2bf9ebff8382f808ded78be67182 +LCM = 0 + +GCD = bb80bf51757ba696c700fa4e4c0132b3151d2bf9ebff8382f808ded78be67182 +A = bb80bf51757ba696c700fa4e4c0132b3151d2bf9ebff8382f808ded78be67182 +B = 0 +LCM = 0 + +GCD = bb80bf51757ba696c700fa4e4c0132b3151d2bf9ebff8382f808ded78be67182 +A = bb80bf51757ba696c700fa4e4c0132b3151d2bf9ebff8382f808ded78be67182 +B = bb80bf51757ba696c700fa4e4c0132b3151d2bf9ebff8382f808ded78be67182 +LCM = bb80bf51757ba696c700fa4e4c0132b3151d2bf9ebff8382f808ded78be67182 + +GCD = 120451d8307219aa0c96f328ad653ccd462e92423ca93ed8a3dde45bf5cb9b13cdaf9800e4d05dd71c4db6a129fb3280ee4ec96ec5297d881c1a8b5efccbd91fef21f5c5bf5fba42a4c8eaa358f620a074b7a17054527bdaa58d5acaa0dfdc48ecba1a10ebf4d57bb4215de406e6be13fed3fe493b1cd1e2d11a8d4ac03c47756 +A = 3f8179a8e1f0b342475a855c3e1bae402dd41424cf24a0b4d2e263c8efb08bde7d92eae8607fb5e88b1378f0f1bd0733f229a35be6b1383a48d32749d5d6b32427d26323b7ab05bb5781289e96bfbc21971439319b15f6c0fe93fdb35d0b67ec41443c59a081dd3cef047ac797fccb45bece84c0bb0bb7e1797259526d8ec9cc63ba4d32cfc692ccd3d243cb2b53ac216312f3a8e8c0daa09d21b6150d697639a5e52059414a417c607be8ec0eee2e708219cadbaf37a369c4485b01ed87bbc2 +B = 2c474e396a2dd9cd10b9d7313f69d3b4ca123e9fd853edd488339236d14c56453a1381958864a04d2624e81995dabcdd0ccf60db9917813f887de68da075d0ea4440001e18f470e43b38ee3440b49be651d709fbdef980e3e4149913f4ae2681124f54523f4881376ddb533b5219e804cc26f4c2e577be4e02613c4da80ba1215775b0a5178a965ad47bd2befb32493943ded1004ef66347b4983f8d1ba990d4a943505dfce6debcfb322842ed88106cd6dee9aa592ff0d2274bc727a6e1f14c +LCM = 9c129cf649555bfd2d3d9c64dc6d6f022295e53bca5d2f218adaa66aa60eb4694429b7e83bf81b6df4459c5104023ab9a33f006ffcd8114507baa17e2ef6fe23ebdd4740f66879033da2041f2cb7ba517ad3526ffe75614ea9432c085f71b2d65a736bac7ba42b639e330b82733372083843dcb78b6a273ab20e0d4b7c8998a14048aa15bb20a0a0bd997917107274c89b4cec175fb98043d52e6c555bd9e0036566d052a6d4e7e276d1e8835e1f06e3ca46d47747ba586e95fb1a790d992834b7c3e136141eb8a434e6c12067246ac3c0a81c69e03b1ed28aa0b3173d6eff83d278c2f461a47a416f3f9a5dae3bb410fd18817bd4115e7f1e84b936cc02364 + +GCD = 95aa569a2c76854300d7660847dd20fe0b8c445fdbcaa98465cee61aee76ad6a438e75a8c573198570ffb62bc07ec3a2be0ae0a1f631670fa88d6f75f3161e8b9a4d44b6801ffc884c7f469c5ed1f27b1edecce9f2977f9e92d1a3b230492fea7e6f2af739dc158a7fbd29856cbedb57b4119e64b27ab09eb1c2df01507d6e7fd +A = 4c653b5bfec44e9be100c064dffe5d8cd59b0cf4cc56b03eabb4ef87cfda6506c9a756b811907fe9d8b783eb7a0b9e129773bf1da365ddb488d27b16fb983e89345d1ccdb4f06a67a11925c3f266373be5d7b0075189c6f3c2157e2da197058fe0a7bcc50adc34e99e254a29abbe2d5948d3157e1b0c3fca3d641760f7b9862843b63abef0b3d83fd486f4526b30382fda355575da30e9a106718a3921774c4d69f5311f8d737fe618f5236b4763fe1b2ee7f13184db67367d3903c535ff6d7b +B = 2dcca83c99a28e9fd2f84e78973699baf2f04fd454094730948b22477834a0064817b86e0835e6d7b26e5b0b1dcf4ad91a07ac0780d6522df1fcac758cf5db6c2a5623d7c0f1afefd5718f7b6de639867d07a9ec525991304e9355d1635104bea837f74758d6aa2aab4e4afbb606af1d98de7417505e4710cd0589bdff9a0bf38a857cc59a5f1781043e694fc2337fd84bdeb28b13a222bb09328a81ec409ad586e74236393d27398cc24d412135e34247c589149e134b97f4bd538ac9a3424b +LCM = 1760c0b0066aa0695767099e87e9388729ea89b8e8c36bddcd04d257591e741613c07b0e69447c0a468c33a745084171e06523d987d8db40a1433bf435325e8a724a0876503b34495170ff3671d42117a2e4f3a75b1d9dd809a34fa0fb26fe50d84f80a9b02e40190e5efb927a5a61a03f13edbce2e666af6c3a2a9bcb84e47e3090008753ff27c4b8cf06480f471379a93f5230923623a83b286b71a555cd5e5347282f664ed90b14b2c4de84a70375e488211a7b3931119ef3bbe029b712389fe784818a0bf29d80733ce9cc940c547aa1eb3f06d492eb676bf37802283c82ce76156dfaab5c2d5107e08062681b5fa169f6eb68e1ab8bd9b2005e90bd4fd + +GCD = 244b9b1290cf5b4ba2f810574c050651489f2d3a2b03e702b76ebfaf4e33de9bbe5da24c919e68d3a72eadd35982b3a89c6b18b38ff7082ac65263e52b6ec75a5717b971c98257b194c828bff0216a99536603b41a396ea2fb50f5ea7cf3edf10bb0d039123e78593ae9ffcbbba02e51e038533e83b6bc73c70551d6467f39809 +A = 41a0b1310669500681cdf888836f6c556758750f562d743ac780dd4c0d161856380e44fdbb1f8a2786bf45be6b0e7f1cb2cd85f6b9e50acc72793d92383c7d7fb796fc74d32e8fac8225bdc19ae47546d9c9c75f5f06ca684f07daccaf89ccf2cddeb7ec255d530c7dd1e71daf44cafdc9d30fbcb1cbaefae3480585f79f4177e3834a5bc91845e2e8cd8aeb27f484e5e5b2c3c076dbb6c23e91303f0a0fdde83cd33a8ea6ed1549e727b4d766c1017c169710fd98e1585d60f66e121f9180b3 +B = 251f5aeaa60b3959285f49540cdaf8e21451110bbddb9933bbbcaea3112f4eb45e435a3ba37c52d2ab79ce997a8f6c829b3aa561f2852924b8effb52396d09d2bf257ebb4fb56c7aa25648f69b06d2cd01e876c9f9c0679de9e6fffa79eb7e603723e5af7de46ee405a5a079229577b5b6fffb8d43e391fe6f4eb89638e64d6eff8026249aaa355a91625eb0bfd14caa81e4c3586aaa2e94fde143a44f223a91e226661d12f55dfcdb4215e5a64e14e968005733be6a71c465de312ca109b34a +LCM = 431f918b274f3e43f446e4e85567883d6536a0332db662cef088f5a36b0f4b68372048174ba10fee94b9f8f1c2e189c974be2e6e8ae8e2ae108445326d40f63e38d8d4e2e46174589a3cbc9583e0036dc8146e79eee9e96f4436313b3f143dd0f5aceab05243def7f915169c360f55ef123977cf623c5ba432c3259c62fb5e37d5adab0f24b825aa4ada99ec4e83e9ca4698399e1ed633091ce5f9844c540a642cd264201116ed4168aa2105a5159f5df064f845830c469140f766c7319052ce59bd1ad7c3f2d8c30e54f147f6aeb5586c70c984302ba18d854a60aec01b394c7d66fa33fe18fe4a8cfb3238df219294e6e42190a30d28b10049a1b75853a4e + +GCD = 206695d52bc391a4db61bf8cb6ea96188333a9c78f477ee76976c2346dad682cf56ca6f176d86ef67d41ff5921b6162b0eca52359975872430dd14c45643eacdf028d830770714c033fd150669705851b2f02de932322d271d565d26768530c3f6cb84f0b3356f970b9070b26c050ead0417152c324c8ffe266d4e8b5b7bef3a +A = 1114eb9f1a9d5947eb1399e57f5c980833489685023ed2fe537fe1276c1e026b9a19e6fff55aa889d6c4e977b6e6f3111e2ad463138637b50f42cf32e57d83f282de9e72f813e5969195159a666d74dcd689bd527c60199ae327f7bd548ac36868fea5fdf6f35d19b921e7c10b6448ca480de6826478cd0642d72f05af3f8e65ce42409fbd49f56e81946e89c8e83962c4edc0ed54600600a305e52d081aed3c351e450e11f8fb0ce5754c92cf765b71393b2b7a89c95df79b9ea1b3cb600862 +B = 1d8f3179ca7b5cc7119360c10de939ffa57c9043da2f2b0ca3009c9bdad9f19ed16e3c2c197bef4b527fa1bf2bbab98b77e26c329911db68bd63d3d0fbfc727a977395b9ad067106de3094d68e097830858c5ccfa505fc25e972bdee6f347e7d1163efacd3d29a791ec2a94ffeed467884ae04896efc5e7e5f43d8d76c147e3c9951a1999173bc4e5767d51268b92cc68487ba1295372143b538711e0a62bf0ac111cc750ca4dd6c318c9cbe106d7fc492261404b86a1ba728e2d25b1976dc42 +LCM = f9570211f694141bfb096560551080cbe02a80271b4505591aaea9e3b99ea1d5ac1c1f2378fd72799e117ac2a73381b1ad26314e39972164d93971479ee3ba21a4d98cef0bd299d540ce5826995dcee0de420dff73d30b23cbf3188c625c7696df517535bc5675d71faa00807efbebdca547933f4a37849d1c014484a77da6df0670c4974bcc91eb5f5fe5faf9dd095ef195ec32ad9eeebf0e63288b4032ed9e70b888afc642f4ff96f0b4c0a68787301c12e4527fe79bdfe72dd3844ab5e094a9295df6616f24d1b9eeebc2116177dacf91969dda73667bc421ef3ccd8d5c23dddc283f5d36568d31f2654926be67f78e181075bdc148f2b39c630b141ae8a + +GCD = 3d319c42d872f21131ce5ff3ab8bec94339308e620316dda218e85fedcd511cd62f0b2f3448d5e58fd3520ae8118abd54ead9ad9e8ec3890365c6b2cca2172d4b8839b2d2c5ab02f65180826cb0cd5c9798f5d6261efe6e6ec31dea047da7c486b0590359e6f333557f67ceebf9ea9cd5dd986a999a8c88bdbd0ca21816b2423 +A = 0 +B = 3d319c42d872f21131ce5ff3ab8bec94339308e620316dda218e85fedcd511cd62f0b2f3448d5e58fd3520ae8118abd54ead9ad9e8ec3890365c6b2cca2172d4b8839b2d2c5ab02f65180826cb0cd5c9798f5d6261efe6e6ec31dea047da7c486b0590359e6f333557f67ceebf9ea9cd5dd986a999a8c88bdbd0ca21816b2423 +LCM = 0 + +GCD = 3d319c42d872f21131ce5ff3ab8bec94339308e620316dda218e85fedcd511cd62f0b2f3448d5e58fd3520ae8118abd54ead9ad9e8ec3890365c6b2cca2172d4b8839b2d2c5ab02f65180826cb0cd5c9798f5d6261efe6e6ec31dea047da7c486b0590359e6f333557f67ceebf9ea9cd5dd986a999a8c88bdbd0ca21816b2423 +A = 3d319c42d872f21131ce5ff3ab8bec94339308e620316dda218e85fedcd511cd62f0b2f3448d5e58fd3520ae8118abd54ead9ad9e8ec3890365c6b2cca2172d4b8839b2d2c5ab02f65180826cb0cd5c9798f5d6261efe6e6ec31dea047da7c486b0590359e6f333557f67ceebf9ea9cd5dd986a999a8c88bdbd0ca21816b2423 +B = 0 +LCM = 0 + +GCD = 3d319c42d872f21131ce5ff3ab8bec94339308e620316dda218e85fedcd511cd62f0b2f3448d5e58fd3520ae8118abd54ead9ad9e8ec3890365c6b2cca2172d4b8839b2d2c5ab02f65180826cb0cd5c9798f5d6261efe6e6ec31dea047da7c486b0590359e6f333557f67ceebf9ea9cd5dd986a999a8c88bdbd0ca21816b2423 +A = 3d319c42d872f21131ce5ff3ab8bec94339308e620316dda218e85fedcd511cd62f0b2f3448d5e58fd3520ae8118abd54ead9ad9e8ec3890365c6b2cca2172d4b8839b2d2c5ab02f65180826cb0cd5c9798f5d6261efe6e6ec31dea047da7c486b0590359e6f333557f67ceebf9ea9cd5dd986a999a8c88bdbd0ca21816b2423 +B = 3d319c42d872f21131ce5ff3ab8bec94339308e620316dda218e85fedcd511cd62f0b2f3448d5e58fd3520ae8118abd54ead9ad9e8ec3890365c6b2cca2172d4b8839b2d2c5ab02f65180826cb0cd5c9798f5d6261efe6e6ec31dea047da7c486b0590359e6f333557f67ceebf9ea9cd5dd986a999a8c88bdbd0ca21816b2423 +LCM = 3d319c42d872f21131ce5ff3ab8bec94339308e620316dda218e85fedcd511cd62f0b2f3448d5e58fd3520ae8118abd54ead9ad9e8ec3890365c6b2cca2172d4b8839b2d2c5ab02f65180826cb0cd5c9798f5d6261efe6e6ec31dea047da7c486b0590359e6f333557f67ceebf9ea9cd5dd986a999a8c88bdbd0ca21816b2423 + +GCD = 2 +A = 14e95a85e59ade9ef39e2f400c65db18702fa5fc485b9bba479a5282b2206129160e54f73ef4917983c17b4c5ebff7be112a886de069706eee29ba902515cb038 +B = ddcfff1d39c90c599f55495bf71c1e7597c6b08b7430707f360c6a6e5137bbc7b403c6d9e2c34f3d2f29d5d32b869346853c2de239cc35381bdfb4a01569211a +LCM = 90f38564ee72e55d362c04599e7d74f068c75f541b84e97abba2841f1a9f66b06b5c9009f6a4c2e319fced85270588de03ccebddbd9279aaecb13bdc1dbea7f42acaee751cb7da83779b8785cc86f41b94b13b54964208ca287d981634778d1096f20e76ca636c0717fd27e0800c43f599a5eded807421b502eaf9990a8c8ed8 + +GCD = 4 +A = 3c719c1c363cdeb7b57c2aabb71f425da4c3e6d3e447204d555e7cf0f3d372bdda906f36078045044978dafc20171767c8b1464d52dfdf3e2ba8a4906da033a8 +B = 30fe0ef151ac51404e128c064d836b191921769dc02d9b09889ed40eb68d15bfdd2edea33580a1a4d7dcee918fefd5c776cbe80ca6131aa080d3989b5e77e1b24 +LCM = 2e4526157bbd765b0486d90bcd4728f890bc6dbd9a855c67ca5cb2d6b48f8e74e1d99485999e04b193afca58dbf282610185d6c0272007744ff26e00dbdc813929b47940b137dc56ba974da07d54a1c50ec4a5c2b26e83f47cf17f4ccce8c3687e8d1e91d7c491a599f3d057c73473723ce9eee52c20fe8ae1595447552a7ee8 + +GCD = 10 +A = 44e04071d09119ea9783a53df35de4a989200133bb20280fdca6003d3ca63fdd9350ad1a1673d444d2f7c7be639824681643ec4f77535c626bd3ee8fa100e0bb0 +B = ca927a5a3124ce89accd6ac41a8441d352a5d42feb7f62687a5ebc0e181cc2679888ecc2d38516bdc3b3443550efccac81e53044ae9341ecace2598fe5ce67780 +LCM = 36805ba9b2412a0cb3fe4ed9bdabfa55515c9d615a3d0af268c45c5f6098d2de4a583f3791f1e3883c55d51ce23c5658fd0e8faa9a3709a1cfbd6a61dbab861690f27c86664f084c86cfd4a183b24aaadf59a6f8cbec04f1b0ded8a59b188cb46ae920052e3e099a570540dbc00f7d4a571eef08aa70d2d189a1804bf04e94a80 + +GCD = 100 +A = 73725032b214a677687c811031555b0c51c1703f10d59b97a4d732b7feaec5726cb3882193419d3f057583b2bc02b297d76bb689977936febaae92638fdfc46a00 +B = 979f4c10f4dc60ad15068cedd62ff0ab293aeaa1d6935763aed41fe3e445de2e366e8661eadf345201529310f4b805c5800b99f351fddab95d7f313e3bb429d900 +LCM = 4460439b4be72f533e9c7232f7e99c48328b457969364c951868ceab56cb2cbbeda8be2e8e3cae45c0758048468b841fdb246b2086d19b59d17b389333166ab82ed785860620d53c44f7aaaff4625ee70fb8072df10fb4d1acb142eadc02978ff2bb07cea9f434e35424b3323a7bda3a1a57aa60c75e49ebb2f59fb653aa77da00 + +GCD = 100000000 +A = f8b4f19e09f5862d79fb2931c4d616a1b8e0dd44781ca52902c8035166c8fca52d33a56ff484c365ec1257de7fa8ed2786163cfc051d5223b4aad859a049e8ba00000000 +B = 6e54cb41b454b080e68a2c3dd0fa79f516eb80239af2be8250ca9cd377ba501aabafc09146fad4402bdc7a49f2c3eec815e25f4c0a223f58e36709eefd92410500000000 +LCM = 6b3020a880ddeff9d17d3dc234da8771962de3322cd15ba7b1e4b1dd4a6a2a802a16c49653865c6fdf6c207cbe0940f8d81ef4cb0e159385fd709d515ee99d109ad9ad680031cbae4eab2ed62944babdade4e3036426b18920022f737897c7d751dce98d626cdda761fec48ad87a377fb70f97a0a15aa3d10d865785719cc5a200000000 From d8ad4af78bba1f4bf2bb1ce1ace2b62bc86540fd Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Sat, 4 Jan 2025 03:44:40 +1100 Subject: [PATCH 105/397] cmd/internal/disasm: correct instruction length handling for riscv64 disasm_riscv64 currently always returns an instruction length of four, which is not correct if compressed instructions are in use. Return the length of the decoded instruction, defaulting to two bytes if the instruction is unknown. With this change it is possible to correctly objdump a binary that is written in C and includes compressed instructions: $ go tool objdump ./hello TEXT _start(SB) :0 0x5b0 ef002002 CALL 8(PC) :0 0x5b4 aa87 ADD X10, X0, X15 :0 0x5b6 17250000 AUIPC $2, X10 :0 0x5ba 033525a3 MOV -1486(X10), X10 :0 0x5be 8265 MOV (X2), X11 :0 0x5c0 3000 ADDI $8, X2, X12 ... Fixes #71102 Change-Id: Ia99eb114a98c6d535de872ce8a526cd5e6203fff Reviewed-on: https://go-review.googlesource.com/c/go/+/639995 Reviewed-by: Michael Knyszek Reviewed-by: Jorropo LUCI-TryBot-Result: Go LUCI Reviewed-by: Michael Pratt --- src/cmd/internal/disasm/disasm.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/cmd/internal/disasm/disasm.go b/src/cmd/internal/disasm/disasm.go index c317effa900f60..3ae8989b38d080 100644 --- a/src/cmd/internal/disasm/disasm.go +++ b/src/cmd/internal/disasm/disasm.go @@ -410,14 +410,16 @@ func disasm_ppc64(code []byte, pc uint64, lookup lookupFunc, byteOrder binary.By func disasm_riscv64(code []byte, pc uint64, lookup lookupFunc, byteOrder binary.ByteOrder, gnuAsm bool) (string, int) { inst, err := riscv64asm.Decode(code) var text string + size := inst.Len if err != nil || inst.Op == 0 { + size = 2 text = "?" } else if gnuAsm { text = fmt.Sprintf("%-36s // %s", riscv64asm.GoSyntax(inst, pc, lookup, textReader{code, pc}), riscv64asm.GNUSyntax(inst)) } else { text = riscv64asm.GoSyntax(inst, pc, lookup, textReader{code, pc}) } - return text, 4 + return text, size } func disasm_s390x(code []byte, pc uint64, lookup lookupFunc, _ binary.ByteOrder, gnuAsm bool) (string, int) { From 27c516437439c47c2479201191642bf7aaf5885b Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Mon, 16 Dec 2024 17:20:46 +0100 Subject: [PATCH 106/397] crypto/internal/fips140: zeroise integrity test temporary values There is no point to zeroise anything here because there are no secrets, but there is a strict FIPS 140-3 test requirement for it. > TE05.08.02 (Levels 1, 2, 3, and 4): verify that any temporary values > generated during the integrity test are zeroised upon completion of > the integrity test Change-Id: I7b0db075dae9910f8e825a22ca2caa2b4c918980 Reviewed-on: https://go-review.googlesource.com/c/go/+/636556 LUCI-TryBot-Result: Go LUCI Reviewed-by: Daniel McCarney Reviewed-by: Michael Pratt Reviewed-by: Roland Shoemaker Auto-Submit: Filippo Valsorda --- src/crypto/internal/fips140/check/check.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/crypto/internal/fips140/check/check.go b/src/crypto/internal/fips140/check/check.go index 9d2e5d5cf6db68..f8a5d7a41e982e 100644 --- a/src/crypto/internal/fips140/check/check.go +++ b/src/crypto/internal/fips140/check/check.go @@ -93,6 +93,13 @@ func init() { panic("fips140: verification mismatch") } + // "The temporary value(s) generated during the integrity test of the + // module’s software or firmware shall [05.10] be zeroised from the module + // upon completion of the integrity test" + clear(sum) + clear(nbuf[:]) + h.Reset() + if godebug.Value("#fips140") == "debug" { println("fips140: verified code+data") } From 850b276a6765d20bf01c44d6126386e8fb7d8a76 Mon Sep 17 00:00:00 2001 From: thekuwayama Date: Mon, 30 Dec 2024 19:28:35 +0000 Subject: [PATCH 107/397] crypto/tls: send illegal_parameter on invalid ECHClientHello.type The spec indicates that if a client sends an invalid ECHClientHello.type in ClientHelloOuter, the server will abort the handshake with a decode_error alert. Define errInvalidECHExt for invalid ECHClientHello.type. If parseECHExt returns an errInvalidECHExt error, Conn now sends an illegal_parameter alert. Fixes #71061. Change-Id: I240241fe8bbe3e77d6ad1af989794647bfa2ff87 GitHub-Last-Rev: 3d6c233ccd401453bfb1a4fc97fa5deeb5b2fbc8 GitHub-Pull-Request: golang/go#71062 Reviewed-on: https://go-review.googlesource.com/c/go/+/639235 Reviewed-by: Dmitri Shuralyov LUCI-TryBot-Result: Go LUCI Reviewed-by: Roland Shoemaker --- src/crypto/tls/ech.go | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/crypto/tls/ech.go b/src/crypto/tls/ech.go index 55d52179c2c823..d9795b4ee2e291 100644 --- a/src/crypto/tls/ech.go +++ b/src/crypto/tls/ech.go @@ -378,7 +378,7 @@ func decodeInnerClientHello(outer *clientHelloMsg, encoded []byte) (*clientHello } if !bytes.Equal(inner.encryptedClientHello, []byte{uint8(innerECHExt)}) { - return nil, errors.New("tls: client sent invalid encrypted_client_hello extension") + return nil, errInvalidECHExt } if len(inner.supportedVersions) != 1 || (len(inner.supportedVersions) >= 1 && inner.supportedVersions[0] != VersionTLS13) { @@ -481,6 +481,7 @@ func (e *ECHRejectionError) Error() string { } var errMalformedECHExt = errors.New("tls: malformed encrypted_client_hello extension") +var errInvalidECHExt = errors.New("tls: client sent invalid encrypted_client_hello extension") type echExtType uint8 @@ -507,7 +508,7 @@ func parseECHExt(ext []byte) (echType echExtType, cs echCipher, configID uint8, return echType, cs, 0, nil, nil, nil } if echType != outerECHExt { - err = errMalformedECHExt + err = errInvalidECHExt return } if !s.ReadUint16(&cs.KDFID) { @@ -549,8 +550,13 @@ func marshalEncryptedClientHelloConfigList(configs []EncryptedClientHelloKey) ([ func (c *Conn) processECHClientHello(outer *clientHelloMsg) (*clientHelloMsg, *echServerContext, error) { echType, echCiphersuite, configID, encap, payload, err := parseECHExt(outer.encryptedClientHello) if err != nil { - c.sendAlert(alertDecodeError) - return nil, nil, errors.New("tls: client sent invalid encrypted_client_hello extension") + if errors.Is(err, errInvalidECHExt) { + c.sendAlert(alertIllegalParameter) + } else { + c.sendAlert(alertDecodeError) + } + + return nil, nil, errInvalidECHExt } if echType == innerECHExt { @@ -597,7 +603,7 @@ func (c *Conn) processECHClientHello(outer *clientHelloMsg) (*clientHelloMsg, *e echInner, err := decodeInnerClientHello(outer, encodedInner) if err != nil { c.sendAlert(alertIllegalParameter) - return nil, nil, errors.New("tls: client sent invalid encrypted_client_hello extension") + return nil, nil, errInvalidECHExt } c.echAccepted = true From a9bd6239a440dedc354f7651259fabef4610ebdc Mon Sep 17 00:00:00 2001 From: Michael Matloob Date: Mon, 6 Jan 2025 14:08:53 -0500 Subject: [PATCH 108/397] cmd/go/internal/env: add GOCACHEPROG to go env output For #71059 Change-Id: I4bbdd14d416dc2e6dae3549a84c16dbef9d4e645 Reviewed-on: https://go-review.googlesource.com/c/go/+/640755 Reviewed-by: Sam Thanawalla Reviewed-by: Austin Clements LUCI-TryBot-Result: Go LUCI --- src/cmd/go/internal/cache/default.go | 4 +- src/cmd/go/internal/cfg/cfg.go | 5 ++- src/cmd/go/internal/envcmd/env.go | 1 + .../go/testdata/script/env_gocacheprog.txt | 42 +++++++++++++++++++ 4 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 src/cmd/go/testdata/script/env_gocacheprog.txt diff --git a/src/cmd/go/internal/cache/default.go b/src/cmd/go/internal/cache/default.go index 074f9115933739..f8e5696cbd1e84 100644 --- a/src/cmd/go/internal/cache/default.go +++ b/src/cmd/go/internal/cache/default.go @@ -54,8 +54,8 @@ func initDefaultCache() Cache { base.Fatalf("failed to initialize build cache at %s: %s\n", dir, err) } - if v := cfg.Getenv("GOCACHEPROG"); v != "" { - return startCacheProg(v, diskCache) + if cfg.GOCACHEPROG != "" { + return startCacheProg(cfg.GOCACHEPROG, diskCache) } return diskCache diff --git a/src/cmd/go/internal/cfg/cfg.go b/src/cmd/go/internal/cfg/cfg.go index 6c2af99c2dfb09..3b9f27e91d517e 100644 --- a/src/cmd/go/internal/cfg/cfg.go +++ b/src/cmd/go/internal/cfg/cfg.go @@ -425,8 +425,9 @@ var ( GOROOTpkg string GOROOTsrc string - GOBIN = Getenv("GOBIN") - GOMODCACHE, GOMODCACHEChanged = EnvOrAndChanged("GOMODCACHE", gopathDir("pkg/mod")) + GOBIN = Getenv("GOBIN") + GOCACHEPROG, GOCACHEPROGChanged = EnvOrAndChanged("GOCACHEPROG", "") + GOMODCACHE, GOMODCACHEChanged = EnvOrAndChanged("GOMODCACHE", gopathDir("pkg/mod")) // Used in envcmd.MkEnv and build ID computations. GOARM64, goARM64Changed = EnvOrAndChanged("GOARM64", buildcfg.DefaultGOARM64) diff --git a/src/cmd/go/internal/envcmd/env.go b/src/cmd/go/internal/envcmd/env.go index 19db68e4f8f01d..7c370d427f9c2f 100644 --- a/src/cmd/go/internal/envcmd/env.go +++ b/src/cmd/go/internal/envcmd/env.go @@ -85,6 +85,7 @@ func MkEnv() []cfg.EnvVar { {Name: "GOAUTH", Value: cfg.GOAUTH, Changed: cfg.GOAUTHChanged}, {Name: "GOBIN", Value: cfg.GOBIN}, {Name: "GOCACHE"}, + {Name: "GOCACHEPROG", Value: cfg.GOCACHEPROG, Changed: cfg.GOCACHEPROGChanged}, {Name: "GODEBUG", Value: os.Getenv("GODEBUG")}, {Name: "GOENV", Value: envFile, Changed: envFileChanged}, {Name: "GOEXE", Value: cfg.ExeSuffix}, diff --git a/src/cmd/go/testdata/script/env_gocacheprog.txt b/src/cmd/go/testdata/script/env_gocacheprog.txt new file mode 100644 index 00000000000000..f5f15ed0784fda --- /dev/null +++ b/src/cmd/go/testdata/script/env_gocacheprog.txt @@ -0,0 +1,42 @@ +# GOCACHEPROG unset +env GOCACHEPROG= + +go env +stdout 'GOCACHEPROG=''?''?' + +go env -changed +! stdout 'GOCACHEPROG' + +go env -changed -json +! stdout 'GOCACHEPROG' + +# GOCACHEPROG set +[short] skip 'compiles and runs a go program' + +go build -o cacheprog$GOEXE cacheprog.go + +env GOCACHEPROG=$GOPATH/src/cacheprog$GOEXE + +go env +stdout 'GOCACHEPROG=''?'$GOCACHEPROG'''?' + +go env -changed +stdout 'GOCACHEPROG=''?'$GOCACHEPROG'''?' + +go env -changed -json +stdout '"GOCACHEPROG": "'$GOCACHEPROG'"' + +-- cacheprog.go -- +// This is a minimal GOCACHEPROG program that can't actually do anything but exit. +package main + +import ( + "encoding/json" + "os" +) + +func main() { + json.NewEncoder(os.Stdout).Encode(map[string][]string{"KnownCommands": {"close"}}) + var res struct{} + json.NewDecoder(os.Stdin).Decode(&res) +} \ No newline at end of file From 1d20bce981005777424b9c8da199015ab2148810 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Mon, 6 Jan 2025 13:25:08 -0800 Subject: [PATCH 109/397] go/types, types2: expand documentation for Info.Types map Function types for function (and method) declarations do not appear in Info.Types maps, only Info.Defs maps, because the function type is implicit in the declaration and not a proper (function) type expression. This is true even though the AST represents these types via an (artificial) FuncType node. Document this explicitly in the API. No functional code changes. Fixes #70908. Change-Id: I2aa897daed04e7ad0fa8b625d9adc7b423c57387 Reviewed-on: https://go-review.googlesource.com/c/go/+/640776 Reviewed-by: Alan Donovan Auto-Submit: Robert Griesemer Reviewed-by: Robert Griesemer Reviewed-by: Robert Findley LUCI-TryBot-Result: Go LUCI --- src/cmd/compile/internal/types2/api.go | 18 +++++++++++++----- src/go/types/api.go | 18 +++++++++++++----- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/cmd/compile/internal/types2/api.go b/src/cmd/compile/internal/types2/api.go index 74c549076df090..49cc0e54ecf750 100644 --- a/src/cmd/compile/internal/types2/api.go +++ b/src/cmd/compile/internal/types2/api.go @@ -208,11 +208,19 @@ type Info struct { // // The Types map does not record the type of every identifier, // only those that appear where an arbitrary expression is - // permitted. For instance, the identifier f in a selector - // expression x.f is found only in the Selections map, the - // identifier z in a variable declaration 'var z int' is found - // only in the Defs map, and identifiers denoting packages in - // qualified identifiers are collected in the Uses map. + // permitted. For instance: + // - an identifier f in a selector expression x.f is found + // only in the Selections map; + // - an identifier z in a variable declaration 'var z int' + // is found only in the Defs map; + // - an identifier p denoting a package in a qualified + // identifier p.X is found only in the Uses map. + // + // Similarly, no type is recorded for the (synthetic) FuncType + // node in a FuncDecl.Type field, since there is no corresponding + // syntactic function type expression in the source in this case + // Instead, the function type is found in the Defs.map entry for + // the corresponding function declaration. Types map[syntax.Expr]TypeAndValue // If StoreTypesInSyntax is set, type information identical to diff --git a/src/go/types/api.go b/src/go/types/api.go index dea974bec80918..beb2258c8b6f47 100644 --- a/src/go/types/api.go +++ b/src/go/types/api.go @@ -217,11 +217,19 @@ type Info struct { // // The Types map does not record the type of every identifier, // only those that appear where an arbitrary expression is - // permitted. For instance, the identifier f in a selector - // expression x.f is found only in the Selections map, the - // identifier z in a variable declaration 'var z int' is found - // only in the Defs map, and identifiers denoting packages in - // qualified identifiers are collected in the Uses map. + // permitted. For instance: + // - an identifier f in a selector expression x.f is found + // only in the Selections map; + // - an identifier z in a variable declaration 'var z int' + // is found only in the Defs map; + // - an identifier p denoting a package in a qualified + // identifier p.X is found only in the Uses map. + // + // Similarly, no type is recorded for the (synthetic) FuncType + // node in a FuncDecl.Type field, since there is no corresponding + // syntactic function type expression in the source in this case + // Instead, the function type is found in the Defs.map entry for + // the corresponding function declaration. Types map[ast.Expr]TypeAndValue // Instances maps identifiers denoting generic types or functions to their From 9d0772b23ed8dae1667a3328a72f384eccf812d7 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Mon, 6 Jan 2025 16:22:10 -0800 Subject: [PATCH 110/397] cmd/compile/internal/syntax: add test case for invalid label use This case is not properly handled by the type checkers (see issue) but the compiler uses the parser's label checking so it works as expected. For #70974. Change-Id: I0849376bf7514a9a7730846649c3fe28c91f44ca Reviewed-on: https://go-review.googlesource.com/c/go/+/640895 LUCI-TryBot-Result: Go LUCI Reviewed-by: Alan Donovan Reviewed-by: Robert Griesemer Auto-Submit: Robert Griesemer --- .../internal/syntax/testdata/issue70974.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/cmd/compile/internal/syntax/testdata/issue70974.go diff --git a/src/cmd/compile/internal/syntax/testdata/issue70974.go b/src/cmd/compile/internal/syntax/testdata/issue70974.go new file mode 100644 index 00000000000000..ebc69eda950254 --- /dev/null +++ b/src/cmd/compile/internal/syntax/testdata/issue70974.go @@ -0,0 +1,17 @@ +// Copyright 2025 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +func _() { +M: +L: + for range 0 { + break L + break /* ERROR invalid break label M */ M + } + for range 0 { + break /* ERROR invalid break label L */ L + } +} From d62154db837fef880714f710bafbe0af94034b40 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Tue, 7 Jan 2025 16:01:46 +0000 Subject: [PATCH 111/397] weak: don't panic when calling Value on a zero Pointer Currently weak.Pointer.Value will panic if the weak.Pointer is uninitialized (zero value) which goes against it's documentation. Fix this and add a test. While we're here, also add a test to ensure weak.Make[T](nil) is equivalent to the zero value of weak.Pointer[T]. Fixes #71153. Change-Id: I4d9196026360bc42a5bfcb33ce449131ec251dba Reviewed-on: https://go-review.googlesource.com/c/go/+/641095 Reviewed-by: David Finkel Auto-Submit: Michael Knyszek LUCI-TryBot-Result: Go LUCI Reviewed-by: Carlos Amedee --- src/weak/pointer.go | 3 +++ src/weak/pointer_test.go | 15 +++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/weak/pointer.go b/src/weak/pointer.go index 50af0c2fdc0a16..39c512e76d6fe4 100644 --- a/src/weak/pointer.go +++ b/src/weak/pointer.go @@ -78,6 +78,9 @@ func Make[T any](ptr *T) Pointer[T] { // If a weak pointer points to an object with a finalizer, then Value will // return nil as soon as the object's finalizer is queued for execution. func (p Pointer[T]) Value() *T { + if p.u == nil { + return nil + } return (*T)(runtime_makeStrongFromWeak(p.u)) } diff --git a/src/weak/pointer_test.go b/src/weak/pointer_test.go index 002b4130f0b553..e0ef30377e9e81 100644 --- a/src/weak/pointer_test.go +++ b/src/weak/pointer_test.go @@ -21,6 +21,15 @@ type T struct { } func TestPointer(t *testing.T) { + var zero weak.Pointer[T] + if zero.Value() != nil { + t.Error("Value of zero value of weak.Pointer is not nil") + } + zeroNil := weak.Make[T](nil) + if zeroNil.Value() != nil { + t.Error("Value of weak.Make[T](nil) is not nil") + } + bt := new(T) wt := weak.Make(bt) if st := wt.Value(); st != bt { @@ -41,6 +50,12 @@ func TestPointer(t *testing.T) { } func TestPointerEquality(t *testing.T) { + var zero weak.Pointer[T] + zeroNil := weak.Make[T](nil) + if zero != zeroNil { + t.Error("weak.Make[T](nil) != zero value of weak.Pointer[T]") + } + bt := make([]*T, 10) wt := make([]weak.Pointer[T], 10) wo := make([]weak.Pointer[int], 10) From d93b549f0502ad9f44b7eacc282c304b22d2603b Mon Sep 17 00:00:00 2001 From: Michael Matloob Date: Mon, 6 Jan 2025 16:02:38 -0500 Subject: [PATCH 112/397] cmd/go/internal/cache: handle cacheprog not responding to close Allow a gocacheprog to not respond to close. The intention of the code is that after we send the close message we'd ignore errors reading from the cacheprog's stdout. But before this change if a cacheprog did not respond to close and we got an EOF reading from the cacheprog's stdout we'd just ignore all pending requests. The send operation would then block forever waiting for a response. With this change, we close all response channels for pending responses if there's an error reading from the cacheprog's stdout while we're closing. The receives from the response channels would then proceed (but now have to handle a nil value). Then the send operation would return and the (*ProgCache).Close function can proceed. Fixes #70848 Change-Id: I6631d317ba7aea3f25f714f31cd2aeef0f4d4e3e Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest,gotip-windows-amd64-longtest Reviewed-on: https://go-review.googlesource.com/c/go/+/640516 Reviewed-by: Austin Clements Reviewed-by: Sam Thanawalla LUCI-TryBot-Result: Go LUCI --- src/cmd/go/internal/cache/prog.go | 22 ++++++++++++++- .../script/build_cacheprog_issue70848.txt | 27 +++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 src/cmd/go/testdata/script/build_cacheprog_issue70848.txt diff --git a/src/cmd/go/internal/cache/prog.go b/src/cmd/go/internal/cache/prog.go index 01ed9438e3978d..bfddf5e4deec83 100644 --- a/src/cmd/go/internal/cache/prog.go +++ b/src/cmd/go/internal/cache/prog.go @@ -153,6 +153,12 @@ func (c *ProgCache) readLoop(readLoopDone chan<- struct{}) { res := new(cacheprog.Response) if err := jd.Decode(res); err != nil { if c.closing.Load() { + c.mu.Lock() + for _, ch := range c.inFlight { + close(ch) + } + c.inFlight = nil + c.mu.Unlock() return // quietly } if err == io.EOF { @@ -175,6 +181,8 @@ func (c *ProgCache) readLoop(readLoopDone chan<- struct{}) { } } +var errCacheprogClosed = errors.New("GOCACHEPROG program closed unexpectedly") + func (c *ProgCache) send(ctx context.Context, req *cacheprog.Request) (*cacheprog.Response, error) { resc := make(chan *cacheprog.Response, 1) if err := c.writeToChild(req, resc); err != nil { @@ -182,6 +190,9 @@ func (c *ProgCache) send(ctx context.Context, req *cacheprog.Request) (*cachepro } select { case res := <-resc: + if res == nil { + return nil, errCacheprogClosed + } if res.Err != "" { return nil, errors.New(res.Err) } @@ -193,6 +204,9 @@ func (c *ProgCache) send(ctx context.Context, req *cacheprog.Request) (*cachepro func (c *ProgCache) writeToChild(req *cacheprog.Request, resc chan<- *cacheprog.Response) (err error) { c.mu.Lock() + if c.inFlight == nil { + return errCacheprogClosed + } c.nextID++ req.ID = c.nextID c.inFlight[req.ID] = resc @@ -201,7 +215,9 @@ func (c *ProgCache) writeToChild(req *cacheprog.Request, resc chan<- *cacheprog. defer func() { if err != nil { c.mu.Lock() - delete(c.inFlight, req.ID) + if c.inFlight != nil { + delete(c.inFlight, req.ID) + } c.mu.Unlock() } }() @@ -348,6 +364,10 @@ func (c *ProgCache) Close() error { // the context that kills the process. if c.can[cacheprog.CmdClose] { _, err = c.send(c.ctx, &cacheprog.Request{Command: cacheprog.CmdClose}) + if errors.Is(err, errCacheprogClosed) { + // Allow the child to quit without responding to close. + err = nil + } } // Cancel the context, which will close the helper's stdin. c.ctxCancel() diff --git a/src/cmd/go/testdata/script/build_cacheprog_issue70848.txt b/src/cmd/go/testdata/script/build_cacheprog_issue70848.txt new file mode 100644 index 00000000000000..194fd47d93443d --- /dev/null +++ b/src/cmd/go/testdata/script/build_cacheprog_issue70848.txt @@ -0,0 +1,27 @@ +[short] skip 'builds go programs' + +go build -o cacheprog$GOEXE cacheprog.go +env GOCACHEPROG=$GOPATH/src/cacheprog$GOEXE + +# This should not deadlock +go build simple.go +! stderr 'cacheprog closed' + +-- simple.go -- +package main + +func main() {} +-- cacheprog.go -- +// This is a minimal GOCACHEPROG program that doesn't respond to close. +package main + +import ( + "encoding/json" + "os" +) + +func main() { + json.NewEncoder(os.Stdout).Encode(map[string][]string{"KnownCommands": {"close"}}) + var res struct{} + json.NewDecoder(os.Stdin).Decode(&res) +} \ No newline at end of file From b2aa18b96cefb48641ec69a79bc67d030b93f093 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 7 Jan 2025 11:20:07 -0500 Subject: [PATCH 113/397] cmd/internal/hash: stop using md5, sha1 These break if the tools are run with GODEBUG=fips140=only, which happens if someone sets that during 'go test' (and a test binary must be built). The easiest fix is to make the tools compatible with this GODEBUG by just using sha256 as the underlying hash always. Just in case, I made the wrappers select different sections of the hash, but none of the call sites really care. This CL is for the Go 1.24 release, but a follow-up during the Go 1.25 dev cycle could change all the usage sites to only use Sum32/New32. For #70514 Fixes #70878 Change-Id: Id5fea779c83df51d1680dbe561e0949c56e8d1e5 Reviewed-on: https://go-review.googlesource.com/c/go/+/641096 Reviewed-by: Keith Randall Auto-Submit: Russ Cox LUCI-TryBot-Result: Go LUCI Reviewed-by: Keith Randall --- src/cmd/internal/hash/hash.go | 41 +++++++++++++++++++++++---------- src/go/build/deps_test.go | 2 +- src/internal/pkgbits/encoder.go | 4 ++-- 3 files changed, 32 insertions(+), 15 deletions(-) diff --git a/src/cmd/internal/hash/hash.go b/src/cmd/internal/hash/hash.go index 20edc72c20e648..a37368f50e74b9 100644 --- a/src/cmd/internal/hash/hash.go +++ b/src/cmd/internal/hash/hash.go @@ -5,22 +5,33 @@ // Package hash implements hash functions used in the compiler toolchain. package hash +// TODO(rsc): Delete the 16 and 20 forms and use 32 at all call sites. + import ( - "crypto/md5" - "crypto/sha1" "crypto/sha256" "hash" ) const ( - // Size32 is the size of 32 bytes hash checksum. - Size32 = sha256.Size - // Size20 is the size of 20 bytes hash checksum. - Size20 = sha1.Size - // Size16 is the size of 16 bytes hash checksum. - Size16 = md5.Size + // Size32 is the size of the 32-byte hash checksum. + Size32 = 32 + // Size20 is the size of the 20-byte hash checksum. + Size20 = 20 + // Size16 is the size of the 16-byte hash checksum. + Size16 = 16 ) +type shortHash struct { + hash.Hash + n int +} + +func (h *shortHash) Sum(b []byte) []byte { + old := b + sum := h.Hash.Sum(b) + return sum[:len(old)+h.n] +} + // New32 returns a new [hash.Hash] computing the 32 bytes hash checksum. func New32() hash.Hash { h := sha256.New() @@ -30,12 +41,12 @@ func New32() hash.Hash { // New20 returns a new [hash.Hash] computing the 20 bytes hash checksum. func New20() hash.Hash { - return sha1.New() + return &shortHash{New32(), 20} } // New16 returns a new [hash.Hash] computing the 16 bytes hash checksum. func New16() hash.Hash { - return md5.New() + return &shortHash{New32(), 16} } // Sum32 returns the 32 bytes checksum of the data. @@ -47,10 +58,16 @@ func Sum32(data []byte) [Size32]byte { // Sum20 returns the 20 bytes checksum of the data. func Sum20(data []byte) [Size20]byte { - return sha1.Sum(data) + sum := Sum32(data) + var short [Size20]byte + copy(short[:], sum[4:]) + return short } // Sum16 returns the 16 bytes checksum of the data. func Sum16(data []byte) [Size16]byte { - return md5.Sum(data) + sum := Sum32(data) + var short [Size16]byte + copy(short[:], sum[8:]) + return short } diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index d9d985dca4ade4..a62a5173b9c6bc 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -568,7 +568,7 @@ var depsRules = ` # crypto-aware packages - DEBUG, go/build, go/types, text/scanner, crypto/md5 + DEBUG, go/build, go/types, text/scanner, crypto/sha256 < internal/pkgbits, internal/exportdata < go/internal/gcimporter, go/internal/gccgoimporter, go/internal/srcimporter < go/importer; diff --git a/src/internal/pkgbits/encoder.go b/src/internal/pkgbits/encoder.go index c17a12399d0597..015842f58c06af 100644 --- a/src/internal/pkgbits/encoder.go +++ b/src/internal/pkgbits/encoder.go @@ -6,7 +6,7 @@ package pkgbits import ( "bytes" - "crypto/md5" + "crypto/sha256" "encoding/binary" "go/constant" "io" @@ -55,7 +55,7 @@ func NewPkgEncoder(version Version, syncFrames int) PkgEncoder { // DumpTo writes the package's encoded data to out0 and returns the // package fingerprint. func (pw *PkgEncoder) DumpTo(out0 io.Writer) (fingerprint [8]byte) { - h := md5.New() + h := sha256.New() out := io.MultiWriter(out0, h) writeUint32 := func(x uint32) { From b50ccef67a5cd4a2919131cfeb6f3a21d6742385 Mon Sep 17 00:00:00 2001 From: Michael Matloob Date: Mon, 6 Jan 2025 11:10:02 -0500 Subject: [PATCH 114/397] cmd/go/internal/modindex: don't write index entry if file open On Windows, we can't open a file that's already been opened. Before this change, we'd try to write an index entry if mmapping the entry failed. But that could happen either if the file doesn't exist or if there was a problem mmapping an already opened file. Pass through information about whether the file was actually opened so that we don't try to write to an already opened file. For #71059 Change-Id: I6adabe1093fed9ec37e7fafb13384c102786cbce Reviewed-on: https://go-review.googlesource.com/c/go/+/640577 Reviewed-by: Sam Thanawalla LUCI-TryBot-Result: Go LUCI --- src/cmd/go/internal/cache/cache.go | 12 ++++++------ src/cmd/go/internal/mmap/mmap.go | 7 ++++--- src/cmd/go/internal/modindex/read.go | 22 ++++++++++++++++------ 3 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/cmd/go/internal/cache/cache.go b/src/cmd/go/internal/cache/cache.go index c9acd8782db964..1bef1db08c7a8f 100644 --- a/src/cmd/go/internal/cache/cache.go +++ b/src/cmd/go/internal/cache/cache.go @@ -296,19 +296,19 @@ func GetBytes(c Cache, id ActionID) ([]byte, Entry, error) { // GetMmap looks up the action ID in the cache and returns // the corresponding output bytes. // GetMmap should only be used for data that can be expected to fit in memory. -func GetMmap(c Cache, id ActionID) ([]byte, Entry, error) { +func GetMmap(c Cache, id ActionID) ([]byte, Entry, bool, error) { entry, err := c.Get(id) if err != nil { - return nil, entry, err + return nil, entry, false, err } - md, err := mmap.Mmap(c.OutputFile(entry.OutputID)) + md, opened, err := mmap.Mmap(c.OutputFile(entry.OutputID)) if err != nil { - return nil, Entry{}, err + return nil, Entry{}, opened, err } if int64(len(md.Data)) != entry.Size { - return nil, Entry{}, &entryNotFoundError{Err: errors.New("file incomplete")} + return nil, Entry{}, true, &entryNotFoundError{Err: errors.New("file incomplete")} } - return md.Data, entry, nil + return md.Data, entry, true, nil } // OutputFile returns the name of the cache file storing output with the given OutputID. diff --git a/src/cmd/go/internal/mmap/mmap.go b/src/cmd/go/internal/mmap/mmap.go index fcbd3e08c1c517..fd374df82efa1f 100644 --- a/src/cmd/go/internal/mmap/mmap.go +++ b/src/cmd/go/internal/mmap/mmap.go @@ -22,10 +22,11 @@ type Data struct { } // Mmap maps the given file into memory. -func Mmap(file string) (Data, error) { +func Mmap(file string) (Data, bool, error) { f, err := os.Open(file) if err != nil { - return Data{}, err + return Data{}, false, err } - return mmapFile(f) + data, err := mmapFile(f) + return data, true, err } diff --git a/src/cmd/go/internal/modindex/read.go b/src/cmd/go/internal/modindex/read.go index c4102409b433f3..4c1fbd835961f6 100644 --- a/src/cmd/go/internal/modindex/read.go +++ b/src/cmd/go/internal/modindex/read.go @@ -183,16 +183,21 @@ func openIndexModule(modroot string, ismodcache bool) (*Module, error) { if err != nil { return nil, err } - data, _, err := cache.GetMmap(cache.Default(), id) + data, _, opened, err := cache.GetMmap(cache.Default(), id) if err != nil { // Couldn't read from modindex. Assume we couldn't read from // the index because the module hasn't been indexed yet. + // But double check on Windows that we haven't opened the file yet, + // because once mmap opens the file, we can't close it, and + // Windows won't let us open an already opened file. data, err = indexModule(modroot) if err != nil { return nil, err } - if err = cache.PutBytes(cache.Default(), id, data); err != nil { - return nil, err + if runtime.GOOS != "windows" || !opened { + if err = cache.PutBytes(cache.Default(), id, data); err != nil { + return nil, err + } } } mi, err := fromBytes(modroot, data) @@ -212,13 +217,18 @@ func openIndexPackage(modroot, pkgdir string) (*IndexPackage, error) { if err != nil { return nil, err } - data, _, err := cache.GetMmap(cache.Default(), id) + data, _, opened, err := cache.GetMmap(cache.Default(), id) if err != nil { // Couldn't read from index. Assume we couldn't read from // the index because the package hasn't been indexed yet. + // But double check on Windows that we haven't opened the file yet, + // because once mmap opens the file, we can't close it, and + // Windows won't let us open an already opened file. data = indexPackage(modroot, pkgdir) - if err = cache.PutBytes(cache.Default(), id, data); err != nil { - return nil, err + if runtime.GOOS != "windows" || !opened { + if err = cache.PutBytes(cache.Default(), id, data); err != nil { + return nil, err + } } } pkg, err := packageFromBytes(modroot, data) From 39f2032c17516a55c165d329dd5e2e07f49132b0 Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Tue, 7 Jan 2025 14:29:23 -0800 Subject: [PATCH 115/397] testing/synctest: add some examples For #67434 Change-Id: Iebcfc2559a62405fea7e3ceff8cf6c2f50b61def Reviewed-on: https://go-review.googlesource.com/c/go/+/641176 Reviewed-by: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Auto-Submit: Damien Neil --- src/testing/synctest/context_example_test.go | 78 ++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 src/testing/synctest/context_example_test.go diff --git a/src/testing/synctest/context_example_test.go b/src/testing/synctest/context_example_test.go new file mode 100644 index 00000000000000..5f7205e50e4c42 --- /dev/null +++ b/src/testing/synctest/context_example_test.go @@ -0,0 +1,78 @@ +// Copyright 2025 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. + +//go:build goexperiment.synctest + +package synctest_test + +import ( + "context" + "fmt" + "testing/synctest" + "time" +) + +// This example demonstrates testing the context.AfterFunc function. +// +// AfterFunc registers a function to execute in a new goroutine +// after a context is canceled. +// +// The test verifies that the function is not run before the context is canceled, +// and is run after the context is canceled. +func Example_contextAfterFunc() { + synctest.Run(func() { + // Create a context.Context which can be canceled. + ctx, cancel := context.WithCancel(context.Background()) + + // context.AfterFunc registers a function to be called + // when a context is canceled. + afterFuncCalled := false + context.AfterFunc(ctx, func() { + afterFuncCalled = true + }) + + // The context has not been canceled, so the AfterFunc is not called. + synctest.Wait() + fmt.Printf("before context is canceled: afterFuncCalled=%v\n", afterFuncCalled) + + // Cancel the context and wait for the AfterFunc to finish executing. + // Verify that the AfterFunc ran. + cancel() + synctest.Wait() + fmt.Printf("after context is canceled: afterFuncCalled=%v\n", afterFuncCalled) + + // Output: + // before context is canceled: afterFuncCalled=false + // after context is canceled: afterFuncCalled=true + }) +} + +// This example demonstrates testing the context.WithTimeout function. +// +// WithTimeout creates a context which is canceled after a timeout. +// +// The test verifies that the context is not canceled before the timeout expires, +// and is canceled after the timeout expires. +func Example_contextWithTimeout() { + synctest.Run(func() { + // Create a context.Context which is canceled after a timeout. + const timeout = 5 * time.Second + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + // Wait just less than the timeout. + time.Sleep(timeout - time.Nanosecond) + synctest.Wait() + fmt.Printf("before timeout: ctx.Err() = %v\n", ctx.Err()) + + // Wait the rest of the way until the timeout. + time.Sleep(time.Nanosecond) + synctest.Wait() + fmt.Printf("after timeout: ctx.Err() = %v\n", ctx.Err()) + + // Output: + // before timeout: ctx.Err() = + // after timeout: ctx.Err() = context deadline exceeded + }) +} From 1e9835f5b1806e8e6197f87c1696dc773b68a98a Mon Sep 17 00:00:00 2001 From: Koichi Shiraishi Date: Sat, 28 Dec 2024 13:56:04 +0900 Subject: [PATCH 116/397] internal/sync: fix typo of panic message Change-Id: I3e7a8498514da1d278acd566d526fdf6278f7d41 Reviewed-on: https://go-review.googlesource.com/c/go/+/638916 Reviewed-by: Dmitri Shuralyov LUCI-TryBot-Result: Go LUCI Reviewed-by: Ian Lance Taylor Auto-Submit: Dmitri Shuralyov Reviewed-by: Dmitri Shuralyov --- src/internal/sync/hashtriemap.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/internal/sync/hashtriemap.go b/src/internal/sync/hashtriemap.go index defcd0b793947f..6f5e0b437fea23 100644 --- a/src/internal/sync/hashtriemap.go +++ b/src/internal/sync/hashtriemap.go @@ -79,7 +79,7 @@ func (ht *HashTrieMap[K, V]) Load(key K) (value V, ok bool) { } i = n.indirect() } - panic("internal/concurrent.HashMapTrie: ran out of hash bits while iterating") + panic("internal/sync.HashTrieMap: ran out of hash bits while iterating") } // LoadOrStore returns the existing value for the key if present. @@ -120,7 +120,7 @@ func (ht *HashTrieMap[K, V]) LoadOrStore(key K, value V) (result V, loaded bool) i = n.indirect() } if !haveInsertPoint { - panic("internal/concurrent.HashMapTrie: ran out of hash bits while iterating") + panic("internal/sync.HashTrieMap: ran out of hash bits while iterating") } // Grab the lock and double-check what we saw. @@ -178,7 +178,7 @@ func (ht *HashTrieMap[K, V]) expand(oldEntry, newEntry *entry[K, V], newHash uin top := newIndirect for { if hashShift == 0 { - panic("internal/concurrent.HashMapTrie: ran out of hash bits while inserting") + panic("internal/sync.HashTrieMap: ran out of hash bits while inserting") } hashShift -= nChildrenLog2 // hashShift is for the level parent is at. We need to go deeper. oi := (oldHash >> hashShift) & nChildrenMask @@ -228,7 +228,7 @@ func (ht *HashTrieMap[K, V]) Swap(key K, new V) (previous V, loaded bool) { i = n.indirect() } if !haveInsertPoint { - panic("internal/concurrent.HashMapTrie: ran out of hash bits while iterating") + panic("internal/sync.HashTrieMap: ran out of hash bits while iterating") } // Grab the lock and double-check what we saw. @@ -339,7 +339,7 @@ func (ht *HashTrieMap[K, V]) LoadAndDelete(key K) (value V, loaded bool) { // Check if the node is now empty (and isn't the root), and delete it if able. for i.parent != nil && i.empty() { if hashShift == 8*goarch.PtrSize { - panic("internal/concurrent.HashMapTrie: ran out of hash bits while iterating") + panic("internal/sync.HashTrieMap: ran out of hash bits while iterating") } hashShift += nChildrenLog2 @@ -401,7 +401,7 @@ func (ht *HashTrieMap[K, V]) CompareAndDelete(key K, old V) (deleted bool) { // Check if the node is now empty (and isn't the root), and delete it if able. for i.parent != nil && i.empty() { if hashShift == 8*goarch.PtrSize { - panic("internal/concurrent.HashMapTrie: ran out of hash bits while iterating") + panic("internal/sync.HashTrieMap: ran out of hash bits while iterating") } hashShift += nChildrenLog2 @@ -454,7 +454,7 @@ func (ht *HashTrieMap[K, V]) find(key K, hash uintptr, valEqual equalFunc, value i = n.indirect() } if !found { - panic("internal/concurrent.HashMapTrie: ran out of hash bits while iterating") + panic("internal/sync.HashTrieMap: ran out of hash bits while iterating") } // Grab the lock and double-check what we saw. From f025d19e7b3f0c66242760c213cc2b54cb100f69 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Mon, 23 Dec 2024 17:21:07 +0000 Subject: [PATCH 117/397] runtime: hold traceAcquire across casgstatus in injectglist Currently injectglist emits all the trace events before actually calling casgstatus on each goroutine. This is a problem, since tracing can observe an inconsistent state (gstatus does not match tracer's 'emitted an event' state). This change fixes the problem by having injectglist do what every other scheduler function does, and that's wrap each call to casgstatus in traceAcquire/traceRelease. Fixes #70883. Change-Id: I857e96cec01688013597e8efc0c4c3d0b72d3a70 Reviewed-on: https://go-review.googlesource.com/c/go/+/638558 Reviewed-by: Michael Pratt LUCI-TryBot-Result: Go LUCI --- src/runtime/proc.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 63629602004832..e9873e54cd5709 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -3894,23 +3894,23 @@ func injectglist(glist *gList) { if glist.empty() { return } - trace := traceAcquire() - if trace.ok() { - for gp := glist.head.ptr(); gp != nil; gp = gp.schedlink.ptr() { - trace.GoUnpark(gp, 0) - } - traceRelease(trace) - } // Mark all the goroutines as runnable before we put them // on the run queues. head := glist.head.ptr() var tail *g qsize := 0 + trace := traceAcquire() for gp := head; gp != nil; gp = gp.schedlink.ptr() { tail = gp qsize++ casgstatus(gp, _Gwaiting, _Grunnable) + if trace.ok() { + trace.GoUnpark(gp, 0) + } + } + if trace.ok() { + traceRelease(trace) } // Turn the gList into a gQueue. From 9a44df66758c65e6f0b3ab0002a297d2fc266d7c Mon Sep 17 00:00:00 2001 From: Michael Matloob Date: Wed, 8 Jan 2025 11:19:05 -0500 Subject: [PATCH 118/397] cmd/go/testdata/script: fix TestScript/env_gocacheprog on Windows The backslashes on the windows paths will be escaped, so when checking for them in the regular expression we'd have to have quadruple backslashes '\\\\'. Since it's difficult to escape $GOCACHEPROG properly for both json and regexp, just check for a string that ends in cacheprog$GOEXE. We already check that the proper value is reported in go env and go env -changed, and the json test case is mostly useful to verify that GOCACHEPROG shows up in the json output. For #71059 Change-Id: I52d49de61f2309a139f84c4d232b4cd94546ec8c Cq-Include-Trybots: luci.golang.try:gotip-windows-amd64-longtest,gotip-linux-amd64-longtest Reviewed-on: https://go-review.googlesource.com/c/go/+/641375 Reviewed-by: Dmitri Shuralyov LUCI-TryBot-Result: Go LUCI Reviewed-by: Sam Thanawalla Reviewed-by: Dmitri Shuralyov --- src/cmd/go/testdata/script/env_gocacheprog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/go/testdata/script/env_gocacheprog.txt b/src/cmd/go/testdata/script/env_gocacheprog.txt index f5f15ed0784fda..1547bf058c16ca 100644 --- a/src/cmd/go/testdata/script/env_gocacheprog.txt +++ b/src/cmd/go/testdata/script/env_gocacheprog.txt @@ -24,7 +24,7 @@ go env -changed stdout 'GOCACHEPROG=''?'$GOCACHEPROG'''?' go env -changed -json -stdout '"GOCACHEPROG": "'$GOCACHEPROG'"' +stdout '"GOCACHEPROG": ".*cacheprog'$GOEXE'"' -- cacheprog.go -- // This is a minimal GOCACHEPROG program that can't actually do anything but exit. From e966a2773cced08d584e0a462c4b30a84e3a46be Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 7 Jan 2025 12:07:07 -0500 Subject: [PATCH 119/397] crypto/internal/fips140/drbg: avoid global lock on rand state Having a global lock on the random state (used only in FIPS-140 mode) introduces contention in concurrent programs. Use an approximately per-P random state instead, using sync.Pool to manage per-P state. This code is important to land for the Go 1.24 release because it is part of the FIPS-140 module that will be validated and certified, so it will live for a long time. We otherwise wouldn't be able to correct this contention for at least a year, perhaps more. At the same time, the code is only used in the FIPS-140 mode, so there is no risk to normal programs. Fixes #71155. Change-Id: I6b779f15ddfdf232f608f5cda08f75906e58114f Reviewed-on: https://go-review.googlesource.com/c/go/+/641097 Reviewed-by: Austin Clements Reviewed-by: Filippo Valsorda Reviewed-by: Michael Knyszek LUCI-TryBot-Result: Go LUCI --- src/crypto/internal/fips140/drbg/rand.go | 21 ++++++++------- src/crypto/internal/fips140/drbg/rand_test.go | 27 +++++++++++++++++++ 2 files changed, 38 insertions(+), 10 deletions(-) create mode 100644 src/crypto/internal/fips140/drbg/rand_test.go diff --git a/src/crypto/internal/fips140/drbg/rand.go b/src/crypto/internal/fips140/drbg/rand.go index 967fb0673ef1a1..e7ab19a4cfe0a6 100644 --- a/src/crypto/internal/fips140/drbg/rand.go +++ b/src/crypto/internal/fips140/drbg/rand.go @@ -13,8 +13,15 @@ import ( "sync" ) -var mu sync.Mutex -var drbg *Counter +var drbgs = sync.Pool{ + New: func() any { + var c *Counter + entropy.Depleted(func(seed *[48]byte) { + c = NewCounter(seed) + }) + return c + }, +} // Read fills b with cryptographically secure random bytes. In FIPS mode, it // uses an SP 800-90A Rev. 1 Deterministic Random Bit Generator (DRBG). @@ -33,14 +40,8 @@ func Read(b []byte) { additionalInput := new([SeedSize]byte) sysrand.Read(additionalInput[:16]) - mu.Lock() - defer mu.Unlock() - - if drbg == nil { - entropy.Depleted(func(seed *[48]byte) { - drbg = NewCounter(seed) - }) - } + drbg := drbgs.Get().(*Counter) + defer drbgs.Put(drbg) for len(b) > 0 { size := min(len(b), maxRequestSize) diff --git a/src/crypto/internal/fips140/drbg/rand_test.go b/src/crypto/internal/fips140/drbg/rand_test.go new file mode 100644 index 00000000000000..945ebde933e1bc --- /dev/null +++ b/src/crypto/internal/fips140/drbg/rand_test.go @@ -0,0 +1,27 @@ +// Copyright 2025 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package drbg + +import ( + "crypto/internal/fips140" + "testing" +) + +func BenchmarkDBRG(b *testing.B) { + old := fips140.Enabled + defer func() { + fips140.Enabled = old + }() + fips140.Enabled = true + + const N = 64 + b.SetBytes(N) + b.RunParallel(func(pb *testing.PB) { + buf := make([]byte, N) + for pb.Next() { + Read(buf) + } + }) +} From 4640e92af70810001ecb3228640ea45448879cd0 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Mon, 6 Jan 2025 21:12:03 +0100 Subject: [PATCH 120/397] crypto/rsa: apply fips140=only to opts.Hash in SignPSS Change-Id: I6a6a46569bd364b36f83b9aef640eca94e045173 Reviewed-on: https://go-review.googlesource.com/c/go/+/641315 Reviewed-by: Roland Shoemaker LUCI-TryBot-Result: Go LUCI Reviewed-by: Russ Cox Auto-Submit: Filippo Valsorda Reviewed-by: Daniel McCarney --- src/crypto/rsa/fips.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/crypto/rsa/fips.go b/src/crypto/rsa/fips.go index 24dfb38cf625bd..347775df1603c0 100644 --- a/src/crypto/rsa/fips.go +++ b/src/crypto/rsa/fips.go @@ -67,6 +67,11 @@ func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, digest []byte, if err := checkFIPS140OnlyPrivateKey(priv); err != nil { return nil, err } + + if opts != nil && opts.Hash != 0 { + hash = opts.Hash + } + if fips140only.Enabled && !fips140only.ApprovedHash(hash.New()) { return nil, errors.New("crypto/rsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode") } @@ -74,10 +79,6 @@ func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, digest []byte, return nil, errors.New("crypto/rsa: only crypto/rand.Reader is allowed in FIPS 140-only mode") } - if opts != nil && opts.Hash != 0 { - hash = opts.Hash - } - if boring.Enabled && rand == boring.RandReader { bkey, err := boringPrivateKey(priv) if err != nil { From 0cdf8c7a8ce5913845ab46e49a1befd86c9c565d Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Mon, 6 Jan 2025 21:12:03 +0100 Subject: [PATCH 121/397] crypto/ecdsa: apply fips140=only to deterministic ECDSA hash Change-Id: I6a6a46567b1eaaef080ac0994afa83db2624a75a Reviewed-on: https://go-review.googlesource.com/c/go/+/641316 Auto-Submit: Filippo Valsorda Reviewed-by: Daniel McCarney LUCI-TryBot-Result: Go LUCI Reviewed-by: Russ Cox Reviewed-by: Roland Shoemaker --- src/crypto/ecdsa/ecdsa.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/crypto/ecdsa/ecdsa.go b/src/crypto/ecdsa/ecdsa.go index f682e6b1c6cfa6..d9ebe56ef007e5 100644 --- a/src/crypto/ecdsa/ecdsa.go +++ b/src/crypto/ecdsa/ecdsa.go @@ -281,6 +281,9 @@ func signFIPSDeterministic[P ecdsa.Point[P]](c *ecdsa.Curve[P], hashFunc crypto. if err != nil { return nil, err } + if fips140only.Enabled && !fips140only.ApprovedHash(hashFunc.New()) { + return nil, errors.New("crypto/ecdsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode") + } sig, err := ecdsa.SignDeterministic(c, hashFunc.New, k, hash) if err != nil { return nil, err From 54693a81fd605a9c1abbee83da072c61e38d3ebf Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Mon, 6 Jan 2025 18:49:45 +0100 Subject: [PATCH 122/397] crypto/md5,crypto/sha1: apply fips140=only to Write and Sum, not New New is called to get a Hash which can then be rejected with an error (instead of a panic) from fips140only.ApprovedHash. Also, it's reasonable to call New().Size() and then not use the hash. Change-Id: I6a6a4656c43528d169c4b28c8b6de48448236d4f Reviewed-on: https://go-review.googlesource.com/c/go/+/641317 Auto-Submit: Filippo Valsorda Reviewed-by: Daniel McCarney Reviewed-by: Russ Cox Reviewed-by: Roland Shoemaker LUCI-TryBot-Result: Go LUCI --- src/crypto/md5/md5.go | 13 +++++++------ src/crypto/sha1/sha1.go | 16 ++++++++++++---- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/crypto/md5/md5.go b/src/crypto/md5/md5.go index 75e1fc7404724a..a0384e175f31bd 100644 --- a/src/crypto/md5/md5.go +++ b/src/crypto/md5/md5.go @@ -104,9 +104,6 @@ func consumeUint32(b []byte) ([]byte, uint32) { // [encoding.BinaryUnmarshaler] to marshal and unmarshal the internal // state of the hash. func New() hash.Hash { - if fips140only.Enabled { - panic("crypto/md5: use of MD5 is not allowed in FIPS 140-only mode") - } d := new(digest) d.Reset() return d @@ -117,6 +114,9 @@ func (d *digest) Size() int { return Size } func (d *digest) BlockSize() int { return BlockSize } func (d *digest) Write(p []byte) (nn int, err error) { + if fips140only.Enabled { + return 0, errors.New("crypto/md5: use of MD5 is not allowed in FIPS 140-only mode") + } // Note that we currently call block or blockGeneric // directly (guarded using haveAsm) because this allows // escape analysis to see that p and d don't escape. @@ -158,6 +158,10 @@ func (d *digest) Sum(in []byte) []byte { } func (d *digest) checkSum() [Size]byte { + if fips140only.Enabled { + panic("crypto/md5: use of MD5 is not allowed in FIPS 140-only mode") + } + // Append 0x80 to the end of the message and then append zeros // until the length is a multiple of 56 bytes. Finally append // 8 bytes representing the message length in bits. @@ -184,9 +188,6 @@ func (d *digest) checkSum() [Size]byte { // Sum returns the MD5 checksum of the data. func Sum(data []byte) [Size]byte { - if fips140only.Enabled { - panic("crypto/md5: use of MD5 is not allowed in FIPS 140-only mode") - } var d digest d.Reset() d.Write(data) diff --git a/src/crypto/sha1/sha1.go b/src/crypto/sha1/sha1.go index b799f0d2fb1548..d2ffaac0aeb674 100644 --- a/src/crypto/sha1/sha1.go +++ b/src/crypto/sha1/sha1.go @@ -111,9 +111,6 @@ func New() hash.Hash { if boring.Enabled { return boring.NewSHA1() } - if fips140only.Enabled { - panic("crypto/sha1: use of weak SHA-1 is not allowed in FIPS 140-only mode") - } d := new(digest) d.Reset() return d @@ -124,6 +121,9 @@ func (d *digest) Size() int { return Size } func (d *digest) BlockSize() int { return BlockSize } func (d *digest) Write(p []byte) (nn int, err error) { + if fips140only.Enabled { + return 0, errors.New("crypto/sha1: use of SHA-1 is not allowed in FIPS 140-only mode") + } boring.Unreachable() nn = len(p) d.len += uint64(nn) @@ -156,6 +156,10 @@ func (d *digest) Sum(in []byte) []byte { } func (d *digest) checkSum() [Size]byte { + if fips140only.Enabled { + panic("crypto/sha1: use of SHA-1 is not allowed in FIPS 140-only mode") + } + len := d.len // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64. var tmp [64 + 8]byte // padding + length buffer @@ -196,6 +200,10 @@ func (d *digest) ConstantTimeSum(in []byte) []byte { } func (d *digest) constSum() [Size]byte { + if fips140only.Enabled { + panic("crypto/sha1: use of SHA-1 is not allowed in FIPS 140-only mode") + } + var length [8]byte l := d.len << 3 for i := uint(0); i < 8; i++ { @@ -262,7 +270,7 @@ func Sum(data []byte) [Size]byte { return boring.SHA1(data) } if fips140only.Enabled { - panic("crypto/sha1: use of weak SHA-1 is not allowed in FIPS 140-only mode") + panic("crypto/sha1: use of SHA-1 is not allowed in FIPS 140-only mode") } var d digest d.Reset() From c9afcbade7308cf66b67b9ce080f10b621b17c6a Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 7 Jan 2025 15:06:05 -0800 Subject: [PATCH 123/397] go/types, types2: require iterator yield to return bool (work-around) The original implementation of the type checkers accepted any boolean result type for yield, but the compiler's front-end had a problem with it (#71131). As a temporary fix (for 1.24), adjust the type checkers to insist on the spec's literal wording and avoid the compiler panic. Fixes #71131. For #71164. Change-Id: Ie25f9a892e58b5e489d399b0bce2d0af55dc3c48 Reviewed-on: https://go-review.googlesource.com/c/go/+/640599 Reviewed-by: Robert Griesemer Auto-Submit: Robert Griesemer Reviewed-by: Tim King LUCI-TryBot-Result: Go LUCI --- src/cmd/compile/internal/types2/stmt.go | 9 +++++++-- src/cmd/compile/internal/types2/universe.go | 2 ++ src/go/types/stmt.go | 9 +++++++-- src/go/types/universe.go | 2 ++ .../types/testdata/fixedbugs/issue71131.go | 15 +++++++++++++++ src/internal/types/testdata/spec/range.go | 2 +- 6 files changed, 34 insertions(+), 5 deletions(-) create mode 100644 src/internal/types/testdata/fixedbugs/issue71131.go diff --git a/src/cmd/compile/internal/types2/stmt.go b/src/cmd/compile/internal/types2/stmt.go index 2174aedf7f4f01..c46ea7a091afd2 100644 --- a/src/cmd/compile/internal/types2/stmt.go +++ b/src/cmd/compile/internal/types2/stmt.go @@ -1057,8 +1057,13 @@ func rangeKeyVal(typ Type, allowVersion func(goVersion) bool) (key, val Type, ca return bad("func must be func(yield func(...) bool): argument is not func") case cb.Params().Len() > 2: return bad("func must be func(yield func(...) bool): yield func has too many parameters") - case cb.Results().Len() != 1 || !isBoolean(cb.Results().At(0).Type()): - return bad("func must be func(yield func(...) bool): yield func does not return bool") + case cb.Results().Len() != 1 || !Identical(cb.Results().At(0).Type(), universeBool): + // see go.dev/issues/71131, go.dev/issues/71164 + if cb.Results().Len() == 1 && isBoolean(cb.Results().At(0).Type()) { + return bad("func must be func(yield func(...) bool): yield func returns user-defined boolean, not bool") + } else { + return bad("func must be func(yield func(...) bool): yield func does not return bool") + } } assert(cb.Recv() == nil) // determine key and value types, if any diff --git a/src/cmd/compile/internal/types2/universe.go b/src/cmd/compile/internal/types2/universe.go index 9c76ac23730f0f..7664a53579ab3b 100644 --- a/src/cmd/compile/internal/types2/universe.go +++ b/src/cmd/compile/internal/types2/universe.go @@ -21,6 +21,7 @@ var Unsafe *Package var ( universeIota Object + universeBool Type universeByte Type // uint8 alias, but has name "byte" universeRune Type // int32 alias, but has name "rune" universeAnyNoAlias *TypeName @@ -275,6 +276,7 @@ func init() { defPredeclaredFuncs() universeIota = Universe.Lookup("iota") + universeBool = Universe.Lookup("bool").Type() universeByte = Universe.Lookup("byte").Type() universeRune = Universe.Lookup("rune").Type() universeError = Universe.Lookup("error").Type() diff --git a/src/go/types/stmt.go b/src/go/types/stmt.go index d3223f3b92395f..de3d01e8dd2b43 100644 --- a/src/go/types/stmt.go +++ b/src/go/types/stmt.go @@ -1075,8 +1075,13 @@ func rangeKeyVal(typ Type, allowVersion func(goVersion) bool) (key, val Type, ca return bad("func must be func(yield func(...) bool): argument is not func") case cb.Params().Len() > 2: return bad("func must be func(yield func(...) bool): yield func has too many parameters") - case cb.Results().Len() != 1 || !isBoolean(cb.Results().At(0).Type()): - return bad("func must be func(yield func(...) bool): yield func does not return bool") + case cb.Results().Len() != 1 || !Identical(cb.Results().At(0).Type(), universeBool): + // see go.dev/issues/71131, go.dev/issues/71164 + if cb.Results().Len() == 1 && isBoolean(cb.Results().At(0).Type()) { + return bad("func must be func(yield func(...) bool): yield func returns user-defined boolean, not bool") + } else { + return bad("func must be func(yield func(...) bool): yield func does not return bool") + } } assert(cb.Recv() == nil) // determine key and value types, if any diff --git a/src/go/types/universe.go b/src/go/types/universe.go index 09b882ce055551..750a368278ab63 100644 --- a/src/go/types/universe.go +++ b/src/go/types/universe.go @@ -24,6 +24,7 @@ var Unsafe *Package var ( universeIota Object + universeBool Type universeByte Type // uint8 alias, but has name "byte" universeRune Type // int32 alias, but has name "rune" universeAnyNoAlias *TypeName @@ -278,6 +279,7 @@ func init() { defPredeclaredFuncs() universeIota = Universe.Lookup("iota") + universeBool = Universe.Lookup("bool").Type() universeByte = Universe.Lookup("byte").Type() universeRune = Universe.Lookup("rune").Type() universeError = Universe.Lookup("error").Type() diff --git a/src/internal/types/testdata/fixedbugs/issue71131.go b/src/internal/types/testdata/fixedbugs/issue71131.go new file mode 100644 index 00000000000000..8e7575b02828de --- /dev/null +++ b/src/internal/types/testdata/fixedbugs/issue71131.go @@ -0,0 +1,15 @@ +// Copyright 2025 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +func _() { + type Bool bool + for range func /* ERROR "yield func returns user-defined boolean, not bool" */ (func() Bool) {} { + } + for range func /* ERROR "yield func returns user-defined boolean, not bool" */ (func(int) Bool) {} { + } + for range func /* ERROR "yield func returns user-defined boolean, not bool" */ (func(int, string) Bool) {} { + } +} diff --git a/src/internal/types/testdata/spec/range.go b/src/internal/types/testdata/spec/range.go index 52d1e70382bd2e..c0f579479f60ec 100644 --- a/src/internal/types/testdata/spec/range.go +++ b/src/internal/types/testdata/spec/range.go @@ -5,7 +5,7 @@ package p type MyInt int32 -type MyBool bool +type MyBool = bool // TODO(gri) remove alias declaration - see go.dev/issues/71131, go.dev/issues/71164 type MyString string type MyFunc1 func(func(int) bool) type MyFunc2 func(int) bool From f57a3a7c047f16da76b0f7afbb6684dbad9be4ec Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Wed, 8 Jan 2025 10:15:23 +0100 Subject: [PATCH 124/397] crypto/mlkem: add example and improve docs Change-Id: I6a6a46565f9135d8f18bf219e5b76d5957df5ab0 Reviewed-on: https://go-review.googlesource.com/c/go/+/641295 LUCI-TryBot-Result: Go LUCI Reviewed-by: Russ Cox Reviewed-by: Daniel McCarney Auto-Submit: Filippo Valsorda Reviewed-by: Dmitri Shuralyov --- src/crypto/mlkem/example_test.go | 47 ++++++++++++++++++++++++++++++++ src/crypto/mlkem/mlkem1024.go | 12 ++++---- src/crypto/mlkem/mlkem768.go | 15 +++++----- 3 files changed, 60 insertions(+), 14 deletions(-) create mode 100644 src/crypto/mlkem/example_test.go diff --git a/src/crypto/mlkem/example_test.go b/src/crypto/mlkem/example_test.go new file mode 100644 index 00000000000000..28bf3f29e711ed --- /dev/null +++ b/src/crypto/mlkem/example_test.go @@ -0,0 +1,47 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package mlkem_test + +import ( + "crypto/mlkem" + "log" +) + +func Example() { + // Alice generates a new key pair and sends the encapsulation key to Bob. + dk, err := mlkem.GenerateKey768() + if err != nil { + log.Fatal(err) + } + encapsulationKey := dk.EncapsulationKey().Bytes() + + // Bob uses the encapsulation key to encapsulate a shared secret, and sends + // back the ciphertext to Alice. + ciphertext := Bob(encapsulationKey) + + // Alice decapsulates the shared secret from the ciphertext. + sharedSecret, err := dk.Decapsulate(ciphertext) + if err != nil { + log.Fatal(err) + } + + // Alice and Bob now share a secret. + _ = sharedSecret +} + +func Bob(encapsulationKey []byte) (ciphertext []byte) { + // Bob encapsulates a shared secret using the encapsulation key. + ek, err := mlkem.NewEncapsulationKey768(encapsulationKey) + if err != nil { + log.Fatal(err) + } + sharedSecret, ciphertext := ek.Encapsulate() + + // Alice and Bob now share a secret. + _ = sharedSecret + + // Bob sends the ciphertext to Alice. + return ciphertext +} diff --git a/src/crypto/mlkem/mlkem1024.go b/src/crypto/mlkem/mlkem1024.go index 05bad1eb2aa42c..014cfce1e4e17b 100644 --- a/src/crypto/mlkem/mlkem1024.go +++ b/src/crypto/mlkem/mlkem1024.go @@ -7,12 +7,10 @@ package mlkem import "crypto/internal/fips140/mlkem" const ( - // CiphertextSize1024 is the size of a ciphertext produced by the 1024-bit - // variant of ML-KEM. + // CiphertextSize1024 is the size of a ciphertext produced by ML-KEM-1024. CiphertextSize1024 = 1568 - // EncapsulationKeySize1024 is the size of an encapsulation key for the - // 1024-bit variant of ML-KEM. + // EncapsulationKeySize1024 is the size of an ML-KEM-1024 encapsulation key. EncapsulationKeySize1024 = 1568 ) @@ -23,7 +21,7 @@ type DecapsulationKey1024 struct { } // GenerateKey1024 generates a new decapsulation key, drawing random bytes from -// crypto/rand. The decapsulation key must be kept secret. +// the default crypto/rand source. The decapsulation key must be kept secret. func GenerateKey1024() (*DecapsulationKey1024, error) { key, err := mlkem.GenerateKey1024() if err != nil { @@ -33,7 +31,7 @@ func GenerateKey1024() (*DecapsulationKey1024, error) { return &DecapsulationKey1024{key}, nil } -// NewDecapsulationKey1024 parses a decapsulation key from a 64-byte seed in the +// NewDecapsulationKey1024 expands a decapsulation key from a 64-byte seed in the // "d || z" form. The seed must be uniformly random. func NewDecapsulationKey1024(seed []byte) (*DecapsulationKey1024, error) { key, err := mlkem.NewDecapsulationKey1024(seed) @@ -88,7 +86,7 @@ func (ek *EncapsulationKey1024) Bytes() []byte { } // Encapsulate generates a shared key and an associated ciphertext from an -// encapsulation key, drawing random bytes from crypto/rand. +// encapsulation key, drawing random bytes from the default crypto/rand source. // // The shared key must be kept secret. func (ek *EncapsulationKey1024) Encapsulate() (sharedKey, ciphertext []byte) { diff --git a/src/crypto/mlkem/mlkem768.go b/src/crypto/mlkem/mlkem768.go index c367c551e6fc02..a165eb1c9f8b11 100644 --- a/src/crypto/mlkem/mlkem768.go +++ b/src/crypto/mlkem/mlkem768.go @@ -5,6 +5,9 @@ // Package mlkem implements the quantum-resistant key encapsulation method // ML-KEM (formerly known as Kyber), as specified in [NIST FIPS 203]. // +// Most applications should use the ML-KEM-768 parameter set, as implemented by +// [DecapsulationKey768] and [EncapsulationKey768]. +// // [NIST FIPS 203]: https://doi.org/10.6028/NIST.FIPS.203 package mlkem @@ -17,12 +20,10 @@ const ( // SeedSize is the size of a seed used to generate a decapsulation key. SeedSize = 64 - // CiphertextSize768 is the size of a ciphertext produced by the 768-bit - // variant of ML-KEM. + // CiphertextSize768 is the size of a ciphertext produced by ML-KEM-768. CiphertextSize768 = 1088 - // EncapsulationKeySize768 is the size of an encapsulation key for the - // 768-bit variant of ML-KEM. + // EncapsulationKeySize768 is the size of an ML-KEM-768 encapsulation key. EncapsulationKeySize768 = 1184 ) @@ -33,7 +34,7 @@ type DecapsulationKey768 struct { } // GenerateKey768 generates a new decapsulation key, drawing random bytes from -// crypto/rand. The decapsulation key must be kept secret. +// the default crypto/rand source. The decapsulation key must be kept secret. func GenerateKey768() (*DecapsulationKey768, error) { key, err := mlkem.GenerateKey768() if err != nil { @@ -43,7 +44,7 @@ func GenerateKey768() (*DecapsulationKey768, error) { return &DecapsulationKey768{key}, nil } -// NewDecapsulationKey768 parses a decapsulation key from a 64-byte seed in the +// NewDecapsulationKey768 expands a decapsulation key from a 64-byte seed in the // "d || z" form. The seed must be uniformly random. func NewDecapsulationKey768(seed []byte) (*DecapsulationKey768, error) { key, err := mlkem.NewDecapsulationKey768(seed) @@ -98,7 +99,7 @@ func (ek *EncapsulationKey768) Bytes() []byte { } // Encapsulate generates a shared key and an associated ciphertext from an -// encapsulation key, drawing random bytes from crypto/rand. +// encapsulation key, drawing random bytes from the default crypto/rand source. // // The shared key must be kept secret. func (ek *EncapsulationKey768) Encapsulate() (sharedKey, ciphertext []byte) { From c87a6f932efd3643c73f6b972da5500755048f85 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Wed, 8 Jan 2025 10:40:39 +0100 Subject: [PATCH 125/397] crypto/mlkem: merge mlkem768.go and mlkem1024.go to improve godoc The constants appeared badly ordered and grouped in the godoc before const ( CiphertextSize1024 = 1568 EncapsulationKeySize1024 = 1568 ) const ( SharedKeySize = 32 SeedSize = 64 CiphertextSize768 = 1088 EncapsulationKeySize768 = 1184 ) while now they are a single group with the good size first const ( SharedKeySize = 32 SeedSize = 64 CiphertextSize768 = 1088 EncapsulationKeySize768 = 1184 CiphertextSize1024 = 1568 EncapsulationKeySize1024 = 1568 ) No code changes. Change-Id: I6a6a4656961b1e8c8bca3992aafa33e0575af8a2 Reviewed-on: https://go-review.googlesource.com/c/go/+/640997 Auto-Submit: Filippo Valsorda Reviewed-by: Dmitri Shuralyov LUCI-TryBot-Result: Go LUCI Reviewed-by: Russ Cox Reviewed-by: Daniel McCarney --- src/crypto/mlkem/{mlkem768.go => mlkem.go} | 85 +++++++++++++++++++ src/crypto/mlkem/mlkem1024.go | 94 ---------------------- 2 files changed, 85 insertions(+), 94 deletions(-) rename src/crypto/mlkem/{mlkem768.go => mlkem.go} (55%) delete mode 100644 src/crypto/mlkem/mlkem1024.go diff --git a/src/crypto/mlkem/mlkem768.go b/src/crypto/mlkem/mlkem.go similarity index 55% rename from src/crypto/mlkem/mlkem768.go rename to src/crypto/mlkem/mlkem.go index a165eb1c9f8b11..69c0bc571f95a9 100644 --- a/src/crypto/mlkem/mlkem768.go +++ b/src/crypto/mlkem/mlkem.go @@ -25,6 +25,12 @@ const ( // EncapsulationKeySize768 is the size of an ML-KEM-768 encapsulation key. EncapsulationKeySize768 = 1184 + + // CiphertextSize1024 is the size of a ciphertext produced by ML-KEM-1024. + CiphertextSize1024 = 1568 + + // EncapsulationKeySize1024 is the size of an ML-KEM-1024 encapsulation key. + EncapsulationKeySize1024 = 1568 ) // DecapsulationKey768 is the secret key used to decapsulate a shared key @@ -105,3 +111,82 @@ func (ek *EncapsulationKey768) Bytes() []byte { func (ek *EncapsulationKey768) Encapsulate() (sharedKey, ciphertext []byte) { return ek.key.Encapsulate() } + +// DecapsulationKey1024 is the secret key used to decapsulate a shared key +// from a ciphertext. It includes various precomputed values. +type DecapsulationKey1024 struct { + key *mlkem.DecapsulationKey1024 +} + +// GenerateKey1024 generates a new decapsulation key, drawing random bytes from +// the default crypto/rand source. The decapsulation key must be kept secret. +func GenerateKey1024() (*DecapsulationKey1024, error) { + key, err := mlkem.GenerateKey1024() + if err != nil { + return nil, err + } + + return &DecapsulationKey1024{key}, nil +} + +// NewDecapsulationKey1024 expands a decapsulation key from a 64-byte seed in the +// "d || z" form. The seed must be uniformly random. +func NewDecapsulationKey1024(seed []byte) (*DecapsulationKey1024, error) { + key, err := mlkem.NewDecapsulationKey1024(seed) + if err != nil { + return nil, err + } + + return &DecapsulationKey1024{key}, nil +} + +// Bytes returns the decapsulation key as a 64-byte seed in the "d || z" form. +// +// The decapsulation key must be kept secret. +func (dk *DecapsulationKey1024) Bytes() []byte { + return dk.key.Bytes() +} + +// Decapsulate generates a shared key from a ciphertext and a decapsulation +// key. If the ciphertext is not valid, Decapsulate returns an error. +// +// The shared key must be kept secret. +func (dk *DecapsulationKey1024) Decapsulate(ciphertext []byte) (sharedKey []byte, err error) { + return dk.key.Decapsulate(ciphertext) +} + +// EncapsulationKey returns the public encapsulation key necessary to produce +// ciphertexts. +func (dk *DecapsulationKey1024) EncapsulationKey() *EncapsulationKey1024 { + return &EncapsulationKey1024{dk.key.EncapsulationKey()} +} + +// An EncapsulationKey1024 is the public key used to produce ciphertexts to be +// decapsulated by the corresponding DecapsulationKey1024. +type EncapsulationKey1024 struct { + key *mlkem.EncapsulationKey1024 +} + +// NewEncapsulationKey1024 parses an encapsulation key from its encoded form. If +// the encapsulation key is not valid, NewEncapsulationKey1024 returns an error. +func NewEncapsulationKey1024(encapsulationKey []byte) (*EncapsulationKey1024, error) { + key, err := mlkem.NewEncapsulationKey1024(encapsulationKey) + if err != nil { + return nil, err + } + + return &EncapsulationKey1024{key}, nil +} + +// Bytes returns the encapsulation key as a byte slice. +func (ek *EncapsulationKey1024) Bytes() []byte { + return ek.key.Bytes() +} + +// Encapsulate generates a shared key and an associated ciphertext from an +// encapsulation key, drawing random bytes from the default crypto/rand source. +// +// The shared key must be kept secret. +func (ek *EncapsulationKey1024) Encapsulate() (sharedKey, ciphertext []byte) { + return ek.key.Encapsulate() +} diff --git a/src/crypto/mlkem/mlkem1024.go b/src/crypto/mlkem/mlkem1024.go deleted file mode 100644 index 014cfce1e4e17b..00000000000000 --- a/src/crypto/mlkem/mlkem1024.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package mlkem - -import "crypto/internal/fips140/mlkem" - -const ( - // CiphertextSize1024 is the size of a ciphertext produced by ML-KEM-1024. - CiphertextSize1024 = 1568 - - // EncapsulationKeySize1024 is the size of an ML-KEM-1024 encapsulation key. - EncapsulationKeySize1024 = 1568 -) - -// DecapsulationKey1024 is the secret key used to decapsulate a shared key -// from a ciphertext. It includes various precomputed values. -type DecapsulationKey1024 struct { - key *mlkem.DecapsulationKey1024 -} - -// GenerateKey1024 generates a new decapsulation key, drawing random bytes from -// the default crypto/rand source. The decapsulation key must be kept secret. -func GenerateKey1024() (*DecapsulationKey1024, error) { - key, err := mlkem.GenerateKey1024() - if err != nil { - return nil, err - } - - return &DecapsulationKey1024{key}, nil -} - -// NewDecapsulationKey1024 expands a decapsulation key from a 64-byte seed in the -// "d || z" form. The seed must be uniformly random. -func NewDecapsulationKey1024(seed []byte) (*DecapsulationKey1024, error) { - key, err := mlkem.NewDecapsulationKey1024(seed) - if err != nil { - return nil, err - } - - return &DecapsulationKey1024{key}, nil -} - -// Bytes returns the decapsulation key as a 64-byte seed in the "d || z" form. -// -// The decapsulation key must be kept secret. -func (dk *DecapsulationKey1024) Bytes() []byte { - return dk.key.Bytes() -} - -// Decapsulate generates a shared key from a ciphertext and a decapsulation -// key. If the ciphertext is not valid, Decapsulate returns an error. -// -// The shared key must be kept secret. -func (dk *DecapsulationKey1024) Decapsulate(ciphertext []byte) (sharedKey []byte, err error) { - return dk.key.Decapsulate(ciphertext) -} - -// EncapsulationKey returns the public encapsulation key necessary to produce -// ciphertexts. -func (dk *DecapsulationKey1024) EncapsulationKey() *EncapsulationKey1024 { - return &EncapsulationKey1024{dk.key.EncapsulationKey()} -} - -// An EncapsulationKey1024 is the public key used to produce ciphertexts to be -// decapsulated by the corresponding DecapsulationKey1024. -type EncapsulationKey1024 struct { - key *mlkem.EncapsulationKey1024 -} - -// NewEncapsulationKey1024 parses an encapsulation key from its encoded form. If -// the encapsulation key is not valid, NewEncapsulationKey1024 returns an error. -func NewEncapsulationKey1024(encapsulationKey []byte) (*EncapsulationKey1024, error) { - key, err := mlkem.NewEncapsulationKey1024(encapsulationKey) - if err != nil { - return nil, err - } - - return &EncapsulationKey1024{key}, nil -} - -// Bytes returns the encapsulation key as a byte slice. -func (ek *EncapsulationKey1024) Bytes() []byte { - return ek.key.Bytes() -} - -// Encapsulate generates a shared key and an associated ciphertext from an -// encapsulation key, drawing random bytes from the default crypto/rand source. -// -// The shared key must be kept secret. -func (ek *EncapsulationKey1024) Encapsulate() (sharedKey, ciphertext []byte) { - return ek.key.Encapsulate() -} From 4225c6cb372e0fea7586dd646e991faa5df20671 Mon Sep 17 00:00:00 2001 From: Joe Tsai Date: Wed, 8 Jan 2025 12:30:01 -0800 Subject: [PATCH 126/397] encoding/json: improve fidelity of TestUnmarshal for Numbers In particular, cover the behavior of unmarshaling a JSON string into a Number type regardless of whether the `string` option is specified or not. Change-Id: Ibc55f16860442240bcfeea1fd51aaa76f7e50f67 Reviewed-on: https://go-review.googlesource.com/c/go/+/641416 LUCI-TryBot-Result: Go LUCI Auto-Submit: Joseph Tsai Reviewed-by: Damien Neil Reviewed-by: Dmitri Shuralyov --- src/encoding/json/decode_test.go | 43 ++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/encoding/json/decode_test.go b/src/encoding/json/decode_test.go index a2b462af775e3a..278d1e94fafa3a 100644 --- a/src/encoding/json/decode_test.go +++ b/src/encoding/json/decode_test.go @@ -1068,6 +1068,49 @@ var unmarshalTests = []struct { ptr: new(map[string]Number), err: fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", `"invalid"`), }, + + { + CaseName: Name(""), + in: `5`, + ptr: new(Number), + out: Number("5"), + }, + { + CaseName: Name(""), + in: `"5"`, + ptr: new(Number), + out: Number("5"), + }, + { + CaseName: Name(""), + in: `{"N":5}`, + ptr: new(struct{ N Number }), + out: struct{ N Number }{"5"}, + }, + { + CaseName: Name(""), + in: `{"N":"5"}`, + ptr: new(struct{ N Number }), + out: struct{ N Number }{"5"}, + }, + { + CaseName: Name(""), + in: `{"N":5}`, + ptr: new(struct { + N Number `json:",string"` + }), + err: fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into json.Number"), + }, + { + CaseName: Name(""), + in: `{"N":"5"}`, + ptr: new(struct { + N Number `json:",string"` + }), + out: struct { + N Number `json:",string"` + }{"5"}, + }, } func TestMarshal(t *testing.T) { From f5a89dff67ae00bfc70fbfccc1b1cc044e565b50 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Mon, 6 Jan 2025 18:52:35 +0100 Subject: [PATCH 127/397] crypto: fix fips140=only detection of SHA-3 Both fips140only and the service indicator checks in crypto/internal/fips140/... expect to type assert to crypto/internal/fips140/{sha256,sha512,sha3}.Digest. However, crypto/sha3 returns a wrapper concrete type around sha3.Digest. Add a new fips140hash.Unwrap function to turn the wrapper into the underlying sha3.Digest, and use it consistently before calling into fips140only or the FIPS 140-3 module. In crypto/rsa, also made the fips140only checks apply consistently after the Go+BoringCrypto shims, so we can instantiate the hash, and avoid having to wrap the New function. Note that fips140=only is incompatible with Go+BoringCrypto. Fixes #70879 Change-Id: I6a6a4656ec55c3e13f6cbfadb9cf89c0f9183bdc Reviewed-on: https://go-review.googlesource.com/c/go/+/640855 Auto-Submit: Filippo Valsorda Reviewed-by: Roland Shoemaker Reviewed-by: Russ Cox LUCI-TryBot-Result: Go LUCI --- src/crypto/ecdsa/ecdsa.go | 6 +- src/crypto/hkdf/hkdf.go | 22 ++-- src/crypto/hmac/hmac.go | 2 + src/crypto/internal/fips140hash/hash.go | 34 ++++++ src/crypto/pbkdf2/pbkdf2.go | 6 +- src/crypto/rsa/fips.go | 133 +++++++++++++----------- src/crypto/sha3/sha3.go | 6 ++ src/go/build/deps_test.go | 3 +- 8 files changed, 139 insertions(+), 73 deletions(-) create mode 100644 src/crypto/internal/fips140hash/hash.go diff --git a/src/crypto/ecdsa/ecdsa.go b/src/crypto/ecdsa/ecdsa.go index d9ebe56ef007e5..cb308b41e9df86 100644 --- a/src/crypto/ecdsa/ecdsa.go +++ b/src/crypto/ecdsa/ecdsa.go @@ -23,6 +23,7 @@ import ( "crypto/internal/boring" "crypto/internal/boring/bbig" "crypto/internal/fips140/ecdsa" + "crypto/internal/fips140hash" "crypto/internal/fips140only" "crypto/internal/randutil" "crypto/sha512" @@ -281,10 +282,11 @@ func signFIPSDeterministic[P ecdsa.Point[P]](c *ecdsa.Curve[P], hashFunc crypto. if err != nil { return nil, err } - if fips140only.Enabled && !fips140only.ApprovedHash(hashFunc.New()) { + h := fips140hash.UnwrapNew(hashFunc.New) + if fips140only.Enabled && !fips140only.ApprovedHash(h()) { return nil, errors.New("crypto/ecdsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode") } - sig, err := ecdsa.SignDeterministic(c, hashFunc.New, k, hash) + sig, err := ecdsa.SignDeterministic(c, h, k, hash) if err != nil { return nil, err } diff --git a/src/crypto/hkdf/hkdf.go b/src/crypto/hkdf/hkdf.go index 7cfbe2c60de356..6b02522866d57f 100644 --- a/src/crypto/hkdf/hkdf.go +++ b/src/crypto/hkdf/hkdf.go @@ -12,6 +12,7 @@ package hkdf import ( "crypto/internal/fips140/hkdf" + "crypto/internal/fips140hash" "crypto/internal/fips140only" "errors" "hash" @@ -24,10 +25,11 @@ import ( // Expand invocations and different context values. Most common scenarios, // including the generation of multiple keys, should use [Key] instead. func Extract[H hash.Hash](h func() H, secret, salt []byte) ([]byte, error) { - if err := checkFIPS140Only(h, secret); err != nil { + fh := fips140hash.UnwrapNew(h) + if err := checkFIPS140Only(fh, secret); err != nil { return nil, err } - return hkdf.Extract(h, secret, salt), nil + return hkdf.Extract(fh, secret, salt), nil } // Expand derives a key from the given hash, key, and optional context info, @@ -38,35 +40,37 @@ func Extract[H hash.Hash](h func() H, secret, salt []byte) ([]byte, error) { // random or pseudorandom cryptographically strong key. See RFC 5869, Section // 3.3. Most common scenarios will want to use [Key] instead. func Expand[H hash.Hash](h func() H, pseudorandomKey []byte, info string, keyLength int) ([]byte, error) { - if err := checkFIPS140Only(h, pseudorandomKey); err != nil { + fh := fips140hash.UnwrapNew(h) + if err := checkFIPS140Only(fh, pseudorandomKey); err != nil { return nil, err } - limit := h().Size() * 255 + limit := fh().Size() * 255 if keyLength > limit { return nil, errors.New("hkdf: requested key length too large") } - return hkdf.Expand(h, pseudorandomKey, info, keyLength), nil + return hkdf.Expand(fh, pseudorandomKey, info, keyLength), nil } // Key derives a key from the given hash, secret, salt and context info, // returning a []byte of length keyLength that can be used as cryptographic key. // Salt and info can be nil. func Key[Hash hash.Hash](h func() Hash, secret, salt []byte, info string, keyLength int) ([]byte, error) { - if err := checkFIPS140Only(h, secret); err != nil { + fh := fips140hash.UnwrapNew(h) + if err := checkFIPS140Only(fh, secret); err != nil { return nil, err } - limit := h().Size() * 255 + limit := fh().Size() * 255 if keyLength > limit { return nil, errors.New("hkdf: requested key length too large") } - return hkdf.Key(h, secret, salt, info, keyLength), nil + return hkdf.Key(fh, secret, salt, info, keyLength), nil } -func checkFIPS140Only[H hash.Hash](h func() H, key []byte) error { +func checkFIPS140Only[Hash hash.Hash](h func() Hash, key []byte) error { if !fips140only.Enabled { return nil } diff --git a/src/crypto/hmac/hmac.go b/src/crypto/hmac/hmac.go index 72f5a4abea9d35..554c8c9b78940b 100644 --- a/src/crypto/hmac/hmac.go +++ b/src/crypto/hmac/hmac.go @@ -24,6 +24,7 @@ package hmac import ( "crypto/internal/boring" "crypto/internal/fips140/hmac" + "crypto/internal/fips140hash" "crypto/internal/fips140only" "crypto/subtle" "hash" @@ -43,6 +44,7 @@ func New(h func() hash.Hash, key []byte) hash.Hash { } // BoringCrypto did not recognize h, so fall through to standard Go code. } + h = fips140hash.UnwrapNew(h) if fips140only.Enabled { if len(key) < 112/8 { panic("crypto/hmac: use of keys shorter than 112 bits is not allowed in FIPS 140-only mode") diff --git a/src/crypto/internal/fips140hash/hash.go b/src/crypto/internal/fips140hash/hash.go new file mode 100644 index 00000000000000..6d67ee8b3429a1 --- /dev/null +++ b/src/crypto/internal/fips140hash/hash.go @@ -0,0 +1,34 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package fips140hash + +import ( + fsha3 "crypto/internal/fips140/sha3" + "crypto/sha3" + "hash" + _ "unsafe" +) + +//go:linkname sha3Unwrap +func sha3Unwrap(*sha3.SHA3) *fsha3.Digest + +// Unwrap returns h, or a crypto/internal/fips140 inner implementation of h. +// +// The return value can be type asserted to one of +// [crypto/internal/fips140/sha256.Digest], +// [crypto/internal/fips140/sha512.Digest], or +// [crypto/internal/fips140/sha3.Digest] if it is a FIPS 140-3 approved hash. +func Unwrap(h hash.Hash) hash.Hash { + if sha3, ok := h.(*sha3.SHA3); ok { + return sha3Unwrap(sha3) + } + return h +} + +// UnwrapNew returns a function that calls newHash and applies [Unwrap] to the +// return value. +func UnwrapNew[Hash hash.Hash](newHash func() Hash) func() hash.Hash { + return func() hash.Hash { return Unwrap(newHash()) } +} diff --git a/src/crypto/pbkdf2/pbkdf2.go b/src/crypto/pbkdf2/pbkdf2.go index d40daab5e5b879..271d2b03312ef0 100644 --- a/src/crypto/pbkdf2/pbkdf2.go +++ b/src/crypto/pbkdf2/pbkdf2.go @@ -12,6 +12,7 @@ package pbkdf2 import ( "crypto/internal/fips140/pbkdf2" + "crypto/internal/fips140hash" "crypto/internal/fips140only" "errors" "hash" @@ -34,6 +35,7 @@ import ( // Using a higher iteration count will increase the cost of an exhaustive // search but will also make derivation proportionally slower. func Key[Hash hash.Hash](h func() Hash, password string, salt []byte, iter, keyLength int) ([]byte, error) { + fh := fips140hash.UnwrapNew(h) if fips140only.Enabled { if keyLength < 112/8 { return nil, errors.New("crypto/pbkdf2: use of keys shorter than 112 bits is not allowed in FIPS 140-only mode") @@ -41,9 +43,9 @@ func Key[Hash hash.Hash](h func() Hash, password string, salt []byte, iter, keyL if len(salt) < 128/8 { return nil, errors.New("crypto/pbkdf2: use of salts shorter than 128 bits is not allowed in FIPS 140-only mode") } - if !fips140only.ApprovedHash(h()) { + if !fips140only.ApprovedHash(fh()) { return nil, errors.New("crypto/pbkdf2: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode") } } - return pbkdf2.Key(h, password, salt, iter, keyLength) + return pbkdf2.Key(fh, password, salt, iter, keyLength) } diff --git a/src/crypto/rsa/fips.go b/src/crypto/rsa/fips.go index 347775df1603c0..8373c125ae3096 100644 --- a/src/crypto/rsa/fips.go +++ b/src/crypto/rsa/fips.go @@ -8,6 +8,7 @@ import ( "crypto" "crypto/internal/boring" "crypto/internal/fips140/rsa" + "crypto/internal/fips140hash" "crypto/internal/fips140only" "errors" "hash" @@ -64,21 +65,11 @@ func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, digest []byte, if err := checkPublicKeySize(&priv.PublicKey); err != nil { return nil, err } - if err := checkFIPS140OnlyPrivateKey(priv); err != nil { - return nil, err - } if opts != nil && opts.Hash != 0 { hash = opts.Hash } - if fips140only.Enabled && !fips140only.ApprovedHash(hash.New()) { - return nil, errors.New("crypto/rsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode") - } - if fips140only.Enabled && !fips140only.ApprovedRandomReader(rand) { - return nil, errors.New("crypto/rsa: only crypto/rand.Reader is allowed in FIPS 140-only mode") - } - if boring.Enabled && rand == boring.RandReader { bkey, err := boringPrivateKey(priv) if err != nil { @@ -88,14 +79,25 @@ func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, digest []byte, } boring.UnreachableExceptTests() + h := fips140hash.Unwrap(hash.New()) + + if err := checkFIPS140OnlyPrivateKey(priv); err != nil { + return nil, err + } + if fips140only.Enabled && !fips140only.ApprovedHash(h) { + return nil, errors.New("crypto/rsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode") + } + if fips140only.Enabled && !fips140only.ApprovedRandomReader(rand) { + return nil, errors.New("crypto/rsa: only crypto/rand.Reader is allowed in FIPS 140-only mode") + } + k, err := fipsPrivateKey(priv) if err != nil { return nil, err } - h := hash.New() saltLength := opts.saltLength() - if fips140only.Enabled && saltLength > hash.Size() { + if fips140only.Enabled && saltLength > h.Size() { return nil, errors.New("crypto/rsa: use of PSS salt longer than the hash is not allowed in FIPS 140-only mode") } switch saltLength { @@ -105,7 +107,7 @@ func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, digest []byte, return nil, fipsError(err) } case PSSSaltLengthEqualsHash: - saltLength = hash.Size() + saltLength = h.Size() default: // If we get here saltLength is either > 0 or < -1, in the // latter case we fail out. @@ -130,12 +132,6 @@ func VerifyPSS(pub *PublicKey, hash crypto.Hash, digest []byte, sig []byte, opts if err := checkPublicKeySize(pub); err != nil { return err } - if err := checkFIPS140OnlyPublicKey(pub); err != nil { - return err - } - if fips140only.Enabled && !fips140only.ApprovedHash(hash.New()) { - return errors.New("crypto/rsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode") - } if boring.Enabled { bkey, err := boringPublicKey(pub) @@ -148,22 +144,31 @@ func VerifyPSS(pub *PublicKey, hash crypto.Hash, digest []byte, sig []byte, opts return nil } + h := fips140hash.Unwrap(hash.New()) + + if err := checkFIPS140OnlyPublicKey(pub); err != nil { + return err + } + if fips140only.Enabled && !fips140only.ApprovedHash(h) { + return errors.New("crypto/rsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode") + } + k, err := fipsPublicKey(pub) if err != nil { return err } saltLength := opts.saltLength() - if fips140only.Enabled && saltLength > hash.Size() { + if fips140only.Enabled && saltLength > h.Size() { return errors.New("crypto/rsa: use of PSS salt longer than the hash is not allowed in FIPS 140-only mode") } switch saltLength { case PSSSaltLengthAuto: - return fipsError(rsa.VerifyPSS(k, hash.New(), digest, sig)) + return fipsError(rsa.VerifyPSS(k, h, digest, sig)) case PSSSaltLengthEqualsHash: - return fipsError(rsa.VerifyPSSWithSaltLength(k, hash.New(), digest, sig, hash.Size())) + return fipsError(rsa.VerifyPSSWithSaltLength(k, h, digest, sig, h.Size())) default: - return fipsError(rsa.VerifyPSSWithSaltLength(k, hash.New(), digest, sig, saltLength)) + return fipsError(rsa.VerifyPSSWithSaltLength(k, h, digest, sig, saltLength)) } } @@ -189,15 +194,6 @@ func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, l if err := checkPublicKeySize(pub); err != nil { return nil, err } - if err := checkFIPS140OnlyPublicKey(pub); err != nil { - return nil, err - } - if fips140only.Enabled && !fips140only.ApprovedHash(hash) { - return nil, errors.New("crypto/rsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode") - } - if fips140only.Enabled && !fips140only.ApprovedRandomReader(random) { - return nil, errors.New("crypto/rsa: only crypto/rand.Reader is allowed in FIPS 140-only mode") - } defer hash.Reset() @@ -215,6 +211,18 @@ func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, l } boring.UnreachableExceptTests() + hash = fips140hash.Unwrap(hash) + + if err := checkFIPS140OnlyPublicKey(pub); err != nil { + return nil, err + } + if fips140only.Enabled && !fips140only.ApprovedHash(hash) { + return nil, errors.New("crypto/rsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode") + } + if fips140only.Enabled && !fips140only.ApprovedRandomReader(random) { + return nil, errors.New("crypto/rsa: only crypto/rand.Reader is allowed in FIPS 140-only mode") + } + k, err := fipsPublicKey(pub) if err != nil { return nil, err @@ -241,14 +249,6 @@ func decryptOAEP(hash, mgfHash hash.Hash, priv *PrivateKey, ciphertext []byte, l if err := checkPublicKeySize(&priv.PublicKey); err != nil { return nil, err } - if err := checkFIPS140OnlyPrivateKey(priv); err != nil { - return nil, err - } - if fips140only.Enabled { - if !fips140only.ApprovedHash(hash) || !fips140only.ApprovedHash(mgfHash) { - return nil, errors.New("crypto/rsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode") - } - } if boring.Enabled { k := priv.Size() @@ -267,6 +267,18 @@ func decryptOAEP(hash, mgfHash hash.Hash, priv *PrivateKey, ciphertext []byte, l return out, nil } + hash = fips140hash.Unwrap(hash) + mgfHash = fips140hash.Unwrap(mgfHash) + + if err := checkFIPS140OnlyPrivateKey(priv); err != nil { + return nil, err + } + if fips140only.Enabled { + if !fips140only.ApprovedHash(hash) || !fips140only.ApprovedHash(mgfHash) { + return nil, errors.New("crypto/rsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode") + } + } + k, err := fipsPrivateKey(priv) if err != nil { return nil, err @@ -299,12 +311,6 @@ func SignPKCS1v15(random io.Reader, priv *PrivateKey, hash crypto.Hash, hashed [ if err := checkPublicKeySize(&priv.PublicKey); err != nil { return nil, err } - if err := checkFIPS140OnlyPrivateKey(priv); err != nil { - return nil, err - } - if fips140only.Enabled && !fips140only.ApprovedHash(hash.New()) { - return nil, errors.New("crypto/rsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode") - } if boring.Enabled { bkey, err := boringPrivateKey(priv) @@ -314,6 +320,13 @@ func SignPKCS1v15(random io.Reader, priv *PrivateKey, hash crypto.Hash, hashed [ return boring.SignRSAPKCS1v15(bkey, hash, hashed) } + if err := checkFIPS140OnlyPrivateKey(priv); err != nil { + return nil, err + } + if fips140only.Enabled && !fips140only.ApprovedHash(fips140hash.Unwrap(hash.New())) { + return nil, errors.New("crypto/rsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode") + } + k, err := fipsPrivateKey(priv) if err != nil { return nil, err @@ -330,15 +343,17 @@ func SignPKCS1v15(random io.Reader, priv *PrivateKey, hash crypto.Hash, hashed [ // The inputs are not considered confidential, and may leak through timing side // channels, or if an attacker has control of part of the inputs. func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) error { - if err := checkPublicKeySize(pub); err != nil { - return err + var hashName string + if hash != crypto.Hash(0) { + if len(hashed) != hash.Size() { + return errors.New("crypto/rsa: input must be hashed message") + } + hashName = hash.String() } - if err := checkFIPS140OnlyPublicKey(pub); err != nil { + + if err := checkPublicKeySize(pub); err != nil { return err } - if fips140only.Enabled && !fips140only.ApprovedHash(hash.New()) { - return errors.New("crypto/rsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode") - } if boring.Enabled { bkey, err := boringPublicKey(pub) @@ -351,17 +366,17 @@ func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) return nil } + if err := checkFIPS140OnlyPublicKey(pub); err != nil { + return err + } + if fips140only.Enabled && !fips140only.ApprovedHash(fips140hash.Unwrap(hash.New())) { + return errors.New("crypto/rsa: use of hash functions other than SHA-2 or SHA-3 is not allowed in FIPS 140-only mode") + } + k, err := fipsPublicKey(pub) if err != nil { return err } - var hashName string - if hash != crypto.Hash(0) { - if len(hashed) != hash.Size() { - return errors.New("crypto/rsa: input must be hashed message") - } - hashName = hash.String() - } return fipsError(rsa.VerifyPKCS1v15(k, hashName, hashed, sig)) } diff --git a/src/crypto/sha3/sha3.go b/src/crypto/sha3/sha3.go index 0f4d7ed4370b5f..a6c5ae55f1ff20 100644 --- a/src/crypto/sha3/sha3.go +++ b/src/crypto/sha3/sha3.go @@ -10,6 +10,7 @@ import ( "crypto" "crypto/internal/fips140/sha3" "hash" + _ "unsafe" ) func init() { @@ -100,6 +101,11 @@ type SHA3 struct { s sha3.Digest } +//go:linkname fips140hash_sha3Unwrap crypto/internal/fips140hash.sha3Unwrap +func fips140hash_sha3Unwrap(sha3 *SHA3) *sha3.Digest { + return &sha3.s +} + // New224 creates a new SHA3-224 hash. func New224() *SHA3 { return &SHA3{*sha3.New224()} diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index a62a5173b9c6bc..e3e01077c18b17 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -510,6 +510,8 @@ var depsRules = ` < crypto/internal/fips140only < crypto < crypto/subtle + < crypto/sha3 + < crypto/internal/fips140hash < crypto/cipher < crypto/internal/boring < crypto/boring @@ -520,7 +522,6 @@ var depsRules = ` crypto/sha1, crypto/sha256, crypto/sha512, - crypto/sha3, crypto/hmac, crypto/hkdf, crypto/pbkdf2, From c6ab13fc43477d36158aecd85680301094a84488 Mon Sep 17 00:00:00 2001 From: Michael Matloob Date: Fri, 3 Jan 2025 15:06:42 -0500 Subject: [PATCH 128/397] cmd/go/internal/mmap: reslice to file size on Windows The Mmap function returns a Data struct containing a slice with the mapped contents of the file. Before this change, on Windows, the slice contained the contents of all the pages of the mapping, including past the end of the file. Re-slice the slice to the length of the file (if if the slice is longer) so that the slice contains only the data in the file. For #71059 Change-Id: I389b752505b6fa1252b5c6d836a37bc7e662a45d Reviewed-on: https://go-review.googlesource.com/c/go/+/640155 Reviewed-by: Russ Cox LUCI-TryBot-Result: Go LUCI --- src/cmd/go/internal/mmap/mmap_test.go | 32 +++++++++++++++++++ src/cmd/go/internal/mmap/mmap_windows.go | 8 ++++- .../go/internal/mmap/testdata/small_file.txt | 1 + 3 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 src/cmd/go/internal/mmap/mmap_test.go create mode 100644 src/cmd/go/internal/mmap/testdata/small_file.txt diff --git a/src/cmd/go/internal/mmap/mmap_test.go b/src/cmd/go/internal/mmap/mmap_test.go new file mode 100644 index 00000000000000..3f4b63caf19bd2 --- /dev/null +++ b/src/cmd/go/internal/mmap/mmap_test.go @@ -0,0 +1,32 @@ +// Copyright 2025 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package mmap + +import ( + "bytes" + "testing" +) + +// TestMmap does a round trip to make sure the slice returned by +// mmap contains the same data as was written to the file. It's +// a test on one of the issues in #71059: on Windows we were +// returning a slice containing all the data in the mmapped pages, +// which could be longer than the file. +func TestMmap(t *testing.T) { + // Use an already existing file as our test data. Avoid creating + // a temporary file so that we don't have to close the mapping on + // Windows before deleting the file during test cleanup. + f := "testdata/small_file.txt" + + want := []byte("This file is shorter than 4096 bytes.\n") + + data, _, err := Mmap(f) + if err != nil { + t.Fatalf("calling Mmap: %v", err) + } + if !bytes.Equal(data.Data, want) { + t.Fatalf("mmapped data slice: got %q; want %q", data.Data, want) + } +} diff --git a/src/cmd/go/internal/mmap/mmap_windows.go b/src/cmd/go/internal/mmap/mmap_windows.go index d00bef71e5cfc5..4163484b1a3510 100644 --- a/src/cmd/go/internal/mmap/mmap_windows.go +++ b/src/cmd/go/internal/mmap/mmap_windows.go @@ -37,5 +37,11 @@ func mmapFile(f *os.File) (Data, error) { return Data{}, fmt.Errorf("VirtualQuery %s: %w", f.Name(), err) } data := unsafe.Slice((*byte)(unsafe.Pointer(addr)), int(info.RegionSize)) - return Data{f, data}, nil + if len(data) < int(size) { + // In some cases, especially on 386, we may not receive a in incomplete mapping: + // one that is shorter than the file itself. Return an error in those cases because + // incomplete mappings are not useful. + return Data{}, fmt.Errorf("mmapFile: received incomplete mapping of file") + } + return Data{f, data[:int(size)]}, nil } diff --git a/src/cmd/go/internal/mmap/testdata/small_file.txt b/src/cmd/go/internal/mmap/testdata/small_file.txt new file mode 100644 index 00000000000000..10bb609f2ab334 --- /dev/null +++ b/src/cmd/go/internal/mmap/testdata/small_file.txt @@ -0,0 +1 @@ +This file is shorter than 4096 bytes. From c7c4420ae4b0e82b26606776fbd0e4fea97d37c9 Mon Sep 17 00:00:00 2001 From: Sean Liao Date: Thu, 28 Nov 2024 16:10:52 +0000 Subject: [PATCH 129/397] cmd/go: clarify GODEBUG in go help environment Fixes #37004 Fixes #50444 Change-Id: I7dd5a8c9bd0a2122ff38508cf509369d6d8ad599 Reviewed-on: https://go-review.googlesource.com/c/go/+/632177 Reviewed-by: Dmitri Shuralyov LUCI-TryBot-Result: Go LUCI Reviewed-by: Michael Matloob --- src/cmd/go/alldocs.go | 5 +++-- src/cmd/go/internal/help/helpdoc.go | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index 20d76de0c742e1..830bac2b2f8965 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -2338,8 +2338,9 @@ // external go command build cache. // See 'go doc cmd/go/internal/cacheprog'. // GODEBUG -// Enable various debugging facilities. See https://go.dev/doc/godebug -// for details. +// Enable various debugging facilities for programs built with Go, +// including the go command. Cannot be set using 'go env -w'. +// See https://go.dev/doc/godebug for details. // GOENV // The location of the Go environment configuration file. // Cannot be set using 'go env -w'. diff --git a/src/cmd/go/internal/help/helpdoc.go b/src/cmd/go/internal/help/helpdoc.go index 65d0f1a45c0c17..23459ef15413e3 100644 --- a/src/cmd/go/internal/help/helpdoc.go +++ b/src/cmd/go/internal/help/helpdoc.go @@ -511,8 +511,9 @@ General-purpose environment variables: external go command build cache. See 'go doc cmd/go/internal/cacheprog'. GODEBUG - Enable various debugging facilities. See https://go.dev/doc/godebug - for details. + Enable various debugging facilities for programs built with Go, + including the go command. Cannot be set using 'go env -w'. + See https://go.dev/doc/godebug for details. GOENV The location of the Go environment configuration file. Cannot be set using 'go env -w'. From d0c9142ce3b6fac83dadcc76ecfb85311431e743 Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Thu, 9 Jan 2025 12:22:53 -0500 Subject: [PATCH 130/397] runtime/pprof: hide map runtime frames from heap profiles Heap profiles hide "runtime" frames like runtime.mapassign. This broke in 1.24 because the map implementation moved to internal/runtime/maps, and runtime/pprof only considered literal "runtime." when looking for runtime frames. It would be nice to use cmd/internal/objabi.PkgSpecial to find runtime packages, but that is hidden away in cmd. Fixes #71174. Change-Id: I6a6a636cb42aa17539e47da16854bd3fd8cb1bfe Reviewed-on: https://go-review.googlesource.com/c/go/+/641775 Auto-Submit: Michael Pratt LUCI-TryBot-Result: Go LUCI Reviewed-by: Michael Knyszek --- src/runtime/pprof/pprof.go | 2 +- src/runtime/pprof/protomem.go | 2 +- src/runtime/pprof/protomem_test.go | 60 +++++++++++++++++++++++++++++- 3 files changed, 61 insertions(+), 3 deletions(-) diff --git a/src/runtime/pprof/pprof.go b/src/runtime/pprof/pprof.go index f6b4a5c367f05f..b7680a13fdcb25 100644 --- a/src/runtime/pprof/pprof.go +++ b/src/runtime/pprof/pprof.go @@ -555,7 +555,7 @@ func printStackRecord(w io.Writer, stk []uintptr, allFrames bool) { if name == "" { show = true fmt.Fprintf(w, "#\t%#x\n", frame.PC) - } else if name != "runtime.goexit" && (show || !strings.HasPrefix(name, "runtime.")) { + } else if name != "runtime.goexit" && (show || !(strings.HasPrefix(name, "runtime.") || strings.HasPrefix(name, "internal/runtime/"))) { // Hide runtime.goexit and any runtime functions at the beginning. // This is useful mainly for allocation traces. show = true diff --git a/src/runtime/pprof/protomem.go b/src/runtime/pprof/protomem.go index ab3550f43f9a39..72aad82b300534 100644 --- a/src/runtime/pprof/protomem.go +++ b/src/runtime/pprof/protomem.go @@ -36,7 +36,7 @@ func writeHeapProto(w io.Writer, p []profilerecord.MemProfileRecord, rate int64, // what appendLocsForStack expects. if hideRuntime { for i, addr := range stk { - if f := runtime.FuncForPC(addr); f != nil && strings.HasPrefix(f.Name(), "runtime.") { + if f := runtime.FuncForPC(addr); f != nil && (strings.HasPrefix(f.Name(), "runtime.") || strings.HasPrefix(f.Name(), "internal/runtime/")) { continue } // Found non-runtime. Show any runtime uses above it. diff --git a/src/runtime/pprof/protomem_test.go b/src/runtime/pprof/protomem_test.go index 885f4dca5b8762..4d08e67ddc7540 100644 --- a/src/runtime/pprof/protomem_test.go +++ b/src/runtime/pprof/protomem_test.go @@ -118,7 +118,7 @@ func locationToStrings(loc *profile.Location, funcs []string) []string { return funcs } -// This is a regression test for https://go.dev/issue/64528 . +// This is a regression test for https://go.dev/issue/64528. func TestGenericsHashKeyInPprofBuilder(t *testing.T) { if asan.Enabled { t.Skip("extra allocations with -asan throw off the test; see #70079") @@ -229,3 +229,61 @@ func TestGenericsInlineLocations(t *testing.T) { t.Errorf("expected a location with at least 3 functions\n%s\ngot\n%s\n", expectedLocation, actual) } } + +func growMap() { + m := make(map[int]int) + for i := range 512 { + m[i] = i + } +} + +// Runtime frames are hidden in heap profiles. +// This is a regression test for https://go.dev/issue/71174. +func TestHeapRuntimeFrames(t *testing.T) { + previousRate := runtime.MemProfileRate + runtime.MemProfileRate = 1 + defer func() { + runtime.MemProfileRate = previousRate + }() + + growMap() + + runtime.GC() + buf := bytes.NewBuffer(nil) + if err := WriteHeapProfile(buf); err != nil { + t.Fatalf("writing profile: %v", err) + } + p, err := profile.Parse(buf) + if err != nil { + t.Fatalf("profile.Parse: %v", err) + } + + actual := profileToStrings(p) + + // We must see growMap at least once. + foundGrowMap := false + for _, l := range actual { + if !strings.Contains(l, "runtime/pprof.growMap") { + continue + } + foundGrowMap = true + + // Runtime frames like mapassign and map internals should be hidden. + if strings.Contains(l, "runtime.") { + t.Errorf("Sample got %s, want no runtime frames", l) + } + if strings.Contains(l, "internal/runtime/") { + t.Errorf("Sample got %s, want no runtime frames", l) + } + if strings.Contains(l, "runtime/internal/") { + t.Errorf("Sample got %s, want no runtime frames", l) + } + if strings.Contains(l, "mapassign") { // in case mapassign moves to a package not matching above paths. + t.Errorf("Sample got %s, want no mapassign frames", l) + } + } + + if !foundGrowMap { + t.Errorf("Profile got:\n%s\nwant sample in runtime/pprof.growMap", strings.Join(actual, "\n")) + } +} From 932ec2be8d01e553a768df3709182abf2b579097 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Thu, 9 Jan 2025 15:12:49 +0100 Subject: [PATCH 131/397] crypto/rsa: fix GenerateKey flakes for toy-sized keys Could have fixed this some other ways, including inside the FIPS 140-3 module, but this is small and self-contained, clearly not affecting production non-toy key sizes. This late in the freeze, a surgical fix felt best. Fixes #71185 Change-Id: I6a6a465641357c9d6b076c8a520b221be4210ed5 Reviewed-on: https://go-review.googlesource.com/c/go/+/641755 LUCI-TryBot-Result: Go LUCI Reviewed-by: Roland Shoemaker Auto-Submit: Filippo Valsorda Reviewed-by: Russ Cox --- src/crypto/rsa/rsa.go | 15 +++++++++++++++ src/crypto/rsa/rsa_test.go | 17 +++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/crypto/rsa/rsa.go b/src/crypto/rsa/rsa.go index fb23f003a6f217..95bb4becd2ff8c 100644 --- a/src/crypto/rsa/rsa.go +++ b/src/crypto/rsa/rsa.go @@ -327,6 +327,21 @@ func GenerateKey(random io.Reader, bits int) (*PrivateKey, error) { } k, err := rsa.GenerateKey(random, bits) + if bits < 256 && err != nil { + // Toy-sized keys have a non-negligible chance of hitting two hard + // failure cases: p == q and d <= 2^(nlen / 2). + // + // Since these are impossible to hit for real keys, we don't want to + // make the production code path more complex and harder to think about + // to handle them. + // + // Instead, just rerun the whole process a total of 8 times, which + // brings the chance of failure for 32-bit keys down to the same as for + // 256-bit keys. + for i := 1; i < 8 && err != nil; i++ { + k, err = rsa.GenerateKey(random, bits) + } + } if err != nil { return nil, err } diff --git a/src/crypto/rsa/rsa_test.go b/src/crypto/rsa/rsa_test.go index 2535661040273a..73b0c3749eedb2 100644 --- a/src/crypto/rsa/rsa_test.go +++ b/src/crypto/rsa/rsa_test.go @@ -109,6 +109,23 @@ func TestImpossibleKeyGeneration(t *testing.T) { } } +func TestTinyKeyGeneration(t *testing.T) { + // Toy-sized keys can randomly hit hard failures in GenerateKey. + if testing.Short() { + t.Skip("skipping in short mode") + } + t.Setenv("GODEBUG", "rsa1024min=0") + for range 10000 { + k, err := GenerateKey(rand.Reader, 32) + if err != nil { + t.Fatalf("GenerateKey(32): %v", err) + } + if err := k.Validate(); err != nil { + t.Fatalf("Validate(32): %v", err) + } + } +} + func TestGnuTLSKey(t *testing.T) { t.Setenv("GODEBUG", "rsa1024min=0") // This is a key generated by `certtool --generate-privkey --bits 128`. From 7255b949202bb752b6525aa24cb636ceaf24e4d1 Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Wed, 18 Dec 2024 13:26:20 -0500 Subject: [PATCH 132/397] crypto/internal/fips140test: add ML-KEM ACVP tests Adds ACVP test coverage for ML-KEM based on the NIST spec: https://pages.nist.gov/ACVP/draft-celi-acvp-ml-kem.html Notably we need to update the BoringSSL module version because the acvptool was only recently updated to support testing ML-KEM. A few non-test updates are also required for the crypto/internal/fips140/mlkem package: * For keyGen tests a new ExpandedBytes768() function is added that converts a DecapsualtionKey768 struct into the expanded NIST serialization. The existing Bytes() function returns the key's seed, while ACVP testing requires the more cumbersome format. * For decap tests a new TestingOnlyNewDecapsulationKey768() constructor is added to produce a DecapsulationKey768 struct from the expanded FIPS 203 serialization provided by the ACVP test vector. The pre-existing NewDecapsulationKey768() function expects a seed as input. The generate1024.go helper is updated to translate the above changes to the generated mlkem1024.go implementation. Both of these new functions are exclusively for ACVP usage and so not present in the public mlkem API. End users should always prefer to work with seeds. Updates #69642 Change-Id: I79784f8a8db00a2ddefdcece4b8de50b033c8f69 Reviewed-on: https://go-review.googlesource.com/c/go/+/637439 Reviewed-by: Carlos Amedee Reviewed-by: Filippo Valsorda Reviewed-by: David Chase LUCI-TryBot-Result: Go LUCI --- .../internal/fips140/mlkem/generate1024.go | 9 +- .../internal/fips140/mlkem/mlkem1024.go | 74 ++++++++++ src/crypto/internal/fips140/mlkem/mlkem768.go | 76 ++++++++++ .../fips140test/acvp_capabilities.json | 7 +- .../fips140test/acvp_test.config.json | 4 +- src/crypto/internal/fips140test/acvp_test.go | 138 +++++++++++++++++- 6 files changed, 300 insertions(+), 8 deletions(-) diff --git a/src/crypto/internal/fips140/mlkem/generate1024.go b/src/crypto/internal/fips140/mlkem/generate1024.go index e002bf1414ae96..9e38ad00df99e0 100644 --- a/src/crypto/internal/fips140/mlkem/generate1024.go +++ b/src/crypto/internal/fips140/mlkem/generate1024.go @@ -22,6 +22,7 @@ var replacements = map[string]string{ "CiphertextSize768": "CiphertextSize1024", "EncapsulationKeySize768": "EncapsulationKeySize1024", + "decapsulationKeySize768": "decapsulationKeySize1024", "encryptionKey": "encryptionKey1024", "decryptionKey": "decryptionKey1024", @@ -33,9 +34,11 @@ var replacements = map[string]string{ "kemEncaps": "kemEncaps1024", "pkeEncrypt": "pkeEncrypt1024", - "DecapsulationKey768": "DecapsulationKey1024", - "NewDecapsulationKey768": "NewDecapsulationKey1024", - "newKeyFromSeed": "newKeyFromSeed1024", + "DecapsulationKey768": "DecapsulationKey1024", + "NewDecapsulationKey768": "NewDecapsulationKey1024", + "TestingOnlyNewDecapsulationKey768": "TestingOnlyNewDecapsulationKey1024", + "newKeyFromSeed": "newKeyFromSeed1024", + "TestingOnlyExpandedBytes768": "TestingOnlyExpandedBytes1024", "kemDecaps": "kemDecaps1024", "pkeDecrypt": "pkeDecrypt1024", diff --git a/src/crypto/internal/fips140/mlkem/mlkem1024.go b/src/crypto/internal/fips140/mlkem/mlkem1024.go index c924c382933c5f..034bf3b5d6682d 100644 --- a/src/crypto/internal/fips140/mlkem/mlkem1024.go +++ b/src/crypto/internal/fips140/mlkem/mlkem1024.go @@ -3,6 +3,7 @@ package mlkem import ( + "bytes" "crypto/internal/fips140" "crypto/internal/fips140/drbg" "crypto/internal/fips140/sha3" @@ -33,6 +34,32 @@ func (dk *DecapsulationKey1024) Bytes() []byte { return b[:] } +// TestingOnlyExpandedBytes1024 returns the decapsulation key as a byte slice +// using the full expanded NIST encoding. +// +// This should only be used for ACVP testing. For all other purposes prefer +// the Bytes method that returns the (much smaller) seed. +func TestingOnlyExpandedBytes1024(dk *DecapsulationKey1024) []byte { + b := make([]byte, 0, decapsulationKeySize1024) + + // ByteEncode₁₂(s) + for i := range dk.s { + b = polyByteEncode(b, dk.s[i]) + } + + // ByteEncode₁₂(t) || ρ + for i := range dk.t { + b = polyByteEncode(b, dk.t[i]) + } + b = append(b, dk.ρ[:]...) + + // H(ek) || z + b = append(b, dk.h[:]...) + b = append(b, dk.z[:]...) + + return b +} + // EncapsulationKey returns the public encapsulation key necessary to produce // ciphertexts. func (dk *DecapsulationKey1024) EncapsulationKey() *EncapsulationKey1024 { @@ -130,6 +157,53 @@ func newKeyFromSeed1024(dk *DecapsulationKey1024, seed []byte) (*DecapsulationKe return dk, nil } +// TestingOnlyNewDecapsulationKey1024 parses a decapsulation key from its expanded NIST format. +// +// Bytes() must not be called on the returned key, as it will not produce the +// original seed. +// +// This function should only be used for ACVP testing. Prefer NewDecapsulationKey1024 for all +// other purposes. +func TestingOnlyNewDecapsulationKey1024(b []byte) (*DecapsulationKey1024, error) { + if len(b) != decapsulationKeySize1024 { + return nil, errors.New("mlkem: invalid NIST decapsulation key length") + } + + dk := &DecapsulationKey1024{} + for i := range dk.s { + var err error + dk.s[i], err = polyByteDecode[nttElement](b[:encodingSize12]) + if err != nil { + return nil, errors.New("mlkem: invalid secret key encoding") + } + b = b[encodingSize12:] + } + + ek, err := NewEncapsulationKey1024(b[:EncapsulationKeySize1024]) + if err != nil { + return nil, err + } + dk.ρ = ek.ρ + dk.h = ek.h + dk.encryptionKey1024 = ek.encryptionKey1024 + b = b[EncapsulationKeySize1024:] + + if !bytes.Equal(dk.h[:], b[:32]) { + return nil, errors.New("mlkem: inconsistent H(ek) in encoded bytes") + } + b = b[32:] + + copy(dk.z[:], b) + + // Generate a random d value for use in Bytes(). This is a safety mechanism + // that avoids returning a broken key vs a random key if this function is + // called in contravention of the TestingOnlyNewDecapsulationKey1024 function + // comment advising against it. + drbg.Read(dk.d[:]) + + return dk, nil +} + // kemKeyGen1024 generates a decapsulation key. // // It implements ML-KEM.KeyGen_internal according to FIPS 203, Algorithm 16, and diff --git a/src/crypto/internal/fips140/mlkem/mlkem768.go b/src/crypto/internal/fips140/mlkem/mlkem768.go index 2c1cb5c33fcdd1..77043830d4d962 100644 --- a/src/crypto/internal/fips140/mlkem/mlkem768.go +++ b/src/crypto/internal/fips140/mlkem/mlkem768.go @@ -24,6 +24,7 @@ package mlkem //go:generate go run generate1024.go -input mlkem768.go -output mlkem1024.go import ( + "bytes" "crypto/internal/fips140" "crypto/internal/fips140/drbg" "crypto/internal/fips140/sha3" @@ -57,6 +58,7 @@ const ( CiphertextSize768 = k*encodingSize10 + encodingSize4 EncapsulationKeySize768 = k*encodingSize12 + 32 + decapsulationKeySize768 = k*encodingSize12 + EncapsulationKeySize768 + 32 + 32 ) // ML-KEM-1024 parameters. @@ -65,6 +67,7 @@ const ( CiphertextSize1024 = k1024*encodingSize11 + encodingSize5 EncapsulationKeySize1024 = k1024*encodingSize12 + 32 + decapsulationKeySize1024 = k1024*encodingSize12 + EncapsulationKeySize1024 + 32 + 32 ) // A DecapsulationKey768 is the secret key used to decapsulate a shared key from a @@ -90,6 +93,32 @@ func (dk *DecapsulationKey768) Bytes() []byte { return b[:] } +// TestingOnlyExpandedBytes768 returns the decapsulation key as a byte slice +// using the full expanded NIST encoding. +// +// This should only be used for ACVP testing. For all other purposes prefer +// the Bytes method that returns the (much smaller) seed. +func TestingOnlyExpandedBytes768(dk *DecapsulationKey768) []byte { + b := make([]byte, 0, decapsulationKeySize768) + + // ByteEncode₁₂(s) + for i := range dk.s { + b = polyByteEncode(b, dk.s[i]) + } + + // ByteEncode₁₂(t) || ρ + for i := range dk.t { + b = polyByteEncode(b, dk.t[i]) + } + b = append(b, dk.ρ[:]...) + + // H(ek) || z + b = append(b, dk.h[:]...) + b = append(b, dk.z[:]...) + + return b +} + // EncapsulationKey returns the public encapsulation key necessary to produce // ciphertexts. func (dk *DecapsulationKey768) EncapsulationKey() *EncapsulationKey768 { @@ -187,6 +216,53 @@ func newKeyFromSeed(dk *DecapsulationKey768, seed []byte) (*DecapsulationKey768, return dk, nil } +// TestingOnlyNewDecapsulationKey768 parses a decapsulation key from its expanded NIST format. +// +// Bytes() must not be called on the returned key, as it will not produce the +// original seed. +// +// This function should only be used for ACVP testing. Prefer NewDecapsulationKey768 for all +// other purposes. +func TestingOnlyNewDecapsulationKey768(b []byte) (*DecapsulationKey768, error) { + if len(b) != decapsulationKeySize768 { + return nil, errors.New("mlkem: invalid NIST decapsulation key length") + } + + dk := &DecapsulationKey768{} + for i := range dk.s { + var err error + dk.s[i], err = polyByteDecode[nttElement](b[:encodingSize12]) + if err != nil { + return nil, errors.New("mlkem: invalid secret key encoding") + } + b = b[encodingSize12:] + } + + ek, err := NewEncapsulationKey768(b[:EncapsulationKeySize768]) + if err != nil { + return nil, err + } + dk.ρ = ek.ρ + dk.h = ek.h + dk.encryptionKey = ek.encryptionKey + b = b[EncapsulationKeySize768:] + + if !bytes.Equal(dk.h[:], b[:32]) { + return nil, errors.New("mlkem: inconsistent H(ek) in encoded bytes") + } + b = b[32:] + + copy(dk.z[:], b) + + // Generate a random d value for use in Bytes(). This is a safety mechanism + // that avoids returning a broken key vs a random key if this function is + // called in contravention of the TestingOnlyNewDecapsulationKey768 function + // comment advising against it. + drbg.Read(dk.d[:]) + + return dk, nil +} + // kemKeyGen generates a decapsulation key. // // It implements ML-KEM.KeyGen_internal according to FIPS 203, Algorithm 16, and diff --git a/src/crypto/internal/fips140test/acvp_capabilities.json b/src/crypto/internal/fips140test/acvp_capabilities.json index 6502a98db12dcb..38ce3a39c4b30f 100644 --- a/src/crypto/internal/fips140test/acvp_capabilities.json +++ b/src/crypto/internal/fips140test/acvp_capabilities.json @@ -23,5 +23,8 @@ {"algorithm":"HMAC-SHA3-384","keyLen":[{"increment":8,"max":524288,"min":8}],"macLen":[{"increment":8,"max":384,"min":32}],"revision":"1.0"}, {"algorithm":"HMAC-SHA3-512","keyLen":[{"increment":8,"max":524288,"min":8}],"macLen":[{"increment":8,"max":512,"min":32}],"revision":"1.0"}, - {"algorithm":"PBKDF","capabilities":[{"iterationCount":[{"min":1,"max":10000,"increment":1}],"keyLen":[{"min":112,"max":4096,"increment":8}],"passwordLen":[{"min":8,"max":64,"increment":1}],"saltLen":[{"min":128,"max":512,"increment":8}],"hmacAlg":["SHA2-224","SHA2-256","SHA2-384","SHA2-512","SHA2-512/224","SHA2-512/256","SHA3-224","SHA3-256","SHA3-384","SHA3-512"]}],"revision":"1.0"} -] \ No newline at end of file + {"algorithm":"PBKDF","capabilities":[{"iterationCount":[{"min":1,"max":10000,"increment":1}],"keyLen":[{"min":112,"max":4096,"increment":8}],"passwordLen":[{"min":8,"max":64,"increment":1}],"saltLen":[{"min":128,"max":512,"increment":8}],"hmacAlg":["SHA2-224","SHA2-256","SHA2-384","SHA2-512","SHA2-512/224","SHA2-512/256","SHA3-224","SHA3-256","SHA3-384","SHA3-512"]}],"revision":"1.0"}, + + {"algorithm":"ML-KEM","mode":"keyGen","revision":"FIPS203","parameterSets":["ML-KEM-768","ML-KEM-1024"]}, + {"algorithm":"ML-KEM","mode":"encapDecap","revision":"FIPS203","parameterSets":["ML-KEM-768","ML-KEM-1024"],"functions":["encapsulation","decapsulation"]} +] diff --git a/src/crypto/internal/fips140test/acvp_test.config.json b/src/crypto/internal/fips140test/acvp_test.config.json index 49ab51d0d2a552..f62743f0c5d1aa 100644 --- a/src/crypto/internal/fips140test/acvp_test.config.json +++ b/src/crypto/internal/fips140test/acvp_test.config.json @@ -23,5 +23,7 @@ {"Wrapper": "go", "In": "vectors/HMAC-SHA3-384.bz2", "Out": "expected/HMAC-SHA3-384.bz2"}, {"Wrapper": "go", "In": "vectors/HMAC-SHA3-512.bz2", "Out": "expected/HMAC-SHA3-512.bz2"}, - {"Wrapper": "go", "In": "vectors/PBKDF.bz2", "Out": "expected/PBKDF.bz2"} + {"Wrapper": "go", "In": "vectors/PBKDF.bz2", "Out": "expected/PBKDF.bz2"}, + + {"Wrapper": "go", "In": "vectors/ML-KEM.bz2", "Out": "expected/ML-KEM.bz2"} ] \ No newline at end of file diff --git a/src/crypto/internal/fips140test/acvp_test.go b/src/crypto/internal/fips140test/acvp_test.go index 139655ecf60389..70c2b7e718ddf4 100644 --- a/src/crypto/internal/fips140test/acvp_test.go +++ b/src/crypto/internal/fips140test/acvp_test.go @@ -24,6 +24,7 @@ import ( "crypto/internal/cryptotest" "crypto/internal/fips140" "crypto/internal/fips140/hmac" + "crypto/internal/fips140/mlkem" "crypto/internal/fips140/pbkdf2" "crypto/internal/fips140/sha256" "crypto/internal/fips140/sha3" @@ -75,6 +76,8 @@ var ( // https://pages.nist.gov/ACVP/draft-fussell-acvp-mac.html#section-7 // PBKDF2 algorithm capabilities: // https://pages.nist.gov/ACVP/draft-celi-acvp-pbkdf.html#section-7.3 + // ML-KEM algorithm capabilities: + // https://pages.nist.gov/ACVP/draft-celi-acvp-ml-kem.html#section-7.3 //go:embed acvp_capabilities.json capabilitiesJson []byte @@ -118,6 +121,13 @@ var ( "HMAC-SHA3-512": cmdHmacAft(func() fips140.Hash { return sha3.New512() }), "PBKDF": cmdPbkdf(), + + "ML-KEM-768/keyGen": cmdMlKem768KeyGenAft(), + "ML-KEM-768/encap": cmdMlKem768EncapAft(), + "ML-KEM-768/decap": cmdMlKem768DecapAft(), + "ML-KEM-1024/keyGen": cmdMlKem1024KeyGenAft(), + "ML-KEM-1024/encap": cmdMlKem1024EncapAft(), + "ML-KEM-1024/decap": cmdMlKem1024DecapAft(), } ) @@ -404,14 +414,138 @@ func lookupHash(name string) (func() fips140.Hash, error) { return h, nil } +func cmdMlKem768KeyGenAft() command { + return command{ + requiredArgs: 1, // Seed + handler: func(args [][]byte) ([][]byte, error) { + seed := args[0] + + dk, err := mlkem.NewDecapsulationKey768(seed) + if err != nil { + return nil, fmt.Errorf("generating ML-KEM 768 decapsulation key: %w", err) + } + + // Important: we must return the full encoding of dk, not the seed. + return [][]byte{dk.EncapsulationKey().Bytes(), mlkem.TestingOnlyExpandedBytes768(dk)}, nil + }, + } +} + +func cmdMlKem768EncapAft() command { + return command{ + requiredArgs: 2, // Public key, entropy + handler: func(args [][]byte) ([][]byte, error) { + pk := args[0] + entropy := args[1] + + ek, err := mlkem.NewEncapsulationKey768(pk) + if err != nil { + return nil, fmt.Errorf("generating ML-KEM 768 encapsulation key: %w", err) + } + + if len(entropy) != 32 { + return nil, fmt.Errorf("wrong entropy length: got %d, want 32", len(entropy)) + } + + sharedKey, ct := ek.EncapsulateInternal((*[32]byte)(entropy[:32])) + + return [][]byte{ct, sharedKey}, nil + }, + } +} + +func cmdMlKem768DecapAft() command { + return command{ + requiredArgs: 2, // Private key, ciphertext + handler: func(args [][]byte) ([][]byte, error) { + pk := args[0] + ct := args[1] + + dk, err := mlkem.TestingOnlyNewDecapsulationKey768(pk) + if err != nil { + return nil, fmt.Errorf("generating ML-KEM 768 decapsulation key: %w", err) + } + + sharedKey, err := dk.Decapsulate(ct) + if err != nil { + return nil, fmt.Errorf("decapsulating ML-KEM 768 ciphertext: %w", err) + } + + return [][]byte{sharedKey}, nil + }, + } +} + +func cmdMlKem1024KeyGenAft() command { + return command{ + requiredArgs: 1, // Seed + handler: func(args [][]byte) ([][]byte, error) { + seed := args[0] + + dk, err := mlkem.NewDecapsulationKey1024(seed) + if err != nil { + return nil, fmt.Errorf("generating ML-KEM 1024 decapsulation key: %w", err) + } + + // Important: we must return the full encoding of dk, not the seed. + return [][]byte{dk.EncapsulationKey().Bytes(), mlkem.TestingOnlyExpandedBytes1024(dk)}, nil + }, + } +} + +func cmdMlKem1024EncapAft() command { + return command{ + requiredArgs: 2, // Public key, entropy + handler: func(args [][]byte) ([][]byte, error) { + pk := args[0] + entropy := args[1] + + ek, err := mlkem.NewEncapsulationKey1024(pk) + if err != nil { + return nil, fmt.Errorf("generating ML-KEM 1024 encapsulation key: %w", err) + } + + if len(entropy) != 32 { + return nil, fmt.Errorf("wrong entropy length: got %d, want 32", len(entropy)) + } + + sharedKey, ct := ek.EncapsulateInternal((*[32]byte)(entropy[:32])) + + return [][]byte{ct, sharedKey}, nil + }, + } +} + +func cmdMlKem1024DecapAft() command { + return command{ + requiredArgs: 2, // Private key, ciphertext + handler: func(args [][]byte) ([][]byte, error) { + pk := args[0] + ct := args[1] + + dk, err := mlkem.TestingOnlyNewDecapsulationKey1024(pk) + if err != nil { + return nil, fmt.Errorf("generating ML-KEM 1024 decapsulation key: %w", err) + } + + sharedKey, err := dk.Decapsulate(ct) + if err != nil { + return nil, fmt.Errorf("decapsulating ML-KEM 1024 ciphertext: %w", err) + } + + return [][]byte{sharedKey}, nil + }, + } +} + func TestACVP(t *testing.T) { testenv.SkipIfShortAndSlow(t) const ( bsslModule = "boringssl.googlesource.com/boringssl.git" - bsslVersion = "v0.0.0-20241015160643-2587c4974dbe" + bsslVersion = "v0.0.0-20241218033850-ca3146c56300" goAcvpModule = "github.com/cpu/go-acvp" - goAcvpVersion = "v0.0.0-20241011151719-6e0509dcb7ce" + goAcvpVersion = "v0.0.0-20250102201911-6839fc40f9f8" ) // In crypto/tls/bogo_shim_test.go the test is skipped if run on a builder with runtime.GOOS == "windows" From 19e923182e590ae6568c2c714f20f32512aeb3e3 Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Thu, 2 Jan 2025 13:27:09 -0500 Subject: [PATCH 133/397] crypto/internal/fips140test: add hmac DRBG ACVP tests Adds ACVP test coverage for the hmacDRBG algorithm based on the NIST spec: https://pages.nist.gov/ACVP/draft-vassilev-acvp-drbg.html#section-7.2 The HMAC DRBG algorithm in our fips module is a minimal implementation tailored for use for generating ECDSA nonces and so lives in crypto/internal/fips140/ecdsa. In order to be testable by crypto/internal/fips140test this changeset exports a ecdsa.TestingOnlyNewDrbg() constructor to support the ACVP use-case. All FIPS-compatible SHA2 and SHA3 digests are tested. The ACVP capability registration is customized to match the limited capabilities of our ecdsa-focused impl. Most notably: * reseedImplemented is false - we expect this impl to be invoked only once or twice per instantiation and do not support explicit reseeding. * predResistanceEnabled is false - this requires reseeding. * Per mode: * derFuncEnabled is always false - this is only used by ctrDRBG. * additionalInputLen is 0 for all modes - this is only used with preResistanceEnabled. The other capability values are chosen based on Table 4: https://pages.nist.gov/ACVP/draft-vassilev-acvp-drbg.html#section-7.4 Updates #69642 Change-Id: Ia58979d691f912e2ed739a05efb719f580fbbf89 Reviewed-on: https://go-review.googlesource.com/c/go/+/639775 Reviewed-by: Michael Pratt LUCI-TryBot-Result: Go LUCI Auto-Submit: Filippo Valsorda Reviewed-by: Dmitri Shuralyov Reviewed-by: Filippo Valsorda --- src/crypto/internal/fips140/ecdsa/hmacdrbg.go | 9 ++++ .../fips140test/acvp_capabilities.json | 13 ++++- .../fips140test/acvp_test.config.json | 4 +- src/crypto/internal/fips140test/acvp_test.go | 49 ++++++++++++++++++- 4 files changed, 72 insertions(+), 3 deletions(-) diff --git a/src/crypto/internal/fips140/ecdsa/hmacdrbg.go b/src/crypto/internal/fips140/ecdsa/hmacdrbg.go index 4f085e2801b79d..8f520911702492 100644 --- a/src/crypto/internal/fips140/ecdsa/hmacdrbg.go +++ b/src/crypto/internal/fips140/ecdsa/hmacdrbg.go @@ -116,6 +116,15 @@ func newDRBG[H fips140.Hash](hash func() H, entropy, nonce []byte, s personaliza return d } +// TestingOnlyNewDRBG creates an SP 800-90A Rev. 1 HMAC_DRBG with a plain +// personalization string. +// +// This should only be used for ACVP testing. hmacDRBG is not intended to be +// used directly. +func TestingOnlyNewDRBG(hash func() fips140.Hash, entropy, nonce []byte, s []byte) *hmacDRBG { + return newDRBG(hash, entropy, nonce, plainPersonalizationString(s)) +} + func pad000(h *hmac.HMAC, writtenSoFar int) { blockSize := h.BlockSize() if rem := writtenSoFar % blockSize; rem != 0 { diff --git a/src/crypto/internal/fips140test/acvp_capabilities.json b/src/crypto/internal/fips140test/acvp_capabilities.json index 38ce3a39c4b30f..8a4a97758cce39 100644 --- a/src/crypto/internal/fips140test/acvp_capabilities.json +++ b/src/crypto/internal/fips140test/acvp_capabilities.json @@ -26,5 +26,16 @@ {"algorithm":"PBKDF","capabilities":[{"iterationCount":[{"min":1,"max":10000,"increment":1}],"keyLen":[{"min":112,"max":4096,"increment":8}],"passwordLen":[{"min":8,"max":64,"increment":1}],"saltLen":[{"min":128,"max":512,"increment":8}],"hmacAlg":["SHA2-224","SHA2-256","SHA2-384","SHA2-512","SHA2-512/224","SHA2-512/256","SHA3-224","SHA3-256","SHA3-384","SHA3-512"]}],"revision":"1.0"}, {"algorithm":"ML-KEM","mode":"keyGen","revision":"FIPS203","parameterSets":["ML-KEM-768","ML-KEM-1024"]}, - {"algorithm":"ML-KEM","mode":"encapDecap","revision":"FIPS203","parameterSets":["ML-KEM-768","ML-KEM-1024"],"functions":["encapsulation","decapsulation"]} + {"algorithm":"ML-KEM","mode":"encapDecap","revision":"FIPS203","parameterSets":["ML-KEM-768","ML-KEM-1024"],"functions":["encapsulation","decapsulation"]}, + + {"algorithm":"hmacDRBG","revision":"1.0","predResistanceEnabled":[false],"reseedImplemented":false,"capabilities":[{"mode":"SHA2-224","derFuncEnabled":false,"entropyInputLen":[192],"nonceLen":[96],"persoStringLen":[192],"additionalInputLen":[0],"returnedBitsLen":224}]}, + {"algorithm":"hmacDRBG","revision":"1.0","predResistanceEnabled":[false],"reseedImplemented":false,"capabilities":[{"mode":"SHA2-256","derFuncEnabled":false,"entropyInputLen":[256],"nonceLen":[128],"persoStringLen":[256],"additionalInputLen":[0],"returnedBitsLen":256}]}, + {"algorithm":"hmacDRBG","revision":"1.0","predResistanceEnabled":[false],"reseedImplemented":false,"capabilities":[{"mode":"SHA2-384","derFuncEnabled":false,"entropyInputLen":[256],"nonceLen":[128],"persoStringLen":[256],"additionalInputLen":[0],"returnedBitsLen":384}]}, + {"algorithm":"hmacDRBG","revision":"1.0","predResistanceEnabled":[false],"reseedImplemented":false,"capabilities":[{"mode":"SHA2-512","derFuncEnabled":false,"entropyInputLen":[256],"nonceLen":[128],"persoStringLen":[256],"additionalInputLen":[0],"returnedBitsLen":512}]}, + {"algorithm":"hmacDRBG","revision":"1.0","predResistanceEnabled":[false],"reseedImplemented":false,"capabilities":[{"mode":"SHA2-512/224","derFuncEnabled":false,"entropyInputLen":[192],"nonceLen":[96],"persoStringLen":[192],"additionalInputLen":[0],"returnedBitsLen":224}]}, + {"algorithm":"hmacDRBG","revision":"1.0","predResistanceEnabled":[false],"reseedImplemented":false,"capabilities":[{"mode":"SHA2-512/256","derFuncEnabled":false,"entropyInputLen":[256],"nonceLen":[128],"persoStringLen":[256],"additionalInputLen":[0],"returnedBitsLen":256}]}, + {"algorithm":"hmacDRBG","revision":"1.0","predResistanceEnabled":[false],"reseedImplemented":false,"capabilities":[{"mode":"SHA3-224","derFuncEnabled":false,"entropyInputLen":[192],"nonceLen":[96],"persoStringLen":[192],"additionalInputLen":[0],"returnedBitsLen":224}]}, + {"algorithm":"hmacDRBG","revision":"1.0","predResistanceEnabled":[false],"reseedImplemented":false,"capabilities":[{"mode":"SHA3-256","derFuncEnabled":false,"entropyInputLen":[256],"nonceLen":[128],"persoStringLen":[256],"additionalInputLen":[0],"returnedBitsLen":256}]}, + {"algorithm":"hmacDRBG","revision":"1.0","predResistanceEnabled":[false],"reseedImplemented":false,"capabilities":[{"mode":"SHA3-384","derFuncEnabled":false,"entropyInputLen":[256],"nonceLen":[128],"persoStringLen":[256],"additionalInputLen":[0],"returnedBitsLen":384}]}, + {"algorithm":"hmacDRBG","revision":"1.0","predResistanceEnabled":[false],"reseedImplemented":false,"capabilities":[{"mode":"SHA3-512","derFuncEnabled":false,"entropyInputLen":[256],"nonceLen":[128],"persoStringLen":[256],"additionalInputLen":[0],"returnedBitsLen":512}]} ] diff --git a/src/crypto/internal/fips140test/acvp_test.config.json b/src/crypto/internal/fips140test/acvp_test.config.json index f62743f0c5d1aa..dc4d714f19c620 100644 --- a/src/crypto/internal/fips140test/acvp_test.config.json +++ b/src/crypto/internal/fips140test/acvp_test.config.json @@ -25,5 +25,7 @@ {"Wrapper": "go", "In": "vectors/PBKDF.bz2", "Out": "expected/PBKDF.bz2"}, - {"Wrapper": "go", "In": "vectors/ML-KEM.bz2", "Out": "expected/ML-KEM.bz2"} + {"Wrapper": "go", "In": "vectors/ML-KEM.bz2", "Out": "expected/ML-KEM.bz2"}, + + {"Wrapper": "go", "In": "vectors/hmacDRBG.bz2", "Out": "expected/hmacDRBG.bz2"} ] \ No newline at end of file diff --git a/src/crypto/internal/fips140test/acvp_test.go b/src/crypto/internal/fips140test/acvp_test.go index 70c2b7e718ddf4..8dedb9a79159b5 100644 --- a/src/crypto/internal/fips140test/acvp_test.go +++ b/src/crypto/internal/fips140test/acvp_test.go @@ -23,6 +23,7 @@ import ( "bytes" "crypto/internal/cryptotest" "crypto/internal/fips140" + "crypto/internal/fips140/ecdsa" "crypto/internal/fips140/hmac" "crypto/internal/fips140/mlkem" "crypto/internal/fips140/pbkdf2" @@ -78,6 +79,8 @@ var ( // https://pages.nist.gov/ACVP/draft-celi-acvp-pbkdf.html#section-7.3 // ML-KEM algorithm capabilities: // https://pages.nist.gov/ACVP/draft-celi-acvp-ml-kem.html#section-7.3 + // HMAC DRBG algorithm capabilities: + // https://pages.nist.gov/ACVP/draft-vassilev-acvp-drbg.html#section-7.2 //go:embed acvp_capabilities.json capabilitiesJson []byte @@ -128,6 +131,17 @@ var ( "ML-KEM-1024/keyGen": cmdMlKem1024KeyGenAft(), "ML-KEM-1024/encap": cmdMlKem1024EncapAft(), "ML-KEM-1024/decap": cmdMlKem1024DecapAft(), + + "hmacDRBG/SHA2-224": cmdHmacDrbgAft(func() fips140.Hash { return sha256.New224() }), + "hmacDRBG/SHA2-256": cmdHmacDrbgAft(func() fips140.Hash { return sha256.New() }), + "hmacDRBG/SHA2-384": cmdHmacDrbgAft(func() fips140.Hash { return sha512.New384() }), + "hmacDRBG/SHA2-512": cmdHmacDrbgAft(func() fips140.Hash { return sha512.New() }), + "hmacDRBG/SHA2-512/224": cmdHmacDrbgAft(func() fips140.Hash { return sha512.New512_224() }), + "hmacDRBG/SHA2-512/256": cmdHmacDrbgAft(func() fips140.Hash { return sha512.New512_256() }), + "hmacDRBG/SHA3-224": cmdHmacDrbgAft(func() fips140.Hash { return sha3.New224() }), + "hmacDRBG/SHA3-256": cmdHmacDrbgAft(func() fips140.Hash { return sha3.New256() }), + "hmacDRBG/SHA3-384": cmdHmacDrbgAft(func() fips140.Hash { return sha3.New384() }), + "hmacDRBG/SHA3-512": cmdHmacDrbgAft(func() fips140.Hash { return sha3.New512() }), } ) @@ -538,12 +552,45 @@ func cmdMlKem1024DecapAft() command { } } +func cmdHmacDrbgAft(h func() fips140.Hash) command { + return command{ + requiredArgs: 6, // Output length, entropy, personalization, ad1, ad2, nonce + handler: func(args [][]byte) ([][]byte, error) { + outLen := binary.LittleEndian.Uint32(args[0]) + entropy := args[1] + personalization := args[2] + ad1 := args[3] + ad2 := args[4] + nonce := args[5] + + // Our capabilities describe no additional data support. + if len(ad1) != 0 || len(ad2) != 0 { + return nil, errors.New("additional data not supported") + } + + // Our capabilities describe no prediction resistance (requires reseed) and no reseed. + // So the test procedure is: + // * Instantiate DRBG + // * Generate but don't output + // * Generate output + // * Uninstantiate + // See Table 7 in draft-vassilev-acvp-drbg + out := make([]byte, outLen) + drbg := ecdsa.TestingOnlyNewDRBG(h, entropy, nonce, personalization) + drbg.Generate(out) + drbg.Generate(out) + + return [][]byte{out}, nil + }, + } +} + func TestACVP(t *testing.T) { testenv.SkipIfShortAndSlow(t) const ( bsslModule = "boringssl.googlesource.com/boringssl.git" - bsslVersion = "v0.0.0-20241218033850-ca3146c56300" + bsslVersion = "v0.0.0-20250108043213-d3f61eeacbf7" goAcvpModule = "github.com/cpu/go-acvp" goAcvpVersion = "v0.0.0-20250102201911-6839fc40f9f8" ) From 44a6f817ea0fbeb3ba4aa398794c4e80dba13b1e Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Fri, 10 Jan 2025 17:33:26 -0800 Subject: [PATCH 134/397] cmd/compile: fix write barrier coalescing We can't coalesce a non-WB store with a subsequent Move, as the result of the store might be the source of the move. There's a simple codegen test. Not sure how we might do a real test, as all the repro's I've come up with are very expensive and unreliable. Fixes #71228 Change-Id: If18bf181a266b9b90964e2591cd2e61a7168371c Reviewed-on: https://go-review.googlesource.com/c/go/+/642197 Reviewed-by: Keith Randall LUCI-TryBot-Result: Go LUCI Reviewed-by: David Chase --- src/cmd/compile/internal/ssa/writebarrier.go | 15 ++++++++++++ test/codegen/writebarrier.go | 25 ++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/src/cmd/compile/internal/ssa/writebarrier.go b/src/cmd/compile/internal/ssa/writebarrier.go index 1caccb7c18d3c4..71acefbf8ae526 100644 --- a/src/cmd/compile/internal/ssa/writebarrier.go +++ b/src/cmd/compile/internal/ssa/writebarrier.go @@ -252,6 +252,7 @@ func writebarrier(f *Func) { var start, end int var nonPtrStores int values := b.Values + hasMove := false FindSeq: for i := len(values) - 1; i >= 0; i-- { w := values[i] @@ -263,6 +264,9 @@ func writebarrier(f *Func) { end = i + 1 } nonPtrStores = 0 + if w.Op == OpMoveWB { + hasMove = true + } case OpVarDef, OpVarLive: continue case OpStore: @@ -273,6 +277,17 @@ func writebarrier(f *Func) { if nonPtrStores > 2 { break FindSeq } + if hasMove { + // We need to ensure that this store happens + // before we issue a wbMove, as the wbMove might + // use the result of this store as its source. + // Even though this store is not write-barrier + // eligible, it might nevertheless be the store + // of a pointer to the stack, which is then the + // source of the move. + // See issue 71228. + break FindSeq + } default: if last == nil { continue diff --git a/test/codegen/writebarrier.go b/test/codegen/writebarrier.go index e125973e7cf09f..e2b1399399b020 100644 --- a/test/codegen/writebarrier.go +++ b/test/codegen/writebarrier.go @@ -63,3 +63,28 @@ func trickyWriteNil(p *int, q **int) { *q = p } } + +type S struct { + a, b string + c *int +} + +var g1, g2 *int + +func issue71228(dst *S, ptr *int) { + // Make sure that the non-write-barrier write. + // "sp.c = ptr" happens before the large write + // barrier "*dst = *sp". We approximate testing + // that by ensuring that two global variable write + // barriers aren't combined. + _ = *dst + var s S + sp := &s + //amd64:`.*runtime[.]gcWriteBarrier1` + g1 = nil + sp.c = ptr // outside of any write barrier + //amd64:`.*runtime[.]gcWriteBarrier1` + g2 = nil + //amd64:`.*runtime[.]wbMove` + *dst = *sp +} From 7bb192a1c56e2961b3eeffb8250615e395c903d4 Mon Sep 17 00:00:00 2001 From: Joe Tsai Date: Fri, 10 Jan 2025 11:49:07 -0800 Subject: [PATCH 135/397] encoding/json: always check resulting Go value for unmarshaling Even if an error occurs during unmarshal, check the resulting Go value. The documented API specifies no guarantees on how much of a Go value will be populated when an error occurs and the "json" package is technically not bounded by the Go compatibility agreement to ensure this behavior never changes. However, there is still value in running checks for what exactly what is partially mutated in the event of an error even if this is not guaranteed behavior. Change-Id: I6e923a31f77768a14c4adfb0d37dbeee5807a4a2 Reviewed-on: https://go-review.googlesource.com/c/go/+/642275 Auto-Submit: Joseph Tsai LUCI-TryBot-Result: Go LUCI Reviewed-by: Michael Knyszek Reviewed-by: Ian Lance Taylor --- src/encoding/json/decode_test.go | 75 +++++++++++++++++++++++++++++--- 1 file changed, 68 insertions(+), 7 deletions(-) diff --git a/src/encoding/json/decode_test.go b/src/encoding/json/decode_test.go index 278d1e94fafa3a..d08d9a4e0aaf93 100644 --- a/src/encoding/json/decode_test.go +++ b/src/encoding/json/decode_test.go @@ -458,10 +458,10 @@ var unmarshalTests = []struct { // Z has a "-" tag. {CaseName: Name(""), in: `{"Y": 1, "Z": 2}`, ptr: new(T), out: T{Y: 1}}, - {CaseName: Name(""), in: `{"Y": 1, "Z": 2}`, ptr: new(T), err: fmt.Errorf("json: unknown field \"Z\""), disallowUnknownFields: true}, + {CaseName: Name(""), in: `{"Y": 1, "Z": 2}`, ptr: new(T), out: T{Y: 1}, err: fmt.Errorf("json: unknown field \"Z\""), disallowUnknownFields: true}, {CaseName: Name(""), in: `{"alpha": "abc", "alphabet": "xyz"}`, ptr: new(U), out: U{Alphabet: "abc"}}, - {CaseName: Name(""), in: `{"alpha": "abc", "alphabet": "xyz"}`, ptr: new(U), err: fmt.Errorf("json: unknown field \"alphabet\""), disallowUnknownFields: true}, + {CaseName: Name(""), in: `{"alpha": "abc", "alphabet": "xyz"}`, ptr: new(U), out: U{Alphabet: "abc"}, err: fmt.Errorf("json: unknown field \"alphabet\""), disallowUnknownFields: true}, {CaseName: Name(""), in: `{"alpha": "abc"}`, ptr: new(U), out: U{Alphabet: "abc"}}, {CaseName: Name(""), in: `{"alphabet": "xyz"}`, ptr: new(U), out: U{}}, {CaseName: Name(""), in: `{"alphabet": "xyz"}`, ptr: new(U), err: fmt.Errorf("json: unknown field \"alphabet\""), disallowUnknownFields: true}, @@ -471,7 +471,7 @@ var unmarshalTests = []struct { {CaseName: Name(""), in: `[1, 2, 3+]`, err: &SyntaxError{"invalid character '+' after array element", 9}}, {CaseName: Name(""), in: `{"X":12x}`, err: &SyntaxError{"invalid character 'x' after object key:value pair", 8}, useNumber: true}, {CaseName: Name(""), in: `[2, 3`, err: &SyntaxError{msg: "unexpected end of JSON input", Offset: 5}}, - {CaseName: Name(""), in: `{"F3": -}`, ptr: new(V), out: V{F3: Number("-")}, err: &SyntaxError{msg: "invalid character '}' in numeric literal", Offset: 9}}, + {CaseName: Name(""), in: `{"F3": -}`, ptr: new(V), err: &SyntaxError{msg: "invalid character '}' in numeric literal", Offset: 9}}, // raw value errors {CaseName: Name(""), in: "\x01 42", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}}, @@ -563,6 +563,7 @@ var unmarshalTests = []struct { CaseName: Name(""), in: `{"2":4}`, ptr: new(map[u8marshal]int), + out: map[u8marshal]int{}, err: errMissingU8Prefix, }, @@ -571,36 +572,42 @@ var unmarshalTests = []struct { CaseName: Name(""), in: `{"abc":"abc"}`, ptr: new(map[int]string), + out: map[int]string{}, err: &UnmarshalTypeError{Value: "number abc", Type: reflect.TypeFor[int](), Offset: 2}, }, { CaseName: Name(""), in: `{"256":"abc"}`, ptr: new(map[uint8]string), + out: map[uint8]string{}, err: &UnmarshalTypeError{Value: "number 256", Type: reflect.TypeFor[uint8](), Offset: 2}, }, { CaseName: Name(""), in: `{"128":"abc"}`, ptr: new(map[int8]string), + out: map[int8]string{}, err: &UnmarshalTypeError{Value: "number 128", Type: reflect.TypeFor[int8](), Offset: 2}, }, { CaseName: Name(""), in: `{"-1":"abc"}`, ptr: new(map[uint8]string), + out: map[uint8]string{}, err: &UnmarshalTypeError{Value: "number -1", Type: reflect.TypeFor[uint8](), Offset: 2}, }, { CaseName: Name(""), in: `{"F":{"a":2,"3":4}}`, ptr: new(map[string]map[int]int), + out: map[string]map[int]int{"F": {3: 4}}, err: &UnmarshalTypeError{Value: "number a", Type: reflect.TypeFor[int](), Offset: 7}, }, { CaseName: Name(""), in: `{"F":{"a":2,"3":4}}`, ptr: new(map[string]map[uint]int), + out: map[string]map[uint]int{"F": {3: 4}}, err: &UnmarshalTypeError{Value: "number a", Type: reflect.TypeFor[uint](), Offset: 7}, }, @@ -682,6 +689,7 @@ var unmarshalTests = []struct { CaseName: Name(""), in: `{"X": 1,"Y":2}`, ptr: new(S5), + out: S5{S8: S8{S9{Y: 2}}}, err: fmt.Errorf("json: unknown field \"X\""), disallowUnknownFields: true, }, @@ -695,6 +703,7 @@ var unmarshalTests = []struct { CaseName: Name(""), in: `{"X": 1,"Y":2}`, ptr: new(S10), + out: S10{S13: S13{S8{S9{Y: 2}}}}, err: fmt.Errorf("json: unknown field \"X\""), disallowUnknownFields: true, }, @@ -889,6 +898,7 @@ var unmarshalTests = []struct { CaseName: Name(""), in: `{"V": {"F4": {}, "F2": "hello"}}`, ptr: new(VOuter), + out: VOuter{V: V{F4: &VOuter{}}}, err: &UnmarshalTypeError{ Value: "string", Struct: "V", @@ -902,6 +912,7 @@ var unmarshalTests = []struct { CaseName: Name(""), in: `{"Level1a": "hello"}`, ptr: new(Top), + out: Top{Embed0a: &Embed0a{}}, err: &UnmarshalTypeError{ Value: "string", Struct: "Top", @@ -947,7 +958,29 @@ var unmarshalTests = []struct { "Q": 18, "extra": true }`, - ptr: new(Top), + ptr: new(Top), + out: Top{ + Level0: 1, + Embed0: Embed0{ + Level1b: 2, + Level1c: 3, + }, + Embed0a: &Embed0a{Level1a: 5, Level1b: 6}, + Embed0b: &Embed0b{Level1a: 8, Level1b: 9, Level1c: 10, Level1d: 11, Level1e: 12}, + Loop: Loop{ + Loop1: 13, + Loop2: 14, + Loop: nil, + }, + Embed0p: Embed0p{ + Point: image.Point{ + X: 15, + Y: 16, + }, + }, + Embed0q: Embed0q{Point: Point{Z: 17}}, + embed: embed{Q: 18}, + }, err: fmt.Errorf("json: unknown field \"extra\""), disallowUnknownFields: true, }, @@ -975,7 +1008,29 @@ var unmarshalTests = []struct { "Z": 17, "Q": 18 }`, - ptr: new(Top), + ptr: new(Top), + out: Top{ + Level0: 1, + Embed0: Embed0{ + Level1b: 2, + Level1c: 3, + }, + Embed0a: &Embed0a{Level1a: 5, Level1b: 6}, + Embed0b: &Embed0b{Level1a: 8, Level1b: 9, Level1c: 10, Level1d: 11, Level1e: 12}, + Loop: Loop{ + Loop1: 13, + Loop2: 14, + Loop: nil, + }, + Embed0p: Embed0p{ + Point: image.Point{ + X: 15, + Y: 16, + }, + }, + Embed0q: Embed0q{Point: Point{Z: 17}}, + embed: embed{Q: 18}, + }, err: fmt.Errorf("json: unknown field \"extra\""), disallowUnknownFields: true, }, @@ -985,12 +1040,14 @@ var unmarshalTests = []struct { CaseName: Name(""), in: `{"data":{"test1": "bob", "test2": 123}}`, ptr: new(mapStringToStringData), + out: mapStringToStringData{map[string]string{"test1": "bob", "test2": ""}}, err: &UnmarshalTypeError{Value: "number", Type: reflect.TypeFor[string](), Offset: 37, Struct: "mapStringToStringData", Field: "data"}, }, { CaseName: Name(""), in: `{"data":{"test1": 123, "test2": "bob"}}`, ptr: new(mapStringToStringData), + out: mapStringToStringData{Data: map[string]string{"test1": "", "test2": "bob"}}, err: &UnmarshalTypeError{Value: "number", Type: reflect.TypeFor[string](), Offset: 21, Struct: "mapStringToStringData", Field: "data"}, }, @@ -1024,6 +1081,7 @@ var unmarshalTests = []struct { CaseName: Name(""), in: `{"Ts": [{"Y": 1}, {"Y": 2}, {"Y": "bad-type"}]}`, ptr: new(PP), + out: PP{Ts: []T{{Y: 1}, {Y: 2}, {Y: 0}}}, err: &UnmarshalTypeError{ Value: "string", Struct: "T", @@ -1066,6 +1124,7 @@ var unmarshalTests = []struct { CaseName: Name(""), in: `{"A":"invalid"}`, ptr: new(map[string]Number), + out: map[string]Number{}, err: fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", `"invalid"`), }, @@ -1280,8 +1339,10 @@ func TestUnmarshal(t *testing.T) { } if err := dec.Decode(v.Interface()); !equalError(err, tt.err) { t.Fatalf("%s: Decode error:\n\tgot: %#v\n\twant: %#v", tt.Where, err, tt.err) - } else if err != nil { - return + } else if err != nil && tt.out == nil { + // Initialize tt.out during an error where there are no mutations, + // so the output is just the zero value of the input type. + tt.out = reflect.Zero(v.Elem().Type()).Interface() } if got := v.Elem().Interface(); !reflect.DeepEqual(got, tt.out) { gotJSON, _ := Marshal(got) From 47a56b2b6d2cca56384810027964968667b86fdc Mon Sep 17 00:00:00 2001 From: Joe Tsai Date: Sat, 11 Jan 2025 12:48:33 -0800 Subject: [PATCH 136/397] encoding/json: add cases to TestUnmarshal for fatal syntactic errors The presence of a syntax error in the input immediately unmarshaling before unmarshaling into the underlying value. Otherwise, semantic errors are generally lazily reported and allow unmarshaling to continue on. Change-Id: Icf1cfc684e415312d9c8bf739c396ede15299d7d Reviewed-on: https://go-review.googlesource.com/c/go/+/642295 LUCI-TryBot-Result: Go LUCI Reviewed-by: Ian Lance Taylor Auto-Submit: Joseph Tsai Reviewed-by: Michael Knyszek --- src/encoding/json/decode_test.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/encoding/json/decode_test.go b/src/encoding/json/decode_test.go index d08d9a4e0aaf93..3905a054cedc26 100644 --- a/src/encoding/json/decode_test.go +++ b/src/encoding/json/decode_test.go @@ -1170,6 +1170,23 @@ var unmarshalTests = []struct { N Number `json:",string"` }{"5"}, }, + + // Verify that syntactic errors are immediately fatal, + // while semantic errors are lazily reported + // (i.e., allow processing to continue). + { + CaseName: Name(""), + in: `[1,2,true,4,5}`, + ptr: new([]int), + err: &SyntaxError{msg: "invalid character '}' after array element", Offset: 14}, + }, + { + CaseName: Name(""), + in: `[1,2,true,4,5]`, + ptr: new([]int), + out: []int{1, 2, 0, 4, 5}, + err: &UnmarshalTypeError{Value: "bool", Type: reflect.TypeFor[int](), Offset: 9}, + }, } func TestMarshal(t *testing.T) { From c53307c3fdf1126eb6cdb1f09f4f9b83759be705 Mon Sep 17 00:00:00 2001 From: Oleksandr Redko Date: Fri, 10 Jan 2025 17:00:24 +0200 Subject: [PATCH 137/397] spec: fix grammar issue Change-Id: If4d3b3965762c8979d304a82493c9eb1068ee13c Reviewed-on: https://go-review.googlesource.com/c/go/+/642037 Reviewed-by: Robert Griesemer TryBot-Bypass: Robert Griesemer Reviewed-by: Michael Knyszek Auto-Submit: Robert Griesemer --- doc/go_spec.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/go_spec.html b/doc/go_spec.html index ab90c420fd359c..db5fba45a53378 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -8514,7 +8514,7 @@

    Package unsafe

    The functions Alignof and Sizeof take an expression x of any type and return the alignment or size, respectively, of a hypothetical variable v -as if v was declared via var v = x. +as if v were declared via var v = x.

    The function Offsetof takes a (possibly parenthesized) selector From 17ed2159583289d77c994d479c24f7e7c2837332 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 9 Jan 2025 15:01:03 -0800 Subject: [PATCH 138/397] go/types, types2: don't panic when instantiating generic alias with wrong number of type arguments The existing code assumed the type argument count check in Checker.instance couldn't fail for generic alias types (matching the code for generic signatures), but it actually can. Adjust the code accordingly and document that the result of Checker.instance may be invalid. Review all call sites of Checker.instance and make sure we handle the failure case, or document the code accordingly (in the case of generic signatures). When reporting an type argument count error, use the alias name rather than the alias string representation to match the error we get for a non-alias type. While at it, update the manual.go template for ease of use. Fixes #71198. Change-Id: I6d19ec6418440e9b49574a2d7dd9825e0af6c2fc Reviewed-on: https://go-review.googlesource.com/c/go/+/641857 Reviewed-by: Robert Findley Reviewed-by: Robert Griesemer LUCI-TryBot-Result: Go LUCI Auto-Submit: Robert Griesemer --- src/cmd/compile/internal/types2/call.go | 3 +++ src/cmd/compile/internal/types2/instantiate.go | 11 ++++++++--- .../compile/internal/types2/testdata/manual.go | 2 +- src/cmd/compile/internal/types2/typexpr.go | 11 ++++++++--- src/go/types/call.go | 3 +++ src/go/types/instantiate.go | 11 ++++++++--- src/go/types/testdata/manual.go | 2 +- src/go/types/typexpr.go | 11 ++++++++--- .../types/testdata/fixedbugs/issue71198.go | 16 ++++++++++++++++ 9 files changed, 56 insertions(+), 14 deletions(-) create mode 100644 src/internal/types/testdata/fixedbugs/issue71198.go diff --git a/src/cmd/compile/internal/types2/call.go b/src/cmd/compile/internal/types2/call.go index ae2ab5f9849bc9..897c846d8ff98d 100644 --- a/src/cmd/compile/internal/types2/call.go +++ b/src/cmd/compile/internal/types2/call.go @@ -142,6 +142,9 @@ func (check *Checker) instantiateSignature(pos syntax.Pos, expr syntax.Expr, typ }() } + // For signatures, Checker.instance will always succeed because the type argument + // count is correct at this point (see assertion above); hence the type assertion + // to *Signature will always succeed. inst := check.instance(pos, typ, targs, nil, check.context()).(*Signature) assert(inst.TypeParams().Len() == 0) // signature is not generic anymore check.recordInstance(expr, targs, inst) diff --git a/src/cmd/compile/internal/types2/instantiate.go b/src/cmd/compile/internal/types2/instantiate.go index e51cf18de67fd6..03c490a3866df2 100644 --- a/src/cmd/compile/internal/types2/instantiate.go +++ b/src/cmd/compile/internal/types2/instantiate.go @@ -74,7 +74,8 @@ func Instantiate(ctxt *Context, orig Type, targs []Type, validate bool) (Type, e // instance instantiates the given original (generic) function or type with the // provided type arguments and returns the resulting instance. If an identical // instance exists already in the given contexts, it returns that instance, -// otherwise it creates a new one. +// otherwise it creates a new one. If there is an error (such as wrong number +// of type arguments), the result is Typ[Invalid]. // // If expanding is non-nil, it is the Named instance type currently being // expanded. If ctxt is non-nil, it is the context associated with the current @@ -133,9 +134,13 @@ func (check *Checker) instance(pos syntax.Pos, orig genericType, targs []Type, e assert(expanding == nil) // Alias instances cannot be reached from Named types } + // verify type parameter count (see go.dev/issue/71198 for a test case) tparams := orig.TypeParams() - // TODO(gri) investigate if this is needed (type argument and parameter count seem to be correct here) - if !check.validateTArgLen(pos, orig.String(), tparams.Len(), len(targs)) { + if !check.validateTArgLen(pos, orig.obj.Name(), tparams.Len(), len(targs)) { + // TODO(gri) Consider returning a valid alias instance with invalid + // underlying (aliased) type to match behavior of *Named + // types. Then this function will never return an invalid + // result. return Typ[Invalid] } if tparams.Len() == 0 { diff --git a/src/cmd/compile/internal/types2/testdata/manual.go b/src/cmd/compile/internal/types2/testdata/manual.go index d8f312f61d58c5..825ab50f92de49 100644 --- a/src/cmd/compile/internal/types2/testdata/manual.go +++ b/src/cmd/compile/internal/types2/testdata/manual.go @@ -1,4 +1,4 @@ -// Copyright 2024 The Go Authors. All rights reserved. +// Copyright 2025 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. diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go index d955654fc9af37..fa6a6f622af7cf 100644 --- a/src/cmd/compile/internal/types2/typexpr.go +++ b/src/cmd/compile/internal/types2/typexpr.go @@ -475,9 +475,14 @@ func (check *Checker) instantiatedType(x syntax.Expr, xlist []syntax.Expr, def * } // create instance - // The instance is not generic anymore as it has type arguments, but it still - // satisfies the genericType interface because it has type parameters, too. - inst := check.instance(x.Pos(), gtyp, targs, nil, check.context()).(genericType) + // The instance is not generic anymore as it has type arguments, but unless + // instantiation failed, it still satisfies the genericType interface because + // it has type parameters, too. + ityp := check.instance(x.Pos(), gtyp, targs, nil, check.context()) + inst, _ := ityp.(genericType) + if inst == nil { + return Typ[Invalid] + } // For Named types, orig.tparams may not be set up, so we need to do expansion later. check.later(func() { diff --git a/src/go/types/call.go b/src/go/types/call.go index 200068b1760054..4e8dfc0d6bdc9d 100644 --- a/src/go/types/call.go +++ b/src/go/types/call.go @@ -143,6 +143,9 @@ func (check *Checker) instantiateSignature(pos token.Pos, expr ast.Expr, typ *Si }() } + // For signatures, Checker.instance will always succeed because the type argument + // count is correct at this point (see assertion above); hence the type assertion + // to *Signature will always succeed. inst := check.instance(pos, typ, targs, nil, check.context()).(*Signature) assert(inst.TypeParams().Len() == 0) // signature is not generic anymore check.recordInstance(expr, targs, inst) diff --git a/src/go/types/instantiate.go b/src/go/types/instantiate.go index 48eef7ca76c187..4b36312f96e75e 100644 --- a/src/go/types/instantiate.go +++ b/src/go/types/instantiate.go @@ -77,7 +77,8 @@ func Instantiate(ctxt *Context, orig Type, targs []Type, validate bool) (Type, e // instance instantiates the given original (generic) function or type with the // provided type arguments and returns the resulting instance. If an identical // instance exists already in the given contexts, it returns that instance, -// otherwise it creates a new one. +// otherwise it creates a new one. If there is an error (such as wrong number +// of type arguments), the result is Typ[Invalid]. // // If expanding is non-nil, it is the Named instance type currently being // expanded. If ctxt is non-nil, it is the context associated with the current @@ -136,9 +137,13 @@ func (check *Checker) instance(pos token.Pos, orig genericType, targs []Type, ex assert(expanding == nil) // Alias instances cannot be reached from Named types } + // verify type parameter count (see go.dev/issue/71198 for a test case) tparams := orig.TypeParams() - // TODO(gri) investigate if this is needed (type argument and parameter count seem to be correct here) - if !check.validateTArgLen(pos, orig.String(), tparams.Len(), len(targs)) { + if !check.validateTArgLen(pos, orig.obj.Name(), tparams.Len(), len(targs)) { + // TODO(gri) Consider returning a valid alias instance with invalid + // underlying (aliased) type to match behavior of *Named + // types. Then this function will never return an invalid + // result. return Typ[Invalid] } if tparams.Len() == 0 { diff --git a/src/go/types/testdata/manual.go b/src/go/types/testdata/manual.go index d8f312f61d58c5..825ab50f92de49 100644 --- a/src/go/types/testdata/manual.go +++ b/src/go/types/testdata/manual.go @@ -1,4 +1,4 @@ -// Copyright 2024 The Go Authors. All rights reserved. +// Copyright 2025 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. diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index 5bcbc2d1d3b114..e560f2c131bd37 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -471,9 +471,14 @@ func (check *Checker) instantiatedType(ix *indexedExpr, def *TypeName) (res Type } // create instance - // The instance is not generic anymore as it has type arguments, but it still - // satisfies the genericType interface because it has type parameters, too. - inst := check.instance(ix.Pos(), gtyp, targs, nil, check.context()).(genericType) + // The instance is not generic anymore as it has type arguments, but unless + // instantiation failed, it still satisfies the genericType interface because + // it has type parameters, too. + ityp := check.instance(ix.Pos(), gtyp, targs, nil, check.context()) + inst, _ := ityp.(genericType) + if inst == nil { + return Typ[Invalid] + } // For Named types, orig.tparams may not be set up, so we need to do expansion later. check.later(func() { diff --git a/src/internal/types/testdata/fixedbugs/issue71198.go b/src/internal/types/testdata/fixedbugs/issue71198.go new file mode 100644 index 00000000000000..479f8e2b0c4e64 --- /dev/null +++ b/src/internal/types/testdata/fixedbugs/issue71198.go @@ -0,0 +1,16 @@ +// -gotypesalias=1 + +// Copyright 2025 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +type A[_ any] = any + +// This must not panic; also the error message must match the style for non-alias types, below. +func _[_ A /* ERROR "too many type arguments for type A: have 2, want 1" */ [int, string]]() {} + +type T[_ any] any + +func _[_ T /* ERROR "too many type arguments for type T: have 2, want 1" */ [int, string]]() {} From de9fdc7b7154a1ddd73cb44292cdd65f4f56029a Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 13 Jan 2025 09:56:13 -0800 Subject: [PATCH 139/397] syscall/js: adjust comments to that gofmt does not change them Change-Id: Ic410375987c0f376d0a975e5a6284de10f08b741 Reviewed-on: https://go-review.googlesource.com/c/go/+/642495 Auto-Submit: Ian Lance Taylor Reviewed-by: Alan Donovan Reviewed-by: Michael Knyszek LUCI-TryBot-Result: Go LUCI --- src/syscall/js/js.go | 48 ++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/syscall/js/js.go b/src/syscall/js/js.go index 74c02cdbe64ada..bbf3de199b4b82 100644 --- a/src/syscall/js/js.go +++ b/src/syscall/js/js.go @@ -212,8 +212,8 @@ func ValueOf(x any) Value { // stringVal copies string x to Javascript and returns a ref. // -// (noescape): This is safe because no references are maintained to the -// Go string x after the syscall returns. +// Using go:noescape is safe because no references are maintained to the +// Go string x after the syscall returns. // //go:wasmimport gojs syscall/js.stringVal //go:noescape @@ -302,8 +302,8 @@ func (v Value) Get(p string) Value { // valueGet returns a ref to JavaScript property p of ref v. // -// (noescape): This is safe because no references are maintained to the -// Go string p after the syscall returns. +// Using go:noescape is safe because no references are maintained to the +// Go string p after the syscall returns. // //go:wasmimport gojs syscall/js.valueGet //go:noescape @@ -323,8 +323,8 @@ func (v Value) Set(p string, x any) { // valueSet sets property p of ref v to ref x. // -// (noescape): This is safe because no references are maintained to the -// Go string p after the syscall returns. +// Using go:noescape is safe because no references are maintained to the +// Go string p after the syscall returns. // //go:wasmimport gojs syscall/js.valueSet //go:noescape @@ -342,8 +342,8 @@ func (v Value) Delete(p string) { // valueDelete deletes the JavaScript property p of ref v. // -// (noescape): This is safe because no references are maintained to the -// Go string p after the syscall returns. +// Using go:noescape is safe because no references are maintained to the +// Go string p after the syscall returns. // //go:wasmimport gojs syscall/js.valueDelete //go:noescape @@ -447,10 +447,10 @@ func (v Value) Call(m string, args ...any) Value { // valueCall does a JavaScript call to the method name m of ref v with the given arguments. // -// (noescape): This is safe because no references are maintained to the -// Go string m after the syscall returns. Additionally, the args slice -// is only used temporarily to collect the JavaScript objects for -// the JavaScript method invocation. +// Using go:noescape is safe because no references are maintained to the +// Go string m after the syscall returns. Additionally, the args slice +// is only used temporarily to collect the JavaScript objects for +// the JavaScript method invocation. // //go:wasmimport gojs syscall/js.valueCall //go:nosplit @@ -477,9 +477,9 @@ func (v Value) Invoke(args ...any) Value { // valueInvoke does a JavaScript call to value v with the given arguments. // -// (noescape): This is safe because the args slice is only used temporarily -// to collect the JavaScript objects for the JavaScript method -// invocation. +// Using go:noescape is safe because the args slice is only used temporarily +// to collect the JavaScript objects for the JavaScript method +// invocation. // //go:wasmimport gojs syscall/js.valueInvoke //go:noescape @@ -505,8 +505,8 @@ func (v Value) New(args ...any) Value { // valueNew uses JavaScript's "new" operator with value v as a constructor and the given arguments. // -// (noescape): This is safe because the args slice is only used temporarily -// to collect the JavaScript objects for the constructor execution. +// Using go:noescape is safe because the args slice is only used temporarily +// to collect the JavaScript objects for the constructor execution. // //go:wasmimport gojs syscall/js.valueNew //go:noescape @@ -614,8 +614,8 @@ func valuePrepareString(v ref) (ref, int) // valueLoadString loads string data located at ref v into byte slice b. // -// (noescape): This is safe because the byte slice is only used as a destination -// for storing the string data and references to it are not maintained. +// Using go:noescape is safe because the byte slice is only used as a destination +// for storing the string data and references to it are not maintained. // //go:wasmimport gojs syscall/js.valueLoadString //go:noescape @@ -658,8 +658,8 @@ func CopyBytesToGo(dst []byte, src Value) int { // copyBytesToGo copies bytes from src to dst. // -// (noescape): This is safe because the dst byte slice is only used as a dst -// copy buffer and no references to it are maintained. +// Using go:noescape is safe because the dst byte slice is only used as a dst +// copy buffer and no references to it are maintained. // //go:wasmimport gojs syscall/js.copyBytesToGo //go:noescape @@ -677,10 +677,10 @@ func CopyBytesToJS(dst Value, src []byte) int { return n } -// copyBytesToJs copies bytes from src to dst. +// copyBytesToJS copies bytes from src to dst. // -// (noescape): This is safe because the src byte slice is only used as a src -// copy buffer and no references to it are maintained. +// Using go:noescape is safe because the src byte slice is only used as a src +// copy buffer and no references to it are maintained. // //go:wasmimport gojs syscall/js.copyBytesToJS //go:noescape From 6da16013ba4444e0d71540f68279f0283a92d05d Mon Sep 17 00:00:00 2001 From: Sean Liao Date: Sat, 28 Dec 2024 11:19:23 -0500 Subject: [PATCH 140/397] cmd/go: check go version when parsing go.mod fails Fixes #70979 Change-Id: I6597fe178eed34702eea6cba4eec5174c9203458 Reviewed-on: https://go-review.googlesource.com/c/go/+/639115 LUCI-TryBot-Result: Go LUCI Reviewed-by: Michael Matloob Reviewed-by: Michael Knyszek --- src/cmd/go/internal/modload/modfile.go | 11 +++++++++++ src/cmd/go/testdata/script/mod_unknown_block.txt | 11 +++++++++++ 2 files changed, 22 insertions(+) create mode 100644 src/cmd/go/testdata/script/mod_unknown_block.txt diff --git a/src/cmd/go/internal/modload/modfile.go b/src/cmd/go/internal/modload/modfile.go index 94d2f5bd666cab..4687deae686c89 100644 --- a/src/cmd/go/internal/modload/modfile.go +++ b/src/cmd/go/internal/modload/modfile.go @@ -44,6 +44,17 @@ func ReadModFile(gomod string, fix modfile.VersionFixer) (data []byte, f *modfil f, err = modfile.Parse(gomod, data, fix) if err != nil { + f, laxErr := modfile.ParseLax(gomod, data, fix) + if laxErr == nil { + if f.Go != nil && gover.Compare(f.Go.Version, gover.Local()) > 0 { + toolchain := "" + if f.Toolchain != nil { + toolchain = f.Toolchain.Name + } + return nil, nil, &gover.TooNewError{What: base.ShortPath(gomod), GoVersion: f.Go.Version, Toolchain: toolchain} + } + } + // Errors returned by modfile.Parse begin with file:line. return nil, nil, fmt.Errorf("errors parsing %s:\n%w", base.ShortPath(gomod), shortPathErrorList(err)) } diff --git a/src/cmd/go/testdata/script/mod_unknown_block.txt b/src/cmd/go/testdata/script/mod_unknown_block.txt new file mode 100644 index 00000000000000..071269bb8db0ea --- /dev/null +++ b/src/cmd/go/testdata/script/mod_unknown_block.txt @@ -0,0 +1,11 @@ +env GOTOOLCHAIN=local +! go list . +stderr 'go: go.mod requires go >= 1.999' + + +-- go.mod -- +module example.com + +go 1.999 + +anewblock foo From c83f2ca4b3964917adc3b06f661785cc6b53792d Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 14 Jan 2025 06:58:32 -0800 Subject: [PATCH 141/397] cmd/dist: ignore packages with no Go files in BenchmarkAll This case recently started happening on the builders. The synctest experiment was recently enabled for some targets (CL 642422). This caused the list of standard packages to include testing/synctest. However, BenchmarkAll tests for all configurations; some did not include testing/synctest. That caused the test to crash. Change-Id: Icade10af147c2e2bcbac25bf744919083db3e70f Reviewed-on: https://go-review.googlesource.com/c/go/+/642397 Auto-Submit: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Reviewed-by: Ian Lance Taylor Reviewed-by: Russ Cox --- src/cmd/api/api_test.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/cmd/api/api_test.go b/src/cmd/api/api_test.go index 78482333330bd8..cac624af8a6530 100644 --- a/src/cmd/api/api_test.go +++ b/src/cmd/api/api_test.go @@ -201,7 +201,10 @@ func BenchmarkAll(b *testing.B) { for _, context := range contexts { w := NewWalker(context, filepath.Join(testenv.GOROOT(b), "src")) for _, name := range w.stdPackages { - pkg, _ := w.import_(name) + pkg, err := w.import_(name) + if _, nogo := err.(*build.NoGoError); nogo { + continue + } w.export(pkg) } w.Features() From befc43655b6d93f0be883222fbb3fde5768892c1 Mon Sep 17 00:00:00 2001 From: cuishuang Date: Tue, 14 Jan 2025 01:11:22 +0800 Subject: [PATCH 142/397] testing/fstest: fix function name and comment Change-Id: I17bc68a2e3a96d0dc3d9ddcad40149df37fc4839 Reviewed-on: https://go-review.googlesource.com/c/go/+/642198 Reviewed-by: Ian Lance Taylor Reviewed-by: Damien Neil LUCI-TryBot-Result: Go LUCI Auto-Submit: Ian Lance Taylor Auto-Submit: Damien Neil --- src/testing/fstest/testfs.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/testing/fstest/testfs.go b/src/testing/fstest/testfs.go index 2917a303b20adf..affdfa64291ba8 100644 --- a/src/testing/fstest/testfs.go +++ b/src/testing/fstest/testfs.go @@ -570,7 +570,7 @@ func (t *fsTester) checkFileRead(file, desc string, data1, data2 []byte) { } } -// checkBadPath checks that various invalid forms of file's name cannot be opened using t.fsys.Open. +// checkOpen validates file opening behavior by attempting to open and then close the given file path. func (t *fsTester) checkOpen(file string) { t.checkBadPath(file, "Open", func(file string) error { f, err := t.fsys.Open(file) From c5e205e928bd4b70c90698b5ca1dd583a8036864 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Mon, 13 Jan 2025 16:21:29 -0800 Subject: [PATCH 143/397] internal/runtime/maps: re-enable some tests Re-enable tests for stack-allocated maps and fast map accessors. Those are implemented now. Update #54766 Change-Id: I8c019702bd9fb077b2fe3f7c78e8e9e10d2263a6 Reviewed-on: https://go-review.googlesource.com/c/go/+/642376 LUCI-TryBot-Result: Go LUCI Reviewed-by: Keith Randall Reviewed-by: Michael Pratt Auto-Submit: Keith Randall --- src/internal/runtime/maps/map_swiss_test.go | 1 - src/runtime/map_test.go | 4 ---- test/codegen/maps.go | 5 ----- 3 files changed, 10 deletions(-) diff --git a/src/internal/runtime/maps/map_swiss_test.go b/src/internal/runtime/maps/map_swiss_test.go index 4e02f3e66076b6..6da006413ac61d 100644 --- a/src/internal/runtime/maps/map_swiss_test.go +++ b/src/internal/runtime/maps/map_swiss_test.go @@ -50,7 +50,6 @@ func TestTableGroupCount(t *testing.T) { var testCases = []struct { n int // n is the number of map elements escape mapCase // expected values for escaping map - // TODO(go.dev/issue/54766): implement stack allocated maps }{ { n: -(1 << 30), diff --git a/src/runtime/map_test.go b/src/runtime/map_test.go index e3c092bef90562..c522c44a4ef476 100644 --- a/src/runtime/map_test.go +++ b/src/runtime/map_test.go @@ -674,10 +674,6 @@ func TestIgnoreBogusMapHint(t *testing.T) { var testNonEscapingMapVariable int = 8 func TestNonEscapingMap(t *testing.T) { - if goexperiment.SwissMap { - t.Skip("TODO(go.dev/issue/54766): implement stack allocated maps") - } - n := testing.AllocsPerRun(1000, func() { m := map[int]int{} m[0] = 0 diff --git a/test/codegen/maps.go b/test/codegen/maps.go index d7cf6534ad907a..25505799e9351d 100644 --- a/test/codegen/maps.go +++ b/test/codegen/maps.go @@ -4,11 +4,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// TODO(#54766): Temporarily disable for swissmap, which have fast variants -// disabled. This test expects fast variants. -// -//go:build !goexperiment.swissmap - package codegen // This file contains code generation tests related to the handling of From 4fa61d6f9c9c7c3a5e74472f1cfb9c12eed1a368 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 14 Jan 2025 08:22:08 -0500 Subject: [PATCH 144/397] cmd/api: report error in test instead of crashing https://ci.chromium.org/ui/inv/build-8725798219051312433/test-results?sortby=&groupby= shows a mysterious failure with this stack: === RUN BenchmarkAll BenchmarkAll panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x7c497f] goroutine 20 gp=0xc000004000 m=7 mp=0xc000182808 [running]: panic({0x81c5e0?, 0xabc6b0?}) /home/swarming/.swarming/w/ir/x/w/goroot/src/runtime/panic.go:806 +0x168 fp=0xc00c7ffce0 sp=0xc00c7ffc30 pc=0x4ad4c8 runtime.panicmem(...) /home/swarming/.swarming/w/ir/x/w/goroot/src/runtime/panic.go:262 runtime.sigpanic() /home/swarming/.swarming/w/ir/x/w/goroot/src/runtime/signal_unix.go:925 +0x359 fp=0xc00c7ffd40 sp=0xc00c7ffce0 pc=0x4af6d9 cmd/api.(*Walker).export(0xc000034100, 0x0) /home/swarming/.swarming/w/ir/x/w/goroot/src/cmd/api/main_test.go:193 +0x3f fp=0xc00c7ffe08 sp=0xc00c7ffd40 pc=0x7c497f cmd/api.BenchmarkAll(0xc000214288) /home/swarming/.swarming/w/ir/x/w/goroot/src/cmd/api/api_test.go:205 +0x207 fp=0xc00c7ffeb0 sp=0xc00c7ffe08 pc=0x7c1c07 testing.(*B).runN(0xc000214288, 0x1) /home/swarming/.swarming/w/ir/x/w/goroot/src/testing/benchmark.go:202 +0x291 fp=0xc00c7fff78 sp=0xc00c7ffeb0 pc=0x57e611 testing.(*B).run1.func1() /home/swarming/.swarming/w/ir/x/w/goroot/src/testing/benchmark.go:224 +0x7c fp=0xc00c7fffe0 sp=0xc00c7fff78 pc=0x57f11c runtime.goexit({}) /home/swarming/.swarming/w/ir/x/w/goroot/src/runtime/asm_amd64.s:1700 +0x1 fp=0xc00c7fffe8 sp=0xc00c7fffe0 pc=0x4b4a61 created by testing.(*B).run1 in goroutine 1 /home/swarming/.swarming/w/ir/x/w/goroot/src/testing/benchmark.go:217 +0x173 So import_ must have returned an error, making pkg nil. Show that error. Also do the same at the other calls to import_. Change-Id: Ie782571c4bda3334a86b303f61969cf1cc7d3c32 Reviewed-on: https://go-review.googlesource.com/c/go/+/642438 Auto-Submit: Dmitri Shuralyov Reviewed-by: Dmitri Shuralyov LUCI-TryBot-Result: Go LUCI Reviewed-by: Dmitri Shuralyov --- src/cmd/api/api_test.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/cmd/api/api_test.go b/src/cmd/api/api_test.go index cac624af8a6530..32da68982bce45 100644 --- a/src/cmd/api/api_test.go +++ b/src/cmd/api/api_test.go @@ -57,7 +57,10 @@ func TestGolden(t *testing.T) { // TODO(gri) remove extra pkg directory eventually goldenFile := filepath.Join("testdata", "src", "pkg", fi.Name(), "golden.txt") w := NewWalker(nil, "testdata/src/pkg") - pkg, _ := w.import_(fi.Name()) + pkg, err := w.import_(fi.Name()) + if err != nil { + t.Fatalf("import %s: %v", fi.Name(), err) + } w.export(pkg) if *updateGolden { @@ -205,6 +208,9 @@ func BenchmarkAll(b *testing.B) { if _, nogo := err.(*build.NoGoError); nogo { continue } + if err != nil { + b.Fatalf("import %s (%s-%s): %v", name, context.GOOS, context.GOARCH, err) + } w.export(pkg) } w.Features() @@ -242,8 +248,7 @@ func TestIssue21181(t *testing.T) { w := NewWalker(context, "testdata/src/issue21181") pkg, err := w.import_("p") if err != nil { - t.Fatalf("%s: (%s-%s) %s %v", err, context.GOOS, context.GOARCH, - pkg.Name(), w.imported) + t.Fatalf("import %s (%s-%s): %v", "p", context.GOOS, context.GOARCH, err) } w.export(pkg) } From bd80d8956f3062d2b2bff2d7da6b879dfa909f12 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 13 Jan 2025 23:00:14 -0500 Subject: [PATCH 145/397] cmd/go/internal/modfetch: do not trust server to send all tags in shallow fetch Newer git versions (at least git 2.47.1) do not send all the matching tags for a shallow fetch of a specific hash anymore. The go command assumes that git servers do this. Since that assumption is broken, use the local copy of the remote refs list to augment the tags sent by the server. This makes the cmd/go/internal/modfetch tests pass again with newer git. Fixes #71261. Change-Id: I9fd4f3fd7beeb68a522938599f8f3acd887d0b26 Reviewed-on: https://go-review.googlesource.com/c/go/+/642437 Reviewed-by: Michael Matloob LUCI-TryBot-Result: Go LUCI Auto-Submit: Russ Cox --- src/cmd/go/internal/modfetch/codehost/git.go | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/cmd/go/internal/modfetch/codehost/git.go b/src/cmd/go/internal/modfetch/codehost/git.go index 50a4526eb3ca64..dfb366788967f7 100644 --- a/src/cmd/go/internal/modfetch/codehost/git.go +++ b/src/cmd/go/internal/modfetch/codehost/git.go @@ -649,7 +649,21 @@ func (r *gitRepo) statLocal(ctx context.Context, version, rev string) (*RevInfo, } } } - sort.Strings(info.Tags) + + // Git 2.47.1 does not send the tags during shallow clone anymore + // (perhaps the exact version that changed behavior is an earlier one), + // so we have to also add tags from the refs list we fetched with ls-remote. + if refs, err := r.loadRefs(ctx); err == nil { + for ref, h := range refs { + if h == hash { + if tag, found := strings.CutPrefix(ref, "refs/tags/"); found { + info.Tags = append(info.Tags, tag) + } + } + } + } + slices.Sort(info.Tags) + info.Tags = slices.Compact(info.Tags) // Used hash as info.Version above. // Use caller's suggested version if it appears in the tag list From 368a9ec99834652ca3f7d8fe24862a7581e12358 Mon Sep 17 00:00:00 2001 From: Joe Tsai Date: Tue, 14 Jan 2025 12:43:27 -0800 Subject: [PATCH 146/397] encoding/json: cleanup tests Perform minor cleanups in tests to improve printout of diffs and/or follow modern coding style. This reduces the amount of diffs between v1 and the v2 prototype. Change-Id: I019bb9642e2135f2fa3eac6abfa6df91c397aa82 Reviewed-on: https://go-review.googlesource.com/c/go/+/642257 Reviewed-by: Damien Neil Auto-Submit: Joseph Tsai LUCI-TryBot-Result: Go LUCI Reviewed-by: Ian Lance Taylor --- src/encoding/json/decode_test.go | 4 ++-- src/encoding/json/stream_test.go | 10 +++++----- src/encoding/json/tags_test.go | 4 +--- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/encoding/json/decode_test.go b/src/encoding/json/decode_test.go index 3905a054cedc26..8aad11b8bfbce2 100644 --- a/src/encoding/json/decode_test.go +++ b/src/encoding/json/decode_test.go @@ -1321,7 +1321,7 @@ func TestUnmarshal(t *testing.T) { var scan scanner if err := checkValid(in, &scan); err != nil { if !equalError(err, tt.err) { - t.Fatalf("%s: checkValid error: %#v", tt.Where, err) + t.Fatalf("%s: checkValid error:\n\tgot %#v\n\twant %#v", tt.Where, err, tt.err) } } if tt.ptr == nil { @@ -1355,7 +1355,7 @@ func TestUnmarshal(t *testing.T) { dec.DisallowUnknownFields() } if err := dec.Decode(v.Interface()); !equalError(err, tt.err) { - t.Fatalf("%s: Decode error:\n\tgot: %#v\n\twant: %#v", tt.Where, err, tt.err) + t.Fatalf("%s: Decode error:\n\tgot: %v\n\twant: %v\n\n\tgot: %#v\n\twant: %#v", tt.Where, err, tt.err, err, tt.err) } else if err != nil && tt.out == nil { // Initialize tt.out during an error where there are no mutations, // so the output is just the zero value of the input type. diff --git a/src/encoding/json/stream_test.go b/src/encoding/json/stream_test.go index 32ede8cc7e6271..46f9407c881c36 100644 --- a/src/encoding/json/stream_test.go +++ b/src/encoding/json/stream_test.go @@ -79,9 +79,9 @@ func TestEncoder(t *testing.T) { t.Fatalf("#%d.%d Encode error: %v", i, j, err) } } - if have, want := buf.String(), nlines(streamEncoded, i); have != want { + if got, want := buf.String(), nlines(streamEncoded, i); got != want { t.Errorf("encoding %d items: mismatch:", i) - diff(t, []byte(have), []byte(want)) + diff(t, []byte(got), []byte(want)) break } } @@ -148,9 +148,9 @@ func TestEncoderIndent(t *testing.T) { for _, v := range streamTest { enc.Encode(v) } - if have, want := buf.String(), streamEncodedIndent; have != want { - t.Error("Encode mismatch:") - diff(t, []byte(have), []byte(want)) + if got, want := buf.String(), streamEncodedIndent; got != want { + t.Errorf("Encode mismatch:\ngot:\n%s\n\nwant:\n%s", got, want) + diff(t, []byte(got), []byte(want)) } } diff --git a/src/encoding/json/tags_test.go b/src/encoding/json/tags_test.go index 1d2323dcee6014..eb43ff553095c0 100644 --- a/src/encoding/json/tags_test.go +++ b/src/encoding/json/tags_test.go @@ -4,9 +4,7 @@ package json -import ( - "testing" -) +import "testing" func TestTagParsing(t *testing.T) { name, opts := parseTag("field,foobar,foo") From 6783377295e0878aa3ad821eefe3d7879064df6d Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Fri, 22 Nov 2024 12:34:11 -0800 Subject: [PATCH 147/397] net/http: persist header stripping across repeated redirects When an HTTP redirect changes the host of a request, we drop sensitive headers such as Authorization from the redirected request. Fix a bug where a chain of redirects could result in sensitive headers being sent to the wrong host: 1. request to a.tld with Authorization header 2. a.tld redirects to b.tld 3. request to b.tld with no Authorization header 4. b.tld redirects to b.tld 3. request to b.tld with Authorization header restored Thanks to Kyle Seely for reporting this issue. For #70530 Fixes CVE-2024-45336 Change-Id: Ia58a2e10d33d6b0cc7220935e771450e5c34de72 Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/1641 Reviewed-by: Roland Shoemaker Reviewed-by: Tatiana Bradley Commit-Queue: Roland Shoemaker Reviewed-on: https://go-review.googlesource.com/c/go/+/643095 LUCI-TryBot-Result: Go LUCI Reviewed-by: Michael Pratt Auto-Submit: Michael Knyszek --- src/net/http/client.go | 65 ++++++------ src/net/http/client_test.go | 111 +++++++++++++++------ src/net/http/internal/testcert/testcert.go | 84 ++++++++-------- 3 files changed, 154 insertions(+), 106 deletions(-) diff --git a/src/net/http/client.go b/src/net/http/client.go index fda7815436c25c..9231f63e65b134 100644 --- a/src/net/http/client.go +++ b/src/net/http/client.go @@ -610,8 +610,9 @@ func (c *Client) do(req *Request) (retres *Response, reterr error) { reqBodyClosed = false // have we closed the current req.Body? // Redirect behavior: - redirectMethod string - includeBody = true + redirectMethod string + includeBody = true + stripSensitiveHeaders = false ) uerr := func(err error) error { // the body may have been closed already by c.send() @@ -678,7 +679,12 @@ func (c *Client) do(req *Request) (retres *Response, reterr error) { // in case the user set Referer on their first request. // If they really want to override, they can do it in // their CheckRedirect func. - copyHeaders(req) + if !stripSensitiveHeaders && reqs[0].URL.Host != req.URL.Host { + if !shouldCopyHeaderOnRedirect(reqs[0].URL, req.URL) { + stripSensitiveHeaders = true + } + } + copyHeaders(req, stripSensitiveHeaders) // Add the Referer header from the most recent // request URL to the new one, if it's not https->http: @@ -746,7 +752,7 @@ func (c *Client) do(req *Request) (retres *Response, reterr error) { // makeHeadersCopier makes a function that copies headers from the // initial Request, ireq. For every redirect, this function must be called // so that it can copy headers into the upcoming Request. -func (c *Client) makeHeadersCopier(ireq *Request) func(*Request) { +func (c *Client) makeHeadersCopier(ireq *Request) func(req *Request, stripSensitiveHeaders bool) { // The headers to copy are from the very initial request. // We use a closured callback to keep a reference to these original headers. var ( @@ -760,8 +766,7 @@ func (c *Client) makeHeadersCopier(ireq *Request) func(*Request) { } } - preq := ireq // The previous request - return func(req *Request) { + return func(req *Request, stripSensitiveHeaders bool) { // If Jar is present and there was some initial cookies provided // via the request header, then we may need to alter the initial // cookies as we follow redirects since each redirect may end up @@ -798,12 +803,15 @@ func (c *Client) makeHeadersCopier(ireq *Request) func(*Request) { // Copy the initial request's Header values // (at least the safe ones). for k, vv := range ireqhdr { - if shouldCopyHeaderOnRedirect(k, preq.URL, req.URL) { + sensitive := false + switch CanonicalHeaderKey(k) { + case "Authorization", "Www-Authenticate", "Cookie", "Cookie2": + sensitive = true + } + if !(sensitive && stripSensitiveHeaders) { req.Header[k] = vv } } - - preq = req // Update previous Request with the current request } } @@ -979,28 +987,23 @@ func (b *cancelTimerBody) Close() error { return err } -func shouldCopyHeaderOnRedirect(headerKey string, initial, dest *url.URL) bool { - switch CanonicalHeaderKey(headerKey) { - case "Authorization", "Www-Authenticate", "Cookie", "Cookie2": - // Permit sending auth/cookie headers from "foo.com" - // to "sub.foo.com". - - // Note that we don't send all cookies to subdomains - // automatically. This function is only used for - // Cookies set explicitly on the initial outgoing - // client request. Cookies automatically added via the - // CookieJar mechanism continue to follow each - // cookie's scope as set by Set-Cookie. But for - // outgoing requests with the Cookie header set - // directly, we don't know their scope, so we assume - // it's for *.domain.com. - - ihost := idnaASCIIFromURL(initial) - dhost := idnaASCIIFromURL(dest) - return isDomainOrSubdomain(dhost, ihost) - } - // All other headers are copied: - return true +func shouldCopyHeaderOnRedirect(initial, dest *url.URL) bool { + // Permit sending auth/cookie headers from "foo.com" + // to "sub.foo.com". + + // Note that we don't send all cookies to subdomains + // automatically. This function is only used for + // Cookies set explicitly on the initial outgoing + // client request. Cookies automatically added via the + // CookieJar mechanism continue to follow each + // cookie's scope as set by Set-Cookie. But for + // outgoing requests with the Cookie header set + // directly, we don't know their scope, so we assume + // it's for *.domain.com. + + ihost := idnaASCIIFromURL(initial) + dhost := idnaASCIIFromURL(dest) + return isDomainOrSubdomain(dhost, ihost) } // isDomainOrSubdomain reports whether sub is a subdomain (or exact diff --git a/src/net/http/client_test.go b/src/net/http/client_test.go index 429b8f1d2cd556..1ce9539528c668 100644 --- a/src/net/http/client_test.go +++ b/src/net/http/client_test.go @@ -1536,6 +1536,55 @@ func testClientCopyHeadersOnRedirect(t *testing.T, mode testMode) { } } +// Issue #70530: Once we strip a header on a redirect to a different host, +// the header should stay stripped across any further redirects. +func TestClientStripHeadersOnRepeatedRedirect(t *testing.T) { + run(t, testClientStripHeadersOnRepeatedRedirect) +} +func testClientStripHeadersOnRepeatedRedirect(t *testing.T, mode testMode) { + var proto string + ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) { + if r.Host+r.URL.Path != "a.example.com/" { + if h := r.Header.Get("Authorization"); h != "" { + t.Errorf("on request to %v%v, Authorization=%q, want no header", r.Host, r.URL.Path, h) + } + } + // Follow a chain of redirects from a to b and back to a. + // The Authorization header is stripped on the first redirect to b, + // and stays stripped even if we're sent back to a. + switch r.Host + r.URL.Path { + case "a.example.com/": + Redirect(w, r, proto+"://b.example.com/", StatusFound) + case "b.example.com/": + Redirect(w, r, proto+"://b.example.com/redirect", StatusFound) + case "b.example.com/redirect": + Redirect(w, r, proto+"://a.example.com/redirect", StatusFound) + case "a.example.com/redirect": + w.Header().Set("X-Done", "true") + default: + t.Errorf("unexpected request to %v", r.URL) + } + })).ts + proto, _, _ = strings.Cut(ts.URL, ":") + + c := ts.Client() + c.Transport.(*Transport).Dial = func(_ string, _ string) (net.Conn, error) { + return net.Dial("tcp", ts.Listener.Addr().String()) + } + + req, _ := NewRequest("GET", proto+"://a.example.com/", nil) + req.Header.Add("Cookie", "foo=bar") + req.Header.Add("Authorization", "secretpassword") + res, err := c.Do(req) + if err != nil { + t.Fatal(err) + } + defer res.Body.Close() + if res.Header.Get("X-Done") != "true" { + t.Fatalf("response missing expected header: X-Done=true") + } +} + // Issue 22233: copy host when Client follows a relative redirect. func TestClientCopyHostOnRedirect(t *testing.T) { run(t, testClientCopyHostOnRedirect) } func testClientCopyHostOnRedirect(t *testing.T, mode testMode) { @@ -1702,43 +1751,39 @@ func testClientAltersCookiesOnRedirect(t *testing.T, mode testMode) { // Part of Issue 4800 func TestShouldCopyHeaderOnRedirect(t *testing.T) { tests := []struct { - header string initialURL string destURL string want bool }{ - {"User-Agent", "http://foo.com/", "http://bar.com/", true}, - {"X-Foo", "http://foo.com/", "http://bar.com/", true}, - // Sensitive headers: - {"cookie", "http://foo.com/", "http://bar.com/", false}, - {"cookie2", "http://foo.com/", "http://bar.com/", false}, - {"authorization", "http://foo.com/", "http://bar.com/", false}, - {"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}, + {"http://foo.com/", "http://bar.com/", false}, + {"http://foo.com/", "http://bar.com/", false}, + {"http://foo.com/", "http://bar.com/", false}, + {"http://foo.com/", "https://foo.com/", true}, + {"http://foo.com:1234/", "http://foo.com:4321/", true}, + {"http://foo.com/", "http://bar.com/", false}, + {"http://foo.com/", "http://[::1%25.foo.com]/", false}, // But subdomains should work: - {"www-authenticate", "http://foo.com/", "http://foo.com/", true}, - {"www-authenticate", "http://foo.com/", "http://sub.foo.com/", true}, - {"www-authenticate", "http://foo.com/", "http://notfoo.com/", false}, - {"www-authenticate", "http://foo.com/", "https://foo.com/", true}, - {"www-authenticate", "http://foo.com:80/", "http://foo.com/", true}, - {"www-authenticate", "http://foo.com:80/", "http://sub.foo.com/", true}, - {"www-authenticate", "http://foo.com:443/", "https://foo.com/", true}, - {"www-authenticate", "http://foo.com:443/", "https://sub.foo.com/", true}, - {"www-authenticate", "http://foo.com:1234/", "http://foo.com/", true}, - - {"authorization", "http://foo.com/", "http://foo.com/", true}, - {"authorization", "http://foo.com/", "http://sub.foo.com/", true}, - {"authorization", "http://foo.com/", "http://notfoo.com/", false}, - {"authorization", "http://foo.com/", "https://foo.com/", true}, - {"authorization", "http://foo.com:80/", "http://foo.com/", true}, - {"authorization", "http://foo.com:80/", "http://sub.foo.com/", true}, - {"authorization", "http://foo.com:443/", "https://foo.com/", true}, - {"authorization", "http://foo.com:443/", "https://sub.foo.com/", true}, - {"authorization", "http://foo.com:1234/", "http://foo.com/", true}, + {"http://foo.com/", "http://foo.com/", true}, + {"http://foo.com/", "http://sub.foo.com/", true}, + {"http://foo.com/", "http://notfoo.com/", false}, + {"http://foo.com/", "https://foo.com/", true}, + {"http://foo.com:80/", "http://foo.com/", true}, + {"http://foo.com:80/", "http://sub.foo.com/", true}, + {"http://foo.com:443/", "https://foo.com/", true}, + {"http://foo.com:443/", "https://sub.foo.com/", true}, + {"http://foo.com:1234/", "http://foo.com/", true}, + + {"http://foo.com/", "http://foo.com/", true}, + {"http://foo.com/", "http://sub.foo.com/", true}, + {"http://foo.com/", "http://notfoo.com/", false}, + {"http://foo.com/", "https://foo.com/", true}, + {"http://foo.com:80/", "http://foo.com/", true}, + {"http://foo.com:80/", "http://sub.foo.com/", true}, + {"http://foo.com:443/", "https://foo.com/", true}, + {"http://foo.com:443/", "https://sub.foo.com/", true}, + {"http://foo.com:1234/", "http://foo.com/", true}, } for i, tt := range tests { u0, err := url.Parse(tt.initialURL) @@ -1751,10 +1796,10 @@ func TestShouldCopyHeaderOnRedirect(t *testing.T) { t.Errorf("%d. dest URL %q parse error: %v", i, tt.destURL, err) continue } - got := Export_shouldCopyHeaderOnRedirect(tt.header, u0, u1) + got := Export_shouldCopyHeaderOnRedirect(u0, u1) if got != tt.want { - t.Errorf("%d. shouldCopyHeaderOnRedirect(%q, %q => %q) = %v; want %v", - i, tt.header, tt.initialURL, tt.destURL, got, tt.want) + t.Errorf("%d. shouldCopyHeaderOnRedirect(%q => %q) = %v; want %v", + i, tt.initialURL, tt.destURL, got, tt.want) } } } diff --git a/src/net/http/internal/testcert/testcert.go b/src/net/http/internal/testcert/testcert.go index d510e791d617cb..78ce42e2282679 100644 --- a/src/net/http/internal/testcert/testcert.go +++ b/src/net/http/internal/testcert/testcert.go @@ -10,56 +10,56 @@ import "strings" // LocalhostCert is a PEM-encoded TLS cert with SAN IPs // "127.0.0.1" and "[::1]", expiring at Jan 29 16:00:00 2084 GMT. // generated from src/crypto/tls: -// go run generate_cert.go --rsa-bits 2048 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h +// go run generate_cert.go --rsa-bits 2048 --host 127.0.0.1,::1,example.com,*.example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h var LocalhostCert = []byte(`-----BEGIN CERTIFICATE----- -MIIDOTCCAiGgAwIBAgIQSRJrEpBGFc7tNb1fb5pKFzANBgkqhkiG9w0BAQsFADAS +MIIDSDCCAjCgAwIBAgIQEP/md970HysdBTpuzDOf0DANBgkqhkiG9w0BAQsFADAS MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEA6Gba5tHV1dAKouAaXO3/ebDUU4rvwCUg/CNaJ2PT5xLD4N1Vcb8r -bFSW2HXKq+MPfVdwIKR/1DczEoAGf/JWQTW7EgzlXrCd3rlajEX2D73faWJekD0U -aUgz5vtrTXZ90BQL7WvRICd7FlEZ6FPOcPlumiyNmzUqtwGhO+9ad1W5BqJaRI6P -YfouNkwR6Na4TzSj5BrqUfP0FwDizKSJ0XXmh8g8G9mtwxOSN3Ru1QFc61Xyeluk -POGKBV/q6RBNklTNe0gI8usUMlYyoC7ytppNMW7X2vodAelSu25jgx2anj9fDVZu -h7AXF5+4nJS4AAt0n1lNY7nGSsdZas8PbQIDAQABo4GIMIGFMA4GA1UdDwEB/wQE +MIIBCgKCAQEAxcl69ROJdxjN+MJZnbFrYxyQooADCsJ6VDkuMyNQIix/Hk15Nk/u +FyBX1Me++aEpGmY3RIY4fUvELqT/srvAHsTXwVVSttMcY8pcAFmXSqo3x4MuUTG/ +jCX3Vftj0r3EM5M8ImY1rzA/jqTTLJg00rD+DmuDABcqQvoXw/RV8w1yTRi5BPoH +DFD/AWTt/YgMvk1l2Yq/xI8VbMUIpjBoGXxWsSevQ5i2s1mk9/yZzu0Ysp1tTlzD +qOPa4ysFjBitdXiwfxjxtv5nXqOCP5rheKO0sWLk0fetMp1OV5JSJMAJw6c2ZMkl +U2WMqAEpRjdE/vHfIuNg+yGaRRqI07NZRQIDAQABo4GXMIGUMA4GA1UdDwEB/wQE AwICpDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud -DgQWBBStsdjh3/JCXXYlQryOrL4Sh7BW5TAuBgNVHREEJzAlggtleGFtcGxlLmNv -bYcEfwAAAYcQAAAAAAAAAAAAAAAAAAAAATANBgkqhkiG9w0BAQsFAAOCAQEAxWGI -5NhpF3nwwy/4yB4i/CwwSpLrWUa70NyhvprUBC50PxiXav1TeDzwzLx/o5HyNwsv -cxv3HdkLW59i/0SlJSrNnWdfZ19oTcS+6PtLoVyISgtyN6DpkKpdG1cOkW3Cy2P2 -+tK/tKHRP1Y/Ra0RiDpOAmqn0gCOFGz8+lqDIor/T7MTpibL3IxqWfPrvfVRHL3B -grw/ZQTTIVjjh4JBSW3WyWgNo/ikC1lrVxzl4iPUGptxT36Cr7Zk2Bsg0XqwbOvK -5d+NTDREkSnUbie4GeutujmX3Dsx88UiV6UY/4lHJa6I5leHUNOHahRbpbWeOfs/ -WkBKOclmOV2xlTVuPw== +DgQWBBQR5QIzmacmw78ZI1C4MXw7Q0wJ1jA9BgNVHREENjA0ggtleGFtcGxlLmNv +bYINKi5leGFtcGxlLmNvbYcEfwAAAYcQAAAAAAAAAAAAAAAAAAAAATANBgkqhkiG +9w0BAQsFAAOCAQEACrRNgiioUDzxQftd0fwOa6iRRcPampZRDtuaF68yNHoNWbOu +LUwc05eOWxRq3iABGSk2xg+FXM3DDeW4HhAhCFptq7jbVZ+4Jj6HeJG9mYRatAxR +Y/dEpa0D0EHhDxxVg6UzKOXB355n0IetGE/aWvyTV9SiDs6QsaC57Q9qq1/mitx5 +2GFBoapol9L5FxCc77bztzK8CpLujkBi25Vk6GAFbl27opLfpyxkM+rX/T6MXCPO +6/YBacNZ7ff1/57Etg4i5mNA6ubCpuc4Gi9oYqCNNohftr2lkJr7REdDR6OW0lsL +rF7r4gUnKeC7mYIH1zypY7laskopiLFAfe96Kg== -----END CERTIFICATE-----`) // LocalhostKey is the private key for LocalhostCert. var LocalhostKey = []byte(testingKey(`-----BEGIN RSA TESTING KEY----- -MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDoZtrm0dXV0Aqi -4Bpc7f95sNRTiu/AJSD8I1onY9PnEsPg3VVxvytsVJbYdcqr4w99V3AgpH/UNzMS -gAZ/8lZBNbsSDOVesJ3euVqMRfYPvd9pYl6QPRRpSDPm+2tNdn3QFAvta9EgJ3sW -URnoU85w+W6aLI2bNSq3AaE771p3VbkGolpEjo9h+i42TBHo1rhPNKPkGupR8/QX -AOLMpInRdeaHyDwb2a3DE5I3dG7VAVzrVfJ6W6Q84YoFX+rpEE2SVM17SAjy6xQy -VjKgLvK2mk0xbtfa+h0B6VK7bmODHZqeP18NVm6HsBcXn7iclLgAC3SfWU1jucZK -x1lqzw9tAgMBAAECggEABWzxS1Y2wckblnXY57Z+sl6YdmLV+gxj2r8Qib7g4ZIk -lIlWR1OJNfw7kU4eryib4fc6nOh6O4AWZyYqAK6tqNQSS/eVG0LQTLTTEldHyVJL -dvBe+MsUQOj4nTndZW+QvFzbcm2D8lY5n2nBSxU5ypVoKZ1EqQzytFcLZpTN7d89 -EPj0qDyrV4NZlWAwL1AygCwnlwhMQjXEalVF1ylXwU3QzyZ/6MgvF6d3SSUlh+sq -XefuyigXw484cQQgbzopv6niMOmGP3of+yV4JQqUSb3IDmmT68XjGd2Dkxl4iPki -6ZwXf3CCi+c+i/zVEcufgZ3SLf8D99kUGE7v7fZ6AQKBgQD1ZX3RAla9hIhxCf+O -3D+I1j2LMrdjAh0ZKKqwMR4JnHX3mjQI6LwqIctPWTU8wYFECSh9klEclSdCa64s -uI/GNpcqPXejd0cAAdqHEEeG5sHMDt0oFSurL4lyud0GtZvwlzLuwEweuDtvT9cJ -Wfvl86uyO36IW8JdvUprYDctrQKBgQDycZ697qutBieZlGkHpnYWUAeImVA878sJ -w44NuXHvMxBPz+lbJGAg8Cn8fcxNAPqHIraK+kx3po8cZGQywKHUWsxi23ozHoxo -+bGqeQb9U661TnfdDspIXia+xilZt3mm5BPzOUuRqlh4Y9SOBpSWRmEhyw76w4ZP -OPxjWYAgwQKBgA/FehSYxeJgRjSdo+MWnK66tjHgDJE8bYpUZsP0JC4R9DL5oiaA -brd2fI6Y+SbyeNBallObt8LSgzdtnEAbjIH8uDJqyOmknNePRvAvR6mP4xyuR+Bv -m+Lgp0DMWTw5J9CKpydZDItc49T/mJ5tPhdFVd+am0NAQnmr1MCZ6nHxAoGABS3Y -LkaC9FdFUUqSU8+Chkd/YbOkuyiENdkvl6t2e52jo5DVc1T7mLiIrRQi4SI8N9bN -/3oJWCT+uaSLX2ouCtNFunblzWHBrhxnZzTeqVq4SLc8aESAnbslKL4i8/+vYZlN -s8xtiNcSvL+lMsOBORSXzpj/4Ot8WwTkn1qyGgECgYBKNTypzAHeLE6yVadFp3nQ -Ckq9yzvP/ib05rvgbvrne00YeOxqJ9gtTrzgh7koqJyX1L4NwdkEza4ilDWpucn0 -xiUZS4SoaJq6ZvcBYS62Yr1t8n09iG47YL8ibgtmH3L+svaotvpVxVK+d7BLevA/ -ZboOWVe3icTy64BT3OQhmg== +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDFyXr1E4l3GM34 +wlmdsWtjHJCigAMKwnpUOS4zI1AiLH8eTXk2T+4XIFfUx775oSkaZjdEhjh9S8Qu +pP+yu8AexNfBVVK20xxjylwAWZdKqjfHgy5RMb+MJfdV+2PSvcQzkzwiZjWvMD+O +pNMsmDTSsP4Oa4MAFypC+hfD9FXzDXJNGLkE+gcMUP8BZO39iAy+TWXZir/EjxVs +xQimMGgZfFaxJ69DmLazWaT3/JnO7RiynW1OXMOo49rjKwWMGK11eLB/GPG2/mde +o4I/muF4o7SxYuTR960ynU5XklIkwAnDpzZkySVTZYyoASlGN0T+8d8i42D7IZpF +GojTs1lFAgMBAAECggEAIYthUi1lFBDd5gG4Rzlu+BlBIn5JhcqkCqLEBiJIFfOr +/4yuMRrvS3bNzqWt6xJ9MSAC4ZlN/VobRLnxL/QNymoiGYUKCT3Ww8nvPpPzR9OE +sE68TUL9tJw/zZJcRMKwgvrGqSLimfq53MxxkE+kLdOc0v9C8YH8Re26mB5ZcWYa +7YFyZQpKsQYnsmu/05cMbpOQrQWhtmIqRoyn8mG/par2s3NzjtpSE9NINyz26uFc +k/3ovFJQIHkUmTS7KHD3BgY5vuCqP98HramYnOysJ0WoYgvSDNCWw3037s5CCwJT +gCKuM+Ow6liFrj83RrdKBpm5QUGjfNpYP31o+QNP4QKBgQDSrUQ2XdgtAnibAV7u +7kbxOxro0EhIKso0Y/6LbDQgcXgxLqltkmeqZgG8nC3Z793lhlSasz2snhzzooV5 +5fTy1y8ikXqjhG0nNkInFyOhsI0auE28CFoDowaQd+5cmCatpN4Grqo5PNRXxm1w +HktfPEgoP11NNCFHvvN5fEKbbQKBgQDwVlOaV20IvW3IPq7cXZyiyabouFF9eTRo +VJka1Uv+JtyvL2P0NKkjYHOdN8gRblWqxQtJoTNk020rVA4UP1heiXALy50gvj/p +hMcybPTLYSPOhAGx838KIcvGR5oskP1aUCmFbFQzGELxhJ9diVVjxUtbG2DuwPKd +tD9TLxT2OQKBgQCcdlHSjp+dzdgERmBa0ludjGfPv9/uuNizUBAbO6D690psPFtY +JQMYaemgSd1DngEOFVWADt4e9M5Lose+YCoqr+UxpxmNlyv5kzJOFcFAs/4XeglB +PHKdgNW/NVKxMc6H54l9LPr+x05sYdGlEtqnP/3W5jhEvhJ5Vjc8YiyVgQKBgQCl +zwjyrGo+42GACy7cPYE5FeIfIDqoVByB9guC5bD98JXEDu/opQQjsgFRcBCJZhOY +M0UsURiB8ROaFu13rpQq9KrmmF0ZH+g8FSzQbzcbsTLg4VXCDXmR5esOKowFPypr +Sm667BfTAGP++D5ya7MLmCv6+RKQ5XD8uEQQAaV2kQKBgAD8qeJuWIXZT0VKkQrn +nIhgtzGERF/6sZdQGW2LxTbUDWG74AfFkkEbeBfwEkCZXY/xmnYqYABhvlSex8jU +supU6Eea21esIxIub2zv/Np0ojUb6rlqTPS4Ox1E27D787EJ3VOXpriSD10vyNnZ +jel6uj2FOP9g54s+GzlSVg/T -----END RSA TESTING KEY-----`)) func testingKey(s string) string { return strings.ReplaceAll(s, "TESTING KEY", "PRIVATE KEY") } From 2b2314e9f6103de322b2e247387c8b01fd0cd5a4 Mon Sep 17 00:00:00 2001 From: Roland Shoemaker Date: Mon, 9 Dec 2024 11:31:22 -0800 Subject: [PATCH 148/397] crypto/x509: properly check for IPv6 hosts in URIs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When checking URI constraints, use netip.ParseAddr, which understands zones, unlike net.ParseIP which chokes on them. This prevents zone IDs from mistakenly satisfying URI constraints. Thanks to Juho Forsén of Mattermost for reporting this issue. Fixes #71156 Fixes CVE-2024-45341 Change-Id: Iecac2529f3605382d257996e0fb6d6983547e400 Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/1700 Reviewed-by: Tatiana Bradley Reviewed-by: Damien Neil Reviewed-on: https://go-review.googlesource.com/c/go/+/643096 Reviewed-by: Michael Pratt Auto-Submit: Michael Knyszek LUCI-TryBot-Result: Go LUCI --- src/crypto/x509/name_constraints_test.go | 17 +++++++++++++++++ src/crypto/x509/verify.go | 7 +++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/crypto/x509/name_constraints_test.go b/src/crypto/x509/name_constraints_test.go index 008c7028f4e4c4..a5851845164d10 100644 --- a/src/crypto/x509/name_constraints_test.go +++ b/src/crypto/x509/name_constraints_test.go @@ -1607,6 +1607,23 @@ var nameConstraintsTests = []nameConstraintsTest{ leaf: leafSpec{sans: []string{"dns:.example.com"}}, expectedError: "cannot parse dnsName \".example.com\"", }, + // #86: URIs with IPv6 addresses with zones and ports are rejected + { + roots: []constraintsSpec{ + { + ok: []string{"uri:example.com"}, + }, + }, + intermediates: [][]constraintsSpec{ + { + {}, + }, + }, + leaf: leafSpec{ + sans: []string{"uri:http://[2006:abcd::1%25.example.com]:16/"}, + }, + expectedError: "URI with IP", + }, } func makeConstraintsCACert(constraints constraintsSpec, name string, key *ecdsa.PrivateKey, parent *Certificate, parentKey *ecdsa.PrivateKey) (*Certificate, error) { diff --git a/src/crypto/x509/verify.go b/src/crypto/x509/verify.go index d2384f56653f86..5fe93c6124a989 100644 --- a/src/crypto/x509/verify.go +++ b/src/crypto/x509/verify.go @@ -13,6 +13,7 @@ import ( "iter" "maps" "net" + "net/netip" "net/url" "reflect" "runtime" @@ -465,8 +466,10 @@ func matchURIConstraint(uri *url.URL, constraint string) (bool, error) { } } - if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") || - net.ParseIP(host) != nil { + // netip.ParseAddr will reject the URI IPv6 literal form "[...]", so we + // check if _either_ the string parses as an IP, or if it is enclosed in + // square brackets. + if _, err := netip.ParseAddr(host); err == nil || (strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]")) { return false, fmt.Errorf("URI with IP (%q) cannot be matched against constraints", uri.String()) } From 139d6eedae38f9e8bc81bb2c8c5c2c75d12853ab Mon Sep 17 00:00:00 2001 From: Sam Thanawalla Date: Wed, 8 Jan 2025 20:38:32 +0000 Subject: [PATCH 149/397] cmd/go: restore netrc preferences for GOAUTH and fix domain lookup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Store netrc lines into the credential map backward so that earlier lines take priority over later lines. This matches Go 1.23 netrc lookup which stopped at the first match it found. Additionally, this fixes a security issue related to domain parsing which could have allowed servers to read credentials belonging to other servers. The fix was to switch from using path.Dir(currentPrefix) to strings.Cut(currentPrefix, "/") Thanks to Juho Forsén of Mattermost for reporting this issue. Fixes #71249 Fixes CVE-2024-45340 Change-Id: I175a00d6d7f4d31c9e4d79b7cf1c2a0ad35b2781 Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/1781 Reviewed-by: Tatiana Bradley Commit-Queue: Roland Shoemaker Reviewed-by: Roland Shoemaker Reviewed-by: Damien Neil Reviewed-on: https://go-review.googlesource.com/c/go/+/643097 Reviewed-by: Michael Pratt LUCI-TryBot-Result: Go LUCI Auto-Submit: Michael Knyszek --- src/cmd/go/internal/auth/auth.go | 17 +++++++++------ src/cmd/go/internal/auth/auth_test.go | 24 ++++++++++++++++++++- src/cmd/go/testdata/script/goauth_netrc.txt | 7 +++--- 3 files changed, 38 insertions(+), 10 deletions(-) diff --git a/src/cmd/go/internal/auth/auth.go b/src/cmd/go/internal/auth/auth.go index b008e9c2818f2c..bd80222427ae36 100644 --- a/src/cmd/go/internal/auth/auth.go +++ b/src/cmd/go/internal/auth/auth.go @@ -12,7 +12,6 @@ import ( "log" "net/http" "os" - "path" "path/filepath" "slices" "strings" @@ -73,7 +72,12 @@ func runGoAuth(client *http.Client, res *http.Response, url string) { if err != nil { base.Fatalf("go: could not parse netrc (GOAUTH=%s): %v", cfg.GOAUTH, err) } - for _, l := range lines { + // Process lines in reverse so that if the same machine is listed + // multiple times, we end up saving the earlier one + // (overwriting later ones). This matches the way the go command + // worked before GOAUTH. + for i := len(lines) - 1; i >= 0; i-- { + l := lines[i] r := http.Request{Header: make(http.Header)} r.SetBasicAuth(l.login, l.password) storeCredential(l.machine, r.Header) @@ -137,11 +141,13 @@ func runGoAuth(client *http.Client, res *http.Response, url string) { func loadCredential(req *http.Request, url string) bool { currentPrefix := strings.TrimPrefix(url, "https://") // Iteratively try prefixes, moving up the path hierarchy. - for currentPrefix != "/" && currentPrefix != "." && currentPrefix != "" { + for { headers, ok := credentialCache.Load(currentPrefix) if !ok { - // Move to the parent directory. - currentPrefix = path.Dir(currentPrefix) + currentPrefix, _, ok = strings.Cut(currentPrefix, "/") + if !ok { + return false + } continue } for key, values := range headers.(http.Header) { @@ -151,7 +157,6 @@ func loadCredential(req *http.Request, url string) bool { } return true } - return false } // storeCredential caches or removes credentials (represented by HTTP headers) diff --git a/src/cmd/go/internal/auth/auth_test.go b/src/cmd/go/internal/auth/auth_test.go index c7b4851e2882aa..c1bbf4b1a91e6f 100644 --- a/src/cmd/go/internal/auth/auth_test.go +++ b/src/cmd/go/internal/auth/auth_test.go @@ -25,7 +25,29 @@ func TestCredentialCache(t *testing.T) { got := &http.Request{Header: make(http.Header)} ok := loadCredential(got, tc.machine) if !ok || !reflect.DeepEqual(got.Header, want.Header) { - t.Errorf("loadCredential:\nhave %q\nwant %q", got.Header, want.Header) + t.Errorf("loadCredential(%q):\nhave %q\nwant %q", tc.machine, got.Header, want.Header) + } + } + + // Having stored those credentials, we should be able to look up longer URLs too. + extraCases := []netrcLine{ + {"https://api.github.com/foo", "user", "pwd"}, + {"https://api.github.com/foo/bar/baz", "user", "pwd"}, + {"https://example.com/abc", "", ""}, + {"https://example.com/?/../api.github.com/", "", ""}, + {"https://example.com/?/../api.github.com", "", ""}, + {"https://example.com/../api.github.com/", "", ""}, + {"https://example.com/../api.github.com", "", ""}, + } + for _, tc := range extraCases { + want := http.Request{Header: make(http.Header)} + if tc.login != "" { + want.SetBasicAuth(tc.login, tc.password) + } + got := &http.Request{Header: make(http.Header)} + loadCredential(got, tc.machine) + if !reflect.DeepEqual(got.Header, want.Header) { + t.Errorf("loadCredential(%q):\nhave %q\nwant %q", tc.machine, got.Header, want.Header) } } } diff --git a/src/cmd/go/testdata/script/goauth_netrc.txt b/src/cmd/go/testdata/script/goauth_netrc.txt index 2dda119e825d9f..26e03f8968c5b3 100644 --- a/src/cmd/go/testdata/script/goauth_netrc.txt +++ b/src/cmd/go/testdata/script/goauth_netrc.txt @@ -2,8 +2,6 @@ # credentials passed in HTTPS requests to VCS servers. # See golang.org/issue/26232 -[short] skip - env GOPROXY=direct env GOSUMDB=off @@ -55,7 +53,6 @@ go get vcs-test.golang.org/auth/or401 env NETRC=$WORK/missing ! go get vcs-test.golang.org/auth/or401 stderr '^\tserver response: ACCESS DENIED, buddy$' - -- go.mod -- module private.example.com -- $WORK/empty -- @@ -63,3 +60,7 @@ module private.example.com machine vcs-test.golang.org login aladdin password opensesame +# first one should override this one +machine vcs-test.golang.org + login aladdin + password ignored From 6a4effa08ba5c7b182d319a2a8ddd782274c2f74 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Thu, 9 Jan 2025 16:03:08 +0100 Subject: [PATCH 150/397] crypto/x509: avoid panic when parsing partial PKCS#1 private keys These keys are off-spec, but have historically been accepted by ParsePKCS1PrivateKey. Thanks to Philippe Antoine (Catena cyber) for reporting this issue. Fixes #71216 Fixes CVE-2025-22865 Change-Id: I6a6a46564156fa32e29e8d6acbec3fbac47c7352 Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/1820 Reviewed-by: Tatiana Bradley Reviewed-by: Damien Neil Commit-Queue: Roland Shoemaker Reviewed-on: https://go-review.googlesource.com/c/go/+/643098 Auto-Submit: Michael Knyszek LUCI-TryBot-Result: Go LUCI Reviewed-by: Michael Pratt --- src/crypto/x509/pkcs1.go | 4 +++- src/crypto/x509/x509_test.go | 26 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/crypto/x509/pkcs1.go b/src/crypto/x509/pkcs1.go index ca23358c8c4610..68aa8dd980c10e 100644 --- a/src/crypto/x509/pkcs1.go +++ b/src/crypto/x509/pkcs1.go @@ -72,7 +72,9 @@ func ParsePKCS1PrivateKey(der []byte) (*rsa.PrivateKey, error) { } if priv.N.Sign() <= 0 || priv.D.Sign() <= 0 || priv.P.Sign() <= 0 || priv.Q.Sign() <= 0 || - priv.Dp.Sign() <= 0 || priv.Dq.Sign() <= 0 || priv.Qinv.Sign() <= 0 { + priv.Dp != nil && priv.Dp.Sign() <= 0 || + priv.Dq != nil && priv.Dq.Sign() <= 0 || + priv.Qinv != nil && priv.Qinv.Sign() <= 0 { return nil, errors.New("x509: private key contains zero or negative value") } diff --git a/src/crypto/x509/x509_test.go b/src/crypto/x509/x509_test.go index 941ea572e69f26..f67f40778b930b 100644 --- a/src/crypto/x509/x509_test.go +++ b/src/crypto/x509/x509_test.go @@ -59,6 +59,32 @@ func TestParsePKCS1PrivateKey(t *testing.T) { if _, err := ParsePKCS1PrivateKey(data); err == nil { t.Errorf("parsing invalid private key did not result in an error") } + + // A partial key without CRT values should still parse. + b, _ := asn1.Marshal(struct { + Version int + N *big.Int + E int + D *big.Int + P *big.Int + Q *big.Int + }{ + N: priv.N, + E: priv.PublicKey.E, + D: priv.D, + P: priv.Primes[0], + Q: priv.Primes[1], + }) + p2, err := ParsePKCS1PrivateKey(b) + if err != nil { + t.Fatalf("parsing partial private key resulted in an error: %v", err) + } + if !p2.Equal(priv) { + t.Errorf("partial private key did not match original key") + } + if p2.Precomputed.Dp == nil || p2.Precomputed.Dq == nil || p2.Precomputed.Qinv == nil { + t.Errorf("precomputed values not recomputed") + } } func TestPKCS1MismatchPublicKeyFormat(t *testing.T) { From 0b632d26b99e3924aea14574e422065e13f2a1c5 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Thu, 16 Jan 2025 13:56:15 -0500 Subject: [PATCH 151/397] cmd/internal/obj/wasm, runtime: detect wasmexport call before runtime initialization If a wasmexport function is called from the host before initializing the Go Wasm module, currently it will likely fail with a bounds error, because the uninitialized SP is 0, and any SP decrement will make it out of bounds. As at least some Wasm runtime doesn't call _initialize by default, This error can be common. And the bounds error looks confusing to the users. Therefore, we detect this case and emit a clearer error. Fixes #71240. Updates #65199. Change-Id: I107095f08c76cdceb7781ab0304218eab7029ab6 Reviewed-on: https://go-review.googlesource.com/c/go/+/643115 LUCI-TryBot-Result: Go LUCI Reviewed-by: Michael Knyszek --- src/cmd/internal/obj/wasm/wasmobj.go | 25 +++++++++++++++++++++++-- src/cmd/link/internal/wasm/asm.go | 1 + src/runtime/asm_wasm.s | 10 ++++++++++ src/runtime/sys_wasm.go | 14 ++++++++++++++ 4 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/cmd/internal/obj/wasm/wasmobj.go b/src/cmd/internal/obj/wasm/wasmobj.go index 48eee4e3ea12de..42e5534f3b6254 100644 --- a/src/cmd/internal/obj/wasm/wasmobj.go +++ b/src/cmd/internal/obj/wasm/wasmobj.go @@ -129,6 +129,7 @@ var ( morestackNoCtxt *obj.LSym sigpanic *obj.LSym wasm_pc_f_loop_export *obj.LSym + runtimeNotInitialized *obj.LSym ) const ( @@ -149,6 +150,7 @@ func instinit(ctxt *obj.Link) { morestackNoCtxt = ctxt.Lookup("runtime.morestack_noctxt") sigpanic = ctxt.LookupABI("runtime.sigpanic", obj.ABIInternal) wasm_pc_f_loop_export = ctxt.Lookup("wasm_pc_f_loop_export") + runtimeNotInitialized = ctxt.Lookup("runtime.notInitialized") } func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) { @@ -255,7 +257,7 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) { p = appendp(p, AEnd) } - if framesize > 0 { + if framesize > 0 && s.Func().WasmExport == nil { // genWasmExportWrapper has its own prologue generation p := s.Func().Text p = appendp(p, AGet, regAddr(REG_SP)) p = appendp(p, AI32Const, constAddr(framesize)) @@ -935,6 +937,23 @@ func genWasmExportWrapper(s *obj.LSym, appendp func(p *obj.Prog, as obj.As, args panic("wrapper functions for WASM export should not have a body") } + // Detect and error out if called before runtime initialization + // SP is 0 if not initialized + p = appendp(p, AGet, regAddr(REG_SP)) + p = appendp(p, AI32Eqz) + p = appendp(p, AIf) + p = appendp(p, ACall, obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_EXTERN, Sym: runtimeNotInitialized}) + p = appendp(p, AEnd) + + // Now that we've checked the SP, generate the prologue + if framesize > 0 { + p = appendp(p, AGet, regAddr(REG_SP)) + p = appendp(p, AI32Const, constAddr(framesize)) + p = appendp(p, AI32Sub) + p = appendp(p, ASet, regAddr(REG_SP)) + p.Spadj = int32(framesize) + } + // Store args for i, f := range we.Params { p = appendp(p, AGet, regAddr(REG_SP)) @@ -1056,6 +1075,7 @@ var notUsePC_B = map[string]bool{ "runtime.gcWriteBarrier6": true, "runtime.gcWriteBarrier7": true, "runtime.gcWriteBarrier8": true, + "runtime.notInitialized": true, "runtime.wasmDiv": true, "runtime.wasmTruncS": true, "runtime.wasmTruncU": true, @@ -1121,7 +1141,8 @@ func assemble(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) { "runtime.gcWriteBarrier5", "runtime.gcWriteBarrier6", "runtime.gcWriteBarrier7", - "runtime.gcWriteBarrier8": + "runtime.gcWriteBarrier8", + "runtime.notInitialized": // no locals useAssemblyRegMap() default: diff --git a/src/cmd/link/internal/wasm/asm.go b/src/cmd/link/internal/wasm/asm.go index 727da59da630d4..d03102cc6be629 100644 --- a/src/cmd/link/internal/wasm/asm.go +++ b/src/cmd/link/internal/wasm/asm.go @@ -87,6 +87,7 @@ var wasmFuncTypes = map[string]*wasmFuncType{ "runtime.gcWriteBarrier6": {Results: []byte{I64}}, // -> bufptr "runtime.gcWriteBarrier7": {Results: []byte{I64}}, // -> bufptr "runtime.gcWriteBarrier8": {Results: []byte{I64}}, // -> bufptr + "runtime.notInitialized": {}, // "cmpbody": {Params: []byte{I64, I64, I64, I64}, Results: []byte{I64}}, // a, alen, b, blen -> -1/0/1 "memeqbody": {Params: []byte{I64, I64, I64}, Results: []byte{I64}}, // a, b, len -> 0/1 "memcmp": {Params: []byte{I32, I32, I32}, Results: []byte{I32}}, // a, b, len -> <0/0/>0 diff --git a/src/runtime/asm_wasm.s b/src/runtime/asm_wasm.s index 016d2d3825ac49..69da583a1d54e9 100644 --- a/src/runtime/asm_wasm.s +++ b/src/runtime/asm_wasm.s @@ -614,3 +614,13 @@ TEXT runtime·pause(SB), NOSPLIT, $0-8 I32Const $1 Set PAUSE RETUNWIND + +// Called if a wasmexport function is called before runtime initialization +TEXT runtime·notInitialized(SB), NOSPLIT, $0 + MOVD $runtime·wasmStack+(m0Stack__size-16-8)(SB), SP + I32Const $0 // entry PC_B + Call runtime·notInitialized1(SB) + Drop + I32Const $0 // entry PC_B + Call runtime·abort(SB) + UNDEF diff --git a/src/runtime/sys_wasm.go b/src/runtime/sys_wasm.go index f88b992e9c39a3..6b40a8d3e94c96 100644 --- a/src/runtime/sys_wasm.go +++ b/src/runtime/sys_wasm.go @@ -34,3 +34,17 @@ func gostartcall(buf *gobuf, fn, ctxt unsafe.Pointer) { buf.pc = uintptr(fn) buf.ctxt = ctxt } + +func notInitialized() // defined in assembly, call notInitialized1 + +// Called if a wasmexport function is called before runtime initialization +// +//go:nosplit +func notInitialized1() { + writeErrStr("runtime: wasmexport function called before runtime initialization\n") + if isarchive || islibrary { + writeErrStr("\tcall _initialize first\n") + } else { + writeErrStr("\tcall _start first\n") + } +} From 1a93e4a2cf43b0ded141d33620966bb252cac1bd Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Thu, 16 Jan 2025 20:42:39 +0100 Subject: [PATCH 152/397] lib/time: update to 2025a/2025a Commit generated by update.bash. For #22487. Change-Id: Ie5002725b9add75fd22b29ea3a7addbe0151b25c Reviewed-on: https://go-review.googlesource.com/c/go/+/642020 LUCI-TryBot-Result: Go LUCI Reviewed-by: Dmitri Shuralyov Auto-Submit: Tobias Klauser Reviewed-by: Ian Lance Taylor --- lib/time/update.bash | 4 ++-- lib/time/zoneinfo.zip | Bin 406172 -> 406409 bytes 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/time/update.bash b/lib/time/update.bash index 6b66fa54a9595a..67cb016e79392f 100755 --- a/lib/time/update.bash +++ b/lib/time/update.bash @@ -24,8 +24,8 @@ # in the CL match the update.bash in the CL. # Versions to use. -CODE=2024b -DATA=2024b +CODE=2025a +DATA=2025a set -e diff --git a/lib/time/zoneinfo.zip b/lib/time/zoneinfo.zip index b36e82c958aef016d7cdf72cdcbf570adb4418b1..6ba9ff6fd6afc9736c41c5ec2c3bfd1aa12a0f1b 100644 GIT binary patch delta 5106 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 K{EPArTK@%co#X8Q delta 4855 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 SxP{0e@|Wv18jJnnwErLRE2Opn From 80bf7d83edbb48e2411d755f0636565467bb5a56 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 16 Jan 2025 16:08:26 -0800 Subject: [PATCH 153/397] go/types, types2: remove superfluous assertion (fix build) Remove an assertion that was overly restrictive and hard to get correct under all circumstances (i.e., in the presence of incorrect) code. This matches the code for *Named types in that specific switch. Fixes #71284. Change-Id: Ifccf8b73dc70cac9cb1c8b24946d16851d511454 Reviewed-on: https://go-review.googlesource.com/c/go/+/643255 Reviewed-by: Robert Findley Auto-Submit: Robert Griesemer Reviewed-by: Robert Griesemer LUCI-TryBot-Result: Go LUCI --- src/cmd/compile/internal/types2/typexpr.go | 5 ----- src/go/types/typexpr.go | 5 ----- src/internal/types/testdata/fixedbugs/issue71284.go | 10 ++++++++++ 3 files changed, 10 insertions(+), 10 deletions(-) create mode 100644 src/internal/types/testdata/fixedbugs/issue71284.go diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go index fa6a6f622af7cf..e9b5ca9aa6c329 100644 --- a/src/cmd/compile/internal/types2/typexpr.go +++ b/src/cmd/compile/internal/types2/typexpr.go @@ -423,11 +423,6 @@ func setDefType(def *TypeName, typ Type) { if def != nil { switch t := def.typ.(type) { case *Alias: - // t.fromRHS should always be set, either to an invalid type - // in the beginning, or to typ in certain cyclic declarations. - if t.fromRHS != Typ[Invalid] && t.fromRHS != typ { - panic(sprintf(nil, true, "t.fromRHS = %s, typ = %s\n", t.fromRHS, typ)) - } t.fromRHS = typ case *Basic: assert(t == Typ[Invalid]) diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index e560f2c131bd37..7928ed8ef368de 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -419,11 +419,6 @@ func setDefType(def *TypeName, typ Type) { if def != nil { switch t := def.typ.(type) { case *Alias: - // t.fromRHS should always be set, either to an invalid type - // in the beginning, or to typ in certain cyclic declarations. - if t.fromRHS != Typ[Invalid] && t.fromRHS != typ { - panic(sprintf(nil, nil, true, "t.fromRHS = %s, typ = %s\n", t.fromRHS, typ)) - } t.fromRHS = typ case *Basic: assert(t == Typ[Invalid]) diff --git a/src/internal/types/testdata/fixedbugs/issue71284.go b/src/internal/types/testdata/fixedbugs/issue71284.go new file mode 100644 index 00000000000000..4b73087a78a191 --- /dev/null +++ b/src/internal/types/testdata/fixedbugs/issue71284.go @@ -0,0 +1,10 @@ +// Copyright 2025 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package A + +type ( + _ = A + A /* ERROR "invalid recursive type: A refers to itself" */ = A +) From 87023bb27f2cbe86c5baa9cef5ad91a6fc9a1c14 Mon Sep 17 00:00:00 2001 From: Wingrez <31106425+wingrez@users.noreply.github.com> Date: Fri, 17 Jan 2025 00:38:59 +0000 Subject: [PATCH 154/397] go/types, types2: ensure deterministic output when reporting an init cycle Fixes #71254 Change-Id: Ie3bad281403c8ff6215e03d92760b9a378714cee GitHub-Last-Rev: 9b804a7842421dca6a97c57ce18523b593b0817d GitHub-Pull-Request: golang/go#71264 Reviewed-on: https://go-review.googlesource.com/c/go/+/642396 LUCI-TryBot-Result: Go LUCI Reviewed-by: Robert Griesemer Reviewed-by: Robert Findley Auto-Submit: Robert Griesemer --- src/cmd/compile/internal/types2/initorder.go | 10 ++++++++++ .../internal/types2/testdata/local/issue71254.go | 14 ++++++++++++++ src/go/types/initorder.go | 10 ++++++++++ 3 files changed, 34 insertions(+) create mode 100644 src/cmd/compile/internal/types2/testdata/local/issue71254.go diff --git a/src/cmd/compile/internal/types2/initorder.go b/src/cmd/compile/internal/types2/initorder.go index ef2ad010a6d5fb..699bfca8bbc895 100644 --- a/src/cmd/compile/internal/types2/initorder.go +++ b/src/cmd/compile/internal/types2/initorder.go @@ -10,6 +10,7 @@ import ( "fmt" . "internal/types/errors" "slices" + "sort" ) // initOrder computes the Info.InitOrder for package variables. @@ -139,7 +140,16 @@ func findPath(objMap map[Object]*declInfo, from, to Object, seen map[Object]bool } seen[from] = true + // sort deps for deterministic result + var deps []Object for d := range objMap[from].deps { + deps = append(deps, d) + } + sort.Slice(deps, func(i, j int) bool { + return deps[i].order() < deps[j].order() + }) + + for _, d := range deps { if d == to { return []Object{d} } diff --git a/src/cmd/compile/internal/types2/testdata/local/issue71254.go b/src/cmd/compile/internal/types2/testdata/local/issue71254.go new file mode 100644 index 00000000000000..9cca9d5bc4dc6e --- /dev/null +++ b/src/cmd/compile/internal/types2/testdata/local/issue71254.go @@ -0,0 +1,14 @@ +// Copyright 2025 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +const ( + B /* ERROR "initialization cycle: B refers to itself" */ = A + B + A /* ERRORx "initialization cycle for A\\s+.*A refers to B\\s+.*B refers to A" */ = A + B + + C /* ERRORx "initialization cycle for C\\s+.*C refers to D\\s+.*D refers to C" */ = E + D + D /* ERRORx "initialization cycle for D\\s+.*D refers to C\\s+.*C refers to D" */ = E + C + E = D + C +) diff --git a/src/go/types/initorder.go b/src/go/types/initorder.go index 7625c206674994..adf96fe718f13d 100644 --- a/src/go/types/initorder.go +++ b/src/go/types/initorder.go @@ -13,6 +13,7 @@ import ( "fmt" . "internal/types/errors" "slices" + "sort" ) // initOrder computes the Info.InitOrder for package variables. @@ -142,7 +143,16 @@ func findPath(objMap map[Object]*declInfo, from, to Object, seen map[Object]bool } seen[from] = true + // sort deps for deterministic result + var deps []Object for d := range objMap[from].deps { + deps = append(deps, d) + } + sort.Slice(deps, func(i, j int) bool { + return deps[i].order() < deps[j].order() + }) + + for _, d := range deps { if d == to { return []Object{d} } From 40b3c0e58a0ae8dec4684a009bf3806769e0fc41 Mon Sep 17 00:00:00 2001 From: Than McIntosh Date: Tue, 12 Nov 2024 12:12:44 -0500 Subject: [PATCH 155/397] internal/coverage: refactor EmitTextual in preparation for bugfix Refactor cformat.EmitTextual to accept a package filter (list of packages to report). This is a no-op in terms of exposed coverage functionality, but we will need this feature in a subsequent patch. Updates #70244. Change-Id: I1e6bcbfb5e68187d4d69d54b667e97bc1fdfa2d4 Reviewed-on: https://go-review.googlesource.com/c/go/+/627315 Reviewed-by: David Chase Reviewed-by: Michael Knyszek LUCI-TryBot-Result: Go LUCI --- src/cmd/covdata/dump.go | 2 +- src/internal/coverage/cfile/testsupport.go | 2 +- src/internal/coverage/cformat/fmt_test.go | 16 ++++++++++++++-- src/internal/coverage/cformat/format.go | 22 +++++++++++++++++----- 4 files changed, 33 insertions(+), 9 deletions(-) diff --git a/src/cmd/covdata/dump.go b/src/cmd/covdata/dump.go index cbbeae0a8020de..e141689b00e563 100644 --- a/src/cmd/covdata/dump.go +++ b/src/cmd/covdata/dump.go @@ -331,7 +331,7 @@ func (d *dstate) Finish() { d.format.EmitFuncs(os.Stdout) } if d.textfmtoutf != nil { - if err := d.format.EmitTextual(d.textfmtoutf); err != nil { + if err := d.format.EmitTextual(nil, d.textfmtoutf); err != nil { fatal("writing to %s: %v", *textfmtoutflag, err) } } diff --git a/src/internal/coverage/cfile/testsupport.go b/src/internal/coverage/cfile/testsupport.go index 3594b32aee1a8d..56b39c5859a96b 100644 --- a/src/internal/coverage/cfile/testsupport.go +++ b/src/internal/coverage/cfile/testsupport.go @@ -109,7 +109,7 @@ func ProcessCoverTestDir(dir string, cfile string, cm string, cpkg string, w io. // Emit text output. if tf != nil { - if err := ts.cf.EmitTextual(tf); err != nil { + if err := ts.cf.EmitTextual(nil, tf); err != nil { return err } tfClosed = true diff --git a/src/internal/coverage/cformat/fmt_test.go b/src/internal/coverage/cformat/fmt_test.go index d296939d5cd20c..a26de964c43538 100644 --- a/src/internal/coverage/cformat/fmt_test.go +++ b/src/internal/coverage/cformat/fmt_test.go @@ -47,8 +47,8 @@ func TestBasics(t *testing.T) { fm.AddUnit("lit.go", "f3", true, u, 0) } - var b1, b2, b3, b4 strings.Builder - if err := fm.EmitTextual(&b1); err != nil { + var b1, b2, b3, b4, b5 strings.Builder + if err := fm.EmitTextual(nil, &b1); err != nil { t.Fatalf("EmitTextual returned %v", err) } wantText := strings.TrimSpace(` @@ -64,6 +64,18 @@ lit.go:99.0,100.0 1 0`) t.Errorf("emit text: got:\n%s\nwant:\n%s\n", gotText, wantText) } + selected := []string{"my/pack2"} + if err := fm.EmitTextual(selected, &b5); err != nil { + t.Fatalf("EmitTextual returned %v", err) + } + wantText = strings.TrimSpace(` +mode: atomic +lit.go:99.0,100.0 1 0`) + gotText = strings.TrimSpace(b5.String()) + if wantText != gotText { + t.Errorf("emit text: got:\n%s\nwant:\n%s\n", gotText, wantText) + } + // Percent output with no aggregation. noCoverPkg := "" if err := fm.EmitPercent(&b2, nil, noCoverPkg, false, false); err != nil { diff --git a/src/internal/coverage/cformat/format.go b/src/internal/coverage/cformat/format.go index 4df0e70b81ca6e..01d3109e31fd9d 100644 --- a/src/internal/coverage/cformat/format.go +++ b/src/internal/coverage/cformat/format.go @@ -24,7 +24,7 @@ package cformat // } // } // myformatter.EmitPercent(os.Stdout, nil, "", true, true) -// myformatter.EmitTextual(somefile) +// myformatter.EmitTextual(nil, somefile) // // These apis are linked into tests that are built with "-cover", and // called at the end of test execution to produce text output or @@ -38,6 +38,7 @@ import ( "io" "maps" "slices" + "sort" "strings" "text/tabwriter" ) @@ -163,20 +164,31 @@ func (p *pstate) sortUnits(units []extcu) { }) } -// EmitTextual writes the accumulated coverage data in the legacy -// cmd/cover text format to the writer 'w'. We sort the data items by +// EmitTextual writes the accumulated coverage data for 'pkgs' in the legacy +// cmd/cover text format to the writer 'w'; if pkgs is empty, text output +// is emitted for all packages recorded. We sort the data items by // importpath, source file, and line number before emitting (this sorting // is not explicitly mandated by the format, but seems like a good idea // for repeatable/deterministic dumps). -func (fm *Formatter) EmitTextual(w io.Writer) error { +func (fm *Formatter) EmitTextual(pkgs []string, w io.Writer) error { if fm.cm == coverage.CtrModeInvalid { panic("internal error, counter mode unset") } + if len(pkgs) == 0 { + pkgs = make([]string, 0, len(fm.pm)) + for importpath := range fm.pm { + pkgs = append(pkgs, importpath) + } + } if _, err := fmt.Fprintf(w, "mode: %s\n", fm.cm.String()); err != nil { return err } - for _, importpath := range slices.Sorted(maps.Keys(fm.pm)) { + sort.Strings(pkgs) + for _, importpath := range pkgs { p := fm.pm[importpath] + if p == nil { + continue + } units := make([]extcu, 0, len(p.unitTable)) for u := range p.unitTable { units = append(units, u) From 3f4164f508b8148eb526fc096884dba2609f5835 Mon Sep 17 00:00:00 2001 From: Bill Morgan Date: Mon, 20 Jan 2025 04:11:23 +0000 Subject: [PATCH 156/397] runtime: delete out of date comment Fixes #71328 Change-Id: I5827255bf1f53b8fc4a84fa1accb4089f73d5e8a GitHub-Last-Rev: 26f4eab182130c709be269491049fade3327ddd3 GitHub-Pull-Request: golang/go#71337 Reviewed-on: https://go-review.googlesource.com/c/go/+/643456 Reviewed-by: Jorropo Reviewed-by: Keith Randall Auto-Submit: Jorropo LUCI-TryBot-Result: Go LUCI Auto-Submit: Keith Randall Reviewed-by: Dmitri Shuralyov Reviewed-by: Keith Randall --- src/runtime/panic.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/runtime/panic.go b/src/runtime/panic.go index dc7a7fe357e091..3ffb3966d026c8 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -1068,9 +1068,6 @@ func internal_sync_fatal(s string) { // throw should be used for runtime-internal fatal errors where Go itself, // rather than user code, may be at fault for the failure. // -// NOTE: temporarily marked "go:noinline" pending investigation/fix of -// issue #67274, so as to fix longtest builders. -// // throw should be an internal detail, // but widely used packages access it using linkname. // Notable members of the hall of shame include: From 3aa7c5ef01e147fb482f4b3e79c6f875a4b1b9fb Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Mon, 20 Jan 2025 17:38:26 -0800 Subject: [PATCH 157/397] testing: fix reference to B.N in docstring Currently, a documentation reference to a struct member (such as [B.N]) does not result in it being rendered as a link, and thus the square brackets remain in the rendered documentation which is mildly confusing. The issue can be seen at https://pkg.go.dev/testing@master#hdr-b_N_style_benchmarks Remove the square brackets to fix. Change-Id: Id374fd2085bd511018220c5d663650f89672302e Reviewed-on: https://go-review.googlesource.com/c/go/+/643496 Reviewed-by: Ian Lance Taylor Auto-Submit: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Reviewed-by: Alan Donovan --- src/testing/testing.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/testing/testing.go b/src/testing/testing.go index be6391b0ab15ce..3833bfc84be49f 100644 --- a/src/testing/testing.go +++ b/src/testing/testing.go @@ -120,7 +120,7 @@ // # b.N-style benchmarks // // Prior to the introduction of [B.Loop], benchmarks were written in a -// different style using [B.N]. For example: +// different style using B.N. For example: // // func BenchmarkRandInt(b *testing.B) { // for range b.N { From f6d17c540024418ca8a92371931b1b4fb076d2b6 Mon Sep 17 00:00:00 2001 From: Dmitri Shuralyov Date: Tue, 21 Jan 2025 14:41:15 -0500 Subject: [PATCH 158/397] net/http: update bundled golang.org/x/net/http2 [generated] Pull in x/net CL 642606 and CL 643256 and regenerate h2_bundle.go: http2: disable extended CONNECT by default http2: encode :protocol pseudo-header before regular headers For #36905. Fixes #70728. Fixes #71128. [git-generate] go install golang.org/x/build/cmd/updatestd@latest go install golang.org/x/tools/cmd/bundle@latest updatestd -goroot=$(pwd) -branch=internal-branch.go1.24-vendor Change-Id: Id853cb96f8fc410956666f5c3ab4c5889c703503 Reviewed-on: https://go-review.googlesource.com/c/go/+/642398 Reviewed-by: Damien Neil Reviewed-by: Dmitri Shuralyov LUCI-TryBot-Result: Go LUCI Auto-Submit: Dmitri Shuralyov --- src/go.mod | 2 +- src/go.sum | 4 ++-- src/net/http/h2_bundle.go | 45 ++++++++++++++++++++++++++++----------- src/vendor/modules.txt | 2 +- 4 files changed, 36 insertions(+), 17 deletions(-) diff --git a/src/go.mod b/src/go.mod index 7a1318dcac32ba..ccfdbd8ea22d77 100644 --- a/src/go.mod +++ b/src/go.mod @@ -4,7 +4,7 @@ go 1.24 require ( golang.org/x/crypto v0.30.0 - golang.org/x/net v0.32.1-0.20241206180132-552d8ac903a1 + golang.org/x/net v0.32.1-0.20250121202134-9a960c88dd98 ) require ( diff --git a/src/go.sum b/src/go.sum index 9e661352f16e0b..4d6a33e34a4e63 100644 --- a/src/go.sum +++ b/src/go.sum @@ -1,7 +1,7 @@ golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY= golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= -golang.org/x/net v0.32.1-0.20241206180132-552d8ac903a1 h1:+Yk1FZ5E+/ewA0nOO/HRYs9E4yeqpGOShuSAdzCNNoQ= -golang.org/x/net v0.32.1-0.20241206180132-552d8ac903a1/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= +golang.org/x/net v0.32.1-0.20250121202134-9a960c88dd98 h1:36bTiCRO7f/J3t+LumnLTJDXqxsp1x6Q7754SsRD9u4= +golang.org/x/net v0.32.1-0.20250121202134-9a960c88dd98/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go index 46a2b79231e565..22f013f1d48407 100644 --- a/src/net/http/h2_bundle.go +++ b/src/net/http/h2_bundle.go @@ -3509,11 +3509,19 @@ func http2canonicalHeader(v string) string { } var ( - http2VerboseLogs bool - http2logFrameWrites bool - http2logFrameReads bool - http2inTests bool - http2disableExtendedConnectProtocol bool + http2VerboseLogs bool + http2logFrameWrites bool + http2logFrameReads bool + http2inTests bool + + // Enabling extended CONNECT by causes browsers to attempt to use + // WebSockets-over-HTTP/2. This results in problems when the server's websocket + // package doesn't support extended CONNECT. + // + // Disable extended CONNECT by default for now. + // + // Issue #71128. + http2disableExtendedConnectProtocol = true ) func init() { @@ -3526,8 +3534,8 @@ func init() { http2logFrameWrites = true http2logFrameReads = true } - if strings.Contains(e, "http2xconnect=0") { - http2disableExtendedConnectProtocol = true + if strings.Contains(e, "http2xconnect=1") { + http2disableExtendedConnectProtocol = false } } @@ -9500,10 +9508,6 @@ func http2validateHeaders(hdrs Header) string { var http2errNilRequestURL = errors.New("http2: Request.URI is nil") -func http2isNormalConnect(req *Request) bool { - return req.Method == "CONNECT" && req.Header.Get(":protocol") == "" -} - // requires cc.wmu be held. func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trailers string, contentLength int64) ([]byte, error) { cc.hbuf.Reset() @@ -9523,8 +9527,17 @@ func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trail return nil, errors.New("http2: invalid Host header") } + // isNormalConnect is true if this is a non-extended CONNECT request. + isNormalConnect := false + protocol := req.Header.Get(":protocol") + if req.Method == "CONNECT" && protocol == "" { + isNormalConnect = true + } else if protocol != "" && req.Method != "CONNECT" { + return nil, errors.New("http2: invalid :protocol header in non-CONNECT request") + } + var path string - if !http2isNormalConnect(req) { + if !isNormalConnect { path = req.URL.RequestURI() if !http2validPseudoPath(path) { orig := path @@ -9561,10 +9574,13 @@ func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trail m = MethodGet } f(":method", m) - if !http2isNormalConnect(req) { + if !isNormalConnect { f(":path", path) f(":scheme", req.URL.Scheme) } + if protocol != "" { + f(":protocol", protocol) + } if trailers != "" { f("trailer", trailers) } @@ -9621,6 +9637,9 @@ func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trail } } continue + } else if k == ":protocol" { + // :protocol pseudo-header was already sent above. + continue } for _, v := range vv { diff --git a/src/vendor/modules.txt b/src/vendor/modules.txt index 1c8de570cc2f1f..d42f50b43ccdba 100644 --- a/src/vendor/modules.txt +++ b/src/vendor/modules.txt @@ -6,7 +6,7 @@ golang.org/x/crypto/cryptobyte golang.org/x/crypto/cryptobyte/asn1 golang.org/x/crypto/internal/alias golang.org/x/crypto/internal/poly1305 -# golang.org/x/net v0.32.1-0.20241206180132-552d8ac903a1 +# golang.org/x/net v0.32.1-0.20250121202134-9a960c88dd98 ## explicit; go 1.18 golang.org/x/net/dns/dnsmessage golang.org/x/net/http/httpguts From 70b603f4d295573197b43ad090d7cad21895144e Mon Sep 17 00:00:00 2001 From: Alan Donovan Date: Wed, 22 Jan 2025 10:24:11 -0500 Subject: [PATCH 159/397] go/importer: document limitations of this API Arguably it should be deprecated, but that's a process. Updates #71272 Change-Id: I69de1f9709c45dfea0fe67d96a7bd15d3df4e2f1 Reviewed-on: https://go-review.googlesource.com/c/go/+/643795 LUCI-TryBot-Result: Go LUCI Reviewed-by: Robert Findley Auto-Submit: Alan Donovan --- src/go/importer/importer.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/go/importer/importer.go b/src/go/importer/importer.go index 8a8fb0ec04030b..54acd7e6940202 100644 --- a/src/go/importer/importer.go +++ b/src/go/importer/importer.go @@ -3,6 +3,13 @@ // license that can be found in the LICENSE file. // Package importer provides access to export data importers. +// +// These functions, which are mostly deprecated, date from before the +// introduction of modules in release Go 1.11. They should no longer +// be relied on except for use in test cases using small programs that +// depend only on the standard library. For reliable module-aware +// loading of type information, use the packages.Load function from +// golang.org/x/tools/go/packages. package importer import ( @@ -79,6 +86,12 @@ func For(compiler string, lookup Lookup) types.Importer { // Default returns an Importer for the compiler that built the running binary. // If available, the result implements [types.ImporterFrom]. +// +// Default may be convenient for use in the simplest of cases, but +// most clients should instead use [ForCompiler], which accepts a +// [token.FileSet] from the caller; without it, all position +// information derived from the Importer will be incorrect and +// misleading. See also the package documentation. func Default() types.Importer { return For(runtime.Compiler, nil) } From 6fc23a3cff5e38ff72923fee50f51254dcdc6e93 Mon Sep 17 00:00:00 2001 From: Roland Shoemaker Date: Tue, 21 Jan 2025 16:03:14 -0800 Subject: [PATCH 160/397] crypto/internal/fips140/nistec: make p256NegCond constant time on ppc64le Remove the branching instruction from p256NegCond which made it variable time. The technique used matches that used in p256MovCond. Fixes #71383 Fixes CVE-2025-22866 Change-Id: Ibc2a46814d856cbbdaf6cc0c5a415ed5d42ca793 Reviewed-on: https://go-review.googlesource.com/c/go/+/643735 Reviewed-by: David Chase Reviewed-by: Filippo Valsorda Reviewed-by: Paul Murphy LUCI-TryBot-Result: Go LUCI --- .../fips140/nistec/p256_asm_ppc64le.s | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/crypto/internal/fips140/nistec/p256_asm_ppc64le.s b/src/crypto/internal/fips140/nistec/p256_asm_ppc64le.s index 7c46b268ef7571..7efaa6ac187ad7 100644 --- a/src/crypto/internal/fips140/nistec/p256_asm_ppc64le.s +++ b/src/crypto/internal/fips140/nistec/p256_asm_ppc64le.s @@ -126,14 +126,23 @@ GLOBL p256mul<>(SB), 8, $160 #define PH V31 #define CAR1 V6 + +#define SEL V8 +#define ZER V9 + // func p256NegCond(val *p256Point, cond int) TEXT ·p256NegCond(SB), NOSPLIT, $0-16 MOVD val+0(FP), P1ptr MOVD $16, R16 - MOVD cond+8(FP), R6 - CMP $0, R6 - BC 12, 2, LR // just return if cond == 0 + // Copy cond into SEL (cond is R1 + 8 (cond offset) + 32) + MOVD $40, R17 + LXVDSX (R1)(R17), SEL + // Zeroize ZER + VSPLTISB $0, ZER + // SEL controls whether to return the original value (Y1H/Y1L) + // or the negated value (T1H/T1L). + VCMPEQUD SEL, ZER, SEL MOVD $p256mul<>+0x00(SB), CPOOL @@ -150,6 +159,9 @@ TEXT ·p256NegCond(SB), NOSPLIT, $0-16 VSUBUQM PL, Y1L, T1L // subtract part2 giving result VSUBEUQM PH, Y1H, CAR1, T1H // subtract part1 using carry from part2 + VSEL T1H, Y1H, SEL, T1H + VSEL T1L, Y1L, SEL, T1L + XXPERMDI T1H, T1H, $2, T1H XXPERMDI T1L, T1L, $2, T1L @@ -166,6 +178,8 @@ TEXT ·p256NegCond(SB), NOSPLIT, $0-16 #undef PL #undef PH #undef CAR1 +#undef SEL +#undef ZER #define P3ptr R3 #define P1ptr R4 From 5a46b17b5f62616bdbc973bbd6a221edc02a0619 Mon Sep 17 00:00:00 2001 From: Carlos Amedee Date: Fri, 3 Jan 2025 16:53:32 -0500 Subject: [PATCH 161/397] os: force a goroutine to be scheduled on WASM The TestRootConcurrentClose test can fail when GOARCH=WASM because of goroutine starvation. The spawned goroutine will sometimes run in a loop and never have the main goroutine be scheduled. This causes the test to fail due to a timeout. This change forces the goroutine to be scheduled with each iteration of the loop when GOARCH=WASM. For #71134 Fixes #71117 Change-Id: I4fb68907c9ac3b33bd0572d5e5db2974a3379191 Reviewed-on: https://go-review.googlesource.com/c/go/+/640195 Reviewed-by: Michael Knyszek Reviewed-by: Cherry Mui LUCI-TryBot-Result: Go LUCI Auto-Submit: Carlos Amedee --- src/os/root_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/os/root_test.go b/src/os/root_test.go index b461ee220804f9..cbb985b2ceeb48 100644 --- a/src/os/root_test.go +++ b/src/os/root_test.go @@ -1077,6 +1077,10 @@ func TestRootConcurrentClose(t *testing.T) { first = false } f.Close() + if runtime.GOARCH == "wasm" { + // TODO(go.dev/issue/71134) can lead to goroutine starvation. + runtime.Gosched() + } } }() if err := <-ch; err != nil { From 9d21ef3bd43acedfe5317184e63cc6b3dd19cbdf Mon Sep 17 00:00:00 2001 From: Carlos Amedee Date: Tue, 21 Jan 2025 11:52:41 -0500 Subject: [PATCH 162/397] runtime: fix the equality check in AddCleanup This fixes the check that ensures that arg is not equal to ptr in AddCleanup. This also changes any use of throw to panic in AddCleanup. Fixes #71316 Change-Id: Ie5a3e0163b254dff44b7fefedf75207ba587b771 Reviewed-on: https://go-review.googlesource.com/c/go/+/643655 Reviewed-by: Cherry Mui LUCI-TryBot-Result: Go LUCI --- src/runtime/mcleanup.go | 14 +++++++------- src/runtime/mcleanup_test.go | 27 +++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/src/runtime/mcleanup.go b/src/runtime/mcleanup.go index 22d40a5e841243..972532d475c0b4 100644 --- a/src/runtime/mcleanup.go +++ b/src/runtime/mcleanup.go @@ -70,19 +70,19 @@ func AddCleanup[T, S any](ptr *T, cleanup func(S), arg S) Cleanup { // The pointer to the object must be valid. if ptr == nil { - throw("runtime.AddCleanup: ptr is nil") + panic("runtime.AddCleanup: ptr is nil") } usptr := uintptr(unsafe.Pointer(ptr)) // Check that arg is not equal to ptr. - // TODO(67535) this does not cover the case where T and *S are the same - // type and ptr and arg are equal. - if unsafe.Pointer(&arg) == unsafe.Pointer(ptr) { - throw("runtime.AddCleanup: ptr is equal to arg, cleanup will never run") + if kind := abi.TypeOf(arg).Kind(); kind == abi.Pointer || kind == abi.UnsafePointer { + if unsafe.Pointer(ptr) == *((*unsafe.Pointer)(unsafe.Pointer(&arg))) { + panic("runtime.AddCleanup: ptr is equal to arg, cleanup will never run") + } } if inUserArenaChunk(usptr) { // Arena-allocated objects are not eligible for cleanup. - throw("runtime.AddCleanup: ptr is arena-allocated") + panic("runtime.AddCleanup: ptr is arena-allocated") } if debug.sbrk != 0 { // debug.sbrk never frees memory, so no cleanup will ever run @@ -105,7 +105,7 @@ func AddCleanup[T, S any](ptr *T, cleanup func(S), arg S) Cleanup { // Cleanup is a noop. return Cleanup{} } - throw("runtime.AddCleanup: ptr not in allocated block") + panic("runtime.AddCleanup: ptr not in allocated block") } // Ensure we have a finalizer processing goroutine running. diff --git a/src/runtime/mcleanup_test.go b/src/runtime/mcleanup_test.go index 8c2d1f06477fdd..d62356feefb049 100644 --- a/src/runtime/mcleanup_test.go +++ b/src/runtime/mcleanup_test.go @@ -269,3 +269,30 @@ func TestCleanupStopAfterCleanupRuns(t *testing.T) { <-ch stop() } + +func TestCleanupPointerEqualsArg(t *testing.T) { + // See go.dev/issue/71316 + defer func() { + want := "runtime.AddCleanup: ptr is equal to arg, cleanup will never run" + if r := recover(); r == nil { + t.Error("want panic, test did not panic") + } else if r == want { + // do nothing + } else { + t.Errorf("wrong panic: want=%q, got=%q", want, r) + } + }() + + // allocate struct with pointer to avoid hitting tinyalloc. + // Otherwise we can't be sure when the allocation will + // be freed. + type T struct { + v int + p unsafe.Pointer + } + v := &new(T).v + *v = 97531 + runtime.AddCleanup(v, func(x *int) {}, v) + v = nil + runtime.GC() +} From 608acff8479640b00c85371d91280b64f5ec9594 Mon Sep 17 00:00:00 2001 From: Alan Donovan Date: Wed, 22 Jan 2025 10:43:44 -0500 Subject: [PATCH 163/397] go/types: avoid importer.Default It uses a throwaway FileSet, so all position info is wrong, and potentially misleading. (Various other helpers in go/types testing also use a throwaway FileSet, and should really accept it as a parameter.) Fixes #71272 Change-Id: I9d899b987837b4041a299aad5ec266cb4f5d125c Reviewed-on: https://go-review.googlesource.com/c/go/+/643777 LUCI-TryBot-Result: Go LUCI Reviewed-by: Robert Griesemer Auto-Submit: Alan Donovan --- src/go/types/api_test.go | 10 ++++++++-- src/go/types/check_test.go | 3 +-- src/go/types/eval_test.go | 5 ++--- src/go/types/example_test.go | 5 ++--- src/go/types/issues_test.go | 9 ++++++--- src/go/types/lookup_test.go | 3 +-- src/go/types/mono_test.go | 3 +-- src/go/types/resolver_test.go | 6 +++--- src/go/types/self_test.go | 5 ++--- src/go/types/sizes_test.go | 14 ++++++++++---- 10 files changed, 36 insertions(+), 27 deletions(-) diff --git a/src/go/types/api_test.go b/src/go/types/api_test.go index b686578b38278a..27b4ab8ea00413 100644 --- a/src/go/types/api_test.go +++ b/src/go/types/api_test.go @@ -19,11 +19,16 @@ import ( "testing" . "go/types" + "runtime" ) // nopos indicates an unknown position var nopos token.Pos +func defaultImporter(fset *token.FileSet) Importer { + return importer.ForCompiler(fset, runtime.Compiler, nil) +} + func mustParse(fset *token.FileSet, src string) *ast.File { f, err := parser.ParseFile(fset, pkgName(src), src, parser.ParseComments) if err != nil { @@ -33,12 +38,13 @@ func mustParse(fset *token.FileSet, src string) *ast.File { } func typecheck(src string, conf *Config, info *Info) (*Package, error) { + // TODO(adonovan): plumb this from caller. fset := token.NewFileSet() f := mustParse(fset, src) if conf == nil { conf = &Config{ Error: func(err error) {}, // collect all errors - Importer: importer.Default(), + Importer: defaultImporter(fset), } } return conf.Check(f.Name.Name, fset, []*ast.File{f}, info) @@ -1128,7 +1134,7 @@ var ( Implicits: make(map[ast.Node]Object), } var conf Config - conf.Importer = importer.Default() + conf.Importer = defaultImporter(fset) _, err := conf.Check("p", fset, []*ast.File{f}, &info) if err != nil { t.Fatal(err) diff --git a/src/go/types/check_test.go b/src/go/types/check_test.go index a10d0147da2c65..823525828ae3e4 100644 --- a/src/go/types/check_test.go +++ b/src/go/types/check_test.go @@ -34,7 +34,6 @@ import ( "flag" "fmt" "go/ast" - "go/importer" "go/parser" "go/scanner" "go/token" @@ -164,7 +163,7 @@ func testFilesImpl(t *testing.T, filenames []string, srcs [][]byte, manual bool, // set up typechecker var conf Config *boolFieldAddr(&conf, "_Trace") = manual && testing.Verbose() - conf.Importer = importer.Default() + conf.Importer = defaultImporter(fset) conf.Error = func(err error) { if *haltOnError { defer panic(err) diff --git a/src/go/types/eval_test.go b/src/go/types/eval_test.go index b9afb9117f80c1..49d901f6924b69 100644 --- a/src/go/types/eval_test.go +++ b/src/go/types/eval_test.go @@ -9,7 +9,6 @@ package types_test import ( "fmt" "go/ast" - "go/importer" "go/parser" "go/token" "go/types" @@ -188,7 +187,7 @@ func TestEvalPos(t *testing.T) { files = append(files, file) } - conf := Config{Importer: importer.Default()} + conf := Config{Importer: defaultImporter(fset)} pkg, err := conf.Check("p", fset, files, nil) if err != nil { t.Fatal(err) @@ -257,7 +256,7 @@ func f(a int, s string) S { t.Fatal(err) } - conf := Config{Importer: importer.Default()} + conf := Config{Importer: defaultImporter(fset)} pkg, err := conf.Check("p", fset, []*ast.File{f}, nil) if err != nil { t.Fatal(err) diff --git a/src/go/types/example_test.go b/src/go/types/example_test.go index 279771121aaaae..d8e5de7476c81b 100644 --- a/src/go/types/example_test.go +++ b/src/go/types/example_test.go @@ -19,7 +19,6 @@ import ( "fmt" "go/ast" "go/format" - "go/importer" "go/parser" "go/token" "go/types" @@ -57,7 +56,7 @@ func Unused() { {}; {{ var x int; _ = x }} } // make sure empty block scopes get // Type-check a package consisting of these files. // Type information for the imported "fmt" package // comes from $GOROOT/pkg/$GOOS_$GOOARCH/fmt.a. - conf := types.Config{Importer: importer.Default()} + conf := types.Config{Importer: defaultImporter(fset)} pkg, err := conf.Check("temperature", fset, files, nil) if err != nil { log.Fatal(err) @@ -126,7 +125,7 @@ type I interface { m() byte } // Type-check a package consisting of this file. // Type information for the imported packages // comes from $GOROOT/pkg/$GOOS_$GOOARCH/fmt.a. - conf := types.Config{Importer: importer.Default()} + conf := types.Config{Importer: defaultImporter(fset)} pkg, err := conf.Check("temperature", fset, []*ast.File{f}, nil) if err != nil { log.Fatal(err) diff --git a/src/go/types/issues_test.go b/src/go/types/issues_test.go index 3eb34cf2d0dee5..f2c63f16f9aba6 100644 --- a/src/go/types/issues_test.go +++ b/src/go/types/issues_test.go @@ -9,7 +9,6 @@ package types_test import ( "fmt" "go/ast" - "go/importer" "go/parser" "go/token" "internal/testenv" @@ -291,7 +290,7 @@ func TestIssue25627(t *testing.T) { } { f := mustParse(fset, prefix+src) - cfg := Config{Importer: importer.Default(), Error: func(err error) {}} + cfg := Config{Importer: defaultImporter(fset), Error: func(err error) {}} info := &Info{Types: make(map[ast.Expr]TypeAndValue)} _, err := cfg.Check(f.Name.Name, fset, []*ast.File{f}, info) if err != nil { @@ -595,7 +594,11 @@ var _ T = template /* ERRORx "cannot use.*text/template.* as T value" */.Templat ) a := mustTypecheck(asrc, nil, nil) - imp := importHelper{pkg: a, fallback: importer.Default()} + imp := importHelper{ + pkg: a, + // TODO(adonovan): use same FileSet as mustTypecheck. + fallback: defaultImporter(token.NewFileSet()), + } withImporter := func(cfg *Config) { cfg.Importer = imp diff --git a/src/go/types/lookup_test.go b/src/go/types/lookup_test.go index d3ca58b9fa16f2..e90a2ec89a32db 100644 --- a/src/go/types/lookup_test.go +++ b/src/go/types/lookup_test.go @@ -5,7 +5,6 @@ package types_test import ( - "go/importer" "go/token" "path/filepath" "runtime" @@ -28,7 +27,7 @@ func BenchmarkLookupFieldOrMethod(b *testing.B) { } conf := Config{ - Importer: importer.Default(), + Importer: defaultImporter(fset), } pkg, err := conf.Check("http", fset, files, nil) diff --git a/src/go/types/mono_test.go b/src/go/types/mono_test.go index ccab846c6dd6e3..d1f19ac5582fa1 100644 --- a/src/go/types/mono_test.go +++ b/src/go/types/mono_test.go @@ -7,7 +7,6 @@ package types_test import ( "errors" "fmt" - "go/importer" "go/types" "strings" "testing" @@ -19,7 +18,7 @@ func checkMono(t *testing.T, body string) error { var buf strings.Builder conf := types.Config{ Error: func(err error) { fmt.Fprintln(&buf, err) }, - Importer: importer.Default(), + Importer: defaultImporter(fset), // TODO(adonovan): use same FileSet as typecheck } typecheck(src, &conf, nil) if buf.Len() == 0 { diff --git a/src/go/types/resolver_test.go b/src/go/types/resolver_test.go index a83f1344de91c0..680ee69c97f4cc 100644 --- a/src/go/types/resolver_test.go +++ b/src/go/types/resolver_test.go @@ -7,7 +7,6 @@ package types_test import ( "fmt" "go/ast" - "go/importer" "go/token" "internal/testenv" "slices" @@ -17,6 +16,7 @@ import ( ) type resolveTestImporter struct { + fset *token.FileSet importer ImporterFrom imported map[string]bool } @@ -30,7 +30,7 @@ func (imp *resolveTestImporter) ImportFrom(path, srcDir string, mode ImportMode) panic("mode must be 0") } if imp.importer == nil { - imp.importer = importer.Default().(ImporterFrom) + imp.importer = defaultImporter(fset).(ImporterFrom) imp.imported = make(map[string]bool) } pkg, err := imp.importer.ImportFrom(path, srcDir, mode) @@ -124,7 +124,7 @@ func TestResolveIdents(t *testing.T) { } // resolve and type-check package AST - importer := new(resolveTestImporter) + importer := &resolveTestImporter{fset: fset} conf := Config{Importer: importer} uses := make(map[*ast.Ident]Object) defs := make(map[*ast.Ident]Object) diff --git a/src/go/types/self_test.go b/src/go/types/self_test.go index 27fa75652a5204..b4cc6286a18f81 100644 --- a/src/go/types/self_test.go +++ b/src/go/types/self_test.go @@ -6,7 +6,6 @@ package types_test import ( "go/ast" - "go/importer" "go/parser" "go/token" "internal/testenv" @@ -27,7 +26,7 @@ func TestSelf(t *testing.T) { t.Fatal(err) } - conf := Config{Importer: importer.Default()} + conf := Config{Importer: defaultImporter(fset)} _, err = conf.Check("go/types", fset, files, nil) if err != nil { t.Fatal(err) @@ -82,7 +81,7 @@ func runbench(b *testing.B, path string, ignoreFuncBodies, writeInfo bool) { for i := 0; i < b.N; i++ { conf := Config{ IgnoreFuncBodies: ignoreFuncBodies, - Importer: importer.Default(), + Importer: defaultImporter(fset), } var info *Info if writeInfo { diff --git a/src/go/types/sizes_test.go b/src/go/types/sizes_test.go index 825bc1f9f52ada..157faf87d4c575 100644 --- a/src/go/types/sizes_test.go +++ b/src/go/types/sizes_test.go @@ -8,7 +8,7 @@ package types_test import ( "go/ast" - "go/importer" + "go/token" "go/types" "internal/testenv" "testing" @@ -87,7 +87,8 @@ const _ = unsafe.Offsetof(struct{ x int64 }{}.x) ` info := types.Info{Types: make(map[ast.Expr]types.TypeAndValue)} conf := types.Config{ - Importer: importer.Default(), + // TODO(adonovan): use same FileSet as mustTypecheck. + Importer: defaultImporter(token.NewFileSet()), Sizes: &types.StdSizes{WordSize: 8, MaxAlign: 8}, } mustTypecheck(src, &conf, &info) @@ -117,7 +118,8 @@ var s struct { for _, arch := range []string{"386", "amd64"} { t.Run(arch, func(t *testing.T) { conf := types.Config{ - Importer: importer.Default(), + // TODO(adonovan): use same FileSet as findStructTypeConfig. + Importer: defaultImporter(token.NewFileSet()), Sizes: types.SizesFor("gc", arch), } ts := findStructTypeConfig(t, src, &conf) @@ -188,7 +190,11 @@ func TestGCSizes(t *testing.T) { tc := tc t.Run(tc.name, func(t *testing.T) { t.Parallel() - conf := types.Config{Importer: importer.Default(), Sizes: types.SizesFor("gc", "amd64")} + conf := types.Config{ + // TODO(adonovan): use same FileSet as mustTypecheck. + Importer: defaultImporter(token.NewFileSet()), + Sizes: types.SizesFor("gc", "amd64"), + } mustTypecheck(tc.src, &conf, nil) }) } From e2e700f8b174f34b44c32d7e923ffe4e7219e171 Mon Sep 17 00:00:00 2001 From: Roland Shoemaker Date: Fri, 24 Jan 2025 12:21:36 -0800 Subject: [PATCH 164/397] crypto/internal/boring: keep ECDH public key alive during cgo calls This prevents a possible use-after-free. Change-Id: I02488206660d38cac5ebf2f11009907ae8f22157 Reviewed-on: https://go-review.googlesource.com/c/go/+/644119 LUCI-TryBot-Result: Go LUCI Reviewed-by: Filippo Valsorda Reviewed-by: David Chase --- src/crypto/internal/boring/ecdh.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/crypto/internal/boring/ecdh.go b/src/crypto/internal/boring/ecdh.go index b90e533e7cc38c..ff29eb17b11344 100644 --- a/src/crypto/internal/boring/ecdh.go +++ b/src/crypto/internal/boring/ecdh.go @@ -138,6 +138,15 @@ func pointBytesECDH(curve string, group *C.GO_EC_GROUP, pt *C.GO_EC_POINT) ([]by } func ECDH(priv *PrivateKeyECDH, pub *PublicKeyECDH) ([]byte, error) { + // Make sure priv and pub are not garbage collected while we are in a cgo + // call. + // + // The call to xCoordBytesECDH should prevent priv from being collected, but + // include this in case the code is reordered and there is a subsequent call + // cgo call after that point. + defer runtime.KeepAlive(priv) + defer runtime.KeepAlive(pub) + group := C._goboringcrypto_EC_KEY_get0_group(priv.key) if group == nil { return nil, fail("EC_KEY_get0_group") From 475e08349d48b172285fc8629ef1622136ee8173 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Mon, 27 Jan 2025 09:11:36 -0800 Subject: [PATCH 165/397] Revert "runtime: Check LSE support on ARM64 at runtime init" This reverts CL 610195. Reason for revert: SIGILL on macOS. See issue #71411. Updates #69124, #60905. Fixes #71411. Change-Id: Ie0624e516dfb32fb13563327bcd7f557e5cba940 Reviewed-on: https://go-review.googlesource.com/c/go/+/644695 LUCI-TryBot-Result: Go LUCI Reviewed-by: Keith Randall Reviewed-by: Keith Randall Reviewed-by: Mauri de Souza Meneguzzo --- src/runtime/asm_arm64.s | 37 ------------------------------------- 1 file changed, 37 deletions(-) diff --git a/src/runtime/asm_arm64.s b/src/runtime/asm_arm64.s index 88bfd3ce5c3fa5..64a1880589390d 100644 --- a/src/runtime/asm_arm64.s +++ b/src/runtime/asm_arm64.s @@ -8,11 +8,6 @@ #include "funcdata.h" #include "textflag.h" -#ifdef GOARM64_LSE -DATA no_lse_msg<>+0x00(SB)/64, $"This program can only run on ARM64 processors with LSE support.\n" -GLOBL no_lse_msg<>(SB), RODATA, $64 -#endif - TEXT runtime·rt0_go(SB),NOSPLIT|TOPFRAME,$0 // SP = stack; R0 = argc; R1 = argv @@ -82,21 +77,6 @@ nocgo: BL runtime·wintls(SB) #endif - // Check that CPU we use for execution supports instructions targeted during compile-time. -#ifdef GOARM64_LSE -#ifndef GOOS_openbsd - // Read the ID_AA64ISAR0_EL1 register - MRS ID_AA64ISAR0_EL1, R0 - - // Extract the LSE field (bits [23:20]) - LSR $20, R0, R0 - AND $0xf, R0, R0 - - // LSE support is indicated by a non-zero value - CBZ R0, no_lse -#endif -#endif - MOVW 8(RSP), R0 // copy argc MOVW R0, -8(RSP) MOVD 16(RSP), R0 // copy argv @@ -115,23 +95,6 @@ nocgo: // start this M BL runtime·mstart(SB) - RET - -#ifdef GOARM64_LSE -#ifndef GOOS_openbsd -no_lse: - MOVD $1, R0 // stderr - MOVD R0, 8(RSP) - MOVD $no_lse_msg<>(SB), R1 // message address - MOVD R1, 16(RSP) - MOVD $64, R2 // message length - MOVD R2, 24(RSP) - CALL runtime·write(SB) - CALL runtime·exit(SB) - CALL runtime·abort(SB) - RET -#endif -#endif // Prevent dead-code elimination of debugCallV2 and debugPinnerV1, which are // intended to be called by debuggers. From f70aa3824b637d69aaaa944b3e4691c1fbe6c0d4 Mon Sep 17 00:00:00 2001 From: Sam Thanawalla Date: Thu, 23 Jan 2025 19:35:34 +0000 Subject: [PATCH 166/397] cmd/go: do not call base.fatal for an unset HOME for GOAUTH=netrc This CL silences errors caused by GOAUTH=netrc and HOME being unset. Instead, we log the error if the -x flag is set. Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest,gotip-windows-amd64-longtest Change-Id: Ibd323769f3562c169ebf559e060e9afbb63047bc Reviewed-on: https://go-review.googlesource.com/c/go/+/643917 Reviewed-by: Michael Matloob LUCI-TryBot-Result: Go LUCI --- src/cmd/go/internal/auth/auth.go | 3 ++- src/cmd/go/testdata/script/goauth_netrc.txt | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/cmd/go/internal/auth/auth.go b/src/cmd/go/internal/auth/auth.go index bd80222427ae36..79e0d8b5e8f2f6 100644 --- a/src/cmd/go/internal/auth/auth.go +++ b/src/cmd/go/internal/auth/auth.go @@ -70,7 +70,8 @@ func runGoAuth(client *http.Client, res *http.Response, url string) { case "netrc": lines, err := readNetrc() if err != nil { - base.Fatalf("go: could not parse netrc (GOAUTH=%s): %v", cfg.GOAUTH, err) + cmdErrs = append(cmdErrs, fmt.Errorf("GOAUTH=%s: %v", command, err)) + continue } // Process lines in reverse so that if the same machine is listed // multiple times, we end up saving the earlier one diff --git a/src/cmd/go/testdata/script/goauth_netrc.txt b/src/cmd/go/testdata/script/goauth_netrc.txt index 26e03f8968c5b3..0baa09de1ecaf9 100644 --- a/src/cmd/go/testdata/script/goauth_netrc.txt +++ b/src/cmd/go/testdata/script/goauth_netrc.txt @@ -53,6 +53,19 @@ go get vcs-test.golang.org/auth/or401 env NETRC=$WORK/missing ! go get vcs-test.golang.org/auth/or401 stderr '^\tserver response: ACCESS DENIED, buddy$' + +[short] skip 'requires a remote vcs lookup' +[!git] skip +# An unset home directory should warn the user but not cause a failure. +env NETRC= +env HOME= +env USERPROFILE= +env home= +go get -x vcs-test.golang.org/git/emptytest.git +[!GOOS:windows] [!GOOS:plan9] stderr 'GOAUTH=netrc: \$HOME is not defined' +[GOOS:windows] stderr 'GOAUTH=netrc: \%userprofile\% is not defined' +[GOOS:plan9] stderr 'GOAUTH=netrc: \$home is not defined' + -- go.mod -- module private.example.com -- $WORK/empty -- From e0aeee82f3ab81b2a2ac77b352be52d13030820e Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Mon, 27 Jan 2025 19:56:42 +0100 Subject: [PATCH 167/397] crypto/ecdsa: avoid needless ScalarBaseMult in s390x We are running the (slow on s390x) ScalarBaseMult and then discarding the point because we are reusing randomPoint. Copied the function 1:1 removing the point computation. Change-Id: I6a6a46561633ab3bbbaef804481f6c5da15fe2fa Reviewed-on: https://go-review.googlesource.com/c/go/+/644775 LUCI-TryBot-Result: Go LUCI Reviewed-by: Roland Shoemaker Auto-Submit: Roland Shoemaker Run-TryBot: Filippo Valsorda TryBot-Result: Gopher Robot Reviewed-by: Carlos Amedee Auto-Submit: Filippo Valsorda --- .../internal/fips140/ecdsa/ecdsa_s390x.go | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/crypto/internal/fips140/ecdsa/ecdsa_s390x.go b/src/crypto/internal/fips140/ecdsa/ecdsa_s390x.go index 271a35897f8c8f..d0a49cad610c25 100644 --- a/src/crypto/internal/fips140/ecdsa/ecdsa_s390x.go +++ b/src/crypto/internal/fips140/ecdsa/ecdsa_s390x.go @@ -59,6 +59,25 @@ func hashToBytes[P Point[P]](c *Curve[P], hash []byte) []byte { return e.Bytes(c.N) } +// randomScalar is a copy of [randomPoint] that doesn't call ScalarBaseMult. +func randomScalar[P Point[P]](c *Curve[P], generate func([]byte) error) (k *bigmod.Nat, err error) { + for { + b := make([]byte, c.N.Size()) + if err := generate(b); err != nil { + return nil, err + } + if excess := len(b)*8 - c.N.BitLen(); excess > 0 { + if c.curve != p521 { + panic("ecdsa: internal error: unexpectedly masking off bits") + } + b = rightShift(b, excess) + } + if k, err := bigmod.NewNat().SetBytes(b, c.N); err == nil && k.IsZero() == 0 { + return k, nil + } + } +} + func appendBlock(p []byte, blocksize int, b []byte) []byte { if len(b) > blocksize { panic("ecdsa: internal error: appendBlock input larger than block") @@ -83,7 +102,7 @@ func sign[P Point[P]](c *Curve[P], priv *PrivateKey, drbg *hmacDRBG, hash []byte return signGeneric(c, priv, drbg, hash) } for { - k, _, err := randomPoint(c, func(b []byte) error { + k, err := randomScalar(c, func(b []byte) error { drbg.Generate(b) return nil }) From 3f791c8dfba6f946c29c01c2df257c3a4a9f1c8d Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Mon, 27 Jan 2025 14:18:02 +0100 Subject: [PATCH 168/397] crypto/internal/fips140/aes: set FIPS 140 service indicator for CTR and CBC This is a very late Go 1.24 change, but it is necessary for the frozen FIPS module, and doesn't impact anything else than the FIPS status indicator value. Change-Id: I6a6a4656f1ac94ac46d631c90a206ac8b6ddcf4c Reviewed-on: https://go-review.googlesource.com/c/go/+/644635 Auto-Submit: Roland Shoemaker Reviewed-by: Daniel McCarney Reviewed-by: Roland Shoemaker LUCI-TryBot-Result: Go LUCI Reviewed-by: Carlos Amedee Auto-Submit: Filippo Valsorda --- src/crypto/internal/fips140/aes/cbc.go | 3 +++ src/crypto/internal/fips140/aes/ctr.go | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/crypto/internal/fips140/aes/cbc.go b/src/crypto/internal/fips140/aes/cbc.go index f92af23a2a5561..a5a079453f7f4c 100644 --- a/src/crypto/internal/fips140/aes/cbc.go +++ b/src/crypto/internal/fips140/aes/cbc.go @@ -5,6 +5,7 @@ package aes import ( + "crypto/internal/fips140" "crypto/internal/fips140/alias" "crypto/internal/fips140/subtle" ) @@ -32,6 +33,7 @@ func (c *CBCEncrypter) CryptBlocks(dst, src []byte) { if alias.InexactOverlap(dst[:len(src)], src) { panic("crypto/cipher: invalid buffer overlap") } + fips140.RecordApproved() if len(src) == 0 { return } @@ -85,6 +87,7 @@ func (c *CBCDecrypter) CryptBlocks(dst, src []byte) { if alias.InexactOverlap(dst[:len(src)], src) { panic("crypto/cipher: invalid buffer overlap") } + fips140.RecordApproved() if len(src) == 0 { return } diff --git a/src/crypto/internal/fips140/aes/ctr.go b/src/crypto/internal/fips140/aes/ctr.go index 2b0ee44cddb66c..2e55d233d3a767 100644 --- a/src/crypto/internal/fips140/aes/ctr.go +++ b/src/crypto/internal/fips140/aes/ctr.go @@ -5,6 +5,7 @@ package aes import ( + "crypto/internal/fips140" "crypto/internal/fips140/alias" "crypto/internal/fips140/subtle" "crypto/internal/fips140deps/byteorder" @@ -71,6 +72,7 @@ func (c *CTR) XORKeyStreamAt(dst, src []byte, offset uint64) { if alias.InexactOverlap(dst, src) { panic("crypto/aes: invalid buffer overlap") } + fips140.RecordApproved() ivlo, ivhi := add128(c.ivlo, c.ivhi, offset/BlockSize) From b9872221cd024bae5239c001b351a84d32db7bf7 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Mon, 27 Jan 2025 14:21:43 +0100 Subject: [PATCH 169/397] crypto/internal/fips140/rsa: avoid CAST unsetting the service indicator Without fipsApproved set, when the CAST runs it sets the service indicator to false for the whole span. This is a very late Go 1.24 change, but it is necessary for the frozen FIPS module, and doesn't impact anything else than the FIPS status indicator value. Change-Id: I6a6a46567818135158c3c252b5480431a190572b Reviewed-on: https://go-review.googlesource.com/c/go/+/644636 Auto-Submit: Roland Shoemaker LUCI-TryBot-Result: Go LUCI Reviewed-by: Roland Shoemaker Auto-Submit: Filippo Valsorda Reviewed-by: Carlos Amedee Reviewed-by: Daniel McCarney --- src/crypto/internal/fips140/rsa/cast.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/crypto/internal/fips140/rsa/cast.go b/src/crypto/internal/fips140/rsa/cast.go index ec7b5f3aeb9275..b900b32c888641 100644 --- a/src/crypto/internal/fips140/rsa/cast.go +++ b/src/crypto/internal/fips140/rsa/cast.go @@ -171,6 +171,7 @@ func testPrivateKey() *PrivateKey { N: N, E: 65537, }, d: d, p: p, q: q, qInv: qInv, dP: dP, dQ: dQ, + fipsApproved: true, } } From 11e08d9d96fa13346d50b5f728058f2f2647664a Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 13 Jan 2025 10:28:19 -0800 Subject: [PATCH 170/397] strconv: adjust comment so that gofmt doesn't mung it Change-Id: I7fe5c6a0521d3c597eae0f3568942df1db9370b1 Reviewed-on: https://go-review.googlesource.com/c/go/+/642497 LUCI-TryBot-Result: Go LUCI Auto-Submit: Ian Lance Taylor Reviewed-by: Robert Griesemer Reviewed-by: Ian Lance Taylor --- src/strconv/quote.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/strconv/quote.go b/src/strconv/quote.go index 1f4929a952c6bf..99c292a8ed5884 100644 --- a/src/strconv/quote.go +++ b/src/strconv/quote.go @@ -378,7 +378,8 @@ func QuotedPrefix(s string) (string, error) { // or backquoted Go string literal, returning the string value // that s quotes. (If s is single-quoted, it would be a Go // character literal; Unquote returns the corresponding -// one-character string. For '' Unquote returns the empty string.) +// one-character string. For an empty character literal +// Unquote returns the empty string.) func Unquote(s string) (string, error) { out, rem, err := unquote(s, true) if len(rem) > 0 { From f8937cb6255970de3f0c8cbccc5253ae81249c47 Mon Sep 17 00:00:00 2001 From: yincong Date: Wed, 22 Jan 2025 02:23:08 +0000 Subject: [PATCH 171/397] archive/zip, archive/tar: writer appends slash to directory names Fixes #71235 Change-Id: I62aebb9d421db0e4b57ad5cae25c70f47aa5f8f9 GitHub-Last-Rev: 6e0fba07dd128e20e32a3a6258edf80ee91d4690 GitHub-Pull-Request: golang/go#71239 Reviewed-on: https://go-review.googlesource.com/c/go/+/642375 Reviewed-by: Jonathan Amsterdam LUCI-TryBot-Result: Go LUCI Reviewed-by: Ian Lance Taylor Auto-Submit: Ian Lance Taylor Commit-Queue: Ian Lance Taylor --- src/archive/tar/writer.go | 3 +++ src/archive/tar/writer_test.go | 6 +++++- src/archive/zip/writer.go | 3 +++ src/archive/zip/writer_test.go | 5 ++++- 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/archive/tar/writer.go b/src/archive/tar/writer.go index 059669767f2b9d..f966c5b4c648f5 100644 --- a/src/archive/tar/writer.go +++ b/src/archive/tar/writer.go @@ -424,6 +424,9 @@ func (tw *Writer) AddFS(fsys fs.FS) error { return err } h.Name = name + if d.IsDir() { + h.Name += "/" + } if err := tw.WriteHeader(h); err != nil { return err } diff --git a/src/archive/tar/writer_test.go b/src/archive/tar/writer_test.go index 2a01915d368c5a..7b10bf6a700d7f 100644 --- a/src/archive/tar/writer_test.go +++ b/src/archive/tar/writer_test.go @@ -1382,7 +1382,11 @@ func TestWriterAddFS(t *testing.T) { t.Fatal(err) } - if hdr.Name != name { + tmpName := name + if entryInfo.IsDir() { + tmpName += "/" + } + if hdr.Name != tmpName { t.Errorf("test fs has filename %v; archive header has %v", name, hdr.Name) } diff --git a/src/archive/zip/writer.go b/src/archive/zip/writer.go index cbe5ba262747f6..0a310054e37678 100644 --- a/src/archive/zip/writer.go +++ b/src/archive/zip/writer.go @@ -520,6 +520,9 @@ func (w *Writer) AddFS(fsys fs.FS) error { return err } h.Name = name + if d.IsDir() { + h.Name += "/" + } h.Method = Deflate fw, err := w.CreateHeader(h) if err != nil { diff --git a/src/archive/zip/writer_test.go b/src/archive/zip/writer_test.go index 27a99b6b3a13b9..44592ce8318826 100644 --- a/src/archive/zip/writer_test.go +++ b/src/archive/zip/writer_test.go @@ -633,7 +633,7 @@ func TestWriterAddFS(t *testing.T) { t.Fatal(err) } - // Add subfolder into fsys to match what we'll read from the tar. + // Add subfolder into fsys to match what we'll read from the zip. tests = append(tests[:2:2], WriteTest{Name: "subfolder", Mode: 0o555 | os.ModeDir}, tests[2]) // read it back @@ -642,6 +642,9 @@ func TestWriterAddFS(t *testing.T) { t.Fatal(err) } for i, wt := range tests { + if wt.Mode.IsDir() { + wt.Name += "/" + } testReadFile(t, r.File[i], &wt) } } From 4ebd5bf85594f97ae8ea1aa8f08125f41a110b87 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 27 Jan 2025 20:41:55 -0800 Subject: [PATCH 172/397] internal/goexperiment: update location of baseline experiment in comment It moved in CL 310731. Change-Id: I97340848b55e327d3b25949ec3850aec33448bbe Reviewed-on: https://go-review.googlesource.com/c/go/+/644955 Reviewed-by: Carlos Amedee LUCI-TryBot-Result: Go LUCI Reviewed-by: Michael Knyszek Auto-Submit: Ian Lance Taylor --- src/internal/goexperiment/flags.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/internal/goexperiment/flags.go b/src/internal/goexperiment/flags.go index 31b3d0315b64f8..948ed5c802801c 100644 --- a/src/internal/goexperiment/flags.go +++ b/src/internal/goexperiment/flags.go @@ -51,7 +51,7 @@ package goexperiment // tags, experiments use the strings.ToLower of their field name. // // For the baseline experimental configuration, see -// objabi.experimentBaseline. +// [internal/buildcfg.ParseGOEXPERIMENT]. // // If you change this struct definition, run "go generate". type Flags struct { From 78e6f2a1c87df4d588b11b51da63a974ade0ca79 Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Fri, 24 Jan 2025 13:34:26 -0500 Subject: [PATCH 173/397] runtime: rename mapiterinit and mapiternext mapiterinit allows external linkname. These users must allocate their own iter struct for initialization by mapiterinit. Since the type is unexported, they also must define the struct themselves. As a result, they of course define the struct matching the old hiter definition (in map_noswiss.go). The old definition is smaller on 32-bit platforms. On those platforms, mapiternext will clobber memory outside of the caller's allocation. On all platforms, the pointer layout between the old hiter and new maps.Iter does not match. Thus the GC may miss pointers and free reachable objects early, or it may see non-pointers that look like heap pointers and throw due to invalid references to free objects. To avoid these issues, we must keep mapiterinit and mapiternext with the old hiter definition. The most straightforward way to do this is to use mapiterinit and mapiternext as a compatibility layer between the old and new iter types. The first step to that is to move normal map use off of these functions, which is what this CL does. Introduce new mapIterStart and mapIterNext functions that replace the former functions everywhere in the toolchain. These have the same behavior as the old functions. This CL temporarily makes the old functions throw to ensure we don't have hidden dependencies on them. We cannot remove them entirely because GOEXPERIMENT=noswissmap still uses the old names, and internal/goobj requires all builtins to exist regardless of GOEXPERIMENT. The next CL will introduce the compatibility layer. I want to avoid using linkname between runtime and reflect, as that would also allow external linknames. So mapIterStart and mapIterNext are duplicated in reflect, which can be done trivially, as it imports internal/runtime/maps. For #71408. Change-Id: I6a6a636c6d4bd1392618c67ca648d3f061afe669 Reviewed-on: https://go-review.googlesource.com/c/go/+/643898 Auto-Submit: Michael Pratt Reviewed-by: Keith Randall LUCI-TryBot-Result: Go LUCI Reviewed-by: Keith Randall --- .../internal/typecheck/_builtin/runtime.go | 6 +- src/cmd/compile/internal/typecheck/builtin.go | 2 + src/cmd/compile/internal/walk/range.go | 9 ++- src/cmd/internal/goobj/builtinlist.go | 2 + src/reflect/map_noswiss.go | 8 +++ src/reflect/map_swiss.go | 51 +++++++++++++--- src/reflect/value.go | 6 -- src/runtime/map_swiss.go | 58 ++++++++++++------- test/codegen/maps.go | 12 ++-- test/live.go | 6 +- test/live_regabi.go | 6 +- 11 files changed, 115 insertions(+), 51 deletions(-) diff --git a/src/cmd/compile/internal/typecheck/_builtin/runtime.go b/src/cmd/compile/internal/typecheck/_builtin/runtime.go index 9a83911487830a..cf07f31e31b83e 100644 --- a/src/cmd/compile/internal/typecheck/_builtin/runtime.go +++ b/src/cmd/compile/internal/typecheck/_builtin/runtime.go @@ -152,12 +152,14 @@ func mapassign_fast32ptr(mapType *byte, hmap map[any]any, key unsafe.Pointer) (v func mapassign_fast64(mapType *byte, hmap map[any]any, key uint64) (val *any) func mapassign_fast64ptr(mapType *byte, hmap map[any]any, key unsafe.Pointer) (val *any) func mapassign_faststr(mapType *byte, hmap map[any]any, key string) (val *any) -func mapiterinit(mapType *byte, hmap map[any]any, hiter *any) +func mapiterinit(mapType *byte, hmap map[any]any, hiter *any) // old maps +func mapIterStart(mapType *byte, hmap map[any]any, hiter *any) // swiss maps func mapdelete(mapType *byte, hmap map[any]any, key *any) func mapdelete_fast32(mapType *byte, hmap map[any]any, key uint32) func mapdelete_fast64(mapType *byte, hmap map[any]any, key uint64) func mapdelete_faststr(mapType *byte, hmap map[any]any, key string) -func mapiternext(hiter *any) +func mapiternext(hiter *any) // old maps +func mapIterNext(hiter *any) // swiss maps func mapclear(mapType *byte, hmap map[any]any) // *byte is really *runtime.Type diff --git a/src/cmd/compile/internal/typecheck/builtin.go b/src/cmd/compile/internal/typecheck/builtin.go index 6860d78b2e4024..be08d0b40329a1 100644 --- a/src/cmd/compile/internal/typecheck/builtin.go +++ b/src/cmd/compile/internal/typecheck/builtin.go @@ -131,11 +131,13 @@ var runtimeDecls = [...]struct { {"mapassign_fast64ptr", funcTag, 96}, {"mapassign_faststr", funcTag, 89}, {"mapiterinit", funcTag, 97}, + {"mapIterStart", funcTag, 97}, {"mapdelete", funcTag, 97}, {"mapdelete_fast32", funcTag, 98}, {"mapdelete_fast64", funcTag, 99}, {"mapdelete_faststr", funcTag, 100}, {"mapiternext", funcTag, 101}, + {"mapIterNext", funcTag, 101}, {"mapclear", funcTag, 102}, {"makechan64", funcTag, 104}, {"makechan", funcTag, 105}, diff --git a/src/cmd/compile/internal/walk/range.go b/src/cmd/compile/internal/walk/range.go index 27e71425c1b015..a51b218ae57d20 100644 --- a/src/cmd/compile/internal/walk/range.go +++ b/src/cmd/compile/internal/walk/range.go @@ -244,19 +244,24 @@ func walkRange(nrange *ir.RangeStmt) ir.Node { // depends on layout of iterator struct. // See cmd/compile/internal/reflectdata/reflect.go:MapIterType var keysym, elemsym *types.Sym + var iterInit, iterNext string if buildcfg.Experiment.SwissMap { keysym = th.Field(0).Sym elemsym = th.Field(1).Sym // ditto + iterInit = "mapIterStart" + iterNext = "mapIterNext" } else { keysym = th.Field(0).Sym elemsym = th.Field(1).Sym // ditto + iterInit = "mapiterinit" + iterNext = "mapiternext" } - fn := typecheck.LookupRuntime("mapiterinit", t.Key(), t.Elem(), th) + fn := typecheck.LookupRuntime(iterInit, t.Key(), t.Elem(), th) init = append(init, mkcallstmt1(fn, reflectdata.RangeMapRType(base.Pos, nrange), ha, typecheck.NodAddr(hit))) nfor.Cond = ir.NewBinaryExpr(base.Pos, ir.ONE, ir.NewSelectorExpr(base.Pos, ir.ODOT, hit, keysym), typecheck.NodNil()) - fn = typecheck.LookupRuntime("mapiternext", th) + fn = typecheck.LookupRuntime(iterNext, th) nfor.Post = mkcallstmt1(fn, typecheck.NodAddr(hit)) key := ir.NewStarExpr(base.Pos, typecheck.ConvNop(ir.NewSelectorExpr(base.Pos, ir.ODOT, hit, keysym), types.NewPtr(t.Key()))) diff --git a/src/cmd/internal/goobj/builtinlist.go b/src/cmd/internal/goobj/builtinlist.go index c133c60427f598..3e550d8dd9763b 100644 --- a/src/cmd/internal/goobj/builtinlist.go +++ b/src/cmd/internal/goobj/builtinlist.go @@ -110,11 +110,13 @@ var builtins = [...]struct { {"runtime.mapassign_fast64ptr", 1}, {"runtime.mapassign_faststr", 1}, {"runtime.mapiterinit", 1}, + {"runtime.mapIterStart", 1}, {"runtime.mapdelete", 1}, {"runtime.mapdelete_fast32", 1}, {"runtime.mapdelete_fast64", 1}, {"runtime.mapdelete_faststr", 1}, {"runtime.mapiternext", 1}, + {"runtime.mapIterNext", 1}, {"runtime.mapclear", 1}, {"runtime.makechan64", 1}, {"runtime.makechan", 1}, diff --git a/src/reflect/map_noswiss.go b/src/reflect/map_noswiss.go index eb0a52a3902f6f..19696a4f4bd858 100644 --- a/src/reflect/map_noswiss.go +++ b/src/reflect/map_noswiss.go @@ -17,6 +17,14 @@ type mapType struct { abi.OldMapType } +// Pushed from runtime. + +//go:noescape +func mapiterinit(t *abi.Type, m unsafe.Pointer, it *hiter) + +//go:noescape +func mapiternext(it *hiter) + func (t *rtype) Key() Type { if t.Kind() != Map { panic("reflect: Key of non-map type " + t.String()) diff --git a/src/reflect/map_swiss.go b/src/reflect/map_swiss.go index 75dcb117dfd292..2eac51e57dba5d 100644 --- a/src/reflect/map_swiss.go +++ b/src/reflect/map_swiss.go @@ -8,14 +8,16 @@ package reflect import ( "internal/abi" + "internal/race" "internal/runtime/maps" + "internal/runtime/sys" "unsafe" ) // mapType represents a map type. -type mapType struct { - abi.SwissMapType -} +// +// TODO(prattmic): Only used within this file, could be cleaned up. +type mapType = abi.SwissMapType func (t *rtype) Key() Type { if t.Kind() != Map { @@ -176,6 +178,31 @@ func (v Value) MapIndex(key Value) Value { return copyVal(typ, fl, e) } +// Equivalent to runtime.mapIterStart. +// +//go:noinline +func mapIterStart(t *abi.SwissMapType, m *maps.Map, it *maps.Iter) { + if race.Enabled && m != nil { + callerpc := sys.GetCallerPC() + race.ReadPC(unsafe.Pointer(m), callerpc, abi.FuncPCABIInternal(mapIterStart)) + } + + it.Init(t, m) + it.Next() +} + +// Equivalent to runtime.mapIterNext. +// +//go:noinline +func mapIterNext(it *maps.Iter) { + if race.Enabled { + callerpc := sys.GetCallerPC() + race.ReadPC(unsafe.Pointer(it.Map()), callerpc, abi.FuncPCABIInternal(mapIterNext)) + } + + it.Next() +} + // MapKeys returns a slice containing all the keys present in the map, // in unspecified order. // It panics if v's Kind is not [Map]. @@ -187,13 +214,17 @@ func (v Value) MapKeys() []Value { fl := v.flag.ro() | flag(keyType.Kind()) - m := v.pointer() + // Escape analysis can't see that the map doesn't escape. It sees an + // escape from maps.IterStart, via assignment into it, even though it + // doesn't escape this function. + mptr := abi.NoEscape(v.pointer()) + m := (*maps.Map)(mptr) mlen := int(0) if m != nil { - mlen = maplen(m) + mlen = maplen(mptr) } var it maps.Iter - mapiterinit(v.typ(), m, &it) + mapIterStart(tt, m, &it) a := make([]Value, mlen) var i int for i = 0; i < len(a); i++ { @@ -205,7 +236,7 @@ func (v Value) MapKeys() []Value { break } a[i] = copyVal(keyType, fl, key) - mapiternext(&it) + mapIterNext(&it) } return a[:i] } @@ -317,12 +348,14 @@ func (iter *MapIter) Next() bool { panic("MapIter.Next called on an iterator that does not have an associated map Value") } if !iter.hiter.Initialized() { - mapiterinit(iter.m.typ(), iter.m.pointer(), &iter.hiter) + t := (*mapType)(unsafe.Pointer(iter.m.typ())) + m := (*maps.Map)(iter.m.pointer()) + mapIterStart(t, m, &iter.hiter) } else { if iter.hiter.Key() == nil { panic("MapIter.Next called on exhausted iterator") } - mapiternext(&iter.hiter) + mapIterNext(&iter.hiter) } return iter.hiter.Key() != nil } diff --git a/src/reflect/value.go b/src/reflect/value.go index 4ed94addf99a57..ba5b106c18c970 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -3603,12 +3603,6 @@ func mapdelete(t *abi.Type, m unsafe.Pointer, key unsafe.Pointer) //go:noescape func mapdelete_faststr(t *abi.Type, m unsafe.Pointer, key string) -//go:noescape -func mapiterinit(t *abi.Type, m unsafe.Pointer, it *hiter) - -//go:noescape -func mapiternext(it *hiter) - //go:noescape func maplen(m unsafe.Pointer) int diff --git a/src/runtime/map_swiss.go b/src/runtime/map_swiss.go index e6e29bcfb800bb..f4b4062dd9d44e 100644 --- a/src/runtime/map_swiss.go +++ b/src/runtime/map_swiss.go @@ -176,11 +176,21 @@ func mapdelete(t *abi.SwissMapType, m *maps.Map, key unsafe.Pointer) { // Do not remove or change the type signature. // See go.dev/issue/67401. // -//go:linkname mapiterinit +// TODO go:linkname mapiterinit func mapiterinit(t *abi.SwissMapType, m *maps.Map, it *maps.Iter) { + // N.B. This is required by the builtin list in internal/goobj because + // it is a builtin for old maps. + throw("unreachable") +} + +// mapIterStart initializes the Iter struct used for ranging over maps and +// performs the first step of iteration. The Iter struct pointed to by 'it' is +// allocated on the stack by the compilers order pass or on the heap by +// reflect. Both need to have zeroed it since the struct contains pointers. +func mapIterStart(t *abi.SwissMapType, m *maps.Map, it *maps.Iter) { if raceenabled && m != nil { callerpc := sys.GetCallerPC() - racereadpc(unsafe.Pointer(m), callerpc, abi.FuncPCABIInternal(mapiterinit)) + racereadpc(unsafe.Pointer(m), callerpc, abi.FuncPCABIInternal(mapIterStart)) } it.Init(t, m) @@ -199,11 +209,19 @@ func mapiterinit(t *abi.SwissMapType, m *maps.Map, it *maps.Iter) { // Do not remove or change the type signature. // See go.dev/issue/67401. // -//go:linkname mapiternext +// TODO go:linkname mapiternext func mapiternext(it *maps.Iter) { + // N.B. This is required by the builtin list in internal/goobj because + // it is a builtin for old maps. + throw("unreachable") +} + +// mapIterNext performs the next step of iteration. Afterwards, the next +// key/elem are in it.Key()/it.Elem(). +func mapIterNext(it *maps.Iter) { if raceenabled { callerpc := sys.GetCallerPC() - racereadpc(unsafe.Pointer(it.Map()), callerpc, abi.FuncPCABIInternal(mapiternext)) + racereadpc(unsafe.Pointer(it.Map()), callerpc, abi.FuncPCABIInternal(mapIterNext)) } it.Next() @@ -317,10 +335,10 @@ func reflect_mapdelete_faststr(t *abi.SwissMapType, m *maps.Map, key string) { // Do not remove or change the type signature. // See go.dev/issue/67401. // -//go:linkname reflect_mapiterinit reflect.mapiterinit -func reflect_mapiterinit(t *abi.SwissMapType, m *maps.Map, it *maps.Iter) { - mapiterinit(t, m, it) -} +// TODO go:linkname reflect_mapiterinit reflect.mapiterinit +//func reflect_mapiterinit(t *abi.SwissMapType, m *maps.Map, it *maps.Iter) { +// mapiterinit(t, m, it) +//} // reflect_mapiternext is for package reflect, // but widely used packages access it using linkname. @@ -334,10 +352,10 @@ func reflect_mapiterinit(t *abi.SwissMapType, m *maps.Map, it *maps.Iter) { // Do not remove or change the type signature. // See go.dev/issue/67401. // -//go:linkname reflect_mapiternext reflect.mapiternext -func reflect_mapiternext(it *maps.Iter) { - mapiternext(it) -} +// TODO go:linkname reflect_mapiternext reflect.mapiternext +//func reflect_mapiternext(it *maps.Iter) { +// mapiternext(it) +//} // reflect_mapiterkey was for package reflect, // but widely used packages access it using linkname. @@ -348,10 +366,10 @@ func reflect_mapiternext(it *maps.Iter) { // Do not remove or change the type signature. // See go.dev/issue/67401. // -//go:linkname reflect_mapiterkey reflect.mapiterkey -func reflect_mapiterkey(it *maps.Iter) unsafe.Pointer { - return it.Key() -} +// TODO go:linkname reflect_mapiterkey reflect.mapiterkey +//func reflect_mapiterkey(it *maps.Iter) unsafe.Pointer { +// return it.Key() +//} // reflect_mapiterelem was for package reflect, // but widely used packages access it using linkname. @@ -362,10 +380,10 @@ func reflect_mapiterkey(it *maps.Iter) unsafe.Pointer { // Do not remove or change the type signature. // See go.dev/issue/67401. // -//go:linkname reflect_mapiterelem reflect.mapiterelem -func reflect_mapiterelem(it *maps.Iter) unsafe.Pointer { - return it.Elem() -} +// TODO go:linkname reflect_mapiterelem reflect.mapiterelem +//func reflect_mapiterelem(it *maps.Iter) unsafe.Pointer { +// return it.Elem() +//} // reflect_maplen is for package reflect, // but widely used packages access it using linkname. diff --git a/test/codegen/maps.go b/test/codegen/maps.go index 25505799e9351d..c4aed3354514f6 100644 --- a/test/codegen/maps.go +++ b/test/codegen/maps.go @@ -74,7 +74,7 @@ func LookupStringConversionKeyedArrayLit(m map[[2]string]int, bytes []byte) int func MapClearReflexive(m map[int]int) { // amd64:`.*runtime\.mapclear` - // amd64:-`.*runtime\.mapiterinit` + // amd64:-`.*runtime\.(mapiterinit|mapIterStart)` for k := range m { delete(m, k) } @@ -83,7 +83,7 @@ func MapClearReflexive(m map[int]int) { func MapClearIndirect(m map[int]int) { s := struct{ m map[int]int }{m: m} // amd64:`.*runtime\.mapclear` - // amd64:-`.*runtime\.mapiterinit` + // amd64:-`.*runtime\.(mapiterinit|mapIterStart)` for k := range s.m { delete(s.m, k) } @@ -91,14 +91,14 @@ func MapClearIndirect(m map[int]int) { func MapClearPointer(m map[*byte]int) { // amd64:`.*runtime\.mapclear` - // amd64:-`.*runtime\.mapiterinit` + // amd64:-`.*runtime\.(mapiterinit|mapIterStart)` for k := range m { delete(m, k) } } func MapClearNotReflexive(m map[float64]int) { - // amd64:`.*runtime\.mapiterinit` + // amd64:`.*runtime\.(mapiterinit|mapIterStart)` // amd64:-`.*runtime\.mapclear` for k := range m { delete(m, k) @@ -106,7 +106,7 @@ func MapClearNotReflexive(m map[float64]int) { } func MapClearInterface(m map[interface{}]int) { - // amd64:`.*runtime\.mapiterinit` + // amd64:`.*runtime\.(mapiterinit|mapIterStart)` // amd64:-`.*runtime\.mapclear` for k := range m { delete(m, k) @@ -115,7 +115,7 @@ func MapClearInterface(m map[interface{}]int) { func MapClearSideEffect(m map[int]int) int { k := 0 - // amd64:`.*runtime\.mapiterinit` + // amd64:`.*runtime\.(mapiterinit|mapIterStart)` // amd64:-`.*runtime\.mapclear` for k = range m { delete(m, k) diff --git a/test/live.go b/test/live.go index 250a77cdac4614..c0b0fcd274a0ca 100644 --- a/test/live.go +++ b/test/live.go @@ -458,14 +458,14 @@ func f28(b bool) { func f29(b bool) { if b { - for k := range m { // ERROR "live at call to mapiterinit: .autotmp_[0-9]+$" "live at call to mapiternext: .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ (runtime.hiter|internal/runtime/maps.Iter)$" + for k := range m { // ERROR "live at call to (mapiterinit|mapIterStart): .autotmp_[0-9]+$" "live at call to (mapiternext|mapIterNext): .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ (runtime.hiter|internal/runtime/maps.Iter)$" printstring(k) // ERROR "live at call to printstring: .autotmp_[0-9]+$" } } - for k := range m { // ERROR "live at call to mapiterinit: .autotmp_[0-9]+$" "live at call to mapiternext: .autotmp_[0-9]+$" + for k := range m { // ERROR "live at call to (mapiterinit|mapIterStart): .autotmp_[0-9]+$" "live at call to (mapiternext|mapIterNext): .autotmp_[0-9]+$" printstring(k) // ERROR "live at call to printstring: .autotmp_[0-9]+$" } - for k := range m { // ERROR "live at call to mapiterinit: .autotmp_[0-9]+$" "live at call to mapiternext: .autotmp_[0-9]+$" + for k := range m { // ERROR "live at call to (mapiterinit|mapIterStart): .autotmp_[0-9]+$" "live at call to (mapiternext|mapIterNext): .autotmp_[0-9]+$" printstring(k) // ERROR "live at call to printstring: .autotmp_[0-9]+$" } } diff --git a/test/live_regabi.go b/test/live_regabi.go index 090e2ec57776fe..35f874ecc365f6 100644 --- a/test/live_regabi.go +++ b/test/live_regabi.go @@ -456,14 +456,14 @@ func f28(b bool) { func f29(b bool) { if b { - for k := range m { // ERROR "live at call to mapiterinit: .autotmp_[0-9]+$" "live at call to mapiternext: .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ (runtime.hiter|internal/runtime/maps.Iter)$" + for k := range m { // ERROR "live at call to (mapiterinit|mapIterStart): .autotmp_[0-9]+$" "live at call to (mapiternext|mapIterNext): .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ (runtime.hiter|internal/runtime/maps.Iter)$" printstring(k) // ERROR "live at call to printstring: .autotmp_[0-9]+$" } } - for k := range m { // ERROR "live at call to mapiterinit: .autotmp_[0-9]+$" "live at call to mapiternext: .autotmp_[0-9]+$" + for k := range m { // ERROR "live at call to (mapiterinit|mapIterStart): .autotmp_[0-9]+$" "live at call to (mapiternext|mapIterNext): .autotmp_[0-9]+$" printstring(k) // ERROR "live at call to printstring: .autotmp_[0-9]+$" } - for k := range m { // ERROR "live at call to mapiterinit: .autotmp_[0-9]+$" "live at call to mapiternext: .autotmp_[0-9]+$" + for k := range m { // ERROR "live at call to (mapiterinit|mapIterStart): .autotmp_[0-9]+$" "live at call to (mapiternext|mapIterNext): .autotmp_[0-9]+$" printstring(k) // ERROR "live at call to printstring: .autotmp_[0-9]+$" } } From 8071f2a1697c2a8d7e93fb1f45285f18303ddc76 Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Fri, 24 Jan 2025 16:29:13 -0500 Subject: [PATCH 174/397] runtime: mapiter linkname compatibility layer This CL reintroduces the various mapiter* linkname functions with a compatibility layer that is careful to maintain compatibility with users of the linkname. The wrappers are straightforward. Callers of these APIs get an extra layer of indirection, with their hiter containing a pointer to the real maps.Iter. These users will take a minor performance hit from the extra allocation, but this approach should have good long-term maintainability. Fixes #71408. Change-Id: I6a6a636c7574bbd670ff5243dfeb63dfba6dc611 Reviewed-on: https://go-review.googlesource.com/c/go/+/643899 Auto-Submit: Michael Pratt Reviewed-by: Keith Randall Reviewed-by: Keith Randall LUCI-TryBot-Result: Go LUCI --- src/runtime/linkname_swiss.go | 211 ++++++++++++++++++++++++++++++++++ src/runtime/map_swiss.go | 105 ----------------- 2 files changed, 211 insertions(+), 105 deletions(-) create mode 100644 src/runtime/linkname_swiss.go diff --git a/src/runtime/linkname_swiss.go b/src/runtime/linkname_swiss.go new file mode 100644 index 00000000000000..1be724477e5a50 --- /dev/null +++ b/src/runtime/linkname_swiss.go @@ -0,0 +1,211 @@ +// Copyright 2025 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. + +//go:build goexperiment.swissmap + +package runtime + +import ( + "internal/abi" + "internal/runtime/maps" + "internal/runtime/sys" + "unsafe" +) + +// Legacy //go:linkname compatibility shims +// +// The functions below are unused by the toolchain, and exist only for +// compatibility with existing //go:linkname use in the ecosystem (and in +// map_noswiss.go for normal use via GOEXPERIMENT=noswissmap). + +// linknameIter is the it argument to mapiterinit and mapiternext. +// +// Callers of mapiterinit allocate their own iter structure, which has the +// layout of the pre-Go 1.24 hiter structure, shown here for posterity: +// +// type hiter struct { +// key unsafe.Pointer +// elem unsafe.Pointer +// t *maptype +// h *hmap +// buckets unsafe.Pointer +// bptr *bmap +// overflow *[]*bmap +// oldoverflow *[]*bmap +// startBucket uintptr +// offset uint8 +// wrapped bool +// B uint8 +// i uint8 +// bucket uintptr +// checkBucket uintptr +// } +// +// Our structure must maintain compatibility with the old structure. This +// means: +// +// - Our structure must be the same size or smaller than hiter. Otherwise we +// may write outside the caller's hiter allocation. +// - Our structure must have the same pointer layout as hiter, so that the GC +// tracks pointers properly. +// +// Based on analysis of the "hall of shame" users of these linknames: +// +// - The key and elem fields must be kept up to date with the current key/elem. +// Some users directly access the key and elem fields rather than calling +// reflect.mapiterkey/reflect.mapiterelem. +// - The t field must be non-nil after mapiterinit. gonum.org/v1/gonum uses +// this to verify the iterator is initialized. +// - github.com/segmentio/encoding and github.com/RomiChan/protobuf check if h +// is non-nil, but the code has no effect. Thus the value of h does not +// matter. See internal/runtime_reflect/map.go. +type linknameIter struct { + // Fields from hiter. + key unsafe.Pointer + elem unsafe.Pointer + typ *abi.SwissMapType + + // The real iterator. + it *maps.Iter +} + +// mapiterinit is a compatibility wrapper for map iterator for users of +// //go:linkname from before Go 1.24. It is not used by Go itself. New users +// should use reflect or the maps package. +// +// mapiterinit should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// - github.com/goccy/go-json +// - github.com/RomiChan/protobuf +// - github.com/segmentio/encoding +// - github.com/ugorji/go/codec +// - github.com/wI2L/jettison +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mapiterinit +func mapiterinit(t *abi.SwissMapType, m *maps.Map, it *linknameIter) { + if raceenabled && m != nil { + callerpc := sys.GetCallerPC() + racereadpc(unsafe.Pointer(m), callerpc, abi.FuncPCABIInternal(mapiterinit)) + } + + it.typ = t + + it.it = new(maps.Iter) + it.it.Init(t, m) + it.it.Next() + + it.key = it.it.Key() + it.elem = it.it.Elem() +} + +// reflect_mapiterinit is a compatibility wrapper for map iterator for users of +// //go:linkname from before Go 1.24. It is not used by Go itself. New users +// should use reflect or the maps package. +// +// reflect_mapiterinit should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/modern-go/reflect2 +// - gitee.com/quant1x/gox +// - github.com/v2pro/plz +// - github.com/wI2L/jettison +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname reflect_mapiterinit reflect.mapiterinit +func reflect_mapiterinit(t *abi.SwissMapType, m *maps.Map, it *linknameIter) { + mapiterinit(t, m, it) +} + +// mapiternext is a compatibility wrapper for map iterator for users of +// //go:linkname from before Go 1.24. It is not used by Go itself. New users +// should use reflect or the maps package. +// +// mapiternext should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// - github.com/RomiChan/protobuf +// - github.com/segmentio/encoding +// - github.com/ugorji/go/codec +// - gonum.org/v1/gonum +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mapiternext +func mapiternext(it *linknameIter) { + if raceenabled { + callerpc := sys.GetCallerPC() + racereadpc(unsafe.Pointer(it.it.Map()), callerpc, abi.FuncPCABIInternal(mapiternext)) + } + + it.it.Next() + + it.key = it.it.Key() + it.elem = it.it.Elem() +} + +// reflect_mapiternext is a compatibility wrapper for map iterator for users of +// //go:linkname from before Go 1.24. It is not used by Go itself. New users +// should use reflect or the maps package. +// +// reflect_mapiternext is for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gitee.com/quant1x/gox +// - github.com/modern-go/reflect2 +// - github.com/goccy/go-json +// - github.com/v2pro/plz +// - github.com/wI2L/jettison +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname reflect_mapiternext reflect.mapiternext +func reflect_mapiternext(it *linknameIter) { + mapiternext(it) +} + +// reflect_mapiterkey is a compatibility wrapper for map iterator for users of +// //go:linkname from before Go 1.24. It is not used by Go itself. New users +// should use reflect or the maps package. +// +// reflect_mapiterkey should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/goccy/go-json +// - gonum.org/v1/gonum +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname reflect_mapiterkey reflect.mapiterkey +func reflect_mapiterkey(it *linknameIter) unsafe.Pointer { + return it.it.Key() +} + +// reflect_mapiterelem is a compatibility wrapper for map iterator for users of +// //go:linkname from before Go 1.24. It is not used by Go itself. New users +// should use reflect or the maps package. +// +// reflect_mapiterelem should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/goccy/go-json +// - gonum.org/v1/gonum +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname reflect_mapiterelem reflect.mapiterelem +func reflect_mapiterelem(it *linknameIter) unsafe.Pointer { + return it.it.Elem() +} diff --git a/src/runtime/map_swiss.go b/src/runtime/map_swiss.go index f4b4062dd9d44e..a8fe87257acd28 100644 --- a/src/runtime/map_swiss.go +++ b/src/runtime/map_swiss.go @@ -158,31 +158,6 @@ func mapdelete(t *abi.SwissMapType, m *maps.Map, key unsafe.Pointer) { m.Delete(t, key) } -// mapiterinit initializes the Iter struct used for ranging over maps. -// The Iter struct pointed to by 'it' is allocated on the stack -// by the compilers order pass or on the heap by reflect_mapiterinit. -// Both need to have zeroed hiter since the struct contains pointers. -// -// mapiterinit should be an internal detail, -// but widely used packages access it using linkname. -// Notable members of the hall of shame include: -// - github.com/bytedance/sonic -// - github.com/goccy/go-json -// - github.com/RomiChan/protobuf -// - github.com/segmentio/encoding -// - github.com/ugorji/go/codec -// - github.com/wI2L/jettison -// -// Do not remove or change the type signature. -// See go.dev/issue/67401. -// -// TODO go:linkname mapiterinit -func mapiterinit(t *abi.SwissMapType, m *maps.Map, it *maps.Iter) { - // N.B. This is required by the builtin list in internal/goobj because - // it is a builtin for old maps. - throw("unreachable") -} - // mapIterStart initializes the Iter struct used for ranging over maps and // performs the first step of iteration. The Iter struct pointed to by 'it' is // allocated on the stack by the compilers order pass or on the heap by @@ -197,25 +172,6 @@ func mapIterStart(t *abi.SwissMapType, m *maps.Map, it *maps.Iter) { it.Next() } -// mapiternext should be an internal detail, -// but widely used packages access it using linkname. -// Notable members of the hall of shame include: -// - github.com/bytedance/sonic -// - github.com/RomiChan/protobuf -// - github.com/segmentio/encoding -// - github.com/ugorji/go/codec -// - gonum.org/v1/gonum -// -// Do not remove or change the type signature. -// See go.dev/issue/67401. -// -// TODO go:linkname mapiternext -func mapiternext(it *maps.Iter) { - // N.B. This is required by the builtin list in internal/goobj because - // it is a builtin for old maps. - throw("unreachable") -} - // mapIterNext performs the next step of iteration. Afterwards, the next // key/elem are in it.Key()/it.Elem(). func mapIterNext(it *maps.Iter) { @@ -324,67 +280,6 @@ func reflect_mapdelete_faststr(t *abi.SwissMapType, m *maps.Map, key string) { mapdelete_faststr(t, m, key) } -// reflect_mapiterinit is for package reflect, -// but widely used packages access it using linkname. -// Notable members of the hall of shame include: -// - github.com/modern-go/reflect2 -// - gitee.com/quant1x/gox -// - github.com/v2pro/plz -// - github.com/wI2L/jettison -// -// Do not remove or change the type signature. -// See go.dev/issue/67401. -// -// TODO go:linkname reflect_mapiterinit reflect.mapiterinit -//func reflect_mapiterinit(t *abi.SwissMapType, m *maps.Map, it *maps.Iter) { -// mapiterinit(t, m, it) -//} - -// reflect_mapiternext is for package reflect, -// but widely used packages access it using linkname. -// Notable members of the hall of shame include: -// - gitee.com/quant1x/gox -// - github.com/modern-go/reflect2 -// - github.com/goccy/go-json -// - github.com/v2pro/plz -// - github.com/wI2L/jettison -// -// Do not remove or change the type signature. -// See go.dev/issue/67401. -// -// TODO go:linkname reflect_mapiternext reflect.mapiternext -//func reflect_mapiternext(it *maps.Iter) { -// mapiternext(it) -//} - -// reflect_mapiterkey was for package reflect, -// but widely used packages access it using linkname. -// Notable members of the hall of shame include: -// - github.com/goccy/go-json -// - gonum.org/v1/gonum -// -// Do not remove or change the type signature. -// See go.dev/issue/67401. -// -// TODO go:linkname reflect_mapiterkey reflect.mapiterkey -//func reflect_mapiterkey(it *maps.Iter) unsafe.Pointer { -// return it.Key() -//} - -// reflect_mapiterelem was for package reflect, -// but widely used packages access it using linkname. -// Notable members of the hall of shame include: -// - github.com/goccy/go-json -// - gonum.org/v1/gonum -// -// Do not remove or change the type signature. -// See go.dev/issue/67401. -// -// TODO go:linkname reflect_mapiterelem reflect.mapiterelem -//func reflect_mapiterelem(it *maps.Iter) unsafe.Pointer { -// return it.Elem() -//} - // reflect_maplen is for package reflect, // but widely used packages access it using linkname. // Notable members of the hall of shame include: From 28d389ef30fc4c542a80603123990115035c6422 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 23 Jan 2025 17:37:29 -0800 Subject: [PATCH 175/397] internal/godebug: check error from os.ReadFile in test Change-Id: I4770443c8eaa12add2e04cbf9d18ebfbbd851162 Reviewed-on: https://go-review.googlesource.com/c/go/+/643259 Reviewed-by: Michael Pratt Reviewed-by: Ian Lance Taylor Auto-Submit: Ian Lance Taylor Commit-Queue: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI --- src/internal/godebug/godebug_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/internal/godebug/godebug_test.go b/src/internal/godebug/godebug_test.go index 69296303560505..fe1e67225c9928 100644 --- a/src/internal/godebug/godebug_test.go +++ b/src/internal/godebug/godebug_test.go @@ -109,6 +109,9 @@ func TestCmdBisect(t *testing.T) { var want []string src, err := os.ReadFile("godebug_test.go") + if err != nil { + t.Fatal(err) + } for i, line := range strings.Split(string(src), "\n") { if strings.Contains(line, "BISECT"+" "+"BUG") { want = append(want, fmt.Sprintf("godebug_test.go:%d", i+1)) From 50455385b0e668656cac03d3012e48e071df6aa4 Mon Sep 17 00:00:00 2001 From: Than McIntosh Date: Tue, 12 Nov 2024 12:32:39 -0500 Subject: [PATCH 176/397] internal/coverage: fix bug in text-format coverage output with multiple packages In ProcessCoverTestDir pass the selected set of packages to EmitTextual in addition to EmitPercent, so that when we have runs with multiple packages selected but without -coverpkg, text format output for package P was incorrectly including output for P's covered dependencies. This is in effect an extension of the fix for issue 65570. Includes a cmd/go script test to verify correct behavior; ideally it would be nice to locate this test in .../internal/coverage somewhere but at the moment script tests are only supported for cmd/{go,compile,link}. Updates #65570. Fixes #70244. Change-Id: Ia0bb10155353aa0f2ead46e81a2aaa71bde4ef82 Reviewed-on: https://go-review.googlesource.com/c/go/+/627316 Reviewed-by: David Chase Reviewed-by: Michael Knyszek Reviewed-by: Cherry Mui Auto-Submit: Than McIntosh LUCI-TryBot-Result: Go LUCI --- .../script/cover_coverprofile_nocoverpkg.txt | 50 +++++++++++++++++++ src/internal/coverage/cfile/testsupport.go | 2 +- 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 src/cmd/go/testdata/script/cover_coverprofile_nocoverpkg.txt diff --git a/src/cmd/go/testdata/script/cover_coverprofile_nocoverpkg.txt b/src/cmd/go/testdata/script/cover_coverprofile_nocoverpkg.txt new file mode 100644 index 00000000000000..85b3136bf994f6 --- /dev/null +++ b/src/cmd/go/testdata/script/cover_coverprofile_nocoverpkg.txt @@ -0,0 +1,50 @@ +# Testcase for #70244. In this bug we're doing a "go test -coverprofile" +# run for a pair of packages, the first one without tests and the second +# one with tests. When writing the profile for the second test, profile +# data from the first package was leaking into the output (we should +# only see lines in the output profile for the package whose test is +# being run). + +[short] skip + +# Kick off test. +go test -vet=off -count=1 -coverprofile=cov.p ./... + +# Generate a function profile. +go tool cover -func=cov.p + +# Prior to GOEXPERIMENT=coverageredesign we should see no output at all for +# pkg1 (since it has no tests). +[!GOEXPERIMENT:coverageredesign] ! stdout 'pkg1' + +# With GOEXPERIMENT=coverageredesign enabled we should see zero percent +# coverage for pkg1's DoSomething, not 100% (as in the bug). +[GOEXPERIMENT:coverageredesign] stdout 'cov/pkg1/file.go:3:\s+DoSomething\s+0.0%' + +-- go.mod -- +module cov + +-- pkg1/file.go -- +package pkg1 + +func DoSomething() bool { + return true +} +-- pkg2/file.go -- +package pkg2 + +func DoSomething() bool { + return true +} +-- pkg2/file_test.go -- +package pkg2 + +import ( + "cov/pkg1" + "testing" +) + +func TestSmth(t *testing.T) { + pkg1.DoSomething() + DoSomething() +} diff --git a/src/internal/coverage/cfile/testsupport.go b/src/internal/coverage/cfile/testsupport.go index 56b39c5859a96b..adab47fd212d1e 100644 --- a/src/internal/coverage/cfile/testsupport.go +++ b/src/internal/coverage/cfile/testsupport.go @@ -109,7 +109,7 @@ func ProcessCoverTestDir(dir string, cfile string, cm string, cpkg string, w io. // Emit text output. if tf != nil { - if err := ts.cf.EmitTextual(nil, tf); err != nil { + if err := ts.cf.EmitTextual(selpkgs, tf); err != nil { return err } tfClosed = true From 7764c502e28e42279d033719b058690ca8fbaa44 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Fri, 10 Jan 2025 00:06:43 +0100 Subject: [PATCH 177/397] crypto/internal/sysrand: skip TestNoGetrandom without cgo crypto/internal/sysrand/internal/seccomp needs cgo to disable getrandom. Before this change, "CGO_ENABLED=0 go test crypto/internal/sysrand" would fail on Linux. Change-Id: I6a6a465685b480c846e5479da0659e90ab7f3a65 Reviewed-on: https://go-review.googlesource.com/c/go/+/642737 Reviewed-by: Daniel McCarney LUCI-TryBot-Result: Go LUCI Reviewed-by: Ian Lance Taylor Auto-Submit: Roland Shoemaker Auto-Submit: Filippo Valsorda Reviewed-by: Roland Shoemaker --- src/crypto/internal/sysrand/rand_linux_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/crypto/internal/sysrand/rand_linux_test.go b/src/crypto/internal/sysrand/rand_linux_test.go index 417523c29ddc9f..ab43904f91296f 100644 --- a/src/crypto/internal/sysrand/rand_linux_test.go +++ b/src/crypto/internal/sysrand/rand_linux_test.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build cgo + package sysrand_test import ( From 62cd7cb6cdba5cd947c97ee5269699dffdbca1b0 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 23 Jan 2025 15:50:32 -0800 Subject: [PATCH 178/397] crypto/hkdf: check error in TestFIPSServiceIndicator I don't know why this code calls panic(err) rather than t.Fatal(err), but I didn't change it. Change-Id: I9aa7503c604bd8d4f27cc295e2ec742446906df9 Reviewed-on: https://go-review.googlesource.com/c/go/+/643995 Reviewed-by: Daniel McCarney Auto-Submit: Ian Lance Taylor Reviewed-by: Ian Lance Taylor Reviewed-by: Roland Shoemaker LUCI-TryBot-Result: Go LUCI Reviewed-by: Filippo Valsorda --- src/crypto/hkdf/hkdf_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/crypto/hkdf/hkdf_test.go b/src/crypto/hkdf/hkdf_test.go index 201b440289bb2d..57d90f88e93e75 100644 --- a/src/crypto/hkdf/hkdf_test.go +++ b/src/crypto/hkdf/hkdf_test.go @@ -404,6 +404,9 @@ func TestFIPSServiceIndicator(t *testing.T) { // Salt and info are short, which is ok, but translates to a short HMAC key. fips140.ResetServiceIndicator() _, err = Key(sha256.New, []byte("YELLOW SUBMARINE"), []byte("salt"), "info", 32) + if err != nil { + panic(err) + } if !fips140.ServiceIndicator() { t.Error("FIPS service indicator should be set") } From 90ec9996cb6e7ea98ffeab1b6e28037d79e81026 Mon Sep 17 00:00:00 2001 From: Roland Shoemaker Date: Fri, 24 Jan 2025 14:08:03 -0800 Subject: [PATCH 179/397] crypto/pbkdf2: add keyLength limit As specified by RFC 8018. Also prevent unexpected overflows on 32 bit systems. Change-Id: I50c4a177b7d1ebb15f9b3b96e515d93f19d3f68e Reviewed-on: https://go-review.googlesource.com/c/go/+/644122 LUCI-TryBot-Result: Go LUCI Auto-Submit: Roland Shoemaker Reviewed-by: Filippo Valsorda Reviewed-by: Robert Griesemer --- src/crypto/internal/fips140/pbkdf2/pbkdf2.go | 20 ++++++++++++- src/crypto/pbkdf2/pbkdf2.go | 3 ++ src/crypto/pbkdf2/pbkdf2_test.go | 30 ++++++++++++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/crypto/internal/fips140/pbkdf2/pbkdf2.go b/src/crypto/internal/fips140/pbkdf2/pbkdf2.go index 8f6d9915041d3f..05923f68262ac6 100644 --- a/src/crypto/internal/fips140/pbkdf2/pbkdf2.go +++ b/src/crypto/internal/fips140/pbkdf2/pbkdf2.go @@ -7,15 +7,33 @@ package pbkdf2 import ( "crypto/internal/fips140" "crypto/internal/fips140/hmac" + "errors" ) +// divRoundUp divides x+y-1 by y, rounding up if the result is not whole. +// This function casts x and y to int64 in order to avoid cases where +// x+y would overflow int on systems where int is an int32. The result +// is an int, which is safe as (x+y-1)/y should always fit, regardless +// of the integer size. +func divRoundUp(x, y int) int { + return int((int64(x) + int64(y) - 1) / int64(y)) +} + func Key[Hash fips140.Hash](h func() Hash, password string, salt []byte, iter, keyLength int) ([]byte, error) { setServiceIndicator(salt, keyLength) + if keyLength <= 0 { + return nil, errors.New("pkbdf2: keyLength must be larger than 0") + } + prf := hmac.New(h, []byte(password)) hmac.MarkAsUsedInKDF(prf) hashLen := prf.Size() - numBlocks := (keyLength + hashLen - 1) / hashLen + numBlocks := divRoundUp(keyLength, hashLen) + const maxBlocks = int64(1<<32 - 1) + if keyLength+hashLen < keyLength || int64(numBlocks) > maxBlocks { + return nil, errors.New("pbkdf2: keyLength too long") + } var buf [4]byte dk := make([]byte, 0, numBlocks*hashLen) diff --git a/src/crypto/pbkdf2/pbkdf2.go b/src/crypto/pbkdf2/pbkdf2.go index 271d2b03312ef0..dd5fc33f2120c3 100644 --- a/src/crypto/pbkdf2/pbkdf2.go +++ b/src/crypto/pbkdf2/pbkdf2.go @@ -34,6 +34,9 @@ import ( // // Using a higher iteration count will increase the cost of an exhaustive // search but will also make derivation proportionally slower. +// +// keyLength must be a positive integer between 1 and (2^32 - 1) * h.Size(). +// Setting keyLength to a value outside of this range will result in an error. func Key[Hash hash.Hash](h func() Hash, password string, salt []byte, iter, keyLength int) ([]byte, error) { fh := fips140hash.UnwrapNew(h) if fips140only.Enabled { diff --git a/src/crypto/pbkdf2/pbkdf2_test.go b/src/crypto/pbkdf2/pbkdf2_test.go index 03980c7e54d3be..eb0ed14e243c6b 100644 --- a/src/crypto/pbkdf2/pbkdf2_test.go +++ b/src/crypto/pbkdf2/pbkdf2_test.go @@ -221,3 +221,33 @@ func TestPBKDF2ServiceIndicator(t *testing.T) { t.Error("FIPS service indicator should not be set") } } + +func TestMaxKeyLength(t *testing.T) { + // This error cannot be triggered on platforms where int is 31 bits (i.e. + // 32-bit platforms), since the max value for keyLength is 1<<31-1 and + // 1<<31-1 * hLen will always be less than 1<<32-1 * hLen. + keySize := int64(1<<63 - 1) + if int64(int(keySize)) != keySize { + t.Skip("cannot be replicated on platforms where int is 31 bits") + } + _, err := pbkdf2.Key(sha256.New, "password", []byte("salt"), 1, int(keySize)) + if err == nil { + t.Fatal("expected pbkdf2.Key to fail with extremely large keyLength") + } + keySize = int64(1<<32-1) * (sha256.Size + 1) + _, err = pbkdf2.Key(sha256.New, "password", []byte("salt"), 1, int(keySize)) + if err == nil { + t.Fatal("expected pbkdf2.Key to fail with extremely large keyLength") + } +} + +func TestZeroKeyLength(t *testing.T) { + _, err := pbkdf2.Key(sha256.New, "password", []byte("salt"), 1, 0) + if err == nil { + t.Fatal("expected pbkdf2.Key to fail with zero keyLength") + } + _, err = pbkdf2.Key(sha256.New, "password", []byte("salt"), 1, -1) + if err == nil { + t.Fatal("expected pbkdf2.Key to fail with negative keyLength") + } +} From 1f58ad5d6d2eebc1939a65a511ca84c9b997cd6a Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Mon, 27 Jan 2025 14:05:22 -0800 Subject: [PATCH 180/397] Revert "os: employ sendfile(2) for file-to-file copying on Linux when needed" This reverts CL 603295. Reason for revert: can cause child exit_group to hang. This is not a clean revert. CL 603098 did a major refactoring of the tests. That refactor is kept, just the sendfile-specific tests are dropped from the linux tests. Fixes #71375. Change-Id: Ic4d6535759667c69a44bd9281bbb33d5b559f591 Reviewed-on: https://go-review.googlesource.com/c/go/+/644895 Auto-Submit: Michael Pratt LUCI-TryBot-Result: Go LUCI Reviewed-by: Ian Lance Taylor Reviewed-by: Cherry Mui Reviewed-by: Andy Pan --- src/os/readfrom_linux_test.go | 52 ++------------------------------ src/os/readfrom_sendfile_test.go | 2 +- src/os/zero_copy_linux.go | 46 +++------------------------- 3 files changed, 7 insertions(+), 93 deletions(-) diff --git a/src/os/readfrom_linux_test.go b/src/os/readfrom_linux_test.go index cc0322882b1305..d33f9cf9c984f6 100644 --- a/src/os/readfrom_linux_test.go +++ b/src/os/readfrom_linux_test.go @@ -242,13 +242,12 @@ func testSpliceToTTY(t *testing.T, proto string, size int64) { } var ( - copyFileTests = []copyFileTestFunc{newCopyFileRangeTest, newSendfileOverCopyFileRangeTest} - copyFileHooks = []copyFileTestHook{hookCopyFileRange, hookSendFileOverCopyFileRange} + copyFileTests = []copyFileTestFunc{newCopyFileRangeTest} + copyFileHooks = []copyFileTestHook{hookCopyFileRange} ) func testCopyFiles(t *testing.T, size, limit int64) { testCopyFileRange(t, size, limit) - testSendfileOverCopyFileRange(t, size, limit) } func testCopyFileRange(t *testing.T, size int64, limit int64) { @@ -256,11 +255,6 @@ func testCopyFileRange(t *testing.T, size int64, limit int64) { testCopyFile(t, dst, src, data, hook, limit, name) } -func testSendfileOverCopyFileRange(t *testing.T, size int64, limit int64) { - dst, src, data, hook, name := newSendfileOverCopyFileRangeTest(t, size) - testCopyFile(t, dst, src, data, hook, limit, name) -} - // newCopyFileRangeTest initializes a new test for copy_file_range. // // It hooks package os' call to poll.CopyFileRange and returns the hook, @@ -276,20 +270,6 @@ func newCopyFileRangeTest(t *testing.T, size int64) (dst, src *File, data []byte return } -// newSendfileOverCopyFileRangeTest initializes a new test for sendfile over copy_file_range. -// It hooks package os' call to poll.SendFile and returns the hook, -// so it can be inspected. -func newSendfileOverCopyFileRangeTest(t *testing.T, size int64) (dst, src *File, data []byte, hook *copyFileHook, name string) { - t.Helper() - - name = "newSendfileOverCopyFileRangeTest" - - dst, src, data = newCopyFileTest(t, size) - hook, _ = hookSendFileOverCopyFileRange(t) - - return -} - // newSpliceFileTest initializes a new test for splice. // // It creates source sockets and destination file, and populates the source sockets @@ -342,34 +322,6 @@ func hookCopyFileRange(t *testing.T) (hook *copyFileHook, name string) { return } -func hookSendFileOverCopyFileRange(t *testing.T) (*copyFileHook, string) { - return hookSendFileTB(t), "hookSendFileOverCopyFileRange" -} - -func hookSendFileTB(tb testing.TB) *copyFileHook { - // Disable poll.CopyFileRange to force the fallback to poll.SendFile. - originalCopyFileRange := *PollCopyFileRangeP - *PollCopyFileRangeP = func(dst, src *poll.FD, remain int64) (written int64, handled bool, err error) { - return 0, false, nil - } - - hook := new(copyFileHook) - orig := poll.TestHookDidSendFile - tb.Cleanup(func() { - *PollCopyFileRangeP = originalCopyFileRange - poll.TestHookDidSendFile = orig - }) - poll.TestHookDidSendFile = func(dstFD *poll.FD, src int, written int64, err error, handled bool) { - hook.called = true - hook.dstfd = dstFD.Sysfd - hook.srcfd = src - hook.written = written - hook.err = err - hook.handled = handled - } - return hook -} - func hookSpliceFile(t *testing.T) *spliceFileHook { h := new(spliceFileHook) h.install() diff --git a/src/os/readfrom_sendfile_test.go b/src/os/readfrom_sendfile_test.go index dbe1603bd15a49..86ef71ee0293c2 100644 --- a/src/os/readfrom_sendfile_test.go +++ b/src/os/readfrom_sendfile_test.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build linux || solaris +//go:build solaris package os_test diff --git a/src/os/zero_copy_linux.go b/src/os/zero_copy_linux.go index 27a0882560ae2a..9d666a3c791117 100644 --- a/src/os/zero_copy_linux.go +++ b/src/os/zero_copy_linux.go @@ -40,17 +40,16 @@ func (f *File) writeTo(w io.Writer) (written int64, handled bool, err error) { } func (f *File) readFrom(r io.Reader) (written int64, handled bool, err error) { - // Neither copy_file_range(2)/sendfile(2) nor splice(2) supports destinations opened with + // Neither copy_file_range(2) nor splice(2) supports destinations opened with // O_APPEND, so don't bother to try zero-copy with these system calls. // // Visit https://man7.org/linux/man-pages/man2/copy_file_range.2.html#ERRORS and - // https://man7.org/linux/man-pages/man2/sendfile.2.html#ERRORS and // https://man7.org/linux/man-pages/man2/splice.2.html#ERRORS for details. if f.appendMode { return 0, false, nil } - written, handled, err = f.copyFile(r) + written, handled, err = f.copyFileRange(r) if handled { return } @@ -87,7 +86,7 @@ func (f *File) spliceToFile(r io.Reader) (written int64, handled bool, err error return written, handled, wrapSyscallError("splice", err) } -func (f *File) copyFile(r io.Reader) (written int64, handled bool, err error) { +func (f *File) copyFileRange(r io.Reader) (written int64, handled bool, err error) { var ( remain int64 lr *io.LimitedReader @@ -116,44 +115,7 @@ func (f *File) copyFile(r io.Reader) (written int64, handled bool, err error) { if lr != nil { lr.N -= written } - - if handled { - return written, handled, wrapSyscallError("copy_file_range", err) - } - - // If fd_in and fd_out refer to the same file and the source and target ranges overlap, - // copy_file_range(2) just returns EINVAL error. poll.CopyFileRange will ignore that - // error and act like it didn't call copy_file_range(2). Then the caller will fall back - // to generic copy, which results in doubling the content in the file. - // By contrast, sendfile(2) allows this kind of overlapping and works like a memmove, - // in this case the file content will remain the same after copying, which is not what we want. - // Thus, we just bail out here and leave it to generic copy when it's a file copying itself. - if f.pfd.Sysfd == src.pfd.Sysfd { - return 0, false, nil - } - - sc, err := src.SyscallConn() - if err != nil { - return - } - - // We can employ sendfile(2) when copy_file_range(2) fails to handle the copy. - // sendfile(2) enabled file-to-file copying since Linux 2.6.33 and Go requires - // Linux 3.2 or later, so we're good to go. - // Check out https://man7.org/linux/man-pages/man2/sendfile.2.html#DESCRIPTION for more details. - rerr := sc.Read(func(fd uintptr) bool { - written, err, handled = poll.SendFile(&f.pfd, int(fd), remain) - return true - }) - if lr != nil { - lr.N -= written - } - - if err == nil { - err = rerr - } - - return written, handled, wrapSyscallError("sendfile", err) + return written, handled, wrapSyscallError("copy_file_range", err) } // getPollFDAndNetwork tries to get the poll.FD and network type from the given interface From 4f48ad5c6b2775ab295ea0062b93527cbf4ea9d0 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Wed, 29 Jan 2025 03:18:01 +0100 Subject: [PATCH 181/397] cmd/link/internal/loader: fix linknames from FIPS 140 frozen tree blockedLinknames was updated in CL 635676 after the lib/fips140 zip mechanism was last tested. linknames from crypto/internal/fips140/v1.0.0 need to be allowed if they'd be allowed from crypto/internal/fips140. Change-Id: I6a6a4656022118d4739ae14831f2ad721951c192 Reviewed-on: https://go-review.googlesource.com/c/go/+/645195 Reviewed-by: Michael Pratt Auto-Submit: Filippo Valsorda LUCI-TryBot-Result: Go LUCI Reviewed-by: Roland Shoemaker --- src/cmd/link/internal/loader/loader.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/cmd/link/internal/loader/loader.go b/src/cmd/link/internal/loader/loader.go index e7cc30ab0731c2..0c234e89758df3 100644 --- a/src/cmd/link/internal/loader/loader.go +++ b/src/cmd/link/internal/loader/loader.go @@ -2394,6 +2394,16 @@ func (l *Loader) checkLinkname(pkg, name string, s Sym) { if pkg == p { return // pkg is allowed } + // crypto/internal/fips140/vX.Y.Z/... is the frozen version of + // crypto/internal/fips140/... and is similarly allowed. + if strings.HasPrefix(pkg, "crypto/internal/fips140/v") { + parts := strings.Split(pkg, "/") + parts = append(parts[:3], parts[4:]...) + pkg := strings.Join(parts, "/") + if pkg == p { + return + } + } } error() } From e81f7155154c0f5d40363e84a8f24a5b559b5eed Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Wed, 29 Jan 2025 03:49:06 +0100 Subject: [PATCH 182/397] lib/fips140: freeze v1.0.0 FIPS 140 module zip file make v1.0.0.zip make v1.0.0.test make updatesum Changed the v%.zip Makefile target to use the default of origin/master, as per its comment and intention, instead of the local master. Change-Id: I6a6a4656c097d11b8cdc96766394c984f9c47f82 Reviewed-on: https://go-review.googlesource.com/c/go/+/644645 Reviewed-by: Carlos Amedee Reviewed-by: Roland Shoemaker Auto-Submit: Filippo Valsorda LUCI-TryBot-Result: Go LUCI --- lib/fips140/Makefile | 2 +- lib/fips140/fips140.sum | 1 + lib/fips140/v1.0.0.zip | Bin 0 -> 650281 bytes 3 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 lib/fips140/v1.0.0.zip diff --git a/lib/fips140/Makefile b/lib/fips140/Makefile index cd657ae72fd248..8dcb8fbebe5bec 100644 --- a/lib/fips140/Makefile +++ b/lib/fips140/Makefile @@ -27,7 +27,7 @@ default: # copy and edit the 'go run' command by hand to use a different branch. v%.zip: git fetch origin master - go run ../../src/cmd/go/internal/fips140/mkzip.go -b master v$* + go run ../../src/cmd/go/internal/fips140/mkzip.go v$* # normally mkzip refuses to overwrite an existing zip file. # make v1.2.3.rm removes the zip file and and unpacked diff --git a/lib/fips140/fips140.sum b/lib/fips140/fips140.sum index 013112d9e58d0d..66b1e23dfe619d 100644 --- a/lib/fips140/fips140.sum +++ b/lib/fips140/fips140.sum @@ -9,3 +9,4 @@ # # go test cmd/go/internal/fips140 -update # +v1.0.0.zip b50508feaeff05d22516b21e1fd210bbf5d6a1e422eaf2cfa23fe379342713b8 diff --git a/lib/fips140/v1.0.0.zip b/lib/fips140/v1.0.0.zip new file mode 100644 index 0000000000000000000000000000000000000000..bd9d3c19d05b9075a2587806d00224c3f8859ba1 GIT binary patch literal 650281 zcmb@tW3VVevn9H1+qP}*vu)e9t+Q?0wr$(CZQFD1%==;@Uc}6g8`E7~5n0*Yf3jj_ z*2+wIDPRy30EmD0|NmnCw_s*xZD4CgXXj`}Z)#!h#K^)R;L1qHK*#VOk^cV^4NRQq z|2=eOc2{cswws~|ypej0cliX!=}468bG zKyS^!k#N^ojT{)!dvc-rXnRh_ed!aDAQns@$9p?f^OjTkJ)nT8?6>gQyJ+I2P^1dn zAi2=+isos=G}6V)@>t$6cc06h>(A3LXcc`N5R!zc2Y7;c&_K;p(a#8Afxs56#q7kz zyqdHT^FqmV=`rxSeym8rNHJ_2cE$6Tfdo)t3nm6f52D}0OW^~}P9 zIO2ubx7YlkM`^;^OOYr7=JFdJ`J|J=^;D%#ybu(@&yuRab#+6uk?zOmQOMAW{Q)eR zsw)LA@|;n?y|nd^*Im^`p`-eJO9A9yC#UPel+Gai0CFwRungjXJwibG}(9k z`YZvnS!blS+X!r&njnRgwlQ_`D;^M;z;=Y;d+*di5}rV_yZQ;Db&PCI1lB&~92j{i z_Fg{*(E+rPoPcXm*$Cl8wwv(nx4*6=I8Sc z_%cRK~CEd3F~cI0_z$?GDr|YB?HKH0Zv8&0Ai`fWMH$mS~Qla7EAb{x>j5 zx{*Q-5thtce_Q9?)VzS3eg>Ak72RrUJz)!K_Bw+!Jb=I$92O7wIR8NV{T@}f`NX4wCF@_XSHP;TDvg!U{xwcOTx4!o=ccU*fpdbj$V%6mH*-{3oZ z0Y-CdFa;o{5cn=nNM3Nj-M=PF=j>R|iKTf-OX=b=?KH8KV0d1c`R_UEB!j^A+y zQc=&QMOIK;2=3+4g_0?re94J0CI2c=6Yqz zUUX^FoJ}f>TFuq1bkG@c2B|)xFTUgb%1!wtr@{EerOlVwAo=<&NBxp`hZcZ^S_X0Lozj0ObFVK+W;r0BSu08)G&WI;So5ZQBD;l%5eehmP&Y zI)^^IsN=kfg#H~ijfA)~Wm~(rdU6y%Hc;aJ#OEG4RajuWU#~UyN=qNa;lXsfp2tVr znK|1*f;)z(x>$DEFy1u0K3G-i(N|9fX#K{={`DHNnF*!j6`H@9`shNH%eKuM);`ee zm%}hPT{iyrAhB{r4AGqqQV1K@8grR9CsOdf>bGp}Xb=OjPP;lcJTUk|UGTdpGgZ&0 z;D%6k+`FJxotcANSM;`v1+a~hP7aYc)ANH+C_2!d zo25+!u#bu&hu<6b-Slq= zsgFSTGe{#n*oka0x@{=g0KMun(B5P7%rD#Gv)^e`jEjx&^Nl1B(XN?SGDAV2C2~Mc zRIg{865X>!Gi;PZYY}r8JW(O{&;GOvU1Uat|!M(Pd zdeVA-4f!roT+E_lVI+bHG&z8M((Da|9@#YZ20>g@PD^to9wH1#=+Z1OVJbplD?+0c z;jxSH*fe>qn>5$r5-R+s5l_CY<$3>WB-QFW{W3&k&Wr9Dq{7T9^qz^>(0Ly4?&ChB z*eMj}z3E>dD5GM_k}B8j)9ypDbv3K?hqRhgt(ku@EJ9n}a$Iy5-cE{FQq{f|+P|zr zq0IcK#|&()PAIs4DsV<9LPw}VNAOew7Z>VA5M^0)xZwauIE>y{oW4_dtQw{AGl?#y zuQPzpj^4)*%BBd`nWE=oYnXhxEOvN}Z8br-XcYg|KpOufO*dH2kNzCxCn%XaT;~)! z%}vI5Yjlu|ekiBpW3LGp)HRQ)($nL|4*J;46z@(62GhXNfK;KlTBwrmm=bq_j#fm! zPKykmXGfbdOtrx7?mI2JMdRAO{$ZEB9I{wo>Ks=~j>CkDJ}tv`W#%L_bH*?am4!Q9 zwRLWvlk=DPD9F;PnkcBvDa2n~w0EE9h@9jk|#?@FbHr6y_Uq*oiGfelMIgSj#Pgy|DX(p86gmI9@9Q z=-|ZASni#E4rUzl5IbU>Nj_2K&{z)w_xHfzNXW-AXik<$m{t2B1u#txE13ljA z&4T}L)e4~31LIHa<@#jv;GWJ9+q^ZWkLA?v{>||l5)gmKi!ROLFVfF%sZ#@CktwE& zM(SRab(pN_A41xK1hD~#YKZw)VF-&vN{29+j6cMD8(xR}fTY1f_hO4VNH6(5ezbH{2pl8e^JT$$_0}47{ddO6lotgUPkh1*k!n zsMF~CY`zqc5dk8PB7p$L-r=_;RvkUuIc5C1|1>b?S=Bd>{#Z3SkJ5K$&T@`N&q~|~ zRnP%yB$mz`Zl{xGad8?r%d#v_hO)v~JB`TDM2(s++AS_KRV=3K{|;h-so>R*s<9P4 zi=y&ID&!ZPYAi1>GJf)v__?J>^JrOEpmUEIfnZI}kdR0S9q}MZqu{~sxYFQF(n!=m zI-Ev5D9maOb>CCdZjV}c&m2&gp5EmlDz{gOwLd0ZpRO%m|DxS53!iOyTMEuG{3GT* z=M0yj8cFp|pt76Hse>rKbmPAxb?JyV)h*$c#F-I(DyGi%)`mj$}%*eCArNIYyTiKra9d$8t@AMVQ{ zjx`Uu8NvXI5fqPKSHu|oU0yIa1)ozI50ZlqI2-RG_UYsYtI@$gyT)du8o_w7?lm?c zF!B;F!g%2(R#pYgDsd%0YVOFKmFLc4!PfD5MA$5EkPqK=2L74o8$d&z{aZ_Or;%3H zCSt}SyE9~Ny>;(T*H0A17&bDp2bWD*E@NR4KBlG2%pK040@SF2F3Q_%iIjHDCA#A7 zyor&&Bm?Bz`r5OX(@Eb()Q}%rPk~A=RB`6BtEZz+va%t&XGK~m)+*eH{aMMoK=McB z@9#KMR5V|ad>49?Y<+aRyJX3-L=_Q(FX%t3BfRT>&Q`iO#$c$A+%b!mv9s94OJpLY zQHhq>JvTxP+|YXf9@gV+{?Xs)L6_q?)AaTrS)VTfaU&Bwo49zko6k$F((pzkPcnI9 z&|z?Y$$nlKh0w@_k-AdQgjaxuluj5Y7Q)3R9iA1Xg_NenCVh@YR=ZYyR>cg&n`i+q zq&|d8PZ}95y7aPE3%k^CHR8~P<0`a~(T36pp}R%a-rd|*zmG{+ z?`fOIsp&>X3%VNF)_$LSZbTn&Zr1FWqV)POep}zQmB5L8LNd|4<~d&=ptX~AYI-=? z8hoeKgae$M*G&?ZXwQ*t$MY!#@2)A94%E!gr)-D_q^LTG8Me2Jn)|--ce)esizD#Z zAUBrEe*Shr;SK?ZOfW2AJmb4GmF!H|RvH%gGCl~hK?f&@#9XEMOB2doq4E$dmU>qW z(DOD_IsPqUTx4F^Wg;dhmoh4fpDo(SGnoXOl0AY&icK0kCOX~fbXHfeOp1zg&`e`5 zo}^9K@ptN+{UKK*)NX09Vy-adQUcPEg2G5VUJc%>P8@sm&GLj%aX4#RY6wug2iyBC z(q!ub)%TG4{BcPrw={x}KD3sFA+{E0$@OhQK}LbPd?YbNzWQ(HTSPPHa#D(F-p0Mo zu-gGHXS`cBO_x$0{&q2)389`sqoK$}Yt@-bvK`6oevO(PH+k*at>i<+k>0}(@0gc# zX_;CXLZ;gsWkmO;g4X1_8Ke~VFh2DC*PPy+9{mr@f4ox3!R-J87yy7j_W#W*vH!Os zX(yY1v`3Zdwk(y- zs_&~|Tjzyld?MNzZaWsPK_BbhfNFg<=|8>>Kgf}v{dtcD z^=Y};c)prbdIPqpPiLD~H{b6XPL8dS2DyAXs~tD&P>EbNj6-T3wnW$DuWZl|GSkT#K(+3tmjagsvSd)I z_|I1Wuu%OQ&*J`}NB*DDVbRQ=4PgScye>!E4nVNg6E@JL1n*Bl$c?(}rh(bWvq5o0sst zJk_Ip_!|%v$y{u?Sx~_?CDEe%MwB4yX5i1oU>M#+wZ`R{LC$GH0AK@@ga>Nvv=qlo z-ZEuCO(IeUn;0PGP`(D>f7xIIo`3vMc(wXbwH0g7 zr?k|i164#?4^hU$Cu;tL3+Mh3HX*KVBLY|GaaS^V`s_s|7DQ=okB67!wTsWe2^ z+wSXE)Qow0#tVv&AeDhs5zX=dOSBHCF4|89#B^J)UU31?Y_U?Paea*6pZfWc zoPV(yKqQe0>vvoCKr(9Y+-p~Ov$$bV{7t>~vUu;$;hn}Unh*lG4tzl6Y2+scdX046zg~^^mVxP3-urTYVMo$*7_G!v;SN9KQjT`{~i1?GqE*s zv@rTF>Q>#(>0s>Mm)0kurt)JugLwu2&dzT2(xn<;T@_dK4^ro;qXQ)&t0@{`xv3}{ z$-SH0wDI&*?^zaXbl6c#9EHC_v=ey?y<^8i)zv}?Vwyqm8kJG}O`Bf_J2ee9EuRSJ7+zSvm`ejJz_g_Uei zWPnjy03kEc$ZNn5TP;DgTOebN8>)~~qtqd(g{nDDf>EwDA@`X4uAt-mbw zV*W<32Kw9TYAx_$c10#v?cd>MyJ3H~rTh=&Jbm{-68l1^S8>P6d^SHXo@{=RVRZCN ztq(SBFx34?&p;=Nk>7GF5urpHfeKpI>6P>ZlSIlaH)pNhZGE@+k={GVe@* zP+tl(`N^nWGf&Ph23yg508bts(c-0Vh1cdtho%9R5e?%KPgKf2uTYq@$~e_5MQAQj z$GAsHViGYbAcW@QQW&GzhxH(1A>%@Bk^WjaO9+if8mUGTO|btwg!lw=7^a1tUU8nz2lG^Upf_8p0P}u56;jQ;m0^Py zuF)_f?msTUpc{5K;aB)eX^rC{~!faQ;6JaWJ_Kz zA;q0*97z7dE9VVGR8zbwk&y>q@Jy!w>SB2nRC%(&W(WG#Pg~4G?S$a zg|JiBz?V(_kQ1rH%E_gUN-%@hDbyHD`s9t)u#EW__r}Cp1zW*9fmx;wh=j(Vv(UP> zL$k{@9EOe7Hd_uF+ZLB!T~1Jbn_7t?KkMqVrvrW7zY_u|-km@D%Z{y@iJ88+Ydiv5 z9+7QcX>0CeH(f+GI0QF6BGx!$Y`Ni`wPBs$VbQH&(}P3V8SbTQ#c&TR-VaFo>asXh6La&ec7u~5_U{RaKip8q@XfD^D z`J;FUE~d7Ik8Wp_M>O=dsWpK`qN{i{>!w!2>`uCm)x#v3c2P=~6?oIQ`A5M^-tO8f zO|*T1V3NIJl6u!KwB#ZUX?bANjr#~9N-I(Gmk{L(6w-7PD-pmn1PJBu*4&PTa|S;; zon@`q^(o%@4Nk|}0UbQt#cBf?lUM3aiqs9n64EmHokJfS<1$(|~OD+wt(zG2&@$^8U~Rh#|!`SPV( z$ftrz2Y&B$hRo#;B$Pp+tD!fP8;`hGh5q?lSTSKj^z7_mD63_{q*YPC14strKSiiB z0NNFr>$g*obCd6Qe)n*G5w=jglvK?IbM$)qv7$<@y7PG_(!gqQvk$EJevP~Tbi`Qb zKuV*+xwhh>CSw>S=|(LfS*g)Kd3*f8MS?f$R;S8NXiB3tAO^?958?Zy$hD0kOgQPAK^N1SkYTM*L_ zXAc-M^?hHiPZ6EmjIg`bMjd;m>H1gmsMYDYzc$#n^UlDnM{8Cs5lC-Ik+Qaz2+g6L zg8Hk7uiOv*KOt9AE&~G;BmjWl|CPw({O^QZwsr>p^U#5M^C5r zwu0z}w@T{9S3+7-J?t(UCLJZmBBiqWmIKi%c=Hi-B!wc>Mfef4!q3Qs#RAM?i^tb1 z=TXNa--6!p=SbEp%+)+BntmqFZ4CGR_{a78*&tfRu3fpJM(eknvYS;s>s-vKdB8iS z@oE2X*jAcw?9x^`#c1XJ-cn`%9W(z=i*9+INu`z$Gi7q90L#iG8s#VvrWY&r=`)?V znfX$rV&(xzOs_3mXz<=P#!UV3Uwr;d!bZ<++&iQDHv`7hV|;qCI>p8@?SepQD6Vkf zF+VHmiBoX}vQ^z_*-AI(sP3;pCz47DgSXv?#S1Nz1qYy;MNf2!bW;U`-vVFo|JbW+ zB0E(A5CFgw=>HZX|F`UAZ*RoL;{K0$_P%sH5MMa6bC2NR_92^UfuVA6%Ub7MW9a6K zhNZ0=ae@wwgDN!2R}=@z?Dnp0{(T+qDXU6QJ~*&)n;l`78k*y1d{ETTNY`jBU*3xf z&K&F1A<;i80$l_RhKKR2H102GgW}x<|1*j(pC)Q`p*q=&r9F(YhLaGCEB}BFo(C?Rf4?b6QZ_{qyFSs&nhiL~%_BySj4~T==4@XW6 z-xD1CCsRIqF|H1KTD)+g`%k6mZ>sXX7h1nJDk(G; zBpaQK^=vF*2@0A7QqGd)>+7pZF?#dwK+JNMIWpPRitb4Bg&7N#8EZtB7JZ!$V;X2} zJu*w)EvOqqAz$Yx;Bm$XdGkhfDvfGm#b63+D(R?em-2GfyS1v;hJ#R{CI%O4=7_;5 z2TZo*S>YC>mSS2h5c$12fPZ%p%RvxWxP22m4e^0?oNU?( z^uZ7uPQ|gd4c2Z@c4itGyI-OI$%0>A2)mmzF!MznsqDW+KWq?9JwyHl8G2pSeH?3k zQ-si-)H}970l~wl4l{%e1tcdjwpMhICp<%}QSG;G+(2Xn?tD6&_9_A0eYmsXHL^Uo zXd~_ofq}Ti3=g`s`Rj<;e2h2m-q^07&Xw-~Fzr-66&D9<{O+p_~ZBU8{wSoi(#XTn67 zO6X;0SX=WlqFgx{LITvl**dbIW!e5y^UEfFK>DuA>ED2<>%n5d9nNZJ&i4M>OcLyY z-z*GbIHu>4r!LAvL{MQ6aq<3qaK0#cTYpa0&yWP$!|6N|V<9Y0G$Ba)COY}jU-)1+ z%Bo+Sco^vWsGM=vHFQv)QUz<_(dJdwn%ww6BIB&%Ms>1`<|U=+I<()}0~Y$2 zAU0eO+H!COyzN2>Uw7g}Csl;{p^?B!ft#5_7^3{0l{#QFhRi@>_YY^LjXiC$6INVg z-m}Y#XRefTIo&GYbKv-Q#QBxC?ceTAomsaZ{=g*z8?r&mp9@9g67K#qJ2yM_vS0W2 z{$O&_xYzQZeas&+D)eK}jO$cpvp@L*AHgvSg<&VpQNTC6YYsUbkeQwpOD* zxw%x#x{!aTUJh)#XO=uVW{3*TteAD$oYuGChZHX6TTg9T=*Mt$gWYm*#pXGs&g>7C zndN*Ri>7EC+W{!PxqGizZUtTCh`t};xY>pb?8i>!nC4inGyxF^785tV?i?jll}pCY z#1mT;5UPMG%8zH56O1z@TwW?Q`Z0HOVZy~!GPmK&%3^z{O2-HtZkpGDqcWIG0b3l_U zyQW#CrA+03O&$H62|ca9AJ=%eKSyoeKSq^N-A|ccc}rtelN1rW;@tiDVzPpydXMQ+>4l9TRV=B1hmkbK8} zsv;*JTv6vWqO*@MlLoCTNfz_*lY?J+*Xi%y8(xz2aYebyV4Zh&0rWc}F21J%|7m*& zD6%#0`VjvuODYY#r2M+fwah1l@#f5k3O!xy)r;w2_d*B8%a|zEgbkT;byzq~ERgnPqo|*4(qH;E zsNj8SGmR)cc@B^|UxZJQ62K67w$nxg=F^$$js(0jB-w7|0-WM*J4TvkjW&d$ zakNkti9xr{rsYQ>OIdZLf$$+qF~Qx_oNE*m4gMMhxWA(;_3Lm!+A z9lOxL8pDNQ#W$T-gBWc-4P($SBzxvyj}zLHog}qlyoR5hx`RmU0&bjH;{yd_v}=Ob z#FG8U@(>k)B3AOF`=?^USK6~}iO%_{;Gya$fQ)S)Za4-fx3p;yb|mlq_@Q4o0e zMXh77<2a7=q=~L<)}6~^k)O`N^Nm;3)OpTnjXI57z3Wxk@HrKX1qk$J?xW&DM%uEY zgid0%9@3E}XJ1OHEFAO-izI*>rpP?WtVsy4dL2i2rG?MNTDhDX#|K_h`)1m=;RkoWDU=bbCM>zUyUX2T!S~s_G1K5dBjclzfy`)Cpe1pshZh=czMzyJw zxupzV69eR-dg;6rOc+*o(q9wvkQHwhzH4X+x!~09_+!xhFKCl+`T@4n&2byCCg)!M z)2$Wf>Aj!7bWg(PIzD=6;@zisnuarlSc<@k)>%{o=sqJqf+XiSv(F6j@K^i97LV~m z5=@bCxGHV@ym;F!LYgy5EnBmVx(v)4s+w|Z8mvxQ#G0jFYakTfx-8hP6!0ci_3IyY|p6+UyhueX|vp{0t_xOz4q|5d`U#@LXXvwcX|;wyCDszKMsF7!(=#PF_lAs zROucCx#I7+cnyxRqHhyJT`l##IYBCg3rq!R%PVv$|yVy;rO! zg|i@K_NKnD>FF+iF}wqU`UBn%te<45pmZ6`=8> z<$-}a_@Rc!%h5C@{|r~#wlv~~#(VH25Xbu|6+TXisPuikoTdoi|#G2rxI*hn2P!;~uYfT6U)xe0jZ=+gK|$85nrJJzZ!bzxaRXlk)m#i`IySmZ$v zvO-A%1<8$L`Zkc0Zg9#oB5C#1(HP`KUIN-?v28b-Lzo}o^Lzv`XI@8$4_yAI{>byB zut<0S178V7f7I&RG&0u&fvovrDRtoi8eOcBh`9~^gj(5J>~fZ~!<+ZYy{}w4%MCAU zkwGMou?Iiek81L2jP&ZBo>l;h-XAi50eKu7A& z(%ht%lR7@e8A{L;;Jio=`SFOOr|KRg>xHGNz@)vS65iap;IUFOHQH(&{V7S>Z0~+R zmg$*OuS>oa5?F0>!3|+48=$yjmrw0}{*g4QBhJu;sI4}^pJK_Jga)r2 zKiMq$9Y6Uuz#HG49^7;8du`czx6q;Kd-eJJlKWasp3uX;S|`ux7k;cvp4BLyhaW#G zn?7(&UT{C-aNhXInlqipSCn#KDZj|pnPml^TZV4ba;fa;${tJ=SO#flO_g@TP-GJ_b4`j>^TUgavZ;WGHh{PNUw959{e$W%_h95X4m5fPN*Wup zeNYt4{bP3#)P0~_GqRyCY%`Zgm}3ckj#tEVj(}a$)tjwW`2R^cj??ZE^!RC=m^|_#2Ip>3p7bkF&w%(hMBw)Nab%C z-fLfa`G$3yD2#P}Z1mOsZ7$eX(yvjt@@kD7+Wp%KL)+L1#gC{x+ zFWj{=;GDzrI-E6^D1|=kMPW3rHBsi4m&s zJXkhjp!~>C;ez3^CR*f#(QJgtFM`=_;<$?e=Sh|ul}K!oro~j->?p4Vr^yZOa%Aq} zD6a-5!w$ahK1L5Jxxk2^pdu8#^fh2X(v+jAJERC{QzVLRpe&SG-Yo)>Jf~`DS>Ox_ zOVf*DPR`1pz!hSetjCE$OV#V1H{?_6eM!ZqwWe#2A_jNkTwHtPjkQGveSELofqhcF z9O@i~o@u&1vIcic?mBWXCeb?bAf{=XRivfg6_g^MuhMeOic=JucXLLzd3wOw4B~b9 z>LT3GvefDVOUdA;j{fHsJA2@<>-w5e=%_}XK1NMyLI%VS2)E}O&F{x9?VeB0J>%_$ zd#>`q1``kJai&6zx9X`PG&pq3(1^w>NOenSa<^ok4Qmfu-;X#|M1yT`!U;8mM$+9P zjY@sQx{S)7nyXvbgHwkgO_63Ry{eclw$KNBf{VwgDnf*z9Dh zZHY2f>acO=?rV^=i@2I8z+w-lYnQ1bqeASIzBjdw!AFuG+|5>#!A!hNerpw=grJ5BP6K#U3*he{Yf$ z4GpDrS96Ud6I4PM>pJ<3MX)^BxCw%asF7Mo>xj6{F8#HJWWG2tx`n`gVoTX6?L~!R z_Gr?>3hdAFksj^O@=om;v{wiet79;h{a#{=&52E>T(ixwjn=>U)Mj(y*FfKRN4kXA zi6Ei6btDKo!j3K12*0K_v`ZcAZ&iGm4ivTxE-a@L z4@9ZO#)rz0i`_NzPxswlr6w#7Q~Emow3WvJ8%x8vcFfGe{je;rim&oq+>(l1K~8goa@DY{hU1T;+` zXCE1<5Z_Mi$5YjRuQ_Yf|2VtD)*Gcd5<;kVn7Xhu=HJU}QBq%~a(A>7hPVf00Y5SQ zEOK!6i2zW^>4V$B_Q!;|C981U$lfk$=tanXnfU&5!Ok2BCcz#YCP&K!KwFOyyFPVL2_vj%PY&Oju zDvN+s%(;O*V^gW&eu{G4eLKne3tM_TD?l7d*dG%~l^&gn%fdsr@xm^xFScH3%qnoV{1z{|m zxI+sfX%z7fKSmTuDFS)@cZ`%sZ?Z!8MsD4n8ne4)aQ;rcd|=AVHJE&r%N zET}3v0~yejxVjV|D@k?iKz*~?SQeJbat+#P%U(hPzSQP}dU{d?pkpZsJ;4WK03XW1 zQ?Ny~2Op-oo`hTGfGcXwNF&dN$#iqH^4{P^j$3wDPV5X3EW3RgIye?rPIi_^mfZo3 z9Rc&323t!si|&|bHG=nue9F4^rK5<-fpu6*%$3Mq7omd+=WEzn^hbJgP$X36ICPB@cb{J zAinv9HDZcHjM%zLQuXPQafQc1m|7S|a0BK4a*QP+H3 znNB%vaa|b|#3%?FszO4kJ2!rYTzA`q;}z*3=I+gNwGD2>4sYsp}3mK=1g z6=~KIl{zHb2AH={1`_R6{Fu?&U3V4ME=2j*I#-bVM35?qyhD+N@3t;)=(&qk`?%Mn zOx;m!4VM((Ibbz4t?S$lw4QnsrXkR;iN@#cKCeF;z)%4$TR%P?Uk!GsO%eOZ;+H23 zUR=wbLRE2LkjPQfb8Fw=WEbo>)85Jh*oyX5(ME{<1F#9r#$CmOt2-V;EgxnL6wTV| z+~nMgmY)E@vfyo8&+^pUjSf=~tk}6E{;f~z!(XTwuDAj4Sw4xsy{iv>)XH#KA;T9t zix$mY&;6f?{f-XzOHExm4Q!># z3&Y{Ly}K)~bp#1V17oTFvs#lflp=B(0q*a<_1@V*VGEqXjWpbNvE|ygO8KuE`Jg6c z4YL^yspl-&U%M8>!`e_A+E7m8!Vyx8T|W(%ygE>W!yzKRUJH8m)Z_WlVmKBoAqwKW zScAiP2SdpDHu~X)uVAQ}lsgL-iGure=97t;jdVT+3dU^-L^m%f#M60Nx&l_s*@7}T zQJXK4cWL&q6ZZm%K;z<}@{U?K?Zb5a6bAFFcu50BX%;kl9&eDsyw{SB4cQ2MUQh}} zyzi&>4x+#GdKxG$scs{0j08mz>L?n{%_;;u6ln7bTne60!#`VQh*<%9GLM(s);uz1 zHW#+|C#8%2moh)RtC?T(tbQ)fxT{~w$)l*@OYA0aM7-gHgH?fV@ghQ*WN>skDn1I; z5J6;56&rXhO!jnE*$XWPtCD}*9d@{SFIb!5Bi%e2y3^>+=J1-um>#pVnEcxx4SFP8sqcB{I8*roFl zJT!7rXn=ac-*Q}EV+M9kehC4p23;${xHQ-uV9){eg^rIhYNH%&;5QI`Jt29wWP$#C z5{0;ZeG@g%@L-qjk+az7;p)E6f2R-8>u2bd`mKkd?=OFgO}`QUC(~wrlaQ_vX4(u` zCgdsSfbf;an;E1zSf-x)j08;gOd>2ke-QIrDk^U>l5<{mGK=Mukj2 zTc`Qg&7sqD#bHo0cIXzIldE&z@f6=ic&(Y$TgS}e_$h98$6q}FJv7b&3|X-KpvFxp)jwRGY=QO* zTDbm6pE1`*f89o3vKogEqq4z_(0%PV9WvDRSXO;iy#lsY!4=)t^Q&{CGj`e!i7?o| zS3hDZ*uT|svpa-yvs>Bugn#Y4XJUeWBre@7l)^G{rV=$Du5c%RuRaj8_L`n9KqrV| ztf#BL@&9*DS6$o&59D7y7x~|A`+vOCoK2jZ|2e)Um49{Htw=pPJ`uMZb+IUuA5KVX z^(X|R;ei0;;DA?7q-6kZZbij^;-M3)BxHQ%)h?h>&I+F-BKB`49J87zH+JHNuCDA) zK6@}V;AK$rt(ivyX9 zWgyGPAr=g5ZO1Jq;;aepaxdA*XY5e#^(0G*aQjaOh*7a14NN7o1ufsQ?si{O?S9?9 z(U{B2ut$T%Qw?PijtlR7ob6H$px%Q-y?$3+_~+^EvDo$YoUB1D@_ioHy^Q zmMkE?=d0LhV@q9pw=>!Jh86r%jbIMKoD#in^aKn+L^_5on&=5)W7nAz8spaf$llj7 zCRCTIA{zdQzwK#WS<|>AaK|xKigI`}UhLO2pDhi9GcJAa4J^PFo7ce+0TnHb6M*nr z+J*V>f!nPGLVvT38Yr_l_C?xgLT&ctLZq|^<$5ADtPA>O_ zXQ+}~mgEvwki3=)z4kn<6uOqcp>>x#9J|-`v3=e|<(uT)%=7Ul6)i*J;~F3`#*NaJ z7w=si^zxyuLfPmYLONswD~!Jpcwp>TviAMHKW(G(b!gh6?ph5TyvIl=MwjgD3*lT4 zFG5QJ496)Xes9`aMC!)#wqTvI4j~Z-C}O5Cf{LqSjZ!g1k{eyS8eliCpSl%1T6)1u zh{Z_AWk%6};%v*PB(TayDTFVNT;L9CkK6E=xhGlAv9I_@%_UgcQa^uGdDU&fmwZ-l z=5D^hs8Hti{yEUCy=r=!vY6+fwJbH)lW7PP>7!kLSgB^HA|*-EwF`}yaPm9M9LU}KH67lGSFCv?kCO#ho6 zA~G|%w|&U^16dawnKN5gnVA4a^xd4{h8v%6UHTGIgLpe?@Ov&$;(3-m*fy&d>%+De z7x<(|sgt&g1xuHtqNL8(tmiuUp0k?I&&>8rZlImtGBbkHg54VBnhOJL@;v7_iS`m; z#hwL=ZxG(TaDGpuIrrWbODvw;HC>u~@RYt}nKqZ_nfs1q&tz=!eEX;COwH+FeJ9EM zV{*}$F?-BnTlZ4T<~Urhx3=qVWFN$)D=%s_<4DJh-}lAx`s&)mS*`)~XQVYOR?Ez5 z+qvCLAgzbKQ~<4){$xNj-r8A?hGiPBUD>pyE%FK5Cr~SH#qwGtOgd_~v*Rl>m*_ZI%^!xqa z|Np(N_jg_2_j<3I=$tdpd7gXu+@Je%=A4nP7~pb$vFkj%2PFUBo!=*j?&@&>dV~Mt z=e@=M(+?k6SssGk%Q$n#AsNP|qBmOZb3*K0pLM^NE>V9_85W_)yfj;SRA-1ACFk1iJoDbQTUA_8Ipd(YA@MytIsun2ZIxZ>bn;X2 znTCY6=+@k%He!j*oS;WpxphrFqq>seMSC^6k!X$9GgG`arGvw%H!n&4syS)q=9p}n zA|+Uy;PE<-eJ~cQR(NN7Rn%BQ zT?0)rFSYd}YwM{Se6>@?WWl4s=U7|^7@R1}$!><6uTQX0dpq^?-_JAs|2BUp-r-wm zuJ)-5cpq~AfB%D~5;*q1|1o_}#aLZ5@V66xb+%{x^9!r*43bjcs4kl&B5=Or;cN-a zKg?{hi>cVB-&R%1oSZxnL@To!otAMv=G{I&6JLi*P7kfHibX%|>$UIAP3g;KF#`#i zEPp6lLYHbMva#`nH%(0?b>z4|JkHMLDtunpKPbSJNBJRjkHj}@L&PkIt9UwV94qsu zhLz|y0adi(Vg+QW0oWF7DBGRyz3+k6eq zi1NroWq$iVR_6cs88TM44{t;;9CIC#JbuuP-n?(4`$NUJliy1CiMi0xg7XCIz>x+z zMz7+B0!94y_V-B{PT{F zI$U-(%Zk$YSz1`nbyLKy6KnM9TZ}zlONIZVkDV9!mQFfz zd_IRherM!zis}?W;FfKc)32B!Eo80#vp*&tJ1=q0o`w@7YOJ2~6hHs|`m5_}D{hfu zABsaTPaUx>W3D(Ci~6=ZQ}&mXWowYz&suNF?>!eeJNAtZ^W|@$PJ-gObbi^?rXK^& zD3PpPPdb`MZaf*`jVIn{yv>pJky%djiXeh6;AaDgztrYSx%Zh-)bo56 zQTKhdR)dv_ADq;8ic+cN`d#~?o-#$5)=>BJi-9ntCMNH-7rqo%{AQk@9n0f z(_psHF>`XHM??MQ>VUd+BHzS2>GT(6F)y@ON^M9V ziB47I5LDikbSZedl~!~sit=Wl)NLo_(}a!m9K=@VG{*AI;l?7d#0$OG+1=1rs;GLV z?{zIWIS7l`=rFGG?Cv%+my{{8Ps_ahbGnH_P&ne=xuD}SslWT3JD$9~vXrv;#E2df zD#X&uwwRS4LK9wBg_5zpcGU(^5}-ZqO7=~rDH&tIy-lebTQLlR8XF z_O+8!)X$?At_d~8ji}6%2Zoj+>n}X%J-V-CKXNB9xDO`*>B2RWEi7*`H%TgO0iUI z3^PjF(C3BR!nLUwTca*Tt7AQ6OwTgY%c75Q)?AaL-ktwd(mm`lX_Q#=*H5&znsQ%g zLwBIn>TZ1WgJ0{fV#NotUuFot-;3*_U~rYB?ytbEM$%xkf(g27r(~PrT>FK;+`xA~ z%e^E_l=34hI8RY|Zl#Xvx_$XBJ`F)j)#CU?=XWoU3gS&8fvr{g+_ul0YssI5WsamE zL+Z<^3(-YszfwEtyqtJvcL8bsRnDFuHTTN^O4R@3GgJQKkAVU(ng934c3(wlsWn_- z{M@maopkH^O@|u}^sBu=jF|U&T8)au$*0v4N8Y-gi0oYwp4PqkdwijdeR@NU!O4Gw z{DuMjV6 zG4gD0_(Iv|_GLetsMjZW4D26hqAq6qj%u~!xUD23=j5#wj-s-Xx*@1~Jt$40X_}RG za@u7t?B{V@b#Fy$tBq9CR%A8hxevNtd0O_WuNbo;n(T>$9(U&taxLw%I$^3@uL-Xk zC;P*3zB7)!N}5mAUMhq%y$g!`lU^9evyP=vjw$AJH;(L?ah*!oH*nd?UKaXqTU%~D znj?pg+&07O|Ghm!|Hmu^Z2ey!xrGKzx87y&%5m8e^FJP#`=;u4J&IYJ$M8A2J=6=7 zQx+Z33rs_1jJsp%d3+gn^mH``uZ@=mpyACgO|eq>bCyRkVS!YM0h=H&n6 zjASoQ8F_GML-LyLlvE&PgWp78AS-QTrb}rc17Bm$&&#v&x$n%o4da7qvI@WwF zGt4_r)a#B6v3U}#FxG^apFKVFS_IjYvis;v)f0Pmso1L4~>v4;{-`^Xx)xMnyc2ob%5!CZp zuQIOCIpAUO02hVB@_zp{Zw{Kauj1>HHidi_EQJ0VcuIZIJBl*YVtZ|J`)I=Ved20Xp=J`0xU82L(sI zk^2(cfDg8VG`w3 zs$P+ej$6S5g-*PZi4mk=2>rDs&22VvhdVEh()mk^!)f~aw$E>{ZAsm27bV1Iy32)^ zFc_|lpAFhN>zMXPtVy%Av`PQ(7jECCo}c<(zEl3DlKC7?BY*YN`MHcY&+>$%evG5U z^M9wlw~>$KYrXh}cZWsrgzD`UErZ9C#;0vx&yAn?z>yd`)6jM!y0x0sPAWcXCHs>x z8?_Re_J_JmTFr1*oo7{+yq9r8zwWTVAN$W`)wGj+MsJoP#`ruwn2hae2>#y`l9Gzo z@Dl_|@&6bo68|xJxVjuRIR(S5(Pyp&&TOsyKHIJvQlL^}PSKU2%u9LnL9j@cF)amY z4KwNWJEt#(Fb*Ut$=}$>=-U<8Jsq{OW0J>kruTKH>D9}!!)?D@7hTr(lhWeG0yZ}1 z`?Tu(1GjcJmgroa{r-O6*!kmA6f?HBxwkt%Q{l>0xBL5Nx_q6i+)~BvR`!S5-RYVo z&i#&|!1t-mI~x~VV=DT%u7&iP>1%nBdymE83sl-yRv0X>SeRUAQ#nKev*$ zv$T=9RN@+> z%ty_)!xMul`mEMA_TEHn?d|SglP*PX-KG1(> z@xA|exT8{C(1gj>`ggS8598U^A*H@Wimq?$W+(P_bVx=f z#_X`2?#cCU@3 z+sXgVCBMJ1ziQ4E^ylxId1~F>P*C8W|KG-j*{^@S-z3`7n5OQQ2W64OY;A9?1n#VE zyMK@!HLv6NvodeX^d~64H>NJATq%2Zc7khv86FtX{3~sJ#ymBM_?M=E4^QY#)=F#Tse@1+Q(0XQJLH@gmyT*N6GxFkV zQ@pZU3zy{AI$%-z%PSK_ocl$s`(rDwH#f%qx~|*KM+W)^Dh2BAdKlEn)bZ2_)(sPi zo~#LJ?V7yo+q!AG-Gk2JSZNE=Q`=u(+W+IzAx->KaiMPi&r0Akh@zdgySrO|)+g@z z1^Mpl82-xM``Ns^9{FQu*VEju_AfzRrhR^fYg_u~`>4LO1u@RFS}Fm=%3Jxw+%zTm z=9QU09cjixTQWiItAE*ktz>%*7EQ=DFU@ph$(s35y=&k5o0d0z=Q~$|CSmWDtWGwH zX=JUBsq9Tjb)Kuk?Y=z)d+fpw>y%!`s1Ap-@?OiGqBoStA`HZD%Ex4!-LA@u?kra` zFI--+4$&vSA)kVD&TGoUzfLNM#yVK(tKS^DIWoT1mo7VHfY;0^HFL%ae(Btq8+ava z)_5j`W3?}94l$GWvaNi)a2T&zlMqr|sxmTF7N9ppFh8N6SDd?$K1bT8x|12L6%oj} zXicS`VunDaaOk`1*jl`3Xgk3M0vk4w^0H%i!~JL*SeV&&tzw~0LQPs-%&humurslFy} z46ZU&>jfK<-Ewx~$h@2}SgXHE;LOfoslWxAxR5l(XpFhLy778c5p9@e>{A3&(H>`e z3uTkr^-i#NAYyK29z8lk(&=rG6wjYPo$u|XpFDd--(QblfGdtZH%$0kuf#d1uNT~h zxfSFsvpqa36N!zEHqEPbbMAikls&P@zUE>MbM-?xeR5-RB_``0rtlf#W@|4c!qZ1H z3D@+S)fWXQQZ-oY`z$SfWQgj{l{U5rR_A`uc;h*EL%+UPH14rF*YPuSCRsvyc2l47 z_R>FI>J-6xvbc+Sy_#X}dx{Ib8pSHkv!6@Z+~~>`Q@6kQeeZAi{!BLKhU;t2Fi{G5 z<(F$cj19lrMB3ssB4u_X$)ch&zxzHuR5}sj;osaw^~b%J!Gl&&ztn z96s5Rh=^&96iwZFZvQYm!t!}=n`qK;TB*>$i`^o_V^vY2arQ4h|>2m1{o()gwaxX7aa|+(M7)Bn;+;ob9*@JI7;p>&VaSBa= zd*A;4?m35vZ8WXlY_Yx?B55D-Txsv~kroxVY))Oqrn^n5d?*SmgD{2E9osIZJGK<} zluep`W>_&tO-O#&Vy72*7$hMXoA5;L;+?13v6Z5;BBQbBCx%abhTm`bOT>%#i#3VS zom&h@rSLlXsDGSw@ls0T@F!C(Wv|M|NtctZqs2H_BBUQA$6yqmK0W_*;^~biEwLjb z1xsp2|Afz`iHDhntHyE!w>(^pAW5me7bKw{OZW6=tV$e%tKcb#_o_!SsX7JRmLI=h zpJknP_t3p_q)WI<`=au6RHW~);egy(QQwY~vMLR>l%$lp=UXafZ<|tjRFtbSdlPeK zxNe#6Z#8ShY{<#|s+eJ1?&q4BF_)8_Np{uwdm}4xKW)Q*_viPRC7%x#Yg$WMzH(bT zwPT|aXV!Mt_vQCzhQ{gwccS<*H+GAtw*O2``2Bt!d8eHl@%qJ$)^jDxrxtXtr}JtG zXVNs`J)`AQ9m_m8eSa4erD(|wbGEgK--y_tI3{UCAwU17B-+w)(bVJT9hCt(`QM$w zwrRUl>qa(Asn066iMScRj##zY+Xc4k18mj9xwYHUn&ks`tOjL16coF>cGr|odFs8{ ztvhiiM>@f%vZ4L*x{+V--1a@qB{X+IC6Cn&^oUQ#ea;*5yCRxfzYCI$r9(OW{$5;X zHkZNavVYfnvFM+o%ob|zSyR$}`!i*JDD!rTOu%|Fmb>GL;g_Iw*$)TtD?{N8B+;ega1Mxh>t4BZR#$3Y9I|&sdd@qvp|Jr|8bI+}Ge%Cnq zXv}w}C2lyU+=StUSNT|Kq*bBp`j6nqAr|wyr&`$p?^1jkQ4`Fi4_+xB2$LDfOQ(n} z(A!;&8{oa#XT~o?IY4`f^-b?LY1fNS>2GMIJm8OVsrjI49Mi(DRjA{^YAK=_RlNMw zde|mP?^nM>hfWaSEB2C*)HyW3ym*1 z-&BlVlv{F}PFAPLqP@h?F!{y))jQ*KW6_P_Euh#W85O6Xu}&CQSWlrlWz0)^e>ctPipwJK%Gfh^3vnWo28K)tLwC4>I_zCsr+Ij zpF16kUPNZ@Ovdt_(aI0!ObS|>z}V!b-kWR7c|nl)eNo>M+usy;2} z!$q4n-4y3Wk~41SjR&daBhl3BOzac4@G z{3;Hn;q(Vh+M>?o1F_7N24-HTmz|qW&`}XB z+ay}9-CiB_^M9JLR6FJs)#+4nsf=@Ni;JbIJ;{oXHq~b7L(A$itCyaKi@6#0>9>r; zvOYcycCm$0RdKWO2Bb%0ZLiUUFsks~LiuSiDGDwbHj78;;qAJ($K^wsw?_S)-aTC# zV6WxLm)m}LRarxw0%-?SBF>3%xHO|Rj5Y3eiP&G`YPo;!gR)`qSqu5 zloAG2_Xh7~lx|bP#6z6AY|Xo-Ps-jsGtSL(ZMhxw4`+U~C(+yz`}Ovxw>xjtgN2!I zQZs=pKW|4dX%D_AJGv)9`s z#%#(ZN3fU0u@%D#$7@SR)-7_3oNE?7Y4oSz_###_dkmHai+tLv+!Dn-Tccjp$|Jsq z)j8*O)HZpgH!@4#cx~P>{c~Mp#GCz8wVvAff_Lq@QLoZnR!-8!wk#KlSTk7%G8j@zxD>`rFeIO{|Hc-)#~VgT~1&SDFVa zY7v5`F^Ix*Si&ATig7sv876uSDq?&vd=NBwju)igYqSz{>kY_NaeT- zSZxdnog;+A5=7xZcQ$m+V+w4g)+wy^JReq@#hHkYkj4^PP-ubc2voNN9jbKy3Zk(7 z0n$O|0a7_x1oknZbFxU##6dDRmJ~~^JJ9Iiu^C1C4eujv5^u*&n!NNN467fwMM7$?E*5aHX0b@3qj;n4| zM1-2-aa1V;Ogs}2uS`R0#=sO7^s2bU{k2whszSDR$_I14}uW-bW5A!P%I= z3n51!z8)Y2OECzgA26T~27!u8#|a)IMYF!i#UQ*|!;olSMTEW#n0r>~r%*Ah!~Fr$ z6i1H25?~+k3L-QO3@C&pct1c!6kkDj!PSGSFqR1lkIS$p)W5yWgCjjp zNQal9$Ver67@tbvaQ1~7AxMX{U}PS+kZBN)t1eYQaF&vxunJ(Wkzi!C9Va@c_!z4D z6xhs~62lF}X8CMYcKfr}2A$Fe=>VG4zV6_`j=)WY$ zJ;NVQNU_?^C(zp9y>$ruHbq1O!($?TffVAN3{|&(d*)PGQJFIRa*enTV(2!~QsVm566PL$rAI6oW|lg~yr9 z;c+~L5R6hpi^&U+Yh39#2Vnx{4U&M_0b>GK2z;eM(U2y@N-Qivrc%K+PBg1*@V@|G zAVGCMgk1CR2f#Q1&pixA3W|dvWgsLM378>>%IRC3^~bzmI?m~&ab@Aixn>d+O-un1 z-%Abv#E#V#Cjn;#BOUA>AoY&J)V&Dxf9W~aLy&^R*R9G{fPuUma1<%}NuLkVLi`BK z9L&b!NT@$X4yQN)X-I|AYY#@M_d-4&F81cBmwgn-l5FLx<{SLc-($O2F-f7##AdHXhfhKz3M#Sl zKu334wA)jDthOB+n)Uo+h{HmFnFNTTLCDq-aIj%IDV<3;5}mGqShEj74vvDQ>gm8e zG^ohYD~gDD-RhQ6Y#HWC&Q)QB*iR&20{UPa&0r+DNgq*f5!8i}z z9#gO*)P!|dh|w@TiqR$vNpV@g`1>9bRr?V`nr=Cuh!qI|#1rR)JiCIB0BGdBdH7+T#5Fz*AVId?GOe{YYVMPX$H zf$#BvyI`0QT2%K3QZzA%G}f02>?Ux)KwJe>UhGxMp;2=zx0od>U00^`55 zG;lqvScmc3h&YJ&!|fIaPKO5_U`D(k=i0%IO^OI5D|W#y$@Rw(^|Lx3+vH|N&W4BTe{1+BXl1d-#PwB&?>vS#9C`LBsoS`*)2O% zKyR8T9^fo9z~5^&*cNP(XE{?NE^ksr&1L1vLf4wy+&j3G{rk>J`ItmR@ia2Pe`|FO z{VvYt*W^974R7I=&?6irTIn2jB}}8UL<*yxUK^8Pu{G>l2$&giTAL82V`O)%O>@iT ze{IW*ry3vh9nBs{bf2p%%DHZ|VWr#HY`K)3etGDl-eELGeWm#_RdFL-1=QjfRe(wpd_Q=J&pt<|unIuo#E@e4K z$7e<#m!YvGuh%_V@AK;hM4w!Lzl3lq-$6dGXX%Un5T`fVK1w$owqUkEES@TJ3M+FAb^g99**@rd?rpzm zgctYz_#O4f4+fN97+RaOOByG(@8+pGuF(XUr$v{sQ}>rCv6G6K3g?&YT*UU9W!9PJ zp6j3tHCwrOGu~3b~2Xe{WM26;F;Zf|UmrtKU z0QE#5)ty0?-A3i4QCBsS+4t;)7LGN}C9R_@U0&Zj>Pp`!FB%pJSC0(6U$Xh?Uijxj z*B%Fd>n_cZi}Q$05$D$y=7E>DQ#vNA?3sfYl6@kj!bya`U(S@#DMC1Z{=qJi))1cD z7jUhluZmhAbMfxtC5!>3i$>R1qG!%*V5Ly$_-=p>qpkPio}#csd`Cx~T^vDP;=Y?O>ru<*`EH`{G`jD0LBajT z;+yc0hkLRm?K_;!oa~D}#=63-S`1E0igxRP5~T_KZRSslZ|~Nfg%XKV#DaVq z%PO;>ZyRcyjt@jreS0olEbYh|4SH;mJv|o?Cwh~Me5(7n*8FL6>56AQwT`HnU*GPf z`dGDl*2&&A9b9AZSv4CxB^rpF;4X=-_LDAur!X<})~5I}yJ<|rSWhr#G~K52bgIew z{i_Odax*(RVGI+TD}e|b19|EB>l?vS4+yP!r(2o_`sV_!{aQCgU3eyDSnM-UDDJat z)*&QS=+zfv~iKjf*y;p@@PY-$b6Zi>t3r+Q|yS-xo1u@)0*e(;yGL0f>rC_0!yLGiaMs@455!UIXyGK!snxN9y z9|PV(f?^E8A;S`p8MtUVLU1ya&6Fp=K|O%%$3pLxOu%qMaIIAnlSx1j~j1TKaN zMJiW-%Cdith^L-{w&oZCqjQJ&(b^2kl?DNJ14Z!$2EYs_0VY$2L73$nLw%VC!6P18 zF=&&NE-)7*dU4UyZUO|)%LRT{kC%Z_Gx{CyzhXpj9kfT_U0)_}= zSiGkV&jB?udjag?0~30<6dEI-kJwN5!2%$0Wk`X51@sEmq0OR1bX#E~;$04$Z+J)& z^|Zr5xd1NNt^nNxH7Wk6VP3fxr;f#=2E3B(J04CiM$I2ZI>y{GZ;#8_x=<-jX<4qDV$ zPys-AoLtVpb@EVPwI>*`KcxDh+o3#is5!7sJ^dF_R#eb+OJcR9NYTGJ#6ei$1(pwu z7alroZQ!eRiihHhC7UsHX!#gKXk9u^7)~_^j42-YupI}MP#%gDgmBlbJ&K}PK7pcX zJr8HScm^xdMGZb8KV+_v3Eg;7Ef7r6&=Z=Kg5XpijHHqWWkd!jyB;uLa7iHs1TQSe zJi}X;2S8LJtRm!eQTz1vjh{epWd{pPLTiMJ_#Bq+f~%j|CWn zts{Jgt5VLt0izki$)K4G4o3#vZzu|g$zUPkbs>6B+Tn2uLl6a!nI{=Qrv(XR@(9S3 z2f8ef$6SyoK?q|E1P$SOFfvTgVeAN8q9i_7Z7~CC*a=87({02ap=LRA@wOx zIX|u-gh32BnEqdAdzRTCwOkHz?a)%B6^0N76<@)|ZzxcuV;}`K1|Q072hCCY0wFlE zKoJxy48j@uIo1stZqf@Bm0}W< ziV5_GW6*6T03?M#nqh#5BT?AMaAe*`4Wh*ZVMs4OqQzAXB7PUTicMGxSSak# zE$k0rDhM<$$Vre=4?5y<=vddm2+7cmU4Mlq_0a)wD1ru6ngVVHA>}|I5m|hUtd<0! z10->mLFjZcVCAs}ARa;gzIz}uf_OS`A1P?782*9@GI$#@7zC1)X16bpP3Hk|c@z*0 zJLfusk0C*?fynzpiM9*EAqT;1od*&L1Xq~8VQ26Rpl4YQWC{DJPRtPW!Cj7>7;^A3 zAPuI|hj>M~7lb>2kps_zbfE2Xo{0YnKgF5Qb~PA8Dvkn$_4sG<$X<4E%F}e5&f+l? zO)ef}#JB0BS{?woItThJ6am1XkD`B*BD~y7~lvG zB+!90vjQeqf|Y{mtN#|{y#rKsc?8aoI;?-%WDpCWGhzLMk&&+fsIov71pQj?4+vcw z&~P7gf^XhJw#o)8-wZ!co-Tk#O@JPI4|i9-m3v zb)NzOLNGN0IF_e!p(mZP?*47w=VJ5el+DSmxJB6x1@sz0ix;OwLU@IEu6MW{H5_$RVpQ)aBTEx19_q;PHpGt-fWL1X!Kz^HLOaN7@5e|q-+?p>*$HLoid+d?{P+Zyu+o6+?6N^f zfSTEVP$&V&$3S?7Qauk#1Zhy@xmY@G`x2-tR&W7>4=it$PU>kNik$lnWP;>86a`p! zF%|d>NY(}g2vDI&Yf=aZ?F0KhKu*W}v`EK2wSwq$1Kkcw{3ucbsjUeP)l~*u1CTC; zWFY`B^ze0JMqZ?oGGXBY8RWX56HufAY7}EFoUR&VqXPtq3Wv)pARjrvRRy@>cEAN9 z?sv$F=)u(;aeLrob?KxxQUIOLFoQ*0AW^`F4ae*R%fV`YN5V5ZyC~826odXb5fMv~t zvv+_49bC&2ehwq?6F)w<0W|U!0OGu422Qj5P%_0QK>Y4PhL4_&K$=bhPSrsshd2hL z0O8Y#rb9(C$K!F^0YIncK|enS&&%w!xA4O$&<@)d;OZ(!WO#7}^> zw$Dt&0}VP*|CHxXzzRUS2OBVS&)}|~+g-+F)o=jr34+Gj_YGVi0-1b(D z&^_JgT>E+aTl=q-Z}WVV!(XcP{q;{KY1|1431|3eNNE^#Hmgh2RG-P{9YyHL9*UKI zErv}E-Y-YhTO{lTa%i~Yq>lEzjb+z6>Zx+m!YyFG72!NcHLKSs#(1*+*|#fAWUr2e zI$cGY-akvfxBh2({rm2D#`mB4HyjgW556yJVaMN0&F0ka4<+hlWlt$tDB>;jb$^>^ z&BT>VWIWJ+IeUYuT2&*IU)-a>E4G{>>#NSw@#o1GRjWE}1BpAY-_W~oE?!~pv8Jfq zzD3ngH-G(3M{V<^_{jUN*O9a=)3=eTM+Zf0PQ}sslD+nq~}Z{E_1*9j;hS_p>i^tUoxS2*8pqjb3!yu45kuOu1gt(c0 zgYKd7n_`hj3kH+hBe`4&B5dCW;^`GXuzI{OQPgQ+X*a;3eHK9&@zr?Kl5Xe4df4>8~7KVabAVsaG00SSjsy)hj)1 z<(o*c+~xdg0}q__j7jEO)-2Q)xXyVJZ_Xb3T>B z@U+C&RKoWkX3W|2@8hB#{Xh*2De!Ap=D&NJQMcpO_#(d$Z z91eVJF&M@Eb&}h2ulPah%7~7{@OE*Hm)qW5%9*#+a;3>$dMZsD7#EUA(?!fcqCZ`? z4MI@$*DZV2qF>QJ#vMPdFL7B?dfufIyGwV2#Sul<*u5em-_+pW+VGc=F8o2ZZxYv( zrTMZf=X7E3`l+^P%yVb%Hcbrrv<$7iH)B`rq~DV}2yTrS%ySoR4XuCM@BQ1p&A?%` z&2{ob#NUPUv-@+3HRr#qrv%;~>-s8Yv@Py5C*D|!x_M#v+3(!^3xm}=DHh_VlHE=W ztAw7cOg|%+jf$Xgqm8$g8muts)MI*Oq!Mb7@|dX-W1a1yW~2GK+LBa7EUl(qzwDhe z!h5c(evgmcKw_QTSnN#-*X#2mrorciNxPD$X*8XcY~h9aL!Fnm*zR6x{QmmbY~RigsU)YWN${2?~}QklC}H24*Swqoe|eU zd&0#C4?pTw)r-JWL_J&6?b}_}FuO7a^AU}BvIx~sJ$)wDaQyw*!8?i9 zck0#yf(E{dN^tsxBzLKnT=zYN4)^Q$;Qd?HCr1xo_OepMOSX?Ibdjtnt=?Fenb*~W z;`^CRA-b1@{mUlmth<+~n5VInMG5)G)k|(akDnA16G-)X6pp3k8y=`~2#>C9Z;9UiLC7x6P!}RA z+ID>ByH<;#l$}c+`Ij z`i(QPfBnihXJln}vYh*;it$dNL}aetvxqpxd#Ad1c9eB%T~BB3D0`H;S_do%eY(4( z_Q`t5@sqfZ4hyZ{DQa2!JGGxTVlVq%uKlc(%fIk5*S&j*h9+}_ReU){FEnwfZi1ty z^H|hV9N!nEOIvoS(aOhoL(W~*VG`973#=hZUg-My=lkH2^2H!?FF#x$TeN5#jgqbm z<9QyMMluJsh{-LQ#s&35;|50ZyhZ^IrUvI2l@iY)lclr7COn20+st4O>ys1Kfy|!?A zt%*S5W(4`w4`JKSGj1scB)8}qq-KoyP0@3y=iWcV^j1alzDL!Ocq;8$$Jy~lH5NY8 zzY7=ZO?rj*tQPLMI40(~=;z&J^2(p9R?lm_YWBMDX53uw)sg4b!ijSpI)>%fIE#B< zTk1bhe;`4>%wNHf{a?Skuy5V*gNM1v^a=*5#Axk#%eK>>Qqx~yY`sw?(^w+ivY%^a zcI|}5!W??q&cU$nsp^fI>S*)lgFRl)zIPXvTfr@|UMNwowfy%Jj&5Ro}_m_^W~M@;1@=5RNX6=MDM-IqB7lc{b;>I`Y{OZfcu9@ zd_ngogyGI*g){&EW728?t~;`SkXkbwoldlM%o0Y)|U1~@<%0RVOMe%USnCq zfeSBx z9xExUe3|+4ora61BaNzSE=Fep!(V#ybS=kZRj* zM;ol<`CR$_RJ1HKteLH~vNzlvig87#s%w%mbWe?JiBjgAaorW+A<0^nqj`QBuRhA< zRWz6~Ry25?LHkx@pxpM9C-eGOH{PgTiOaNNLMcaQO?oJ%CT+XcUbFONCJiI6O-@_( z*Koy+&~Z8X=`%Em+LubVP2{&{Ygr2AY1Z^!HEeoT%O$6q7#S9$nl{`#mW|WC#C3-F z*L%(!Rk5e7e7l_WYx%SE?LT)fsuc3$EHfVdX;48viFVsbTJ7TRP5Syee4?nPh;yO6~8q_7XN9r7<*@JRVzr7$xvEt9rmK6Ow{qKWyxEG z$m<)gzNggRsn+{TeNW2qOUwJlYVpYHE0dAGv=iE@I-^yjHSay^iM*b<=IDLHHtgvw zk;J-7f+OWx`L>_$)XX&d@l}0cj#sT-TXjWGS_(PQ^GtkS6OBq0Uy){ucS9YWahQID zKblo~8fWq({fq`TcCl0an9r-@d=L7^Khd+e@HuPp3m?}qJ+@(IwlLX!m7njbXu8x+ zk#Kto<_@ntyOOlPpi(D?lAplIGU2m!mQ>HVdk25Ld*oKpLwQHUYHHevM7x%qqRok1 zovYtwH146X1?P~veB9E#F$_v95g8XIk_1ZhEOQx@P-kttXFtj>ZgyG_$S}6?6!Nl-eI9S^ zMZW2OIh#}eHl6$0Yl?=ju$M(AY1mJCusVu3*?nnw13N@_sFa+~;a^_CVH9x;$7m^N z%-SWt>X2M$!z>$^xWuPSmFL_MI4f<|hSyU%@^w2=(XQ&7lbhJ?RF-Pg3RZXGS=`AP zDb=VF4ToF)x+O>*r*wgGIh}O{o%QLgAe)4<=e}ns^%@x6d~}_)WJ_^tq<-`f4Yl0uS}S<@@v%?Bl#HK5dGKH$O?k5QQEzH1D^Ey~MjLt8;3~v|$eu zM6QSzu%5p*Fr34>DbHBwDpkv@(%GOrhp!eS0z+AU-yOyO zlGOb?u5d5fLM&yhtE+k)Yi}l$*jqO9thdbB{=@k<<{I`NkUH%OI_=w6tEiQ#=1(-T zM2yd$m^#lmtDGLzoOBB`#r?@586>7Ed}Et;8EyHMo^s&7}+X$}%Z% z%pvzN)R>R>&{G!uK`*032b)-(ts;BRo82z`@BftRD7zBo&1fmu7AzvYMUMXU$>4O7%>fpe25oJHtOxb6hN!8wMX+q+x z*5a=#vy$c#GQJLJY=6$EKb0w}B;2T1#i%z;buUhi+FshW z>|Qg4%1NF|W-s^H$xG`Dxzsiipb?JT*puRLR z|5KTf{f}?EKA^q_WyT!7P#6T9XGZ3pfsw?{VmKs8@PFqQg-rRq4FJ zI_*eS*X)+?+eeni<2i{EO(#EN|Gj+jpo?UGs5VcES-2|%kOgv_`bhI>lTs(- zsL|p_+{ysHWm8z;li(*g9vTvJKMwzxj|}yKnkq+TDQmoYmH=XZl^f`#0*k{X5daxXqX*)V@ zR}v)??NEJ|JD};AJ6_;(B=1*UbdrL~gmtUaNDO6M;F+WrhsNWGBSgjji?weIvMtE6 zF59nc+qPY=Y}>Z0UfH&7+qU`2wrzgZJ=6W~>xh|{h;!qfllRxTnLBgm%DvXoTrP#^ zgSb?%$CGiQ(d(Q=^0=x~J0C0PWm`Xqv}w=6D47lEac+wO^rwf7gz1_&4Ipd86%@Xp zZ`P;xyETFv=sWDhT-R-e6w$9d?=jdDlla45uO*^mR%6-zW%)-X6(3zz-y=Q7MvUHh z?bVJxV_?z#?$*i!P;q2xBqbuGVoVoaRVbBnv;HAwV*6WeZ(D~l2m17sZCvo8*?0%d z`hDY6@E2;&7<>$28q{evR?Zt)F)UNy&WD8qgGZ{@7dO_lF%+E)qvCSaiq9Dr9{*LC zIO6HxYph3_%ojF1uIPZTDtFsRTE)K0kn$h&k->d-QWW}tRc_bZ>t~7{4P?*00JR1e z_LDWAZIH7#gs?#ac&V6o%fa5**}yem5rReQG%un?raYS%F`&BIB~(@5k#4_F+zX5^ zc>jUER-81{4ahO%Ai+zWDt~c&tEcyiiaEH$e>cAyv zH=;%^Y+)s84jNZcX??k0?WFQMD2tap^t!t5;eI#n-nYqrpErt>8vT`nbcao-R~C&! zjdnC>)JO)=j*qoS=X`YW@Ze0X3=yDG?Vz*qc2BC;yJhKjN2);q_wAfY9-=d^J{?Bl zKqKF3#BUXm1L!YY2KAyA{K{rRS{z@teWlK!>?{sf+svcL8Zs&-+LUe2*B*@+00gnD z_wS?3``psQv+=OVB%QbM5>fI6|T;4`m-EsE?G7KJp|^vMU-C7MO}_$s35$Lfg#eu z+fa$yy%%0K_AjZoEM#iyz^6kW+^4eALGCl(9^Tq$%c4#lC8V1{eMu|F6qrbgYHG=% zf{riWyV@OZq$nxQ+MYIFM>Gf_pz9!na*RwG7G}YMF_m&9eIn08m$p#7mnO+bo-%D# z+SkjIW%R{+4C)#pnRGbWdjmUv-K9wrefw70rj!F+l&a7))ry@_>pTmHA+$qj9K>bpkD z;_xPp_ae0=1MX!xFPh873-~&S!H}NX`yDj?STP=0U}y0N3RP-2zp5?MEw~1^H@gxc zwl$5H&P(7ZgLy`Cz*LTMRozy&P+L)*sM$Hx#JU_D`Fs5oE9wpCXmBf&R%XZNx?TF3PJNduXil04x(& z!=>G4SD+PM`4Nf^u=SM*^}VzX%1K89Y0ADhhMDm%vNH(xbwG(C%$5VfW!5XROb<;_ zQG88TM>HlB%D@O4AW_+Hiy4h&LPb!V3^Sle=>9~c_X4^@v@6KFP#ECyg7@wfbRgH4 zOW+9QerLi~xZ(V`i>S{NZOf4q8S~;P$9Y{^h;TI%O6=@cK1DaqRxt=DA#eN>dP=P# zQr(4H=e6bUg3ETeo5I_;;5OD2s4NC25<;ZR+gE>+RrdI|5E*CQF62Ve$hxjt(iVCx z*@0j=Il>oF10y5m29)=(AXw=WLia9;TI;!Q-3Add^0z^s#lYoivO&M9sP%0Ozfy5J zsP69ue`(P|BidmVd+~*!!Pg7Fg&-o(6$OL5B`J8ShHnf*1t7VGTocNn01d^Us#R59 z+@!ayLMEA?IGtGF7U9 zB0Z(`a7ol?V!~IQ6m_*S31j9%NKgtYMV?U}3L`=3`~)8=HR01Sp9nvN+cp_=w!1lW zZx)MJcm@{5B~p{obmKKPT;oyl?{veT-8B-9{3>=Bh38A;M<5ZA$x|e_eLs!dbHJF{QP2Fr_mw zw{v7*rsw~0OQ5Hv|JNhke?RIQJJS6Vd;6!YZezTF<@#@g;F+Zww}gPYD5Ap!vdFQ# zox);dNje+Z;lRHZ#56jW;aN##n#Vn8Wd!C?6j0T4^SN2xIy{rYh`3f=uI1!Bd+Y3d zDe*Ub26Hd-oN#rsn41g(hzaZRs9^GeHNR^)yvoq6u*e|iO+bdoFQPN^U`}y?o-3Z& zE}qlZG&Lj`f8P|{#P;Kp95gdvB>K@o=J4`T^VKAeCKb~|?y z0E4KyAKt>znG)#oIYyEs=NIGKMp|KAH6>|&+4lV%WhdV+d1)Rp;_29A9)J1Xr(k?i ztW8L*?6^vLlgV(pHiv3jX!cHqvVNw<_~s$IO8aH#@7NHZtv<##n*Kcbb8)6mlMfYA zZL`CCK!8z>ps+bxXB`hY{Pn@?j1@B%)7rM?G<)_LiVW!cCC>EeUZ$DM>~wi|k37Ik zOr-mLk&3{L^FCPO{RaEVDDyL##>`86CY&)!4zx;Me{Q9`FiKuCvV4AW(f1$ zI+7_gzwAH*H_vNr%1DcG^r(CGO4xBBqYy3WG<)$cR(=~*A%B-dj4K*36`NLKvDh~5f5_pf|8@wipH}j zUJ`B|TGiRhR0nIb;-Tb}7u42`W3%U@-mDU{m-$4SU%$OP*?gdtmd`Rl85c)xL)-0@ z)CerfTQ?x5@hQ~3A{v9KG!U~6%YuWh_;)&GO^G17d zbqB4CZpU_n@i_S+>eiDBH%`jRn#{s|J|fIBEBVLhM)OhZhDe4h<*2o^pvA|f=mn^N zR_y#b8wg7am?egKr0o+{Vt9h9BDkKaKWO7wGE82kV~RkmWOa_R_5QH!=5$Z;c~gC@PJA@9?DHKJe=@BeBjw99jmWo zO~MC@kjS#}>QeK0y5bChzi3=&t(v=ox-hP zdfB6z;lOaCS_C_uP)-GzhycBE65@~|w7XWr_1F(o5&BR*)I3`*Sg(Efcs207vJ!K3 zbO+7LgwxvT2U!jh)Yb^EqE`N;;YZ(Mv`Ww<9D)^lNWD50`*Czh|4$YFe8r?GmZ z!VE%51V*-NQ2#XDoXxMX_^0-)B0EBmKT_UOS2;hW9c+Kf`^S^HBXpA$gMKB|VD$>2 z)eyAdUD3j@z@WceYM!G9Ws*=qxQoWbw8^pg%j;YtKUVz?nO8bKCNkGHVAR}jFtthL zRT4m1VT8fU5RiuIHT1526WDH)#wcD2hm+aP7hFAa8VTDkawX@`7!KFh{g6ZwmiKU# zmaYU1fn=q)$X{w(Ho1ZZ5BlctIB@F^SmU-1qbV7tJ$3dxi|2UVzfdD}!)hY?=LQEX zaAbNtBMtDEw~T5B0Ka;IuldIN^58*Ed8bHYuM}lCiFnAm@Us$h;&r5l<3YVq3rWiG ztHk3PpVEuE53)f0X2*B8=3XMdA$uYJ`~n~YkO9a9UBi4!v!dT1ajNM{)hxz28EDUd#DGx&(rvO>Z|PA-x8 zAvH!i88A9CXI1e159GE&?7@N&hdsK#9S`5Vzq&=ZunkZ_>Wc#!EamEpsNiARx5)8u zBU;j*?gMR0a!4rmjeBr%K4Xsm$cL*QN zZ>jc4Ot*VUjvBaruTa#mB~$_b&km~AnK)si6s>r5M|efVll(g|Xj?ts6|bcyZTlC|VrjUzaX0hT-lCF;B!hs#Q7;G zYJFi~U3vtIE>d#7!Eco&RyZEiE(8-rt}MyJQF5JPX!Z3E<)^*Zio}G^4$F1q>OwSX zlkDRI3vR#4vv^8{X)udj%|jO2$Z9)pj?d8381}LHuWy;@E{d~X-x%IBehF=LII~LKh`w`~8H{Z5z*QBbrWi1ZX%>&FRz?x)h)C+V( zdxq#&Dn^|tl!bZCODg3gg#imY&f1cFS&QQy+%|psII8!&bWMa>QDl&g86IR)oC^>k zT&O4jWEq($8kOpe(+ul)C3j4l$XH_38t~a4-NsgP|oX(EIf$%t&t*N`pOR&*u_g{m2#3}V)P;Rr|881NL&IOYik3AImX$9d9; zC}0Z_pL?-(u6~E9E3Nk5*HX3FU7PQE9dO3*q&V|ZNj&zqqpIlbZLw66$rd^6$W3s>U3ue5wR!4OgwXt2N@K^Gu z?{U#oL2FkULDmu01>0z`^#v-NbL!90u$kr1Hf!}lml{Nhj(Tm8OEXkSi0eFowlHtA zq$*9s^DAGnmbTf)r>Kb!Ng?Ah>B}#=M8ke;tAk@vucpNrV?=zFrCOI7ttZ`f%W9xn zs~?!^i#=Hdf?ELH+AJo>@_Dguv)6aQm8Zkv{Zu3HA$+6HaNV+!Bd^uKh=G^Q5U;oF zd52&2C~N5lp6Qnbvk83pU9RRS;P92(I|<8va&b%O1dGHaF?(s91Lib5L7dmSRSD?r1pliwc1k1HEM#<1`t4 zg=MHYJRDCu&Uj!Eh1WAgF-UnLxUB{mLSP)k_`vYRta)PX)t`am!^c5IRYU&2lDSV1 zO7=i~ER~3o3l@-)z{(J=E%zBAhp>s|!+{JFL&>%Xtoi!CS(e!S39vFDm(>}|<^yH! zIcbs}UqxJ=zRMB|_za1L_r|S9X{*0M{;ptREgtv@!JHUkUhVU){aP+$&kH0IL7BWZ zy&tLmj%#A+;3I)2OG3^0UMk&W*yRGrWra;dwFLi0SgOrQ6Al<>{XrGTE;T zCC2*tHxa@&9}$KI6xpN4=#=wF#%8)9J^FsbkB9i=jqdZ&Sonpk($U3UHc)@yl8Ig5 zBtltYc++yWmCN(V37TuIkdog&|GWw0 z^DARdh`xx?C$qH3uC>7iDUWnaK6kWY5bcWe2ybi4FnAL(XkTkn6B75yu3v~JXx(Ap zvZ!ILP=9HIn+3XTH44a#)vO(2SFcV%8Sc$#;cxZ>WR%$#r|=k5sOODRoHM)Nz@#cv zyxRemOvi_@zSXt%4a?G(~oJo-5P)U5^J3J?AKyOFKWD(H9i- zpoNraW-{h8HomZeD8jN`mE@8Iv1`~69+OSP=ooUf!y&`aNWDkRZN?PO$ChS|z^P8F&K=W$u3EnGD##y3Ja6-QRfICzZu9L@t#x zLf*|Y4&sV(cAy+s)DEdSeJaTk10qPY%gbMA)$DsvtZK-710t-SDiysZaU+8vFCkq9 z@^ff7jh7QERPX<;>IsrjA%Xk}xcvW^75laAan5!6Z3#jP<1cBK=P_CyVt?;WMeB6ILEKgME z<{3yYP+Q8;*vrtXIw#w2s-fv+Mm;62Gxwod0dWMhm$u%9@Znx~dspz^&DdBDyZy;* zn7%f4Cxyz%()m*$`kSo}xF5q}0$0YG3c`+nwT6QlppUJv)c{m#?RP`1Il0brUlV0- zidA8&dMq#i|J{Oaqw<86QKh`oP!8lupcS$mE+4-4wDM=iu$;Q8Z||Q~?PTRDc{_=7 zd+=uqfQ()MRzKWO=~4ZUvx^4YhmO`YX zrxi8U{Lm9WstFRiKdpl%v`=abzCdP@rS=pNDUGO&dNkykZ0Rhc#m zWU?-lGX!lXo|)r+?RK){p8R2#t-Uv^K5s{AKXsakygokSqrl+nukb&W{5w;SIl)-R zImIX;Al%wmk5Mof9)8}1ZbsBqK8Pl7YieglWCdx~P1@n^8W6RW@a4CRo8FOr9jGi@ zalqL=woj^e2SW(lOSi_y*XMuMyF(tk+tQ4m1V8f18(+X z_q3=L`yj$GuFu{%p~o14kOb8L==*7jX2tl=uabU zu?m^n8Lf|VaxB4?JyoML5I@A!M;lM4<8ZkcDZKW;RQ>|_@e}J*{xHDZeKH38>n~_C zRjrb5LgNA&GU@$`@bOz2^5Sf{93{VvHVSq9+A9u*SHr1p*d0ioHl+NR{a4`=9Dm3h zEau8#?|Zk*cnWugdM^^1Yx`!|Nxp$3Vu_Xb8_n8e>6g=yI&vPhl;fN3ZFIbD&*vlZ zZN70`p7E&?2J5qp1W!P$(pb&Bl7zC8N7=37 zdDlsS#$)rpD$6!J zl@LKraX)`e|N6iy!Gq^q`DQ~52dbX6Tlu3At1)h}Z$=^;_OjuoSJ1$ctFu2GV4Flp zx&JE{h#4`WXnEO4kh2C-^&o_H9h2fSGM!J6BP_63Gm&b6mL$h=nT|pAuEBPM2bvSl zW-}Z51OF`SiJZWbu)!7Ki@QnJb$z|lQ)Yf*-d)V^6YcoEdUHF?#MfPL`&zeSDuT+s zgndS`n@9XDgd*h|TlSkifnQiV0_aO<$6DIY@=i`ciHo8^8VI92(ju#~>Cpset3N#- z)^fxTN$ymLkGJS|J&InT@l^M4E~;W{Go!_rVTgAuQ)%X-&bT5rt(QO2?LftP9O*;6 zUDfK}vJDywOQ0f1ZR8xU%v@Y^BZaIqlLGlp0+|UsMP^Y?O`?zx4SDVz3J|UMNF#d= zciL|9v54s6DqG?$<>yNOdjQBKU^uf=SkiDxOToV>><3+rX`{HOxUD3b)c zgpE+K@$~u*L|Kvkcv&LolAUmLqy0Y2E(zRrSU7N!0z1Ek=ws@@-+!PJk<^qc)v(KJ z1xSpQ`hkY8;4Cik2*~7<)OlP&z%i!5-qvi})kSpz7`JP2--Ouae!44^7R65*uBPvU z`fh*ZUEP&moCcj9m=!N(f3L*K3A~W!@@lEIFzE##!2Yj15G|%Nitz{2?EH_#ra#B=|1-e*zn7(d7o75FE3S{n&zz`EW*_>2 z0H?=MPb@B}AYL>OoZskkd1@tbCLuM$DD|3H+b1Y(emiep({&W3&6#=d5<^>6@5F{U z%2oVb;IVjoco=#4(IlB6V`vXIy(N^~gKYl@8oux7Fk|HqR&{K2OUxT5}YApTqWJ=P^Jm+Cy?XW8{IQeX0AMoS%O>V3i5yj!fs=mc$JDh1&uDkVmi0Q$ONeZaPkMwn@!zt6};~SnW z!p%K&I>s}n=Yf_J4VD?*3G%b1CuZRrzCD}iB0Bga=No_;mbcR~ccG!r{n}`SfBh=^ zno~1p=Ia`0&X;kd<7)c)_!_g+k|^+(az;*!AmG3XVei^WhB+_v z+JPSIB$0o873n%H`mk6D1JVxI(1*y|;O2JX8fQ8S?;Z;s_z6UuNLE5$8y$3UiDTIR zBzOBf^c4{v-h=W-l8XtD7(wOOGSHjo99cfHW}1KW_=1CiDgouLgpau;S9#=3Kzl-A7SW-(SP&9SeCDV_%- z=eyFIDMeaOPIeajJ8WYV@O03f^r6zBui8)&2l}tjNe+b3rQ5tFp0rJ37tMF?u5QpX#HCW=#LB(M{w z7&6z}tRL+7l$7VPKmY@;W1E={pbf#-+RbD!w_I0tM#>Ji8fhs;@;5%Zc}reP}js4*xl zLtoHld;ELvk5}%d*et~N?BVGpG7GxdsSDE6>ESN3v=xaa6~r2vi085nM(4e1e24Z? zNMbQU&s3gyE=-vF5r>FT>HG<$CnArSQ2LhjtC>?Jjgc3|dAzJ*CSyeyYo zX}kwdMmR)h1E&Ldj(K6vTGjLC^iy%}*gD61MwQq?>Ub z0QE{Q_i2jzi3@>^Q7;g3c0h8Xm^uf}?>I(#JQ@QhzHdajWHVk7JbC5}v&pjvx-VPy%WvZtoX?E`pI(odAU!a z=E^tH=K(ek%Gi84JmV~t!Xk?wm1T~>kLV)~dO&>ZpM*4`u~(%yqSThL386k+(g{+T zIZ0pE`?jns7kLFLxb*zO>akty!(xVL@>E)NT()Eqf`KXV4C~o-M{+wXezbdDHlJ8f z_wjS_my5JhuRo9C?RXBOk^1{7jq{^vORyf-;1P!-1KuTw6>LYqE~vKBd>pUyLQ5>; zEkS$R)KaF^Sej9UU^x8+Y~p)f293l7u?BHK#_C_|P9wU@g=5FBjaBwA^2uE#xIU=9 zXRfv*i41&r%zm$sbS`|S_rGJ@MRIMoepQ*U#7p+etC(4j4bDk2fQO0oZ?C(__G!0X z+iXRl)Ufgq>nb0=#e*7X^NF0#R(6q~EQuk!>5MGEDMq)1%H6PqVdj z=R$|2Opu#~g4C83Dw!neqB>Jif6tJ1M=`1(Gab7*U*)d&_2DOmN|*oRvM%_YXj>_6 zg#}CQ!c|J$tSVwv6TZSao^3%Je$b5Q=TNd#RKDYb()UT}zfKOEk#2Jk4$^`s4+6h2 z?$1^Mu~kXf8pWu_I*(%+{GE3FZU=HYF z)fA)~cN|MF1~MR07+=TZMdm~--uH7O{Q#9z z8CCzc=VF;jZg-@UaGV=^oFNVa^`4bC`iH&KmZ5BD&wY|MbaP1#V-!qgk7IK*XO>R( z*R<&69EZIkKrsUv7(O<>XdjY`hqRi@f_jmn3V*3`(w_LsJDy)_Y|L=+`g$Kw+3aS7w;LdZ5Z_BdZoRa zgK{(m=;bI@2Bq}OFn>w0(8F81d6B2&t9;4#FoOv*L37X4p-zUKoi`g$&dlluy5 zHxTSdKp7CLrSbK8b-7lg?w^61)4T}#;3B19SjpI9VbarmK$g$E^R+z3n`*S!lFs?t zY^q+RA>Kzw9!D#ZlA+itBLzpBDW~Q~#p;4ZT&#n)EveJp6rYQL`qkeTKSZbEeRvM1N@H zXi{dlptk}*1eR+0=M_wC0RS3?9$`{Up-%_bZ=x-kUVx<}7&^YYwp?)lG!0H|vuxM@ zfw1y!(M~`VPQ}xr6+aBLf|q3jU>cYf8BXSUbn2`D);V%VpXNb2VV}L08}`^!7_*VJ zHx#PG^MJ)nVJj5M)boJN>})d>ip+D-YBsY45oP+3+-!ET84*S1vGlJVg)vdJe(_-w z^r2#@->Q?j9xKZa88raRgwRrtG#l(FU(OA8H8_bGDwDO?sU(ciU+wqad}E*35f3k;?R}hkNz7!1x6#%$(S0&rn(OD{PZ7@boWiO2Lm}{F zD{nF3s7}411aex04LuR~@LyD}z{Muvcwulv91tBbbCS5X#+rb1PVyh6S`o%mZS{Kd zT791Th|cuU&Sh5oJSrxH^4zP|xSSnhr+NO$2&JsH!K*H16^%t?&JGtaNT zNF`=sHpn-5K4xS<9v%jl4-}FNl@6P^*Kzk4rbfO^H)OO|cn(X~HKZZ;n1{`bB(w%0-XUU?{addUGbV~c+yan6 z8YY<_h2knuVeNbob;i0DdtR^NOogHvx5-RW6qX1D%)6bK*jQJ?PJ;hCCqOCz35(Yi8u4>yhS}qsXGb{ zSI3k$A}O4*WeCVSdM%1Pv$wOJEFhE+F0Y1Am+lFGkcmpmJI?r#CUDqh=cfg={=Yf4AmGv#;V5of(Rl^4A|^_Kp~JG5FL-(>A(bOC(Mp9 z^aW6aB8-4nP02pzJ!0w#oqY8G=ZF|z2K5hgc~5a>GNy6zC77iP7R+oW$+9+llMqW zN;27>$7Db06TGx>50BIE^-~*(q$f+#<>C&6G>Yn+LMBki=%C3^Jxag|diLZ6(ue3| zoI6O_0VAjqv~yu>^NBzZPq}T<>8zFOBAsVlhyf|4&_knIGYsVDmwdE zk?lBX@*_7XYhs6KL7tp61T&P}!xqcbvYJhOqrj}TYXm#YJ>x_#daDGv=zAogU8qV0 zxtP18s9ZY6JBX{lXd`MXI;HYgGX<>_4z-bn&d66TT-8C|qEB7bL$57HnnoUZnyC+? za5RG@UIGm#5(~z9>x{?aOl(JzKe1wH_T`J3ek#er+YUzSWis*9NgV^(?B7rsu)7bf z_bzC*?H-bQ!V+452KqGnNT)X~Frqi1*zC_#*6mO=J%5e=(O!_Za{G1m=T+V;diM1! zYck7iBTIV4u_$YjtC-a!PCOxxP`BnY8z{)4r-VOm?V3Wa^vM$nx%@jD2y_7KD7x0{ ztXg$-c=cJ*%F?_HATFd_$2#BEP~>W?bHMxD5pG=P^o*nX_#C*@`no}d;Hg|QM>qFq zu?Z*LOeCB5rX%VN z^i0NDvtm8H;A4%eLO1_uv1wfc79y|3=A7H92vlFkbNH)j9kX+T%t=$$;E;I}b7s%- zwAn}Ehe6y?)sW_+zqu5@kI(y%X$ko&*g;tG*-!(ux&+hWs9{A@-Itq z#Ie?JE=E7aH%2KeS?BPx!ERZ^6$3yp3yTh0C!Q>kEYf`G@_2_gS@4{Q5NYn2Nfr&r zYOD$sz9j`&+E|+djCwIkQR<~EcYbxqV`Fs@zf}VNn_zBw5#;J-n;=H>#qNa*K2E zgQ$F^{-@Km|2?Ym-;_CSZN+`@_?h{d(e+dCR2QryVqa!^ItXsd{$La8sA5~SJ;4=F zcKUdsc+X&6m+R*VT1n-ix7iS5m*afb6dyCC^2y4|%E`(Pgv`ud_j+&X2 zo50-~$jr;T65^>hyXIAXhAe?_rc9rKif(rYpdKUic<|AjB@Cl6T5SV0QYx5p7~BL~ z_NZH^D_sJhnVy%#!y2sLwXEkP(M&L}iirb^;k&p4LiG`XYO901dSjgd;Jk0 ztAY9p^r&hHg#BxJ{SexKUXLa|dhmt)fAl*e=nx3|whtdU0?m}7X97S2&8WpEN8kMW zF#Kmx2{RB0Ag@f|0-JYijs(r1uYL|VtO=S|5d<}BS+NAnpodKiA*}nBFPH+K)C>mv zXOmY25jc@_@0s}i%nBF~QRrMIznq|dnPBc7O!VWM&OOi8s)}oS1Kr623BLpOfDMP( z*TmMsVXMI?fgvv_BfFc|`eWoyKfUn%=h&}C%8jU`^-U1{AQ-D z5(TqBt=Yf58S1bR-$P>YU&b};q7GYkUm22e)9TLLy(n?+oX(DJHm_f!xyNtc)_b{K z!iBlM(skSj;P&VYuRq2Gx!I@Lvu$z2e%50dVYpbb=XHvi(z|2%^ZkhzRDO-~T;21+ zc0ZB(EMRuU+Pd8<7; zoVLLmeG0Qmm;uR~PvGgEP?EWZJ%VSQ61TdO+C@hAb+Yonv)W>gx%&ZxAqMi=3f}VJ zc0C?eagp}hEwtN2!Jb{4cW*HiVbl?xTMBhjrBf(yd=)gV_?-w5Y?EBQ#@7%#4pE&! zuN`g0%XkXXeOy*?-bOYcx3~|Yl&(m^!WNf_aWD$*(O1-KiMH69)0)W=VPOyq+9-oa zH%@(Fr#g|oEj3VRxl{w$v}W!Aq8<-l2wMUEq%UpQ04bI4Vh_b9ciw0wDF4PZ9}hb? z6VV+d_mPXcvLpa1sqt0H1Vmb91K za7`@PO{ig}Co!`<0N zDY(d{z~xo04BBjf>(@+UTkreS%MMb}MIWcmae|vfO{>Fpw06fepLGtX*tF|lT>l_N zPvn}@E?zGrY(e4zEt%Aaw!5zbkZOl?_m+*0gpA36RQ;MYQmejAz-B-Y9>+b}a7bRk z3$jB}sAqf+xz^2l9(D}TMRq(m&agd{7>JU6Fpc0iI z>n(tUa{+q3?U;wi!qRq*9n6nmC9#C%1C54lD0soj_a}mbpzwb$DS~q5(eleL-30D2Zv|(sRpMcaH zpk&tSi+74XZD8CipV@jG+!-$e2~YXh_2|nn=|&Q%(`uYJwxDHe5+@}~xG%6pM+KJu>$Yl*I!3F5<6RUKb?0F@$_0gg_SQ2W zwg+DNeXyYcwjhO}i#oi_DKg*iRpWq!#O~1l%{CQ}iR5-9*gbwat|OTIM$AxX!U~m# z$*D0_Vwfz&EFN}LpiL_~2FSzn&IoxVVI6m%#5mM$biVOEl`C9&<}v3{a0sC&C5cqb zeVL>2XfBAu-y-Y>N!GgkAeqG?z5j7G{PG98PSy6#ksws>>R#QGT6zYUXrh4mdHHr9 z%ye;whe-X1y@V(sFQ=OX&~}P;g)}-}+oy6YpBhBV8`76$7#9DlN?L#$comj@i>Cg1 zkU&C{?!cjGJ+*k{vdnx@yiDNtqWySmF#!kocnq#+DSecKB?L|s4=AjmuRuXpeqBjn zT}^RaO{soj^`g*75itOG-a1UXDOvQ|=mu3vwwJi0Okj51V#VSU9s zdKiYoIsyvzRIZaWr?;jxl_CXw7mkI6RH7GBjifcs5;+xS`M8HE;{v;P1EJ4%I{Dva zZlQP*XSW15kwA^}+vmjJw6v1Q4j3p0M-q*DUqLSwUp2#I#O~Cj)XWGEfeUDasvns4 zF@$^wAwE0|2P7!6BhPm2CA4a)=)@UiWzh9Ot7aBsr4K3!MEw$-R*(=4o#5*2)B*j* z*%nFPN0Nkj8w`?K#?17{etV3vO>zuUDMMI@l)R=6rQ#GY%rAuP$T-br4P5Z3wdiBE z{uNkik%w$dYF;X5>7xojN@W}zBDJyU2@~3!0YQt|$cU92g^_m2!xenPVhx0WG!__4 z>RoC|DynbfrXWz|`S{k7Vs#bd&8$TQ?8?Yu8T0ZRl;IW9r{n>Y^V338P`WRW$xsRmEyzDn>vU41e53 zW(`HU&#JFZ&LO7WXE4OD8roQ}Dj;q!h@mt6nei%8AP8k%jb#|6)|~k%vjdl99~y!y zz-DD1cOVx@A^T$<8C*GJ%(PHlNbmR-Db}OB{=rsbm4!$k@G|!1@B)YLYhoO#?YAd1arp zkFx%8wVk`(%lo=9MXfR3^93`E-26#Sei29KKjGA^?BK#uwV<1?7C?+?p-+r|V+O*xkMGiJFH)2_0yUdzTKi8S`DWwkAU>81gf* z`KsgN1cDHoh@V{P85hyzk^kg)jE$D|hia%RqBCqm7v$5g={#7`nKh$OJuguv0ktMd zU~K7wRmeFxhg-0yQG!v4vBO7pmg^@O#+LKzc2+y)K>ZH%xp?CIy{8K^gM!1Fb#W8!twaoS!YO`4ZCti2gG=P%9Yr`N zEGG`tz*%tDuBdHlyeROk2Qz25f1jeLfd7@yTe8QHe9KDZilV^M(#d+Qh15wqiq`sm z#h_yzT>fxa3cUnqfDa=6<(}%}HIXmlK7{$p%-TWnrNQ#mk?ZEz<b^O#Aho^20rm?>sT(&PS6R?KC^0_7s!({JJfX^>RqoMDTIPGvs;mFR zbl@!I#9*FjoNAgm?0jpTXQ>--&{t(7MQ(|+``WwsnRkKDJm++~%GOCw^RjE^VawFx znyKqKZR`Cv_(PiiFl&6jK2C3sOimfI%cAW$Q(67|`)@(H&a^z7J5Q#7HUeqySh5=Y@=={`{0wpgjei8)HGj#$Jb@qwuz@1mTG6qz`n$;9=oI+Y z%zgVVojf9WOCycoM~EL#Pq@&XzaTDgR5Fd`gTuH3i8$3q)n|TNELf;^&g9UCIWc0> zt>%Ob#)`#sK2Z$CT(po#)A;{YcT?1CZu^!rg!wv_alR{VA1cqo=%*Xg{n6Ay`Eo$rJQh)Y>dut? zH;&c_#4(g8#?bf*fT#q}Ycps7>J;Wc@A>0ShKL+hu9{jcB@?z^1%iND=pts+AVM;h z-i^MGi;;OkZbuSC^gN;5Bm{dxt*~0z?_hjlxk&mhY+2qZvRWiaulxRvW2GwA zgGfYA3}T}}J$WCkf!%!FiwmJl@ow;01+>at6mqhLfRFvK{T`$vG=iWg-DqLzbOz6N z2rXH87lO=u5VXCA!jn%i;mdSOw)lapTy)7IIfH=I)j1;{-fV69Ut0_T_rJORf^DT^ z)DDTcg9P_Fqkg=7JrMRBChF38;mVqB7wb-UU(n7RCnS9B7rh?PY;1edw6MN$a`CK! zZqRyXduPaW`J?YT9S`8?NL7XlH8d>zdfs#pgzq*Wrp`NUB+72?n8lSo63d}o*JfX- z>VMXNX9{-XqvHiU3xkcf~%v(`M6rDsWs6oT1H;uocy9C*hf zFxe=&>g+ZV3FX;oh=uU5CRh#wR4o!39}jD14C4R=m7hablK&M)jP0B*(dRf0R_lz% zZ-?eug5p_k7v(x%n+>Ze?^YQDZ2lz>=r?N zS{g~oMSgeUuN2>5FP&<5&UMMY)y<4!u!;e`5p+UA?^{A%a~PafG09Tm0Iw#@{TWN{ z!-dvkD4>nYDX==G?~M+J^XX{7XhiyPfV#QMouLDdEv>0Vw)?U4>Ah{))H9g45NAS?K1gvL3^+6Rrw*eWU97~X?8+nA51yyw$a95~H!UleL_~v$6 zBTI{|H0&W)r>tgPLON8l6z$!U+d>f8SvcVUWudK9d91bA`C{xCDxxYwi6~p6uEb_! z>s`GdGOvp9>U>Yh@N&b1eQdPU6E7?0K*I8%n4&}YU3znV`wHmOG7IZ*-uRjIs5J}6 zx12a`R_D3KpwW96Xmc!Up7?%LGy0weI9YX0w@EnStB;8%l)^}W+NZa&G6h}6_gO%m zoBtkwRikX%J6+Tl(PG0r6E%g6s8z2*bnQR%Q3uWk`nlsv_A2B&Zj@x zE5;7y|DgSBsA$UWk0SXr`-&Q;;ZOldikkwr$(CZQHhO+qP{Rt8Lret8Mf2jyW@zf5e`M zT^AMg-Br{@=9`uIKKX2+CvUIjqtkYCktwZjdXb_eB4O|B?hM^VGMEzb5Gr}`i9XX3 zYJWLUAodde#-1a+7bR9Nm9OY=+vdId-ub^G?^6T-{o^bA_$Nn-4#KL=kaCAcsl}hl!(b>x)wRCbs{FeL?1=Cp))>_EkZB|r> z{CCvs*%y2SGeW4mMSr-C893ozWHO6j9}=-<81%PzlGy&9C-?%Z_Zz%8@=b`Jf0v*t z+Qvj!$9w1iw+!(6T?xcMXi*mH&VVmNY9;OZ&-?Ww@Avcqu~-?d18PH8_)A?_eP1u# zaAt`FLDh=w$g9;Mj3bst|IN>Jed8kwd22z<#A8nfDsg1|M-91W23q3*#^tRz@|~q@ zNel`9ZjL2$5R13#kI`8Zb3&`G!{&9X%x1ITes5b$D@&#tGv~>(Vc9&##ka@TiEU2q z6C`|O=NlUqicw?^caL1sG=Mcn4)2A_ZY+pzjRN9HTOCGR?p-W{N3WJfW;uzl2KsFE z9WnHFC8SwvWyp}to=kKBFUIEubm`W?FagVq{Vd;#`NGl1MaDc_t==i>0{Qe1M@E0G zYEZMvHvBt&?gY7_;L!4=51Z|t1pMH_I%PWYIf4v!1pc9u@T)yjU&tF7I|ny*4~GXE za9pAk@DGOEsQn})UAJAOJ=BFOR1NoJ^9Xh>a!T|wOwN-&Og=#yrkLav_B;&1-kup@ zv(Tp6^f+;`3MAa4aX}-8r?0e9NBLT!@xIK_o(^HpJph0g(wLJn+h1Jk_rI6cB$cw&Vg8yaV{kNR3-GNhn&? z`7+x~WXy+)LT^^-t>fyTSEvH8GUq0;$!&WlZ=N0yTWS<9?56>(SV}+>lW)~OVrg3K z?*KkWH6V#V=r%UcRM&}QXS|Of`plgn4C%!quKZ^Nfg*^1)%+>${Q_jOi*3+NzU`xE zX?d9Mh0r}bxX!X}WZq^?-)o`SIN9}f3XpoRD}^3CsqZs9Myg_@*QTuc$hL4h66S(; zGj#vD*PUaIDq?W_oQ9JI^yOriSTIJ^ z`F(mf5IzRc#<4(p-2>XArbhc>e^!%Z-(zrnIu9@GIue=!g!$+`Am`O%DG)*8z3$_ z&x*i>>8f%@NB*UA@7V-&?fs$KpzTN?l?+Go8PjL|k}Qz=ElA==kXS~xN%%I@i@bbK z2WeB+KA$I|-|GYr%h=5ar{dWwq1D)(g!q8hs*W4Y_v?D1Fx?V+k7yWych|O6 z@45}$CqG5e$8K@d=gFY|KpHQ!ie+ZjL3PKkoxPRH?BRZ;mj7zSyIqs+?lW3D!&;Hj z>LH(IATvnOCq=8zJWQlA5RdOANj^-eNJx5KJ`B4#PEhQOerij}CW7qAG`IKDg4DUb zt|s+7j@BgdXAvV0=Z?>NINQCIQQ~-wzi#Zubn1Ece|+S3-Z#ohzbEehNIKyC-=1^+6xW=)wONe=0lN@@xbu!(2dlh%>X~D;^1tU|3#+_EDb5RAb4m&x_AKq z+Z1EX1_qL)5=$DeZaY+uB@jC(!yZO6l~Od^B(R^Q_#QN+A6QgL|CZssxoVnOC~?9) zT97Cmf(f1pfGD_uS_DwrKLh{Mk&&Gu6;IR(HVB%0Xe`6gd;Ldu3b zHitIe=W5u*;)Kh~7L1WXQ5o5Xq0MqpVpPKVT56`0KVnK9zNy&AwvC2oqgnY?duYrhr+ppV<6GuQsf~ad^-H24M!s z()M6m8dp*o6{gmm_RyvWDg9fLlfS?!_U_KFXO#K)Lb0ZVN&Q%9gt}bkyI1dA7TJDN#@;x0 zyYa^>J>F<@57)f#3#?u%uz;m}ABN)bJ? zs9)N{iWJc@D%2Q}OVaqqY~OPGy|D{p;wAyH77BcruwqK3z z{RU4iHO(Q5Gs=j#?jsR1OgfRTlOgOn#o z!U2#GMUpU)f+HAGnO!S**FY#^2^An+A)?7_tF!9JJZk-2ulhfnLz|QvKpKdh*g?pd ziV%g-{aX2~jyA4T%PpbNdPHlc7%8Cg(It@zNt}W%)FG^u(c|bki~>QF{{pRsjQ*v= zUUF-kEX{h+ABeVzL!4ncmB0k+ba8V11qM(g)h@Q3!9QZ8U;-X+bdE0i8*KsP#Y4qS z1UD{pN&C+D7>pvYGFo${2+IZSqQAKnb~2M0M8jWF+^CYY0cSr~rVa;IHjVfDbw0vS z*-dI%YHZZ1R3B_o5@XqX;JKShP8r4VYCN@MmN($6ush}8^vQh86aJ)xW}t#!P!5%> zyu&>8?e8TgHyK;<#THMMJKxZA7;$KVhw9W7z$lI6+N(ce27*o;Oa%QK)S7o+?u2Xl z!|by+*zcoKdGXe!g5&ZSoO#;NnrWovGDmMgx>0S_Y3!id{!^83XSTQrFl?o~EPKr2 z6#|SG=j#$Q9_g3y(b(l@e>`y}gV`RPh}J4oe=bgIYdmG`X2rbWnkCbE)$ie^NYt1ac$;pro*YeSoEgPj?^Xf#{K0SccQ1Ln!`a5ZJGDcl znw&lZuFmris5ro;?TQnz`FpBaIj{+OAa3rCb-J`OB9J-1z?q%3Tvm9{$h3H4iSpa^ zPc|BPsxte{YO~hjS3~%QSx5Ks;Qi$%_3|;DLfJ=QhQ@5?a>iLHF+EIYe|j9phMgc< z9@uSfSKn?R`1bl-D@M%^w(D-&mK$W-lhPavCta3fjz7(G$9t^YOxt_E9`CB9SZ=0S zlXcA$1J|H+MqQq8%N7;coc8oh9=Fqa-|q0+%*1MwV?k>x!X=%d@oNiu$L__|G{ze* z`070MmT1$hR)I!)i0OWj+S_2%R?mo2X`R~cHkJh1H$yR$o`luI=1j|HEEsF10k*Eh%b3! z^43M8%RnPy_RHY#;|AD|FhEDfuIO-e|K{g^l!eEe_y_%O;mC*cpGw95b#Ah^H)3UW z|IJNHYI?sYo?lWY@84>;v=l(G*aho^$pMgsCGjY$Hj$hi9&`@>(h)?2$fX2jMYFcu zFM4E?$=IYv+?$e^u{XZHHwSLqp^{oPQRI@Kq{B-)dmTb;i*|GEiWr%FLCM=yRA^0R zxAd}kcj#T}K;1y95RfXYA%ylBgy0at-2#R5Awv-8-zBv;8f}TP$(P` zmczDcesXsdk;2Lr2Y9g{0=BA+vj%zC7(>Tyg-`NV#n$$_Xfvu znb;GO0l|Om=8-;zg_R^ZS)v>Y`}C6JHtnT@iYWfT^@7LL+B(0A2vX&bQoa=#<()r= zc28e=PnbzjJCdf0i4rD_8H=d1fXiEcaFkWiLui*(Ydm<^L(;D9t~@Fcxxw|1WUiv$ ztTo2P$Z`x+A(8t+ru>tpcp+ecHeyR@yDj;PROQg$OQmY)?O1-c*vA!10a)07Aay&E z({^SD07J(#wR`ml6Fr<~=OMSp4}GP20T{ZFVOuPq1gqxDb+D4IVf}l#HT@R$F$(!< zQtjz8vE}8h6%Y)@;T+&K{$Bf%?eCwq@6Vgd!K*TsE+MtZmFcI)j=-u)N4>zt+WS6a zGNHC9y8Vh+aL>rR?Rqp3MTMjc6l(b?+5mJ3yN0s9AS~nn_dI}QKFn^KN4|`f%u+U# zrR;z(>Jijs5RdP`5c_{_=Bm4We<5j$B_?#GOcRcP0AXi*8P@c;-+$p02dWGJ`=s^D z(<=hz{!uZPb+p2h3 zz7l2>QT7_e2Dp^&$8y^ZxW^p0kSa%2P0Bd{ge4n@@1^lzpc9)XESk$p20uV3U!oqu zF8UCY&HER~lua-N@_oZ6#==D=M|BD_1u7Q)kVO;@xI^nzjOGd;jFB2Z#@`{%e6rm( zDzxc77MXI0?`I41r$Cj8>gTY6Ln#C&ne($#G$ACD@jpDiFOi{%;`h9J-#y*)NR!e- ze{wxWq+&?x%lMs*p0U+or6K~( zs;Io_xD%t*trP2Tt`Rd16VpB83&zZn5Q64p>PCg&%tZ=Db5r4 zR8ckEVtBW5ev7{hHU_OGbiS$I-5XNWTL3DBkv)QfKGg0kPSVFyM}3O~8c#HPow_c% z|CGa3M|YdUzW8GsvC{clmxbX-Or_Gz3 zml_e8gxL^%M-wJ5J7bYry*I={`9{AE59&$rA|SC5l*wTV^Z2-q4;;L)#nGvXe@~Nr z2SoU~7!g=j7kdv85WUuxxCj9Flp8AcyIG+$mZ1|UcV@eYS}*&qY*2~+P_)NO03w=70#DYnU&GOml`wpkRMQ%zyDr3tSGa2RFyk>*ZmpRc)9a}`a`5tj>0#4Q{p9&&dV-jyjjLmXcklLd2$!E-p3us z*NsTugLcCuhBed}7^SK0%j4w_zE&(sUV4wszjg4ozmV|Y1y`sYF+4l1+6~^@r8DVy z0amJy=|3H?*ZaFX%;W0c;e;>YPez*wJ3~u6nWofai93bYF%A8@d~&-An|6A2Fm{X1 z;E@CLD*0vtgORpd+FSj7WI7Q44oDw2({>1xj4gG}TuU~)B@*WkBsgA9PC8=Zs6$EG zVjA2h)Ek@d6x&ve7hOIX&P0N)diL~dkhU(X$(0-O)~UJx75=i>8MVFNs*zdA*}!=M z?=&4KU6XXqV>r|2A^lk)gm^1je7HKKpCV!h54e)3z9_6!;9334>)f_+>L=CR-s|-t z_vpOpyzsox5ZK?|k#m#(T`sP}H7e|q1+}Kg>8E&c@&iMUOdY!Gy;|+BLkjhJ8qpl; zcK$()J9sk|l9aA%X@aA4t*Pu@QI(0Y#o9|zBKP-aZ~9$F%!qdtJ@i4N`z7cSfOkzn zur^`CNIc?vElC?SoIzueSp*@uizqVc`^ED11m^RZ6XPm3C-;hj%h&t){OE3d{OqvF zIxY?eO-pY*x4)4mz{Cr1@)X#ITr2foaAKe@N?+5F@e>Di+S67z&vSb#J|C1p2 zU;k?O{{?~5miLwGfq3JdoqOcgrptB1CL=jgK*-I~))SbLJCq-@JTp%Z7cV1mJ`I5b zu|b-b*-OjG5BGX*^d~A}vX^D4*J_!RtC+Cp?89J#F8y?kV-d%Vq z6iD0pMk&z*+8Is=dAr& zv5Z(G$|keUd}4jd0ykJ8lu>e?a+dAi^vUF;)DXJJ!%u&IX49if64|7F4hz<h zl5qQuaPqWz|G&%%TMn(4AnU)N)8D-jL)ah`%dY*-UBwJCLD@43@iiE2BAL|yNz)7V zNkjFG52j8SCskKUMyb_V55#;hjV&CdW#k@~wL#Qn7EVnWENNBvS~j1H)21tH!jW`L zRrF#`H`MCfEvEVtrKmc4#cE8}5vF#uc3JzTsiBGm z23yePD_i<64EgJaj;*%FPw#F9+)=Ggk>50BdiNs8)L2!1RjYkjiz4Vs%sn3b-~|R! z0`G^D0734Mj!vT%8<32r+W^Hz^oB9;neCX4lLYEQ@7RLSE7*lyKTdY;v-q7K4U-nm zFGf=YI4}g*j-?-+fOEsEKtkE2RRn^#)gjkW2Kv^}&(DUB2r~2xpivwuljt>nJVxw6 z%59?6{F_gG2sn9}_~na za7#8A8JgQ5#wv;7!%xheR@|Lmc-#5NKe>_O;qgb`d?oy8>`&}vD{N5szx~4R9F|nJ z@Gq3Y@!pVk;n{Azgml!YP*E~-hN3G8>o;T zRJk9>H^NyiFbVpwX9MgL19*Z|6G+KNY+)_iCk8De4?=0D=52l?3Dl7$WKZQ{&h|LZ zLpiuOwU@l>ksbo2v;uDcm$^9?^dF=2$?;PI`d$p3Lbo-83qCN}o3QA*BHTb%dmq0c z3a#v|eJMUQ9nq2r=!RqQ<(n#eMJDKb+nkBC|g|bM7xS z87_sxEw++I1!Iqf$*YdKxRB%9frQQz#r5aWDw|{CY*AEe@{5zAuY}*{+o2Tl2%6Et z%I;|i@Z+cP4bhCI-cpYG`RUV~z;fPQ^KZAa@!#F>$4=KoaphZFg+7MxY$WR354Ys| z$>`-3Wezn8i>t=a0&UM?szNu2GpH6KX&NUEALO{9gYqlreq)ju5*Z6xjVx^rs0|Gk z!9%6f*wYuhBO#S(om6R@&S-8z$?;j)Dq(@WrmMx{d-lb|;StHh<6Be{Tj-bc@Z#&J z?HR%Wg9*WK5RalC%K*6Z2EBt3A2ovKT{O%|&B4Zl**2~`UBAIQM@5qo5mn{Tf}AZ?!j^7hgon84k+1#R*PSgva;BOs)qTwjbE z94|E(NsK$(Y(Oj4J-!v>1^W&k2WrQ4I4Ha&2r4*t2%XbqP0s|q4so$|*qM^S43miD zg8e`N{VjtCHzeUB)*V@N$7NV3`ZJGlFq364Q0MkiNegTUu|uQ8JBPdhypS4j3uq__ zeWk#^o!wIOG~DcOJKS_43us(iK|I|AF?Or)iFyB)0Zw(RyIth^YizomW+2xmL75ID z+kg#&4rPL3dhDPxWI9s_2bI2e$X!jrdzTPNv1d7~@s~!cP7^c!)Ve2b{y2HbWDdbc zUmgJ(y-vv42Ks?ywDb`&C>1oVe)u4Kj{jZEno{xEM%~&BEE46|46O|y;Eo{ z)4*to`j!K!G2Hu9M)PyNkJ*7kv*sc2z5o3u(8Nb`5w~^rEm}%g#1BmKD1m9@AVKd% zegQoJ>>1|sG{>~MswBtunTDpkNKta%yWJO(;W;_|8Selo}2-; z=}7~~rrj&~q!MN|6UVN#9x<#)atpH2+@2xxGhW%t$UtBKLYM)H!f1YZI4`J(2r?r% zWnqGV0zwM2h>G+7IV1}h2vg;!%YsQKotp*X6d-BGlEp5GbL3hDT!~HIc>4`cu8zZH4)P1y4`+3>=M4Sp%dQcm`>m@Bj|bXz1lIFkZfm&u zk&G_c^?V*~EY7bofnQsWm=*ZCJI<%|2j59<{2X8-pgw@zQ6%P6bP|KAYz?oWq88L5kg>}$eY#^cWL^?_qoqw zkEct2fWsm9sP5$863{Lh+dy%o*8g;>~2)N6B)G@=J?ONbs^dPU_(n&rs{ z$%8FphbtR;&2ShGGK*}Z=*cOyl0}0hHRC;JzJND|`rY72b)uGg%OgVp(Zy<@)m}`h zoV?Z|!8NFM(K0@Cb-H-PvU=Drum~XSKqUG7&Gt+!&wiVNDPJup>p&QxW)P6B@FH`d zV*bdEBM#*s(XSD!I8lf+>A_lsU-WD(XV)T>B6D72A{EWW{=gp;>>>kY3LFS+y#T;= zcE+Ei*=#grOnT=ncCvkk;Vtshy6ogTmFzIz+u;5vkr9Fj*1OhtnP6URlHg;whNeim z{sYwjeP}(pCLYrA#1-;9~N~<#ZxeW0&R%F@$qGM&SnbL;`#(uBD3~OV_9ZK zNktgBUEnsDL7qnsaj-4D>$f6{xp6o2?oQhV-jTeCFe84z#v92> zLfzlX;##LHyp!k}DhS%y=F5GRv%@vsnO%$sC;3)Fy+3j@vvm7YN2O8-5^Q3Tn61i0 zu(1zP$NItAARXx%&aj(?JjNB$fbWIH)I*4($FKs*Xk%KOo$UwyyNmD|?L~UnAmiSV z5LZA2=ygtwo$rGzq7>+@V>_1yrd#`KxOBllYtr-TUI>l>$|pFBC=Tmq{-f~U!Rd*t z%<44GZo=Sq36LluwaMez{rP#MPyka?GNcOlorx!HNM8pP)xh z)nl|fgm za@Gd)eXUftZX0eMekU>#Ea{sB#)-Yc6aq#L5K8KzBL(`^Fd`l--TvgLlh&45`<(Xj z@zC1OQpnn}17!6rM34OlspqYB*Sx-LyH_jY^7gpZgr<$A%b{Lx3Git#fVo;_Y{(Q$ z_|&U8J+GmWg*9({^co{e#oi3ZT^HbWqa zB!|fEbo}j-6*JvX96NONG^fl76j-l56a%u5+#>+awhbf1NcR!>gnaDP!&(LK)N(Rn zsSOTg5^Tkzz|NG0)gcWji4Z#qSIZOSV7x~&4Aw-M|044u%nN^aL0$bOJc0zY_4qby zq}90=v;mAWG<~5CZ81KT^Q3+tUg?tm=`D;NVom>|;s%MEepQ;#qzg?gXe*}_aha@L zZ$-HgS8D-2;|hVv_mui3*hH6%6M(B>c5hDy;CI8aDhd!2fHey0WU4xiiV;_W(GhsY z^z>h(>=1o<(*`#ZS|q)uLntb_m+*;~a7jolN-Ap#&U7JsRr++b+_skUr;TI%=zIKV z{Ui{KFtrW~dpNGt7cKUcHrJdl+A16=Qh=#<9;>#)lw-B*nTDwF-W;J}oR^EO=T-Kr*h$Sz_r*6#MVF{c~ z)*B9S=f4ca?CTz8*(*7oiHm=pk8cUYmO05iC-o9NdGtz>ud7QeF}Ry6eJ-3EI0=sO zEc!PF@OJnIUJnLb2>|ENpujdQ(#J7VbyAN!Ftu_g_Ju02X^S1(JRj=cLaE?W|T%-Xj?jwF(Gr##a4u3S$R z_%|j!&aBu>#0Zzk1`{QBhdoYaiaiVHWO-Oid*2^ZFUNb`V)fp*%PqtW->XUmtU51o zN-MAcD%`8aQJOBAM<6#HT^GMqB{p^wE&5pa5wPH(@2|`hCr~713y#p@(t_gR8Ua-% z19$ua?X8q64d>!|^5S)B&W&!$#B>@a4!n3k$`!i9h2ZO+^QpMRLCwplJjNEl?V)cl z_qcRv0|R)f^n>@fErzmIu)4N@mH>-YYrxzwsBRv?G(=bB5c=NYt{3ewMg)M*pdgu= zV-|@cPqB|7_^1K^K`v~P!?3D&`Ee)-Z)fY?o=n&oV2zp~7Vsm@kMh%0*tG_Zi`FTN zXS)*vG;jhK5I_*+(ak(2(kvWU5GDw3c`?nqA(`}1OdurB0!u668LO%epbfg6-5pSL zyGfdOk2dF=6N)eJa|PZynLR*zOgdw;6m)|wyl6-GjodY4`sUVAna7*&k!ckY3(2RP zbX63*!>X+M%L5%bk^{$soFzQ`Zhb$^BYO2_R?ybp*D~vijI+3;Q|?XLshjVDO=3~_BsJ;m=x zZTB!R?E@|6s#3 zxKUp$-{O-*NuS;0!F?CicZb3{o31Bo)~pLBrAE~T<49|w>pai>IN}Wd4E=QJE~ef5 zU0bTgUX8YjTeC4-7|vBu!~ZQv-%$|MsJD8b3GjZYhW~KtVEY*E@HD#F>zI01$8B>U zF#yy1%$R30s#f>BTvT3#cTBi*-~nl=yrtwP%JCyb@44KZ3YbM{t$s<oU%>JjA;&Wcg-N|-aAZ|Es#5A_l_HMdb zkQeEC9A?w=UcuW7>kd*W{_E8hGvPycb1FAs6SaoxC=|yUy#LxwT#q?E1vFW-JQtw? zsrlM2TiAt46aL*o0*ArU2uUPkuMaZsqn^p-fDL)jw+zfUHlD1)Qp*C zgZp#vZn9y)V`{h)_C6Erkmue zgj0#kCF`UCjwISK+~gCH^&|dRD=?IYo%qd%Y$ncl7@YTgqd7*pgTZ>pBr6D?I}YLkE8oEv>HG{A_Ek5}eC=ThC|3a-(~1i> z%DJVyq$F}olPa$5`d@aH#eldo@jBzgEm$K$N)#iE>!tRjV&xeyrhAahB3?nE{#|PM z>?2qufoN3$?l|%&Bl%@H;rYf)SJ+6T9;N0W1aq`>KX{iH*NMj~WbmbxO37ns`%Tts z2wNyreQ+IvlM-AQ7%)cG>~Dp?pg4$vC`j%I^^NR{{9-|OUL#E}LtZCUcq2CqP``VQ zs*AQ%wChZD8gd6pruGWXdv7ns6fL3K+NTl*(INUwRnf~aIC>59Ewe+IZ~W(sSUsp--Ps8 zSUSk{lky$sX;wrsA_CnWqmzAa&v5HwIRACtuqq|RWU(`4Vh~~C|h1Nks5VezK z7;C&DpB)X{ni=WGZCSy3+E$ROQp#U-q}+?E`2=zA4pIo>G_X%7kLcjKW6nT6kE+0{z(fxt59F6-gk2 zbpIBU;LynG<4Ix@jk#x@_PbL}KzEf}2DHf}NEWaXh>p$}C5{>wMg;iIu8K`nICxSg z3KR;l>5NU_dbjbQnz`h>Tc5U4UWX&0skn0Muq~4cJZud#mp4<#OjNFkf$qU+DNK*> zi#0h2Qb63w0#f%7Q;=jWO(;6W$k4pX7T3d@8skSgV^oT3^|ZKoxH{Rf_-*DL(RXJ{ z)A|CGS28$DLiU*R4Xg576_1Ov0&~wZt%FNu*o6d5bcfz9+l%xIU~XA=Frz9;n_Z^v zTBXf)5EaELk#`CLUYd$xd%FZnL6pr=H>hc*TB!Kd%mZJ(Jg)jVC2oiKEG@cuStl*X zgK6@SNyX$fOU%KdQQhOz6SQ1Q6x)+({o^6jHWUah=g0q^IlGcdyOKfcE};yVC2v6j z$)FnmTByX)?s)h8yfCHuZ*NblA@9VrQEyph&geI)zR3@qIj0gwX_nxpIDY|nOL!tr z&D*6*UCceY-8*+M1?QZN7M;x+IeMFcciA-NY4CDcs>+!K9a*hW(a`sBh=hoi{(C;^ z9b7U%b=9lB`g)ihiJ+6HQ-dH;+S!B06b8a9nl|{Obgg1LNFbyo5hfq(9`ppTi$UB| zXT0PtZSo0KxrKsy9qnvhAlxE{np_Ucubw{X4W~jH5~!uH0_*?-2)lEwpb|(gS}nTM z*V4#qf#HeMqI`YT2Gq{!?ln!Qm$*ZNExUoH*Gt;dIw;1M<6XUdL%rD7v%%MG%JLC3 zy4nq81q&)Mn_m?ZxY^=mHi&xT00K%?D1Yo7!}`pWZ1>7_nC+2-`l=kxxGLId$RW8^ zIjC-6CYNAH)}j{v;VNJ9wjQ?{tV7pA7&jtjmUe0g*IF4h{Hzt>ZA z`7~nmny<5WZwh81kgSU2sVQ4FQMMxwp=MpPt+0S(E=HD{=S%70>4dAlvO6tSQ4Pr~ zG$v+{Mg{5iX*CC&rHiwEoC(fmxMrKD;Gd3Xu0m_4pa9F=rXXEREM>1o@f7HnX^)`d#4fGyiA6hS>SHClq05hHkq5hDuK;@Aj$W^F`8!onK2 z)QmdVLF9%~Tqu2^C=UYVx)T=j4vKZ0VMtZKUN%ICA!yq&xGOY=GMvCeE;x-fA-|Q8{ubh{BOvL7OW%O z)fQQit^R`Z>Pb+|w{0}N707aSh{FTPX_SVnP@j?Gp2%)4h|01n53Iq)O({u3TXdI~u(-J-O@M3; z^eRRpxp1rrQY=eH{zybesYpGAv>k;~WDc@gmoTip*TvNR$r;P#$?9Fv>csplVA8A00+H;|OIIE#oO%1?U;xTGcd4k=0?W27e=aG=_mdNO z%2PN!y5PqXPc0`N<3;xbDeN?z9lc!^r5Ki?B&oHK{tGUN*&rqEtxxz^=JkzHr{B1` z)9&TfTdor!#iwXFHU>Vn(T1)r*yIt5ci;z=2M%CP*`!lSugCTaFS87h5Rsh&ro2G1 zGS?+4DT5Ob)h@nF_&dqI;yW4u!m2q$6; z8v%~doyl9YAI2TK8-GLJ_{UzrRMbuG2WG?)PF%g2(E5uk_o_}|6N-v?2opbaS<T4rgj`vzPWC7aZoWR^v-33bt;ND{yu_ZBSAG-ugzQlk z=;$9T#fwrV?!V6ie|*SvH0P8ksY9{+g$#v}k3ZHE+UWhHm+=#c)UYHnZSqp4>5M~_-IamB;xHz(Mhc5yf~d$c?6oQTc@=2Q07 zg=vSa#?8qbTOSmU5>jLsI1@f_47r9@sz1)->o?EwwCyUgLCe&(e{H-c#4~4eD3xW7 z2xuN);oc38#Mnb9P*?RJDOr(i1B?sxAURsh!ne`JcmijrZ*@8C+(3(Hw|ZE`KUmF( z@33SES87&A;ucm-t^C1|=7pstO2bT$hu`&^dn8@TBp}oE2BDNkIcC@R7 zR!_tvN(Fh3wy6h~fUj}ZZ~I{EYhfp%lPeEc+IKG26by&Ueb_iSVpV-$nmUjd{e=l* zVJ9xp{7bd`$Ho(*Y=IrC_YRmhZ?;*fsqC-W-JpQGxaz7-(cgY30@H5Qqz`mMeG0az zfpmhe$T+15_Q53{%2}p7KbGH3^}TxPQ5{9ZdYu>Cj;ep;^=cXeMTHH;0Ku&@>a83H8LB@UdD zheT>1yu5Kb2;d1Vk3uC_+f_WiMsv^W{9SaXO<7E$!)iaQGBk>Y*=4Z7w`9y?&vJNW za;%f2re{cG<5x9~Lnd;J4kSOzJ8#nAd3Jd}EP~&8rHg#Po$d-@uTmVb*nPg}j|7*Z zUM?OVd@DShF#CD``CL|26LMzXYyRvD&unCMRNVYOY~x7F3sm zp@ai689&`;l1$Wyjb+z1;NQZ0k_|#?CC!BMh!4Ym-`wj1&`)OT6p+~4^aOmcX0OxU zLN6cm5(_@0tO=mA4nFFl*tm$lp+l0<1)_)@R8uwH;cpWjcX#uL&ucY1vDI9He10M~ z6g#lQm;m`2F`qlB2Y3|^Jvv<}n&gd9Y?mQ|eFghzxCMB6FiMz9;v{@9Fph(}H(SR~ zeS26-_*;q1%SYCcZAuh-uwRMC2wQ~BkJcFej1X)cv){@^x(#iS8hD5cEf9F4Pvxis zqV@8S@rs7jeHEBi@6GSbESxgxqkc-={^pOW*R&VBI80q%2k+NrOWKQG+U;r{jZl!_w8jmIaaO+xtf(g)gr&WcX$% zuwq`9tVIFuk;5~;k=eCp`@xgGuSr_fn9*=hO^157cnV1VupA-riR6A{Ffq{gPxjw@ zB*B{dr%W^8Zti31P$q2D8EDC2<7eT+EsL30yi{gT45fKH&k_B!QO#lolB5ege4z8O zl%XI|JafdE?0-)IKyff&xB3}lQF+`_zKa=Ybrj0)k2oQci#RaZevV=)>AFZ>^cQ*A zIJncgzi;E?_x%pp^- z^-SN=B_;+UIw9aKU)~I_5)KE=Vwh>o zp=2#|2v1No6o3zn3Co8Y+JxwkmP&b1gax{IwqW8q3-6!tK`~H)HZE0b>`be{oVH$tK+-j==Kh_0{aFH8Yp*V&a*(D36X85hS(KaM z^6%=3_t(WpDH_1gPBBjXeT=`;7OfVae{L}WQoA|HLq%;Ccv5O)@yA^gEMm;cK+t)6L;WcF*E#`%xNX^#Ju_14_L$^6&Zl&!w0xFx>OYs(|@ z?KI#lRK(jpP5;?U)E^W>w9P;Ij1~2=am)SS3mA^zzP{!Z8HwL#cy}~hHrBzgl<3AG^ zqGTopk6JvBm4tyFb!m3n=1^@_I5^;da5MU*r+;KBP zq`-{%JWi~vZ%CjhT!{%v&FAfLW%-=+PJl(GJ<_qkAB|4$ME&!1$;bQq;~<4i?|yNK zF6aC1c1wz;VaJU_?ORuN^JK(Jdtde2XU_lhzA98*eqyOaG4OanKtaOQ3f<1| zufK>Ds>5dtwhLG`OA;90-Ws)cWRb%`&_-iBk^hH z8*kWcgVAlf#}FRqpbAC4Q3;qcun4QW2adraD_<+85lPx%@9?&d%MC#CV~$3(l}e2K zk@$!7${V`^*)#R9OU;P)u-Kmt2uywI+)Jt*m<+wk)Y!LMNSC8q_Ghlvr$A@If(*2= zE@<=tGg1UpT|QT?+2A~6SBNKY?U;dsrI(z>9;RWroPV+K9-j)>7Lz~G(D9y&xbs&r zChk2v=fXc~B!S@(X%D^_D0P52+QV`+W5+b(qI9LBjQ(zKj*B$?`|fP}dQI#3P9{vY&_?>^K91NM^6IV?IMxLK1$ur{w{3Iol5V;u;ZfzRq}4*i<9^6?lEUjh ze>nXDL{ObPs8KCDuShDYB1THO<2+LMd-|j%X1}P9EFZ%K08r299~iV7n>1{Gi|pm8|=aVomzP z7Ymf9E0Bv}_btLB*nE>Yx$f%E}l(6hwFDP&dc2WQ#i(J_Rl%4gH1p z%9_T38+^zam-8zXgk5N)bu1Oh;{uqp=}h`r0%tr~$_EwIg3Aia5K=1y%=ZNA3{V2$D4BU8Mzj0?gIw6aqr`jV$_!J3%BXi-xY@Zg z|Jb-i=rMzYn=P2|nx@8LSO7?CAyBwvy7PwIVUiti{Q%+x6X#yy-yg+(r%?-?<{73A zoMAi-CS+Zdvgs@=5k#&eIF0X^b})U*m~wr7*>q0qWGUUcHfP+wyg`o$0^)O+=@S6? ze)9e)oB`^6N%&Js1?2n6`-gZ2A~#{!wj$GinqPXmnypP!D54kUACp5+w|U+&Ilqe5 zq|cx-TfmNr`;SaShrpk(GgogzT){=!kWk~JLW@XFAeE(?YVxV5c70{Kr?}m3vS&&K^^)3t3iaQVf300c0N&V%wFQ6yNx$rvo{+X}-SFA0=b(SPIG7Dq zU4(+@^Ig^|&OCfdT-Ca(ZOgfB0qt#Jy&RBmFyyf4p)k;&aA6_{76I;^ZctCH;O&ju zhu(WQoVE#89ug@lRS7G3UqwT7EXLb+c!p`XdR!yWw0;^xU+6*mwtis#JE&@1wU)jH z|MTbae@hV)_`eCN%x#>E9Zd8Mjdh)j9i4uoE1`)xnE`rakv$B)p&A()MEkOK#z5xs zSl=Rg)oMpWP4?!ae@GOzF}{9J*j^e16UJ42?tS_`?E3>q(->FOys9>{!=XD`z&{*Zs4*EY*;@T+28FY-$(d3 zYslEcH>noU?!+^qEhjacK(Xw1t3l6YK~9ZgLb1n)N)K@tmOic)VM~yRikbg+JdUR? zB^Vy0!+~&mQEy{FzgvSl>^W>&IXt@_o|!$!6+=@%GrEm`a`vyAPen>j1<879DPyst z_l*m%XuUil3n^}Ue|Vldy4y7u&GHB>{BN$)KxO|j-rDe2$g0kn7>J4S_z)dS%Zo*J z=;qFUuYjnnTVw!x;WWD{aSX?%TF2+Bi1uyd?Hem|1*)A|=<~)P?It4U|Bvxr2@U7# zul1iS&;N`u+wTffTPuAVQ(9XGQ#uoKJ4Xg)`oAs=wDh#}|83I!|4e-=bA3m;|8@M& z1AyYMuqY=yw`Pw)te_rH*iq*KS0{Jx+h2rSX&_=A4361F2|@unWrw41v-=&Wd53gl zbEre3$|k1FtSlPI%nn+Qg+_lLRI;D_Y7$R7wdZ+Gykj+uh)<4QMf{#33!OxgZeafk zf+`5`>X-CfZDD$VsEv5j^4e%Q_Kq%gSVS6k!d}LxHYgch4l>#ff+&*9kIq@{* z&B-j=@w`P|mwkx=f$St2rn$~joo-cRlLZbs_EV11blCbrl93tBdll!~L|!mYOL2{R z^xRefA+w|s(=fmx1VtA>QfUHmTPrE0b$8i3M=cB+6MC&V`WZ>|I?M3ric4v+>pn!b zdD0x|f$0+GMVba^`_`j)bZrL?bkchdlJN9G0TOfLq`R=6f{xx1{uCczMOk?yCBWGLe|mf6$wRj$48BU z4RyvRUeS^gwcR^=yh5)upoH?yOW?JW8WmPK26qqGL%KHUi*JPgzV(4I1e6(n1)-9E zbsGO?x1|3+a!W^jn_qv#p5V6_poa&U?UK2plcR!BM`;&RRD>+bXatKbvXxXai!{N$ zy^^f==Dx9ybG|Vi3qII$>z5_v1wNUocfzr&MuAgtqWp+5x7$8Yg-FwHBUft14I>XD z4;Qw%jDlE*_HDWNNLbf#*KHDFC7}irgoZ(4m{>-X2r%BicwqF_6`d?{u$%r6)+w%9 z49v~rXbFBrLp7kS;LU-Z7B;tl!`4itMAFgsD)@l=Z!|1qIU;L+&voPX^*^J*`hS9k zfw`%*tr4A#{(rWS#jdS*EVg=lPibCZTwza4g?-rul8Nl*($M9ZN%_Ddj=W{;A-~^(6m>4>-DOSC#()iV@%A zsV`7)GhJvGRja_t$jX@Bnvm?hfKFSsFeYX7y37CRYL*kHs)(8-`#MAZHX}(TX-%rv zlh!syWK58hL#>_^QPDWAUG?)VL7N#_zJd(vf=m*({#|4j3jqTKA*pzQoe0_zf4ekc zO4r@(1|X?CD&EtBy4KVhUn{3tH1^@8TrGX1_bXf(!lmA%$;G6+J|+=i(5__3_0NrQ zN`28c2E%3fr4As3t1G zw3R}ozkWGQQACq`s3}n46bE^@k_Nw@9~mUd&aixQA0Dt9HJUZz!*OGM96OVL(h$qi zxQ*O}NY106QUe)LH<~JL3?VWI#RFL2gr4?}3{Z0swy~|R&IO+m@Zq0eRO0kGWM%uj zMHyor&Xg5N(2lMlNg`=VvZ=A2JcXBV1FJBsr87dHV7)bxtXm zYJi;Cl`hoDidVrVWbp!(V=)Y^0idigsRh+SNGz5)KUT<}9I!viUS%7Lsw9JhrG|y%k0xBjivc5&n4;q3oDjpPKW1-Jd5K0yVY4UGRE` zuYYeR2udzR$u`3udKW{14h-JWmphfoi%X_ftB>aO}g#iIh0)eR$QtBGj^UO?q zP`m1vy-O(jNXUS{UEhiQI&w zg+Xn$%&9P6iq`2NWS;SiFA}SkI<5drP!gXRW-c(>p+B929G^&2eN~09SlvMkmv#%T^uaWnrTM;8WyZoK z0F3g=Tt<>aqb7F87#qS}x%MJLqKa2pj$O%R(2FNBgo zgE+vt0_Wm;hf6q1EgE^c>p$U4I}qv_iMQWPS|$V%gWBjpUZDyn&gR&LD-U6RGewG@GAXhY_@49 zR}k6aJtJN_+Vgt`ku_9d5#!sT=MwFPgjIdoMD$8+v_=#xHO0)!clvaaTE)|6@&f}n zo!#sqmTg44NN#7|hG}sU*5?%{{*$5Znu5RGd18pfT=kKEs243S?{5!VVo1LeU6&a{ z77{{qowmJ%$x{b%7hZYC*BB;)ee<)zKQ-5hQD6j8?Ll>~8wtuL)vrfYdXm!o1*8xqmN}1yL18uWJwL^}qASKE=4rYWtBl zJSfe~P7?*3J^5AojuxHEMNUl!uOQKA6Xw-RqsUHEL@;gPPU zSxT%;edAkbe;u&G?kqoTWeMGbQH@rv0q+|izwyC#fTz`f`TOIF0JYfx@0ygfCmZ_s}X)|)`zVTJt&gSWzYyd{XE-A zMTJClG69K<0l>7*N@8lU^Z?-s|3xHclvSd#l~AyXZpC-VJ#%6OPF72$H_9M^Xt#tE z8uG}Fd*D7BdvqaA#!c=_`nWa?WH%8a!`>0%1o0?E)%92pO|iIxo>s+qT%k7IV?BTy zTKjXD`xd0_1OSCugHX>4!uzTSf~)9C%3>C(tPrNp`0Vcm>_$r7qg!er*n9;WWr-3- zACLZMDXpS$e)#oQFeSzsrZh1)0pzkk*dtr^kF6ud!d7k}E`Or6I80a|RS0ExtU2pB zHluhr)&-~V_ww3i+BsmFm3)O|Gn4g2hh9{ui7H_dr)JFkh_^`n zXA*KZ#*hR${-}{asl_wyvvSG7dkCIu8cHP~kI)W5rD|GDv!_>~d5N=sY=8|S)zPei z#QMY6`tQ~S=wrqwKCWZnDa{X(SkGy5Z)Z_@XtHLe!Llf6Ka&p4zU8W-IANyn?tdr`#`}XPJbWa`WA+}sLU_=<8B9Pqc0107B$cprqyk7mN}-mx5gmioRCb*jGg3IgQXjVQ&!@{FjF=?=8rW9aO8MeOeK$)V7V8hM;SMCOJa@gwHw z&lo|P&qUxQ`4?GsNCH1YBP^er7Y2UIxb>26yt|gM&>)Y8~f(;M@^h#v0R~PBmnHIaVK4rnXn!Z+8s1K ztSb}@r%$CwiLO_HAZwXg>$j6;A@>cuh5*f>3}2h8ZcTQXkDiDW)xb}rx-Q5gWlW|! zk~M%=PLhxZd>d4Zx+^eKb#|LPPLv;{ALXq!ASg_ z*OHPNN*aho?O)|e&acdo?zg6XwG7zN?MTn3Ya)dY()ub<@O8U4NV}fjuv!;`a~xC6 zK{2DPK0Bopf^+L7ism3RrF<24R_t5B6wGFB(=VY&QUvwQ3uv`k0KwW^Maj-oG5|Rs zKkE5Gu4a`8!$;s%o%}_)fVA=PU&eVj9V#tPo?mVbM z==hTtt`UQugWIzZ_52(JCz3DU7y2;fmZ<>8-SGBvQF0l1B}oVibtd2jXF6#yjh|oK zpH=xyg9sX4Vb(f8N=1^n|HRSlk$woUZ6V*s`~DFG(CrbPA6k=pUvB`cqWP4$XP)G42`N z)lW?G3h%OPwEh?RJ^K9ajbDp*4D_(9AS?@y?=Ou~rdC;K46l*fH*QUKWE8LQlZ$}( zb$?ZSiTvJ=0A0)Km#yI^ZEx?u;lD=Tw|@zbT6Z8CXVw_W?pfsI1sr#PQBSKh8J&62 ztll1FqT*Ps32ld%9-1FdxWj-as7*&EiK>}adW^SIMSqkWv}~n=p&}HF*=CUuk`Up+ zuZ_gPtM84N4vqCb{y?jd2qH)@Oe^v%MmeKNyyV=EyZv^X5_3bG`ATcUD|;E`dbG*7tXgVzZ6m+5S3G z#!}v{*AJ>szC)oCO;=3FcI~V3w9Gum8o%GV1idSkQji$*hRoKN$Nfv92)tCQ zcG^z$2FJ|@f>Epp5gd3ig3*9p%&($ySG=9zGjSN&LS?)+llF1bSvjz~*p|^Q zckX`ylT@ueh|hco3u9wkGY=cGxCadEZ5P7fmkcrhI?XgQL1mPVNIb)PW|&`+*1lC} zKVfXU1(h{T0BBTAPBlwQ;~;kz81vXg(@3*9$e@yhZ7p1+9R)B>BfcL+cAGcy?a1By zZIydJ0WY>8-{zNtHN}tN!f;(F94)sLNTuM!Uv7$Kd>U0JyDfR<|6ImA>^GHfWKLjp zM(|~S={!Nhuz7(kQ+r0T52r0ygk3IOp!n zuo!H$5Q6Vh@-N#xK_7Fmj!egig443|nT*8cRz;bU zTG~Uk?YfqFtllw@Wnm4?1w%ymMX`wLkW>`@^!H_B(%5SltU~Pozx4|KV~O>qN$lpy zB?k(sG6WD0sV{c;-GPbrwL*dOkC%_G>|(Pe>a7?7(BiLhh+uh4)PDR1MJ4gZY(!VJ z*8RLvBLX(|Df%6^ z`$znfB~aUn0tJ|fsjIt8@3DOuEk3&Lh0b6$sun0BGkp8Tj$(eEem-}8q-|iB|5iZ$ zQ45qQxqaWZltozAPE%0nSRqJ>ukRNilt#f|e9krQ4(7=8{;kX6o)Y8<0zDKn|J{>S zR<l;}3KUB`-{o){$dW4JDWhBU(WBQ%MS8zkC_5F?y)aq}RpS&FI(a8fN3J@@B7I z4jblh6|B?~YIWIoX7*?^okqw3^8JU%REKezo^!iw~90=fn>-ffQ91 zl=vx?b5ndW;>~WbKFGPcy-WtvHc%jIj_v{%Pj()1c3dO&>^-^Qh$XJn3?{*GvB36yw)93Zv|7y?TarD|jdYZgLXE9t#)&QM(RP zzaD-yNDF=X{kLwwJTPS49c4VqVKK5qOm3n-V;he{tTkEHc)Oj2HhE4$>C_ZG>8TMi zE#!_^r-Gu=^g%o1wgm4Q06SJN zB}=^FhJ-M}3aCYCmE+)>$W&4RP8q{2^Ltw@;v43I>?t<2Q4&btc4`C}nM?qpcrlzr z*{mqF>{qA6X%Gxz_re=8S!C{PveQ>y2qSxT+S;guy%cQ90~_7`rz$d{%pPZBMwzm{ zh7jf`DE3afe1Y>WS!ki4yV~Jf4Hk2?yNdQ)^}w`OXpAOk$8Ii3mgeV1E)5rDcNH1h zofOO@rnm7!TdV|+PH7U58E+`k87v+w=e<}>92UrFPFT$iEdqcdw&GR0bPva2^WXUr z&xHA04SmZMdd~S|wy~1rXvgr^F?s%%>O{8E1Vj4kk4|dJrM48fFl4Ot|mx43~lc#*pew;xQThcg2^IY=fw=nBvLhuV@&ag%Lg&q#3i zsbc6cxc9`MPK2QZbe&~Io@C`iC=nRjIZrHY9vz%ta>DPi}l1&FfcebIWO{#s1U&z1~hIcYs z_{|&_jp1ou3{OoLlrn59Wc+MlBxe)5LfnDXh$Y@DJ+C@YuAu2mOlnKf05&;%F9UFQ zAS3R41U1$FRL3A2x79R%iR0Q%4cOZrJ+Gu;d0>4qOH#VwHxCf!A2wPHHq#I zxpeaE>5;tzNT`gRMqlyXK1X3O9}TfgtUN{E+<>1DK_?!hLof?TCKQ~DDgISXg;7j0 zs}yK39)I!sE98wX{88vQ_|C)A$22US4r2~B@+m>HCAmc&-bePCst|uYFs-RthT8{= z>;vI4kwU3H{{HG#F(d!N1$X86Z=E6>!10Z@!wRnd#bB-Tu_CtJK2hvd&|n)~q-N0A!R+@5dJDH2 z3ue_^F`YTTWxL3zqaSXPEDyYb9Pon`94dxDOP325($-&*mXU!Hlh?%u_J~8@Af6rm2ShF z=&}%QckJN@v6`zWZmF-DG!!G?1tMPO-GvNqPm=%+0I*=P-OoSIH$e(bW)`n zbm+9R;bPYeiDIBBJftFPynJK>=RmE~+OG<1Z6fQgOENTWG2hkErrm$4;Ei z@;e8w{`t_4$GXbO?31bOg75|9>2?O8l;+%5+jRJ$Rof5ZJFJJhoZjiYwlURn@xvQb zu7~?HtwHLbno!kqtVYFm$<_fLF|l$;s?*njG34w{AMK5%J&9$$C@e@M4-0KNH$Zc| zlc3ALwyR6z>edlcTb@uGB4=Ot;f5TT*_^1?eefjx%Fr=tI9-^f%|~V!d<9b+E(FnaX|0s3|K(h+31h&%9Qw%GxYLTOXDRyzG^&o3P$Zd6z{MVA9+Id%KEd~3E z`E$AKuZYyPM=J~;UFlM@vlCqw?YR6M_KEyHg!a6cJ|5}6D$e$7n;5*qN1hMQu6v8+ zvf-xwiHI{+l^TY`&eq?PW^Rk&E$D_`rcW(uzSDTp^!84$>-r`LIyA{Em4LW9-7mOb z-)&hj^(|jqvx;DTrfG8QBWkX!Z<_s*ABuibkyVhp<1=SME$r21!pC}AWx?V?g3s-J zx^@h5a^WNTnf8WgCe`p$MV?0u?bRRJd%yeF&W6&nJf@Ji6F!>)thAWI{6OV#A(xVUo1lUB|Nr*|yRp$%s5L zHr-y|r#hItZjep4pvW>dXX?T;f?A5lMHduSs0d<9v_WZGqQPKuZ*(j=*YGmv91xW+Kim{W4vU|=3kab zq)Mt@0mSfB{)%+uk0+4JG;UB=rJiUq>A#TS$oDH97 z**oq)?6PLc0e!~o(?--_@<~06A5g>8b-R~L-|m6Gip6a(KfcXk<^*7KVD&UM+W03{ ziopL7AeS4(rGg`RtrD1F_KY@&=&jE_C%fpA`y^OyB36^`f6Z`Rq#xcxwjpnO@LZP@ zb5SsC*=HcFD(bSLEK+GA)r4nDKEIAf#$Wu0X`m|jFxr0>^K<0GgXyjoHuftcDl1{( zj$?VEP#7ej?KzudeLG0v6|i|R=s3D0uWA0Z&I0Fj&fGIzTKep?tX7DbM-B!Z&J5zyppOv$P}l@y+ZDCw>a02HI0* z+UJw2);0a zk9wEx^doxWw@&wx8QQk+6Khb9;beDcBet+lrAbZX!fispDj(5^T}|Z6WN@ueNg;$B z4K8H`QJ=aXWW$L&W(QmRlivMKq#uF!K#mR)Fg-TEvP5QTFK?KFQx#J0c8H=Im^ zhw;$5-2^-#Q)JUgy-}q`=By07A_^iwtpiOkBV6%+KF`=iuZ+&5x8{CRBF(VgASKCR`y`f zFqZTEyFG<3A2`s3TFT*ZdsHpp47!8!J^xQ-4EwLM=OmU`le?EaX!g$_1~9IGT79 zu#crSHuF1dhc>58j0oSm4X`HoBT~7J{jh{1KaTVYO;W;#4STki|JV9d-dFUgb&-gi zTo=*0xr6GRw!`K?KR!xk5rn7-@XpXXH&1kIo;HF8v9jye7g3(QwV@~Pu`v0R>X*P_ z96(qQ%Mu|)dn~EwM`8^9_@L~Umqh;S?w}(1Oed4Q?sI^Nx8+T&X_LZlGMTGeU%Rnl zOD`f8weeyd2quGKTipd_VYGp zs|X$Zi-_<_#ddBv!`D17+3bYidgs!1hbjRsoenXxF9WWpyxp6?c%&$X$KfoH@{%r} z=!e;=#c8#WSrhCCPxO{9*Z+GksgQDCwh!88G)W#_p^sD09soB{BG89<=4r?U=RxbJ zuYDxU_oGClABW;^_al>-iE~MtJZ5(s2;5sUJ4Xg-Vy*dkc(<3MVfjUWsOO@^z%%QX zY_+FB@vL2XvtCc+4=|b+A+SkFZcxFdfeL|@ihP`V2P%f?-2h%y&*Zr~N=JXxchtdZ zaUh+URr$ZjL~XHgs4(8(;4l3K0qqHc6C}~nn8>`WMSIq>mw#II2Uf5*piWTV1Vyzv zgxx)0h@TMx^`uQfwtBhOGo65CZwstxy2}hKzZrH$ ziB5>*)*54Z^)H9WbC!CB+Ve*&lL}*PA&){6LF8z0VnzM&s5a zmdp`mIp*h6O|N}`+1!4%A$Djos10k8GU_YO2LlqLBi2!6cGthf{}m$8Krkov@RQ_T zPw<6@?_(UwpAFk;Q3Bq@y5=RsYJFHTW>M_Z-hS;i8F?gHeRQ-EM}Y_Om4PnJJMHu+ zbFu*ua-B*k6sT;kbl=am6?)Em*gl+i7hY66C~{%<&$@XPQDY;^sIpFOeEfyxuv%{K zpX-v)@nxasL6eys)7n)^+6|X*Gzi)3Q0?#FB=ES*eqCvgI&H^(SW~Kgjmuu@lmvJm zoVR-<{{z><=Hu5S@_7wdf``$M{<7Y%E|m-C$Ons~MDpBnih1nroyP?lh2xsVYv=J( zO=o&N=sbz#zp#7W@IX}};(LcNcbJ^srjF=hhY$hRYT*`(v(7Dadz=))_Q3S(W76i~ zvb+J`n0J0eVrMeabK#74ed_2|qE2+~VrL7zI|GIOa54lN0epdkWd+yp6rn}rm528t zdC^oQdiHL7q%)!xTe7jj%G7city2v@PuXfuyC)7Y8$7I6B*RvvKs%3W=!&rswYYt6 z!_LH1$kBBzD8N+25gHs1+}_&6q`TQm61DU==vb z-b=7Ih2a?+3nn<}+?eMNUyP?3mq+)d>^rtRNH-VRVxaLY^eh?X7sMa^EQ87pOH+x zZ8c0JmyNV(WBo)mk&^sXqy<|duJ5Kr`r9E!&&x$ZtLMcF7dO^Xg=g+6PK3V(Enm8U zFx}#iJFajn!LEL(_S^k4CLgG^4@&I1mAj(HCC0VoI0 z9E-AIrpz9bR-j1OINPvGrfm%06S$A5fwVbvH!OwEAoe_A>@B!{XgCaxq`5O(fyo!R zRo-u>oa^h@1a!>hL_HJL?Fk>~K4Aac}RyQ2vV(0cofkKx`pJCl)&YI+p(KTILe zl?+W#J^flzev82ssynH>tfOU3H3-sYA#6~!Z$ZgDwKrlBiRBn6Do^H2b5@<%61ZXZWjVi zF$z{^{-vR9_t@PKs>1)oHfXAJpa*!=0~sz~SpS9lteMZ>WDWG)i;S_K;G9e-vTGrT zGizt#n8*M1`nD&Z*#JU1<36(RCblGBd-_A-0+n7Z701SnvwrUH6FhnF)`d8Hd#R%b zLw1X9;l>?u*oV#f+QaDO02{LbmwoN*v210 z3jeu;7pq=O>6N-eRx4Ta2-AgE|6i>P90u-5hpYaAmxxHNMn9?NR-Md@QH| z7UF)DSPZ)Zlu@rmX7;=`ufv70v+wr`$?dvDg_TNi8g6gq^=kYcRn;{3@o49c#=BVU-Aj*X82xZB6weH_?<^D_e*e zP07=jF8~f=oPb4x4=ihj8%BbJO2b{S*S_4F!nZ=_3Lz;5c00>47s=s&AmpCae*=3B z$XT~N(eRtaF~8_TZbdJM{v684$Sh4M1jI!b z2s_%LDMiGz%5n;h#6T=hg^;^Wy<~Ha@Tg)LdzDKT4Bv_pm0!Pvw<~KsL&+2siIm6s zKWbTnE`iUxUcCz`{|Ns4{4!Plix_Y`v`tw_`8&Zq;(yl<`+vk+{eSymb(z>%X&n<| zXKXU0{tV7^$TH~i;$8Z}xR5(k9ryMKRikb|Mo%mSH}MO=_aUa0-Yosgsnp1|o>xlp z1e}_lv~^*Dk-1w;JflEJJ$o0mLW=$XRH2E_uOzLlhrY58idXIQJiZIGz{I7B-Up8> zL@CdwC5kQ$<(P*o*-uO1h_N@T4Z&$WkYL70DWi^Z)3FaVqJzJ3#Ac5c&KePO3=IsR z!LdbgV=u}l!v1h> z-tbC0XEJ=v-;ccDoC*pDz31wuKleUehH82JzOp8)6{Q4yce7B~uW^lpwlSf+jE$f9 z4vy75ZgBdB`Pduogr`EfsT=-8yp&=)PSM{O{8wrI3AEwTiK1M&>rtSU$?IH#~ z$6VMt#C`(>)(%N#^#tBByHU~0L}7fK-_S|hARzH6I;_!s)DA7PT9$m_WNovWqn7t> zv4t1iyaq$k*#cK=!6i?tge<}1$dBzq#=OycmjP|EaPo80}j`BC(@ zKl;D?=h8Z6VC|RiQ2IOQ@qg~8=K8Qgj`_wXL;#OTI= z2{EdtKr?DnqiY_rk&oXnW!%}^LA$umq-Hbf&`ofz`_S4%^mGJKQqqAqwb| zvxUYT>jrb#fO!>0tx=0{=uas_bf8aoPMc)Rhaz+ z%KZHYG47wUuSyS#L}MlgM)`{ZE5-`+H?R1kr{+IHtW;8Wc%#KnA@bWbz3ISaT{BY9 zsmhSh2Y;RbFf+tvS1F+&Rtgao$?%!yd}k?P{$nhY0n*Qb_x_i$L?*B!MD$oSA8RL# zS(mSmY-XmKM?g7O$cunMg1MGt7ATRpL}pMRWY~ciB_CG&6gEgcH&`u%q?E6uENikz z-cTVQY>{|QXi=T-B0Me^r=TpRSRkR;K`AYtq@XNbX1iFnT0d4e{7+a|Sy3WN14UD% zOirt+JYRu+T-i#!i12Rlxl#7m6duxa|EZd`nx}?5XZk|>%2EVU<^%J}3AS6r)AY!4 zxb2Z=DI{iL{0^V=WZ^@rEscs)J-S|;HmAp69|?_2cr6(+9*2IUtsmLv z6d*xA7g`V`sQgm|OBvI!)d8ge6{Xez-rAF3(D#Va1eH?n2x1)_%okun`SQKScZp_a znEjDKuPt2r6fw1Hie1PMEx%6^*$%m9id`T8Ew9fIk{x!(1iPRwVs5txlHIQbgUsv} zk=aej6#HSPcyjiXf!X6R)=ircPL_w+Q;AG>o#0J@*_#5Bue?E4m(#j%h=97zi#b@y zG`CwsBLY--K#i_IH5fPq)|?zxf7cFqTwXnX!{9qKq7 z8nW#Z)B91}AiSs4KC1J2tpLAytpSRCrJ*Amr$epnVoiJI+QUV9;OVm3)OK&r<2k3m z)K(#k1*O1XC|R4b)kN92$nWhL?y|i3e_an%%yeTcjb!W42^D2E%rs*x^ zmnMFjQ-E>6_6@y1`_#4iw3fH9W#q7VyKc7=c?z^kFvtuL0xmU#Q??qzHwHuXN zCK1HIm2*L!^)Wk!@gAj~?xbR8d*Ees-<;}HwKaTTV zd+?rvwqtt`!G!t!Q4DEdYZA*mwl%|@XbR1h$+ocW;AeWWLtI#OW087evEE8itGRsL z-!`#owO+jF7b=ovrO0{|O_#FWdgUe5$u3kio8~_^&3~0O&CXh^*tFb6Kz`S^od8Zq zqwQ*|=9bf>e$du#x&dsvgD5Hfl3*Mjln=_RUudH`T+OBR{_9=Lztz?JT6-PJ?uB-$ zOY*~fyND&793tCgY!(^LEc_R#QXB8})Cj@Vt?L7Ts9!`FmHvZ>?>RKcI)NZS3zzQ) z&MXGxEP-I3p1a))5T_u)X>6YF25zsH>@HrVMhG;>=KG&(FF=n!H~;w_kNug?XM*dX z=a*jeU)urv^Rr{|Z*ZX`{J+}{{%^wxeFy9RgcB1s>wnRMR+wb%(@pfl4>Umm$+2i< zlE$?-(dTJaftron34aOii!bNhvMNywRryMBYHN-om=1gvGZrws#LAL)?8!G zIp!FdJpDpD6@#@3VN?>(15|?E+WGKBWI94t^6SIp$g!NIMAY)*<)I)17|?~pkKev( zZJ~AFM8-J>2gPzj5+@2t!nl;56su%H8Q7YBS(SI_=5R?6ATfr%%@1{wjQa8x>z?c@ zD(0yB3y#X6U4;*h>7wc=&|2j7avfF;E%B7rL)GJiR(oz5#^->9bGJ!1X8Yb0im9Y9 z!iN@6LXMBw*)N2>r<#_q!&2kDwKn^XM5*I*QU~wzv>hCYZfUf@cV@iCd*7z4^{b#J zj@#~J08JSHd#R(cS*Ek*vi_Ha<*?@5pw(w@h~n3=Rks#MOx{tJel(;HPiHgEzWy9T z-=+wAqk4f`l!Mh1=3#RDu91M-@uv=Nk0<6CUXnb6|8@z}$uEml4R{kfSyKQ_#cwr) ztwkavu$~2n3KI><{?#$&%t*-P#tyJc^bPB*6Fkl;VOZ0(ZKHEIk+N;P*x4_cX~q~6 z9>~{+3j>n;=JQi#@?9UXukSgue?Kg2s2vx>-`FAW{|$CJ>jNL1Ri*%LwT&UO#4 zS=Z{_1C6nks{I=Qzv4nEHj6%AKBvR>h_30(WoBiHf947J$C3G(XHqWG@|%A7oSwvx zC236_X^{9O4mn}O;u6*ygQ%*UCZ-%|pJZIR4w^_7=z%zwDnqh@_LD&*tq>GSy-eO)%5l9R3Yp_<&~W<)0l@^-ckukk*5wyhS7;_0 z(>trZka!hLw6K|Zz9Hy=Q+Vx~AMFFWzTGCz5qW;l_X*bW^=)06@z6(@J0!%sw#|VL zI|(A6DVKj;w#_RrY^|w}xto(uwYq1TO*)&Js=n%~n03%#H#U5ZR5KRwSX(|_K8#BM z8g<8U?9ZJzm^+nKnIb9HMT}fAsq4uXGy&#+I03O9ICud}q9liPx~(1y2lA!4$e>2i zKYpdb_%8nd-!2S?3MI{(7L$aPFs>eo78p|CE`9-e+PGzF;F?YyNjtrLQGNe$r3YfO zPk8lGG-8VD%FXi;j&St_y5z8pm=}0-BIKt~779=KqDFfsA6BBIG9>vE_-j^(prI7( zXiv$aiKZpee%>@sc?RMRqNWOg%+D}){D>*gCs|o#&s_?D;hv~P>qEG~1V5%FC$Thf z=_Z-VxwACe`$rbm&h@#OX8|Y#)(?iQBEr$z^(Z#J;&7f+tL7jxe#%F>)d!{7hO^!C z5@|XUbMw(u+jmXOqC_N-Ub{J%TUOMd@=)7_tL3_bIXnKtr04S#R6mV5e-&+_u&TEa zskUQf(#E0X9hdGL$He*$b#BUpUgABAr{t3ihAF^FDWYjt(}MT06D_CZmb1v_Q&nLT zdFl+wx92z7C7K@p!<0ff?O)67(C%ck(;l{?E{x z<9`di9j(8|84DGpW3X6ZxUb*CRq?bs?6{+snVW$;?3VaD_?n@a@Bqq7b|!%qLVk%C ztCc*>>EbI1jU(rN2|_}7Y+PEB5;c% zW$pbc#8%<6ECKciVl^8GnYmj(BDsJMNHAI*+n!~oJ0-O(btnn3F7a9tJy|pM5HOnG zfI!t>PqempGb{}hfF+sDp=P`v_GC77vZXhOgbp%(*o?bF1YdO ziNFg92QcFl&5b?x{e9xg0mYo8bD_7{T#+a$+`71)k08-RB~`Ho5h00^VZV6b`l7kvl6n(=ng-W67Yyo_1&A zdV`NNankByrgY(i?z#pOck1~ClHA8ig{k=Qja0yoiHPF26Nd}QAtzjrY$d4+tKqiU z&9Vtg?r4OvIXP9poJ@eGM@3pBtGbdSgUWAB_-NxX;ny5J!|dy;r5<$Z7q|DJzKD?! zW924xwbq?^qwt<`tmSMm6 z4JTzGT`1|ez!bCEB7SjC5l%FT52ku>S^=1T0n@_z86{}2;eSeSbl`J;mH{;bsJ+G_) zWDgmn-oHZ`QqeBqCJ(nuF~K)Zj9h6n1RW7FYQIxw)SDtlYz|3W6A{WkXb5HwN%`3y zo;h^W83Y`g38q|M`dj1RW>RnLoGX|qghJo${#&KQhQrS|y$&Cd zke+fL4RxS?hZmos`8=G{T&Ipe*JzqSJ0-P!+Ohq0%#c)9i8s74Qs*ZJ)zCw@uSfL) zRj}@obDs)!p6<7X$XRM%NVs*makCn1!Y>9h^=pRvSis0-fN>?(E+^`lXCJ5F z&>%lq-Zca<4Ne!Wk_>jBM7%5@;Phxlz|J8KA9`1;`l-YPpI!IL%k`^>z^djRRB!;EMNK8j;X@_z5R z>ytR;3fYP>q76}fLT$Vlp*v?7*_fxmo4Vg$t~_fFeTjStixBcLRRvBdald$_mHnyf zdr`{4>|Xr8(CUYx@jk9OJFFNm$F)gIFWqyB!;!90s>{n!w+iT@BT;m-5GA^%(!f+J z`;rYKL0(=3$*V%YLSLZop#jGIKL`>yEj)0;lFHcEmEbQ2^3#FxicwVPTVX5c4J=-r zB01v5T}z}Z4il$tqfxmFiFvivJ8Du^3k4;6n!NMCTa^|F`?x#bgHvoh5RwGfIxz_! zrSqcYSyM5<U(`y*!$j8B<4 zIs5eu&i);$37+u=(|p4;amau6*8EF)rT^_>+Suy<+iO!9D{cFi4n1(@Srvwx*i2lY zJ_@Qufg%t@3w4dq;es_R$WZiCjYaO0^R75wI1!1vOO_$sohXHv=Ax60ITFZOne~|o zaZ4j}gihlaI@2=B@M3o~VLgFLO?|I{bOl#m33p3`6rx|k{|@~kI}<<52597bGvkkv3kalnY!&?3DG znk{VjK3fL;yZ~WG!6)?f?Ce!o*|y;t3;TwO0*OT})+SnNqyN|ApnT}`MpC_VGa>tiY;xwu`-IP0V~ifJ^_uUBFX^wzx{S z@UDKuc1ANr7LLwU$p3=~L>bsbCG=D3j|2kh{n*8oKA7cjo#}dYM;x9C=sx6oEj7c2 znA;mF$2xVC!1E*Q&ySMLTRX?o-k_&$yp^TP(*}!(lSV`@9G}CFh5cph3 zI(l$Kf-5HR2HA!`Ez^Jy)6JC^6ygzihpAuK+%`E@%Wq8^XdjDk(-ES z!T^Mv^LUgTGkYEe=5X@Y0*i&LYE`En4wbN5-`?$dQfUE36?M4nI>*OvlHhwjP4(w+ z6-l)ktF9lV8kj2pXE(S(!io7OdVkAYJ6J%r{Xwr029`ZdszG1_aI#`V8Yp;b2kXxca__T{XimjHz5#=GlNPi1^NGQy&SU}fAp7Izww1#JM$-?O zAgJC>sBOnykSpP($)I1dfrd+y#)*EM6X|J+7_AGHQ6-A!`FM%HUY|)Dt1?bE(Ik7A z)@2HNU%SlB)?fub`mHImsV~3&vv8sr0g^2I9blWj6-EE&>-xV%J`U!NhA#h(e6(#F zSg?m`ZcCnPCWO~!|5*PloTrIr+2lAZveXGyQC5VK;S-PpEseL>wtSi)^$e7j`c11~ zyEc6M{=u0Ern#`g^SNT}-<0!n4l*chX6FgrL;Y+dqY$=>4upoZRv&WRi=ifp3HAsw zzzwtvk0^FVO<8NaDnq})R zik5zg2rV^_Ei!1dh@Lu`$fFb}&DJr0GG%@6mupM2_Pt+BSZs{Xx4zB>YdtDhuhhh1 z7}BT`z!?;5N}}W6B~4+CmbPo;M!_jtf%`CyMD%Sx#Le0s@IxeLGGeq`uaL8Rj%=>( z2a$lU;e^xs8}nior@94INn0Ks-HIKj!Tx4rH0Wftm8M$t%2ZHo)joXfz{Jm;8eim) zGYU8RK{@mhJlFn$?G@>ggkSpFb4<@3i`#+zl0i_QXi(%Rie!ayW@S!60^74dqvOP! zs?Ex9XmqF&L4?SHWGK;cRCy57Ue6<1_7|N$QLqtqb$Q(uw|7{h1F=@@bx-SqC?n6S zw*~_2^tT9kE(28NR-M==S3r(=#p(o8eA)0sZF)Binl(Rpr-AZ7uW-jhgvJRec2`2J z740U%>1eWXkXI&7pC+)MD-!le07bnK63-BH&)XuiWmprriI0$^N&^s{bpxzM(kvkNPB+ zXO2NS0g8VgFHnfkW#6BK;yu}6aZgasJ{4`+yK2SISDmh>v2tw~eB$zW$zO;5t}aIz zAD=M5+|6qTV+^RZ(i8mfidu}VL80o?8FmZEXX%6`nMY4d7Kj7A)Fpb*p=`T5m7{{; zvBJoZBk`LHTm=Y6Sd+6^k62n(3KYubi1U$(p>8Db(+rd3sFkAxL>S-w=hjpAg0c|d z_<0ii;5ws}djfI7PIVM^Z3clY67^KnZ~LcQ%Q`XB2@@}ZGBsrNP<3S3h=;4I2IIA= zvw&!3nFt~z4wl$2W~G5kaL7(tAfFGf@>CZ~4hoa~Ns=`?ujOTmm2r)#-wmV%?<#j=DL-$j%fw*NVDmqu9b3RNpAGq^SEosR?M6m2gU{n!xjrV z?wJX|LSbPyWw)-{RiaRlAfx>-aTb)kF1&1@MGsv}hV%KyJv^`Kb51GwoNYr5a_1;H z;%)T4-_b?vLVTtixg`3{`usRaI%mA75~d5}LvX@XQwao$X2>~w)wv`TR|x!a+r~)g zYnH}hiwt#IpkU+f<&NPO>Zh>#M%{&IvN7V+<&)9 zL^Vh@a_V|3r?=!-OtmZI_^CBFF0~}D+qfZqIYS8AA-*`R;M0Q{eKk_C%wFF*V*Qux93YzUqh}Wst6<<_By}2G>yw!hau9Bvk%QrT*3$^LCs-e ziInnTnUy_n0r=$V^+qG+4H48(!UQ1$X}fl8f^gi}{p(KMqbE+oeU4mcJkt>Gj6n_l zGxJm}yHwHqO2@HrnMN%{^?+UY&jchf(q2=h5H9NaSiV#d5Hq-ihh(EjA$Y3Z5LVT% zm5CPuk`;<#e0_Exo_qE{o`65SMAT{^i9k6B&w%&Kj)@9ax;*+iXYZ>J*3U#fz7lcF zQx54P^WnbPCVn|7GmhRAP|_E^<$f#rWAmd12(UZvP&^0$wN#Nr=@3SRy(gmGXVTjj zEA(0O{j6hv=pq}6Fh<%S5%QG7fdKLmSAi9U4*M9p@xt)=jV1p;hM&#ZsJqNF76&Nr z%xU7GTt7J-^gMeB`Tf3|-+a+iqO>27Y!KD^3zy_E27ui!a|5!9vBSS?kPgD0nfbF}TP_=`xH^f&0-DvJA4c9fy`4pz zF&84`#Y%#Y#dDUqs&VMe^c7SlFEFhbSfV;o(1{&# zUCLk&{_rua+CBLc0kp6&ohK4|xd?n984Tdv;XFGtAIAliG=v1ZsV4b`iOg}C$9yB3vUG+YafrlQ97RU8{+fSMKZNtc8X0t$d z67?e>1gKL5x4v@|N70-vQ=&He>CCe6KRAp3+oIbWuc|*=pkZZ} zK*^cTe*)Sie!L;7(HGZtzG*zy;pa)Qaf7xTof*=qV(XAc)$*o~!i_Opw9y}l)NoNf z^Y;~636%VjR9rp*seOr1)KeN2*?;Vyl4J}pN<$A}M$kp+8^O>wm3P8L7$(>C%1K>_ zl=(iFKK$#d!g6CPwosk%d5F3}MY?~unRxj_H6)8+PsGk4RUN%VDr!b7xRX|&DVMI*HFj5q2uRj$jBn{)&#}2P}Dp-U^^;FXfbwDd{P9jPyg)vYIA6_56VFC<)*^`Gbe>4$!Boa z#>QD;by`=U+k6_A@u%zUo*o-s_(Fo6LW@)Vi6T(hv#Xno4#zC(5B4I)=3ep`Y%h)u zt^#H#N?yypFwl{smU;Ev94Qyy&#_EzQe$a)E8`c)nL0i9GRozlpVO+<2HYrte1j4s zQ7dm$(uFU38>qvE>ESMu$5rj~joV3%Il|WqlVVbwsz_>70h#O2j>cYM?AL77Rl5(!f}-0`+~j9~x1F1@NQIwvCZ zc%)S7HOWbPVM2$L)v+z!nPa5qS}JTrTW_p58R8(?5p?>YR>R#~&ER|oOI%#b*#his z{I;yfRu7wm+XWAAiEYlPi(MN3HKJQmrY(YVQayJih7P&92{A8PX<3`E$!}Hd#%!{N ztXk%rxrW(g(jHiwgvKGx7b(=zA1#)j>@5Moj(_3eYfnIro9RyT^`Z1sCkIJp z{14*$y0zo4W15Y9wRHut)r96(`S`h8QQc4@saCd8c@@FR{i@AjejI3O+_bB;6T?;- z%wK9=3P9VPnyYz;&mJRPPsr??KXX@TwknDh`s23YOteX_&JVf?i$$$Vk^eYDfUDXF z5I8l2Ja*BrL;8F!pua*XZrqu$jWS2xgVmRIWozL$-$n-HKW(NxG53FH$1-Kho~#X3 z%jaQg>gV^0OiQwpvT78gOuTVEEPCNqj0JH6R_I&U7wuqlC%7Az*{saxSTwQ_Iw<@} z;nF$FL-@!N=Pz#^$}A%Q^MX{=LnQb4l({5@=lEnj)3 zjIZ-&)Xk48Q#^A4Ik4&{w0j=x@m0k^JTaxfJu+qYc7nIP{80P>OacbZ@YG|zT0=3$ zQA3WbTQ{JE$mdL>(5M-&H2K^@;{oM#c(p7jKRnrm$UF6T!NhvJwheQFllf$>d;AB+ zpIpL5<9<*JRD}375VgDE@TvAZGqS-0<`$v{E@JnczXe^LF0j{ND`pQWd~2?0g0Mw_ z{QU(L1~adA!{P2DNr+mUr&L3@&q>A3GJWja*f2RoM+|Mf+}L>Ry5bz2cHG{gT@O4A zUA^4A+;-RrUAZvb2|*mP>Kb}@IoNny;J{H^qsuJ&2)$cHr=M3i??eojF`{A~e{Jjo zFFSM1IFG!IfR9|A*nRETIk_F+;zeiHdAivhV7q_+lY>@eyvl_>VFavhP`|SCHRC6- z2GPs8OWW66e`d10Ueo-0R#dI@NB7SjBFU&~Ff3p^9sWP%Ai-`Z zbkSV%bIfapWKq+r)MF0$=m}m;D^MC%m%WSbc&bh~5?M+vt+rV>Hi?66v4I@7#zqNL zWF5?2iV#HbzXPrW)CRfVLLWo?F#@=5_ucfya?N4Ivi%JWq2WfRZ$?3wEX#||-QGBv zglYlF;03od)W1abo078|d>aKNK@_Pq!Cx&MYX6M=jRB`GqK60(d5vL9HYf&|@iPWZ ze)7GGVV_i|fN~o{Mn8We57agq#-EHFS#g;GIW1JhTu;a$AhrueSEfS6s=c&35J|nX zY(axRb=e?sZgN3!|L*u@vZ77VwWOnt1@ql?&Df{O`xUx06AL|3x30iWWKgU5YuBA< zSPR$orEP$)u?I0S575f(jA3zHGFBl98R=RD_0GXI3+$*h@IdJ6ZqJs1hVt=;r3Qt~ z8!2lnY|XR4kP&N|EWUC_8LnDyN@2vKDS#KkvMY9=Q06i(^MPa(fx7Yxr1*hulAISG zcA7%Mni6%s;E8vnmf;6BBnAsb*GgejaD1VK9TPDs{lIy&1}mFO;;$a`A>Y5X?VFyT z8g-_2&p};fnX$pELRinQfU*gsp(I!rx3x^enBMPs(*se;Z0*aYr262& ze33xRkJ6&0oc%_pIPimNf`yTPe<=6#2*=HxQAZJg7@+r8ou~`07cC7u#wea~OO&<9 zn8W6hCH>eIDeAyVvI!a2&0ZKCND$;BO9VJ}aiy*OuhjD(b0rU^}PQwPg-yk%|Oe#X1nV>#z!couJxTV1%sx$wX(RL91ze7loZWkty$)QJ$Vx)WwkyZ@-a%QG0VGMc-%teW@$2CMq^ z&XC<}s74U~yd_LcVVTC5Qn#(>`510*p53b<&E6?*(-& zb(AL5Kxpt&8QUs{Yj=e=e;BM<%CnDXhNw#JpQsZ2NGIRVPom~P*sB7Q$Yog^Q)vK_ z5X|#X<2<(T%cD?|fjSdvm{&koIo46GmUq;ns4|P|w{j-#^~sn#mm(|?lq96Aw^1lT z3*$*KV58SjKU|hh0qcg+Xr32Tp#TgjEK2vXpkmyxQnnc47@Ngy_1wZvzweZ<%4^OY#Vpj2d5y;>wn zyc#etOIdp}gZ(KB+a$m^HOHXTPN3x11M+nK5cjHhe*hdD^Z2mT7MQi++d@E_hUIK3 zQLjBHS*s|;a5dohwNmI;Iu!;2D6v)=9rXs?nCF->2T9kBS#QPG5;i62^yau%@ddm;Z5qd;z zt0;)z&Dw0-v2;b3fNrK(W@LDY^hz}7F=gDn9&b}KSc0_0wo;`GwHpj-GrxoepnnUk zbi2NoXGvbUf-M&*WGU_ZoAiA4na(lf5`g!V!3FY5e$3#NaUhv#QFScx?s}g z%M5dPWVDYFY+aaNAM`0KLS`0h{rr0zU!QGxfTcB8Z~SALKtg|>i7rZ zn4EC9tF-kyJB57L$kj2^2<>H-6|g|1GIFTqBchXy#JlR6nMQ;5AsfmOZkoFla3+!s zx}t7<60*r>!-3>Jv2tU(dhS6Dj5=I)#3vnLEf1np|?>XmU+3K zFp3C$?S=5u)po@j4+}{vfEpUM;g4wUx_xMLMF1)3;faq$iHMLbMNsL04@K(k@!XNW zKY#fo&f5?xpQpPR_Em+KRp6<)Y1;XX`hV+;kMmDllgV^r`4K)i{sbPo-vRmVSF;7J zx4%j)Wi~<4BDazya@JTM=AZ-jDdORxK{O zQT{qIOUkqm?V6iY|uo9zS*14j`h3O8y3+Vz_=)pic^iOdDuR&4@I;A&a491bfVsUWYY&cAM4(roaL=Z^{?{lB zJ!;4C2I7w&{Nn#FifFF?-r_EdmyKCxfghULD{-63YhwK*9FMMphzFf#GJ|du_G?@< z*oY(R^Qo_i1)x3>@a@ z>Cb2urtoCDJK&M;LOf^wd<602Gg}#0?=$yrX7=NbenesyWPT(>_VM~!m=CEdT3M_o z*@w)N2hzZ}fCT4E#k7LQ?6>Xd_I?_9b7ixWq{Lr3FYs=|YpuG~=4Ip1!1pNPEhp5U z8JS)Zuv^wdyRo9v!8uX4k|<$|#~;Dm08l#{`9oR3VmC?QF6p&!Up7x*scRd~0Bz2K zU1=_@mPp}c7vrU&b6|xcY_EDmbhxOt$3A_VCn=9?O*8mP zDB>uOhkw8=AR^?&WNb2ek*v#r`xjd92%TYMHf}DNq1}-f6L;eUW;MHbjA1JBbHW+l zxhMxszle;7*Gi4xo1Ii&*(_@%sTDWjAr)GqYUO9|7pnH<_%=u}j+U|6(ywdfB0Esw z;Q0}C6Pmj7U-#g?wc9-ByO^B#PkDtB{|jE>KMKi4`cC?^-+l?Y<~A<>=Dp)cYn`{-CuiH|>yp>!Wr5cB^%d{S(I?~jm+n{U=g0NeaZAni-P0Ff{d3!w z`qNg|_v3W}&F3TK>*MJSaPIpt-m^*j{CcnZY5aA+T=R81LHqT7pF;ab_w)7T1@N)s zYtZj&o9}D8_qAPkyiRny&h$PI_->v5%0mB6H|LY_ypO;BYvGvdUCa6G*xmbLedWn9 zgXF_0h=Ruj@9iS`bD&86)_VIhMUtQQ;uJ6B_OH*Q;q=U#x4g^Ew;+G@jTan2dhYuv z%)&52b&Oz}hbph-3vSx$%Rxn6CEm8i(!S1%P6zCq*$3m6(6s%BXPrR8?6DRnh}|CP z56$>&MwLZV9{dtU=PY7ai)pXkXcj~iPGIW$ZxwGd<~Z!!fVmt-bTJ?{=$0$euFRYJu{Z}vOO!j^F47H?P1RJobm$y!Y}m*&aSpfAan9d#_(AOO z?k6v{C;_i45vt+Gshq#_*j^WckDyiA%r^rpjE z$)F%yc7HcG>5iZ_T&9|x%fl$>jD$}k3E^A=`D-h$7 zrRvy%2*}W`GL&6fXdX|2dcB(1ZU(vutg_TuYe<6!6ZYspVRIfj7Ux*(q*asDXZ(l6 z4b?&v3oj+Snk#FdiiV1RykoV>E7uPb#hOj$3jPpTC?3R8-Zg;`7^dJ;WHl=_n$%3f zpvo1#KR!*>`oAfnG(IY6$NhFt>|FOwvTra2z`$+;w3O)((atO=@>4tfjI`wzE4E{x z5PKvp9Q~gO_~(T6Q1>^dm-z6fz9C54?DS=~GU}BI-Yb9%RLHS*mwP-d$x9YP`fLhG zTV8-3J3yalVv|+D8QjYkb*hZB*r9zklN})u{Y?p`N^i%{el@dijRXAv2D>{CKj~&Ubm8?&bqzia)x-tKHfy(=igj-2W6v!PcfEJT~di zL!T+kqP2sdilJoz*~nC0a3_ZSWc(EWs;I^~EZ2{e@;_rhn1`oz8?bt^A%XZ?)Iru% zf@F(ljezpoh^trt!TVXt;Orr9Ew@mtqXwi}=mNv9UW}BZQ+OnfpC5Y-=E{8VzMRxJ zuKmZ#;O+d7GA4L02z!jy$VIlD(b*41&JhDZu-hORWHkP{hSBL^y-RvRR*2mN;^j)! zGNx~0jXCRD14xJ=gjzqxOjfH{o{O8{WS!Z_;dqueGJMTACv>9dgrLz3u(zD}QUx6R zixIz*jzn^Fr-Zu67#+5h4KgA%ZncZtDM?lWT~x&u-Lj!o=P7jM^Sf;Po*57u; zO?%CRsq@T=6?L!)b0e@V!&+I@8_5cbE&A1O6;h=uteJU(gaNd>z^_Xib0%5Bk1 zrvri985gHl_qA(Iawv>6#-pOsIM|j5Fjx~t@wDSeUSw!LZQ5B@i#WvDAQ{$7rp++^ zj98l}$hd~Jp(S$$v^|vVfu5jFaNXOiWk1 z=@S?R>Ak~)45oZSXe*9KyV&(`_JCT^f7@H! z80}L&p5ZiIHo&}qLTxA0^^=%~%C!|O&Z`YU`S~J~J#egZ8fwD}%~7o+r@T;EbNspx zo@YnctLgmI_pE&1IwC8A1%fIl6#Th7#|3WB2g)?r6-+mC?D9M;vJzhMEIcrWxoay7oa<+w%hO8#Ci>?i)(`7)U}Svh9sR|pi#jyS1p+pV{$qZw;JnQU z*`Uj*wo8I?Gy2rYDo8z9o^kz82=SVAT4?gOdAHZ`X0xM0 zX{=G0(jNLJPt-y$BoXHmOdea}?F0WXsCaNmz7ECO{Y%}DY0FWEoq`7g(wz zLb~xfv&T#R(!~Ow><|=MPDy}HfFWyK!61n2RN%-c&Y!ih#4xHkLsLy%JHaZQAn$>L z0!Zr~bT(p+aLmvoPA)f-B%c@G|6~E{sCpjce=~rwkp5YQ#PBa6Lt6*)Z!0`gTdwFn z31E6;;ir3)W$C$~1dU)C5VWRmMv625m|-k~D7BlFDD8}oS7$!FV}P4|mprH{(h+JJ ztuna+4lnzLYDH>Da-5oley@@d(O5#X-nsyphmju)`FlU5#^58>1V-%~3I~nmW@gmX90hWeG{KrO%OE#t_Lo;ZDj1m})< zs{|0wBf%xDJ~s1o`3%}i2to9F?G`Ic!pw>7YtAKaq6qLrCi#1;|6o}wJ9CKq_}*=k z@6Z2Cm4tCrY z+(aL%!{}yk$En~v$8-}0sRgb-3v-cg3#m~8!6bO?azIVKas{;eu^FfS4!I6~0m;FAJJfNXKf8b6^{1STQnM$= z-?9<*fI8hITAs;%fm3*WC1prme2a7DZm`dCePSO^PGn+59#R@O>wdOFvfwgcC@x$W zUyc*T%qVl)tC2rOsYKUDw;$R4Hz;S6-6(=Ycrkk!!!a)~!!kv?**dnGv0cd0nwVY$ zHV9BZfEKTM%eOrkd<__LAGhh!4}cB}c3EllQ@^3R1N?Z`#W6=hNLG?Oq`rMd-cunr zztJzp#^!owZ}a86~y4l`0SBBxuDT6(n4Zt=Z+U2x=y7Wvkg#QWs4N`Bd z4uEvCnrBQymml5UXmTkgu)2(Nb?K((91 z>>-aV08K)~qI)VBw99y>brhzq2*kyUCW7QK)WrKkP?aoYd@gl&2mU=O;ANyMH&Em6 zXzseY;tLjaZkRk8vMX>5bBaAi1Ze~{)^v|)CP)kk?NlkUFy7)Mgw4;aF>S(^c+5yv znZ{FoRvjUxU58_8g<2+QK$oArnjCT&Uxs{D?E+nAMf%`PY|(m^D$Qfuj!Q#ApNoY$q;1&NwUrw&GR;9PBO09OpP> z`V)Bufm%fFf7{fHUBwf9X$SZZ-x2l z#)g)(|MvGgb_J?z+N`r7bv0)jlwXTj;Eahc>;<5;nKf()|7nI;T7T?^MMY+hUy&>1 zQ*hak{^K3x-Q^uW6kDHF$m?mSmcDCul*w2?F3HCFu{2%`uw&q458BoY)P?QD^s=m^ z+(}Y^pM<00XtYEYR!F|t!cWEYqQqfiREzG7;){jDY!IoC=W7B5t4ZO-WA9NGD@i;k z#qqaI1D|G6f@s2M{884|0%1!tjdq<3U0T#nkVlvjsoMbN*D_ke@6y!|*W}vwkrFXM zjGZ&hhd~nEd0~J$19A_uWM)jwem{Q_dv6fsf;IDC_;)M430Z-)_p(U{uP)r*5t@JP{)Bw5;h zTNYMh>8TVasG^nymEYo&Sn*EMi4MTCEs_>auEt2IUNjrj9@-$W5C{CkYxD<~&HU_jE=~o#^xZ5b zo`1NU+yeVUt+_mJVloz+C^8vT>k2FO*25?_)Lv8>>^euOfU5_m9!x!E0~u<%8?ves zXj+M$l^zlc_?Aa8aZhnyt;u7ovT-Dodw1Nc#@QO5{#Q^OZ%3jTq zLrDC)Y!+aV9NNn%KVJc?AOTVvKFnuL1@RzNK8ql(&SE07mG11;`n6Sszu491&T03{ zmn5O3G7ej1gtjKM$fzEhz&J`z# zgQ`}#TrZQ;G`cCKECzJx2HE1)Iz%O~N?Kn4US+Wk=1i-bh=px#4867&!A<`Ur@5{LwlD*pjOmQ%VOzZZ;MsqC2N|0ffe5C+du@+{17ILSBDaWu-1T4L~N|XQIr#( zsuW@kngL;P>=l#AgtdQkEXWEGY&MOZ7qzM3D?eJ8vPvf5N7bFh-1DCC5FjKQ<(UXG zP#;JT#X(GM5hFs7>I1I|dcnBhN)eQ802faFLbj5f=95H`0V{5Ba>^2fni(xpQ?s;6 zK7LEJ#r@Hdt}UOqDy=p&_=r9q9*PD=xqTmi>q@9&M!kCdz4O3%tt|m}4ywDzXIyDq)CorQVa74B zM&?LG5XG;N8w0P;2{MiXfrF(LdBKZcBe#N~@AROeKKG2ZyA_^03{r&S;t9@~$QbTu z(9{lW9?vunJj7jJ1SmCVDFME;O}_5wbBh%(i%i)0rUo`SA7))&7T9Q#8u#@VN1v}B5yvn^+>qhK1dM?a~aqABqHi^B8N<4c)%rZO}3JF&lv9YM^B zz$P>yV9XjK44A6O=^RXln37n!sd4%}L-56n26E3cy1om|ns2by%EJQG)@Yv{$<4`& z7sB>j9r@<6A4KA5P0ZR5xPpOZg0kAkDT(%dZ?CURX?8)AU{o$&zj9lKY)@uQ2_5#! z<-8z3i@(;X8QGa#F_%Lja+B65KTrb6;41FndOk|tsl473Iu5q~lZ*eOIt+3CyTVKl z^Ut1*f60;jzdalOs5I05qvPUOIH@ah$A=7h^Q1oH7ZW=J!YTH8p!tGiAV7qm#h13_ zLK4k5wV~O_sRvv+V(>L8B|PCDxHKMGI6Q`#5x})}C;Ed2rysk~}(O4N~Lb&2CnG@@4IrdjTm()39y6 zpVIXqc|JvobO50IM_%FWfOPziyu$pS<`n|}O5XPWvDg2u_U0AcXYsw?BFoc?UOm33 z5{B^-Dn-co#R_7|QW_h>2P7Ei3=EEhuST0sW8uQ){1>m8p55nfsb`yWqwV^U0rsJl z_>;`}(OA}%A!6iShR}k^li3oo&pcaH{Hi-58fu$q{&FYrzo{*{NEZ~sE)m#CPOXey zN>7}MjQFdF?GhNnJBO0xPOGW$HSGk&bc$~YqU6Pev*EjS&qJ(9mBV~Hrsb-Fo@v(w zoQd;hoOUD*oBj`P?-*QZw?>P0)UoYOC+XO>ZQHi3j&0kvxnkRP(y{HFeEZvbpHuhN z*{61$y0=!52EJixW`>3}SzMoS~I*#H* zzgE-80$rL^5Y48pK6b{JCI~rXlYMgX?bcx6fW$#gIQIxZy@kxWggkRFo)-x%;E4{C zrP7BzGj~&YbXolo=Kb%g%r*tH1gtL<=KmuSg8#Qj{8KmWFDy=YQG&j(cw0&jv^R*O zpr%fi4@nd6DPuCT!;X(1?~aL0MV=u!{n9=8(!tSR+H&dq3?TSr?9xz{6rsn6Ll7U3 z%C}y}xCj=~I7s4Lvp;-M3L}WIJAf$pRUpxmx`-Cgn*jPpHl1rFNZc}dm`=JFWJpA+ zn4%KO9LLvalJw@g2EWm2QGj`O9Ia0VQ8*)CAtM-nfS%QdjYgrw+iGKyIbpxe0!kYd zq*f7#3VSuk3aUPq37!0;8tPoeZTqV>`$aGz{^pkG_`%rqTiA;#rOL``FbmR83FeiR z;iGQ!zHmX4Ohc28k0$-s#8y&&pS;@!Pp=>sE<~G2%FU;mexJO}zA_&|clA!x_m2gc zndpBTAxv77UEKd89RJtE_=j$hXVlbRUDjgSnsWRPW=Q&peKCWQ@!!nQ`!_SPsQx$1C_481-!em$dvaF^ zD?cublfbiU@v}Kok@(|`U7!(dx7reVAu)h^&X*!_NqY`mAI}K!3k6# zHo*xQu;DSX|?D{tr&kHs)|FbyD=l_Vs|2;MSmIeBMQ3GjUpfG`-u@t33 zJTA%Fz&;KJ1~Zin(W~xD{9z!k;fM3P*WqjQr9qX82;pfE9poQG=_uj{AeaJRomf7BuNt6KoWKc7?Q?Asce^5grKlV?4-dtiFSYuMR)E70- zH24eKn*uC*VD+9EqgBiz#K~_0uHMzRtT;-=-&UN0%&GcyR?x~QAich*L0%0gq7g(f zCin{txyk4Ez8{&e@1_4lL*w6QC=k>=QE^~n;y&rK`W_M6IUjtLE--JUhSR^$xKEuf zK}_BY(sS1vp7kPpLVu4=--$djdseXT%Xyi;Veq$q6vb3_Idwx3wiHp8mpuP8&i zqulEjjnAoB@E7GC?6A}y($Eo6tO#j}d4bUgBCc-QR@yGujNGz?idxObJF=cN81TlA z&=JBINAX(Y)uA#zK6KgJ_IxTSs|AY16LQUpdT6nj4?@vyh`)9;y&x6+C1lQ;hZiZY0vNJD8?X z%gG7u%~RcA;yp&-5UhS^1sGh$)u^J(b+WLBTzK7{uZaJdze-MhuO6W#@JUv-#aN=| z3?esY5BiTF+z`-rn%4<|Sc2K;upW7G&}(5`sovOWdnq^qKF*zYE5Q4*%}kJJq`bPz zn`Z?9yX1k4gl09ZNwem7t7M0=<4iE8QQa{MvGVmuclsvLQS$E2T})IbBH zd|Bm)K8YKRu-^s-T|C)^g(!XYdpP(@+z3in!-}0Kzna%qHTB=?duZI<&n0rH=!{$vvr_jq~&#{qo$>%{nsnaKVSc!N1%U}$pt8Ag|7*tcrCt# zeKiGbS1L?&PHzF?Ir}9+nqU~J1rbmeQ9xm)>Lxs{No5!L>Cw6u9h78^&*Z>;(Q1-# z=z2Ps$)YtyT0M$w>E7!RycX(lC=j%!$J+sSg)+>e5MRnUbm_aTZfgVVm+mQ5q9s5J zll4pE(D<@=zY$6x6^fX|vv5sUAm39@*O z?*$zE8w&6JC>XGfgK^8&GDWM*ri>O1lLk{BV_`-t`EOvdD?&m(m!vy^!x*p3nm`)urw#8pOeM7+$ z#V*b18W>}$xgi8brzS-1Hvxm7TCgZN{!Lf&somQ3b`NzA*0zaw@;fSu79+SlxOUyj zEYpeU7@GqNI5T{s3T_`0hEI2NlehY#Z*}Qs5Yc+lk_OLh2_3!|XR_ky?3VQieL@k$ z=6;$FFR8L@7rAt8M`*8e%+^FLdwZ@4&iKUTJ1L?G5lohMx*rAK)Aj~`d_{+hRq^mW zW+|6;jwogq=`I#e&pM9lDE)vB)nL$%DL@|-CYH+$e$_w%lbZE zC6dXi;J4;InzcnlIb)-T70wMUEH8L$4xrCuo?68VQgTVJ3rRmqoF$9niLZ>@I8`%R z=yPmoLKZOVXyg;fsub1>p4bM;QK}Uv;eE=hsb4;QrLHBycFBe03P?x&#igs+JubhX zVbCE>3@{64p$M6LGtWhO-oaDwOcbcL5@E%@P(qsFsk%}k22V^uyLsP$s!qOko?o25 zT}hozF;D=;0$`88x3BP*h^&3OXmuL8zn|z7jiGbGpHzSSga1v4sNMFZ{I4t@od1~R z!}Q+}!q8sdgyx?Chk%7G>wIC9?^hPCVG7jbly0@bJK2Qyz3Gv8B}$6K#|vfZkvqDw z!!Wo(MAnHe)lU$i@=lE`B2jt=kD16AHq4IJFY#8FJB#uk8T3D;mRdmiFrdv({ zV<2jH%iQ*;&*`x5bhN2ynsacBDKklug{3L0zEKCUl?P#PB=UF94`anWne180PF5rC zy7rOwisVw@MXM2QdCFgnnY`QCyIMK{Ic?{xH}Besk0-;5D}6JMYr&hUBDt4f!SQ

    }d4a$JqdHmQvVf6*r2ORxM(t@Q-h2=(YmoW@^nDp3df# z=}XJwlem87xEXIL7S0rF$I6+6Y`L0Zoky2B2o$f@XHPNs6Go@G`pQTz-ba(=195n1 zvnBGOyZN@Di$=FuMY7@=G6yCf8_m9lz6FUz%VH;SmE|#}ic&^+KwX5J8s6Y!EJHy_ z^P5>4GkevMoD-pl??C-c(gvUmIK;$RJhMRji8w&iDp?#Z&jdBw4e;{){j+kH}N zo7Lw5PqCPc3gG-!xx(zVBU0{*HEDUqC2Z!k-dc5i*--bt)$^1~BGhG+EOnA0NP)wC z|IGRO3r&a@Q5F;h=pSDRu5$XMbO{*ZFvLMf0-?G6;r|$A|2Zkd?{>{KwfpIDoj)R8 z5GzU;EBrH35G#}s$!tIF-;YGIqF;ZDr{p4$MIwbv02K!&_Ko8eL;J^=L-fzdHd3+# z6mclxz&L)f+ydEIp}$7?e@_CWl$De?01;*Fv+qZpJZms+^!p<*Bm!Cge9*Wt9F8ZD z3F5^3*TeIy6C81HoWMx#zN|edTY{(DUn7qAKPOSb<$1|+P-LMAxbv-lG^kUpH+Cu~CGNqcui~|LdWy~94K8=Fxf{y#g6|f^ zUK3O{D%SFZ&H1bzU|=#Ncl0p^cng1e&C~IGe^!sJ(PcvB&^W^zr+2B|hDj^zK!EM- z>Z0nH2Y%i0bVgSa{v@lP=Ow!lnxbck8M zqCqso)cLpsh2~)&9T;M^kKv)diTGa3EX+wZoTxbzYR6VO`&5o2msgOMNknc7)^g3N zNU7}#((ZIBj0V%i6kA+?x z1YqRh+x8c{wqOncfmMp%<$cExKb+jIkH_wiDGhxg4T#ZQJVRqrpX2CS$s6qu>b4_k z(`Szr$%BQje`*cSK78L`nM#+BdLXW^JgDkM=cK2!V&7t&|0N(0MR9TCNS*1`_jAyb ziegnzXd9|XM{oJuncI0v*Y6b6-PVrl`Fd&pjX~51S4G-B7;{}Bxo@S|toU;$!CXRA zXQrDe8y$j#P86K2xw|K?B*GE9W->>;ErayPhZRix=L1}dZ(3Bv`nKG<3YDS6ztjpDMZc+~gqAvJ@W*Rb@&RtAnRLmtJ?S2oGJ4(!SqE4QQ1L)hMcDNVL652Q!263*jkxfNHrfZt060%4&p$C5D6swQU#~xDTk! zDawnK75gI%e&$P;n|OcH)i;q~zWEjj0F}q6(+x{GPZ^wU>wJ7V3`BFe^TFP)EA)Wj zdfJ1>fKjX2j~O@QetdE2H)7dHpqjkjT)s-rb(g{6S@h-_!np;N+$L z{Mq7JF$1qn*%(W$Ga!g2Iimm!u%4B19}%0CP@P`yHuU39KdYdO)HXm9jsR1k#p(;& z(sSMOA3TpGL>rH?^bpE9H-loRiNZGVh%O~U-S|xZ@4;zI z(sLSDd~G4h80fB-XgX3gSv~(a3Nn7iU-~^DRz*}c>9e2Sy1t^I5j$F6Q9Uk5jW;#H z#nJ52!Wo)#iS@PFP5W%Q6Be0m(na!`lCsvP|(7IRRBvAXfk~74UJkIuTfW5h zOO*q?7xh@naP_a^@)ol)j8=|+6f|nXY=i*!Ux7SSG|Wfx2~sW(ysNivEYt1ZfJN^d zF$eLB$c$O--mi!=Z<@^|&ll<>>H&0^}bt$ZHaT;tt5#~Cmg zj6S=A>wqXNy;>Lp#{%(xz!f9An=2}z)HYKW)LtAN$2A4jxYSY7mFsjIcEcorp`R1= zpA?RdH7iy}V`w9QAEx;7L z!7B6X^d|!QpFHsY{Rz-s&)V?I{`V`(eM!Ti|7HK5Z{%BL_lb073d!hyn63WkP6D$F z=EC6P3sqtMGXJ9FQR@3$@X2xKgV#Y9W;8*2V;-)q7hI3VoP*$Nj?z;HKqBBGHdk)a zEe)&|ee3MmdlglPeRxrvt>E&l7}3}5B+F2GRa_lbT4JP?KTV@ky?&U8<{tg9<8EDk z%q)|TPUn`QdL&sf)y%;0A~APE65t$-F4 zs#9sJf^@Es`e9PozivT|> z#E)0Jjem=6acc9kwdfCI*6Oj+N4+SdKt=)tr;CKw{1CXLZB z&G(unw)QA+z_k?%%79rU0JLy*;S4Z8Q;m;MHAZ)HkteS(dn%@5dLDvMX+NWq%uz$x zr&M;^_W%zJ6@nFEdpQPv!WK^OV5!X)M~wlZD)cD& z@ODk9<7gixDCyXdzu?yk#eE>^)L3&OBNv;e$Coo%?~#t*QO{e90Qb-Fs3Bo2X_@Jj zsrOt^LYEz0xoW&vIHLC;-xl=?1>HPhO@pOFc1u3TAUm)$SePK$nGxxswOC zBUj9IQc1jH>@)i|+ZQXk`E{sv|899+KArRd%h=)L z2((RIEp|JEq$n7N)Hb};S9q`y>xcH8?}KT%zeLM#q+&c;&N4&{t`+;zXUetA$vkb8C!yoYGBw{8@^+Dez5Jl>gZe{`NXYr&vE1?4T0z%8hUVQfP z;9EOT_$~j)*In=>F#k$sVM~P0)fxoL@S^3Zf}-+BTZuxalhw5Ppkn0GcGk{kwKw>2_hQQgv5g?Z zpoubq!wPJ)$z+&^tjf!qJ2gz>V?^ClImM_!vSFQ^h^nWs$|CQwSKQ7IGnaqC_!+hCI%P2mJby|eLsWhGI<#;W1 z4p=kzK%8Ae$iTXQjV}*#Ohqh}G6kj?j``@vXApuqJC)omGj|btP?_e?(_a0o!8)w^|Sl#w^9*Fq*Niu#2m^ ziXmi2liwv9T2O@g^eIH2tyvTrH^1;;@>KNNh92}G2#a9+MYOx_vgP-mK56o3iUrJG z+P}mqqkGv-rrCKCznb1)%VY2S24}7Q;5C+!u@o|Iz*TU+r~928O2p@^&~XYDMQWqj&}B*d+&(i%NEb(u)eQ6`?V7*eeDs0a}pV~%C6doo1Ye7a!NJ^y0_~p;s$IjTbuj1Uz>|-!LH@b`@ zW%=r3dRLG(w)&H{Y!+;^?Z~5O%pShENh{=OfAcmNBJ8(p1uf`Xd(m zUTeHB{>w+{wBZzPt5P&4RvTe^^IK#5o8HMjzZ%5x!sBiVT*dL6hdT$X_4i1{kJ4u$co=EifBUg3ZR<*>!*J~sQZ8Y z5C@J8EV3n95&EbaGmjmJ#tE2%l`<8GFVodoE#30iXo_o-Taw`?4F-g1=VkDIJ>-%CLbrxbnEw-kSVYW5fn;}|)xx=;Ddu{4!O`-(S zf`z1p?-Yg3pmZya|BQ;udyd$*?q>^uNrok#&>D6u5_Q4X#OPO;?f~*PHbAVkSA#Mc!0S>U84A5y98HNZt;?=d8#<)E>)@J z*v!y76^bsoKgPDKw9vJr?<_8LI|NQOb!5ZYZ0%Y!=3nX<3-&2~DRuyQtLYbr@*pX(IZ~+@W9v`JFv0fmQL!B<+0%_IgdV*7kYL(NE9l|^P?Hng*XflDt zE0S&XK2x>WLYG&Z)cBp!LhZk+GL@ff{Jgfiu9}5to!;nc7&TW!yv?N$CiQQ3s?5AD zkzSIgKfiPn|F)6^ZV&oUU({pxk7{)PJ=y+Z+?RpuP=B{y6SehCwP{#?o94RPDFmsH*Y%#V<7KB z99D%@7ywVY7bd?^I2pSatM4_aouV{JWlfjxctSR4>wwuPfk;c`Q6yneB+- z)A&5^s^jx|hw`Ms!#GrEAoetDM53t~fw~3dmI$VMRiF;6{GScE`S6hIRweA6>#ZxG zfFxR)IZdNCW5kB*8o@|qqixuV0V=;6S&T!)G{VS47_6$$q*>iJD5|GmVBB@GF8V_7 z!c6p4ik(F58~rR`psH?3D#h=Ca;vw@Njt?#PC(VNvt+_5{6a01=ikeb<;N#*pAwn= z*bmfWPIy1zp+PxdG6WZpR=|$>Qif|9_2vfzGFh+&?0sW67Q~;OWe{uYKv8CILqtq4 zujLJ2Wzhe8(enlyF@%`SG3XbRZmv^h-+e^G#|at7I!t+F4LiEA+Rkh?I@pnzCmVI7 z@GBt%+I|TFh4Kd~FmGk1zwmyPd(wW3LV=Y$4xbfp$-R){k8(d&0UT+dP>E;qHP@Jf zY*|I00NI>AnAhp#MG5Js!!|G`O<7q{FP`_fXb7#uxlS;K(G!#VjuIRR=n;2`UI>HfyMh3H$4#5podL)^hGEdQ|7F{167&qpz+9YZV%NaKqKvN6ni!pHc z=RaSYGP31eACGK4-31H|nRuKInRIxwi#rb$=Lb|qO_?xtW`QqO9kQ@QBLFY^6gfg&`+L23kAksv+f_p% z^xmi~!w&Ojh|XT2)@qMO@@ubG_MGPAdJW`ERHPSPb=tU&f?~OAE>DCqDem;_QjYjs zHq*uhsn2ALF3j$ZQ7;1ow4HRtDkb_ckDX&C2)%7q%Rc7QXyizSFEb1UM(3m1Bi|+| zBBOYAwd#Y>JUOce#56u6FWT{)I%gJ`d#%Csl&_zNPhc+5!?`=2o@Zf4Ah`xYShi!d zXBn~%x`u|s2k#Q%vhrE(G9=yl81s{_a3D8-yix@elLRAFH5{r1oHD&a$jD>~x2)Dj zU)}A0>s{C$L%@TB=hO+iiV~F%g2KE51NnuaWH-usdkbse%?wFGdq?J zNzBQWdzfM(!b#m1M7Ac?%a3&)<)6lD3O5N`od=19Nn$Ql&m zR4NDTV6m_99Xg8qKiq;uNbWLF&=lI7>XDoWp;`12J%_M*g+vukq8{Q_rgj? zOzh`3C_k1@g)*bm5iA-4!nln;wi0!~5ZVI7vSlycW0L`CzRGOKRj_L188e~mnKp94 z7*9Dp`L|VmchYjcIB4OV!CkpbQ50x(J66|nm9G@W+|vYZv-(MOwu)C)jlRDU1Z-gB}C`D7ym z!x!?skm=p?)v8ix zXb2p8qUxS&(v2r7h`cITA1(?w`?q~L`$8~K1QPOGDUS_ zlB&EJWvI8inD$=f6oX7lc!r$AfzdX^kEx_>cT$Q5+nnU>`+QsS=?iI`t(IjdwRHkV zGLGrN{}H;Af30L8EQcs??<8alVZ+y}F-_NDL&@!P#8AiqBXU7?e(Q$HPag##T_**c zOj~)5(&-KM=L4h?QbDJym*S7N;NcMfzT-gRZkQ<235BHHDfv4?D?4~0%TJZMbAf1g z#PCj2(5wNc{_}@jKriv|N9~ctV=+#`YTmH&&k02NalwTQNcC|R!q@n)Kl*5Tw-E*{2;m5B8x&VIuMn0B9cME;;a>uSP#*v5Q+JQ7D(Nh;ReiV+%-UjX1Ezs zIU(itwTQ~Kl}{!NqD`Vdawa2){Hry2_o`bcoyBP!_5(62xvFNML9+s<>G1h7v#vs! zaBp&`c#v=?#SuzZIxspbZHTcr4t1j}=3&+Sfi$}j16w%$AW&P-qzC?RQGC|7>bA>P zpc-cXP;a9mwDglKb)s|`3HVN_+#*bI)ATWT6<=%0Z2H>30;+AbEzS9xMUs3u`{qYR z9LBI(LeU8*@Mie9Ke9!@ct!YZ@G@l*|8dJ7rIclYDf+N@SKy!R3kTF9t^L~=evuOX z(x3I<5-Z=driLVsWDek-7xAk;U`EpCSo&^fXfdtGvIj?K@rDdk?II)`a&2mJ1-ik{ zjm&SyWOk^gG<5B^sy*z40*U~c$~)H>+;87Jdxh|+4QWMVgE{*vQoVsCkXN+|hEO(u zE4Gh#X1fW2W8hpU*x7|hr>P^f@?n;31kRmshFHA1VNX`uG<<6>Y^^m?m~>(NMd&m! z3*gd(4)IbqOzUruH&*O9V^=XS$EcW1TJb znv{F7Y{88ZAn-_^`-$*cP^5Pf7wOmtT%fz*-NZl9vtXr~blyBSO}!MB?Uaodz-Lc2 zOM1O7&ighK;G2?w+?Syr0^bJ#6t_*Bohl4+D`oUFXc7(*teze&)Pfj0{4Jmt!v?ZTdp$!prM%cyK+vUr;^F|@U{)} zyN6o=81&Yev6wCUbwfe^@r|CqW5#7ic(y0)5R7;B$VqhaDJ`L>%Ze!#s`Im$~)%c(u*K(I~fav_4| z&Lyvts#!>Gzf9bxO1U?Wh^qdGEPyGtWA^D$>f#41MUu zEn3G`IZg=c$J8xM9!`I7m+%|PF4Rkidi3=ui5)2RW&S*BCMv#TIu^XX^+=n-Yge8s zt1AU>vRtz;1@){zNc=P2Eu4@^ zwaT$md|Tj>xs-qZ3mM_7uW$uAn!x#OkHuIKAxY@3MWAx*;{unGUJ_lDECk`etf?Ii?UonEe zFL%gxZno}UZzRP3$p!XbY3TpMlVW3UXk`B{A6UXvk97v^SAH6kcbI~*EK`x4ah_#7 zic(_Pv1lsy?;*_^CI3>d(15ZI4=^zo$wJHL>u1MusA#>6{L`;ip2{24nrVzgvL6fHgO~OE!Sifq5U0>`IT^|}cZYHN= zAS{{sj(|+~v5RtjvAdJ5-q#GgT+3$IW#mKT(skMhW6UZLs_+F2QGSk1F(`}*C8e`Q zAjE$uU%j&2fwD5@llp!xWGtmI z{_y}9pV%0%(4PD5;P7~1@o@5jbeqPU0%+Sb)b9VEuh{%=U+2bhYN!=}DN5zpHAaPOdQ>ox zW%_4l+F=CUaq_B{%~m)LEW_a*+t48=115~B=6Q78vL))RmQTNRlOLdR`7Wm^vEtRT zZH*3RNis}*7(Dj=t9inEIaM9yjdAa|--!(aMMafE$J3<`_rbINQUj6-Bp7K!U zv~s&&cpaLg74m?qe4S!V2YUi0g?Leu-}|1;_3pcS&y7CGOA|om$*T@g@~T4Gvi+&0 zx`^0NjX7w$><>NQ&x{=^E&wQ~_c zUKuI )NOd8+AFU?df(QGH~WKyLSPclo@Q<(%eWrRh6JlajfP4&3+X=xDFhTj*HS zvbc9~>+kf3FEmh^&0R|PE;>(9>A2ze z`~EG49y}1Z@2_*j?SQ$$p3*=lS_^d9wLT7-PbRMb)sYdS@3A2YIGyhN%REK+49t`31tH!WDU}7f7 z{o@S- zPQbIq)J!so7ZXH*)>4W;1zeRzch_w&z&k1j2X-w4nKcyAsDZIc(s}CPc4fOm;>4=i zWOiXrpS^Qp%j<^J6e<-Yf|s&_goy2-)u5S*`rA5K*td{DGYt^9>f>S6?RBsh&{E@R z++Q(Q+y(ChY6Ug$q(eCa-H050AD|HY*_1zLvJm1R;;=$SC5t(Uprh4e(x4XE3V17n z8AGPUA_Bh&!%^8R>!;{$1-qa_fcTS-Y0OjCP1F`$&^q;WUUoitrV*%IPn?H+H5*rK zE^lxDaz^P-2sW2<1aD+B=tcYTOmWxhEq{=A9y_C5dvY0-KNaoKo&!9JY^>tl$Ed3( zv4r76C0X3-QKD~8SJtQzojw7sj>}#=4yx)UtJN(?WfxU%Kh7R-in#7^l+ifO^Qf7l z;PN--2a3+@gEu%NJ($ayj8NGWwYAJBy3LRf%Xucf7b8omww4U`7~7)@m@P_C?EC0^EY|3+|vM0ftx2K zV0!Q#U7}ugmaaeJ8fh$o13vwXHLK6z&;fgSx2EK#QJRi{9CV=DS&hNr#?Ex0*55;! z9cOg2PE+*H11pxqy^%KsT&HX_mTJg)Js@mKav(1WI)bl)@DaY|(=ha5K2bi}C+<=b z#BDmY(bMVWz{PT^x;ll-_W8HNev^{COjFLf-bmA35Bc;|dv_`7t*kc(=pH!Jk1(Z`wFf-?ykkB03%N@y>t-8QMOK zN|(O|TC^W3BJ2hoqBz>0A`AAWVh$sP(&UU8*|AR{9O1*8 zQJAZdH3{Gq#j?jGotp=!shyAAIf4}@mc$bs4oMc5&$gjX&*ukMtEeSFwbzNrS6bZi zIga>s1G;9YB+nZ>$HFn708qD#*nZzx*xV}1?@c+HrwsOKRFw{WFVOai8}%wsFFgg# z%^2z79-bx_vg({2GFLH&lP?sS0V+jvkc5Z4Pscjpp41qLFSUBWjLs26=$m}T$jxSH zkEMV`yNl?WD*}3b%=*4l5sx)79bo-hZ(*=qr7QkZULV8A-&u&oFEohr>@eAkpUpi32$3y38it%6!A zEan7;Pd(-2uk-8 zexc)kd43BV=!Ci%>wkvr=S>gtv7B&U!D#Aq~J=^|-=3rm;&^1jN zKIS)ppBR>;_cGNKJEbkeG>u^PL?}I;t5SR+IuUYQgC?vF?DH8wg-GlXO5LabWAmNQ z3|v9c)DTL#kAEDoz@J}(A|B^hZ6u=?Y$gt>Aw3tUnS8oezAcp+SJWs|RvLRq6L_l1=+*O{Ibm_w z(CQRnxnF_#Ny}wqz%7-)o#N8AE~ zEs&HK7=ERuVF{HgCn*(SM8luVD7f0weLZAN-}dEmOuPKZQ3$W|)58S>ziRq< zgsGTX-M@4=@VRvymurK2&qFWP#461`$!J4=K3E?HohTowIFPT`>G+BtqqfFs#znyu z>*}iZ(y3+hLt(xZEok_aDo+|K`_|c3eI>*}^Sha|KhV)Iq|CEVagL$1AbX%J{dr#Q z%v#A_QX70%uUPtUtL=uiXRt{2V6&I#-Ywp_rrw{AG8L9U*%kOzM>A_rrC(Z`eqC1kU5{M6o&holcMnUn_sn4-$Zx39zMP_O%7srVvB}G@;@95*CGoRPU8~Ig zDg7tT{AIkxIrvWI01n8e5NplqV+M-Lu%`3}x97DV;kMC?ZRgJv^ZvG2`)_0?XB(2g zyq2FGmca4}Ur-FRe|y{!vmNMtc;LIua(fwLdPQZ=9rh5=uzp1ZK5?M6W9~KRIXPGR zZ*#g&>Gw+`Vc?^kll25_(qYOmPw9!s@bD@n5Eu6`7H1L$lNR%euAA@of&(UQn;0I=EZP#&<20;>$aMM$XV<*FvaH*OkbARxN2ymy1OAabA`v-+ z(LcQ7=*>Hf+?sR@4sAJCf1Hk1SL+SQRMraAE>ta>&8+!lx)0)>;Y5jO)GAcEed7q; zn{hr<^oMnRuznEM`MEDb@@_+YRl>Rtjav`NZrp<7f!!BB`1YJ35{;yN6@l+I?P~4X zFXeiT2O>(FLT`imh+H%jEsyuGd7kp=JsAM!TFYyL>ehpJ8Sg4F%zVXm*)$a%4fke^ zDl4|>gxA1j>#-8-BDK6Mo>_Jj^9@6O?+Ho4s;)kd_64inI=Y?@eCY=iK;VI%U4d8nikoIhR(J`yH+WXeudyreQg68Lr$ z6L8P({HuYs#}PLlX@%EGwG-po-zmAi7d73wKRd!2%@(-@ddrTknapT(~FN z&|1g&3HZx@RbD!11(=ANq)L`GjuapXieZ5ItEK9HhaLrCMDa>VcosZxD{=YVvn6h3 z>pQBpySD%~$F{kK9aE*LH(J3R@wjJ)9eu=KM<%RMNC z(#bQ_FXG|Q!gfCOaYt){HLn;w%fW1mtzCb^3qTE@o0z2%aDZDrnJ??!$)||0p*uY?4ZxN-{d0! z8SdNF!7h|AxQD;jm*2K_9P?JH{U0B?Kp#~g2{lM{I)T_ zkv9JH8-b#}=J6ZU3Kim0U%efgv66okJOQ5AHfd0njGdp)@xQf?%`q#5LY$2+8x?(B zwQ4u5@9g7_UFj6_0GF>zKANT^65^-7UtRVOopb=~%QMTh+pBgHXr$J>%XuP1`_VTM z)oWo=H0o4afDxZfo{}%N+Io?8qwB7UV@pVg@ zv5Tap+LzC*#KKbw_P?k_CYZ_!XSfH>$smEJnWF@%bgn9F9g$lJPYZX}Qi z4QUMy?#eQ}Z&EM~^pT6{D;7kjLsUe6?$cWLC^Hk`urt2pW>GA8X6RaE+uAw-EBOqa zu0SS0*+5C+8b628@nXy)%RE7rqGOuM_s*exYePA>0eDcMuIfv|@6wf52hs;f+JbCl z^|Ha}YGT@=Qg#$Of_&l&(`8r$D~+STC|;3xTvcX+ZuPps*l@C=zg=>+$nSj&P6Rci-pUt@D4x!w$6!vy_eKVZV6iEoHR5o>d+20I#{8m!Bm5B|R z9D|d3bx0F&c}K9byXUYgPJtL_fGB~j1OaXB#4LMK(hSI;NgNT%9}V^Sho0CC$Sge~ zKT@!+gP1VgQ*v;6MDEaBM!uPj*29iDAW^XX$+kZ=wT9t{+JrvSH#3xzMBz{YMdQG- z$qXu3CkC292qYXKO;#Qq41CBjgqSh`--E!=z-FcZoEtB4XQDujh-yD=9VR?4FIkiY zVhI+

    J5iDt{jl**{(H<^<7N9Kr`4GU*0!XpB*I*<&$cK~_flic!3<~LL2#%J$4 zmfww*hFmJgulbB4hf4nbzlh?HOJ3?DE33ypf-L#5C7g4cKF%}3aiE(Iym)&Uvz}Z% zJ$(Izt7x-3L{3??u;6xP!RhciXPGa$bk;a}s*--7_1n9Bus`Xxs_OmeKV1_{BQC2F#7l)fHoCMG`8-w#`07thB|H^&!bt@~#l4k8GouyCMf zlP{hVKfu=d7iGx0IerdI@Q*r+TpS=(nI9941D*qyp_E9>MA&{OUxCrCb!cs}n5)Pa z?dnW#D;YeWR{RO;ajaHGUs{K%8j`*p#Wu_xL7E`P`yIFn3~>vIhCaey$^*n_OA1oX z6_DB^eYxq!5dk31MUnnGqHiS`GXqe+glWt#r~(wPZf;(eywq_O9er3IE@-GC9m{np z891lGr(E!N5T&$YYy~G9pcrkPdW@nEJxq+}Aud_D!?N#BGp2K3CoX{_3-51Svbzy6 zKNr8LsnzMjBYL4llj;U4Qiwd(WN3l~NHwTEed9cdfe=f8N_JejsDSSZFeDstV&@tA zqp0Ux>zziyJxmfE$_=hG!LCx}8`Fnw|t(^Usl&uvE%C{rsu!8-sGXj$WHh z%V)#FFL!L1$L!`+!Ky7VzbBgNPs1fDQayA`ri2@e=m{RIZ`o*&}sn zh)}Qns^Zmzzsvok>L_CZ9qUdAfX28q^t5pLsUr$_JL4zk=vk7&G=ZJXR^rEn)B6zC z>LVNfyl(z{x%`Y^e{(`kFZ5yi4JYjILQCS{;ii!NL0_dUvTFAlEm~Y=X9^NFVCks#3I-C(5z5WzRx6 zcz*BR2(EOf(ifM2W6uO}W~!R&*gW5i-|zNStL>VV?gEXWPll^p-)qhX_1oL<8{jBc ztQMsX^E=IXWpuTf`dT;#V_*>Z+nG?%ESp{U%GXd2M>C7;PQk{L&JH|Jl;sLiovWev zCk1E_!ZcZ-z^M$?z0P^5!*IMH8{I%c4WMFa21b>ug(3d5VzUgK%_$od9PiC=VLd5{ z+)W=_e%m$}=vrKW&i8thBi$u&p=+hwC<9tVZChJ~0wB1lAN1~Mjo6Jm+{16&lC!@7 zkx75Fjbgbvq1!-JPIt{$DiNPSV|2Gn5j>aEi`+7)P&f1lO=(;|ElAB|&Q0`USFSpkq*R3KKCwvevsu=*dYeN&Ka?UwA`W!tvx+GX3e zZM$lhZQHhO+qP}{R>$AxM!)ol+a339&WIIjJ$!SGnIlJzOc<$!w~$D#yE|+8`o)?( zc~YS|`Bn;cXU$GnwT;dtH1ThXND9UU5buxIi@|Cnu^^SteN(oAM$MV*Q)0P_ZSx!h zCLk}RkislHim(&8735EiM$$e$k~rP7aEgF3;w9`;3m{^JzI;Um4Q6VMOURNkdL`0{ z#(X;f6rS%Vq^F%|p1$U5>0MXQ)|b&z*{<<;JR(Xo_@L}Xt;F>Z4vL1{NSy=qSKZ_k z+H`9~DBTBW(KXj=%ou;)>tOE~++B`77OMj}DooS68{Fa;&lvw%k(Vcp6ND@`d%%eu z_qe}t-FdO`$eQy!bK`AVp-uK{)fEy7e7a(r)cA@ht_qhfmGV8+^a1>Qsg|WzZ+%zE z3*co0zZKS$Nx^PBr@1T0GAn(W6U>c_fk4fFO?r|A_Ph4=GZbI7&B@2iPrEe!v5mcN*f194>it)E|kcTF(&KR0>K+ z@6=-S72WYs*V9(xIHn6G$qiqR+^(B$k*Kp<)v5FB-*!C7-0uBO=84LiY8TPY-`ghQ zLi%1-TlW{sB{e=|>hfgDFNq5cMl6h+?TEfGU+hXIxr}?B!LQ~%j)6VEZpXgUUb=N_ z-LM6dU<1a4_&q*c_G_GbrKaj-c>5cq_~!SnndxXVHmyBVwL0+W0x&J^9)x`|VrhZKpoLPLJ`!tp z#@VGjLn-tATecQWDfu|K=5Vz)rO*~LSK15OoB0AC31gG()(fYahtgzm?e~vk@IO>x z#nCUVp`SZN&VNT0{*Qw0{|i;9V{P+K&Wh($ZPh#-($FnB&*1QqU~VZ5qUCdwQXnr` z9-R=np7p1}Kc(?XkouOvvr(eu}q_`2{62aBo z$@<{xu6H@(h&|tIIeoga=v!i+_!k<%ua%q)qL*(k+xulUtWy}`!TBZSeUgKC+oI(| z@I4|=B5W|3dS4e8x&8}&=a157m8_VlOdFa!YLNm8cD?1;X#PPkqnI{LVRloAbAdKP{Pae$O z=@g%lKMasC_xWlEak15`LLZ;2UjFY9{eD9BW&4>O9{yXg{Qvrh{>e!pah5(*{3xMS3K9io~9T$#Tlo}Q0KP^}w_4#Hox01)Z$ z5mIiXrWPPM5nu%T<76_SjNz-~95n|qRUvy9G7!k5tdil~ufEc%K#xe75Ti0z&B2yB zvGaIy-W+3HAy8wOMm?Js)FA80=fXGcXoX=_NL-;RH)~`XS)|CosGB%Hoj4&_zLryn zS?A!nBL|R-)KMiKo(ehVVg1)EfIVJqm$n(jinGcqwX{~zl#P-;hdNj(#i1mi!A578 z8whZ?8EFL@7=%{m4^$q!x=vi zn(zhffh@IpcLPn2>Oj0duzf7m_)ydKrOJ7p*VWF;`&R3K=x8a)m=mpH`CPDIJfQp# zPhkT}7UoOQ*fuSLsNY9T34$AbiKg zD{OZJohNM9h_#2T#l>wf^KQ4A62=uy+o?AeoQ=RF5wurK^Le zG~XiGQjJFmNc$97o*QjI-FTELds*zFNy?woc-P72;m8VV`E$O0`Qg#n5rNpLYZOi1 zm=2Jbqis|j%2Eb{F}qfGAREj=4(Z_qd@QxXV(joswy@5sC5MT93!?(o(kqGsEl%Df z)Lx64>?Q*l1Tp*1Wp9j!Rq{0<80IqV$UTW!=Cy*omMCU?onmR-5>?P+n_ikOgr;XJ=PCBs-Q4Twn9DODzXb^W*&UHV{~!D?pbjsY*+iK1+mO z*0Ly%E7VC~ex*nXn+Cp2RT^tS>coQmm|Aax2StxkYc8qnd2@z}3r-0L`cxP|#{`G* zO>tR`QZrQJOH&E0!>*^cY1DKC^YC@k*9q`f~{mlVI zZU$sN*@;|M?2c<4GfL4c&*oY{<}k;k1bQs0c3(626i^zcB(7s zMKqbf++nmQpg^_6K@Z~hl(wX1(d(o3Xu*z?9HziLm6xnR3DK7vL30W+rYb`{oIMD| zG(PeYmK@bou{H#v3{8^fbf1!&&Vsn7<{Cmwwqxw_9|DPWnf{$8x>D+0=B;VY{- zvTy_2#%~k&d2*XW@AUQxDmmlplhpuXrsSQhA4clKQD!f!BM7PM6pPe9*zODs2!DKx zzxM%(xv=OV4XpA#N2QL65Dq-J(%0LH`6Q99G%?VqBVC};Fo8(y-F&USRKo_YMx6?G zXgdI>SNYib>MNKRUFIZr0&Z-b-c3o^3!%e-ECfqlJZEqP*pp zumVnPygDlH2nTcU&}!KKHnaPjL@>_d13g*2V&_FY9J&4l&{}`Q@sI!hYuxQK>oqrL ziPr9IgPj3rqBQ7f1I#kZP<&?BzK+U4dx*ND2dLYduXfvx;@b%G^;8qcR`X!K7wM+E zkbM{56u{ zo{>lO+dFsl*`~~|8X=C3&>k=D)=mFBSfb+TgpaILcH3X;Q zE4ZpMqp&x%IG;~X_nK6q(f#yyB3SM5Y3mwQ8ti$EB=Nikk`3;u^cJrYh3w{(McKE6 zr|Sr`Je8Aq)B;E@07F4lv`95wwN!*o&dHZUIgi^&t1k)*^LdxIS~aIkH{=Q7vRFIc)W^A>X*6=gIpL$ea{ zRO2pA9l~LJ!!c|RAsPdb&0}qFA`oCKkMK7)#aLxsM(f-1KEiq+@_7l2z0YnZUdki> zYCw=jAb(Ki5l`~qIV%puSa%eu-;SP86~&92EEFQ6m2>WGrWP_dDyssTQ@ha4T9m(H zMl#HmI_o-qk`=hS-vBxl4|n`w_rmO#@M*6Ce4W*0BT2HRkS+*=U`1&W zG~2{t%;H@!^0|Tdg75t`r5U*06c0mO5??HpiS`E~KaGyt62+q}(8TA+4pRe>BlYb& zwR~B}nxl6(o&E%^$bjw{8rQKVlWj#apHoofOR#dyW`J5U1AkNitN>4iUA zve{78X0&F!NhW)vY*p(r<$|C+c|UfLRu7Fk$<8)KAIlIeIBf^t`xf2aV|CDEKygy|#J0{iu= z9R1&6-ydN7|87F|U$O5$z{VioH%oG4jW1Ih-&Bqbm_+3WyS{PZ8*JCWW*vjUs`=mg??4_MSuNR$Pp44c>E{ z3uu`Pyb-+3Z{db|_wCHGbu780Fpu8AY%OJ;K~!nCTdHOOZRjgmy+jrshV%2Lac{DP zD@1OA50XBhSkG5mgJw7iF)C~fbHS6L)rxD`imsj7ucVI6&I3ZNGZ4OZJRo)z(8L_5 zE?DbAn_RQ-`VZ?)eg8qH-!Y9tdyD#7qn%MNiIR9u$S!e!B9ny>NoePk(jErEY6x;~ zuJ#CpLJ7pU6~aMs%~W0ll;_w@8@oohm=(#u2Ag4A7I!!ncR|R@f|%I(@9`c(4_reJ zxE|V={iaA(!=iV}nhhxJUq4&Q|1@0dG&TK@KPo_vpN+i#UJ3ZWe(3(w_3lD>R(k)( z^)9M=kBPPsb)QI^x7=DGv~Z@Xp%82(nLu6Y;@ox2a3~WUQ9c3GJ5)JQcKZdXs~|0u zm1t%z$g8Y@R_vnnc;nn7%Er3bA6rR^2{#GFjCHfePV7Zkuf3^oj-NI#po;4d{7S)B8ez-;(J^v<$^(f$#igQ;i2H0hlrrx_k) zP6qsqGo(A>*A1FP~osC@NpfFOK$KVhzIr%_wsb|BnWnJeoI zD2-#ilIuSy@Hn%#q{^oV-mBY*TMrd^GwEy=?2f)-7?3LDFQFfr;HBVLuJEPRo&6*g zY2n9p>)Z64L%^6ue2OpoE-M?a^~>{q$TI|iI^A5%ZtmXHCZtp&yse1U_lwhDmF&Tg zt}^uFD%>6BY5Cl6<({^4@Nn?p@>u=Ud>Wpd-CUg9T)h6tl}i8nbCPhjUM`QpfS8AG zj3mkEn(p?jvk@E^vD8}38##*V_r58*6^U3RV9!|?^u%rixE$Gx9lS|~))?*H%2oKu z4w#-NufuQWTh-q(#a@pyri}&RW9{c#2#h<9dj2m-sduWE_0cQ1C}dg9T%35SUM{L6 zu0uyPk~hyD{hY>umA#$3eXHf~7yvr@<>%fNm2QRNE;j?;`L-}r$B9Pt#*}%OeOJOr z`IZkKl>e#_pkQwFEkD%(_5Yu%!9TAhQ!71#|8xVpP?2!hXo2TO?9R(CD;NpscN09X zL!MS1tutsRu~WpTw3jtgLaQ?gK>*eLWh>mk8T?Urkh1=j@DZm7c+l}+Ps4s0D8%_D zz{Bmx+NQ;(WK=mw)l7E+9koLs@=~%>P}e#~;v1j$tJ#t_pRcorN^g_q!w_x($&v;N zP3aT~UkTlhj!pq`0f8}Pp=WpV#cOz_jW>=$Fl-KQB|}5BH2}O%QHcQ%zxN2t=gaeL zcl-rVQs_U7!DMV+p?=R#*bWVJD6a93`1y-j&0^K;;4M0tDXEBttKa2uAQztEK4z(% z9XVv-)P%$eKYV|EY>LQdNT6l+o@-a%7r6i&w}|GzW`Eh+y9;oPSjN3rnpMXMK?hJV zPV`XJ6)=3c1R*dtgW*bVN6YY1q~?j~QW=KfQBeuW^$f5JiW;;w_-Rc1y8a_ijU<@} za$p7{JVDf)ID{6!d{aA^sm##GFBW~EXts-ThQgSG$Y)j~5lawY4Vs(f1j5r1rbliG zQ>cu{4Ify;4E1#%?el$Ct@DN6D4dlW1j$Vf2ja+bu<^?Us%Ij#614*l0Lq)&9U9|X zJGYhugobg4?$||Ndve_kfN78N?emkB4&S1$cluLhXAiBvoDeP4MXt|MYmbC%=!~M# zb{Zg5A}oNBt78zOs!EK>Z+reIU`FztA6Ae&K^f6bPrl^gsQ`{KbT!_b zwy_3r;5{m(AT2i8Rzkz zoC**?I6CuFa)wS$Jr`c~jW(;QT(Ix+1|+_2?OZot1w+YYVqIT|AnZm@3GBpvcfA2g zb%}A?#p?vKv$hu70A=f=f+;Q4%D_rx7|=yi&faX$A7=q?UImGoNeqMU~S_fi=5h5^%nV!@K99_S^^7}*~?x6}FIKU}$YR?5T?T?GRZBBb4G zKrL${=+wq`Jj8ug$`G!a@FmUEjnj{^CyiJE+R2=kW9LK)_)suP7jy3Q^3^FXui`}M zw*=U1cZ_X!$ti1vK-H&5XyDZ1xqw`|8wuWzZa37R8IK+=ndWQSG%|168d(g*lIZ)Y zK}ZDpNz;poQbm#Bk+V)0CK{krubiREF1Cj1 z@$09Jqx;h#&=CmO)Ma>@)Xa$;#=KUd{DJ+S)Petp5X zc&NM9P_=IKaA7Qe^|z1&xJH3ky&u%=WFz8~^&Z*^} z`l1Mb3zylBF+V`jF^BM?9Q1P4#H=~DJkt%xXtY`kv`BVPLRMREdR_Xf>0$5g2C`%k zcfnL7zuKuC-;<$B!c^2$f~ez(gHfm8(nLAONNh?v+RR*Rm%8D%861+GYi61!6=?}x zuOz(Jw2D^FV<&a==Z=FQdc7~U!y?%6dH{)O%1lq>p}7X-Er0zc9sdDKPUGleA@1=g zYRC-C(AWNx5(U7}CLr>Vi3-s!P_Pymev$i%dusw18qgfOvwXD`Kf9x9nnV z`CX}V^MPONd-pYtrs(RdbWHeWziaCtE>0pg2=vO=3F=Y-T-Ks6dL3lT<=Qowz_{r0 z3O1vB1O8p*LS)6F2sf+YJK<(0rLm-mS1k6DKG}KW=5h!HU_%_8H9yAwx0F^791WR) zPF;_YuT<7k|K-7~AuMaR22=+?uz;wN+I*@Clbt8Ff3oIl(QbI%q=hn5^zP&O#DTe4 z4h5gsH{1nMOOM}*V6_I~`{x((MUSG{pr+^GqXnDNeQVqfqdPRZv|M{q0tz#5k=X?C z)+%!)mhxCQL68y6+(tJ7F^w!D0YaN#RXB#L9GheO2Q62O4=;k7OWB@7rQE=i{w*Go z2BL>njK%j7eq5ewo+cAHk3?D(GZvTk)IPkAEEx>!YS`zG`uHC}+*x|L8~h_y#)toR zfcSr8eQ9LKz|2g~{;%bj2xW;MW*d%MqFa9{m|vZ(?ogyo4KJ7|T?cJ^OkDr{E)X2cyS2l;&vi=f9bQ!=@wK8UXi=!KKk0{MkT zLZ(8C!dRzQVhYH-sz^g0&^1?HQXzk}k#7;DYb3o(l$%$8ub23=*axy{rl^cPon!Od zcqQB=>)4@L-Cr(4E|tf%wUy2@4MHS!>~ECjCLqnooCKT@m$d~{OZtH|ebiL42BJ~5 z2|?A(_3Ra9CltG!YurNO^Gn34me_s7ic1x{8X-id=$ef<0W993Ns1@H`GIZ+vLuRK z{RM7cFUpXKc!T(;8v-LAHc! zinAI;SyeW?*F%kCl$fGouRoah*9AvXhMK+cXezPEe_j|3P|?~wxL=kEH$1~vUhd|M zcj)37D);`OP-a1oKH%&SD@C2tGg{&WHOcITc`lP^M{1nQecMt@8OHT6AUl}{VTQgVDU^_PIf|-Z>P2z zobxB%Aa#x#stLxM4LGngADo}x=~t2ESHbO3Mvm2k8qcd=w|F_QA3G+jKFxX3uA^of zbITfB%R9p3jT3h@ZnXJT+t`vyKP?2+<&^PU+JayeSV<#Kb7hA*YG9NPvcJh zld<~Wx9b11-OB&0O#fM-epV?C)UAG^KoP#EzQRiXj)zuCs@r1~&>;2H#*?&U8K_FX z_nKfSAB1Rz9MrW-teeMtd#7l1jnxsoX9!$Z=}=scPt@N}tkdkj+Y;Or9>`Vbb?|tD zC)4*$14Kb$LzZ%~Nh8qBLl99Uu%fv~UH6*=;vMA}RPl!LgMj&h!MFH{ZsbhR1*{^V zb!28;k#|bQI1_XBNaCNQn1QK+Fb1@e)xo)f{1JXR+#hYPKjlcd2jUtYRjbj32MF5l z@1Kp1>YvvXg$68M&ZcHA>zY3YwNJI!y_d|NP~Dq$s}iPtW|e%+%@9gIqVF(bP!v8b za-uK}&Zn>BB@bk>O-S+`v3`p>pNTCFfwRagC)~~^Cb*No1(iWK0!M#smNX{&y!|pg zh!*~O5$WbU-2zA+3vP`uM2SNTVM0YWR#$5$oI%i4GyM`Bgq|iCNwq|&Awq~dXM4mV zg-c~{RtVWm`1aNPPVebmIXxVt+U?!8H8UCG8?{LpGIs=cT*A$%?>!~QF_J_@DF3Y1 z{=;RFp`MKHh%G|v5OA-~LPj0V+m8wf{i}+CYgw@Nx5#_-pFiX5Ml!QU6g^d+i^wV>EC`6f`?>JA6h@B~yjX{s~- zPC8Br^bgE@I>A#BS?;eyO*blU05G0MSDNpX&p8*vpube)y-c~vJ2 zRcA0Q)WEfIDw60CSR1?8)B33Zt{KPj8*sPM(RWEMzEoHZpX1D3(%^YBDD*hpU49|> z(6$H~DZEni!x_}vWN6cxpu>WY6`ns}V8)K&mzG&M1T{l1Js#q`*CkDs=ehl?*$39kirS^T(yfi+xU*OzQa4Prt-3LuO+x)S;t&&WjgvKX&qX0 z4K*{X=rD_gQD*c|pw(Qqb2nFA9UQwUDv=_2i#&fJ(leW?H-*!|#*V1QWNd;mmRW;S zbAnGgB9tv*UbHqkLzzIAp}Wwi$BN(T4Sy$p99LqZU5A#0ZEoLm-Qdm2j+ zH!+h+-!oMnPysby7+dRUDB3!De~p@D8?id{zyn$iz==#~+*jMHPErBZYmU0c3A=Q! zqb67mGK?&E$gnx;@r3#IjDXz^fAJai^}?MB82a;-DmW4lG$Yt3SZGS>RNmBC|Cq{& zrJumYgkX$T!;fzZoklI&i-~sqU1;vWEHkMUz_%Hs9GDzF!H7`AIVLJcCM(xQQAmG= zP{EQ!ZL>P3fyxi9z#`i;FpDTpK0XEn(P6oH&$;W%{;Qw_Dadx*$r5_eH7n6q4Ua!d zsQ-;+rq0M|FX6Q3id87UXk1bB;i|peX(iIA-5RUZ!(z~gxr>BZQGqfwHG;2F(bh(h+mQGsDTy_>K0aXiN;K#>#!}KEEAeLi zqNlsG5ZJAlIl`H-22t)ik~F*=Io%+#Pq0V}60l)v*i>}OI1QG`_F)gKmq}Jcl8WBp zYQ6`3yVCIZ4(;+7`CJxv2fA&Hdgq==sATH$p+CGgrZuXz&K44u+`l_B2ZlaFHVj`} zr8O2yhkrg#Gn%ZRH{n|E3~#MWZHssw(<$cUFI?t2ZN8c;FDH!|daByQDYC6hf1JXc zMBiFlPW6@ed_Rtu4wSUQ?55aL(}~E~8YIk$Alg($mC<*pjoloyzNmsYt<#v+X0lP8 z)IAT|!m)mdB9?F=YHxG|fE;&Z6yC#?aWMI2bl}_!2`D*qtK)>3EG|NQnlu5c^KL6) z40O9i=U?xkgoGJ#q|Rv4f!7e5s3?t}ttNZ@_;Tu$HVqSTQm~8?OCl@WT<~beOnY;_ zM>=hHF~-JH67K{xF{rnimbrX#kC>r&gH75Z<@Iq?Xss;rYWKDWos6a~iq@slo@Y^; zlZ1SwR(+Rg7MmU#P!zM#Wuapx&4jh(EHlWzuSRjEmzvkJst=JX zb9HoF&swK7WkYt4DC2R}tHKBUVG5Z=m4DYaKt2$h|QK?EdOE=Rw7eOk|Gwv5(Req*( z|DZJuk?we*AEfp`^6${v|7@^g=%QzD=ktY>}XyE%>paR&?5{Hu8LeW}R>7yen9|vOUQHMV)TMma6_ zp;B?X0e1zo+{uEVA7pV%$4>wt1OZyNN-%xPg;3zff(2g)OPq@&u@j;WgT$$J0gC47 z-KHjljYXWaALmJAYJgODyMjn@+6nAoD)91Vh?8#)<9_+s;9DpxYROmW~o(C zUB&YH;^5?Mw}y<`UzKv>DhxXX z9?G2i&PL31D%nJ^yk&|DR%=;OXt}kUE+`cMr#JXrek15S)|I}OYCIt9o?I6pK12dC zM(0SuK8Z*HE_P!jtC@#l;+ZK{a<9PMKi+&eENRnHmZJQ8plR`e5HC8p_V8Yjz*4>V zlFVtlz*{D7$wF8Sxq(2W3emlFy13Mdb;_#;E&*ykN9;2!tZT$Vrdy39S;|(&Vr#G2 z8t^$2M3guptmcVjk(i-!(Q;0-fAEE!83&M=&_Nsy7&x-0Q=U<9BnWT%WisCyDN`7q zV|)!(xw6%nd3?d=c=doA6t(>7p-lqUVLE34?ZJGp4QWsMv#3eN2q;%%^7OlINO^6F z?0U5p#uaMLzTm=h_VWmy+WUvo_~*&g>o`ZG`x*KD{^=$D`#wVGe>7+QuTQ4Yf4TXO z7b4=7wp3Z(NkSh>=`hqxW^|{8TQ!yl&liyxJ zUJ;!9I7ZoqcE+xa1uLsfY7Jn9u?|@t#tKq)BUk1nL>yv8^=s}|5Yi_vO`Fl=+3S-l7aHP9j zu)3rT%X*zax_k5Ks1d0}G)*Oe!$l;rN=AEKk*erCzemt7fKKMHsM&|$`3%y=6uIm< zgAcr@TW4~{fs}UG9#G>Hzdj!eT)BQ1&QmSi^rCCN*q-)p1Ut|L_$AX<$(bG-pqjOX z)`D-*Nzvo`LstIf)7KWW$gkRgGd7DlfbZiZwLuGFW$>!zy=9J8!${5{u1M96MERg# zLs2MT6%KXIG#m4bYGzKA@V4SeDVroCl1i zvZ~UX6u+}6q5~k`LqIE)uLr9zs;H~f6DDNSyPhR8{}r$RH|EqQ-xLC`iKDA)wq@Jt zw+dxwPF}4Ba9#W0sXGSOcOG#}C7fINTM64f(#k4E*t2yYp~t%tN&fdB3M#e1uq;ty zC2fn}pS-;~kr>Dx{`?R+KiM&+JwG$WohG?GbbVGzNqC5q-a*qV0dU5a0$Rf^zpN<{ z2T{7f#HCPo77V>O`&_`OKBkz{MbkexJlNRM#lDPWo@8Dvk9^l5JykR}&L7sPp)-$I z!C!u(i3YvQCiLBdBb5`#K)nY0c+r~m3FIF~0szy-F${KrjY>Rh{=aqj5s(gGnn`j1Wx1 zBD#+HJn`pc^07hm$B9v0d15P(B&m^6!pDq_R9J(DSsuAk3@Eg!y-DWWY~fd$A3hme ziD$esmvs~t)F|+(Rd2uokJ<`$=B0=jpf#yRMU8e2sH}QCU!aZgZiX7Up{8WN70nf| z)?LEo_d!kQZuLHpzcYHh;68nDt&q6})Az-T+L~gu6Y2qM&Jg~ll|h{8<@apvU&~ZFV2I)DWZK!iECk!#Zo0s}5e0bo zc9HX+e-EX=Li}Cgh-_U`J&AYcrDI}}WO_iDFY@4FFGtWtSTOcUPgO!*i7Run<&I2q zydtsguhGy`PwH&Drz>h_ixj@mB=;tk6o8!wXJkrJis^@9=svq!dUKnBP)T&FQ(59{ zO!AUEiLQtCrY-Mjo{;=tIe5?7$i9+OZ7wB9j(P9tn`s!Kyz|PW=t|^V(1c)vBI$Kh zkWZ(?S+Oh?24(yOU(kC1VOV59bMdRb>KFpUoL?9(A;(cWIvYRSKoYt%;YaGZ#rT^t ziHPj%)gq7zJma^~J%L8w`e!M8ZlhEUT^%&)Y8|e9;>lBrE$;G&78gsK-4%P%=4I`O zSB|z%F);KA5gQ77(HizqZzbqc_v{E>FBA!#Un?V-Up&m6Li{6-C+;WMP_lq2>woR1qo ztVTX6#(7DxdEzbv)y3hgGVMeVCCl{?3xJNB^wKZ|r&SEc-&nM{e?{~1PUFa!?=k5( z2A)W*=LtWObg*~*hMi+jbe}-n@$3T>rdx?bN&1kXCFOoqla*PwtO?Up7oRJXmSdOt z>gk1mOP$(5@rQM?)S7Q5$W050Uh*ly7$tQ~MwVxq9rZF>Yf_l;1s3^~TVOWwty(muvmO(3>>Y zhw_8xLc{olIGrQzTLuB>&a?|?szhKjBOI%r5QyemKEtbo^sC3qlXMFMRggh3%dQqU z%i2igqEUdyj!^>v7#v&PE(n-apKRf`9K*sEUbrr`813f7dpX$T8-hMu-7G;8)1Az) zNBr&9i*B?;Kf)&;{00NB6 zUR065p(Of8KbM4Y+CS~XSbCI*=F0{l7yz; zX@%`)R!)r1qkp7Ox0lY=Xs!fcT*gG2tH%q7UYe)3USmKPf6X`Xcq~-KvloRy+%#F; zB`a1{(NZnsvXX-xIqBjsD(h*(JL`#q4kIFR`3wk%k;W<`;BRXP zq?)(Nk^I2U%sJZy4s8YK!1j5fmRY>cT!es?TGrvEvVn70sAv75@SxmUwk zP3*7r&{nm?EjS-snVc?vrOEUS$?gJX+>AtX*N(al=)QbG+USn_eN`r>(+mxsODYaq z))isV`-YHu{PZHN-(oXkAU7}>Cz_vHw$M-yUpXtcK!Xg<>3iX3((P`Z)cst zHHo@QxYt{wZnAd;>@0J?EqjzYXB0H4Z^-KUe3?5VD}{e* z=kZ*+g+#`l(cl)FR31#<=$&{|9fgPwvM8i=Zs!Y?#s;0w0id2B0|DzPwq!w z?#rD8p$#$SA>S0c{Yq%5a%PgFV^oZhbdF!$aUW0vxBQd{Nberx2 z*7H@Vi0@L&=0BDS!grTi(X6bJUNi5WpPXS?>BkIYBp)s zFN@ywQ!ANXI?0|sQo)}2SRV#hO_QuTWA)Wy^|N5!Nvi}+sJH8$mQl6MNtSF6ei?3N zW5uwjhNTitox20!;ZxlFwcc*4Zgy&k6<=d@mGaQ$FpXyGTt)1qr3*y z(Dy9Y*KH+5dw`KK92m+tmgs1gkxpD#YvG~JL2D9M*g0kG5eIzr@v#*p*F0&d?HAXR z&7VqqE<2A!AhgwtD69z5e`)cHA8YQrMNQSdxtT!Jw&iWg^vRsO3D*jRuLP8BfZX@| zv)*!^y=FjNTmZRFrLF>D`zK5b+bd}qL0h?2uJsbAhxlOgE9fyiPQ-MP(auUi1!mqS z?|Du7oSL=2)Uhx&y^(nC7 zSH3pz-7Ol*B?3#2}a&5%odUzNI7K%3W% zO5K2u6^mSFs}{#e@5iba?8}P6>fZnEwCai3 zL~a#LU16%VYk80~ccm76s;=anTMvJqu6>dIs}bRJFQY+$`t?hk{NFVq;{RV7k$-td zHmL7fue05KQ*jM0@Isa*8I6}_7JMGVE||4xBM|{PA;TK zcg;fd713Hm5rMb~u{8Ph{B}ef&iHtJr{T7`Ik?%mIDYeh%`QErwCIc?{qDr<>nPws zV+(G>(Hw-|*F8}mH!_>Zx8`MM5bvwP9SFV8Tc(CRdHWrtEwQXFx;X-Q(!kMQ_%byE zJA1fCI2-`#xHc!Hr2_{-$mXZe@d`}N&`0=04?)H%x%w>q*m)mw_qW(B`D(fp@(OCR z8u#QjgL-D?hLh1UTLTVq5Xf@fn`SuWMr*m{lQM{&p?`syM;}fVu78|RH$a*m_fBh> ziT-{t5I8v*C1QB5`xdRh;z=w-MYOfb3>Ech^)Z8vDQoa)Zh`sou5KYNEa|po;ZCYC zVQt7@cHxrW#LWlPO7!}A2Mo*9zqzAZ;`+Kydq0nZr7*~@l-o#MO=PL8A#y5Ev9qI_ zv3;L^`G)4|T5)|E_gh=Vt4dL*xTYe3k)}^g|93jE1y(@)0C&0!8zBvA7I<5hmS)P+ z_7Ohp9vySmXl!b>Wm1KE2eT515-qLNd*kt;4zQNKuo} zgwO=5I)O0?+*vPL2bk#qe&{T;XDz4UUwrx1>#%~?NbMeYPOT4N+WKyT*JdL=OWHx6 z(iahsD`mMR$z8Ci_Wg-hWKVXyXbz8=M=9sq?>R*hUdoNp(@WkbE_m1jNuU=irC6&97Sq)w(-scR4*+Nmoj_1zkx)xCsNeiZ?o?Z!@Ha$4M0%h2j{=TI~1b!FdgkR?>(MZ9_=B#bxpDG_#6-DQL7T{U54VitbT>?&Yw>p~#| zA!=?Cz*8D}@KlF)Q?3NqGoO(`LrA`p64qy%uH$*61*2}j@-TPO@Q^!+@rtc244jam z4ECPt2A?B(<=89&*OO3!YMus~v3#Z=O!SR?a#`)k#MI zEFo(xhpMqdG)0h(&@O`MHw`xpocxPVh?UkjXb3~d7faoBv!fJ_A4_HrklbvB#@`6= z%oT2ds<4FMJonEq2|_@^vLsoKKL8j3N@rp2etR4v^(w0-V%WMVcqQmUFUu7N4*saF z_A-Ve#}VR#ApmOdskq$b&iho~!s!SymTnY%tVF)$Bak1zxLQ(y@%>MrC?cqXZIpR<&aKG^nDYh$fp2dAsn!L7!=B4rTnTs7PNdHTVPVvjmuW2 z7A1fy&VTn|XJMlw1iwiKD{~}nsxrH)m=}-6l8{_AQ@it+KDELJ?aWL$C1-3_1~=ZQ z0vNnp%J}XETyy)iVC5%I%Ryg%eax#gmm%CxFTU)Uh)zL_N|a#$@cG`J&GYs0x*r|o z048i1hM{T>NNCLgYRsOhf9lRLe8Ie17XL{gtT7gZrbO6)Ea}5a2WxKM)fu0$z3nyS z(k`o(rf))mFR)iw7m^2Rh(JA~+-BFF{hdIdCMM2NzRi{>Xnw7v`RpNewKzKV*hzAH zW~31DL^0ZcE$hR|%St*QPLVH-nD9r9{w)t&vXc|0p&l{k%lfaiv7@X}!!}T%v~mPY zTF=7xJ}(Ey@3U)=6Jz0ECE@3^oQ2V_Sv|xQcQ-6k6H?yK&0kz4%114o+lp3&OMLN5 zW2gP*jzLn^i=z~Of~BGs$BRy|l=JJ6|Kn$IS9d&=#Glh^e!fF~E}%%;JjU7CZ($pH zt}((TqsUO%Jn|T>uxYtKIq$gl>W>*gjE zUghF_`pkj^^xTwm%v(F(8(1-{^Gc=nJ5q-AYj_@vnF*=r=O&&OEnB3AngoDrTsqDW9FK`^ILRK5J-H}OI6*ulURH7jX$JI{(xtic)AYBR3s%PlSwRl%5 z6UUC+cQB|Ng(fZh&!g}OUOEB;H3}#0@MT7BLM$zo%2J()=ODAL`rZK>m-ZKpnP!znX8%!;UpfeO*V_m^O8EnDI(o(S}{a=cz`nL<7|(G~nQvu|P&x_usSvCC}P?zrH~c-ye{H zE}H_FQs2+e3BqHl%(`vdGg2l#FG@f4tfdvrjja!9559k<4gWB_RZ-I&yFZ&mIfVZX zSn>U@ft9hDk)KKtw8SLz3s|1ZYW3r7%0 z%NQ8b)TYppyr8@dXBqoi7mv>CI#iGL=sTX#Jkhfqh2n1}KUI=)RUK?qsw7UFeo8f~ zgcMq)7q?$bB*!<_y}Kshw3wYSWl=jua)0ql`EJw7k+X%jT%mjxunwRe_!nfyg%7dp z*$?r|Q^t{1h_m|)0inD*KHtqMS%F2W_zyZN*iV4xW9kt|u#D@-i}A!~AYr;Yyq)fk zoiS=HLWP9hw~OR6D!cB1(o8NaE>9feBP!ov58C4Lup*X@?MV&#yar$XpB(e-BbN(3A~|?^rLaG%tP}XMZR+;`y=4b5Q1i z+LFr&kTcWOv>b&gLB`hSt?*9X3)`hot}5c!*h4(>vkW2`s#(qeOHCH%5Tj|SR@rrW zDPmm}z9|Y&C*|put?Z;pAGH>;k;k3ln=nEP6MegROtjU?Qj4Qz7*#Z1RcNdNuOv5Uodjzx)2pTN%-m14S0*m zoM1;P9I#q^j68B36OV*Z76nqB&yeYa92T&+-#HCBSRwx(*4`;fwkYWqK2@h|+qP}n zwr$(CZQHhO+dSo}Q}$ooeZL<6%hwP0cE-pYxpwZS*g0mziWM<b zmv&){VG^#lR#dq z=4opTkkxy^fv;G9u*LU)#*D!dMFhuRo#shD$8rAKB4H019%0&~N%1VvF;g1FJq4 zoW!$E?4M(NByWcuG5F#7_(kotVUKX9-$XA27LNDNJF#tS9uC)ZI%3|P^jRkB$xSG# z3*Tx&vIFJ!)=o2cu^hIeQ0iFuDJ$3WC+5X^-b9eoHqVjB9z-#tj)0$gMi z4pTR=EH8UxN@SIYB0&b<#LyA}`9#Q%_nhU|6bih%?o=8y6lBe1e9Fa0)~4Ei)2Y9X zT_Z%LWlt7TCfE)IyFQ|$-)R-SFmh;kmQ6S*3gz%89N zZfXzY)S#1h)f|(K~_Qva9=+WA4QrUIHEwgklm!ZJyshRB-Gcf;V1Km{08V~@X z5m+}3!DiC!mDpO-+h40B@ti9$K#TAAaVaytY&a$%1upMZn~Po$RU?41DQQPnD6PWH zn1K*qce>xuOaZGHlD8e3N6eZ9)ZbQa>6w-&A}XJzgGpqkEk-0jDbo4E%3)j9vMPh` zs?i$uiZ#A{e+(gT%)nq%@wwm-27Z60c}Go?hHwA2#%*ZJWRUHs&f~Uy;49Qjn*9v@ z724tOMBLdWsI z4hsDlh&XJrYlkE(a|>ZGCh|f1A0oXAwar?LQ-9-ufaHT>FVQaRvoVQVGvVY&O&K}3 zF)$}~g3m~s*xbOvG+-msX+npKYoguhOFsk!KBQa}mX>v&HFQh7rCi{$W~^2dQR_#u za#0DawlpTpEsl#E7Asu@d?^!59jrf=J#Q&(UWPS+UdBRt&i<(xo>cW+T0L!cXuF}fIS=M|4I(4+k# zSEP6AL%&1i>&@HC`3~QXXtoAci#B>FN-I9Cg<-Zv>^!IhRW)c%#j1fa1q(4!(u)o{ zU@H+D}omBeZKa5`UyeGG>!}a>scy>DEnUh{%yn zbTb;gE&8km=EkM=tYJQw%v#WGoM)Yqf)ZjK<@E$`W^!6!SUy`E0I_w1jY2W3qy!79tx>5lHcyHD$mF@8)dqYiGB7&>E z)=l?cMd{tWZ*T&42fz@wo+rNDV1Twu2I*2BbYaNA(MMJxh1|0*fH{GE zmcytGi4$|joy{q;gmO)W1S$$cm{uo5B^^oNVMSBbT zEk2n=gjUaclcooMn9vbefy*_*og-H)3DH0asx`-AQ@mSH4j8I5D)b^seo4?!QdwR? zTvcPb&Z%2Gc|vmP%x>Wx%o?)~n~{v#JyX7_ zkD~@ec#y^xKNHE8wz<}~Br9IQ!`k==q4lq4J#)u zss7Dj;NizsKO}w;6~o5Pm!)ygCJKuLq_i&$Z8we5_{kTtPB0SnfyaJ3^ixke_FrBVY6UW7VfIX@1jrv8vtS_ zHKGsk%^HH#2@m;kWGH>k`t_nM4!`O!xIK_IlYsDRBdfzKkeR;G$TX!*-NNK-hRV4y zJYCww1d%l}W8KM=rMZ#DlYs3$W!PQ6*l%pJ%!pd`*)?Dt3R_q*fwVyr z09u`2^`-L-b+iDTeJ&AQ$<~Y~GnJx_KTpoczRg$HD`(1DrDTT35SzI_ZE0k(LzE10)0W=RhJn z5d`(#*6$4Q$hNfu_b}{xMFe_E#?Y~y4#TcSjBC(O{d5#;n+mJ12C)&ZZbzB?7jgT% zbXuveMt}9^Rd>fm4EoN-dE!Coh&G-Z-qDE184v)?pL0wU z1%v>>zOLOMevi<`am+aU>WFP1RBN!N8Vq^jJuSljF0={I4}6cacPTWPoBIOMoqsW( zDH#2ArDnFa@de^KKchQ}01UOcBb!%f2XVH~;~X_S5jSIX^O${u;G|i<>`U=US)Y!H z$OS%PKKErX*41%zB4Jk3=oXcOkY=@4Lf-b)6QcTaWlBD5eY2Y71AUFXoh`O8X@nf# z-US6vdSUYA;DBJfp^>TwsvEvoJRzQmyL8@)u5N(y_T_I43dR_zzpdJb6an)jynu28MsJFwoa_@uW?tojl?Y2}^OS5E z_Zbs&4||N!d~-F}812ZyPOQr6fEE4QOt=uzy6^YAjV{yX%Ct?->=^o|P~qMyFv=t7e*Vu1ohK)0jNFnnj)T?uA+u!;apRC&V70 z;?o52mR~?SW-4J72aAP7wl7|}=Z`e&b4gRXxXJO0n%P?zei?IsJHPs&$BrN4(l{&;;POd2R}n>q*5T8I8j zPDp-Ud7_XKKK5TCNwLpfSR`sq87tE10CX_CTOTjn8^W8kc`%ygig|)ba6p`aBZCh@ zty8dGvb5ABN^65ORNy8W5GITzWRiMbjDB4Z{$jp%Iz6Rwc0g6|0J^wxh~^=n6lglP z-j`QTL1}-M3OKA{{=6)BI}-iyxC#XlJR-T6+l$f3O4&$CF=7Aun_9H*0frzYz4(`& zHg$4oxR)KjxwyD>y>IpoYT$2%Tftpf$#MVFvEC`j{;0V18-!C1NQJtRyokIIR#o7g zyrR12=GN`hr1I>mfU`s=}kk4 z3ELGS#6x(-xZE*MnaIU@+aB7+jJtNLIA*8!_`oxr5;wubR=6#dBR8Byt_x+aZlBO= z6Po2vSOX277#~Xqw@97})r`;uz6EVOqjU4$Axc3x5GRt#na3!U=lZ_Pkli0iKJOiT z-Y_ifwmpAS4BAu7ChUVH7Z-G`LiEHBPqq>)y@=5^xYpO_O0TB0WS)B@T*!?~H`ox` zSbE}d9&Ql)V#o^w;L^laP?9 z3;k1w^`Q?Xqz5PZnz1dan+&xpZ|A%6FpdA!D5`VEXYfjKFvp&m_Hcz62)t7OZrtT1 zDE~bX`!TOR30{Tk^uQ z#X{&PAiFjfVi)3oG5FT+(}Nx$*u4>2a8{n6&88XTMZbaf%5aK?Av-^1Fz zZp^>QBg&->2u9x3?QJ>qZ%CDUq1xIdYCA=pL#`B=t*6e=;7o;S>v7GFaS z-ZgYE_5PS5IMfU+0AcQUX6GiOF|G9w$qFF(vMMbjOZyVO zFC}K%6w2YyjM!z28&6K%F1CyUSh3X>jI#rXs-(14AspmcI@L2MbpM#_GQQ)u*@P$D z3K|g%ur2*Gx=lvAV(gWlxMaQ(E^K^bN${{*;PsR?Du;}%DbP*>VMU#DU;5e)_zz=JI)6Sy@oVp!! zjx$G16;~;{P74R!k?yO*JJ|GmL$WV}mWv+4G-{$T=vFz^LJtVT59PH3M-32}|gXaaCeU0^F}C6S~3iAX?x#JBE`<2r>_jnzSH-&kVJtF90eRj+(Ne0vBnj zg>L|=cPB0Q@L@A)s!|pt_yokpqnMIcFF&SS&IXBh425ptQ?`*6ao;$y#IGy|^zu^g z_MDKNcrm%);iR4N>e77Iosov*e|@W{D}zhQ07fo`5C-p0K#)X1$Vh;Y#@1HSDVI~O z6q0w<2d(6KYIGDW}dX7p9m`gNsQIMjVc_lY)<#5D;L~z|UHc zX+S#Aq!yNkO-iCQJ(ay55RipK}(SsoE;^i&QHgC<9m_McWq}hlOK$ zPRmpN;S(Psw>um4oqF7p{|{GbKs{9gDbm&f5Dq+emB4M4(Xx@1^y$X#YDlh#UXR$Z*6g&2B2M!QhE_$_L-fp37kf59lsavsX!PfW^0`A;!P`o9FD|0dDanv|9ip#LSj z@2+Z}?ayB^lJ*BG9uCntfF`f0wKlqV_^a!M;ClPlJlg1~mx4h~i{MjsCE6K1%`C0W z?LnCFK$UW;L%IP9AdDoxiT<^DiGV~G3W2)PDWrsjIwA-90IE~DX$+GZtX!Msc5X5U z(6#byMm^keIYc$VN{}=)#!J|F*l6hMfqS#xqrW14(dEKb$Lo)`C1Y z*WI6R^e@j2ZwP$+Lp7K8KL)7(MznXZ{%5q;nwtHI_Gm!2j`v81)s$=0+#Z$9VR!^e zxOkb_+dzgr$C3?oVK+2i{6(wjyHcA6c#8%455ShIdac{mcbDOu{XHnO8LVrgVYUhR zQ%mWeBTdvg4EVnzVA0hpI0nRJgQDb3EDU08{D-H{o+wg@|5_pk8cqn^we+nA#h?|H z;Na)G9qfPEd2wOW2aQG3TXRl0s|sG)(<>j7jYzF@Z^WYk8h%SA&~b9kLou_nRd#Td zOSv=!U!bRsj(L^jb_ws8^6ooeX;YJAV>=f`-`s@u=W`^yq&h zrLm&Yq(DoCa706;&E>}-Ou9{ z&HgI!bw`6UQ>^!&Za6qcF12p*7!M4f`M7UtDM6&+_SO>R55Ep81PJHlio~zTaOq|T zU8UnJ(-JJr)GMRn#B(rTkkl)deDaT2 zs1*d=63>+bcNV9VJe59@dB}3a;ttRi;tN-btU*^qOECxBaN5yC<2UCPiFz`k3&FI^ z3eTtP$eGLrqs>8^r%fFikCDkyD>u{%ok-nlp{<98dva>YP;A7} z!D!0((A=Fqg9$@I5oS zSZ^_rI+vYcze|M!X-V0f;9;`^`{}s$?!xM4+;H+QdVRIOpWDr%KN_9%zW1oC?*neB zxSJk+J{p`BHIeY2Zmw%K+YC#D0|`AM8qC~;WWiCeapnWQ^Dkrd-Ul41)E?~Oz z<7R^Y2nhd$N{@lDjiK59RCP*|U^J^#L^XLk3@-()D+y}K@k4@(1au~s&ZsU8{1*VLa`63h1~x+AUnIEGKP0$g z;KgT70Ok9Z1EW_Sjht3;62jz$)TpF7@Dkz`dQvRa^*FLQS*aZ!2340$eGyG%m^QML z1!0a{n4@PD{jMmFZuc-5J;Rv7(B`>Cp3?RM1^co5W6z2Y;E{hH7}@`duE#-77T3q& z(`oV@Q2%vm^~;hH5M26}f&q`Dx%}ICp;+2wwS1dv*L!XY39HL#bB3d}H)*_S0tu z~qm2e>^{ZomW~zBi4w;x{P6J7? zsr0TsmAmHeC#CiIE(7qEB}>Tk-t=DXUz?&D5z%s@)tJO=V>`|R!_ew z2WePDnRZ!WaKMa{7NT*74R@n)480x z3}j%YzqyFta>bZ2B=~-g1;d4;%Fa{^R5gps_Np03dG;`O_T=6YyaZ-vDY`sE9R3N@ zd#wSyry8(}0%Rpx-`MOx1En^+p1Jzi*~~jSirddYfoh{8f>Dq;gaKb9lvo!zFd042 z`F379l$ZbqIj~Km#0R<6JDWx6{`EeQyY=?gXjh7E>jZh^Rl385rESGN z%h_$esY5W~T`bU-gx-YOxr@Hzy2 z;(-bBzUl5d(VLg8A34gb0E9I=D>N3xt&4q5J&6=3_Fb#jfDpiorGtq zL9itiPR+Kw!lFZ>uG$31C9d_ua!I9jK3?hQ7smC=jXq3R6}pdYwf*{fn&zD~GrPXZ z#P#_yhvHBgt^9uE4?)_XIPRWzw6pdb$#XB)=xnL?d{8evVey~ME;W8|wdk(*fZ~L9 z1Z{?tYkw?(#`w4-T&s4fZrvblX0C=d3q7~u)~HxoS)K%Oy>GN<^67$Yaw*si1V^h_ zM~v{W;JK-Z8Z)nTPHc}8FSX6-QGdH;#b!tqn?YcgJc3$F?9^naz`=@D5gOuZjrcx1_oo1y82@Ip!@~}et0gfS z#>3j&;1UZOF1lj#XQ_Zz6ciila!M<99H?r;N~$~RiJqK}zSE`n0|cx%x!~}%jbwN`Xm2Mqu*=Z4^>{tujg4f;U9N$aL{Nz# zS*iW)Nm|j%8CuvPeNuyO%BcE0FXaK%O>VM%N^}Ai)ntF1tP26$4_7J`+yp;lBO|*S z*5&nxTnyF0G15(#8#^TjfzHfCV3<5uPVk;OSjy}^S@hUK9$XV0FJi!G|FsPlc>i0e zTgr`tgws)HRx;>o0T6*CUIP%9WZz$KBYCl3>QG&5hq*xrq@LkJyf?WA>P?g6@xq;1 z383=?_Y91*jQ0eLvyAstmOdI#U0jA)Nkp2{&^U!ewx_0Qx}0})Wxz~(m3>tGkQsM z#cWpMkLCAOJ(D&{L=l)h>tD)bVZzNv2=G8>gc4Y|kgv2@M#eED<7Szg&w$hYVF9?& z5Bb4_%KWm7MP#|+O$$1G0o$8B7IWA|EE&R{;`!f)n6(vIxrZd?$vI2p*2u6iE)JaA zLzkarG+VJrJ3)y2AwC=d+4WBk>ceFI7=t#(706VY$I94EGNCe~7SS|;P>C+u7y9fGU_usu+v zK3^!ye7?ZHv6=pExkvYN>DYFVk%p3pK9J3DMi9{os7X!Vg7)XR63Ds!MD6#DSK;=rm}GneE;xa&&)yoAa{gZ znatoE1<6Uo$!7e(zHZ8Fd8E2pqg`_=B4QHmWSSyb+0WT3lfxR4Ax`gB7o0gYN*Rk@ zFbXwkm~cS9=1HrI8hCZY;p7b5 z#Pjxrw#cHRS~8Eub!YCXa)9dRWms$+ruR>4 z`^VxqZ111;&joTA+&}G~i{!Alf7;6~`Hd4#kt4_6!}KDnO*wS5z;KEOe zI_|l)8XAy~c>B0U`U)AA8ucnX=C28X(-fD5cC9TVEp)HgePkQ$Yrrb)X10rxg#zZjqHs_a)%1RwPP!r$kOMHm4~a;?EeX9s7vrVx0YGsM?=mtEc4LA_yTv zycBcNNEX|AS|y%CXdp{XtRK;nwSa1Bo%)EFqW#Cc8|I;^>-&#j?9>88Jnxfm;j>=? zLDB>ty!}48K<~Q~9JMtw66oajK?sRMCHI+P<<*=0QHzx^KIx;U=*sXNv`kue-adZe zoMU6cZ^O=QS4Umlm(Zf15K<9`&g(LlOkYzOwc{=Z>-s^Z@IGkp=0aE^Mi}wtK~u*^ zSCD6^+HC+N9XE%drL($EFE3mr$_DL~Dkz1k?$$)*&VaO28*0baRdB_*@&iDzu~6{6 zJIk*O2 zg+}dvCJo|By0N4#HdI)~;FBxD6oiPk z?{x#Shmlw$4m$hL}mnLF@S?p;+@1L-xC1K`(-(}eVz{w=k93pkvQ1E zhBBsTHG+pq-Ev{W3{O{85upwC%Xg)8@nFEjBv^1K9+w#iN5poCO(-EH&L`F0swcg8 z4jwrnMT+0(9GG>D#^-5j5+Khyu|^LQn70Wuk(kLAH&(Lemz3 z-xv``{4iNp+w2|M$=S2lLZtmo_V(|(dp2IQ)aM-)Mk`_O!X)5`xQ!&2t@-*TvkX4zUd`93PboIxjt_6ot}G@y6o496FO-5DCiTc!T?(d~(g;3LPDZ?> zwc&x@nTYAEL$kY2glA_?s!8RA1(RR}XnHDlTRiV;3cq}&H9y4&aY%%oZ6CNc?TA($6=MjRxGPa5>Pb_j$b=GR*hqZ| z!A8ydvqS6cp*@Z{E0BNhG`GK$Bn$A2#4-fGG-A!RfNw^MZHGkf)6uETvdLszIJpOf z)qeZBtf(s-*oIHtr3@f20vWN{+?`{;6udIi8(53BO9gWiAm}0KS7p+XJHD`b9hdH) zw7Pwk4MQ?lvmg1DX6s^q!f89VRviTEpAgF2K6Wjg>17ExtuLQZng1x`LlT|_|9C7zb;ZTj!PoZh?8M8yx(UAs=sN~-F!Ot`lw2hv%*o z+mm*rMz7DvzFYhpNuBSGz2!zGW}>VnoX2j564vJ@;nFCg=wx6^NS;0%z~9Jk+fyeA zfkGEnRXJ7DiLitHds*?A{_~9sI87Em{)dM>24V)+Epo-j7B{yQ z0wWo9Ach2oK3&zHbKz`DjMKSD*`lX%V9=dSv=tRqP&&#czJsg{uw3d07}t{-_>3DD zXg%y$L!7e_>zG7(bdUzvKRSpy2S+mzLbqp#N>55HoeLQrSiW9T0b{CVP^4of z1MfDpgCc?t&^;8uu@luCzIi7B+NvU^D632PAwMRln&yTU)OO#rDYZ{&Zb{xy(r>CB zL^*|sBiWrTP)hAnjlBT;PPXqPHV-@ads)#;Ypdp6?U>Ub(n?1zM1l}f9vg=i5Ahm` zF;qlGneEqNWJUL-M8ga(zm(9Z6g*Hh0bH9$qd$({&%ITo^vFzNSMZ07>|04?&8qMU zewf(9K|ZbY2qI>)%AhJSBAQ$w-NG<>NyBbh`@GdKIHr*VfWs=7!62WxeYMGGBwodo z`{Had6}41$nOcdhzr1Sb5(dd@}!_F=DkV4(heSx>_-#OTPm65x1#`A*QCl1I+iW_{Fua5DEtnSG9Jj zhQ^i-U-J$L1#9sMqoJb9Kk4|xgDvg?Jv6G{W4ia2hI4GRz-9%ihn!W z^?=4P^_3o0kZ)jAuCsp2MX2E{rf2@)VjLSv93FwsA7G-Q9K_%l;CVN!7Z_&(j5ixT zDmU`N_0eB65LWYndF<*pY zaS9Pkw<4cqGAM8Y)L>YUWw!i6)Oh$Y4<5h0i1s^CN@)1BR{>||wLj{C0TxDa@@)Z# zYk+CwyUKI9sRU>X0I)r4PK99-FggL81MqGO$sB%=a_>F#@EB(g@fhkI z^=%n2O*5VoJkBU!tvaK!mvBC?Ay%o0pkJ84k|2g5mL))b({I7_z=nWcbv$B=-lr6e za2^WapI!;_t7v373bX!Q7s2-E;kbpEGbodS-D6>Q%xVyp@L{`lg?dIP zpMQVNgJCG;oiv01X9?<)@2;GTKx!)Q)8~!5)5j}9DM7TQuPU%B_DHbF`oH;aE9bGA z+eEqpkXAQ!v`U-j)#XCIW}t?E%k~$O<{P+-K*Xboa%neERF~f*{(%yz*J~GRg$%}v zSl1#w7L7*bBw{Xw*D{n%F;2Fjia5x(ff(%6lslg24HxJ^#ARdQW(S=nYS^`5ar1xy z&ph*dbbwRM(mveIZfKFvU$YvCMDkRZfQ2#=D*wY*|L}0e9#nmd27`jRJ!0*3vOw9m zIT9%yZ-RQS>qcOsX0s%H<%{_^5b*bHj>cjJ(1Phq`mC$#dh$2%44)+avSU_1JeR*m zB}L;O7R~t-?WLAAGh~rbsEl@4bD73yj&6P$jCL1MT5_%sY~8eWeaj;4D0cl zc%S~h6?m4 zYR(<8Phs_?1muPt)`LfD;$1ju6Rj)w@PN2DzqUiY%P8;B*bh9Xkr_4zY+4Ax-9nf< zZd$v5K2jf{Z8`_A5yBk7a7Gt!XF-f;LEFnkLhD48M(&%=;zVwosa!r@mXo+z6K>Pa zyXFo=67E>kl@g3nt!kfAjb?-xkvN0Z5*JoOghHf!Sgpc*j9I zthb&Ej(l8q7-;R?=UAjy+CHkQJqcKRW( z?+e=AoP78+!}CN!n+BoZo7;=M3cI|+YcwYgj#WDl93lJbKg)jHa#dr4~%yxAW4 zRErGhgdARpUgQMyxedW&l+@bJMCFW(*{bD@`Iw#b!Z*qvYWG~6(h~(J%}2rw*J);y zo*cuS*^LpKm{mGfBA0=IR4CeJ>Zh zbLNrHUQaj%TlUH-U3^JO`6zt}EKlzH?H*hxXNp!~_}Rd!x0b9Rr#gaTy+gL!7^3?? zax+};q>olx? z2949~zx>jFG7fTu<<28!ql%80}A-+{OxIn<*(< z#4+qpLJwo9;AvKQZ04dw=NwyJG8T^?KcsV4IF~ z++X)tT%oHZg>htd=h2B3JyX^)kj{*LBBEUwO_Kqk1_JQdah00yGs;+W3y`{YDcSJ00Qj`uruN zQA|B?pyX~Qm4#A`pz&;WJ!x9ItDOeAe7;Hbnpx|*=Oqev7Uq=O-|{4AtB5>U5qdM2Iwo>u%aYwa+zDy~Xc zQDiN;*4y;xw5R=}eWq%?Y#LmSK3t@ z23>`3G63%;Ij&)hLRz0g(3fMA^nz2%vReSNNVic1+R@A2AIAcH4sSh#Xz;`)g zX$a_>i0FkSUnQ8RUNvhQXYk)@`8HXPClBuT{*qhDdZk{*-vw_iqcfnAHE&1llx;1$ za!@xR--!QHw27aFLE-;7LS_0<75d)~O?m&X4^15n^{w%Z2O@7^Du4@515B)gduBRj3bBI(qA5vrE^h%Bt_l)Pl7z4jM-mDW6w{|+!1;Zc zmx5Fin9rN>MrR6ctwdpo;7tq(!L$>{l%msmk)uRm)r?XeU~#-Bon*5r!Gx~LbWCJE zv#!yRts=GBfNq0~Y%aCPnjFZ=BrQy_t7L(kWcX__jEG3s9voCicMeH~UhrR}hJ`|#)WRKI$C!24O_xxmB2WB&MlrBk}gZjLFmMy1{)G*LFk zVN4030cBV_I?+dfyxyTtZ)zsptgW~f_D~5lu0n-x-T+LjC%n{v-XKi4HvuqUh$jw6 zq-{hwfqV{67@Z`Nw7sYVC{7*_1|1EbOB6MRO$xDVMzNPel>UU#pG(D3$&@eFBtJi( zrYW9m5+87r9B6`QRFl^f!t~V%uSGo+QKA_(96@(|#OWAc6V|{oM|2WZ)?trVx4cnD z6al_dh9%Z*&2|%}W09d6MN)6ON6Aak&f}=HQy8=r9rP{W5gj}SFTpMy&VXMLycr&_ zv{L@U8jYlsDp7rG-q@~Zkscf^R+T|na(;2tqb^VmAn!*a8uDB%QfUvUT#M~#kG34Q z!-Y(VHv%NyAgsn>$~59vD1M#T!2O^eF%%&&#x@c|kMEIqC+rjBAoX#7MCE#+Gij+l zc}eztZgl!U!epXQOf}VnO~1n+-poC1Kbjn8pJ3B$u;34^C<#~oRr{mYYEEpxVjBMx zT3F~Hy@;%6_U%k@tsVssfxcg#5Whz+NQ6BB%v>QOX>fqsT2ER%L`P{_tW1Jjqy&!{ zMTGR+W-P5jG7@Y6?<{2^nYM(li4r{O=`bQC0{>Da%<1< z#ohKmyMJ)+GX+2|-x1MZY)Ze1Sw7v09&^2KM-yl1dM3*Ay_*8DULN{? zu8^8t?Yl8$Ld|h4t`ninOz0hgPmLt1i{E9fjQRRvcRh;=;`)z>T`JN&TGFKfE$Ths zkQc(`g5>IZRbKhsIdVQu&+26;P6%$z%Y^PhfTZ?eE~sfcF|40tzQDX4hT!5@v*^)}hz2XsFt%V3uBQOqr5hYPW7jCL5N9q?Qtn-b z_&p{vqvlx69M|i_ceqle{8VKRw0TN>r&OtxnX1GeK-2aA(e_S3qC`!%VB5BB+qP|Y zpSEq=wyo2)ZQHi{wB3FCyLaZ^n1}ga{+WlJwX>=sDxxCxj@+3m*P=zP#<{xSD8!!# zb>90Y_|t7OmUyMsWr0?iEK*7H=j(~-1IQ~-JR;31zMl*Je)4Pkel-oz7}=C zKn>rQ5?`y~Nu}q`Q#bLp!dNu@M)Zq%*b7C3KZ%iFdN$lWiL{nsKRNa5(`uYyC$Duw zyZGPpJ||pjwqclKy{db%D_Z@^8jXe2em_fpw;b*%m_)h~WVJG0+8~{B=FOAp};7t#KHEbo?2xI2*9HDhAS_R+I z9{%arz1K0p3#?g0NOBC~w#sg@c%ibvRy5IvC3DY=BXe(sDx9y1Gl6em9m&g*3@$%RBq`psugd91Og5l47blTcBch1sVLj$f{PR? z4?z7N^%kc2G$klUN+nU{qF#^#0rOa;rX(l;ygeKU96<=X{*S@yr+o;bug>ioLEm87 zPjbtPO|FszjcR65TDS#P3{#yMa79PKA$QJNy|Zd2T$RiLRRpU0#(~To5zt{pWX9lGk9NQEnet z-_Gs7%T%2zhXx{>-pZzhs5F1h&reO5m0}mAqWQ?)M9dq{<;C{QgqUZwb36ys3L>CM z%t!HW;cGX&xc;(Jy>OhQp>oiBQh7kR<#+00BGj!u%Z)L{$P;alUa!RA$6*#J>KWsV zT(8+YRiL+YvP5=B)M7VFeym-G-F=d9S%hRd)XI*HGg`E6*D=3PEF+ENdhy(bHm$}C z*gg(+RN;X3QX$Nug?@q%vF6Zk>_llg)1O4*XjPhYF1_90NE%+~AkP$*Wh`uYWf*&Q zlu3#t29KP)B1(Yh1DtsFFpNI{#Ne4awOM&-g-!sn6)ZDk?dJG8>=mf}rrs8+)OOLn z%g>SYo%R@}PU8B^jL`L3;LCfqZQ?+FG$ph|gbVyglVU!!v ztycMMex#3c44zr1Cc?v?MB*cRyu1n)ek!N<)h+Rpez=EM#HOT&+30JZPil1J6K43+ zvkl%$852LSgB_udOWvC6m3^|n4XWQ2K6=9o^Gq(VN0>QJmRc~7kjjIiG8WW4kU5UG zUNMflIQVzFU1tGjU2y+#>4MAgfOq8rlas@>`GCLsY+ZBgxgyp$UHNYcW5EAhWFPfv z!F^WyZRaYM+v^~PXOXH(dwG>__Aa~}yTYX+NA zh$umczsYdSND@`RA|wC}7TOwK?tO#7IO$!o8$5N0C1IBqmV8%~8F`HM^mU%{IE?mW ztHC{Erqs>o1(YnnB>0{!D(F$)$Bn!XEjgygFKfBEUAhdEpHB{0^OaFnEk<8<3Q`p% zhp6z|%hZI<*){WyDlq99wC=NYD3C^={7Z>~9lgNUTwq-kOh+jTmL+78RuR^}y3j+c zIES8zM{^l9#wop*F}*Rc*m^yFy)R7tIXp5oO;1pG-WF%VLyd#-n5^8TVl)0A*~;ZB zOec~ioLKPkQOw!|DPbY*3nh(MvA3yh3HWDIV@q;EqC`|J4oRv3M}0EkC#!6-C84qp zxMU(4(E~PN_xA}m!L%L)I}*xH=BPuF#hmR zu2*3JM$)6nnxMqbl%|BS6rk@Wj{>bBxZ?VuoUPjQ`bR0&=q6uFk%38`c;Lg`~}MYWa@ z$wuK1Y79y|sG*LLAHgb%krNswR9s%}fVH8Kh49=mA}C^}8`>i!W32)W)yqC)#Gg#I zZ#`Z=2X|l3Q2pF|PS%8s^Ht4Cv-$hE%*f?$o}0C#&oNXk^NN>@THp^IY zPv*QT2h}j&L6+jNHI$W3y|S%TH0)B&?!}}H+xjO^xY_>8$H^!g_1fo+k0`$!;acSm zw(Z^x3g*dMS^V9TGXk29L4CHY*&S0%JytKZ$fSN(bYyoT(Nd(57%#P>zjyGGNC|QC z(TBc#Tjw?W%f(8CP~7z6p0Xafj;YC2)%_0zPVAs4YV#$ft0O5W z3%bg0j4$ZCo4%W`=#V*W_M=W{NUR<=5s6hb5^f?40WC+#XWxpK_E%UI)pBdDjx{g-F&07PQ=O{J!O#I zmmi&wj1bRnd1Vac&nv{-Pq;y2Om@@IDK+U^r+qS~84wMfcC1>paMPx``FII))K)KD zPsx22$jNPx#D}gIiJ3IMv${t7>Edi?c{Us)I8huGEBGX*dpHd3U zl7PZe?KVfhhy`0iU=W$j zOrnu_j>9Wk_>NQQaHDs*ZTVkp_w^-LD2@vWF|Kg?#lSkIwR6H@{n{47TXU0D{^j0* zdnX#xZe@#QN>F(5c?(Fi6$RNqPQdE5#W_aY`Jhd0kbm3a66-vTK0^xqk6&YzT~vC< z*oo-3AV2Dy+1%w4d!{|&gV_B~e5uRe5*B1lc#UZXcw#g?5>!U1tHF4luq`|F9{Lm# zCvo;nw3(Bda6ME#z(xVVFwEQ~M(+E)^beIBW*I!xGlrVqNIjSzD!|P=+|d@5@%hms4(^zak*9koZ+dLI3$#xLdI=BF1OaPr~sPy3;fD~nyRAtqj6!f3re zK>jW)lr%O=JBlXK;kga3@VpP~aD0Vd$OcPIf5L$Y9Ual1N4%V@-S&z0FetBqj0!^8 zB%7;sPIgB}re1C6h*NYYf#v+AXCnr22fx6=L6IN3s#MWz4M_ImOE9^USy!z@T8t3v_|6f%G76@jOUhS=md5Oce!APRz?OafPpG>69ouuruZj+D*p{e+= zJy)x^=eRAP0e=HG#Yw>HE2aVsU&@&ZXFfB;qEAgk&+D9DVZ5pvq({U@s}>*1l50<2 zrr8<1>wI%@*V%BR95VnaeyShb|2xUz;||6B`pYPxPyJsdS)~4(NtXX7pTtnA;xC^B zN=RObzJpPIsEYZ0av}Wm9ymL6D4;et&H7>;cxG2}#8|PoQe^Pbk59fesqNq5^NS|= z)Eej8w;^I&PqxAKb!W8{>bT%Cj<0(6pued5=s}{_>LVREQI$e|Q9-2QErbc9jhNq# zAjJFX6a5(*jzH{z`8ZOG@yjH2SAGAU?@#fwZ>gYkQx1x8`)kv|&9I~cS(?!luzW>d zuU8+U+|tnFD+_sI*`xIv69o=JHTUK8d+BzD>b2~mpCk^<55_%8Cda?_uXeTWE+w-^ z>Z@2sQ91p_HHWVXm8K|l$?$$vRZrC^Z4bk1!}a0Qe&(9$NM}wUz9P21STMD^wqT{g zf?#|+%IRV%2HMJLnOHH?Qawq9*?mu|s6JL^rCnQM9AD=d-a9F z`#GJLc8qyNvlp=Jl|`7P+YfD2 zDX=A@T{cit^Lz&PqsIDXkHGP-)HE*%J5yxNW{9HSc@f{Op~a1`sB!-!$=avujl{ zdAMYjc5Xqz{%W5zkG{NxG>=Re-xqQYMwupFI|WwBx@oq@wBGssc7yz{PM^aTmoli| zz7VWm%K!iOG^faacLkbS7&`x_EyQO#_DIa}rum%`iL0+tx-!%B2;T2R0@}Q}6TBn7 z$-jvMJ!r*WcQ}`>tx`jKICDRG70mlj-?QF3;wRF`&Kuw-f+rHOpM;oLqNXmbMYXQE zbAf4M^wii`_}C`~qKnfY-(Pi9FV*Wx;dK>i*O$~US6#NN#=%V=FMQZ*pJ7hr7x@5^{n?gPmh=9lDD6h9oE`kwH5bCv?$qjui|Hj~aZ{FP0YMqgdp)Z_hsuJcP#oh}ci-IjRidk-oN z!$y7`n^kF1AB(o@RhQdFnt0SLG_A`g%wOt10uQeGFfq^818(Yx?M4);cap=F6R1H!KRh*UCxE3%Km7eBQO)ofb4?PV#~NsmG0~-d(x@qZ z0cw)DQ7R`52>1-NX^zcCql>tIU%XoWy4_X^Pv5{lp+z-Uj4y9*mU3;3PUYFA(8!0a zqH3#-9vgPAGXL9(nc3b=oeX=bVVXQ?^Hr~xf2^xz#eMdr+RbY}g#n`h z!OOdxpLw!B_3U!u-Sc2S;KaS(!hh((f8@b=O7$5?L`!_-kNX4q50ueePkPgPc!&2m+m>A`B4 zl-oM8*6nkdSlnTa(dbE?9$QwcwK8s8l?R2Jsk2rYbxXB++4T8X&9A6DwHvjXZLEtt zSi-YJ4Q<4t?N^xcaIA?_gQY|HbJ&H(H5T!=8E=j}JN8i4O`vM$;kW`Fw(O-w{fX@K zGkCXqri+VlNskwYYE_T;p@m!+u9vQ@-11!pdC2U=^>^{8fgRuNZiQYN_H(Syz)rV> z?Yj8Y`!;l&3BKQNl+l>Br2{m(-CVZ{n)f6!wcy1mN%cZmf=9UXL_A%xccYXcozXVA zq~}`9)Xsl2pks;LY|SR3B)ag zz^lkD7XNFc6mS)D+uqK@9qnPiKsqp|xC*yoSZ+f|z0TXfxRr7rMU+?Pkei8*yLH-d zDQ`&!uO&R_u@gAvT|_|JLcKLmrnBB(9X0Jz`_F4exi~ z_1ykJyH?Yxclcv|q@VMrtd!t(tJ}n)c0Oa9SsU(1)YfEY-SaFhFMD>@!ozy`X|utz zyIr2VelMpycVGGHvaJYz`gU9S=d5&+rCgnae*Hw|#Hy~=?cior>eRpIrdVs^Q?*dT zhrPo#s$2kXs)v2N*U`F7M&ef9Yuv{Eq~ZRJ0*7=Q*z2!^FKk^=xyszar<+3^wXy4E6arv7Yp{@;$7EA@|8cf%76&T6N6 zmSsV!gSF=Em0HPGoy}Lr#p}1OkM+A(4!ln-A8Q|<;p(NA8lK)cKeCnS#2~e8jI@V4 zDc9g@`#MD%r8CK+*DT_u{coq#!Cof!HB7#EaA$gbZ?ETUhriXPV>RT|S{QLqx^DNX<3oA#yeZQ<{`%8XEA5muaNcyy z&c~c&;qmWYR{S+=QS`Dg?b$n@Mc$oupZaxomHD$>0417Ncl&+Je}y(7(>H33&E~Yq z(;YaKwE7ra*q(8YTfRQ6AIHBWyLqI`=fpDBH>GnPfC%a5u)#6UHv_>ruYb?tceQAq zaVDqNXVZ!@MY@_+*o*S6^qe++z3f#x32c?3?R>*@O~2_}bL%_M^x^wFY>_l^xkC2~ zP1u^*g3kEyp%;RM39HQLxZw*7#O|J*s*P~U`OB!zc}8~d2fVaFq7;&aD!4S0jM!n>(~8Zds*KL z0@125%XSiqBY#Lx_L7%J@`RdSOqx07;B}n1JueB?3q3oxI60@_jYN8UbQG!;cx(!G z7aTJ6N^p*7CW@GdKv$E~anXgoft0fEc<-xY?nnhygb6?qHfM|wV2u8EfBr=FT9*#0 zh#H_GYF-f`pekd9L>T8RilB=qp&p#8C+IS4j&O>2Pe~*nohC9OjpDQ@Fm|cd-9%Ssx`|}5dd^vzw?0y?wWLZ+y@jap@7xttHDcsN#4#%oPYTR{vhe|GrhAF1h~jYl zfj@-DUyf=eMd18mR)EBpKZGqZgxaOiS+ipr(Uz0e-Us2N%43O?hgRjJ%$YP%5N7KP z4i*PV^5C4!70*eO3in!Os@4ZkBDt?QC~r9`)T&ez9*s>zM)H6OxU`%-eQD4rM@3+~FFVugP5Gv?ms3*+>bc62%p!{L_%#EHRvi(PIq4OjAv^CeDp} zXR;iJ(Gax4LX(e5(`Tmr3t5gMmfSFqTH+@dGx7>piw)2owkV#Wr@N@+PUkBOAQMOzQQ&|xN99rBTPY>DKQ+Dc(wII{DN*J*o zIDQY=S}3j#l5ddg1R)EgOoO;`j7KQ(fRCbXj~IG*i!FhV#w+0o0Fo&kK>!}_*#u^!D^Pu0{9sVCX2$)OwZI(@Bx{rkdmLTnI#*wE_C>>?>l8NI-%S>+-p% z0=oefhJYE400+Vq6q-@`zX2$k05LWJEJ8$B6@%Akh8X~YFbou6APis-4;oQM0bq>% zn-FXOL^a=ygeoX%05R48ERw~+UXu=aBUg;f#1r8A=D;P2c$oYPvWtx-bzR%4d4RX1 z!nOi2XsQdP%IlD*28*DQ=diGX6<_PvRXIacJd_RTu@0iKGBZsJiR@OL(zIO8bio@e6`JmlGcex*)*Lvq#r%R! zy#4bHpbeTpr!b*_x`xlKu^LU`94!dLnDMs~U%`L|Gvk$Ur|V-+#Ns{dynFe!Gxkl3 zv`_Cyla)iJ>jzH6!rP%d75+eBXXN5!?Pp&Pe6HPbf%lob3UBYPpftmpjGb3P6 zoQ}$GG@6b4LO#{}ke9Difq!^#oxaEZ1brz<`K+ z01=JOU%u}zCj2x{%#TK7S(t4I$mfz*7>2-tG#kE}2>$N+jq}J&$+lVBtoCc#J5z78 z+N@AP*1UfsTF2)1P3Y>kv#?*|-2844va%+6oCV_To^dHX``I~``TfXbDSi&V9#Hsp z!X|`h`{A_Q^i0gogS$|KYtOX++U+RsS2jig05rF_$P| z)->)I=5`?Rfy`&B@RS)lXZd+|8zGTHFoHZOd8*?~mk z(qi6pN!w#4l03KeV6UADFEr5Cr{mA)qOKD~+VpO2r`D(a&Bf*7wtj7AL*=`02ertZ zxTAV`82-3!0bcG+4cU_Wl+^JOQLLDo@{f2zia4+Yf7WO-Ms4af- z_&-8eYdf{izvmvk6j>J!wHZ*;myh*T(WxFiBZ1zHTR#!tcafyC>gpXnU;Rc5r7uRA zKWme5hIoT|zHABnS!2D)5uXdo)a9~0EAbg4u1~gxH|Z$NPrMUc`uJg;$F{>X0Vf4q zU7GlR@t6ENQ2qw{yv+XabuWvouyE!*KQHO@mF<2SCLLstjW8YXT`j^pOk^>4Ud2^y z%0K%#ew8tEnOZza+91%R?BZR}I;Kq*Y~ivO^)&ObR`vWyzo|1D{WKYo2kGiR*eP>< z+~j?K>i<~erTb9RJ5};62KezN!M%f^N8Qi9Co}yhtNznvc&drEsFO;3u>9(`O+dY}uZP04x# z#r<_~WG2+8E1Z%PZ^Oq53z z6_{`|Oo3E@IGD7gIgpomlcNvCWjs-iZsWkB4kj3posoniGg~Q(E`fnZ=;o@GtsXh= z-%8ARyic9$)PQ+>Wn956q8 zwb{~1Y)BUwdhnB96MCkRT(7q>+ubl%R}X{EThSD=^_mnhpdy-br*O=B`ImqMuWw)Kkx^@T0rtjTYTF z?N_Qiaw?%8fx6<4inA{lQ4^M}QP%h+dc1l65>aCHVeMlJ{+8z>1v32Eyz24|5#Ro} zsd7qLQ9&5T3XSUo62`=j9h=;NfI=k*7#h%b7xyD}y(w0qKnU>TBe7v2s!4R?Oka$> zli(%)qJw&Ot&P)}=eZTTee)@foS8URVToSi{HX&>gwe<eg}{L zPEQ3scvrPs&Dyy>fGhWdrd7TxI2PN_twn+cj}CshbekO00C43&jcCP_dlLX&!# znv>aHc43MY{$G3T?Uccqk2+u$4FGh!q4|QveF@0g9f= zZPbm2xU5E$ED~C9mh)L}Q!`W5@0Z*n*~b{TkK&^F|6_ zt6qXzIVpd|5@WmH(h)UlO^oQn8zVIC@gWk@*!XM}nm){5JH5)I1NkdT1!DK+FSoZsSwL2onJsDyz{m z#R=&#&ewbyU`Y4jY9Jshm@-`XB!ROa>67G{Re4+GQF>OiZ7BjJnLG z^f$>*1Ms4(QZX7%;(0xm1g#et^5Lt-N)2zHb84=OMglX44hOPDi3W@w@elYz(Dz3K z#kt5GhR(0#cE$!-5q))8!~rXEe9uVz{bq|zF%yj`Iz?+AgX~bncmO$LTml9#JAY+O zg1+qvN7Ti>p4!LFHcNt@uH9uITY&;R7~BO*6?Puy?*LCIQ6%()4(51hdd%`11_dZa z3#U5B}?1;7>UgeZYwS1_58i;Ov^3(&zTv>A%qB!;dNSw0S<@|6cXai4;kK64w zg)GtmJ^AU;?*_*u<;wL`x0hk_{{XZcJFuuD;ox+c zj@zbY_hk4z;24n1P%wiRjs5jf!l*9M)gCUO(95Bv(C7TA`Vdu1qf;yjd3Ch<`lxA~ zOJCEf5l~Ukl;UQD1{~B+BLgv`62VwQmr9Odl;|b4<3JWx@xB<@X6}L~p-RkpXS1NR ziB*`gj_uHA>UgDQOBV#Wv{3sIn=VCQOMDs{n-OJPYAgaIjEhK-xB}V0 z16J51ocO(HXg?q8Y3?3I8yKk1vfkBC(yZf_4Rvi-Zp8|bjC$`(eFv5hG;Y^Sw^_0* z6|dDU9Y-$)E4e=N9iZu2EwpdepZtC@nw_4v^S+%4rXLh7#q6cR2^z)>$ zbAa^7gboW}pe@4nmL%%8I+`l!T-RQ#>${qhejL+l+WKAs@@F21JAIgM@N4}lc}4X>-#Se5`g9zn$A3M>>-}}Oec$@%U;d|aHwo_BKKdU=uF5-}`UT@S z*LeHZ@qD#oG-R~$p9U(=Z+f8H-ugz zPJdm}bx+;%Qz}mXT!b2YUMf!U+<^+W%+Wygz2l;uN|`5139gay3-!AD2qUxr`uDZF zzc{^)d+HvaRB`&pud2Yk6NmqCMr*NNRq_7gaL!i>Hck9d@hDV{Rb~xW^QfYVTW0BR ztho1Oo41{cL!ACZQ1ruJQO!wwZupy5eq|y~;gZGXma#r*JDK)zTn*Kmi@L^m7t7Li zul_}#`}H@LqYX&IrI5)@qVrvmHuMaoR@8l5q3v4-7-u1B^H}6VX za^r417O(X%$>*s0*DqU-m4AM`epQj*jg^1;-;;taxzg^vtJei%mg*hb0`+BO_W74E z&kvv0`7`k+{N@Zer(4Pp^SxWq%@b%get!M$UnuT9vDDG)!($dPcv-?d{LV=GCix5Y zsVzD09rmKuo!Ql4T!xg{7reCB3$mB~#e!W@5i`f-FgOcV@K z3A35U7-tdWu#CekIxAYQ&#QY&ZuJ%LHa%YbAJ^c>;Xq8Y!jQpn8m9*%fcvZ;><GA_U$J?PSm4mSf^?*G8l$xFlO3L zP%dL(-kW<2x+0Rr%)k=T_uv_^CNLwb)igr-B=NvgvNJ&0XtXn{L%>=DFBEV1T^)D#c z5zoQ$w$y8!w*w;-@k=zvc2w+SU_CWL|Rpm9;|l>RHMKG|pOm*%M> zWA##Gh|>2Jeaf7!2)Y!3#6kO(Y<7%=K@U}>a27-YvWpTeq~=tGLoDL=EWvUUN06tO zP=rhZJvL{aBz+CVDkS+^vOk(a$(mdJ#!|rg=5r^5wHax5{{HB{M9H>%d6XtSwMBm~ zV;{dxgyxk3`ZoC&UfQ+4p5-qUyd|S#u0b zs*!S@ju>xPncMc9y;h0rOQuQvIr%!5<$Yrf6=9Qyk1N=1`MbH3#3U$5yhF8sbUK}d zXvj#%nxNpM(lyc!2|7AEDO6rm{%WccSUvnc7)wfPvNN5G8e9AZNKt+X)B3l;VdL6Z z#b5(;W)9+eEkCWrxk#wN7%&ItI&`_NCr$Fv?odO1S5s2F*z!kQl+i8!Ga?o9>!b59 zy12s=muOR3%n%5_xYLRkO|ot`P03aVH439dk=R;7h}MI7~4Blu)EzkH1*BLT1rh@`unyyk6dAT^yr}jPwYX#8$V_u3trq}zcEr=qGaO8 zHbQuY`bpxGKGTVIJ2=s9Wrk1N&Axc3JwO9av* z{R#ALCH$4~i!gWmkGWU9+IRocRblZ%NQ67F_%j*N$wJLh#xK(D^s5&o{ySfuEMEOG zBo%)vHkV%d3owIs*JrGp$&8;nXRO_!oICOlS{#|A)Pdr_J&T#7T!T?!VsxEhW;7V+ zbV78ZvCshp=3M#^2a#y9JQ*V9Z;7+KyK9?Ul;z9N9IoLfh(K*_d#|5Jb5rbipF zwtT>CQt89AtG!G}TN^Sf+JY-w3=})wTqNw!U4;NsG>He7DK$Phy2v^`W{dj^%tqL9Qf)ZBX^6nRDZyxyo(LsJ0NhlKj-b1%Cy^?88a=?os(nBG>mK z)O474CFF@&Z2^n#b;b`n{s(bHtW)?k3xKUXek475(II)!2qWg<&KOBqtbrp(MA6V* zeuO5Iq zge?p}?y|>-#l$r^eKGEAcd2_2rZVH2wgE^Fzp4x(qnT#XwvCh0ls&d))a%IghwZ2h zePyGu1v$Jwn||VHHcJ?{^2JRfgKX`pMZb8vrB4;&5`nLE<_6udN5c|Cb`R%sxzWY` zef@In14Pym4w$F@cNL%xjC0vTV^e=2%L;M4S<7jG6A^QSEuWjYgI(s#nUgQ^je1EH z@@7zzH!RNI?Ob?vVsQpJqYOmER@*L$*G6P*)m}SSwHDbxaBV#Q)4g1B4P91rn&~B@ z9sF@ov0Hx@dq39r9E1BvtZ)4!*863Tx3;Ku{-w5r^X3Iqn+tOBdaX^(s4=f;<(xyh z+QG{0uOwaIy3jvZ%C5M)T94bgxCC4uzEk{!*ZE0^*O$6W{1SCSc}Lfr&dRqV1OG90 zdYO0qIg^S|#Rn~dbmBp&nMR73&N1 zeYJivVrD0tS#UJYS^oZ)xAZ2ooS%xawC^?9Djy3?$-&F-GdaYz#b{p*gU4hW!M!a3 z6|VwvD`HhmzFUs~qT&aiTJuLusWtHZB{s-y_p5QVbUK~9hOUI6p?{lU)!asXT5%2c z!_ZBBo1dZ20%oc>G=-D-UC@tN)+=YGAGHbd?klPK6#Fl>dc zHE}3=HMS&>A(nvi;_ok`9Pok+T97GOV1&8Hp@{$s!BP#;#BuKYM;}8lYEY^Zlv*N% zsFXoy4~wi>fRx^U28RJdzl&q;lt%1u%p+QWIF*bkk>QUxppi-hOxGua=*#K#_568H z8|@M6fPg~NZGsFkbs}TJ#mRT`g#zNOCShVAzZ>C9PtZ4S zb0US!;2qjG9fu_)%Z8Okw9TQ8A^34Y(Z0h4?+vRZy8vBAd=i+YFB*A=jhQ&aK(wI- z=*J)8l-=tVmUUm*OPK5^@Mz+}R)G*sp=jENlu5{rr>1hmOe zyfbA?**Xlk-HPedjCrZ?UIP^A#BDPW3Oj5PWu*AYcb8*4$NS6RcGkAyYs zn(%7yz)1){;w$`cjqd4Mi{ApC*6ORM8t?j%=MvEehgI`h>u0R-o3;95?y_}I>vF$i z#W-!Hm^V6A>EDd=gt+mnD-C8RRR9aRbh=jttBE zM|cPE(bdyoe##vrduCT}IBOon)b}`3&)HM;2XA{!EWVC!m+3i5W9^IJQd^$%DUM4*W(U{mA*%NdfaI#+q*VX&o3>Lmfn+$@D#0{QZQ>C<2qUc zT8_HV;4jSg577epP^Ds4%jE*Pw$pbSXql!p*FTf?UMlW$l*LWvepoZkAK=D+(Cb-| z&4cWLF=DVSlP<149+ed9y6WkCDLLc=Bk9~6Qdv@kMX?N=kh-9zt(QMUo`e!;%aO_c%r{tlvoxFY42>_KHGBM zCtwLo|&}Y@(4l=0Zb8GL9 zJg6wC@s-{XMm7gJ$32@$@5lG73-1R3CB{2{)-Z3~R0?U2^j4ys*z{&Hg5d&VRvGSw z*aDh*GI1il-Uk0v$DNGI>RuKJ$-WHzdnNDzo^+E*n+HbTk>k`B-T_;#;j}w+jFWNy zF}*;}D}Wvg8{q}B!RX_Q#>4-R&~v)qtQoLFPfvwQ8CS(bqhNwvh>_JnDVg7Nc}Y+X zwN?!W&n*xp-^K%NwY={`kCWy*-sU$6i_aiJBQ zyoo~IUR~|QoNCXoonm3^<3GZoR>8$EoRGR+JB5%Ttm8>@f-;o^b*R|Lltk-EwfM`E zbRho61JtO+S_`LIxk9iq2G&bv@)+(GWMuN*hf=a7Yd9DMoTk%|5=z*D1DF$x)(pZa zH-mDj0+C^iDgMu7RXNUL73e>U3D#k;89T|PaOlz-0mA}?B6~~1;!rD>!sE8nim2=o zjQ(<#6&_=(OAI^93yS1oVT~KiEC|~Pm;h^9!nd!>&wMv|*hC+K#x&CLXI^+ftb@sRL^#?M9xIh8hmitR=vU5K2~R8bbDD2Qu>%T zAZGLh8TZ>+k5H%?@LTUDijam5l}=(wVM z*89$)>TTpazuPtq@VgCFtC6UnR2zrH!$X6o{1N?um|Hhn@7}>tfwK0F_R!v(0m9EW z^5~V`?aLe?*Gv74&sYAn`LFr+fArmuZFKwm<;L4(zVWCX>hqL&GUJ&j8^pHGX6rv% z%5|P}NfWFSBft2QO|1cJXp14Hyuyq^+O&z@O;2V|d^*{4=Lziz)Rw9Tg38ABYg|^lkK&P0x((~m97F_F!4jOS;)qu{0v#gq?l*ufvupBL=L)U3ekF~DDv#gs} z+DiBqXZ_S7-Hsq|EQ2(8J->q>lkTsN|08jdO=k(H2mt^|hBEJx~_&RzeUKeiVFTM(WO9Hw`&Jqx37MH9TZCYYLNkWpp@rL=e1 zyninXa7G}eBdnI3$`nB=Byf!(L75C>ssIZ()K^r}ZgYkijJyetsSq=Ruq8n$5D{2K zb~s2I0JHJGx5c~j^*a z-R_;8FQ3q+u@&)wqb!%Ru!}b@`14zJoeXD)5Sh3@f^%g4^dB}rhSiW3uK3lD*gp?s!9d0$Gt3xc; z>&(54X0lCM>iXFgHv?5Jwo+bf<;iy|w_DyL2`)rN9VVN|sa_c-C&ofewJyumK3hqe zpM@aqve4p=5Tj1_$$qraisSEvaP3~wxtDA#`TZn6uH3n)>QlTf?qGoFrD(s(WR)8^ zr`EWIli1Uxn;b13h5ppyTlT;Q**pSy_QM9uh!kmEvDSzyZD6`zG~zfxf=p06nApz;rnHBMG=XnxU}8;$WD;yHfDeaWFdG$a)zuS z>gGmu9NYyn&{Mm*?J39z2nrzfV<1Y(3@3Gsg-sVx&hHVVViHZ10_Oze;t+gY%FsSc zKo_xmQ`RajBLYcO0NNlKJS+^sz=JkihH`2<7VVqSvSaf?1WNX=JB{cBxGnW#7qHdo zHX%fAwZTksgMzKtwM?WuBywn0d-W=pDaXXR=MGE;CKG7fC8P?8Lh5~h1Tde8E6$wr zPGMO($C}d#sQ9}?J;PTE6}#pr%{Xsjl41)(DKva zu5hB!#9(iAz4vcnCPCbn3<@W{LN@-=_e-{A{dTw-uhb>SjkB4Glz1#v(WOcqYp&as{ z9P=K4$@FDU+Tx{3SzdF6OlJcj_Y%m~94PtO(}Y^$d&&omhR~Opbu*9tfqqLs=IcNizA~69yoZ1NFL_$@;dL;(=$@2z1 z9P5G^PW9MHk_2$q%E;b=9zK(&Qj2>YMD5-#a_@guoWMUR{ z!rJwLWKbNpIc!i7Mw#j|koI!o7DLbI@3K=Z2(*f7{Z=Z_i#;_0 zia5K&ov$;LO*-G3kk1(Wt-)SGr3tCEmA?}cl4xncuShZW^hx`Nkh;(p@dP!>;r1cN zs87V5tR9Yy$g*?X`mEC1xs2qR!>IOAEVBToI}qR_5Dboux!6#TyCxL@s>(vBIvT-O9$}V zp!jwnP4(_qu6V?`M-q5Ot7xhV_BbBGt9pghAL~HJd{u^Rv*H}=v4F7C*_MyQp+yo= zjcpjfv2$a~^x!XE-oeD#O5-cGuggwA` zFqFFLL+-he^2{D;kbRekUAq>%;YvP7uI?%|&DkAe{8iWbXo`Ii+#?dph#HzMX zaS`Z7j;+-1!m_7Fn{yQwqxSoxsSFS8qg|z(oyOjq=b6L2F}@=vx`49Zx;ZuTdW-0j z>~d1%O-LdPq4|0CgN`s`btDt#a82Xe3-pQO!O-z|`N$$xD!$Ug*t9uTg0|UxJw=~8 zg4*Zq3n{yRtYzh6)Nm!tZ3>btl&C%eIk19p4y`iqwm zHxWnDBfim$z6`zSqF53_CEwF;_jADwq@zJ6H{I>!mjx$5CE;U$g`$bd-AmIq318dF zfI7{JCN(2;iYLT3v@F96gdU10RmLwHugH5GlR^FjLT{pr6}D#3D9M*rAa%sns8Y;A4X*zioR z;bexMXmk+CYs0KmdwK|2Ok_5xA{y;uCu&Tp!~6m6;rXP))Py>ws_rZ*=Pu3ZgNjV; z2;YiKzL(oTj+VL*n&w(BJQG>>weQNMDQd?VZq;DBWPuj-0mrEEZT4eK(v5M_qrod> z%_BV9{clgM=YHDg0i6s5^bzkEjxId17pZ-;2LQ3u&>(B-yQLbqV4~(y^6Y%sVTJuyjB284L?*M@cw8-)puU z*_WY9vqzs?^sIEz*cBcoKa(w=p#%qa`A)NryJUES_QL$9Jc z|8Aoc2m}t<-;&d)f-m6_T}-jHR+f97Ri#d$%Oy4BE zj?M=q-sxhGSG?$_3D2hsaBE@uFf*l-u&27}JFRzgYw-FVMu%!Z+Iy~H3W(Bi? z7DAoIbL5ap@@fgG*sHSMFKNaoNX8+cl~_+ckVwqKzqfV$)#e_3qOmnr9V0P^+>QNC_Eido^^#2;;mE?vNTRkeDWPK{9taT3ep* zi>zdstmrV&#RLTm5tDfM-M84N1UtOn9pgHwFI`3RgHh!C&KN*uM`Q$(*@`XW;1|qu ztFA$QR8LuZfySeyB<9pW@AJ9|>N78^QZfRh81%Ome*OhLMD&`feQ|-&topIkOP~7W zgZ(ckxpP1c)bfg~(B^Pw)`()u>bW~$shL&lotho*t={%*=M$@^+nw-OkFZLDp?frHxZLj03D%O`rvn$!M2$Md1tZTGc zG83B$%SDBvQUlF0G-c|;>qFi2*BJ#gOM>U5)K0oV$#X|ksSOy#Dl7M+wdPbiiKCoM zSbD#QZRImPUl$qogp;7ApVAQ-WTniFKJaY7`mKkQvXd8C5YJX2Fce zI_2V;M=5UxDOTj@BF8=m#Hf9Y5U6f&uoPUD8WL`+DMddJ%Y%L;i}CS<3e->ZPMjKk zS)9q|tKdCNkyxNCSx6T}^iDUYpO;^ZHrFf%jCldeERkcRywA;mypU_=hh^U zh;aYI!O10jjua+H!t#C>Bny&{ zZ;S8K(W`gR|Gipk^YvUdC@kfEU}~lMpjBMe%k*s%^L8$2%_H3<5rfn}K{0z%e76-O zJkjX^3COe}#}X@vGzm}6(lS&bdC84&Z_UyJxJQ2+3A>|IYTG2HSIEWv3kbEfp*FN6 zIR3;bfCL50%G8Eh4w>9Gik6^EbJgxQvGCoJ;(7Zl+M(sw%=N;aA0H!?fvf2X2nzUp zHn;lwbKk7W9){mn3`ncu*7)-Wc?8X{iKcX_piSe!P;u~2Aj z>=!AM$dE2>9-+f14?vx(iVd!3inU2A4ihUbGys*mYTv1pv2aX*gqusQ3%VHdzIB0Z zEc&eY;QBW-0W>9mcz)su{7=^OUqh4Se*{e{V^caKgWvyXa(XGr#AI+I@E+(f(2>VN zAPA0TNb(e}HEP*3rC7_Us30sgCj!sFC5N>P(!q(ft4_o;b5t}q{Rm6B)g9W(A~C7MY@j8e9N0PS421;VVXy> zvKliO87kux#?yxHaY38fw(sEP!Cu^P4y!eV~E{s04@ue>#JC~J!`Pr zP6_yor$Zj4a~EhOqJ~@vLfs3w{Weavw$MP%hTt#|`V-WD!1xkR1s#y0`IY8P^zuZ* zQsP>#r6h;ChN`@`!O>BuT!=RG%;qjcCMCHgU!*=ApRUM`ifvh4xR5MNTlz$!q4Gvu zHrkVS8h%KHL=z)7rvJx3{XkdUqZ?J2TwmxN>tL3+n`7Bj`kf=$+1?5N4xWzWh?_`MTi9F zYy@8fXKS;lEOt4JsfT&$k!xOP=C>)`@{ADt=@PsK!@$9PHg5f+ttgR)*dP2CoFRVnnZQ z-e^SMS$Es0?t-TA9gH6T2MQ~ZS(V`xVBt){ zc}5_dOn#rw`W4Hf(+Gyeh3Ub(wll6J zCFhLa5FB>?MpJ#$ikxK5JS+KDlin4ZQe1MxMA$x#iS7M@w;&hb!`G;7GD8+i>HYB+d#Z%<# zXJ&lCS^#G@KkIg4k4~o18QRVkJzAto?}F}mRJ-;H&S4A9o8IVhT3UEB-cyLerY+QS z;rqC&jZtF`jf!Rd8wq?p^agZe3fF0)ketmNGRu`rJI@U3j;C0XiEHQ*vGvV6?hB<} zvEq~YcPmuv_iPxfrs1Se<0GewPt;!Y=TCzDujpN0A>Zr#<02V<7_k2q3F_ehW7*sr*CFP1ML2a2M7LIFDOKfwFDoEgJJO@UXPtb$)RqZ_$+2->38*OS-N zwh6_xOI!MfWe)PjB9Jq%{ot?}+blmM7po0)Vzd5izIz{~fd!NvbwG6=%Y4967b1k9 z8pM3RL{F}QdY=OT+zs4K$ucaBhYA%aWyCJlHNQQmSdivRIZ#6TVb9jpd4Od3Wny+G+jT?iW8yHqW z6s*Ri`W6+Sq6GTTZ3HMW+nO!hjKb@qdqWmpHtWzLH2LnB0u0H^C4YIf>+L&@*AH#- zkVnvA`UX;OrHU{OA=S^Z7ho^ZnjRU?@^u&_CMckeNMvxuFw=QB9I)HJw9|DlnV?Fd zg&N~3akQ-bN6A<&!;rzFTgtIK zMA_YkJaz`t9SvoyOfBu(Vb#skvs3tGfz-28+Rp{=!}@+nJan!HxIQGI7?))%k55dp z`3~Dn#5dpgrQyWJY2FsdC&B420sW~*!8Lhvw*ksCR1GdvXwo;z`*QFd`;NG3y-6R9 zDckdZf-K^h#M#b|XH@?`^o;*NkonKgKRl!Qmg8nKYByQVzB>9DV*?Q>$31(7t(h@L zG;?^8w6Pp5vn03_9xVeAAR2(Hkkunl*A4Wu1m_9Bp`%HMrMCf{#O}b`*EF~pX68jR zo1+c~I|t`G967!ys*5Q>xf3Xos$(f`r8JoYTr@hS*9W?Py+||u-GnZy3o-)v9v+4`T4b@ zAh5=F+?rHYR*$D)|A=WvE=CS+Kj^?Ah6nTw84I?G0*ZRnHGHdl`He^Y?UylF9#V5a zy;56(=A7wTI8d_v|t?Ky5hA6oDLkfaSpyJ(XOYSq%f`oia0Q)VWq_N49E7k=l9 z?F+@*++Ggtoh)<0-|ZlO^Y}#a@S?Xk7f;~kDYBpNx&!!# z;hat9r3ETO!3Jqc&;?cPvyU^jQiD^~?P6rWog60Ir=c!7Jr>O7HU?@_krx6XmWK;C zZaoVzY#H%|s+{yfsO9asb|6f) zD005ip=fGr_4tUE=^FWKrkp8o(Rimqr&1;}kc_}GmRYYbs?Bbb+pDcvrh+8~j36Wi z7!FtBr{vpP8DRJ86mrvPN}3Yme*e3O1OYt{P>x~;7q>fTB4?M|n=j`Ps7>{P1_wW< zSCUiDL34@cPy4dg4i}8df#xBP6Pf{;lC(jfXtFUUn_u}y(APE*issjl|CMGjVg57< z?IRkS`Ele>w=l%lr|l@-H=h&H_hSb2D1%{+4Xm zg%-!C<*B!~$5-QTmmYCv>`kprQU~K%XVIu+j}cpRgE5`^;PPkoEA?e2k)xSLl+rM1 z9Dnb@{$jeltx-94DG1=#8DMUfaXL4z_B&YEva#ziQQuRizLS%X)wsGDV}`{YCXK{z zEi@rxuOir0BfOUbRDLnEVzf(T|Ke+l*jwpj7f!+B#iPQI%2fjOEdus6f-`a|)&ldXfXA)wrK=M9W6^&)>Lqcye%hKaTDC|0R9$H&TUEQDdYf% zVlyel_1+90a?bm5xe9<&Cyd}>yV?~vS}S4g*Y1&TZ5#T8pfUs0#4jD|YlMPrwwi&-qP?a5A$5O`V>Pl+ z6N1;45I;Y1z71Cr78?*^kS*&XDiW;k}p*lD+ZV8R5Gb;U0ZCQh7dn;inlPxF}AVCw>nCMc{LP zdr7RsC62;rLgxgH zmmHZFTcUB+e64%=G=E|Y5bWN|eit?JM0LM#Xu9;w=_T$dc;SyHPL1S`PPZ^$gK)CZ z^R8V7-DPr4@80-jV@Q(r%m75O)=28*>~9bxF()CvBMcQZb;;#zI;{Q%eGYW>de0K_ zn^F^!H`}27Z^_$k-dCZsm#WS{zE6|PIKG`ca;`_G5sPaT!-g8}bOjHX{BlT}7v0nk zrjI#8hcfYT?Bu!S83??SP2588pz$}w=>-vW^I!+&2@vfrZ}j(T$W7TC1<$CL;JUm2 z@2pUdH>ueQH~@ed(*IfRX<=(@VPxQB_m5*ji7I`z8=?q28G3iSQq=s#^8}&!e(<*G zC_qs7h9}yUV}xzDmMK|TNrE76FNVoTA{s91o7Pv?8Ekgj+|{bD2=D$j8<5*w-Yif$ahX)YF;+;k9)T&foVL`L}oY;s$`{DAz>H5U$wWQC=2M&IHH!r^0 zVwgB*RAyB7aX*(nl!p)EW`ho`)Zxz{e5?4pIy=7q40BROW(d zPbOA{*e<-J@YGmy78Zk^(xy zAx$Z86wO6Rh>gsLrfZ+vk#ZC}sUWMb-6u&gfeRr=k`YaC}r~ zzcO9@(KN*kADmC>ywaKNq~Ca9>YXFh&%O)7Z~Y(=h{$a>Eg32%{FPR!=C`@Z5$|tR z?aq3o^I#E&yRSj`2h6WVQb(U2g#0yBaHhkWf!{A(rlA@aOs0I2;W)RaGdsnvV4K4p6Rn2Xa6xBW$H;a9NZ z`@{8>$_X7yX!$zYB`2BhC=Y5|0guwsV>QXeD1It$XU~>T`-Y;4mG0mj2VL|V&q5jR z{jcb&v(3ird3MQX^cfu_F^M_d>23|plQw7fuFA_cWKOC5Q~dX>!+Lgm2biVJW|3)?H@Uyr?bfJp}Exd)~>dXOfq~v?W<<|n&k=^#*)~yX^1957LQRa%CnylZ-x7t z+6H{%JDZAaw&$c1izbmKF;G@^dLDpu+!YEEQ2u zKt%);BoC{%P!r$zV}{hxi%fVg6|n40ACk zz{36iX~xe*61dun>G)jOF$U1JP-i|cwl_8T=n99-YeE}vyYprKV3$_raN$3<_%daA zg*=583_RRcRfl{-WV^euaQ_-$fHUK=h9ss^M;(6Hqp>T7n;`yjkg3^mjLYfhp6;^Q zjHbI-I@U_%y|)-ialM?sXD@M-)iZNIVF({TFuc%BE;4W#`AsPZ^qty!Gg3jyLs*s> zYGt5(l6KMvvC!OqSz+baJUoTibosFyyytMyoUhipiMHYU(J33)kumpj!v~v!@z)~C z-o$tRd%n>1)9twbH)i!!_w$&wwy(5Hb96z8#wW@*{=c7$m{#)T%nzRf^51r2*#75F z#?->Z+W04`PHKPIZjQ!%YdxT#0y~7Du?Vqp=;=-YELXqOwyus8&WE+pWTw~rB?NG)cgvty=WvUXHdTpXw^i8OcU zyfW%iBfB$9_-RZAFQobThVO}FPwkUj^+wQxv}XwtDaLI=^emja?75ctvHMw*DTyC& zr$MC-cLSvLi+B;oi@)yD_z#R_)I`r)V?yDej+gyW1YCW&-T_ zdpwa+v(p*GACkXdN%Q&`t_P7Cs%E%tIrc^*%V^#Lmo1%eL=@4%I4+EISBpI=V%ed} zmgR6VcKy+ZvSPKJ^1t*$5z1kq z1F-PF0ddao2AoS!59geI%V$`ngEdw#rSVHK?dn|cgY_CPhFEp7iwh@{BdWKHt-I6M zZpht>|E?;gNPZnO$MrHtH7ZALY%>rf8CVWovP6;V2`d(yAgHQ5z)-hAt(ZrE&uP&URb^kfft#+4@1e}Qoed2FG%pYDCCO7+?Mu(1tLyJ!luX)0z76}pY&d>db1 zF>_1sjLF%9;ARiH2sKR`R*-}{ydy!>c&3DBYJ(^e*N5Smz!YeS$p6@@xs~>HRbXuY z$Vh`>%mg$ z@Z38HYI@2;m)^sC<#P^>gYR5lFZ=MxV?{0|`}xB^WEkI@r)u*7U;ULio9;)BmHs56 zQNJlt%$+2VJuOs9oAmtG-dr#MG~L?w=hci@Go%-16f(XJZA9Gu%FgFAEd2z-9u?xK zczomLG=EKJYOS}L7JfCJ2HuYlrhVTQ?Wb-pO$=iug4l5yf1^ifo4@df2rPibsE-(b4oJWk)*TI{BF8-`j{sSXKL@=X#pY!0mK zA|%kcr3faFmGpM5WsB(g%jAOu~|<@dxP$s~oy#mvQ~H zR9&;`+d1>h+O_H=OIG{3=VPYh#cUM>vP;IBvyR&Ei6WiCtqn^WnA6yW1Vqg293!{!=C2L3jpQ(D6?fVg4K zKI4AV53oIZ2{<5nQR5F6qLMSC-xvM7(R zBhFnPM#JyD(k)&V8oPNBV}(Rg2K(Z{34k@S$6+PWiybY+|DvSQDQ@tdP?(g*@E|IP zIL}5wb7+m+Z#&$3H+|e_!O#O;&-=sZB(XklPqHUP(ln5-Cc5vU-DOoZ?SYo{Bf(G> z#I4m4+JQoqs4Nf6BLPcacLbw%tky7uey18eAa5_AsMtnA%`&IJG}-5g3%XmO*n z%*-K2l5>Gc?IGel#Ux>pCi$(_W#a$>sDb-lhQz z+3C!a6P2Pt_vYf{8j!M~k{TY%vJNtp-{R*?*>Nwygi%?;L=cC{@$CpnXpq-R{U#dh ziWw;c@W7ZMmi^>4hJ5f3%5mNSkMq*h_UmdryzeI|HM=IvM-j~MZR<%_^{`E;!_9Mg z4X`X;H8vQtygF2T!9t;oY5m$n zehZ=2bK&VCcH zqg!~W_F3760q&~E~+!%o^ z*Cql@Zt9^hqpzq}>!od*^*Sd+L#f3Jo$LV2&54#ZCa}4M#f&6JwhG0yx z3F`o*hAc%Ozwu~Lby(=;kQdnRpCD8+VM*mg%9{lguP7a`XbVvGA%0J$0XU?Pb{fZ% zi8(qD(HRd4$=DAoi9Y}#=#Qg&Q8pB<;|nw7i*nOgVL->}qfvQXC0prJ6(Hr5Ioa@g zlC|0i4x6aAm)wt0PrLoG^`HJl3=B7CR_rB!o=|t~r|QS755vgmDH~NPfnY#c?t1bm z*%+}_mLc%BLERG1xKKOU4HK9(`>bt_H4%vJ4_? zFoS2B1gxx%=rN0DWt&4pI#o{);donn9G!GTmTgZ8t!7GV1vGmp^vuo2T%)Z}By>dI z6^<9iDTFRXdRNYO?T&V4M2G~hPRsKjh7#C)!Rz!IscT!lFDDnY9pBeYeGGhmAgx!v{Qb+gBpUYIMSw0OdTXiYUx z*`R=Th&nKOVTj#TCCCd?g+z6T`~+w10@LOMH|LOLPS zT!%-6jXDA>wP(xi_vTi%UbeK%qv<&8zSELfO5v$=S1@3Oga@JxvWt~!HTB!*tE zykO3~u{{Jt(-^GA1A$ltZvfp`UrA8$sPE#*l9U@EO4O`Dblb23*^b8YcRj9bVp41B zu)2a{8sCzw>E3XsxT~{Fn;8(*32l=W&cQvx(mV#{P%vV1r=Y1{-xf7Awh858{5``Z z1j`NdzUgsQcC&mA;-pc5EFV#gtek;kZD`vxHbfS>6jeYtzAZzBW^h@4te;rDgkpU| zhV03Qx*Q3$Ava_pI~}ghD~G4#?{j&S@No(LW$Mxie~sO`pqsk``j7-J zL)9rZ@j{V$wzKmJ)fBp+vwItR=^H*}#eR*A^<09AB^-nm-KSPW1TTPTW-UjK+$lm4 ziM*f#QhH*PI#J5Q-LH!LNqjEa61TXQisHYr&}4;KN*Xyrue^X;NWUE7XD~_3cxaIP zF0!>W1g;YPK1+G_X$XThr*SJTOZ7zkG@M)R%u{mKlWaiYg>`qx&~^c}@S8tN? z#$bq&WEBOe8S6^O-!L4{5@oonypfIJMjk}NtKg;eEa4bpv*Nn>1D>3EBQI5#_?544 z?|W{N`{iV}BaC_QNH^hA3)&gHHUlAbmg)IGqNW|)mf)eOi(cZX!BC26?Me<2yZja~ z=**@#wCifkKm=YZ4(ef;MaBBM)iU^WTdq?0rq%~B9DDL4WA*#z7R(5EOP&l=?ng^r zl;r~KW^Xh8EpUe_xh=upc48EuzmwIo@*(iHsaTYcd9VpxCIgKHiJOz8s+JNQlDjPq zt)KUYRJX`J8J1z_!hs~&6)!>PhLr9QdS9FiHJ>`!hqQXn}6>qvNSciMbD9SCva zZmQfF$hRAIJz(1P9vogBk+Iv7%R=SkD}%=7uc;y{$yldTIsHObE8 zYm$DK&ql6R)($x%@>Qct5k>a{FGdxx2VMTNSLF?_5!jD(!vUW@j5O@0s(p{Q;b{x2 zm7?t2d9voJa+hTT{PZr9a;7(Ac$daNATDtFpr&idol!p^l)1{lX`(jItoPtzlTn5)tI zMzI|ha%Gos!*gpN=i~PNv}08ou7_O~O~(lh%BIkbja`D^_pB$^YPXh7msDX4{Li65 zovzrSrnBYkHO{T~X*8sQm1ew$X;qVFn;L7K+qcY;BTxHx)OP&uzjl|xraR#o0$Nz1 ztdmCg)oQGy#Cn_ln=kvV<)q_WZh$r(mv~{&*#_NtClt|WCJfa3%KJ103xZq=+);az zrUO_LH<$j9(MC+jtGRX=vls9(r?9x4E+1sI-CT@$e2vnzAJYJQVv|9D19;xhp0#_k zARCT0L39)SXsnEVE;OGw4Ay5aX^>yMvcnKA21(Jp6oWheve=SagaRd8bvwH?>tU%Hm;-67*FJYb4tXe^Jn^@FB$Ize|NK!ewas9T5wv&sxwDjfxPKlSoOhHyYs9k; zEyi@XB7$0rSk`OU=%W~Z6%Q5atym}$j)O?dV?4-WApW9#X$FrmfT~UcP%nUeHHQah zFJl`+W>SbyPqk6JbO5vl(e_(ZxK0d3Cw-xa!;@68b6hADo$j^571`>B$aaGL(ckar zVqsy+^Falq(FXTs(dnu;C}NyM6qWIj)=SlbYFl|)Nnw{~KLGtC^Eny=!j%;m^5V%VFG!2b9-FIlJ)z$m1|b;|Z>u#I z8+|BB<10&^GcVAaCTe5Rj{(@oKL9&iIRr~93}9)FwccOZlAdpY{u?~b26P@stS0h` z!lOyVMBENm1eLj5qM3*olOkOcUT4Mt;#VYp{tZHPBm$E5y>Sqmr!n#_2N}#Q8g_0O zSEZbfXs^g0PDMDskn33D4&Y0(J(+$1(b^+|)>T@Llwg-_rN8VXF#Q^KF7!LeZmW zD$6VE35y_w6H)reAI>ra_KP6?@^C@Kb<)p`rB{?X-4FqoUA2RS?o^Ynk1zXW1l@z`M72dWw5nC5mjRFwRL-ruO^sDIpwFuT(hY8dvV}B99YotL2O^vnQZH9X zyj3DD>6eag=$8PEbD5zrsAHd2km);P>1YgBeJZr%Qt#&FvGI#5KoxFYd9HGH>J)se zLk$Tg%BN!e4DgW~?p>_0eM8}qC75!Hw`f)BVL2>=4(KvtjtuudyOGv=xqrk}iut z=A-&@^YQ>4DjPWu3kxs1{8LsVCwIg5_XU23trm4-ez<w1pG6WlTg754OQ_HM0rWaOrOI?Jdyot>0(MPk@*uDT^Im|Wr z&P#tOEwwRoDY0_DP(@;v@)&hGO4UhF1>A}{6T2z?`VgYmJk<*RzCX+~GiOwUYtkv}jJy2g z&l2=uWq6|0NO_V7zhe;*p-qy5e^PcryfQ{nBHAHlsR(H+GCETyge)<88$mo1#=-}c zuvQT%1gzY6ott~Ha+V2SJ`QIvVPLl0zH?=`_*F$7@x{%MoUskmR~CA zmXz8VoPZU!$rr@QOAL)76lxJd_U%zmLgXypL~)jXIpk`B^!V62-leYjz8ngU4n!wP z#%Eu|vbj>Ie)7s*R*7nQ%^&c%swZij&CTZ?45(yxL2~H z^r2ZgWh!CXf8`#NaXjgP7da7hQQ+RMgCS|r&b>!GDH4>#BYA+V%(y=QOs9JIB6_-U z;M$7LoOD0;CoBu#$YUmFI~@Dh$xcoHD-DTrZcXon*8hds3Agil$A7K_}BL zfa9&RJ23*b6diNp1QuXC*|0Bv$ISrN42~12zp*lSNN5!Bf;wqXM_mNFhwZ9WeDHeu zk$K`wsbCyc!B>65{+qzAy%wU^MgssamHh8|KHUFH0{h?FZI>E*Kb;?>zcf5Um4G{8 z(S~8V1vHvm{4E)@K%1bUg)b)om$WnrjEHIVzkZZguf9F=E{q;=uVvtb6q>CkWapVb zF8(%>nT@9198B7mf&g|-lt_`z*M;b=ejxHja(u=QY_#E>l%Mu*Py-Xw^4|qiXyLhT z5%~F{;oO5fs-wss{zi59bDtVWK`>?47SA0rhlKIz^!DJ8mx4K>lJ=*Sn*Eev0f7OM z7*2vWg#iN6V{*^V>_&EmPL2=}^QQeeQG|{9h$!!2GPC**-DHcl7rYZ~v z+)%pWinoPGxzW8(jPS|rB9DM%9J>}qv5J*(9sPF zu5W%;NDjrxyq6Y6*P^HbUF1+>Hb(Ix<>#o#({$G*t{d zFx4q&k?wsv;8k5T5TJA0_xr&P!hX>o6eiTA7#KQWq59$n>@$wVbWKQ%putsQfJVt% z_du(-T7voakU_lqJFzpUtUM3WLJZR<8ZguyMiW3C$rid0G`4MatTc`YR7D-yTL4tM z(HoYFpf>}lRDV~1jN$6!x##_copjp)U}#gXkyaRlqMfCG3EOZbUGt?{1KdR5GN>dB1MK`Gi7h5%Ke8G{Eo(!+8t4 zjTnrp#8*Jliw7BFrX~wVXuIf$Iq;~}Q@Ss0+hl+-5Mrag*k?r{a(M?50yn;Z?XQE9 zD4=x%YAnNQEJdjt`SNT+97I_s4AK>>3Wef~)SYxFV8PQONT4Dgc`L71-oGf9X|p8e zuN3!R>&nlEuC`!Tn@qK}br&Km&ok;wOtc@ca-}ru4nJvY@wx^~Tieny&@-sXco@nI z>i0it109o3JL^kS?tVkQ%Rq8^3cJ`2K68qh8Ow1!Ha=D=`pPBSf;H0MfHO9_{JK{1 zQFpn1X51m>yYo+zqYaX#3Vl>9=ilb&i6!#y77a4phT2Sgvvv2E?Og``T_$JCZhiMfwlqoM zOLh3-Tme)o5MqEvCs->mfUVtQYOX!@tmt*r!p$a-?h033RA}Zx+lEG15~5ohR_NCd zR^l_3x+9L4FUy^b2?=GiPP*vaS#+rNr>lzxAWbnNu(d<>L%^m@Lt-<%zE zl@z_GggzzAqJKUYkzecx>8^pNaC7`WoSk!wCgHa3r)}HQwr$&-Y1_7KyZdX~wrv~J zwmEIzK4SwN|a?_qd0Xl2-O)8CCBVy}%l}Q@jZ@Ogp1` zVFv^yqPPM1`rDy~=s#;>hBVTht%$NzMtZO!!L8)yE#IRdDqAq zfb*Bc&zL!RJg+}+#lLbRV?E8LE8be6_t_MA;i_6rb-oBeG~gpmUa}I$sY03eW>53* zVkA9ht`<$Wy(!1jU5_;QNa?lg177>WNY`C8`m60GZC}7@Z}Qu;`j;TaK^R|Fv)pwU ze*W}oPi)8hnD7BswDsdB#=r7_0_z5!?C;^Qe%$|*2k`yR^8iz08)FB3Cu2qiCYJB- z*->h;-=sp*+jv zK!u%U$Q(M8$cjT?XhKF~D<;Z^F>P8S_ryxnP?38=f0;}a zwa%bgs$ZxY|NK=eZLKrI?mLB}dQDl&Fqi()Fb$%zo)nAPbOZsX9%J6fcR(+$JzSDi zXoLImHdX8lm;brd>3w(Q&0|6nVVbW|VE=rQvS<5#_|-E^j`*1^7%hoPuQE)nDSZ{B zmfCuL2``kT9V31TFX$as%G6MS9k%#{9`gQX;R(aLdH1s;Q}-v{0~#N0Ggpw4T6bXN zM0M__Zsa|qwH=O`L|dvyIUJqP{6S-?M+hhWn8nFc+dM-b0Wz-A8Kjz7mcn6ELPvoX zzrtB7DxcQg)#S+~GNZ3LAHihzd>#jSEZQ&5BLY|W%dKI);>ML&M4k26pKx!CBl`T< zWu_eB!6DpUierTHw{XjJNx}uKRu(QlPAkXpJ(tV>2FJ!Nl3q(@2FIp1G4eo9>Go;uQt@MV0Og%37%iee~Q#pH`YLi{{Ulvlo%1r=_`1lEo;UzD>T zc@gghTlW?HyU@~AhFw6|7{NCWD=`W)5;`)b@|`q6XBT9SW{$Lw3;bKsW48^;tRyjN z1zXepb0jwix5Z;3y0rTGvwzZCw8B_6^f`xcM8@_*l*J&PqBHSJHryXMwvcXt`KncB z7Jw9){X5CpUDV$0oML$Row+7mAc7IqTz))%4D?9sSFKoffq$j{ynyq*yHkuLV>{S2 z=c?CGRkyfZy9ezpKBrk!*)5^pWQ9Gn?F}-7=X#Z@zzu);-@A z9c`^Q$8eM}F)3oVT!dmiSHgWAVz-|4ASgjCy;VEdhgk%x1+pgW0v9bUvz8)%?eJ8} zR&R~X&c(Y)%RQ1}ywO2u2{I8%L0pI_I~|ArH|;4eo=N-j`{AplxTq-cK(WT`atqUQ zyL%g~1+K*DimCy0XSu?mWCt=8(%QP3{+epFb*OKH->4#|A|%V8oNB8=bN?ji; zR1Rh0$ZRq3hJ5k;T%Remv5>dI&CM;x0)|xy^;gN?82v;}%pq_1o1X8%v!X!V>$hY! zYVC0Qq&>7mY1KD#eW>ZjMr)wHRL01)b*`+~MjwOk5@#Wy&8L$;T>+hEkSeEL)dc{#Rvzsh^om{@3KUK<)w2%yxh9I>^FE;Gvg4Ln|bnk81do# zzVTMEU4X4d=+UU}Uk-gYC<4MRO(bFpARif<7+~AXUpy1513E$Dx5D3l7`tNk`FiQR z!_fx0Vh|oTXeom$PUc?B(mHKq+dcRDf-|v8!P+4UZ(OB7O4O@0&YjWw)@!6Jj zV+(`YzVptTbA@ppQiV!+D0`oCdY3S>-x5|-C#i0hNt)hHcpX^XPlpf{lWMVc7%mA+ zESEW~c>oC%l{$}M4+tii^rwUg#T^<|G=b9(Th>vQs0m1zRx~LSW1zNv2I;>E7w*)1 z$dSEs8MvXUl#Nuva0FSBpx@~{PCXGWJ{xMh`ZzXfSUhu^ZFGVp{)B>s!ZW@wz6PX6 z3f+{O>EA;~OYolIiE~RIgh-jbGKApiqz}=MzQ%@DX7#2*uj{=vOWC*GobGmxFG2>- zcVTCN80NktgsQE2=J49L6O^3gmIJ|Dg;Xk5^2L?_3W44g`fdYRHyEbFJWr(eQ+c}{ z@ih{EM>h%N8VF+&<2?PC+F>nCa>z{4w2&P!OAbsf@)?R_4+dtj=Mx#5-~i6aEkd#D z1Kz)mrpP8Q!&x(OHeO-Nf-Kx^x6KH#u^0QEcdJ%tW{s?UtmqoW69fxxj-P}W=0QmG zlihzIComfZnM4xQ&<`M4ycCBSbCV%cZMU@-2u$*pp9m9bBWX&3puAiAE+V)YJzM|ugQ#C1Bj69qsI3W z8%=8`K)I(&_)2=U8XF+^$+Ko&9mR7_(0}P|iJ$jS$}tk7s(`-y1aDri0k% zBmu~$$fq073H)gT)T0e<%JL4!UX?>K^L0Mh@nyUYbM!f(B7S7$Ke48lYS7enSPs_RQx z_|!{g_I7j6=`KC&X1#~=ZtW``K4(4aFH>j8XFp=6j=2-ZEN(U;@Na+;0a-*UIc zQ=<4Q953b^o=XM&2N+aKJCnV5{#1SBY@(t|YQSnr4q)MpZx~Rv1)ky@zp^S3-I|?+ z`*k&x?m~K@#o?C?8&RFc^PAt(7o^6*)Vas&akmR$zQOZSFlywwDSK_zQdg&I#Xzq{ z*fVOmAu$_Q3_f|;mgcc~xwMu8Ogh5#BmY{sa1gKP2kAV8bW|+kZ&G()ov-`LjGZxt z(t^-)e{Mjow_fYzNAv)rhBD0sLe=x_!g5tA9%+FyUhs#jA==SyG}2^6T^n&Pm76hDRb8~hFxed5Dmv&{!-+Y!^aks zD=7`TNFizMWp#`MjY5sys|_+SNe=_)9xP^pC1F+CkdAC zKBpVR3sByh7)hPy%snZUf~wQEpw%2Gim*bJC3qKQ)R>Hk>tz0uzPMh5Wn;veC{8b;qM2LvMI z`x;EyxihFou^y{Lk0rain=;i|bDl5wEr6#@S&X{uPn(jXk@sip^;Q~GB4NdD8VBlB z9?Wl1AYwMpm|h;r*-Q@GU;fhf4tEvq0xjcO&fZvb&&zWZH%^QzRrmWHs_1-DW9FUeQ&oAdMXEmx6%0~=0u)Wk z2y%M(Tnw0ZP9`l@fEMe%Emp?&M%Gl*O;-hp%kZ#CNNyYdL=_6KFdt13+Q25Gnjp0% zjK-!YlFHjm=LV;3KS{7RLhPgF2z$QutjAZ2C7uO&$DteDD$(Tes(i$5bfm zZz}&nDLbwQUngUH{S?HK$p(GS7=auoocOr_O9EYw@0B+Q^5>k>>9(KOW7Gfuyvr8O zLl?or7DBc)y2Nz9il;m45+mpRAGl!TlH%pKv8>S5kWlGJlqUsMtlz?5F>FyjJLC7BFR+ z6XT;@U@>uwT*9O>DN#JIptCDm=1;0yXQ@OOy7>5Jdmlc@((`z{u(}gE6h$u!=Geel zK|7IcYi=8zU3v)l$DPTcLz=2S!n0?Nm?@x$bbEs=9QWDV zjpJINO3n)n+L<`6-h)1NPoS2}Xi2ED(9u;CdXqmu2Z5#7*?)qtQjyfiAti~`OjnOV z+QT*%GJGT+-xjwsoGPcZf@i7YPjy>tAgvkr0x?EV(Jooh1!WFNIJ9ezV09ivnqid_ zN$t_5drHOYx#A^mm=Uy5Kmt#QI^POm)l?+6g&l~5sra3r4#PTD#=sH_NaiLCZdS>> zFfq3r@v*FQW4^>ur%}!WY|{#ILXm*NczaeX;gktY#V(`m)A?5eU16k1P+^7ibY9mj%1P+jr^WRClS{emK(O z#T{G5pIN5usHYqV<$3N73?(5wG%~kEdY&Yq3k_qcyD9G%Zo$DdTR852rdQx5M-#!2 zhRO_Z!+pdxXT9l1)a_y5q*g_vxo*_QI384?{8$O=_(_X>Hhre?#!fN3GT+*abgFF zrx*LXM2xv%xc5)b{}?>y_8NM)JVM1md8bP|xsi2`mG{a_Rh#ILL;>UT3L-qt{9vRv zo7Ep^mcSNm@%gaK_a)b1&(8^1@zn%5Nm<*+m&d_wZbUFzs?PA-ahSIG?TFDVx3-Ec zdwklI>p*3w43z{nd|iIGuL?!nl8vYZ59L>NyKz6TKJbU&EZ$qfOQFd(@sm}P$4yw1 zQS($lWqC2h+NZ)+XXo#Y)mh!g)i;FyrFIsZHI?$f~e`=e-{K z2nAj7b-jHLOG7Ux(*q7(Jkg3{m|1rm#lsAG-t1P&UKRc(MorPm^Fcn!etXSJm_4-D zOumoV??{sbH4oH(_@z&s#++UdH*;l5qvznLqT9X1*qLNZ z{gsIg>^u_TIQQ&uaSvt2hljx%A*hVM@%dh#HD8|yPxt9qaEE=&z2@>Y2}@M8GmLm7 zT$4xZ&#LthoyR&V#VuxB3W~jWLJ^p0SHHp=M;m~N9nu&43X`nc3lA!Lk)h$?CNg(I z1tz!FPx1&O#uCL!-yi5J^JG%VA~TEUEI-$N=_|@?4mKDqT^>HLHu6Kv^}L_^VprVH zoC+uRnQ2s!e{9Tiv6z`8B}|@pIgquG6kuzA^wiNK@4WblXCwH2z)+5qGQ(0PW3ztl z4CH$<1zDNJnz|U4m>YHTrOR#3h6by9IW0ty`wundb>@22MMF`$D5aE4jH(pnXZ(F&Y$O66eyX{?X!U%=i?ap2V z+F$i#{+zHjD6QmH+mA1aM-LHet@UzpzaVA5Cv>FJ=I>7^2WyNbrIQY&=0?LbV|TK4 zF}(hO5Y}n^F8+)jf9PQek~(JKYeM>H6b(=BgFunbx*v?2D#v<4L~;$!_Ah3wvzeJq zr5Z}tKOS`q;Qc-*;;yNcAc}B?h(tw0CyY~oe=izcsUigb*Z@YxR@vlcEc{DD z)mEV}*5Poq)$E53b%Q;shiTlZwSHAf{FU?F4fu!PE_spCehJ~nkAiPa-M^>7aQ!d4 z2kdMd-woFd&nX8SNrx}257aiElkK0HvH^uGcgFw-_@OzoHezbAdkn-%z77df}CWlOYO2mLRhPW_fGRTE;I^{T00B1jePL^(`k0+3F znj!9N5yqRsYSwiEyuld+_@1p2d&cNU1caCXQB73ztBB?qcAPvDGZr%$ z3(_g3fI=l`6y^M7B(nrs;U^Lr!@H|BHQa3{hyZls@qD>`YnEQk;MG8tX&iQ0@;K?EdJL)N1bk%N}3ZV!s;i8|Zq|jhQIlCfI6u+NJ>SfH4@>!51*_11j`zvD} zo0ZC9N|;h3MbRcK_=&UJH6WR{LpAmrr+KNp$_x9>&&nCfB7i4Qm48E$LbH?#6xf%) z+*cgyj#vd;c{Wrd%bZq2(|9mk77?h!{~oitEKKD24ho-33q_U-IxXeRedZayrfK zdQl&Y&FiT=qQ_M94o!}#RJuFROo%;$Sq&#wkTQinhFEAVf^Lm-jMs5#$z882zLg6f z$jXaV!}aPD-V@@3w@aU%LhiCb$Rb2Z)+RPs-_E5Lg$%v@>1!-}V4vn-68{T9Qy;!F z>^DC;af_X+djANPIUNZ!(6J3r!1TO@NQ-@SYTRMjQM;o5{ZF(S2mB3VD6A%(GvSop z1EAJRuOFnP$QngeuDF8t;q2QCN$I^WtII@x9hrVGali6{UZK2ys%x&OV|>BtR3eqg zI)E25Dw-L(R&k063_u6`n2HzzS#5!WSE!JU*i8mfCv(rr55dVZQdPbncI_w~Bi;(@ z6vKlsY3tRIYgBYL*b!!s(D!n3n_}zfLCB)j2WLqL-gXvynT3Vk&WjG$P|)OT*bnSG zme0c4h_0!rZY3yA4rqXEEK7RJ_dW$qgH7$z+sgav9rmY|d8%C9O7wlqbJA}ry|XkK z5ZnIn5oS6wE>gz;b}}X22dSK!;S(1i`w%H3Nhv7-`r^ z>dX+B{mVI9NcBj1ji4E9IqHtT8_3W-acJk z|B~%XUyqD0sC zg>-R1Pe4gJzet2rn2TBV00M=>m}f->n%t|~e* zET!!H_1)ad0dJ%(F{moOD%bR417Y)`-Lljz+3B_QN{2hNwUoR~hAj&;37`N_lXfVC zQ7vjx9Uay`gSfQzKD2}EIJY)JBT(bvKRqpu{&+tHUHfv|&evlA*f!3Twe6S6m9{M) z&nd2Ma#FLeT7jXp@LuNbJ?3{IE%NMcnv3GfX@`T8>v?okTo{d7rI4(>cg^8=9cA_!yT%z z-6Fc{kah}n4pCbH$wli9(;OWTWx`6{K!Dl_XZ^4iT&BUlZgJbNxm|63c2>T`U6g_d zCR!>mazFf}rM=#Ky}|E~cvzi-wJAI9KZy{L19(>`iGIu<~-af3O!*g2Xhf zg~@U^;x=r{xa{f(SrEe+n8_h>!|=!DO5^&ud&|VSpuyy9&dPMkn)Z4i*>Edq$_L>! zb10oU#8q)8NsA>A-jY$r6`%q|$3dZ3tg5dX>Q5Sva-nX-&rmy6jIXKqGpRN4E&O=0D$g|=mI zU0TbhqAZ_C)Am2o#3sEgd(lvhWFGZ_;Tn$0AU z?PSeuGsH1Ui6(OB`7lN!hmPSY*U$c2JBwQ$-|5ShO#b$h4DRI!Q?(#kuS_k7$} zwP6hY6(R&}pq~NZ&Q7rlfI_OK#Sp!^D%#QcZN}fT?F)sJ&7Eki2B{TPA`JFTPy}Cs zZj0v;`PRKVoq|@@DT-m}$}G|p3~7-{X93~%ypkI#Ob_N1dFDVUs>WsyFJkP}b1hD; zL)79wSrZ+m#Zux_iWK+2rT6{d-E$yh-9=}W_Rm>Ch`Qpnyzibu=Lhjb&ZGl1aj&Un zo$ABkDjw*rlFhg8+mI_sYpMDIBu0-NC2Iq^CvxZRmb9-97uZuVV)}{6@YSCUZK%5~ zX%(id`h+8KG+)Zl6GSK$(4TLv>hV-tdPAH6qhSnkyQnV8pLa2zoiG7?QC7cZhLFns zHp~$YHLJhRNMYZ*`+YUiJqthDe|OaoR5gwv%V=tiN+-~w8mWS4c#F$baA9@kp&Op9 zwS&${gO5iB^ciw#9`AI`7NyymA$2s?e`9rHki5T#tL#K&S*H)>A8NLJ={>_qJVT6j z1GTk`h)IKNIfHjLfNZq^1wtrUJ_a0IjB59QXTX@x1Z>$|FSjHThbmJ)JJe#fc^}2~ofir>-ocx5#?8kb4t@#4S ze*6*G*ZcdmQN|NweeZ=4wP1Rlg$1`o%Fw6uZr0We)Z_iiV|A_ndVS61`GV6N$KgVz z!L1<(iyHz1w%e6!l(qR8ls>Aa*=H)cN4ibru-e>koTWlX_R1i7R zgU-RTgSKgxY0@B`{^M}K#2S(L3A*6aLc6|g)fJZv(dTwLKgpxvv77zre&SMyvImT@;PpFbJ|+3 zp83~$m#r?79(JG5m=w~8mmzU7TTmvov97v^LfI1HOb%X?hd8kVUz>s)7Vi2V)N*?b zN~@_-R`~s_4{r$8JX~_WOX2zodlE#9cA!L%zI~swIN*cZO*S!_c27lwMi4I zii!Zu8VW8Cue%93HBU`8G@8^~j;d`<$eWx$Ae($qk(%1@*yHc7f6L^?C6F*|xzX)P z*~l7q8Nco(lDNwRckz-+>bXu(#UiCW)97t@$kr>O(9rx|-40zzwxRt{q>zc;6A-xkTyH-p;{e=+8R_*zGfb7C7-<;`PVbs(HBT8Mr zR=sU-{A6Gw{V2`w^a~DBr>;Y_Nit@uD%!8vUOOukv0m54dfWS^^`zghk#fH_&`ml` z)3ye;`;w>4pmg1wa4`e1di2rzaSXttjIIj-D_xRB)ZCI!~Iy!>5E;O~A(xUYy^Zgt!at7SSuwY}G| z&ErJlENnh4v#vkNZa1R)m}yE8i^8vkVOcn^vYk3v)DJmf&ay2#UdZJl=|#HhJs$nt zyM@?^u;Gc^9ZJ!d*dM28CTl8l+)Q8ZBu@p@SjA)J*)j=f8AGqrr>e4zra|#^5MDrcz#Bz)4VF}m^3wsxCKkCkphMd-9;gQBDLad zeQkSR)_gvEqR3nqIe_Cc+*N0ex|6JR;We}g?fMu`FCsPsG?KL?^kj1{^{*p;UhBJV zK0FS_K&qrY@|c)mz^Q<8tfgOwceg$0w6#FyR-#!`1D7&s*DzF4cY%Fz)RTCWw49@a zTA6nh1PE>-n?*b3nmIW?oR@sP*Z3mLRJRW2hSWlEtnHMUq*(lN$9zb^uiViNqkPHT zwojp$z-eqF{Hh0%8eBXol1lPWG?$TNpEk%>a)rTU#o<<-t^BA?@xL}?^l8bsRBYLE z5Su{$eEfAJm%@CGIX!+4#&4in`anSwQf=jQ_j(519!oY^^Yxd&MVxKsxXV?FrD`{x z@0Tb#HcPXNWObbvEI7N!KF3wYkQ$aYE-i$qx+B1$3OO4sE_KJ4=hzqdfAK3>e;P z5*Km4y7TPVkF;@Or4C}b%i`pIEKX}W${Jh7W8Igk-)k^XDfGI{R1S%UDG5FsaxOIL z-2k}|OIN7one7z5!h|Oij+DhzBMx15tm%jmTH{a8#McQI{03eqx>Zx7AS(_`KFNmG zJD14E<4EMZMtY<(`VU>YB$}JZ`hx8iEO%}UEUt^EHxu_KzOfdP$GiG+xJrJji`ipN zt*P9)fzWg2vC+%yP-J-y&2=}Bb$3EVSWagc@UGzYA*Rj}zf=Z%X|VxFx|bFY7YNO8 zJ=F~G_%`8(*q3|a`(*=0{#$)#?_thi=$Kp9LLp+KQ{UC*_8N=0)L+f_ycgBf>%3f> zz2%+?Bj{#~_Sw~M=fu}X%jvG9nY|jy6i;Hp!w>LWRxoc6yMsj(-j?{bnoJF`S64u& zBfEnj5ke*C@HcvH_*+cy@0(qM|C45yjk%+fu_3*Iv5nz3 zzShC=Uvh&*WkLCM8B`um-ysU}H{u*PvTy}+1gM`XWui!u@)YIEkB*)Ff0|rYRBVQP zYnI^=&Acd!lwz-qx1vm$a6~zjRSSmNYr_!sky5~RmGm{%h0IY5G*Zlb*=CI-wiVIq zDf%&l6*#R3VWY~Or6g3v5Wy{-#Wj>d3V}wf>_2lWHMD+WkOoJo@^l?q2A~cry)GrxMTN^2H3rXg3YKS#mrF=UYy4#z7d4I% z3snpy;2~s5O~b(pj5`N{!EBISVw_2ido+Qf%Rtkp&MXNcn9N{Ji6YoBNoGj_wEXmx zOkin|dIL(iECz9o`|;@jIj?c*=e|JWxL+@tUBN{;b{!%*E?v#PQsnIC-GXN@4A)f3 z8|OLvSECpZFB1v3(!yN`^|`JAXX@{m5VX>C4{^tV4;NzR+GEgZM6h6&;o~N{z2Tmb zLJ&05fJwv$1#l&}kccL)Nx+tWEsWX6P#Phxad7sUKexD_U*h2Nh+gF2J4;NL;VKLL zaz^+wcN) zX|dS2OljYiJ>){kN}_}F7k2+Gezwrgw?6RulXZ(@hSYW zMx|B$D%xU$_(@ImD*o+*iy!ebG1*6EU%kZl|I*GJTOND~ztK%{-&3#uen0+?jOhNk zA5F~lo#;hu4K0lwOw6r}jpC+k76ed(pL`;So67a{xm{$|MGWGLfy#xHNNK4_ShCxi zLt~EHnOD%=J(KEpO+Bw-yRS3#rv?~Tn^BS)>U#~vpGSX3&)bJ#sZH-X<04Tg0Y;6+ zu(FB#aU@KMiDCs&Sa1TO&D`^M#&Y?Dc8}~b#5lR6rgtjI2%zRE{nhYU^LFQO{tJef zbG@8#sUJAZHJ)%V;PV8QuFKKbc9eSPtTx%eB>5<>*{GI_=P5+aG-#aNqSjtF&GO`K zONzIV#I7b;K46bHJOtL*$3NBr+Iy{wcWR0ccDRvLyqsKKgYm1l)IwO5wIaPDjqST} z_&sF1LUUjF{KgaGJY(V%WX~W4X>QSlR%rf{H^hwGW9XB>pX|`?GX!EO@csTV>ESFb z?z0q8)V)A1ozilN8~5rOzkA!t=BeYs`=whVVd{|@UoAE#&UIsNK3=eRxg!R0DiEMrWP!)w-CnTY z_v1${(_uz^?YXmd-z@LZodXPhXfOmw`(~59q$U2Hs$?e#Gf(ZvD;ZT;t(Lsw!3t+ ze1N_k#or3r>0-{aEy?x23W}?zI&2UW&Xt<7+Evp53qxlEbA2m+p^Ep%zCssnonZHr zF%+(2hFutQ+e2#eKq|P5XUg020Od}{m0J(f>|^WK9kch-_suFRJ|}8x(kJQ|eH||1 z3~cY|TVOJVR9!1Y_i>Pgs&-1vbJMXSW9bdmDqvR>n(!=ats4$68hWDDJ~uji33cqK$GfOw;4EV0J^~_+`-?3gxCPbU^;x% zyOYz{PcItqQ!<_qUEw^SigIMfQVL3*Nkok!+W#O#UA4ku}x;tgzTD&A`g<7j&h5J0dSdUw%@Op*8_^P_Jl|fO=}6ul@?>kX5$7 zCdlcI@8bTBf(qc28hKzxHxK-y>dfh=ur*#sPVk)odqELG1{w<4K$n<5)RGKeP*{h3 zntk@5l*pqHJ%&djH#t5Zl{+L9ByGJ>XqJLzpPulVACiUzZB%x5My$FF!oD! z-~1-<32YXKROlv14%j~@-UV_b*rT||7{yh1mGXjWfwLUvY?D<`0MOXdhCzV%&TNdV z%lq@omII$wj~twAlzC!BKkt9@*hckV*iWuyh!0W2+E2iW#yg@^e-rssZy=n*yh6z-S>nji!pzJ8pKdP1OAK4i!8Hk>O(P z@bA-P`FjO^ba8P*jAIOpJHuFfK~i7#9_niU;m{d*Ua+sdbcgX@C*ob%FPz#>&QgIA z+CJj_GN~KbElP2zNrzf|?N) ze5XtPHt_@JI9ThatT1Jg&3tv_e*6egwK0jTo{jF>!w3fPG!xrl5f}X101`p+4G~9` zj;M8i8S8tU;Ftsfi#(y27q%dDXMLa1lFTR*%4+RsVBo`5pgV)!em3W*JVO zrNhCZJu#~K8|>AMl$$57?p6&3strppgHm@%umXoWge zmH`TBUO~bg>EawSh5aTV40NwGh{vi%;~OE{Cf2pbm0-J`+I$VZ5)52kNY$H@JA~)D zgZ3Pb*cDW~7-DrNnP|CVG9Aa}^5G4YAz^2;WPQ z4nQZPENAOgpoEB&L96wtj!Qv{8FYXHujzDx)@YbXs-ws$SOU@*L7-3=!~mm8g}q<^ ztbT-=>FI5)%z+?NO!qB2j%4!v1XIeJvN&ko8oe=7HqlWmjO>v+Au5pWmGjtCaOdsw zhY|;lcq-Enoz_BMX3nC}#j9;XI)=O)a10YO26`rw+G{u-+i6siqV$3g<<{5SXetyC zcAaaU0o-7qSuuOY2ajvi8Km3}Ka}nhn$CksEjk!0^loA_UjZO3Ok3yu2b)eEI4|H? zUyPB^B}@Jr54l08v6B&k{bxj>Fn&JX5ME5xZAl`e`$!JHM$4vIloMS%ABr}Hkt<=^ zchEg@{}oLz9b1mZPalk7@ezjI$saQ?D)u5)QDKQ3~lG8HN0YWU* zO(+kEaVF*kI{ly)ioeV9o)oGN79F4Z87*k$WX|%Uhrx~;3j9A3cBFm93MhOLl#?lb zLMaRCXjG_HNA%c1EJ0Q#aSTN%S~4x=B@_K7?aps(wgf{3+*6*YvCY_jDeyO$4i+v$ zc=%jGwA{A}QNwBZKmDKs{S%c-EhX;T7l&=PwsxAfZDp4TM6LnzCmEfiK1!7o3UJ`r zD+N!-=IN7|81(KTK)Fgm)Xq-Daaf&$oi}eEKVB>IVKUlTZ#=vVI6s}B15685=@S=D zNSSHw6wAI>$h`}dycF^;?~%h*MXH)?pfrxO*<>U?%w~|%{l%6kMXq8C?s}FT?Wh_xeem@e2 zI))pMt}*M#w+GkNKp&Q5qa#|E?jkJf+Kzz}FMmn%*&NWgjjdJT_e5^l`slmvXy5#N zFRxbTFUjl#hO@}Iv`I%YrJkJe17@lSPE}}+puF)-lwidPA%}6clWj#TE9i$;5;mE| zdWOG7-2|87@_1sygGoN#^qU=VglNyTz;FX3sdw~y(i}P=?rExK`lSqpk+lju$00L} zjn2d@2^tHm@>5Z*2z!1G0KHa*QqTz@S#4T#y9kHOTarSjViOE98De`9nvsi25A)H< z`d(`iR=}R4$&G$v#1&Ah3K=0B`7S28lCvJz1Z|`+F_Zra7RGO7wL3+CK?0-k`ZKmg zUadfU2(wX{;}urZX;~yHdy^t>5c7FmnZb}1R$pYx&Cw-kW{;aQR#Qf`(UMer363s0 zTWh~X6@2rL*Jb+qX-6lC<&N2vo)j5<)%^=0&f-v1c9#;-0FGz@3^(yxJ&SJOLJCls zHc~OsAC=-RpNxf%AC-$A`vU{~xoUQd;>K4M$xrMhpE{|=D<3v4rIPCjR^e-v3QZh1 zG!lm9I2xYb*hN>a&JX_J*~)-QtW3Tx`k@%-r$l0r)VDJ5n}@Iz^#;|J@?Q<;Iim*X1<#`5M#rchu-0}dL~0!_M0 zozkqRwUd~SUcc5~+!-SshT!f2=-xVn@~qDJub;-Yw#Hx7Eqi|NV$Kt84$z!$QQg#u zecJJit%fBXwh@I(n(YD$!@+-e>F8#y9EVZ_`o5ik=l0a}TD2GFDL&YQ_(+6%0rJAA zl%~K6BuqtVB63$t)l5=L_T?IOlA_J{S!Kne^Rtzi0rAU!)xc7Wnd$yigjR58nmt&+A^!nC`OXNqjz5+>q=-Lzl^c+h-r3M1Sx+>ysOnuq* z&?aELTP?@eD0sECj_4ASqPa%{pYjO-%>#6_` zQX!^FH2K^J6>k#>v#e5WJhvlQPdQu`$R)dxl_p^#BV(@DN{^GZd7Qirk$kI}-wU)Z zO~vOA8_Z8IJL&ifB%iaCsbxofsCttW9itk@*2vR(#K)Ob*l`3lapo~wZq=|hE`XfI zQiAmv?4s}Z$KF{uSvbWkVV!Yg{pRSASeqtLKhhMU0%$HNDx#8Z1E)msiVM?PoSL!8 zv}oBjG*3;RoZwDVkN(n0KJJ@NP0OKjZSvORxS(eI<)x7)9%~EPAqqhE7UAZSmey?e2T!LWuYDjj~gS~yJ#AI2|o0$>0?pdrQXCN!DAbSX<(>PKvA zt9DkqC~Se~kCay0L7=p{a_X6d#szHgS_rbOE;k`}KffeKC;@$n4`5Wi74->d>R}47%3sz-u$$5KMG`zQ%g4uQ` zJkzRuwatse=pcJn_nu{!?kai2+!G=Us!g}%@%-x zXRMnpUQM?$ItYdy2i<+2x(2bL_8TTF9fA6wL* z=>?Td+@`a;1{1BSvRaX63aX5(B(qSqK_g8A)Lg!E>gB$w13g8vOFP@|+BnL3*mjB% z{{41OrdO6WCR5m`H`l(OFngshZ>__+(x~B0JnFmFc?HMj<&=tlnV36A-MsyBKbBbN zjX0-g6aG|KbHCfcQBv`Zppr=)8Tn9~5jDu@ESUArCuufmbvDY?TCmx;(Jn9vXH-7S zdrrogcN!^sHq7I|Q$`P1VCN-9gKuxP2s*`6=m3B!)kMq|Hb2S0QO%olqM>!m{ma-~ zL`np4opuXcrR2~i3Zy4t$^d&V=P^A(+XCtsE{@8C-i8geeV(KnV6jcMzbnk5`{q%* zcjwmg!E-S@izLBwLj(eRn}=e2KC&zfsFQoS%*q~Cc>Pp?Y8bD@=9&2z(G&`9*-@$+ zKP+#3I!4KV)+Qr&Nm0^}N`M78I8`h$&)!ru%>;W^ zjBjr4wNG5hw`&VKk-ErrqB7}%H`9HR|Ep49pfO+V{5BhQBl%C2!vDI4vSa#h3P7fs zw(Xh(M)%`;#N825J&IufnyU9gy;AzDY9X6?xD!2k(Yzjk9xC&G%m{qrxUX&&77lDs z&?TDNkr&VLIp@M!eo+SL)-_b}x>_K(t(4IZ8}<>I)D*xUIkrSuS?)LWSJwzMoQWcpLLZh|4%Jl#RCi#$E zFP{yadl9BAba%C3_9RDwW&!(opJ!?xAf{}g{zJ@4X&lrmC{fJ@Sm|$IG_w?H8*YBy zgkcmq&|M~>0Px0T|Bm=rL-GTD7?k^EpuLT?Xi{395Au-C_HvkQvs`eXA6)^4ckk%u z1ISU@Ql2`&@~qZ?=&vMMx~VR}escP;R>8GZ@Xlf&S4hSlK|mYM;2&S8e)Zd5tyRmS z1V`^kA9Dk4<_sHDHnrsK10aOtvY5gw=k*yN6MP~KiO-j0y=H>w1w(QVc+bO7(f^0G zuMCc(S+*3D#mvlTF*7qWGc&Wr%*;$9wwRfjnJvj;%VOU7?%jQFcYnMeyYV8XYC5a3 zs;eWWYr0RK%#?ob6-^q{lH;XT9iS+bQ=|QrI&Q}l&*R|~1+cu&uT1zAr<4q(pGJu` z>?^U+t&_nwr8X!X8lHBYlO^w!UesF7R`H5LCzE;0CkZaW#l*DdTenO+$b4_rZ8c0<{hF^l{Nr8&x-y=uj{ zC*=1O{#+ETk;2uE#&`CH<76$ZNm1~^X2?W`TGB0mz2hq!Fo(8(il>MzM<;5{7J{-(ZWh-$BAHi6 z(qa8YhJ)mGv$9;DC^W-*#ArOO&ClpaG-4Pnd zhNRIFp02EtQrcjPhE*fG1tIdxU80fpGL3sr^4@ioeNXr}?9;{msW?(32GbG2iJHdb zPa=thM56XqKC=tmHv!405A;BT8560)E}kL6W)Nv$u}%L*gZI#ESZ-}weZP+`=eO_B zAqV^qWg2m$#}*MEM99p4i!$_af}gsD%AY;(s>DDV6&;M&f6=kP^HM+@yK9+79Q&sM z=ac$OzAIcT5)tB;+nyiN`aRbI)IyBZ_o32&WVPl-ZvGln3RNH7l^c~3qiq2J+Xi)B zJ-Jms!a-~f?sY(Pk5KKd;>+C%PF1n^zJcXlC>wu)9Tdr3_gdA;vWvo^*5o(DRMDYBuZDSO~-DAbLS&*nF?(Y7srPdKE7Ie%P})PKCD}s zhZe1XbiTfpsCD8>fZoN8;u#V-h%C%3>rF_*0 zwf+?6o_LKrS)eLRfS&KB9lHdyjU5ypRY+YeUc9=5fDcy1Z-$NMRnDA7%4ayO!25(%VGQ36MP`Bd3G20#3hx?(synXP{ZUEvAIGP{dd zOIygv82Q2gC~V$fIw@>?VXZ~gC=~<{lwq$W=!B>Sx=CpD6=O8CJ6GbnjD2ZS(ydM$ zn#JrDDa`UjEztx%*cpYePy8;lc3r3di~c&`9`p}{ktpi z>!l$5DtqLRiN2+do~lg~y6rpZ3jH+q!02d-cWD=gaYNj<~;Pdw@riwtgMvgIkxMuXQJT&p_0Ti?0?V z6N&WCua@;2q?H*9b8$FRw&6W<#klam_G+=MqgmE3i>7Rb)jnOd zsTaqqb<~)i%qU$~Nwpb<3!x~{f+Nqksdsh-g1M2Yj0t9xz*iQQ7=8I+!{dXMk&kwt zs`?rc5o^CTZ9z3+O3c?WQRo%d4sC3qvDVp^n1!} zfYZFL^AjKkc}nJaNVa|)DMH+0*C+a1hk%hYATxVbrJIX7?r=9pn_~B_+#b<-|B6Yd zK_lAWCA&M*^24?E^1EG7KCE7yDh3%5j9U1;f-?FTj-S9J@VYGhMa}ftv2xWGQ5I!- zG2&qzjEOen1@0T@qV^S_85XTDobdHZ#Nj4fE{IkAr`4_PZR}ew_hB{2(Ac_I05(y= zArm{;g+J|BJk$j?&=Ip{Mxp#Lp8s?r(b7J<3is<4F}ar?7CA=R9Z47_0Atz zIy#?!U)fQ`SK(<~v)D2vYz*^#h-6khZnQ<1mrF|Wq94n;vwINz`g{_9@@HmNJldOj zd|Uh?OpXU3N4w)w0M&s5i47$u{{>+fxg^Dd8@(_e8lJt6AbC{%vOO;}c|6?1Arn8* zPBCf*CsvuL@CS;_f@?ydrZAt^3{_?t9c5(Ob)X7bCAXQCU)bYHYq7bx(S{g`0}VSfs|eFb`-??7|c* zKbcAv!lG^Z5<^e$0v#-W34%5Y#)gKQ8*$ZeMR{jZfSScP_5QLF6ic~_woV$|Mu`ig z#<5Dvm963_Z3Ae367mf%E0}n!P?iCpAI1satg)BQ1TtDXh*YC6_B%!!STi@-2h2e% zvPGQ~nr7)F?5u+3)tTN8n!=s z*=N#d{MM|HRszsM`$O!iQIxa`7R$B*NJ9G~>?r{EbEXS^-ZiO7PpF62;R56&7Dn^Z~vTCS0;A)`I%B*LPGSB!<^UTy} z+wQc^<*Lc#szs|pd8$}7@Ca;~PfME*OPfn{;{Y4VB#4q`)AKS}I4sS~X2+*5b7&OS zGv#qHRG~t@=ZLYeL}eOnZ5#a^8$eUHD~B=W$T2hHn23dI+NQ!!UUK2%uon*rqNlKT zmtpJWrpt847Jr=c$-|SW9F=K3Q0Gd%G1gjf)xn zDTCD4#l}+k6Ga%unV@hFnf3b{$4aUhfF|}E&5KyVsIJ(G)_T;ZmPi8b6vPU4<4O00 z%EVGtR9~97=_z7DM2o-4+S1ZBrDC@( zh7>~&T7&rL&BAS zxujGM2#JW8!eHL)o)chUpJ0+XzC?aQM3u>}zvv0;(cgfU^}PqJY{K@Ip14cvZCh@$ z{V-}YBvqAO{t9Z_rTX@{hUPmXVpOv5xq<$JPEqApx|tN_&}Q6Jm46(>^7aQN8}URD zrUX6tBnEj^F!^R2yauy?vcOr$FPkJahIR=k9C|^0Q{*=A2?kk}sX_JbjuC5}_o~=) z9S-8yOL61U5Mv>aZ4`76NpTP`F5ZaepHS$Yq0u}dVf-4~C_J(m3;Vd}?qShgBI5c* zA~bZ@aCuczTsmdwWd+W!++_vwmkbI-_WGm39BC@AkQIh1uOq{|hxb>N(Y87rT1ak& z4bXr~STqn|WLkV#5ID*o635mKp|p`0KSZI08o`DBfPmc#LEeHnJ%dmOfV4Y=fe0&+ zginz`6k>zz58{HM3x_#_N1*&Tgei1Jt^kcc`d#51a?k*#qz8(u^#erP$}0g+PKJsG zkqtx~7o-RZrXgHHa>1O9tNj4RdXsZsAi`XnD9|K7ijn(`VG6k*_I04Z$Ok*3xG+J{ zV?p92K*GpCGT4woPz#glxyV7$Q$WCE_T7?hVF(|1zKdJx1>vY0g;QemBPE(I5C?-J z2_-=b{RRcQ3_|%9<$|G%4d#S^2#P!q2_*~>LHff4C9%ZduMksRBNrtiemqFDBnTKP zGBK(Gt+t!~H}7+Lex_G?{<*v|OY^Oi!M$1LwHkHXEA2TOz`j6Zp+I9lA@p--(<2{Y zJJvFlOFI~~0cg8P5J;obD&ZLYk6_Gx;imgJ{~kO?iIP%juv@>$L3RuAjmrmDWC zYo~*X6GbMZkgJxG8%?e%3csXzbD`{J9AoEi;0a!72?J; zlNE%DE*&=2WKzt-urJ+8x$PI%cpDcvH!iKrOhC+0jk zl@1Q_r5ezZ=5r>Tp3B$+6J+j#3~&kf#wQ%`E%#1$_J!f}J^eAvH6TXuIU{EeOfm64 z3$W*wyKe+V;I!@EstdgZce*@-eYx+LUcvuaxK7)Y&VkCV0aM(4<}S02-2WP|Ir|X` zR4V?@0#ppWpL=0Q|K#pF&fWVDO{vp=uLC%N;;iF~jR02D%X^0A^KnxJ_50ryzt3S< zCXSqsd*4iK)3^yvEgo_C>9W&+9hKsltOOpe-lI)rHr3>KrO;}Q96^gJH^cb~c~3~H z6P8kj`b{)w=1nt^bHycLa()qA{gw(+ljezHH{!4{QtR!Y9aBP_$+Jc&P%@t{oX~Kb zC&f4CneD*y!iCWfv|v5fic@%|^*@%egH)ISda+{_mdMdOsUL_~GJAWNra4&ddxdE=jqbWz((rdhl;i4(HPwsN z6V#Kt%KD7&E6qJ!p4%X(P#6ZHJuNQ_dKLWHl|p*omc53U#DhcYE|aA@`BQ*v<;cn7 zghf6Yk5JVMTD1Ew6Sm}f7XHs$!_U8lU)ForeTz?dTz(!=4hm}4JvVHFXqQ{L-hv2J zAea%`7_67eo;yhpamb>_H1fR>@xLtZpTaF|+)8E6FHK9qy6*=9*4Y+97zNfhaA$oV zFG`G`FEWuvsswh6K-wM%&QK1c{5}5ijNW#$;SOxsMmLaI=pZgcJd2El{CJ0wQi@}K zRvt70cOFi+OM$0+#!H(piXpf41TA49l6&BEErh?<%+*_wV!=Z^`NS)ei63rKd$Ix- zt6ntBnCQ=kvUmOdLZm6>mm?;j%J$+RxO1fmcQ*}v263Nh@cX(~{t~Hs-6)!JZ?>ZA zrCk>5@_0+*FnyBq=4_Y$dIFO7NdxMZJitVFbFOoKVB*^u5ldm-q8y~z-AAPEV>TW% zq7%l0Rkjz~jGM5>(GDnx0~uF?x*NDC+Sa@rjhXK*MG0$}m=ctATb_wx;Z0PO#)zfG zOT6_w?KwAlBlFC?{NtBCkHA{n^-sc*Ntvvjq@6%tJ>p})+H0xq{IGht9b4knmnkiC zNFHZmo*gko3F$+^Rp~b2L!tj2K1eoL;>qq=DCLUY*!%204Y=GglFI6XQXkYD4t8Ls zbKvi#qkz+cv2P7&Yz~J=f~rR5$Sq)olwWGp6lA*Zn4?e+5Rd8^Lv7(3Uz%B6=G2MH(nSTzX zz-30vVmOfRf>EN_^B>j>o_Uc|_5MW}!}@gwHQrz(4GGCP?l<56t=u;mY+r%;k5E}; zJ_=;7p4RPq-Kacg~O2_Q-QK24X!VJ0V1T1x8Y-L2-p* zCC(5#9z=Z2K=D|5>JLPH>+~5GnGU5 zEKd|?3V(#VSoPn!D%@wL)T$4LIqE7ekdS6EBP-oe%OVYzj%UQ49Luug(F7t%Kvs=n z4-Jpin$Rk_xf+On%QLc0{tcr_PV6l`Ln5g02*y*^!|C>mh(JJE<{vnc8L+0H3#tsWG9f`? z3J=a!Szs2OqvP*pgu_*zI|D>ui8hW%6?3GZ=16B{!w{Z1$<eS?2pJ8KKK$2mpCq#!u^X`W2?(46erM zqKPGv5PK?x`ucgZI${x|7ET@i23-|Y7+-$}&B4|xNPBtJC7W&3EorH_5kJPoX)v=I zxuqp{U1v5`1bNidzz5q@6k8pmB`S9vLa9h)-=yQA)XI^?2!UE&Z^g#{roMYL5+1Si#B2v&@tRIa$ctcQ}P zu|+L77^$-AcP0=s*JQau{=S&@cmE_rLVXx%G+mAxBFN2LvVEqI0z)~6#yZ`+0i+D} zg@des4$i(RR`y4*6cRY%TSXt~8KjtRLFpm}3v1`~fc6euR;!WC`?I}>A_%#_w7g6| zR|<6r&DYM;5D>vVpd&P-q&<;WFpdoyX$+4F6N9E}U*E1Fhq+7n9Tc7Z8|d237Wa^g z9;nusEH6#+jWQFa?nA=Obh1x^Wpovl6}up2BYB{3-ruLTmp z@xuh~$Fa7sOH*_b`9A(yQZdh9DHBW*;+mRa3sxQ0v2cKu8p-Yf`J!rE7%s*bpOrV} zotufH^Q%S_|B4wk=6Dg3PW}jA-n#Dg!nzM1e>;UFzmP9LGzTuGM+Z&KS-0fDKoP@Q zm_MA|uoeN(E@!o|raGbvOz*BZH%M%LL(6vNuhuz8;+5ZfYHJl8L%y+|KM{>YAs>-! z@zOy;UlJZ8%@2r#Pxp`VDmsv1$)pB1me=9OXUL_d2>B6!Yh*640K8Z00%GlJDk|xm zw8GQF8{H-UU{+X{p-Mi}aEVqAuIpX)ht^s@t^PXLoZ!1!FD4Iy)m^%-eif1DI*OjG zEN0P7BCB~ZwFP}p^Dm;DR>shQ8vW;za(h?I=QJc$@2HyC15G@#&J0pkJ`&Vc)ku~; zDEF3ep!AVBybt|O%xAYy$%H3DQxPY7@R93Oz*d!K0^AG;ny7+eTLjU}Y@K z7RLE@acjBViVNdvMNrj%A}5M{m_@@vFo#tLcXg_8>2(#cLRLO2S^px(dchoPV4#4a zb9h4t$(779vJ#C5c>-Fa&5a0cu$Xuxx-zLoj<%*cD-q9EZiX{y>vy%uMTEc8ik#!F zf;+@a?`|R8_p_4>)j6+2uOV8OBXTu}Q$Ec4j2dgjGmx1KBZPaMV+&l{GhZUHm~9?I zpWl)qU+Z*I(1urB3|lg6F0BHZb_s26FJ_GS9cggkfGFRu%t%3hnq)G)j;_BQUK=|n ztxoJHfoT!)7w49?J22-!=V^8sE~5Y@*Dqds)*Xv}-%gLx@wd>H`bC1BF+N zKqsn9HeL>ow$y2Fp2q)1*Q)m_8XA!to#sY&!%sG#v+zsz%D+0>u`!aA-MWwMhvjU* zbz%Yc{l$}e3)Y)WTP6b*5vjE3Ue9yU(|&a&=OHdE{i;bv<%KzW?dsi#9Ro*~cZ=_0 zGwCUnMpG^J$CKf(Gikv4U0<98ead(__Jn4Mh##$l*SK~&2ZAxd&zHTiL-W6v zS=03jzR6?pf1w5a8d_LrPpA4~rs%Sp!bex0IkXF_X|uc8_S};$S=lrFp^P6l8msHH zW8-};<7acIw>7Q=Y;KP;iobKZyxK?@wuHUKYrok@8#4T^Ho6N;5PxF?@y9{Ev42w) zJgI(kKki}dS!?mt_o(-U4;~}o!Yn#M;iDWlLQRx^8|P~xY9uNGE>c`DIo@!EgM>ez zY^>hxeKOwg?3NBF9BF#I%Ow0G5cK^#()9V4uuRL_Ba@(fX05@kU|ykf+z8;)xT@!3 zUsRK(l0SC6^k4qI&3e%r0M=nn_zf+TaDibIMRHHet2Gqv)~PA8LNMMUQuZ2 zRIPo)ULma5bO!Khv^Z81R`ZlBE_bGsKT0+~C7EJ(Qt|Pmk-?uqFukySf z$>U@Xq)34z%0Fw&J*%$F(K1ROf0Cqjut#)FUzsZ`5S>JQRTkUuvR;o1bT`{RLMA4!@8_O2Y7UaN|T0zO|qL5;MALsYS+ zDFT%$pBkjU{9f8R{H!AV5*prak*q7%veo89T4O$?8rFz)IVPv-M-T7j!j_LHU+)Sm zAGytrDDm$LDjqxXK*jL*Yy<`D3^gAg&?n3fT&)XiG1*$@2KW_6?SKE~SG;tk7&9Q> z(7>Ui=}HV`LQge>frR2V#_n{&`AH|(Zzm{4GsQT0Z!n)~2@?ht&4N(0ETmFLf{yoN z%!8U!imz34AT87uFa7Z9a1u!-XU%o82|hwyLOZ=^US+Zo-n^V!u3rpZ!fp5oCuysO%jGuC*vLja{5@zw`?mGMk|*R_Zy8KNtawyJ)j z!*!K2Rts)pj_+_%i+TbgkQVSgGV?yM%>X zS14OsA{JH*VdIuZYT1j%I6pr_OhCgJA#}WCPl0D5tekL&Y|H-sp z=UCsRA^-vDt@-b>%UU~ln7gE@95MP6A$gfU#TKkB7u zZu`fhp!YufBNmz0&>PGR89t}izFp)`;irBk83B!eB$rWa6E0zNWACUfAtFy4jo(I7 zA-xyGF{CvLhPsw7%FZ}q6R(&M0fBJzxV)x%d49g1aDKIJg~_HdwPeo14^ufK zU0c9>sX8fVXDy0DU}-}=c7nt~p2ICgx_ABQ5mG|?&Z;a_B$G!>PAiTKDW@K$V*+$`Fwv(6&Ky+BwGMZDl-xR+*m9SjHfrhGuwXf z1q8NoIGZ#0p=6e^b3G1g6`L8?nE5|rP~0ErPwUaU-RUpxHP^!VW9RK=h-5dZPTkjv zQO~3Qn2*RGfyI@tG6%(Ol%_%ZgA%W^4N>|F8qZSf-vl(#|DAwl`F{}5B>o|wp^qs1 zLqN;VgM$VoC^`MV2xy=Z8N-wrCkoTIDl@Ki3!beaPUpe|L+-bn1KWs)zxE&wYM$w~ zH7>f5Tt9z&{toD7!xoTrXdvtS_+JFH<{bVdAOTJM{f_kC1T>Aue+XzT6J729Hvuht zO99{gaz7H_dmk@BGJ#h_&fZBYPicjSYwq2`=$&2_ngYX4x5LSw^M_v4Ufx>arG$pY zc=QgRf|`m=G+%PMx}Eaw`zFwRuPL4vS2s5Tz?S})5#lUjcJ-UW^@@6;HtV$YyF;p< zyV$zJd+~}N!!c2|H=)Q*j$2@b0Ozjgp9GKT*nV25mf4m(L+~8Ns4#WHyuEt51^@bs z>0^I&J9U@@)@7KqoYC4}oDcKp0~*>YU-G%dYEZi)@%&1-q0Tm1iqELVl;zcIy)8_G z2n}(vG%VkO;8Gq_z|GdAXi{)8RCUI9b4HSMS8(9_9c4pj&4i*b(8iTs)j___1Pjjk zvev%SiEG$mEFcKHLW^|juU-#?cZdA&R-9hFJBCkz&ZI_AnNS!kOC~+okZA@Hj4<_r zA*l;oAV*1~B=-nc62&#QSH^12XO<5lJ7Z9TqmN zK|&?^;D}ggz<-;*%P)x7O7lZ#g#=X7 zIsDpT_^gN`c}vA76&WXRC0Bk~#By;9AQEY*e!KMl6VWuV@St%N;Y9t*#-#ZaRw4$u zX4>aGY*=FF1Iv1IlZBrP3hk!DmT_^JQ%&|3?^}dYk`s9OX~1CyA@Pt)cTh!>AR+BY z&u!u#0k7V)4XFH*k6S;wrjLI$gbT|09MzGa6!U{}?{MxxrxQ|b68oUQT4XLOrbcsc zRYYhMo5?uVzUJAW$8L>L0poGoVy3VcM0^jQ!Ld^xQ7F{7$#{RTNl;rLb*gW<5y{S1 zNLW&VxRkh8Khd{8iP2yZ!i4d&a?6%gwm6?XFo`bct59uqqah>o46 z{pst&FlDqiy}YN1gMuT7gQMKtX|h*iiQ%hS3%F{ov$#CrfBW#$X>x46;e2?V@#yRb z{EGc}gnauPNx1av`*<9)#M0CRel9QkdmM;-XLoDcn$|dP42Sxr9smJN1{zyWb}ZU* znvUyV+D#K?E&1I!bASmy^`?nm9vuO1#t+6WcL6`QnbysI)?zLVnKk7xoj$zVvv=e< zwB1lW__(mv@6A{~@TZvAq33A*u<6QXr0nw1nRDDQ`?;}4f6|uH^>N;sU$2?6byjE6 zwq)M&Jo;JRQxwowg^Ja7*S6G&>$AO=6cEtbo434Dl)tU!dBHHKEuVq$cF7tz1@LLh ztOuOb&D=kJ$?vJ9XuEf1I#fJ@1|C`H+5=YXTnyzcSJM3-jc_(NIsSYP=k*noGHR;5 zK8b+MU5ByHRK8@ro&0nh9Ht{de+!P%>_-3NXsviRmx-}(t@w7b{IMa@fuR93t*Asl~BKTX62)BX~&c??M z=Eru{$FBCrZhvQ7(xnqzzZ;%>dad4huHCI6yUD>LbbKD~^*!Hu&TX{O$!_A8EB07C z_>VZOzOC4edE}gX1aQ_{*!eUC=r-E;_|9c_a9b>m41za4UdCVT)}Oyk{`DEXUe(pu zoAbQvQYc@#>h3kv(72*sI^CM={Rx>}&+)bye^hSL<-^-oi*>V6ym_VNFQ`B8yCz)I zt|R{n>y4mGFMianGrRH3q|Lz?*$sr-6ZviBUGXjYs{CQMYPfaNu3EnZAbdZklUtAV zO)SSBvRb2ypIFg0rlnfz!(oO)m)H5+yT#Naer?NtWYyD(?;)Ve#IYjAzr`0*>LBOA zrK!!-39F!OPR+66+hdUbh(Pyr-3Hd>-yzw6ncnwg9CnuoFvJe(_eQs|GVB)O?;8eB zA{Zpeus_7^2q7a>o<$KNXzwCM2{@Fv@z0?EFcEr##=And(+DL4hXGm$*q-2Ycx>0w z)3|)sqodw2mHetYQljm{J1`w~!aLX97tYXmuuFI8_!VB`gfw5GsFtiY>@TzwY=vy?XR)(*w*~ z09|K|l{OyxmoFtJ_&N2PocEtIH<#Z6Mi>V)>f&eSO{@T?PgWrw?XLUcTlL>>ZF)zAYO}n3{Z3(_h&)9&hI!J=b=nyPwO&NTqIk7K{Pz_EJO zF?aQWKHcT^_+=5WJSz4{5dM7WB5e9fidn;|P<~L+=M5U(eh%pIp%%5 zU8m}GHhv|#+HOg`IjQE1u`vN>0WP$o-?YR}5|^ni4szhhv_cSv>NKeM5E=@Kwj zzQy_2m&J;^bcJ^yH{$jt!C`T&>-3gyPdF&>gr787|Dk>B7YX`F>3vE0wu$w|6Hrg^ z`e%q^ocO&HB3RJ#9iKN_SCzvWQL=q!Gh}oCZ|&hePb;i2@apo^*0uO)uD#nYLj2g(FVZ!eyznd94M`eZV<}&R&EYmz8MiSyn}l``z`Pr#$K)5-xd4!!WW!sL-#i|_T)?KGk~2!h!Ddt zhvO|`Ye$g4hKpdkz*F&!t~F(ifc$c~bnKc&+^B>k<2#P5(n~mi0BuS=VbHRLWJJ=7 z5>|9vE{H9XFpHi)wL< zp@PX5^GZJwfj?~Fir%*hHO*pJCRPZwgfWQ!QzH|Z`+cKFe7?#FSsckx{Mw7o>`rBa z`RM^0apD~Ws`{5*irK3y+eewd0$eoIC3}@ONs~jTbTJz0S!gpd%OdQ)SP}##Oy=(h zu~!m?(Aayj2-tK82{_WIV5w5#MG+|gad&e+AFLhn_eK>sZ5nfTO%>J=GSRBYT=e9W zpQB>RK*_W!QVJb4O2xFDByJ%~R=m9)`6(@LKN{Dc5GY~SBA29@Hy6ixjI(fuU>wwq zZnuCfsuAJWN;g&&qvcT2uSFhj0>aAypuvgea9X@8Tvi(;t2$gQ8rp9GCOK?B8_`J0#sU$4V8)EQ;W@F~1uuC+D#9ieIr?`%3EEVA>*g6A zr9{|-E#1!)>Q)Dzls%->qGmPI1UcgHSWJr>RRi%B79-s^CJNt>(T9!vRG@NvE5l>D zC7!8*5VCm~UD|&1bY`&4bHi_MOZtV;X-?e|GeMO#mj7s91vWn}~Tu#zB?1{P;6S`wNOI0l3kewPX;VzR1P%a-{?$XS+d zJDCSzrciWavAFC?4=fYR`LMAHSjjjB(iRP=)0Ii!{!A&sCpZT37H-^G2M=aY-zMpG zly#CP%_8SmLl&xtL(=%^y{`C+Hnl*Xd=&_5??cLZ4KJ3cd4?|=Dt`r22x^*o&LL~W zN*`m?yzeXu8oa%E-i{}@%bZ2Z(81~N0|ULCf<=j0r)X`Jq7kle;Bf0Hq`=}^qP0ViNCS*n zTsm`45ZmEVZHVEeTVzM8__JyExitGJzUwbO0OU%aDr<+TKoP4E38|p@0ul!2OF=Y2 z=Y%)ZQYUVksWQ0qOtKb3LC0{w>x6FAa<`nLQ}gF1BRupTMm+Rh)af&{IZ**RaMhUf zqaD#|Q(5p?2GcI$E7Hd9!EQnP;>=k58Q6W;U8?AN(iIWDR@PJO>>0Q@ zvIxx=<9a--Nwa!RVKZgrCn~0{RY6EREE$6fX?n{paWfP%@=m$A`?%A^@hTNIPS#V_ z(ZNUfkZXk&*`t>b&EO@d!``rU!hLKAyRcdiGODQfr{rApZCt-SX1Np_Ymr%QH*>ms&FsYg!nn>E zBuO=Hs&Vv~__@2KSn$%($VsE})=xn(As1j6zrqw@op`!{=kgxThSp#{Q)O_X#pId^ z?~T(#u}vr22ZgsDY-1C|-tvQ6+37W#uj4E=0FR?B44%Cy5#=YJf>00x{p1h3!MHEO zjTlo*J{rk>&P+%NPhuY!poeE}ucrm{u`((#CBk89=cUkJl0-h(!_rh;=*Hc(cXN-K zUa;9`)9Zv5LCnwfXVbF;SGCkXA=NA%=3Pik0zN|GgLA4r{fdnIPPtx(=OG34fFFTo z>Y!i00brjH>X7ex>P~gE?J<95)gck)I{<}{0l?nC;Q!eR3xIp>02sN|(f;W_1%N%( zxvCFz0QU9N=K(WlY8Zd0Drxr>mDKwS3IRU~s^KI~0l}{7pt)R{7`fGOBJV)$JrUq^ z#lY#rfG3Ok*L1{#f|?j?&;Qa5;&ra06#^cEMF-Z=0>^Rv0uBNhH>?NjUu?w6TQ>Fe zCE)wrq7!jH`*8RkvVdzA`@RcMOFF4isOi}Sk3D|>-Y1~q_$??UJL%p&v8#_LWz643GKlb|8G zsJ^@|E7TEny`&d`n|0I06~aI5#ld7ghZF9Wk2G9r_e3W0pPiF@@Hy-v3#h?4Nq+Xr z!Vq%71_?&o4Sj|KUtk_Qe00A)xT7ajxuS_4Is4Eh575tP2p~oLTqJ`U3bvJrFUPo| zr7%S4RFvM>8sf_bxZ`I?e#flNe;m88Eus7h8)!zR=eEd*NdADcL`Ysmk2q591@9SQ z=$z11_`~Dnja4%|cF8V0b;R6umO|dD>tgJh8K&F>6JmieIt`UG1PEvZyjLiC8odmv zY(D^a98ihur=P1RVZ*(P)xqc%oh#DRx>i9L#itSdr1<)nk+!NaOpb5bE+|Ztd-Cc$ zVyyG19Sv@5TYG(3I9H<5>VGt!{d9Kr~R#FpeCxr<}UuIPoqD( z{o315i5p=?jYAVjz92x2PD%u^Ld~p@ZYEn$!;~_sRXAKqE+VO04!v%brmRdhJx|Uk zBP?U{w_zsa=d#pu`Hq)7^pF_Jg2g##D+xs&YB3k?ofP_=6pQRU;|1uWg1K5!HbEdL zYCZX(xNe#XHlAj{(8%n?Yl$J%qxKId_(02{p zTV~Z%t{JS4#d)jhi$F5rKmju);gC=C2VA@CVgC76bLbYyG7hu*2&$ci(QUHEAyk|6 zEv(c<0GT(I3%Bi9PUSN~+Fg+_d7{psYyjHqn_Ze6$Fs|K4VE+P+x&~6sR4$utrY_i z9V8~$wK0r8M>0b#T%W1eB`kq;d!t+_nkc|%a6&HdCXlP1nm$kK{^ z0ba5gkBct;YD4ZD6$hJ=kUt?16mJSoXGsWMmNXx(5z?)x&cNZObKu=QTpm9`#ZM60 zxzc+B&1$_v>f^IR!LE?d$)h43mGxh&g`c2ZTy4PmgkJc7Bwn6M3MAC$fk@wo1Ql=5 zw^Fm5=Io8_Y0Xd0CrY(%z$-=#d@@+9OZJ zh@25pKv9UDa_4;Js>jiygEHmT2#I7idYKR~ms;KtPagm64va{t<~`Ax8lo$^cG8=& z{BZ~o|MRoQ9jR2{{L4iXAbZ-nk|%d^CMBw96~r26b=Br?VMVjZLM7UPwkegKg|it_QqokJ zAMD&V3W|qfUTo+?jhTqJqdCi<-4wM#l=ouF?3{AaDfxcQet4RWqPHGuT?ncyI~K9u z+N^gt7`MU!SCv+}75quJ`QxSh%JF>43d5l)un~HcISa zaX_x|Gz5>M9V7Tr`7Q@nzyIVZ5{1-9KTuaDyf5Lj8f5xwYK%FKk0}O2fhmH+R>j$$ zH77v+BgrLQ48JmE$Fon82#eZZhgdjJx-^Jq1BrqSOY&+lQB7tu5w%KRdN}l-Hn&Js z=Ad*e=~vlO3W_AHC~^&v60S6CEAOOKt*CEJ;XXUwP*aM!!aUS~Vz{3=n4 z!hg(Q^A6rRxms!D6<J*;q2gbH4ggLMdN(;T}-A93@(y;mD~K~+Gb zY{%F&AOJq=_KleXM$G|)8C8u_rDqu1l#ccBA$8A>I}Sb-6^)2GDV2QgiC3QbPgGp; z&njY_rA{^F8TmGC;Qq84FAy#Pa{ATkv zh`}M>(i*wqE&JXq)2SdQ$EgHZDsoP>=QA2B9WIcnk*=X%4xqQGVqX4IKJ$MPY`cr# zjdtExzI5%fJ==et{J9mJ7yR?~a#TdL7WgjyKJ}F_;`KgaJ68z=Z%$Ip-{#n8mwApX zlbNWzs_J&&pWMN(LLIX22l2>xl5FN;T80mbE%;)Bd)wKTzi{}baxA;*1tvZ%&HvO` z<%=6iT?cAF&P|?ZKfhvVoHd-WDOuuBH^Bik0{($_?KJIAmqy-2i;a%oumm4Dv>Sb9 z96*eEO=7(DnE=u)*)tV%t-G^;tCaL+FW$ynhxOyYk1&GK%L>7-i(?94h^1qO!xi%Z z0m}^NN5~_NhIShT0^sw?%bvug`Qv5QFW}?fgsJ7r5zt@R7IyRH4_2U8oNb+uFy0$A zWM)@!RW;lU5gsCet)8#4k^~UZN03s7a#gL02S$ur z7!b`j+WqH@|AV%-0IDNu_6GyO-QAs_!3pl}7VP3~!QCOa2lwFa?he7-A-G=LbuW3} zdn^B~t*x!vs=4Q$)6>(_)6?h7k)Gc`-dHMB9Usnvb$rXw@bqw&s6zTEtjw12csL7w z6ae+D=oLsX^Zw=yMXIj9=fO(8k<1&Xq_>*4gpn~3iUQnG+~Z7C(er6tm-yu(M(-o{>Ir-;nm!lLKKs>Djt~;{~o%q?d zm+KEsfz%zc+C43osgZ26ZPo7Td>lVIS1Xf=@xS%$R4E|m>_mHpGk=GE%TatZ0GoWg zuzSDA9gPp6cPH|_{PuDvftEcu?bS^-#DG`>-md9lTh9Gl?{VI#bi~mk(pxLAn{d${d-{~N;2DzuZJ3+iSL zc&*W(eb@-r*PZ5W9#L!xxV^8?=Z5-&%T(?tV!aPD|nubIZ z?Oq5TV3Z^!TO}*YE?X(fj1WiH=FCv8^UBi0zhKKC6vwAUJ&YiYuve^2yJWE9Xe&7$ zUhL=SF~@*P&vVMnS#L{gJh_)=Yoot>_6KJ=O;D1JDp!YO;+1{+?M%Im24#&i%(V=h zr{|Pg-=+@lFS85e&BLBw=AS!)sk}5yhDcp7J|8gs#A1AOPFvY=IKiG*!DPM9-y0eZ zbgEB}wrx-Mis9cX{2v0A{}MyK5)2~okjl;Z`sG@gedgol#*5Rgcu0Bw>z9tuh9QZTlJ16QJ*kHLo((Dvi(I4jD$y?Yjt$$e~DNV5P-dsT_7XO8M zQB>-T1wruX({TR(PtjGNMaTb%uF6;GvEAXo;MLaqD&Y?NlW)B&xcJSQQwTL@ogwyy zfMzB^RF$fOY>$S~;k+e#iHTNHCj8VEn-P!1kK4|42%ayuL)kE&4-APVW|Kj|RfUrxr)hsey(yKc7tTBkFob+9;#3nK&&=ht&&0-I#TRcy1(54YTY`5 z&jRkd2zN~457DkL=P1#*MBFDz3)e)C-MdEn_=&88D1E4n+Vs$C;Dl!wNr&MK$ZeH; zHf;l~BOqj}NBM+?p5PV=`vFh?_T`;xbEw6rmsIvMoZN<)*posW3kos=s$0{?h~ z9Xi3IRwh%g-B&Dp;b>f(d(~N%1X}LMmqjIHG|q;5oqP+t{Sj1+eB_=WqP!D|6QA{Z z831)}?3I=U^V2(cI`LsqdSe%7Z52q?mATS4DYw_;NKlmb=d#vtsrgqK9^U5A-}Bs> zfh)cnYtybo)amLHPIqTzE2oS;(x2I=j1>#yWt>z3bu89M(1?aEV$nP9k#+FSgFt88 z$9K4qyc3l-k+v4Y8DLkK#`|6-<9wN25!X`(ICe+7w1W7bk9n3{;|U9`eI>f>F)s< zruBnV`?5P=*L%;&@J89CD!TKj&e=~ygK#9R42 za)Q!6)z0Fgaigest-OQgxXhEd;1u0J4g_BeUR~{Tzm)hzFr0%0Q_)oJV~M!)Tbrnd z{bkTH)YMlG{!fvodII`cn#5`229V?PdQMW-4i;zq;7s#mJ9yq^bPz>Es$X>u-ciQZ zNhaQ8P$t5=25lN9psW8PAI6+h(*E%Y;UVJD2;4-ViXto*HuL5>B5X zw>I6s&8r?#}23frU@|zC>S(Qo51<%yV0E zM-<>&Yi0_e{equ-`;+ByoPP5KtOVL#s(hB49 zC;rLq7=-OLb;5HeXn`_VV!*xyAJmdkG5avs3e!}*KvW>f0A4DyB99caP8J+_pfh2P zdk(}LveBeu{?tYLf$g=YCQB-IlnnM_cj1-)4#GSt$FL|!l;C_gB!)dw*Q|rII{U!( z`l>yV>=;R`UkbwZ(*6p<_DU(TnkINbkl!K=vb~L*1X0=c$TAC=BU+WZZWXI=$h` zM{k(D&i%Uk9=m8LiA8O1;@+Cr6aQ%fY8(cUYL@g|Y&3keYds1nqY)<%wAX#NnqwSA zXRg+9XN?^UChVgAx3i+>nP($a*~W`{5QRb8lOs3fYkLv`JnpQm|^Yy zH40TVUtmS)68zlp>n{O4U>u7U)LG4)oaF4~h$#xoq^F#PVIm;m?=;I2ib^Fh3RATI zc>Lo$j*l6!VE2$^Q+*q;U`EzTkC-Dvki)61R%TLj(fHa667VAL>uvuV;(zyY2q`AE zBtW56h5tW=R)HGq|5Ip{17%Cx1_;~h%PvgV97YkmJeUfXy{TX}d{Uc--+5*M z>%4s9%p-l2$Yxwdp5$H@p2U4jTT46we#F8G+k#Z3$0B4W1TM&XiShk(SEi-f7rgDOK5+tRH$u)V?dSWAM zbKTpuaW$)>WzE~uy~a~7uBuHjQ_OFCef)8L`Sr}p^|A3APn)-!qx0k4>3ZMz>iXW@ z{weSgg!km>)6w#z_G0Cuf4>eKY<72j9DlT}J3lyreZI$DZ8B>c-#I%S-(SB&`e8d! z#W}Cwn?}^K?B(g~UYDBH%IEu>J<+w1p=-SX$lS~vBF=}lJLhOhPmid(Prr^B*S(!Z zPEzvPftYl5!_GE?UE8qP(B;pv?_og9Jr=%Ic{h1EDZkSDCUEg?q~Wdn$TXs1miTOe zN$K<+gM8qce*CiiyVciC#m0_fzO4<&F74SgQ1(1NzYjbEnZ)QZ{oEzp^AYSl_2=|z zNE?W0VE+xczGrh9Fxjkrbawl=dY{aRPo#FAylGcDY2>UxCVjiZ`0~KU=i2l*6f*98 znhpetw_d%~eLwm(-x@t%Y1DD@{ZebOeWDD&Br-DTl?FctzGNw9bT?2EyWX?)?Lf0 z>DNu?Wfr>&^N;gt;HCRB&&O|V>FdvO7z1Lrww@Zm4ZRJGE?rR{AJ-O7-;S^ZmOr~! zw&;4?pLI9Z_)iV_HmpmZ*Vp$}*XLd5=l9<_S2_f`wpIonyGkmXu#q*8@8?HuEp#(C zbyN>D?pJZ4a#)9D{N0*cUWP*CoP9ezV__YeS~^zO>}*|lS@<*UecYWPZ6d0QIXLf; zBfUB!zTc-?-UAz3J0f;0L0VUBV=S%nS(gHNiYL#u&I+IQUycnN-z}(u^=zu_hz$vM z_sy>DI5so%)HXG;H8#5}0UFt=)SF!nRb|=l?Z>?(Iv$-)K9Y+Ri+Ku*{#D+q1t&>W z=@Qs!vybe&T3uS+%duT$qkuh;JF2VY2;l@q9?+NUJvuY2*mtAw9&596bjasZs&z^i zAolYOcY^knsoBu85?Z-A$s0>nO^4-g^AhmBr3n>8Gmhmb%Ph+0bV|Ll`g5M9Bn2o zvA90m$5u%RUyEc#X5ti>mlJa|QxU)(S3p!j9ao5QoW4;tFZ|uI-!m?Dt>W{=@}Ovc zrRiG55oqQf+;Ugf->dWN<6~LrEkLhgeh<8RD{ERkSuGpC-8XHLEi4+Iw}tTgYg7W*HHqor`WUptJmKr_iH$Qx-Cr^S*8T zQLMpRBU58>wN1|1(Z{vvwQ+k>V!*zw#j~lSjlavit>ld3;C?mz*;j8JRBxWw&+gvp zl9{?X*E)RNu8&rMx1%Sc>&w7-P9~#`9dzbH0`#L~kIRi28 z+>7VQr{u`aP^>^}KHEetFX;WkM`fHHaC5Y2TQ$jK=i}W1g3;o^^`77Jb_R4rP|llv zL2H1vdlX1MkEelMgiJZ|~B_=VW}lIyT4e z3%w^}8j*Q4yaAayon;f}ozcD=wThXW-ar%gZ(Yx6g#-7T?JY8dStQ%%{DFn7izRcu zja8p#M4S$DA6A%%T=qPT=I`IRY$?@zGk*m7QoU-*q#x|nC8_txNn;ny`}$mxD=|ac^LhBFs=J(ZA9txzQ|s}!s?c5(6*2kT)XhD|ybbtfnmn(Dl({Lc z=xzW8fHrGDQ zS;mq{0gcxt_)Kk&weGLm5}O&DYBAn;PDc(YOvEAIHeTDq|GdwF#5iy5)+Cg6S?XmM z5=TCs>(+g0E{wjn31TMaDk9+(d`Kg%{%YPs5{&wZeD1|BY70A3-N4Cjdj2Dig)pCq z^fWtw7J-BGCbVQ)aJA7!^ueln9SX8b5a5OOV4+WRw*hXO zDSORPE_`1VytLYL`l~TeUg=B0=foND zQ28P^JGS0C#|+>OPKxc6Tvno={Bbv-By@s3t(?)u8pkz6yyKS zWmt}{<>=*<1NcVSjuf;g7Ag-vIh185x8+RIE)QD;y>)9}>f{l#7p|*SwL2G>@x(>v z(J|yOz+a(3b|ggMtyBBo#g0vp^LzW;<6ELp%;$Q5vlBAm`gNh&d5unu!iico(p1rB ztJem8-8+lG<5{pLr%)r`DI>jDPscOlQdj81byB1UA!IiTD=WloFsPTDRxdwB;%z_T z8$WEJ6#VWFQVf!tOXz2xsm}oMuof@^{cdDwE^;{PiBzR3b>1KzM`*5L%UiD2L`pAf zW7u;uLV+)sECF!1?qwxvFiaD#=5Q{mX+98g0)t4n4TT4o?#yi#`333X1ve6kPevG9 z#fkh?!-2F*sK4Hdf4#v-`$h)Z&Piu$?Di0Zlhb%F(o~$|DLz+*&5~o${vgWV=kOvx zU9!XIfkIAWtrjLetQt@5tg*P^Gz&)XShVE_CrR93$kn zz2T4X9IJ1Jazk2KN~7Adz||z4BFY0rhfBqwNiUM(q!f{`0dg9FYyTWAMI=Z}g^`yr z6+upT^CBTn2%wd_DN`}OG*=Pio}yxVL&W4MWM)r0R;&b=dzKbJq2h=#v&DhCYHvr0 zKg;abBCF*wqNCmp?*wg?*q)MV*1@mEvK(Kn377?(?ig?<-lPUObx4{L{#=VIb<(R|V+ zB5rc_P!zil?I*%QBVjDp`>=md337F&Ud#l+e<2?;Vo+orvf9P`o+9z-i89@#f#<}~ z$uwuHEx`A}E6CNwFCe|3VLxNz3TAWMif#SjZ-RZ(dmM2cH7gn{QrHWL8V`{19uczw z^pbwv(!vriyUk#FG?x?M+9lN)&D^k@-$#_!Vv1v6jAKy9RJUT)yPByuJHUEQy|1d& zJu&-RsJ%YPaOX%T>Qu8!`J!LNpLuqT^xVD^HiubC*RT#C)>^}H(ZVA9^ZSEjNk1~2 z^@*^wMt-zd1lO52u2nc{fD83bR;9?(mC_>raM{ z=oQn;Gv`Vz7SesBMOz+~W_s0rzd62n-rN25mWD`=#K84+)=r42*jlVN_%5Ua4NR#>j+VI5om{NOaIStil3%nIGdY|%N2HMu zd|J+^ki}e`P5&~L_Fzq{B9a!tFL8!qR7gtvflI#}EM|rrR7kcfFFctnU4ZZ%9tT#o zHS6QB#Ht}u!A5n9AL@Rr-HpT=RM$4g3vLtber)Iz6{lBVwgdhvLsL&o3!?A1O*lJC z6wmW#i$Fam{8y=_9=ldV-?bN7cFa@ z=d{YZFGTJrlf;o7ba!8V4-6(|1$2Zj{tA_l?!OMPJrC~)H?Nsas&@<}X7h=7$W0=P zVnVAGSmzObk>9xw-JDm>zkIy*G+HHS#=3-#5+Hk1l!+Tm#x;+jfJP`-WDA$T8(@vv zmccWL#Wf#YjIzl0=;BcB(B`2hO*n^7h#1=sctktD-Ig9O7{SKEN)3a&Cfhi<{T1F9 z&qV))B>`?nkqW=c?xTc74-j`#2;#)dYEJGZ{ z+FmHeJ42QQWc4!00kJLTHHqC89-+lJh1s=aRjAuZ*+6J_G!$>JMQz84UotG#F&KZb zBwxxa`(VS2xd}J(7{CUlR2$IRoeY1PMk}VgG!!*+S&?M`2{c4f7?Z@Gyfsj?)&WLL zRjKGPV`1n0OI7+!NdA_%q`KRWf!XJ9r6(xGSh67jTYP!va6Z!znaDDoi**%4%Y*6S zo7iZ_cX-8*0Qgb~p-cJcduWITKMSy18j`oH^Jhc;g5;$}%g)8CBPD)oufNZRNK$r7 zL4N1xxfH?)Qx|*_xk55Ff+aOk67(|7w+7DqD;SivZ;n@FHT01&JHZWl9$djBPj{!%jO zAMF~cXYPi{#0c=(28N)z^ zO?!@VKtnlENMc{S#6os`1#E5w>{m14D1eTL{dY1ObzyUL;jt*iyv12Xf+R`&SQNZi z6i1Rdb6xE4J~Z}~?N*_Llb;pF@Y-=7`_scv(!x;E!xRmu&_Mew#Dii{N#B;_f=wi8 zkYw^xk%jjI-QZ;)uj4N8pW8Sr8Utg2BpZ#&Jub2~oY*kJje%^dLc=a7cG@NSJXE-; z=zgI6<1Q$*g#D}PUzVaR=u^>C{x77lba)gwYv_tv!e2|#T(HS$v6WKYX`w|TH5j#U zq-J((lCuOsY|!pspBa+`)bWkelTn@$VhaUej*t!O48C|ti`vB65Q%h(col5GSfCo7 z82lFQs97N~ivb`XN3rP&OD3b(^TCUtDdF$R-iptWbSBZx&`@m91*?S>Bi4>f!;DKy z&e8?lz=di0N>wrAD>UlD=IX+N&G$0$s48k^Sr-w?{YHtW!Egg837IQ(Z8}Osz^9_a zwF~|XSpNo5Y7*oGTSG1Fwf|YDK_49M=Y1r`ho`R7=Xf+iX4te_d&c~;CeH7=hROFxKdSd7PU)3Xq4|s z62}X&gC#N?I~Ym1b9hjM`tzzboKHQX)LMD{ZpqS~S0oF=L%SW1oPva!r zl?&xVC}uMLqE+4?p?r>_H;P??VfZB&?hBvI>L*Uq+g-h9+GFh1@bMMN5g_K?wfGVPmbe;Ty@L3O2I3hh1V#d0>{2;%%%z zUTw4i@S|!BR9{AtwwA~UQjrTNZnG8&OsSYjLc3o23r_ftSIa@lkUSpkeeSsAOK=K1HxE7pji&PlRZR`T^B8u z5q6se2>-8DMfkQ1VV`^l*<~KUsDxZ^CMP(V)}2217an#m=cyW_o<~m5HSO;}&FjBM zKgmrd>`R9LMknj6jJ3#>pca47l>vURpa+s%hXERR&kn&%4;Q%j4ve)Cs^nzuhr6P} z9K<3`pfZ1x&~JziALL4;6#w zDA^LmQ=W~DS#pkSemG75%9G$V4S(5ky^F!zM+O6XkBlS<2)l1uWF zC5!nNN|Hph6lqw<#Q6FpE!707sJWyCamy18BpEQx_natMaJc2_i_~{UA9I!8`jP!$4*Q;7G*GqPNh|zaf zu!no-OQY2E0RHP$*}`cbe8%||9m<>*Y5nZ%YG$_U)j{emL_WWOeOqt`PJhmgTsm>l zldLxm0$<$;nUG2xR2y4Mt+eTFfm8W zs{{}^?$WW%x=n&^#XnuZ?4JcQV9CgT*t@_9!r+o@KyCSB4nhXq`NtxX(Mg^z0sAI8 zK4$ysB4-+87L8i(9M(CH(mwK}y3bDQg;oKAv0cd*Z)i;KeSu>>f*8Y~sgszqku9PE z>MZW_&m>_lF?_lWZbPr6hn~TSBY~UwUge?Qo8>PPi7Kynb`2-aCe9h@dnMyB~h{zLd0zXM+WF>*Wv z@fYdQ$$f|-AtvYEX9CF*RYX$w0U}^KLGg$?tPzrPy9`N2yMli2;vgl=!a-Wmg0w0G zX_fjP0_fE6FGds+v|RtxVY>hc24j1M7>3^koeVIwo#Pa_TP(0mM9vM`$oQ)ULE=E0 z)rWdwAoVan>ZyR#ll>0?w2$)bYkVHYUuCz*T^h*ZjsLnjRMp5=Q10IUxNim|`D?t9 zKS+6)2M|AOw#3-ic=F1?TrT?8*#Coa|D!F=NKLAaAA(NX4+}DcY77B6_ZjGHkb0(nySD!CBz{~!$lPe}I3r4MQ)Q1Ie;)m2 z)Q2C!B_2V-`5|vWME~D8AUWENc}hnWaH2euLqebq6xI)g9h3JoGFI%0HA4V zZ0!5_vsD|Sfy+1UKCV*3_oA4yhY=4aiTB;Z=&tr=xBaQ;2DbOVjs)QGA@Pl3npilE zA|uWQ+Y!4AFCn?MH$-MayRT9Hhg72XD_Sc0A$fP4)ooiiGEj}#)g57oZTJmM{+Wo- z*UZ%xy;SJ~>=N)Vw?ox&8g&EWu-Tg^f_I8&`UrhQI9FRKEe&yM&=4t6%wa zryU}x%QdRpuNHR51AoY0`CJu}M~sxvgC+Jyb%LeKIFBrRSK+&T?tqZ`@34*7es9#vfKP8jHca7(gL@&k2e(gM6aLtwZOlGU zJW|+1CC<)hR@dnHNx=1p->S9Ux~FrxUKlLZW{hj6qzLADJ9(c9$P8N9i`Ma~WZpUM zPNr~ke@FlT)BuUJv$KV+qB@13kt_U1GN zRf6^@CU1>M>k!?RwE?0`>cw{ZobqPw0V2i-ZQb^phpO|&#i<049nzo6t~2A54WFya z8qc$A`hEy1uQfgL3*Oi{J8XBI_8t+xuXep;zcVOg_$>3OZ61t6!oJyhIx3b4s4c~E z8p_{Qj~!PjmJ}&CPrUJ`S3y*>H5Ct1OVoOwv}=VMP@XAS2|!9S)K&k9F3!&eSNqu* zM7e6B<&M0D1}?^ssVOV-=T|jkQCI8Pe3XsL@20=}07STE;PUO3mb_Lcn*347A!|}B zA=M%D3G1rZn7Wz6`u;JnCKNEDw{cg@=|2Md#v)1?vHmOatsDeDHxLGpf?`hj^Y!GX zOG2zW8FqQ|Ko5L9Ayt||`1)BVb~zVP4rL)nzbKDvV^K}tgFMssO9DS^ zbD7n#sig6qyUuPGL?LZ$8_S5KM#HZS2arh$ncu_s8~1-ET(ANR3hUdyg~r9>mD|sa z7x5VNpN$uj5UL%w{|@Tv^P9xlRq1^0b`T!!Yp1%ELg-E0ac7w38jAWjO- zUzxp3Mv5l)O!und~$)9hy^hc+AH~oT*B??5%J_D`%Dxu<| z^M;wb^G4<-4oz}05vGO&Ynd=cpq}O_DEP|ly*nvsw^=V%HkUoo2xGx^zDlA+%uIl= z9#ay*9}guFa6ojN*7 z%qZ}ndCIVK)8Ne0d=mI6fuzKRMX6Y^Ot`FT0A*6|d93c>S5|)KvBmSj&jihgj zVFY;;^^MdVplgDrV>2j)PymH340P z#F0ho0O@A$5pJ_&k7Lo2YJ^DTfJH4NtABr60|u=d(ScQ%fTBy9WsfY$r7eRP9N@{C z@)9~+9-SctmSUr#KoS`d_lho6;6giVUy~VAvRzwdIv0pc9nW$v(0BYcB=;-Q>Xa~6 zM19ag3o0S}LuyG@N(pZ5y^y>kYl_T289n^|+4hoCT;o&CvEHBd4U}Wq&S2@IMAG&Z zD^ZCUA=P%Wy62l?3)rUfs1(F{^9o6<*U)kBLw=3t%2Lu_1vJ_#{IwxK z)VuDbbBxxMP4d{xO9d^|(0`RrRbC25b%1i{Urtr72mfsdO1DuGS~*ox`KPe(vs9+Y zqfCGQ^?%KYQB%@MF=;N7Sp+~|$4bV-FwUgR;M2kC{P<##1??FBaRnA$8dXIkLXATf zt^c9WzObFCD_j44D$yh!lR`UR0L@OB)RyPN^aQKK2~_I)#{bmZ^39;~V?OvWQQY9J zkEYDmfU8+vlzoCQS1a0?hczZTTJcy!hcu+#4Dw6c%mTvH%e}f%zPDHmhcwLIF$xfk zk}UPIVDr=)%|S#yK_n&LSl&t5=RMKhE+&Sw&VA;Ju=c!1XOenK)HadY;Y2hpJ%y}E z7?XQ9JcBBN8UD|&>EC}N)?{&l6QklyBbkx^WXKfYkSgd$5zL6oUyG;UnoLkDBmAQN zA%QePUbIX;mda8jOglJ=jzbZG5kE_SR;ct(*DCj3af>loxOzFE1YFE&H6bC27HVcG zq!Nm%VhTM)DcfL~t2CKjCt63BU%h{f1Vnb&lXv4}wpB4x9QI0bR$4!`P;7=iiyC-2 ze!3Bq#^exSl>2e#C>3&5Tx}(45n7im^X(UJFr-@A&XUf|kco6Epcd`NV_t2ZY=;3f z#@p7iQap?eCsH3$Q1QRSGbeRF)wP$9vXE~btazyC+KC0s%46?6c)-$nk9;9I-dat=p%}%BZ{$n z7HWOkITAVyyK5<;M~bRPim_@IYI)k5O`2Cz=z4MC5i4QXx{42fIJzX=0Uqkb@Yf4m-fo=IRhm+7Kf^~YDy1_OFKOVE2Czz}R8fA^B2W!bx+1L` zo&8K{oaD}{2q!)w0HO@jcpHZ&Q!`5w;TFViY z+=(HpbjVf91qB^W0SmEsBLbo1K`(2m{;$G~YD`QP=@6E-3)L?;1r);RADR$KU-gcf z_t41g*bWS0FHXjcK7X_<(FtSSn%Z30SLld!y&!d?v6Yy7TM3wcYb-d-y<8A5(XNJr zeE8$)K|<`$5E*A4X6)#=jTL=B_E2T|u!o1&aI@aXX#k!A$RNib208pIZjq>TbrKn$ zjYHYhOXF_*tKIY$vz08U@+g&BUiBW3ww62Jku2t;?MHn0r1EfJD$yTnXa^a9qf81P z)rV2L#^)ICR)2i52#0kX`FEe1QgbnYOpslIY)E;Ht$5?p)NcSW}{^IGkejQR<$sY69kRjCgT|jK;b^itZ9w8 z8Tr+7gq8=(WH^&FBE(KW#X(Lok-YN9Za~GUG0>Cr@yGT+#TArk3l4gdI8Z=Y?)!Wi6W?k{P2x0shcb&I_0Iqf+ABDb}-1j6lwjJ z-U6>pJ;{}P7y*s63z*mG4cyU~oJbJ`LODfSDW6Ml_)1gq(JvkUWLfzL4+EW&BsB6L zaU;4)bTnmJb#JG?^8Gx#cJl{2vfQuGJc;g0&;8B4b}_~}vTSFZ953#e*F7i^^l^x} z^_;4T(nE(cZ24rH0AY|bG6Hw@t+yVnmpHZdUlCH!&`m{;cdSn$9*%gKPG7!!`--+N zcFb)YmW0M+o7ob1%dF{CNFn=+?T0l212bUFqwe)HjBJs7@0gTG5Keu!oBhdn9J61y z6Cv*t=W>4K#jH5$90nBW5^D?y*grqBzT8 z0TpE!V_a$ELp^R2Gz}_!7~!3Z(eV5e^o5TL9M!q}0}O|`e(s_b?=3`VWUSxOe|PBN zHqH;MMuG$~hpJ>VG)KBm%>|A&LvO&e1$g5ad#&an!NL^b!Z?vdel$N9EDJU(5MeMy zd1QIW1|N_3fMotU38+C~m$aH6lA2sh_I1C^qX;jnlZHC2)T1&pjcMEoI&9*?Q4=#w zg{L&^UF7J8QPO>9>0!Q6$@_#-qShwk&56Q%BcJFDfyAyAMz#zihiBo&!{QwVgezW? z9NOS~bThCvZb}oygdE8Z4gQtC4umWaJ){iIS|mZdg72(rg|l@^PG&U?CvwRpx67?*Lg&rYD=xT0oor;AZ8QMj59+aSgH1fp z@tp&sT11{8*AWJcYPgc1)5BcS^o525FK@QZFtn`pNIxA2GYI7?FY!fXKQb%I#pM{~ zJWOA*62p|51P8(LxL&d2 zZQ~!k&4pYt+Z=OSrhiBTO}vkq#*9);(X~TioJuQG(^*H&mczAv`Y-c5I+-^Sw_p~H zVE*Ss4>L@SFR_O9X+}cW-EK`EtCdFUM83oITyhOL@c*&8vmrXS?eK2V0mXikOUC93 z=3_;|w;D%=Hn91ueS;}~CeTxhrjL^kt1peT^L&91D`dpT{`)0eU+!;OA}8<+@3)&$ zS!GnXd<+ViIi^-SMABj3#(KUav+aJ&pY=B^8#jH`G zMN|W=D%O}Zei>P>A~6T$HAz(xyk4XW2O)IZMcFh0vwZ4|^hk3FRGIDp2^@zToSxT& zD0AS2kU>sSX03zRPUAOd>6Mphl|t_w|85tpZRtMa6uIsWyKbPo>xX~i>4};vXy;qC z7g|j{Gk$a^wufmCBoCn_?t(;*T_guPp=%l$VD&2*7flXN$Ji)CE2>h2;$e$WJ#Ej zoB?R<%v|oMMS7HP*I_ca0tr>lJ!@2+a&I}v+0E^jtWXQ}mC3Ol6ePEOfbTD3v!xn1 zPNrCy+f_ws1!^5)1y-HVulL)a_F_&@x=KrvfDIVP@A*$ zv!Ka(<@>c4`c0XAIIZLkXBn(y?5C@=Pgjzk+^PJ$ggzBeItOE1r`-rKb^bH(Nc`dH z9-0(!m5udO#J_{KMp-NqIEWZ*+Npy7L)wX;I7JQ2k6p}1@wgoLH`D?(C^}@cyX>?< z0Iz@Q_!b=W{b3|>Cv$=~M&!q6TkdRdy-WiW7HAu3D6Ve33`{L|g_^HNZe1EDavtEg z1FbmYqp>CI=+s2nRttv@udTq@dNcJ&W(LbPaw;+yNQh>BqA44uko z{4dJuM8D<-C6Z_LjSv=pCJ3=b*3am}pI)xUOcJJKL;T7Npa%kqrH+k*Ur6O9P~urB z#E&4k$&Z7quR>xo{zEc7{$EH7{|l+V&Em^2t`fCzf+0K^V-@#g4GP8kIrR)*eLM~Jqjtjs8@AC0Ho!( z4T}XxhZj=*AQhpv`e&C*)#fiIozn4{6*)fYr5eq&CO*=%sOjp7>bGm)C6JjdUr^!G z;EHhE6ZJF+;Oq*6jJbcUXekHrh)$+s|lke z`J$WdmS2&xGdB-`LJB4-`$_3&lS1Ygj#fPFCO4KlV%LY0|$k9Xw0}O3L9v}O+{pQ4ki1xMBmbSYG6~vkv&KU@vD#!q(+`##2%=f znKQA?rY{btSIPlBl2B&Y`<)OmK`l)@=DUL2qGI+)NRgV*B4`YI4jxxYD!2IG9CB#6 z{|fm>c*3neQz~-PQ;!T!aGovpr^l(QkY35um_J|LAleKT&%)34TdS7srN;G*f%}n`Us|hezos5S*x*Hn!BO$w zrwm^bwy!TxbQivP##({CGX(cL4tfNK?MmN=ihcF#cI-3(Dyf7hIdWNnXLEw^rc|mT&`^!bLY>yQe1;3uuh}$>x4c_rhVm=S1fP-jw7`Rb!1*y>G^iAZLZt1bBC zP11o#22aHBpOKhah3>zR7$R9|Nw$z55uK2Zk^eBtZ-X&%j$m%#1erx$tQy)e)HE7h zWX=Awn~Zg2HzUeV3c)dh5w?EjDkg*NjE+#YS|%MhR(T_5jW zW%lzvwOf|1KaYmMQ`a+&<$V2bqkA8>4K$>w!=IQc`5bYo+}Db509CDvEP5){mF^x3 zESB@1As`9rBFs9pv#$dZrU2|!kb7#^9$H^tp6tBuv^ifF#=8n`HyAVAW zN=}>DUX%7W&y@l^@>@2o`2f@RHk;dyb_B;x_xR+D6gf96c z(skX$R$t{v*4BfIllTAkK#5q&wvWPyt`r z)55}Tcm==q?&sV_bv>ss5K+@p1kL8VDE`$?QwBs8ndHKs=l~q%qO@jHVSiQ}{ z6bHIZvepXYZ(wbqi>3-sOvf_2jGfEl?zj)z`1&5Ere|AuhpwevQ+?Cu;!b(TdOaBv z5LkQXqUrfOw_$5xm)+1bxw1+P0GT>k6Y&vGA}MAd0H^dAy^Rk49TgANFW?d|O^V?NjB;Gg21=qMhYh z33eTXiS`_XU6g4BR7{Q(xfYeb>{I_p{+&K)HjJ_EH7GMZexQG(%$;^w;KH^eb89|G zjK0WmE3qXYF=1(GZb8YH)%OwDNe<>?sg@pggGtj;W z<4L~hi$Z;2Z~%g-zPy?QUWsUe#+>38p?&YpjKQ$l?7X1XU_tYSLnX<_2Y zu{7mQDaDBxvgqHZ!Xoq3@4joT?JFLFYO5V8?!#)U9W5T9YO9^3(NEW1wh)~%Z@OUZ zzloyr4AWUS&GpI|Nz--7Ag)>NJmnJ5uk&8E?;J9HuHEqp8NV|bdc;Zt`qvxEk0!tF z(&De}9bOTo14pB;8LeDEjQzUmvJu~YluaUK^ITAmQ1zRg8 z6CS{%%b5&u$BY-&?qrO9oY1P)G?|c7xGdOsYkSLiqFOe_?BqL*ghpd@aP91s^Vs*{ z>YkpIgryCA1a@m%=5Gk;ZS=5`U~ZaB}vz2A55 z-}Qa}oa>x}|1j=n%=vf$_Z)MMaj!Y##pICQt}Ecv&^SplMN_*Oq!<#WvHK;A1&joQSp-6@QV9aOwLJkU$xQr5FvY}#5E{-B=;K9nxpmSHt>T02VY$W%S zifb;eaV zDX-5}G5Nx8yd~x~_D-tzBz=7IRQs_W`2sS$Mre#K-|Ug6SDu;K=`H!D6*rhQI#sS= zff<)Sv}-eIM@6&7|9qr!)@Wc-hnv@^%HrCpL7N6^?|iT!DF98)Jl+-1kX@h-*XD+{ zq&irEX7e>*5ky>CSu|EZkW0T*YlOMKm>iSQ^;-PCQW4Mh*@nEcgSiwR^6eT%_~r=Z zZEXK0@iqI?EYG*gpKv(^BLbX-nrQiRrK!qyykR-#lk^9UGP*GD5sD_~$<(fs4rWNf zp`Bp60f+uv+hIt|TC{#Oiwwba`6I8VKGduH37bEf7gQox-#zYs@uJ`VxIx~bniqxH zGL-2^A%IZ8uruiATyV(eNicI1dxQBN*+@yK@b@MsdP5%k^A;}0{nf{d*V2)$3~ z!l*uS7J5d^bm9VSk@x`W{r|J@fB(7;E)Mql>pJGGXX~+A z@X`$xSRTn)^04b zJ*4GgJz}2aZGmAOQXbTiI;#sRE}-8LSdj9mSV zwol+31x)2w3Z%y`)iUD}zWuqbgTJfP9#rx+n-1MO^&={MJezPrp|UACXo|NjKDlUV z*9=J|%BU@&J)UAf3AR2lYxNqMDD(63nf3mjfs5zIbT;+h$5F%2bG>!CI$%mOB0b(& zs%0oeUqrNjKsV+K=;Ze2wI*Y*lUFcN!<8&^1~EfYCWRKx+}nxq>6raGs3W(~xR_Mc z*HJFLTKCT~9t#@!a0b?s<>RUfu##Y;+y)P%!+7G@8X0W+n<~D@F<%=C*P(hrD<76( za^iK=XXn3|yFhWd?a;_w+Ae}R<>KXQL>3_6b0D(3e9xc;bUvzC8ta2 z_g(gEtz);_W%9sFcn@?w8qh4vu286aeeI2fXbTzg06HJZk1iIMpgbnHJIllwO>6xa zvmpJ%XW{{HeaACev+A5UL^gvl<=p3#Db@8sQuLv9Fj8AOF_YSD42!+_-n@vIu+j3N#;E9#CMMz zY7LBR5dA$wyHgwQ-|B5#)_IQXpAft{Y_Hk0v_kbj zJTutyOP?d7X+kk)Q{n7dhKbiNIh13XI8J9fX+u^1AKHZzfot% zsnM*4=1%FtJ0ArBosZH?NqcqfJ0E>uG5e{t=HkfWnpPC^cju!+0m)rCc;_QKI)kB* zN7QtzoRYdArhItkqXmU1pQ<4K#8)ZZh1KDwlRgJP=c84w`_4!2a7x*%V?92K)mvW| zj~i0qlFo`_io!b|mA&R#FhWv19SH5Am#7&EOV$&OX9?<}k6H8sQDmj$S#}I|LuRQptkWYO36)h?eN=}a@bM)M@ ziVG-PPkYzYQj;%O^Y_5pCEY=GPv3%3^4Oj1w+!^kz`Ygdz6dF8Mrb#e_#cv#&_%ZV z5ggOhhVWwD8(;7XYF8?C=;Ppo%PeAbRNC$P<1cJUXd!7O@dvecO#wZ8{XRU42J<3o zJ#P|-aHgK$3gTXg@W$oD;-W@okjzRD;ljiCZP(443Ke4;=^@j4E>PETSEqOFj4gUf z&nxB|>5eE-7_3IOdcI8IZ=sjmaP^BP;8WhV1_^09a6QM!cT(a6CL>#p-aG`lNRh&nYdLwdD)j1s<{qB#{BvMS}BiQc+YNfsItUc8^?q4>ZGN(K*j|76Yy zQgM^@rtLQqm8*d;H1Q#F%dWq-JWus}@Q`eKestICft}kHBGCDWps=D9-udXWlkFA1 z6TI`$%l~#hDxs}@#{*o?;r4&&dJbTL{>Swk&GX?PY5RTW<{KPj6!J!m@!8Ei(_8js zl#ICSuOZaPOvvw;OkZ%#PrpQPRO8w=i4;FNKIUTFkaN!6Pytp{y1l z`|FpHjS~l7KP3lKTl+QsUF$`obK~M1L|~^yXpVS~h3pxb^WshQ)of9Jz`V^KSlf|o(yt1zE^fr}Jn)zal@ce)J(ay74L zQ${AVztGam@6qDncD1&*b-A^))!jae5%26Q)a+UBc{M-YPFD8%^>w-I0p-}h=9krhpThL^|$lo_{R45_QCEtAz~IG(mf}ygJoi7_mrhIg4fK8@n{|m zz-(@Aj4xVj(Hi9%TLZl`Z?|_@t~;%JJ8xPAbQegR;>m>e_Q+ai=NE{b()X;(*vl~L z&Npv=U;JKL+DJ~1-(9>pwyodyBEREhNx+D379w>b!#E?`D{WyCI(;#HcRsn@k0JDS zo_O`Lq4n~j{OZJBzbu}vQK*#9rG;i-0qq3 zqHEa83(oD4LSF5(G3-5MCdz4LTAzaHB=TDpat{cc|iBc8XPC3BjrBO?Pe9 zQKW`o$I9S%s{pAJuwX>oyas;!4g7Ot)}*T(7vtM{awankF>FseeZ<1wspjCtq7kF9QdC*)C^F|Ca zrJpH&J~fg})7hF+UXR20D7y>3{k}kqAovfxh&a0tw;xxB-cm z^t<#x8nS*g+|wI2(_*$~mWZe~UuQz`x`JkhT{6jZkh%i}6i(QU)i+)rQ=x4VRFfHH z7=4Gte18AEo^0biVwi!|tF*6ni2Z0p-BA-O)NdFzD#*;|$b8l-mH=mSfpzL|G_sf2 zS5aL?)}xSYYeacqgs$6-l;WiJmgE;Nlx`B*q~tdCp#vydw+%^I?@F&icgUeb!DItH zN$Yrc@_L<_5D!U2N}Ju-fsUQ^@=9H}{srdfOS4@J}2dB3;0l+US9b+;eIbiI;$;Iz-ca%n( zTSg*TXAPe2m4)lY@w~P2JC8HI+t0F)7YjRaLhEh)(HjzXvr9)e24`-~2ZMVh*W!>9 z3sqO;pUrNLjyG$kdj@CkC*v`Mny&V?mTrf2o3&-s3#xA~w$>?jNXx8AId&JCXKxe( z=2vbEtm}b(aj)J&=H?+Y@AgV<_MbH-_cu1q3hk}##|PZTx6kLzHg5MPV+70te7QYc zzXetRvS*ECq@*o#UPpWLXBrqn0+6#JjJnDF(lXKo$i?+a<68LwB$DrBKE8W6ebMjc z^&OAK*;zyY;3NBbaRTq-DqjDl)SWf&cZg==9Ycge?{A?S+bNQWb5+!vliicG@xeu1 zlGk3>$&k*y(mm(+M#cWPc?0V$YSb7dvbBBFs6!#CiqpZpv(`nSUFW-Puhv9l0C(Ha5CRnIRZ2D+#W6MauCjW);DirC-x6FZqJfo9If810BiNZqN(3a$ZU52uwd<-jOWd-&7bvq z?Om0-xt@9M_-q2E`D@)y_GJ65@0Jd}?K$%v zm)#w3n1eUAYp#FlogTT4cpcf5xBhA+x@8Z;uyMLu8fU$1KXP0=bh{YiY1HH6ha7F; zD}q~Q(nakbIp6i~ooovU`0;p(dK|5fvqE@>ZdE)^$RZkUc2_n`Ah)(BYeyVW+UsgX z{JXb1A5J5jpCVhCXV)LAxnQZes zDlWp~x~IR}<2oTeV(q+wiER78=-unumF}CmGRVQo+Wa2@dDO%pvo)L*{dQd7C(*sbfeRoGcrh)~RDI!I?wmz8{I= zKN8gqnZN2(+Td*C4eRF()7fzF`s>-YpA`Z7?bb>+wM2v*{)&6qnc@}COKs)%Jm03} zuTZBmV7)eB-DcenuTE5~Y!p6^(<|EcsWe5RGn9i2_Yo8xJ}MFb^@zd%&qw{K8uMR~ z9~G^Fq!jw_D-B5M_1dP<2cB!1FbQ{!LMyUgPVBSVKaN+?SMH^fB4zHSN^OE1HTKFz z3j7y%&C$@CmDWT{>0!8nKbma9af#DrcUOFxZg3~d5IF9Mb>ufNEJPxTg9{T0T+3Fm z6Mc0edUsVD-ktaHuEV}`He}gO>436BM}a*czEhTgRJdua_UCb>3j+cg{ZDFyojm=Q zX?;&cU%T`^ZDk@WK8&IubG`poYmG|u^&vFky3)fqHUjOUr+*MCJugy;Z@tHss>aP> zOvQTUFvORX;0ozo8KNqCV{r zer*1uAclS^J=im*c(31&;su`o{n;ZcDvgVOh4y;N45AZLl*{OTUX7)86{ju3ptC+i z0o1;$xKg@WPz{H}%bpFIvg1|3*jjeE_?ZCnzK?gnXX(%I55a;iRdYOhxbMcPa@(kK zSvG2tF7d{9n=-`td zcbUN=^kwVv%~r~et_$FiyXAv;BCG>(7$c14%d4-G0Xzy;xukUAP%j+nwTx`ag-(*Y zez+Ksr&ZiaS*9ryK1`C)^;xZ1ljKPiDEJth+=SR`$>53(os1)!cQ`b=AnB9`p8GYY z$?e&3H|&o|3!Wi6y>6Jq?h_oMJ8QNbJ4)Bzh;bJzm|H2fXN_Ic9scZ{s=d|PkAFgZ@Q=lXDzt!R1JikeE zd=I0b2`&2=kWJq6(Q!I^Il^)wHPXL_KyL$wUL=zC0~@iyLh@b{rx@A~Q*O{+zUhK-Bu^sAJ)Iiclj!uPR)0ZyGi_T&Mx_NjN zVj1C{4i-9O3fDida@9qHKgCc+X2&^NpbfDIs_#wSyB(gbMim3G#t|bbQ^^@!u!lnb?eurVc zMj&nxfy|JU;YOtg)J0*4L1%%2Hb4yRiT?l;V_q%Sv4HWbW6 zzX?}uiK)vO@9xtaXYkq(In$6bgeR$O09BQu)#{{_Q~uO>EwlVr66&do!51aaMT_Mu?EADD{XEnn5W2MheROVLQ@V1xb?-9W#{TduBi^t;|+7 zgC-yH*)b*54n+8^$?zp7vp;M_HI#~0FhRr8Kesc3)CcqV;NcR?t2^ScMOgmu$BrYW zRqC#iqtIY<&orvE_Y_R*)~WB6K8XFX=Y^Ni*gvj5D`po5XzGhb-6zUJ z^Am#@dEXOVmGV(69mY?yPkl}6H=i+rWPXTIQ-XsIAB6ko54ew!)ngWjg{e|f z-aAG15sO}5Q>p|d6^I!#fJwiOu*LFDTwIVSt`qi^78KG$?AXW=L4 zf9Cp>WIBdKS)sRiv*SGz{}j@!dLK70h83q;bBfIEct7AbL~o>kP$@RSOR}bVxc|DV z(#H`(c*Kb9*CT;F*5SI>Ev<90i z3_nP`b&mgq>ic5-t|wU?u*Kt4^ujS!Hu*NN;Yiud5F(fNSnRT@y$ZK|6^SZsp+3wv z0q9aFrk0u?9E2r@wJnRCBTj>Z95zYlB^=>VL?vQkj1`lQ5K9L5=RH4SVU~!6sZ+vYrz{`(sCWI2 zxw)p)4*G`^`}pww8%9O*R^Aiq5305e160xvq!;v#hb_vQgNsI*u}5{sVaWMChh_Ml z(c#l&`g-im0Syu}RpIIEul0`Q86aiLg{&tF*j=oAkk0cpn9bV5q4eSc zJwb0!4a+_jgaXBpg8*LF*N6jU>&(cmvRLD?C^W6j!Ilun<8_UX3BJTMK`Z3q(Ru~T z&@wBj%y52Q|1f^u&KpFr5W+AtZT0BozHy4)m+DEzJDk05sCBO9(Jewa$o(Fxbr!qwSftjMXX(xA*< z7d=xCJ;&(k4eHEI>L4Oc!rA`o-P^BXjI+=ogpyEM`^V8yG!euXj~O%FrL&@ae}Q^M zc?cai%Ba15k~f`kNk|8Rp#q?4~HeBiLyW)bU}?T2Und#9U+jX60R~Sb%@sMy52bn3X(7~aK3~zQ)}P}l|_tt z!KHHmUKR)^3lzs>e4|MOa7P2*Xgbr89@&wezF#fIahko4{%}~gt5Q@}6-!1HN?;GQ zTMe}jzTN>CT&+!=sZAXuPD>auM3>jo>Nb)aU2RL9X-kc4EZtT35*WJw+F=`1Vj!Jw zAk6`m>Z$;+)1#2w)a*4THe#5!!YZwb6rdGSD-3P+*3)OtkXW9bm zRa5?a1=V&jWOnJ3oFEH8-GEJ<0IG?nDcls}l8Y&i`k|YYpNl=t2A1E;Gu_Lpc&X+R%k{zxgWA&^=NFylb)gpoFQWg(6%uE(G_d>8lszr!Op2KjV z+Mm$03EQK~$SB1avqw-Uv?&S@dNN{pbH7~Vd{$4RvyyM7-;qSn*gBAU0Bvghl|HTu zPzdTy8(I4tQ#(*fcTSnD#;j~P$%`5x!7{QI4^ultN>@OI?PHj3C)b@ELf5%kw+(@w zTyd8@XJP&Ndp`ZeCm)0;tI498&S{N=w$xJQ0(7s{u6*-XXhT_R4gP`@JOGb%THkA5 zF&E)3$d95|4H(Vma4I7;paj|ahTi0B*x8f09k911)jdDN!>T|fyaJakuf9HBHiB>k zP^_|nPN_IfvvfP7Sj{pFgxp{_JhPg<=z(!cwsP9?qWQTL6{pIh!zvul!>TR(mAFKg zS97v0N#G`*zY>Y4;apC3{|mT@;;)1t+Ds-rii=JdD51S8lJAtc0P%Ie6h(wZsnn^m6QlZYNWpobWJ98#6czc| zEPGzS*P0Y-nwF4fICS6ggOrX760-nES#cCEZ3T$PG@Lt;+&j;SoC4PnP2U*~z}Z|V zCY^;X;vjPPo!UoXy=E1IIP|Qgi!Mf^A^PErevIAVl{T(Os0dNkb3+{HQ#Qg-j(vHr zpA!EY0=qnNzRP4;wv-kZ}Qm+xjWhi#*cGPe?hn@2l&BkG0f9;$i|} zBXGzoOYpAgc;@RvYEt}^hD10t+@;lKRyBT7Y)-W zeKQB`zs?OPXsooeQ_zVVzxxW0iQf&O`aqxc5yY@wI_nZ}Zf79)tcSFidkPJvUR=JI zpdppO#t7Mp2@86khI=OdVBa9rc>aT5#ViT{`jAq&GxSa>{%$ewNEO^^Yg;}t@KISm z+3xkEk8w4p~W7iKh)J2_Dl_}+)zT~ff)&BjnaqabPD_v0$$R%@5*tY~^4 z+&;tG@r&5d)vkZ!2TZxMV$sKsYAKQ79})P}y~lQdKyQ$XAXS2ib!hrkm>X_41cNx7 zZBl=i&(MLSqUrqo3g4C*@s*$l!8^%fUSuj-15B23JCYNI@SBB#&{C?2Yu~8!awOKN z`f&K*F%5}HOv}=?9yLv0Dyz4W&A~>k5vW<)fm}8QtISM>_}rxcbt@Ko{6-u*lG@qq z3GgN{UrYiFpTg(-ZA&7^o>Rh~xQr-9g+pAWKE_sPt|`zgcj?-P2&+&ZWGgh)Y-*JI zGGXv|M6<|y`@i}#>S-Nucg6hMNVW{gPJwthtR>cP3ey=W>jKfpjuP@ z0DryYD1|)y^|09^!-tFmK$I2%qV&j4`y-`jjvl?nGf!@vaWC}&U0ztJ5fojrZsL08O zyiF`v+hmcUT|2amPQsv~qkJ=uqpx5`@7gZh%hT?ICPz&5R2!qvSK`6l5B-_qPQB(~AKSriVzvNzX);y0QG!1~< z{(j*0HV*Jl)5F<*`o*nw^rNCRrcislxS(e|(Tlpkbkx=fdL>o{s>7i?BdU*(0acZCCA6Yf25;Ov+%1&2;P?cacaObgh?HBecloFn zF>hddSnngbL}(dykQsIVkq~@?P2{!tP>fM4D>l@OT9!EyT|3eFOY5VDu-M`e8Hs9W z4qgwi>0as`X8jj(%pU7`qe5!7MxR$w;H==e)r@wSN5yNhbt8UPoW`Wwx%RUzw|9m& zW`s9pt@8u-_SP{2%T%@Fu~3-lF$CGGO}`{gHas)`0nA7&}ThKx|{xG2??{)3ICb7lCm#7BpEFG$GDB z$)|PGZ>p^(jY5a*>U#!kq_+UKfdbJn1kVn}nOYTY@fW z2=&HeefJLy1&hYro)jC8HQ!G>OeifSO98_fKqwAD$(8iL#74=o*AR zp-UvfvtHA2+%~m2gH_BQUf1LdYKK9=VbD%p=sm?hR2L3vheE-j&`zxAKh!O;czLSQ zs~ryo$3r{2{td#QU>GzfU55Kc6;44e4!CCt6kPHTP@bcP|k6^`lW5rRXEg0ev0Qs)>XpW5HY%=Uc=zs0MDT#9usC|bK#!+IuQDP~7 zXD4v^4Z}&@t%zx;EcgBosn=DWMB|LntO46}y5mzE1FFtrx%+hhT~Hh+zmvdieaPcR zeuO5?nfhRpnB|ab(|b}2`KYhUue6xa1*!*2Fd~e|5Taftri24$YOwP25}Yt~ z6j`l&onXTHF8)J8ei*Z09pzsS*gO65_fk z_$!=SYHts87IEIb$~T(?3r~Wh@b5a|!CB*aLeNiRyRH&AmAAZ&>T(43?W>FCzxWuE z(s5R4#eMMsHwoPM>ucC{zFDbqWDyQ#IL-Q&NtPt zadw1p_MEavE4~H1$0Nb&-*8mF#k7!Dn%nE3i7{&LDl6?OUtV_Smfa6llNDBz-Rvhx zR_)4Ewxg$Y(S0WKWbN&)^3!hC~zaxwuboI8SgMQgQ!mK$Sd7*hz=mNvFodK7Oo1xE8Zm zSZgR0Tj)rS>qxI=CGanhngN%ZLG7|Y^*+wGsAa)D#~EUQ-6I0i(6T`f^qw^OqOmv9iD!JeVP#p?1+C4h!n;iZD{BUZtv9rCM>OUKR5_ zuu5E@Fs@uRrd;*lSiP$B`*a4MQNB)rH@HyC_!mH28k{24B|5IHI?oMn3qKigKN(yX z6a4?YQIST(VCGRll%uFqC$`bv%j< z9@Hp22ReGvuUsCTkm2GRmlBnziZQCC-Hm6&y26j$46xY35gGAnWt zm^$!)q2>+O-)#RU0%!YEZP&sku9H%MIR8TSwD8rK0yy1gEX$Um0NX7#l*BibV)5(7 znXowvU$vgdbeeb3vLgv&7_ymH8F5tQqAlo=E=0mFgk#~?@W`%q6din>9sCF?c z@=E=9$hF14*^OHy1zRLBq%By?EUG^Se(Qs(s)IjfqKz#`;8wS)YPagaFZHp5TB1Pp z8kAfZN-j!FL2mB{uID8dHL~J0vbfJx|c~$%u)eF)2 zanbqJveU-@qB`7q;WPt@4Ov69{x8+d9Y&w0a=QNFzTdh(BSxPcDPbN6P7?T({Ef~C?Vv^kon2;(AP4Y0 zd|(Zv-YSL$ZIVBj&jNhso*kV4_?|mXhdxdxze7FvH{WwR>Cijrkyp_PeKxzhbY6khs0?xnr4)+{qKp+1L%!yYStV`mwQk$)|&B?UQK{hteRr|o2 zmt+%b4uo=ZbXie!+2|mVmn9bNyyG54itXw(^8H#weOgI!4oT)}v;76@IZ!kyNsGq@yxIY-K37lhu_c6Wtg7X__uv+>)rZ)@9Pf5KLR2f1T_fPZp zPoqKkVTvaB@qNo}t~s`%D7GT@xcN((G*|UG{Dr@0_ycL??`YbI?a}Fa|3-`o(-(nMoAyGITOGi83;NW5a=yn#eysXqe&)yg z-jG?-IAnN~b<0`e5SHf;CgKZDYI3nQP0Rr3SYkxPg8idJodieY-wnb8_eR|w5X>!-qB&PV^1i6|SodwJe`!|kg|sMSRLo^0blXhTZW_+{ zq;&@L1{v%nsh59oo(PUHqr1vtSIGVgV?*ba!=42H!My#s0nV3LpX6C{*}SRt_g={z z=R_apl&4wUePRMRJ5MEk>oiMsUe`J?#`$B6Qy68}*K(aS_-dwKi0~DYrK7y4qdfMT zQ3a)q`nuzt=FEv)^AdT{5_#;7F$L}9m4)*Q_jbuj^#xAV1y1lnb@btSJ&!Y(+RNtr z(*$3NKVJ$BU&_Ql>=Mt=?=!@R?efXJ+;U0xvBQ0QqpTSt&)ZmUC*XcANM5;Q`yX&& zrK&7$%|)XTR3)ps3uWn&XqF}YSQOTrJ+3=p(`@V$UI$sK!Hm@aD^9i_mMp$qygfe} z9KK80JW20w)!mu!db`jwH4@N^Xg8y=!YQOcMl18G^C4`l1NkcK7008PCw6TbE52c` z>}~MiL35GPYTMP096wv!G%ZWpJ z=rMJVdJ9VX3tBuqkXjeL8m}B%$-Dj8c&aNX!qE+cxU(B5LeV*SIx0SI_;YfvHhk{# z=ivE0rL^IHy(QG*cCwdBe6xQGd_-@ryfOZ+aq->W>vw=WYL4VJSt$k&Mq^R(d^;e} zviYxw^~%NF)79~)NMnD2nd0_f@AuN_`pS6w`0n5hkLL>OX`|PT;+?DW`N84Q-XS1n zy6T@lxxU=J@wsX7I6BE|oZUW~%p+m$zBYCCys~p{2DDE#cRAFz$@8qvdKZ(Jq9jvT z@1E_9tqeYWg9WDyO zi6C1!WG4~IU85oq8a<4PAalJ)h#)&UtRNPOTQd@b6!&*KUDw~8x~LUll8|W&m+GNY zv6yzOq-K(dofBvS68DJ|b_E+UE-Xn(mi_23-j7|cnq7ZPy(p+_ddaOjK)7-|0nYjW znmyE=(qw%fI`%>`tSm}5WPI=yGhoe1gylymg^&yrFalPxL|A5&NQlYzb2`A%kqAqQ z;tYu$nWBM@lL!Nq|R*+3k@lw>tBQIEF@z4+Nj+k|K5yOk*#V zJ!#TLe23sK5Xdm_igJzN;3m>6fK&E|sJ+;bX>sHY*6HMWr{Azzm%8kPhL)Yu)3_^3 zBk+=neppNt-5G8opn4hHFY|BGhA1KUuZHDhJLnT8&aKM#ujH=S5s@lFB&+m^2BNN% z-)a|>%l)2|EvFl*&}Jy<;}f(-de=j?LSOosp{WIyh{xz5m=-smxuxL3W;xQ9=n|}x z(Wh|EYIy*B&wya2iL+oi!&5h1rF1ah%t666;u3E3< zHfVbSkXFOy%j+%|%p|faD=h9nsTNjcqP%$v=!qKd0#)^;WcQdYRDY&1wYHNy&~k!v3hOlrc1RRG0}+~7E~c?@8C)97`_NDDm~6)_$}kfpiM}k*@do0?$@SL z!Y@8;9^dlo>!?JRhSQQIE4ofpP2Yg-`{FZ?-!-|6g8?W_${uff5OM2u*4{l2KpO`d zZ+yKWiEM#&dT;g%Jdd}~4lb`&!6(sdif?Io+?)R}>v_Eqn4~_LW&W!r(wA`J38ZR8 z+LJljsf%ptWXAGoR35=QWG4l4yR~3-8546na#SbX0{)i>I|DdkyLhK=q&Pcs%Fg;I zQ=jPr3z>KR52$+%O&lk+8(QZ(MNuh7p>p`O_R zeNOY2l6y=v88pmh1kWQ8pZxKAD|_3g^N`D2*vI=5T;0P(AU^}_g^~EKB7wC`kMU}`5Qhe!UuFTGjudcB4pEPR{9U#ioB0XFLA4-*)pWr z0@tZEqxD-?xfMuaHiWMb9$zB(NI7|*pq?@g4GYX5_|&2zR-+<< z9%&=^nBqOm6n|c%&!#R+@9oVhg7OOojmY4MF@bQ3w=h2fT<6o1OsS`iTh6TVJ(7xi z4T*yS-Tz~ce6yjvaC_J%2dbV>UV;|(Wvhq28OV}vIxvkPWN53e@Kue%Kc!G1c_aBd zzz-||=B@sOLP*z}Eme0)uW+#})bPxWw9>X(}L z5>-~l5wi3fF)U6hWF%=3R%|pHLfljgnMY7)23XpxX!08rEGjD@y>SHn^c7^GkA;~a z7F8)WhUNalp+%lGLxRa75(_h13|tS#a2#6(*M7GJS2%f&ET;Fzjoi#!JmhsokM z7G{%}c`kvx><)P1f_pd+R-XS^PK+EoC()3TxkB>Y#;od!Sq0#Wg5*P1ynG#if8ze-525byA!xaISHP z&k1}N2aAj``@$q%H1|C$mXcdN_??RZ5uOq#4r004Mi6#{Qa)}1@D8U3AvJB`}v=8Hd1_LRg zA8)8BmEejW#QXuv1+w$Vd@*@dO00XuPhejY&&}r-Q8GWIs4122oeBonJBC>~V)GMa z#B#CL9ulLg+~+YLs-;nWsQDGdseRn>ToEoH_=Ob;h=5Gl%XPIof7R^<&436-Km==H zW}K*>PV5;j(K9Gn9^lpJvBC7%`ikbvuDzR6f+3HK0#QGS?~;W6A_+Zw#z(ZT&zc8Y z{KN=zX0zDWUyZGlAM!bP7H-dQp~33*H0$)4#PKtU&rBmOPbGO{uNyI%eZcNdsemVP zI54%3{S0oQk900tU=- zbk3QCT?$6e^)m+IIbP)i?#9E+Bw*%xg3DHz5&7;c;yVpE;;dNmtlRLTPWgy3PAHbV z5!^^BZ&bz!$C8f+jIf^$Ij>^p65`;z7c;oqrt1JD-A-kx%HuI?rE^4EM>4PtjQxtLYHGGc#(!5)&{Z&k}hT(FAt@b zFyR0WI+KBPoI%>=SYQjRwG&y+KZ=5ge4f8VK0c2vu_0+uk8j1kvzrvK(>u zG9vo~U;6}{E9psG_)|ij!9E2lavJJ)9iYb}P_E&hu6RG8a{W1g;)p{xF;+|Bs|*Ko zJfJY@)ihFHAb3dE>!2lr2%}!{)zUI}5(663q=&!rfI9PtItau`xZfYTUt|qEZ31yN zgTOvCM(&BN^JEETCOV@Hz@b&zTE8m%5?-)a=G*$8TA{CwKcc(n0C^DfsVxVA$=jnA zC%8=LUI!#i`n4CH*SLJlV;GaoE+Y~OU458>22>~l)Ac&&q>W;H38?Lya}%$_D~5*m zztSlN)oCAtNSWP~YV>J3nbpXM)W~3k zC~%Obf)%2?PGIu1=1VdnOEOqJ&``DaF)FKzp1&rfwcDXe?NDP_WT+86f(z4Z9kkweEX_9*L-$Gw0MlZ(EXa21kf}W1|R+q)W z)0j~8Dv)Xw$b2(N?rIC3(*Q9WNYfceQ<}=>#>1mEkj9ku21CuQ;L#d8SPg0$WBlc9 zI(p$pACy?oZ&2cYhz{xiCH_TpPvW?oIA#z*8Dc$oP*8 zP;rVTnNyoWj1e^K1(ynO?u8)!ODY6ZDX(C@&r2dD7=6wBvhm2_I>6QKfPYJj!V9b+ z=C!@KgWS`cv&MNU$ySe~4sT&z>h8O0a}u&vqj;1esF=MWIvhao1o9CbG*&_KGumQi z%#^MNa(@%hm$^b(Cme}c62v;xt9hTe_~Qr>GZO+F74Kz1hdPETnl*}ne2}(t!x!B5 zf}cgK~$)W76ItH6ulDkEm!CO@$qk-w+Io{5n9NFee| z)KG{Lu0|rh@J1v$&7zgDs|pjJ`ecTT(49Tb>1#oRWyzYz)z|ZebF`39WE?FhI)0$i z*qEHi+z~C4&%dKy)|8s#|Gj>QBgAtMUXwJNqWCaH0jP+WuBA;$P7&coIw-2Bs^sr+r-gM-9l}OW?;TLD4}6!q5jezmR}KDKdYK@kwH{DRD@1~qM{@650CG# z+7P}?u?m zlwwC}wkBnPYNSqpITvbXl3!9NO#Y7?@Toa6YNoGW5?ZQ!>lj?w3sfUP1SS`N9%zd* zQ`65kOKI%yR3(a|%P1i1#f_<12^cwO7m=H)mg0TExs`$JlN)lIijPQ562nfXcf8-k zW;P*=ia3bxId%z2f|n+Wz4N_l>v3LZ9O530SVG1ZzBq;YZsur{SYd!{! z@OB*jFXsL-tcvda|A!4aq@|^i?oc{62ojr=?${fYMnpnV*mO5YcY`!2(jijPAl*{Z z^`E`*y1v)v_uzhf>v7DUIcLq9nKke8Tx({%)?z6>yHGY4AbC(R<=S~Qov&aA{jv)H z9Y(Zs8o8JVXLz}U!d@AsRy&Zv!JsG4C``(}PP=q$2${Y+7=m*J&raT-aW#g&a>55G zx6|qy-%&*^>ZAZwbdF9ZZh~j{mnzCDhf_uR0a3*jXmWq4A}V4yRW#q;qxY(V<1bYd zg`kQ)nyhfKmC@Z%MV!{Z7KPkR74+WnbYcgAn4Vdd=9y@WR=BxOm4LhcLlD`Tm}ZxNA7F@NX`PrG!zQ#n2weX!Uf=^xuOBP*X^J)U)+DK*68stN@VXA)uAp(4*?qu~ zy`a^0(@s{%hfz1P6wk+On~u##)m@V*-qx0C&~{djktFR`8GfK zOKxU)1N5H`>L3Zo_KS!r6j9PPrS&7 zp;0=5I=z$T3?W;5a-yJcjf;z5ic=CJE1Z;a^MiA91PfUH9G4E^$~^%>~2dub_p5uDMEpj|JJS8|>C3cF4R#}u4U zNVr~O2LghQQ(`CuW5_ns-B~!TdjO~)_FXa9Wv%A^FbQ(EPBDb12vX(dUJdb10SF;o z{unTSOlMPy(&Y?*`3TrtlsrD}g_D83C|MTO@k3DVjMn4`h$B3)C3eO*t=I$8s!bdC zrt9$&k)a3rRS*lr&dT(0sOST&s!c=q=JZaCcE}N$L~owSYXMw#8+8?sy2@kKXr%}Q zPPCR5x|YUPHDo&=Om_p)n=Zi?CdC%k$w{9gaYc;2snQjEvHk!s3F(=S#=EW|0KsH_ zp=gtwcvn}O zhklRNxFtKNmkF>0_ue_U zRxRmep?RrdZ-HX3>GJ;=*}=U`;NB4xhJQR9ky5L-KeZy?eoD>lk;zZgs)Yv)1!UmpQd{N% zTV@_G>tEzovjRApCBc^^ftFy5MTk_T0$#Y<0De1yC;++_ z@!Zq~lG_nZy_}E6&HOJ>!0h`1_AgNYtB5kaBMJfn(`hlrO#k*SS`(;95~$#fL%9F; zE+S9hvH-n{Um00tHS#-4Xb`=NO!dkR!-Luw0!GYBN6aYsq1!_f-h}#P_0}~29u(Ue zo$;6cC6r;6&5rZ6&J9JreyQ9IymvD(|AQ25ZeNi8ga6(^Mw|VYfTdeQyv>PuxvC-F zAt{73VHDbhOx+8oe?@h2V64M-O6oxG;wPtqo{$++Eo=l6R8FWbP+%%O^Lq%q1}{4+wZq_`(5Tri0I;8)kXutY$jj=ro!(x2tf$ir zjE*alhXX(QhkJa^lthCn7>6;m?IA$2Y?vZ2GQ&lKPn)?%6NV-SyQ2~2)qVgrJLVoe zSdhX0*gi7%m;m3N?rg+-u|NgR@~&9ir5A8@42SThl;>l!`J@BSQl;U*G~d89TD2ilEaBz4OI<%;>n~Fzq(}I#x9jo=F$XCtcyEyX zOAE@H#rl%u{`n6N{9nubAJjJ;O#iVUfC2zG8Yao51~LE3_J99e;{u?9Nv|ROh3v1# zp|LP%EXzqW)V(-#1e&e+dfYS?W*W;9p9n=jy>^;@f2}5g48l8V7^^#|TveJbS!74%QyW5(!Wl2q)$t(i_(*H7P7GDdYhcV0g8xd#*SYRy|<;=*IKh!howlTX!3orj)HZ^6zvmD#aAo}uZrBZ& z$Po8fsm52PaW)?3yBF^w`&hE$nN}ysTB+PDsay<^LdZWbfqFoq#=kIu##j3Be_;a6 zNqK$%CIFbiEX}MHuPRL52mtd>DN+(4QWDYB$R98368R3W!Jn2!BsB$f3Mb8TVOurH zxqiSGbz)MY3A3`sbA`?|R!tAF@n5kH*XI`zFialpJ1}VI77Bps(sh zLN!bcpfZPhdts1P5r`Go5vTi!>>qFcuLbVy4@*Tf0hU1fiK6s4iORpQf33DdFW~L9 zP6b&`1$`ki(0^EhB_2slVHk@Ltf<+o>>rkZg@Zt&cC;XC6i9jm{mT*{prQ$|>;wQ6 z-H!id2?{raijreAR_HbTF%dR7M9p4w{zBGEP1X$@24@L?h6sQZImN;Bb7A&52&Cu= zAcx?XQ9P_U7dDyuUz<}Rj3N)VU4XE8NJ>+dW#{XDzEGcNC&w+#`c)6*SCZvdB2uyA z-?f8NKE;+SMV8Rr7d*A$@GUczBC{el=i*H_J#3j`U1W7IvO02~#^?$HCz{U9n$E=t zDg;nLI8LOgD66SR^h*tJbvRDM_zA}NiN!cK`FAZGCmIwZ8WhvKr@)VWhZDK8B)b=V z0GwwGffMa%@a<_td20Q2_3^+oSYR59+7R@ws{>mAQ}nv6uha3N;J>au%_js2Qcf0e zPJuVv9Z|yrUqe#5m;e?i2GyRI#KQ3C_m>IWY`*^@MS^oaP5+A&aR;91W(JbvLPAG? zwD0Z-A_f4g)eU~Gc@6kGfDvs2{yqwg4TQ!rocuGzs3qn5P_(qF9!=a)+ z1XL85n;8i3Kbc8dwJoX8*71Ck;_19qHtbb4B}SpanxfrRjiXWpY`t-TQd>xYErbVb z1DZl)T8hYYbwqU)fQqI<`*P#|B7>tW34tsLjGq@Q|009QTGf0S)qItw0)LUg#_1jta{z;yVxw$Ym4{LJ9|;H?_cyEpR>fr_a7 zbLP1wF>#DVqn7cHk_(-U%=z?v8aCHhu~W+V4$k@RM)zC=ml>gNXA=a9lNLcr$%v{30NKCn4Acry3DHmAfuioD?M0)!3ld2+z# zwdyX^>yiOxQ2MLGC^R_`n#@RW=<3VU_Wnxw5l7Q5-qnoJHiT>ol1v@o+RpEU)9Jap znt??TU)z|M*_ek;4S8DNG^^)+GOubgTJtjxpoq|yAWusN9qg{IS{CVaSnbGI?2?)6 zreC~snoVgch;9?~kg%atmZnrDpj5V5>)R){I(zTe?J{ZeR(&$N1#*5GQVHIz6uVWB zY*L@JX#_7XW57&k)ft-eouf<=n0_tdi{3Yuld=>MJhD z-!?h_X;)_FeRaOJ?*0AG#n7q|r|Y&jhn@M(#y4}nXS>A?$yE6f1PrN5_l6yp{I5Y2 zr1uqkpDh+Uv;)vk9j0{Z+4wUDy71ZBT#3{_Bn)=8<8h(FFgTNbk+QsMLF z$F)O_<~2BYxn7Rar{}YxF|n$#ASUL&u-7(s-DnhPCY?w=J&D^LSV2WTGK<@Vl1#od z`Nc_^jQns`!c01e+|9PYN!sg}3O?_ha`;WTm=`er*p*w``?KZU-=pJ;N8NLaM~fHs zNA_(^jZ>mm_LJ8qCu@tBGuz+hRGK2{CK9v-+W_`x?(h_tg6_=z{m}t1!5uIGR7&ds z@#S3GP5y1O@Ri%Sj-klTjpN(bg58xmS+n!vlU#>`6YvS*7K}1Z+JISxfZ3EHnzrZ4 z-vToYu{Rkg1P^+L*@3WJj1`@qSExh?QmswBW7qR;@Bn7$Xp2AEuj}8uNb&l7VH0oV z#hHFPpEBp2II-xC7O3l3NUurxeE#@POON-Lg6HM7n&MK&^<&{HGFZH(XFti^EBR-I z1T?~zwBDL_lL|Lh4og>shuuVltY(L$S?;WKb?Nwc{Ydi_Y$#6K;LDC7r(8qQ?F^<> zes@{Ukh(m#5j6D1W6S|c`n2fT>T%mo`|yN%Gt{Yt`zxB;&%j;Gd$+YgPR*~M2s7P0 zqHfUb2^LbuyJtrReXkv2P#-RrxFyDWQi) zLz}F%Lc3|=dm+YDw^ytTLdbhV3C)x?P8SLm%EOmVl>`)k8TmQG-VkyjC9vx9Eb4UK zaZ7pqH|wfk<sdybOJUAgn!(D=EI*jb`8!$F62vnq`bP+*r@RH&cL8_-8a(8OoT<`AQg<6X<6KtYBIEp{3yC00?-xSz(BexbYNEeVqYb${`$38DVcr~F$qk+-O%9u@nVIs`6?^KE> z6&(2r@{&BYBJH^cL$0iJ0VzIClXZ4SRc3Q}9TPIs4O!_*1A3Kg-okwyv+<*W5 zQ&sS#rUk)rQB`nFk*%qrra)yGOG=HArT{bWD^uLZNaK1nx4204=227AH~8FsEri^~ zBbIO9J3TX+yCR-oSZo*%pjhL@#9~HMe(HX!ae5{$vdvZTYpO0KrY-4eaL4ZZ&DxS( znfnp5jraSv@3E)c>YJJyZavQJ>lX~R{)me0yb-_dg^lt~#b1@!d^gq;|7@Z%@+B57IW>zSZ_8noN5Ry7`}PR|vW5$8%OHh_EQNP9xm4vbXwdX+u!mij}Ay-@VQ{cWX< zTS<=N&u%{-78!xdLN^w)j9iEpGg@194_AxaZ(fg&M?Vv^yZt<^u>WVO56b?G3meG- z>tNhR*Db8k#-VWgjSsH$Ja>I}AZAH1QYMPt1@e}w4;1w#qMPWaW|3+HJN84DHi_DY zf{^+revhrP1@szGw`)np9?gbe6Py2#dOZeFyfkhh@tgK}AM*nm#aa-|KHb7z}Dg z4^uA?Gjd@Trm8p^*76(e8IQkHoqn7|r1^qqBX65Jr}C7aH{|EY1dMCc6SwN;Wkph_ zP1_TdgzHzQr-l)nA^DC~P|&1sKnqj)Z-pQwbelcLlPb4H*82hsk@M)B{U3j;1u0?J z>;)VE)?y@qINXYxDi3RHeuaXj+$s0#m4Z2knT=d92m6x9@=lD?FTtmJQv#a5;vh#- z0tH`MDAS1D82kjZ=+S0hQwZ7b39h4nI;$UxWY0HXK6N3Qow?WO1D>_58N{t;O#x;Z zQxTk{$p7-SFL8ne7^D3HIYF|sj-`aYA5__l&-S*ZDv6{AZG(}!WV|=O#$~F)K>5{g z?9(D__v3&M#hgf+GvotXn6udDHHHBh;SWV5p!gj4q>9uhpps2v)k-Q1Ib_MSjA{Lij150zlp8M$+0(NGO+5?J}ELz z-Jg^HZAIj{|Mg1@ktiOjCYRXRY|L&x(d&K5Z?PZv7|@i_lk?p$cmDkRG=DJ;*)|&4 zA7)=ydokQwsO~dybaZ)7-!8HH4Jx?%1Uq`Q`=N^Wm{os#zxwd~iu(G#pM~@RX~MlSZah97 zjGj>6XKsE6Tm9G7$^1x4fe*4Wsg;+Fch2d)YcZ4XVPgdOJ#aDcU0eV-mMfYE7-KZ` znZJN_TbdK}G06&(MPPlFdJBCi5vMC1nA##w`2K-%q*s8CQ8JT~^8?znF9r`!M`R!{ z0=MHTDf~`gMjVvq_g^SS;6G%} z7o+@rBCJNB58OzRx)z;m25ChgGeI?Q7BNs)D&}KY$w{tz z?NJRu5YuN{G$-pnBWB1*WXiU@(F-E%CG+1%BPD{OS zHJZiw@iBV*egBwXS}wxCn`h}4s@!d4c*y25k{3P5)j^$14p*{|9&niceLfP|p9-V$ zmsKomQ1DGBukx=QS_-*Er@lO_=K%fCXQ58SkjnFwR0rZuK;e8^QK5ze8v^20o- zcOdl8AQo#75w03?rp8y}BGq*81G)-~;ds)UIDCoHHo%ed6KLaSh%(?DM$JZx7BVu;{aeZ4b^Jjn**jSoLx%-Q*Sy%9i{ub+Oj%G4D{O^E zw|1!ElaM!BeHI#D*7#K_W>Iy3J}WGhUUwC~Lold1E66Bo{1(_j5J1T4%9^8jKMft~ zFTu+2V_%|`4-CSod5rWTYrr=f{^7T@L&5;t{A^@4sVz{0kLOd|qXJAHte0d~okl3U zWgQYA?3(C@E~1f{^1N}aZm0*~u`?!GF_;=i)-M8>#-X@8l3aE$jMgzbv9U%mBJn71 z3fE*&wa^DFV@#ME3PT|o6rP(frD2986Ux%dg8K@r<%dbqPk>%_JlU`yTG}k8#w_c2 znlxaXh|w6KEVb+&=Y`erWTZP2$oqnlp8+NxoK+B*rDIt`EImw&C9B(e;c&#zX>3rj#|81M^9PLjpnP1fC75GA*iOB+RrR7%eGGmzQrVeWN&lwl5%y zQ2{Sljj&Ud51UHv>vBi{ZBam0pd#L)8sS$}zCkLv++~{pT3A5V+Dp9W>MLbm_)e`j z9j?{_@lwP=VX3sV`Aj{`(3O>!d`szq>(nm53qF(Q+99Eg<|O5C_=Jk#rrYWTw;PZqnJ~&xR;htjt&Ay_m8=g)qY6W7$_g~VGtnlT zB*NZ-T>+6QNqdYZFGwhlX)Zr|(Ksr@0sU9<6L5BAkTn~OkOuf8ytCrl=fNOjJiJ$g zEi!!Vd3aXUiDR>@w5PDF-$9@`XO4oq9N884@bdvk?{lQREcm-jwi9CJy-F>@G!;Hm z_>Qbdi_U3bzh*u#nQ><${+MFc7BG1ip1Mp2VG4aw3t;AwMS58|p@G5`mZoV`^Mqds zCLd#3o{goHY-J&R6|tP(C6C9gw&N1}70{K}^@l4as25=rRi~jGsTW_lc-swxRo&lJ zc1Qa&+JP*IJ)a#}o0qg{EFZUmd}#C-xED9uA^)+aH+ziJpb@#aMx_2UtT2tTD3BL?fa=3sV3Q^7m00J&sd-9LFc8&=VEilNB8$ z8`juO3}PSzF@(k9)8^8*7nu8lTYkN0VSzNpMshHKK@7`$+i}W=xi6VZW)+3n z99E5@ugI9yIUQDhJ1%8kvq9EkBcC&vD8Jx+YUiaUfUF-SxKPr;_Y)RQOB-u;Qcg-J z&oEen&r?eOl9e=%;dHu^Kk#iaG&T;`f*A~v(%7Va`6ka4S z#NvH*t6;Nz;L)J7zgr+ROR24W7it|(yUWwmMZHZ@--4Q|PRKwUt`oyo{a)iTcqUTQ zaiJgISY&N;2uU}od2}&+_`wQk(U5A8YXP$n`orV3R-mxpNy$m1WFX^a)r z)EOQo0;AWty+-($X_OSyQ@CE6OCJH9;D?SNXt^I$&2o? zi0jLaUm=TPn`_0Cg@4FC;t>*Q7q!pMD9=2is0g!pk2|Wzn}&- z;2OfUj6zH5DaeEOV@UbRj(kX7f=4I<8dF+`qS8Tb@W_W?T&}1w4fA`Wvq_voPnBZO zAowpRWdj)ptCs|ABtvD$=n|~Q@h6r3-|57as#-rh;EzIu0&3>1Ei5;RPn(%ToS92nF-nI8mP6oC5JfaC& zN(t^04A~jU@Bxx8-MQ*Q3&2!@7nPC-J&l4P<7$Pc8ax*ThFHTO;ap8|hEY|>IJmG5 zVM87U2{MeyMFquRVrCBW;|L3 zd{07B&oL%94^P5OF&Li#ZH^-S1(V}6>+z*)w!z~yZ9hh-A2Nr(!)@Q@8ZMokuuHvv z0$G#kNtI6|fUKCdeUx^lJUCCZ_3VgX zgee5qBI*-cl|gcPW>8i$v@)-pgkG0kCIo9Z3y=-k*T;|wS+vjcUmlZI$PTH>;Qd!e zA;2-T9r`)k#58NPU-iwoh~dJLZ;~J7keZg2YU=sHu>`~+v=({HJTzo=`gBPi>d-@8 zj{7x_qAkt*Z9`?UB|uUPr$g>uS)?R159x;0BEd>w&r&*bP>lS4g~;5K0`a>D6nv)| z;lLlqARPySkC0way?l;9-5_|pdChy0xP9q7MVPz8KA}Efp5USlOu&B-_>p0 zc(jbr=z+m0#uQ;=G#Z zrMxi;kdbeD@bU%Lu;ZanMfoI2Qq~p1`kPZZO}m) z9b`n@S+wxOSdzcRq!@uf9m#myJhYFm3CXX=NYp(&$+Ep*_la77N$ifz=uT34TUvF@ zXhAPKvLZ~gBgi@<%Ogz3I4K+L~TUXSrB209YL~)7a|4=6Dvv(-`UP4 zIR=+J$ETAs9hR#cmOF0z=;=xL5$Ngj^rlt&Yx9NMvc+Kh2BtZRY!^%d>CJ|l73CJD zV?328N}->ESLZ0n*@0Sa^3;y|;^-CcQ_xyRdn)h?ujFL)V+D;$ak1Zv1T02aWsq{Q z7V5ii?7qfIt5V6V1W}I6;N5J+@NhQgFA!0#ch(J}K znQf29Q;Coj`eVAUOKib?zzZGdWoS@vH9bokyv4-*fH6K9hHVUIBF{@8_;gC9h1rv? zH@~eq?Zi8RqF$NN0}rnyyeh0sj^+B|{yCnFS4U4o{RB9WYH)j~+#8po5=AcbSI~P( z3xtv`u!HezOgrR5;Yr}_@Nx!RqDqi#XaPKlD$oq~@Fb(7GaU>fA;k;vf`xfO;RBYy z;+-F0=3b^XYS~ZvZmv@J8BIH6;1Btt0E~5h!36RoMCAJF57_n(I2+^e7#w=R^m9K5 z?@8rG_T)x3=zRJARS{6LO~`R?Wxt|h0OkCZByz-^B=ZzQor3{McEt#?P#X1j6j+#I zCzD7L^fw6$=;nc!&TiO2-cM}SI(kxHB@)=ItsLXzDd7=!@0NWtIa@Bo@)oh<^2>~L z2R>^rTuq0K3s}kP2Mz`le&Mv+HcG#5!498QHOxp%d$63N-D&R{i^@4|qi^VKCFmxK})+RO}z6ps~)qveu`{Bfc9n{2O@5UgCq0~uF zA0?f7)$x;ra@7t54alSTiGP*0OqW$QVSmY8B6=HVCtbD}&>Ki>PHwoO|FzxYo6w`? zlh>09iSOJbw-#lUU$DIt)4y;tpcyp!fc@}S^@4DVK-VWdG5uNgo@dRo*%XFBPHuQ3 zi$c~b?9Ox_TEjr?E|xOg0nNGJg4(P)hQj21KeK;~vLBL9B#&ZqoOwidkRJ6+khbu* zmuP6td(g;ikjBm_%}JbUq%fsomrT6wj}qJdDro>sZGvGeuZ+wx^6&)b91x3^lhWjOWk zacs)X9At@&dRIb_fNjHoZ<^C+*!x_~34A|hG~HI;v(p(r2>jBjzDarM8^A)$8wApk2SCj}>2E<_~~f z$e}m%Z6Cb)D8}n)mW);+`c#s#VS+W6DOcF1%ua;piOsQ<z214Im3XPa_XJ;p99ReS*t`U$O0kdBI8WnK8`ayAlpW{!^k%Xt0O*TZ?b_ zg)UH%k?-=uK7&bmvE>gRlKy-gXB9|io*1=+G{aq2kReiS0y%epl0^5)S zb09=mNyPKl6^+${XU|56@+4JoQ)DWA(xOs46qA?)cpbAakbCS7^Wq|@t%H40-ZRzZ z-n|joB2j?k}vip zn;^11FiGRf>~xx~q^xvqzevKj4VS)jABA5Ak-btSIw;FR}dVcIE zj|2ydhC&x>n|1nx@g{HLoSC^$Bi%~F6N(a2aI{yWFAr3cPrCc9 z^b>du{p^9!;2+0!sM_u&tP|D~J**=y8xJQH_qzY*dmJtLC0E=)99`1UH{y~X!rB-d zwjCN--%OYcf#kl;YLO;SL2e9otWQ%cP%4~j2tkv!c;EYH`q1-|pD8wK!N@2Eh#bGq z^pUQ4z9&aU7tr&U{qxxYcK+o_Cz61+|1z)<4r~P66Hxc}Jp4Q;Z4Zsm)~z37Ihafj z=>{Eq7{q6=oufz_zK{tJB(R~V{o;Ot7!)^|^t`KrN>qiI?9^{51&%QPJoQw-X-Z~96%Msa7knBSU2B~N z>#2A4g+P}bc-xOG{ksRzI5%?I9QSkj%SKk52EJSvg_v4R&hKW;7fcWNG@V0 zKy6_&EJUQUEkvPAx8>k;pHw#hr_bpg1J1(w_Dk_!qZI6v<>**gr&L8t3CKkh+-2NTuV?sA~PMFvG%UbDisBy z9rClV=coNH*d*=LCD1z33|=&od0MBb4VXS;L-N?s#g9wX@n*bJ1Kj;zi!2Msm+96h z%U&gSV?K(Y4!0si?bQtVNy;&PlDzLWwTL%*fVD+^3eC2qbV%EGJ6Ob9l6)}1@?{d3 z!;|J@@c_T$sqKSMR2uQ(5%E4z0jn5DAe!~_F0^~-O1ZPVwNCL@?*iQ-qct1&SJR({ zIbPvT;7O@AtUu4jTBT+v=1J%iRUuoQr1qk7j&dA|0XRSCgG|^wW$?S1DyikkFu*H5!1_tO3@_74PwZ8Z z=Mn{7yjp&t#Xy;MoYYfv{6D{iflI@6sQ9Yq$Q8a6=>xo4xRl97)Y zH0p)|jf_Gl%8N36?LaoMi&xn%v;>ih%geOxx1DEYCqbb`A75=%Eh72466Q zp~bwIRw$LI`!(pX(bXQ{!*6XSuQMD(4W6+*WXQ8U7JWGu6pD%PsQo{U`fLV=PT_Zl#Ya=g0)TDa05x?nvCR!6o!_CTkLzLLDuT#)6W%&AJS>{G#33yLOg#jG!69i{Mn-%aCrRlW;!dWb~lf8pWy?fi0AEe zm83WaB0POQJgDzjdbg^5$dr!~mqp?%j;AEBKe`VTrYn?Q*nT2m!dR1uFjq1W8C5qD zpvrsrP*%POQIP637DC@pkYEq~wHQf1AH;n?E8~MlORotp+t1}@->%Szq@;Z^Y5uXK zS$aidaA$r=RF!ziB%eo!^0MIg52O(n7YhRmg=X_kZwRFjGI3$}=iKQHt`uS%RGRK0 z$AL#NpAMDM?q&M;P~T;m4wDfR-yqn}Q89jr_5yIY!k}FnBhdq@Y%+L2d0_icZBK7c{`5C{4`8HB}^o zL-GNgrhGcQ;53G&+v3lCI=^fX^5i1?ZA^^+)=Pj|h=?Rj3N{8v%Ji~a-U%-U151rY z7G59+HinfWk|iu$S^j;Q)W*i9Ft69wIu9=_aXE1`)~vB`^555F5^4c=`v?O3U=5+=h(FLx1Qeg(sQGRH#NFk@<6UJ;RWijF1#t3i$g6@NyCo8EpGfpIi=p z);jMIL3=>?oqwF$#mkg!sh2SaOq86rNT_ZAN~O+>ilV;DI2~rrn3`b-b8~0rVe)TA z_~S|Kz|$MED-tTH`MctWhlFnrUq)rp{=J$uXq)KyAJpaUf`4vm!b^Bh+|8ev=Yu~* z{#{I5_`V!s6;5mRLf-ZNLd{vyD~eVE=~v8K38q-AgYnecn=gthQh!JI$FeBJq@Kon z7P8}A!>m~(;5)+BwUAHqq-;v{rWE$@v=kSQIpLDfto80ZPwIc>;bz$?GO99!;#PE0 z_&h*@FCzncAtMRr#~;j^`{}UqXAOjd6V{<>vPYuHpEMjK3YS=wIb@NFY5g>Ne06KS zN2Z@lh!}3lbd=DVX~{=VH)wv8_}I;w7W6}N#ZO5-Wg7C}<0QgBRV@pukCZ=V6bW;T z7(6ncrpbF1&P}V+{*?Ljui>Th%|bFpV0%rsmHFe+V*jMXfvL ziIzENh2Xm=dL(+DNZhRgsD|uLHGz)lwA3<$q_k2{_+z5I1Zp95ijF{9Gimv-yAl^3 z6p@uyW#VBX#3O_yvtWNx-QGNMHsLpdIC_p>3ClGNH~<{u`#YL|Wax zqbI3Zp!1|ciu!{H==pf?{l^O67bd{Jnv`J%a|?$H24Mo~zk#Pzr3l3!F2(c`p%^E) zVsb!tc>=NIW}iaceC+QH?bx*Qigyzp0H%BBkeB}nFO;%f(UC(n@TLVkCV3pt)%R53 z<0k>m6ICg`tf7$qvD8##jyhOuj3FrXI)-OxX5h`u4~f?(I$%~z68qA2d~;C)U;4nJ z$OrI}DoC&O-aXoQk*o)8>LeDJjc$yMPTFZO?QRMNH!LjA7eyj;_)$q zEUArb(=IH~Px&=aA5C11p#7jecN()Vc#(j&iG;2cigcGV_?&MwiOO8TEs~j=$$#f> zco=ZHtv**I>c%<9q(@B}v5zbS>LkCH=r}wKfw0Kyf1m$lKcm;II3B-(Vc1AJgU%pRfK)Ea4%PhSShd6IJw&coD2FsGo4O~sN_*Dy*R zMYURM-X1bJOuTCTNOw<(KlW)`Nr$)?kIX-o+G{2C)X+&)OItMbJKsUw4R*R*%TK3J zM+&IA@%6eF0JL>)aS4V$4Orvie?rvh<=;j{TG1X_1o}kYyNh1og-2&glKC(FvEMx# z(@4O3DsOE`|2NBg+NdEM9t)A4SW-eM-%&(xD?S--xCIo%EB5b|ETmsW5iNJC;^8A6 z*$hwz*?Gg0K>shv_e-27=6zVyG^7aE@Z7BfPMeuM@Cv^w8h&MUc5n;mXviR(vt2>Q zICr38#1_3OE&a1X|0c={1-<3>24oA{&4Ximd;aLh{wmDrx8ePD-u!mxB1V%(M54ru zg?_lT4lQS!>(NK8w-m(C_tJ^V?MJ%jo3RDguhqvKZa!yx51n2R5Vhp?oLP{Fgs*Cg zdCw4t6prwW{NQQ7jyIVP40Xhr)X0s?$&BlmsEhV5UAaG4R1+;y6Mc4}6<~rO-vpEEQua-_wQq9h|fx^p<(wveHQ0d3Fms9{InX&P{{i1nyYG_x9WSC ze21TSsO@Q}tvcQGoU};j&S~h56CHj=WE0+pJrG^L%NrRXt5-O5H|codg0w{B;V|S+ zcBb?LVH+RbYp{KJPeA7Ym3c2O!t$8@&E#Ua z&HC6GYKF~=>V1k_9t!V*fqk6lXR$ZyO*nfur}^UES4XSYI0@yPzyybjqn8=pZnwKs z9BDfn+c*hSD`iF^c~ba|S)819^S5Bq;MQh+&WxL(rie5oX8n23vqgipP|oo+@7uF{ zDscm^qqzvGw#~;O0Y-+cjq_y*x3}9o8qK96`~Cge9}~Na>wX_nNlz8gd6k80QRXsV zpLDC3>9JrRIq^gIUGggD&shg2wJ-H3S6DJ$QH`d$8Z^@Q8iQB`uwtS4xQrmMx< zGXewiq`&>%{j9U{^gj8{L^W8QDN24({TAiaJUwi8YBFQ+EhEa2Ep#aFW+!dMjC*M9 z#P;{leD8Cuqn(j-10bbZ*q}($XR8TdKbD!`(3{<<-O{xCElIb&N!M9Pm(gkGY!RQ5 zjbRLusb6-@6Wd>Ebm7==+HceFXCge|joq8e{#Egi1Ws87Sr4Zf&bFIl3xXG4Qd$Jx z%C*c~E}xjciC8<)w~OfB4QUWfnVE2ZFZO0(V7Iuzv%IeS`ox&xxNB5Z^!Q`(*Lt$h zVo7~X&EZYyEbb?EYnfa7uFdUd#Z|X}13_|cr(;2?8_Q)oft$50JF%<5t_9nx!SMx;vnCSn>Vvn1nS*lH#M=ev zyCWi^QcWb<#LHXJl>!NFV{4|O0yz91BeY4piI?}(t_>b}YcKDaUKtd(^)K#0uMEQ4 zY>wZG!heeo-j-$>MEof08Xk9R)B9?idtJ5-PDyz^eD*_&Qu&%F<=`#v z&71Ls-Tk-KW>p7oZTt=w_bjjGLfiC?-wMNjffU7=bKyUJcMT8vyOyWFk+Xigy!A$Z zZji0!8(YoH*C~;)uC-;Nu7$a?CT;K2Z}4Ao@6)Y4ue0rPfwl_tu38I{NK^gS;SRMg zfOS%BV2)RTq55f=YL!2>e;V!b*=E>`?jO*m7@f0PykbA7 zm%_G>x3KxuQ~e2rX*5ftcwINq7W`RuQ){S>YcVS{M6E2{NpfVBdAkadfMZ#8_{5Uc zj(|%KHTeT2`BS?$a@%tC8_<1PyZdw*Sf(q)4@u7ljX{f0iEQJy3chnp=!1u437#{c z5TayA`6{d>k*F8i)e_Gp;A9x`xJi^<&lWd+qP_EtkzzulC%fU+Nv%iW6pn7|*bXYY z5%ffA&gyPap_TFArDZEa;Is`XIBNsYII>>G|9vJZLz z3s1e5{dEGD;Ql(-OCr1-AX}Td{8c^Rj0@9sQ#BrX)fxXRP@mR%=-Iu~Z7rQr(QR#+ z89m&cOOLm+E9KN2tD2cO+#U4#dAQpGnecMhz4WcM(w`xB+$Eo|*sbj0XJrQddi#{;~7Ei9L;`#oF4(g7~YZ5a<$W^2~?%SWX zdEU;|VeEMw{my^T?0t39WOu6-r2XXfdfR8-Y+D0&u0O#KIf@{V4TmDn2z^uReuziw z6+B8T9OZhuFD&K%j=J(>Zkb#EebnA7cItEZpx|;%PE06I;*Hnkq2u{@IUlds{yc-r zmpakH!!xZnL;Z@MkR8&11TqV92*yy4sW^t=Q9G8{f9VIfZUqPm_N4-jFJ!H$TU%iIN z)#2=mq7UqKyDP9ZVq@lcee-?uv2sZbRQK(b19Rq#Nl887@Gh5@KE{SC2`k4tdtnM; z{1>jI?XOfE1m8sLvcBostz24yz3B#)zVM|fsBZa{19#?(LrFc!*IhT;QJE?CU^7wK z2w<;ICu<{RHw?4M;eAPc1!*0y%G#LL1;fNdEJ@-s$ITK5TgB7DjEJ%xrnf@pm( zGQJyjWGUYdKPYFla>-t%zdMNWq3#o#-cYOl$;JWu&o9^R|8YwSwcOa}*^JrPXN+x z53qiDy;os7?GfjP^>qVtA(wm>z08+7CN(G<>$1NSSPFx@Agr?SM)!J$3ZuoJsCq%- zWEpQtUcUwPwZg=SnmKpddO9+~r}tjv75iR~m)D?=ww#UIU)I20UKM@u+}xIZY;>78I{PKFb<#9P%Ghz9>f2*h1p~V!?Qa{|v7QOf zG$UI>$ANS0yzbZNYYh=6is!7BiV7CLtkiaoWo8UGC^iCbxf8dM(Ng7>y;W)f0R6sJ z#Z)pvs+^ssuS@;rdj3rqGlmth^G5tGMNA$^n-Puyxl+Hz8zTSUDdn+X7>!^?f#S4K zrBw^pG>N=8dqd@`6=w2IHFJ|qHNUjvDAO8fy6@~$A^#x~F8lPpcVPwZxW;c+?RLI6 zpMQvLDoegafxNHmyPHd;Wh{drQDLLomu(hJVw>M?-yZ!cul0CM^@2)OoVC$w^qHGW zwa?a8kl?3_(u>UbfL4{0fM2F8wo2*&TYA>5Cf4XeM&x-L>^VAk11Kl54=7mwOmG47 z?i&Z7cs{h%_T2!!r!EcMEDYT++`D&stEz~K_R>ZQ%`%9IZGlA@)w(d|VQ)+#FmST>orx{@r{7adNgW1FR;_oc8=Y+(wW$ zt`?5Y99DKUF@xbV0)zn*YwD@Flqwd{p969#i6NG%SU(t%EgK*4jl{`lFj7VxTI&zA zZi|^_=LG2}4PF@?0J7W|A|Ttr82ZD_jbYs`l=7ppNt6zwgR zA{ohW{Ac-u{6_2<7Mo^H1*v|&i7bZEc1d}YW>PD;EL{w+DfY{3qD@d8EG~<_DYM(7 z>k5Byp{|DO7*}uHGXAuPlI=NW`xDb~Lz-bysH0LTdrzAJwNuUH-q&)J(I8`-CzZ{^ z%xnJI;9p4W1m98ywaHFyR5t>9WAaA30ls`wgi zd`b~dgaWbGCl*`EE+JA^>s-|`+b3CL6j~ppb(8X#SaY?%G5_kwR_c)UyAiykf7S>f zcnW{`xql+XpV6PGt~Zyzx2*G{@Sh(+pQnA+W}WIZ4@rCN6eR_Tj3+sesG)r#-0-7` z(h#S>TgaJRZfwR?IEX~?whfp}Th>UiygYYeqH3ZpM$*kaSWKr!Fq?PY-AZ-FZFJj4 z%)#Bgrf;`%i+e%yhv-kbgRx!g?Dwo3Zz9fpQ0L6M&eTH(x@$6=)@LI7V((WeT zyx|(B*PGj@WPLMz$h*1P_DqXu_WH9>xW<6a0 z#W*oDu{Cit0GRxYj}5PN$Mw;)8iDgw;n{AjVQD4&|wg4-7KczTS zikzw6ks$?0URg{pggZ90$HY_GZa5}_r3kgK1gCJ;+m-YR~fld26{jpN+z4pKj8Pur*#19(W z2lxF2xFFFDUT^;Et)Bt@1RHCtoB;wG#S1ZO$@l&q0K>~*Ab+R*?Ncs< z$-!^!{T4F}`KI>bAdqJNL{EGB_M^cPFk?KtjTHT@HSTX5L3;Q5T$5*_{aFd}?jhU6 z9+s^oP5Pd{KVgXj;xQ+nne&>YS-*}tXXbNJ&lso%uHcFyUtwVRZ0w9%BWwCKPIQ5X zAPT-CdWj({I+yFP8{nXgFlQCK1DQJ*!E}*bp}Wd6a#opXwmP!iWJKWG0`vaTvAMb( z*{OPAC%OgypN8pzY9jr}f&a?lS^gh#badb9&}XXIJZ%nd9YhBehQ!0^#oqb*0$RGEynEL#HprX%C9D2eD20^7RdwH%k zvf!0Wzx{{Up~S`pub@&eKH~a-Kfdu{cepARIQp;_f&p~#i6f4duD*}oR~_)m^jCK7 zs9E|TwHRM)rrR5atoFIY^Fm23ywt9FZ?zjZYIP`Tbp*6kYfe#zfs!?;w!TSiOuOy2 zEB?PMWOKNRvU-65n`!(Q*0+6TszUo#Y?;_fT3OSiImBCPiK3ecUYsVU3*~};qxZV? z>IqXOvk#OY(0v>WB0VRJ#^%ciYD>`OF0x%?L@#q~X&0!^qz_DK#NbaOf+^d*$E zHgOZ5nDv}leL&O2vAqnD21J7F06#ip9ei}+NfN%`3)*KT@G?YXD{d_^V$-^V?gL_% zDp@n4exUrCMJ4eS3?~M?N3Ly}rL%7hoar~Ok_PvO8Pp_D~Fs{oo7M7Lp_Ov4no+~dMYr8Q}`vCkhos%r0`pem!f1< zi;knP+VIeeHpmVl=lHy(KXi`WztrCHF=RHICUn44kzawq z5PdH|uJ>Ch&t`yzRMu-r~^i$~K1FweODv*ofD$_XV*YpUt4ugOnO(R)VUzC#_kPv4fV#|x!`{zmin8Jin&M1-E6k*n@z+I6_X`qVEe?$r2 zNyD6`bV(4UW|L&^cm1D=0`k6!HTvO$yD&<6bPg$3U?jDYO)M^#@@EB9O zf(U$+29jN*Xy+mOMy=}^Ebq29)}X#mSsj(D_17DMP6gTcT3EzaE05&pCj?k9c%%Do z3F1@;3J!gS(!M8aVfK4|IReSGesXP&FA>irI~+Hj$)?(a^p2tM+WNm{2Ud9ibtMUp zv44Yq3A}{iMA}2R9nPlSE4Zhs(o=9e1UV_8)BDUQ4#to4;jXAq+W96sCG*}?{M3uS$YjidP<5Q!i*E3(Gli|Jp;b!|soPT2hdm`!*hYPRcCTJp*mJuB*%^o))Pi%?n*93+ z328RCb2UK|r>Gz$t{j^`_#7}DV3%XGMpDn<-OP+|nJTSqpqyl&QX0xQEVaKh320vz z$B{P1!HL?L@uh`hz3Lh?q?=FCR6+B7cV!Pb-2MW6qu1>RmYy|Df}asl9yILx9QDc0 zFep3y6qFgxo~4zat1_FNKQ|t$Dj%%DzTN1?zun<|*hesWRm08fUvXfQ>jZQULaYqa?>i|Y z#QJzIzC1re3(C_1y=1&L`dJWvWL!m8*7Jr70bA<~xJ}s#Tf7F$(E!gmoY`M-8SHyC znQ3%8?!?rxU}tAZU=o&)bPpE)x)o`Wpz6<~7IT1zev zYcn{~ndbylszz?aw1F4lExC`cns^rWzzIznLKYX#g}s%9Ai44qSzBT%Snft3$&9!b zop~NM--HCU(ZaokRlC}xkz|?CN#Mn$ZyAafWknYN#kxCP2c0OB0>uvFz`^G5$wEwL%-Bn|x zcXjwLWvz*=!#U!lggfLgt1 z(2T2`k7a#z;fH&n4ZHcerq$yW_W66OyG^_7p_cjQwaj54aA!#ta#O{aS>0Hfhz$Ya z#gmGZcb{M@nf4R?Bd=cdDhaHg!_1~SuV^{v&ivg>#|p^}bSKaFRDNZ-|lD zT!jRMhT!g>VoLL{=sv)E*+p@BS7ViSo(B8rZt$c9c<%-tVE7DUy$C|Gc>yrD+;>Y~ z47ftRunWr6xg8FcA$*Wp@poXfOhT~w-o1j?+^&7uQfbCwfxrbdy0p)Mi)g3T^w=JD z;9EB<1KFUy?=3A?qeII+twToK50%CTw4Olpn11PAr+rqfxEgq;Ho-KI&Gfa*uh0fH zh%Sw2PjUJLaMUv0qN`Rxcy_ws=Gk50SL*j(Kx)}baiLoJVwzjX$z*!bh{-3&o{krO z+!uYx-;(W)ur&hs#5zs1*qnr2S+&Ay@Vh{TVgLu=N5S?_P8}O~xiSFBMPBn9u(qeF zS)0rZiH)97fmFIza62&$9;FT*XD#mafyS6;m=B9+yQEq+sAD6H>Ri%jgEBxujjmw5 zW`Rb>yrPE_$9*~DCHBW%h($s{OZ1sH?5 z<1;3(=t=Ib1G*|lI-z*ozg*PEwJr{4+VS(;&m9gfK|NK{N~@1|dAY54lwgTx1|(-X z3__E#(Wu)Fbn9viLN#aRsqXJ>-C1Trhiev}2i4#aZJxGjl~Z_CPwP^0?uNjaFCZ zRxZBZ#+ zSE^OnENCb7mf9`>x~kq25#f9H>FO8j3#<#BrmKEefMQLy$Z6vbd$SRx*IkbRrnSKG zYKwyT;1wRTKr?3ST}`Fe)`t8gZ*{aA&XeW6T5wM4rbe}cQPYFPiE-Ll50$cire-P1 z|4h3i*2Gjdk0bTgNSYeO2kNK(Rgr;XLq5W6?tEyDD%*#BnF~uho z?lYatgg~NZ1Wv-LYfg4n(+a?2E5Esw&s=s^ZE1(ly>-$@_v=&ao!DDg_*q1ee-AhZ zB&(O57hH}210^={Y=1z8CyqB@uKw|ad}kS5;|2>`X_O_Qj2AyVSR6W$oawsYO-Z6|Y= z>+h&-NDKUio1N_pPQli0mE!J{eAjLS=^k)O+*T>N&>vSXjkFbnR0o`alZRtp-mk#V1K$Vw}5F5sAv)ozJY&zi<>c*1(cGSt+- zOYmPjJ!~iNT=U=F>46xbCni{icRxS-UFm}#dBR-i!+B$?GPj(7*Se4c1_8<*!8G=P zs3brhDHAw4!-&r>uKwD&o zvi@$=F*3ri73+y%s{M`ks-4qCq(x|3F|Sjid|+Q9%jJWV(DV$n?nvmps2q`#B0Lq| zDN&3;8XZE9Aia=^?r%8#_*ahY_g6|!Kf}i-ov-r}u)J;ubPA@>EKMT@&%B0QQP=hY z(LISX50uY64mom;G)R!6eZ{pq~krDG!(dd_v(xb_DlA!8ou`_%F_#n7-OFAm-O*&vy&( zpDIa)%hPeq<$9Nx7eY{%(qM(ZjW>_7kSml9Yx2hRXnyI&l&5cuZ@~2wk?d9-SRVxU zLrHv=Djmjfs(hK>*b09bQ5gdEqY#z9r0S_Y2zb-jDYriw`&9NnY;l;Pn)e51RzsHe z2j@~MWFvi>H?Z;_LQbA8ye`F@?}l{JlKCjYrxz>=cUZLB?j3<^D`^&7uCL2$v@+PdT%aDe>k+EJc|lKK4> zGzKxeCz*UfKz?t$*uZWKpoQuZOKXGhz8U8utE+=qRgrGU2=Bej7O5Im>gh4-`Zxuw zSy{M8fA7&QIn2~<-{Sbf@k<*>v`i%*C8xPxFZMaFlKc<|lgP@6bhUB*DB4p-yZa2u z;4#xTN`CiGRMiUnRc<9caD8H7VJsqgwbHzeTHD^#@a0xpn-uvo+%EJcyuepXh5k~Z zM`+QU3O!yv6*=hK#{N;3^Bs?HX{X5^-}3E7)|S0p%r9Xv+H)_ecW&MmxgxNK<06NP%f?5*vveHrp!A&B%9fj)mD*8GgMpnwMQNmhm<;`zI1 zy9RHNXQ%kQebZXaDwBoCUkpyl?gbXY!Slan2#qOvMvlnQA{gVOMNt1jXh$dN%_Le@ zbnGUsA-;-{c|R9G-iHz0IiA2oq~_Gse8H+x(G2`}rH`Ss$4vDrBHng%e^JO8BdAhk zt_qMo-~g-Ro;g%R_wmRLQ9oi_sWpoWpOs`5DpBc1@jt5!^U8S1$zd%Ehbzcvn5m@RD={%hjEHbLVctCKVsay)T1}{b2cFJzY$}O|AH9*kHGT7i{-z*J63e)J`x?uu7G{VDyhtK>lD^`OMaXpm(rSDJG@>JA*i)s@c2A2ktA`gVIotL zAk-%qaE@$_t7VEbZxV;1LV!#kqL6?brZEMSwm!=4#Qx^z!YMwe*_xf#0mtA9Ju-BK z!mk;Y1?eHckkYhv6v^KFbRlN?q?-qK*Um#^#(;sV_kG_Z=R$;4mG23HH*pBZ>f$4Jx7Nt1 z8JZqOQE9Lt*M3@aD!FnAG=~)Iu%e3)$y$C7rT|Zc4nZO^Gi=cMvDoH*-k2g$(i&%; z?XLz>%OO{e?eOS50W6}z!DztkeSF~Fh;Wp=NYcCXd($1IHf&$7$xgoua1CpTyy6r4 zhUhIKvS8#qataa|`{wqpM}*ztVhZka=q2=#BYfI|7MzJ_-~Aen3SX(AkNjg! zJR44S1@nNbc30Da1B2!71KXYQm1_i@O!98s*Wk!Ihr&H~L{R}P=&$bQ0&AZib>V+> zIeu&G@)ckpp#2}s;s3A8vHcfsk3AzJ^MAAktxel?@#JpwoIPn;knv*jxcCK&=W>5i zJZ9KQ(mqb68-zu;aB7XDSrulDMv)RHKD%01r;g_iyV-ZLd(sG}@*kH~#98(bJQ+r~ z#PVy|y_#Mfe5jBcNdoa9n-tjB==1J=d|wQ*?x7{c!ep?T1MCBPV4?|imsy+@TN$m;ZPhxO3=~`y_bTjweEpZGVH-zgg-=G%0Om6@U6;%IB z9~@{O(~#iAUdvx;v{lt>ja2l%@j|qyQX+^57~Er>W9Fry@EF|kGufEQhfZirxIe(K z80#wujo8cdQDSQF`H!8E%S6x{2@0F#-{fAbp*KldLd4z&NE;6Dd!VXRL3D73*#3Y9 zcE{NDf%s4Y+UC4s1Hn8GU>(7L63X&jN7 z-PXL>%dx!cJT$?%Yixb$Ji3-BBpX+p2VWn<@n$xj1O74ZIj}vdF-b}LU*J+22da4z5r-KAyx-N2dXf>F--OV168l+~M&qrwfwg24d_{l_0?);}_WU?H zc};BLhi(Q-DRJ{vrVy{31-DWUO0VAYN|)^P-5=BU;7{Ec0xTaXQ({xr4$H51lxg-p zk3$IThgvuL->8v}v*L$jI$P&IV2aViXm}K9_wIZX-C$GXzQg2UT-Gok_Lu9g?LGEC;rV)`l5}#*TEayz-=cX|XIcsA^97_x>Yd?o^ZSRU8hnIioX{KO z(^h^Yo{aglcI(%8;xmFd&Hy z_BvE+{?q|JI(}@NFzJCC_g=PYYUWTCD=At`O#jZ=0k4eD?b17}zl`y7{BqcJ;2nu=<0*0U&{Y1)-roSPM>c3{zlF zWJX#-(ysu8+SGw?SkNv1Hu=%AXfAn*5x zDD)uTobx?fALYwI5%b3RhmC^D3pZj$Ci!L_W2uN^;=Nu;o;=mwS=C=OaZ!tmVHJR< zP+}AOcLXDrmg)IY2Y=9|bMj3+geP2=smC;(WnQWPAI=pJ&Jw@yD@fF;sG`o8ZdhMSgSjA|=W$uKs zXkcskC;1GJSb{1yXj(-o47vgG26)b6HfNX-7C8H_3O-)CZGj*G+=fK;B47&vNt!@X zgM8|DDRk26rGfC@PGBqexC7|qA|6YaYeh1hpV~*|(KAgPr$nOXbHt*f_gFZwB6sxK@2}E^+Fsq^%s+>(Z^}1=F{RyV{(Hc~uNwR@BK*=_KOX4y zaxxHQ?Kv?6j{iH6E{Ii^mm6sf!-Zh7d~rkI!xzlG<)-@t@h9c7*ERSlS>ih47LI+s zG@(QK`{J7sp;G7H3bc_~moi&3=oI^SCnCH7~McW*)u2c1!x))oEMsth={Z$7S z2BKaKLMz3W$u>T8cHoLZ+dp*~U6Huq6<7LTVXhXq%Il4{OE>Tq0pOocvx9t>kY!K4 z5M+iMq(P3Gli3#Lpfm$yewb1|wXsLWh(9le9|i1it@t4g_c{mj0AJV-IMv!f7fbDQ zm_!*8a>~Dfy(m(YaN)$QCp{EwABf~r1h#O>FhcHi^B-X9M&U#{T=`AIY#jJV=i{#g^ILC@a}e@1Eru- zO@aXDFlKkY!NamXbc4-_Zp`8%IOc#f3!rQSu~>*8_gzs~!GPco%dQ6+(-to-%Bgm^Tkw!#SBZ zCB-%^FZky~+)3~Xt{fxh&r8n@Icapnvg8iT+o$L0q)tKOzg`A6D7GInfU4H*A=Q|D zqOl4}WNT1{;kjLqYy;qf_2TS5#|<~;F4c;zMr2xQ;1gsIL^;8-Tw?);O@Y-+?j#3v zjq6%Z-t+EB+ec*Pi6z1Bc!8p7?uRL_M+C{$?c-{vnv1sA!af=u-dSD%!q?Jt&pDR8 zDdQL&~&7LFn76+?qjvEjS%igK@#Hk`vh zCX1)fapYY%ZFYrfN!8SeS$B{1w25j>`|vUC`}L|xJ3Fyncq>%e8fIMnff4P~#O!Xk zYRT8ku1eNqrdLJ#?ZuG}xI`HWD&_9B9O zgC4Y$v}pXmiNv5m&~6~hS(eJkh#X?kaDlIvQV`J z@|<+nq^OdZsFEWU<41r^e$7eYj*%ZZfMQ>~2VC!lS!pM$*9M;|dyu+d`tHq7lolQ9 zC%P1OlvLZZ0Rb?dy~`9lSuMr{QQejBFLYVQj&Y&51ON2T2kT$=QI*Q=+50f4Ar*xz z@U-k3O^E}I_3}&V4>>u0*u{FqZf-n6Gyq#CM-9q}0LC;b_vnL@X*)t`7Y`ydYDtLO zPIwV;lQYQ!xXa8uNUFTWoZ)4F-#WJveTh^4c^v50SS2hJ&1Y%41Ri=-7-Fnbo^G;P z97uOgz;gh+X*~bUtWPoDZ}#B3ePC~F_qAH2ELoA8-X&z?YH&w})Cq0jw5v!K8eFY+ z&MJIcAoe4~Qv=V>YrlaW|K~lfosp43@qbLkJ*xKGn4aDTEf>yttLt1DT!es%l(a$@ zJ_0u;2sU;y%!*;BH^yB#_l*-iRy``*zO02Zls3aTN#2r!h7zsii@%N=$IR4!hvg?! zXH!2hwN86&9&b?y8hw8DFlkH!qyDL7XBB=&d4|$i0dI};N&+wca52u*)0V@%EIP*g zc~(?wTnUHxh(c>rYbt-YD|BLIWkXG%e0;k>^NJKhHKbWJ_Z@khDBYK}aXy)PaIgmA zwKADy3=n1hm98V~AB;9WZJ>v*j|@dbS`i@37eEw2qy?qLb<;{jf|sgl3x(lWy52+uR@2EYXzU=qs%U|DLFZGI0|uW}(MQ_Jvp|e4DNML@ z7|wBH0FwoQJSlndVCdFdml$;Pm$~2;fz}{u1fgUT^$})~f1nBVp0xLq8%qWl3Kt72 zD41XCFz#Ar9X;Fl4|!v%PL+=*whYZazO`~7ZwbkMQH_9gJ$8+*cEKn>@S48&!3xzW zdQ$akq{l@IWW54}BnIl;SYn@CF{}@z`<4Ei1&ornON%oz%~Dct%}bz~Nr%1{UURTZ<61{(T~zrH_43bi>DIGA$S#qHEJ&kf0>i1@u)H5M%59)0UuZZBt+ z(a@28J;yJA$XK71&7^tgOD{T&!D}~;<(Uy1E)oYj6zFV(0=s$0e82u>@!pTBLtcQ4$%fWIC*93rg*=9W_Z4T_*)-&Y+q zAOA!Qeb93ZnWAxKzxF=SqXmi<4-iv6&?70^m-IC%J7Q7z1 zp`H(~u9}bY)P##?^mt>#()P;*j*U760L;%D9%Sb=^r_( z(uN@ubxztFucukC8)>1}b-4&3T$Q_aDcVkNzazP%8pg}RJESLSt0H`f0GIwxpx^oiu6$Cln=OSY=fo>+*N%m-h%7ahy{Syna!qY-w0JDc*-Rr zrp{?z9qV3;ZiudIeBJ4{-P+k6BP4&PT?}gwjL}k@PC0qR(7jDpq+F1ZFlx)5Wa+eC zFV5jP9L%;gpbkt^q$Lp1WF{}rWSLB7P4>=Z8BcSSINFoK4_|GbH52K~XK*|izKE}1 z^8~1cd^?BILVRr_B*$(x17<#Xz-?^IrG+l8ynMZ<1K5kSugR6DyUg!fETGOw=%M~? zy#{J7MIB~|je;Z!;&@V zHi6n;67m>+B6Fc<$lRxrfqn1Ff=Nbou3qY{v@a%Ynd4!XNvYc>$ ztvcY1IITt(g}QNlpQ09!)D#sBfJSi_E7hVNKV0fFV7l6KlD_0StTfU-Mfw z=g5Zd-L$0Pl6DBoMb}O!o=$b$V$M2qqc}!~%`&I7NpmwFLe(>C>cmnwuQ|S2;%Qmn z!J1(pMA!?dp77)%pVT}gcCIl|48mgrb~{r?XLD43gV%rKW5tu)xJ7qe9$@uBYiz_T z_0_c;UY*f){pdj#@Ok~>mArvqUa{Ha%~9;jvn8<8CDi~al#+W%RWe!C!?E%C{Qhg( z2pXy0wRPL9wS}k92&XYcmrkvo@QwAY)wX_|Z7c5ceP{06wU z_1nX?u7LGtWK~Z6>F}kH>xbC&+`Hb-B>q2>ei>%%U<4QtkUQ-EHtGL&;GKo_|C;=_ zo%UJdzZ)LZ0L5qL;;b@%3oFxZqf02$vc}m|GK?t`x*lU36;YuiR`dANfNaJR+(##t zcy%xN9Io3sy2j5xC|;$i+kxYAebf_MT1CaeKrwQE7BtU?6)So@-f%|Q^evlL zk7TE(?m+qKdFn?fw zrG$%IvgS-JNDGu~dLWxjv`KnulPCYBKaG0T_6YQmQ@f0EFU{tbmpLLys)eu|w5Ihe zC^ED_Z?IMyGS4z zaZmn=6A9nWFJGWOB370bJpOptd#FF}-Aw%P9od5)cS%{&pfXVJ!qR%A(0Wk}Yuh&s zCUbo%T{mt!*P$;7yLXH(oCi&*GZZV3V?}aE8R`!?0jqgKY~gyY1W$P-L9Mjsx=}r#D^w?vy$kzT<-TT0)4jn$vPse@}9b)oHLU?OzVw< zc7b?uB5|W7V-~K8M+~(KDn;AGKPE13`ghuIur&MbVg+AfW-rg{@twDs-XZmj)5p2# zBIN|+G_a{v+^rvAk|)U&D=m>4DET*-9JOpmA+@)#(jS>-n4WDCaD)!JsTpzJ*#`4W zqm)C3mXK9pl}UU39|JCmqo>Lc^V?@A*<^4?ZfjgT3yoAL!FoVQnCiKSLH)G(J zv+HO1RN<11jE2S=b$g#?o7&BE#ywk@9)=BBCVP{KU2tS{_Qc^Wx_EQH8(N)w^_B~6 zWXV&SYWBck`f?gP2)E=ei_2Ybd|@%Pz`v4ba2B4PD0-ok6s9tngIJbq!atc)TP`a+ zBPLv7!c^%0OPD49Nv`oi?jiT8B}3YP!pweQmXwpN=?_j-zLWhvEv5V3OwsP(N2lH{ znPjjsea+Fvb!uuUMW(=xR&Wo70_Ok}nTGcAjr|@$^_-@04J%4j0%ln(aHVX1JsgCi z!M9|CrL9%T)X(ENaj)x(3#=BO))*Yoe&27Y(epp|x zzcuf&dH$CHgomYlwrm`4(+Z=Cf6D<)W~%v_s1G=@`fcT< zz<13ysaW7h@i|ThB6O{|*~ZDwA$@9jeanzVH5By1Uf`pk=Vv$3&<+Hks-bVc+d=It zU|DawYSyCREjH!lAaU-rYZ=dj%$CQvR6Q5!SkkQ@kJyk)Wsgjuw1U*5OyhFl4=L@*%rd*fOzeK<5 z{CHu??AzP-?Pd4{!ybTCUWK@q!K@Ju7#=8WsB?utFCLMreOu3vc1|WgkJ=>G{!ZU? z&bAlekGTmtbcnxq}NUN*H4J;HnS)n1$IEXCs)SaFnSCM zRy-9Y&4J`SQXof-Y;}a}9*VV0RDFQ?#piI=aj8lra(ru(US366OVws~uTb(49Bpg1Ud@7(}G2N$^OFZ<$SDkHF z<=xSA!7;r7g+Fj&*A9$V*<~X(^t<(s*j`&ZR)h+uVp0C=-Yh@a*e=Ga+@50h6erPEz(s%^O2= zPE4uDCuRlztS(Y(n$4Nd)FHG=0awGE7F=hN4=rASk~*+W z5S;5yb8m2sl1V%%%Su|b)f^$~a8;?M?1FS1EEHIf1jxarq+=UaJXVdxjd~iy4stE4 z!_e=-Hpy0f2H60OmuMssgZM&)Fco`~-aBHln0`_NES99;K`;guxML@>@ZSdG{cY>E zd2CWnU}_l#=yfW<-mbzQ_=RodlTIe$?a zcT?1Al6HnWNx`UTT@xmIsDDL^+Y3HNb5Yqreb%g1;1#)~=8g++R?uJ^AAzS1SNZ3> z8HJYoT`JxJ#{QY3NmDTEa}yWDjR)-YS5?-bVUu@+;**xSB)pN*DLT2Y zo!7Y!2RpiBn%Jhxc=&8{ow|P-^qlvO_cCRHbxaNkt#hWnU**Ge;hP6IA;9l$ z*tI0KWcZYwrle;>(#C#)oPKUTJg0x@E}-=Np4TJxzOffqzPm>Igb4X2X}wvaVObTq z#@J_j5VpS};dzv^F7E|qIq8q?srNl1$N^Uhjgd zs8@sMl*KOD%wIA~z8bZ@#udJGX5YegZ-4IZpU(B%o$sw=?b5#6RDET}5zcFsw@1}u z?f}m|O6PN1dapwl_s^MKYwsxyt{P=MSf3(AUn*~3-4CCR9}~mNcB*{JJv{H7#Sa)s zZ`QBR8FzLEat#=-*J^imqT4kGHK$`8X%= z`FCo-m|0*BvGg z+SZ&kwS2NZg3|}@vrjH--Ef&P{47AUCfm=fwtd}nRxUlBTT4^A9a*98)&9k6`CauV zEN372@M$hYUu%ZuB-Ly2E3ouy_-YAsl)Z~#AD#VDo^-9}=a-HIjXHX?u=il@Bnb_* zoax#Iby2gbCUq716LzZ|8dRV2JLk=hxtEK6?O=dwoT|j;A*)>dgllbc)zSB&1MC?# zl^nY##-*SQ-6HBP7D0=oEmZ-{g*u!_G;Z($8$a_;WJ4Ad9f9uX*mQb3&_bVo9kQCL zFny|yoA1F-^}##X6J2@r+%jz(h%l&p8WEOc>~<9qy?NvEhH9npH31=$?Wzq7LT!T@Zu! zl)y-uFHHzcYSgeQo~9Ob!ZX*ZPyGgE@MGm8m1AtOz6^ z1W1)uvm}X75lu;|>*=-7d7vf#tvqp+qNZ)c$E*;aO!CySrA&Xa$gnR@)P?T8MbfE% zV9r+0u&MWc3e3tj;Q&9+#7m?*uw?a((Y|zN57K#U)_lL&*$U7E;9x8c zixe1lW=Yd6bM6&PmRwJctiO6~4(4KpOPpRO#kaJ{14kQwH+D`9lQ7*=S%18h@L_nF z@4m~--?I{6@J1ibR}3@O4lY;1vC#j(T>HdumXFim4f5q$10rBWLr_*}oFMS&u1yBD zzcO$n9tQnnqVl!3@-Oui)bmsg2B1szzH6A&qWEbX&9838cdJJrW>-01A7QZdQzIk^ zqs^vGnw8R~ukAH|^Q@koG&&{S$&=(^=WNwO*$>4dqpsrQbn6t-8$ACcv9Z*s8V!aa-QK4nL1^58{rS4pp6Q%Un@jlOH{ zQ%P4j?$t7$hDP5P_u()kT^Csa)f{yKL@}T9vn-ouXuj9VjZ-6*tm*I=n3)0f6!NB6 zP)TUX=3-Q6SC`PwdoI$iVQ=u<&|rvsWNAie@Sm?E60M5m!H2PvP7BstZ<4&z*( z?^k+C3|!IGzWke>i;=ZK27RrW zlWH*FfH}OYbbaddWWCc1N%0|r+I?koI3xcngFFCRWc#OVM~&d?PfgaCKA{@%jNRAP zL?qG4!%+?E%ENc2lTuzUgqI2!2!1#$t~|jQ=q`^uJ7{mphx1^63fNNmT4*UT;)%@; ztv_>bXb`~-@Xq#MgU@Q-CHZe#G|Ek z3W5s5>Y4e-CD9Pwj5|Fto}w6ic?8_(-gh{AH-Tt*mnfLTn}XB*A(#_b2z%Ik7fy1c zdCj@{6R2o9O znBPj`P8a^tyJ!E0wr>jVCF-|~ZQHhO+qP}nwoi0oCnr3yZQIUC@{jFIzL~l;H81z! zR?Wj+)el|OFWuF9?S6|%tn(Z|shi@}R$Hz3c2R#iWrz4p<|+0>W~D(d0!UX)A~sv+f>|CNAOXvmQ?h+{tE5B59wWHbV@UQQ6W8`d;a# z;$CbQ))i*>k>1CcubE72eF_UoxTKv&VRW>Z4YOfsaR`ro(+j728>c*rL(-)9(0!a_ zwh#9U;$kq7F0QNRkTv4#{82uV*Q|IcdPJ4&gEk;ecBo5CjWBM%N5=AA zuh8JcTV(t}##o{%=knR2(@Q?5nv+k>#b?*S`iF;-#p3$DSWqm~@1Mf45iu9Hc}!!( znrQL&a-~cs@{uf37R%ozd;UR%0q+Lod|PT_kFTuJgOjkXDhuQ~b28>r#^fnMk?bsg zzQo|pzvk6CK9=P=Ti|ED#HcJgENsO(U}dNW%Fh?3i~vp2e?d+<2jbbCbZDjXc}3}B zz&q11IPPnv9@6(`&^{LdeT5G84@U}hGJ~)Lr{N9DIiMl956e~ABV1JBI6$orruZG* z$k}biHcq4R03BS1C@GW@6K(ozpoBhJ7PGSSL`%wH0IS@h)r4EVXS%A7+^qURTP^Eu zr_EV58&jLRZy4N#vrtr^o=JTq5(Toc?TlRR$+KC9nFBvr0UOwtq6$PlVZFSgs}CfJj17`K-Wo@euf-{gELcNc@qb`E+>UX0+vrvA*sby53i=u=7QFN9Lm6kYu7k`c75_1T zuj&&t!F3PO&#DnnjL5ZB8I3gj!*ZbykoKZAHf?^TLK0@cl)hq<5xbVE_#TFJ^F)u_ zgeWJ`R*O=8*CAn|*JV6|s>)VAEJtHF#?z?1S+rNfN zPfs1&QvhY*ERxFMk1N#J8T|4`Ds6Y31DXIT-cznENQK2w;U*w`Ww=3cNXeuh!afi3 zkSoWV-gdN28pHV;&%3%K>?o8^fxZajuk#zL2Uld?K9lu^Fp?V+SE+pcTZwKYlm;e)6dV>0y@%X_)hY6@R_ax$M47fsDJ*99(M+aK>AobopK6U| z%P{seiMY%gr6L;ZlcLs|v=<)^kyU403*6>FFLtO}O*V@;-Vg}?oN0&w&KRVk9^ETz$Sj`?OhKyx@Idqr} zxnvx(47jV8vBn<|sF77=73qH6h9z-(W7I0u;BDv2P5w4IYkMGuVxV?ffQGV>tq-U1 zOVP0&wf|Nf3LN}A>?MAK&OZ>WBlz~tIqcmp{#l^6yP1bn1js-tOK$ZbKaKkJBn_eP zJ4Z52fk*DXgMcTCwK{dtS%K0?iX_i$G;oqb9O{f@(q9x_T{$el%tg6n-YA1oxN9e; zO{!2;evPKZrqw-*4S<1f$>5!aWlc#rb#I`-^@fY`Sn8Mauf$!T+Hx zT-Lr8-KN2_jGg*hSMt0C5K+g6-gs4BFi$0DqD^eQb zLpVE8aCPiNh;nd=xGXpI(g73eYCD4z-^&Nl{O+$`HV&bV%uf@OP*9`5jJnPw51u(S27wo{luC_W2|n>UH-s&RQF~X z;CnM}2)3HBI)VC47xe46656&Rr#lI>C~iH|pZ@H8lSlbDcEV@s$mxsnztl1CHj;|e!qz39qf?$wyIaYpZKQojjMA8VNW?pS#x%-SHHE> zFhg3g;cUlWNfhtzBN>>zYTV?Q1NQ*p_oq|(|6%hPVou790rM%M6gWVKNK;&C@tq<> z-cXJc=?XO*p_sK`Acs=LVmm=|uH&Op#~Sy9BMG#B99Gh`Ko2TICu-4PqfOQaQOOz4 z7$yH%#PWg}PU**FH1vC0J}$4{gT{4p9>dKA79{>jR~=Q7_06)jVH)SL0>{cJsiu`S zLMRR^q4UZh`K{3 ziW#mq3lXOJ@#9K_%wjLZjG1VJ@d4)>6_r%VcbInvEql*?b=*RJ2kLQxXtfGgm&kGvSi+ zdfOH{2`T54gDbLQhZFBF4uj|S+-tvD4}8g&W`rvHS6<7>}E=8#MOdz!-Ntl zw*}|F3LBy7$TD^a9&5);qZx zvTe5QKp?Rj&IzZ&0E^+?>6dO<1XRB1U6dhsWZf@@LooLLVUYQLzgkg&G=*EP(|bX(ko}ttEb#1IFr9hq|B$WE>?-SIbR}FG$NRgLF(WP zr)@>7Q|PuWjxe;ac2511Nz@$Oq&}wVq{MTB^CQT8-W`5_9gp@t5~Wr2fS~kb%i`tU z6iKa7%bF6D2@MVEXV$D2=-Rnz6rbC;b)Q%>W2Zj^{9b^VxT&Kc&W;g&WbebSWA~%m`(w42h@7Rrk;W4_CiKP;Ugk zJ|+`?>ad{$zwQoat9E^d&J8YWE|JL?t?c0`+UVtO&>q{~4b8i1iMctba&8EI$sd5W zPpwG9S!)zb!<6b3J5#ZIbikq#kP1-B#hADBXoFCu{gwOZwD9!N!K_+0Ctgto-u2{- zI?9Rd)$`jV&AB%mq{=C#5Z9(K$%_C_byB3T24#J*c)1+SA3Lx!h6uzCc)zWSanb=b zhE?vx(qvx#y>gAp)%RqYO? zQ6nBxBe%}KcIhLLx0AFNEs)b9?Af4DjKfh5If@>0-H9KLpD;0U-T8awWWX*$!0ylP zHKWY%r6(^TTl24)m)ughFmVc}c@&p4V(&zzX%&KS=&dxQG3}-@z0}hq4DD{55&W3@ zehbO?*_n0iy%ADJoIKxRB9Tiz+}XkVTM`^bEx!CVgWk?mX*fAc7dZ% z`Y%Mwp5bfVj~@K4x>-esU4w5-x^C(WrqI4tp6@h?b(m$P#)074Smq{i-h}#bQ`$qAxjOrIi<5uQji530z#fcabV^qh`<8*StU3U3BNE-D~x4aZclRWVm z#y&s$kh)lM)MvdF=F49kx5HV3%j`an1YGKYhSM91Pl(#@$2`Gwqx!=~2A04ZgtK)2 znkG!f<{@gyp@d(?bX=h8o=Hf!yS{qA@0+m$#-*%yc!=nvE>}qcvUZq>vBU1|^!r#k zS0M}rbVw|DMEZt74Y=#^7Pjv6IvujK1sqB?4-mHnFla`V|M$j zW^}ZeV;b(MNq8I3X+LbQp22QaqZip(G>2L+RE7KAB9IF6X+)Z~K&?s}Yc~(Z?Ht!a zBLYY?4EzAaxUKGmhOka8Jx|{7pKEXaYeD$B4>pDs*f|Bi%XLz7<>w;h3Hi3eaAf6Q z2pcQ3U`Be@6A!)dcwr)L>~yjx9kwmaj5qjmBcB))T-7}7ZXft!Fj02}6D97s%1E`b z==D7DhAkJ*sGMf?kJr|?9{f3T8E5=vEpNey52>8CqcJ;+&(^JQ;so4i@1|JLvAees zNT98Gcixyn59O64!gUFUwI@m}WNwKTkzmfEJxc9y4e3f7CNjKo;56~%&@KX^DP*N3 zsnIH1obz{T2gTf@N-qkXpU3P@kJo(c&gx*!)!542))oR}^JP(WY-%9=fN{NG+84|) zSx~3o_o{2=&f4b^OoC*^qEaKIQ?`Fu8b&M~Ud#2x8yWY5At)lZPdQP*Bq`yb72%NR z;U|>UD^r?p6s%}e$pyM%o{@rdWOARv$^6qNJYf>GrGWeecr`n+tKG6KrK~$$?OH`R zPFLCirs@s5LlgohS1Ty|D>rufXyaqeJ6O^pCZ_i)u1EWo1l64_JIc+#D#=fIHqQs) z49^q{qTz9kdW=`SHz;&jpy3JTc zB>rD*lH&E*!?rD1-M8NAf-VlK#DWT0;aB^gjmImx+8hKrlA2M$hdk%2_> zyFU1NbI4V8(17N+nCdThZ5qZ3=smQ7RBjxzPxuKI2`g-U zv1#(W*E6-NeaSTF{-Pqhyurn+k^SDs(Ns_`z4)Jjc%q@~wHSB?p&2|01K%uZyM>v# zP&)%%kmY-Y;As;JRE2%WUFu2vFTi*xgm}RYDtmdr&pLhG_)fb)@AP|L2wp~gp%^!P z5OpntBab%U%x)gUW1H?&YHjfAARKA#>zQ`3XV;pc&4;34u}sNvTw~|a=t_TZCzdQc z<;aX3>|J>D>bL6`_U}}ZS!Wx=IQ;gXgfDNmh0G~=h@}nh*i6#;V1K3!o`Y^4X-_PK zR0A4cF>>(~`T+e%67|P)(dMD(%9$fS)Mtzd&nDiIX#Fyq_{$F1vR;Q0d=`~2Z_XUI zcAXFs23gUODj$Wl|N2IbrV+i0XkW(+%WrR;>_=`@6Q4{fr?8wfNk{A0A9mp{m#tr> zk!gIKX4yYuiZcZd_=g|?+FH_ZKjZocz6tkXs@Upno&!mFGvg}X2{`u%^L|6~TP%#M zK)^d_cUb<{QCt1CRIj`&E?))!lW_`J^GZ!gfq6Sq&BRgqC>8?k1sgV2%n#uVM*Wcg z#9XB~vghi>no zA!z4FSZW)Kt#V5{9)i!YXbYB$1+olBeAmKpP_FI1xL~2BtNR2)4mugJ?gY z(Icd1kHOSVT2u1)cd88T;nKB8yN@SdQrOT$$jb8}5JNRrXgL8MsG>ht#A@%yOQ674 zjcdvFzLGw4Id-aYX48ZmaV!Cs}CH#oFm@TS3S(yRR6LrhrVAx*N$rOy8dtitNGn@-RZkwSBZ#So5jn{eUGQ>x{e7Y&1 zG4o`jrKc}pjY@y2n~l419Pl1kGPe^JWEaKM8v~)w${=j?4W?9c*OYxp+n6Lljbkvq zg^HCyYJxY54evSNd%V%|Vec-}wUx;x?b9Zd3q?q(?UIH*jF*P5)mvWh36&1@y7eU| z5sz>`tJ9E>nk=!x)~m=h7+3SRHuo>N{!)}cn8e7dsRIFMi~zMOxO2%32arTXiJA_N0Qs{4!GTklS*BcooL!*fZHZVZJ472$@b=Tb=I)=g^?+zAGHe1SL7BxCB4!2PjfL) zf-@{W=$B@Ousctz9MCA}%rG2SUNlwpVo*=^Ic%|h%A+IdtD<4%)M5mS;3%1G153TAd3-O6q-p$61Ljhc99x%tFW>wV^jcFlP(0}l82(V@9&AMh_e*G3Du)yY ze|%s8`82)M`8N{`q*V~!sZ`i`od*eW-kaM-2AwtFVajUUalv9tO}v@XNhYdBBmy5Q z?+vm|yxNaoGzM|@xGK)awx}?A?tKl*mIsoksUjK;r!}5gr`t)w)TIa!M(zR*dA+ zVi$fp)#uWi#o3^bB@;vhbhOPRAhCTJ*(%7r7PmYmeJbq|5Hfq_%JD3X?Ad?9RJm8? z%L=l`)c_TLk#Q`-f%4P=XM_C1C^v$066u?~aw+sz_iUZ6~KxH8s_0?K{&Xnfa2&M~p?%dx@iY<2tSJH&#P@CaK~- z0$-M=$4nV%>ZU#JzTqZ$sX2He4)Wi4s9IfG=Vho=_TQ@37fu!M14T#38*?tlbXOi! zg>N1Z3i|`PeRTwQz{CRzik?18XUn|)+h?lfhSzXzmO{USm#udf{OAuN8EkN3?oK;# z_*;%0Y6e~s^%LPEm39iZ2H;%OM>KnilEdwn=obFOu0rk;Qkf6UN!Dum z<410YGY|Mu8)n~=M)2(f{eoAh+e8ik?Q;a8lA$hF(^t{7c#5LXAUiixAH2b*u0k3! zYkSDjkEefME@wBS!r)dz=_kRJM;sB7dm{t6<`&LiZeQ zrEM3@o$_2M@R?#cABDnq@0;>UJ3JpUN8sy->{8szFX|Y~-6dkVL>WV0)h1R;QbQPK zqPkgzXC~A3S#(qiIh`_6g?UpVuP~{q(DYsTv0sEh!U(>G(9EDQkxPK?&ct2OpUt15 z(#S4`BUN3p7wb%~^?)~Aq@b7#t}RKf02bNomxT^-ZB2cC_zWCUQGYN@Uyby`A07DN zW_}#!_aKU;<-RbR?|KR?8zG)209&w^lWuJEx9U0Aa@VsIJKYGM40jr@FZCI|LUBT* zEIQL)uooGsCnHPHvMu4wR`{vCONeiQ?0$$m{vYbt+ZFxE-Yh8bB8SX}l(8nb(P^Cgn7trs~`{B+a&}fur(7@8%_uMinG> ze;y=+cQMKoM;n(;dbB2cb)?Z_DiD9G0U`Z`j$=Mg*2F7~i9Aj1F^K48K9%fsCY4ia z`mex0mY*KS4#sm1XBYthP0ASz&+ol%ePTV0)RVUpcUgK|S6F%WLAEIxpcN;{hdvuy zA$t)xGxat3pp5?4G7INy4I@__=j!b>E7{POC!8E+{mG1mQ(<1;z5u_&hrad&$fXV4 z;=mm8c@zO7u^#U*^w$v<(oQU0%+H&X-RP>CqC@|wKohv3uXD@d!5j{J2aI-3^cHz` z#LG8WdjcHZ9fV3L)|ytv77oD`Uy{6Dfb)*%PAW(Vhv*k=mu2(Fx8sM^J-adhqW(0% zi&Cp^Im7Dr$VvZT&VK7{n81h7q*Kd@{*)+;Lwlb`oy98JRuP|TjOrN)24*EK7wedR z=eGT9>S<%p7J$^x7GClmxGw#={W28Cn&3I@3>hG2WT1gEOf^UXnzunNdEPOQ>-h%e zHk%4|LetZr05!5^1~6$Yk+AIzna?H+m;S3z@$o|seFl1UKQjlZU;O*9E?6lvjBkCV zGu1o@n)y-fntSi&@1N5I5&}CHBnOtM0>PLb6U`q<`#Kvl=4k>-ELMej?rF4UBbtM{ zt4@+-;Hwj=4wN;S&s`*g;{UBy|0I=4s@&O>4jbo`)0u6c7Wt`vg%wa5@qh#d29p61 zLYC>OOZu4dJGf~ih`RaJU=Dst7x3UgN*-o5HO4LA66@#8WBbR?EMav61N8}aQHF&P z`H5CGW?dIf7n&&UUtQmAbkHQe6L5-eAD>hF%rUzje1{B%`Be}i;eGVZuU?o~H&vt9 z89KX7jF6MmvEof=h;klJn3uITLy)^Elt6Hl5P|m_KTnr^oxOUaFIjGaQ%GBb?)xX| zMiV~|D!D7F=_pM0*ax@61NC%)9apJi2vD@^z;Ax6Pb{y>&9A~Y;R2B+zvl}lb=sLQ zsJrlaf>Zw%6ZU@ORB}#)ayH9CX_U(Q@F!D5Nb-APq-;kHKk9_uUCCkUcD=Wl*Z60! zU1m5Xgg80}bSa6L(6^mS-+^C+QBV~Tt3A%5*HR3T!)Ep;?hp#STDw(rwIpR8U*XVj zgK7(SnL{7)x$kt+Gr4&J7_G_M?;$d;w}==82qylMdvSy5EH#&`$wn z?#=!y4VV=FWA2pE!lhQxI&IcyOvJCELgZt218wt^=i3M2P+WB~u86hoP!qxMswyl9 z(c5?Pj5JNC=fdb>GFqLOgo!{Il2#IKcK6TxSSD4%H7wq8@_5h* z*b}QxSZ$svy={oGRegnIv)61{R>w=~d8=uBt)+K*40KZJd>_+#%6z$o=H~t;u&oag z$5pRXmicgn-Gjmj_NmpGRY`EymgTGc`M3O#w>bgveQP(zMTs#vOPA5Pq8GVzN~~T< z9jZw`+4Q#`mIlG6I8dm^9_4`!*(U?8JDGi5tCyKpM7aQ1MpgBsc+zfJnR3#2CbmrV zc9it;h?cf<)>6Qz3-nNYH{HW$tA4QsR@~RK+S3bDjqAX^YRQe&xE!VnQ=Rn-5Yk2p;;d+s3n#gNOb!xXxy0#JWrJNDHCU z#QX6J?xUOMuyQPCs7}{w#q`3&U8<_yn8f8HFpQO^PO!=*Lo+zeByDHh_CNE%9E`Jt9()SF#%3q0U{;lsgajg z!>Y~Ywc)R8M$KWnn6FEZ=CQg-4Zv>ft659-$tk1yS93?U`KoXJw@6M=^|IeU88<^O z+{Ej{G>Ksmp@MX7ZpLtzP4U!A2U`!tv0qG#_hUwaTi$mI4aVyoKTbS?6yU(fFZk;^ zaDT4&Ym?*6iG_!sr^~8%wLg*Ax|>Jfbrf3!ivI4nb8mXK+;P*&tD=9sGYwP{$m z5|0PVmP&t`7v+|4B=fJq?*zq}Ge%Q96{$5Jcb>QR(fmlLZiF5PU|aGWgak#znFKS{ zp8C|p8diH$tG=9h;@?C+kGS;53Mi0AX$r^E0CghaaTh92SdZ`oL5&o1lMyaovK!d|{!X4#NJzD3 zl(Bnc`w-~lcZXQB|+bS*PylS(ziNAb-xDyA$<~!FSZ= zDIdC_TZ=Tep+!T0S%@; zb)nUvl3zJqfgGA8e7yo$ioS`!*C|JSjfJ+l-?*ixReMJb#(IfOH;(^B{(LaELUF)1 zTs#6d!i6al2338XD_$r&p#gI?y1Md=a)X#K?kDT4BR(1ff&}K0QQl#c>Jz&8+B$Hi z7Rb@oovwVHZy$PGl}oa!Y)`g2$o)Oq*cCRd*$!|^9^Hdwua26lz13#+Nd6Z!JbPgX`glWHqi!gJfz=wxBX!M5*5ZP}VNlYJ1hAefU zNTGuBD<0NBP_@guUqmyC7a?=_o;H&_?IjEk|888Td&H9Tcz~T%d5~RzThkUp0{}^) zeC9IJ1e}Rr8^Hp;a>P@PTQ(A#gT?+TBnP2cRL0AYF=-MI?|^yi#$K5b;YZWuV@efY zDO|^cd=-zbND?HCI$o2GX)7llMB(?xJe%JN3PRnDl{~4z&TUNk#kE08!zx+zZQkBk z`?$4_g?3{ekz?reTGB3=3~8vO+KHar-m4aOA@8T3g&2#u#1fQUW>_GFb#|clfA@z_k+F|Q3B#9O}GuFyS^|zh=zjfZiY|mH{VRwoJV4~gU?_oU=8UJ!JHIKa`+7Ov#B$P70`1+zIk=q{(4bfMad+1vdf@Zd!4f2@I6LZE zR5yZd<+HFH)4*V1dqq3)hHovT8$49M=@bEavX&c1bFBbBJH57~n%XDv9-iBNjiTkG zOI&kXOubz?-RZV3rS&^7xjZMCmj;T+9%e}8_b8-gFGNn#S{?)ZHvHeRK}q*=57z9P23}!o;zW0U&=1m2iWMt=Lu93fl8O( zVUR?hFg?wZ8QeP;dW+z7kG0e=E#(*YW49KGdOj0;QABg@BPJB^(RSaw5Cr(H$$Z_-BQK8+9xGh>;Y_r& z!sJM0K~EY+&H6Ul%|*l8=PcCLU=pTMGp7Z^qVbNK{8YHhNvkegGF)N3g}+E!HGugV&vzSW0&SH|!ny1z#L)RpMtO9a8oNH-$F1H7 zz8Gd*a-SjwN!JD`z`0cVX`5HP!4X(zX`M2?4T1-!?qTpOerqBL)ii&)->^e-iT37` z!m&86f_n4z(e=@Kj2K^VA2L1VI%E0HaK-Uk;*I37A{_cWUg_(j-|P7be{8C|BlJcN z#6o{9*#rtUe?7A3o^&o;jumech%gA-3J515}?9>Rf@Qbqd8;Bo?j9#jxPcqe3z)&s5b8gJ+K!-+^ zvfGQOkd?bt$+pVt^Lttdi!+-Te&_|oN3dF;7Kzc=u&mVuY@jsDh@I^(Z0t|HRdbRq z*E|(a7JumQZYoS5`3Ov`J>Ij+%CBO$8k}=ZFPAu@{52MN-ha%IRO+?Zva1c?-3M^M zw80`c76C@83!hUPfy` z1tQ+q505dDio`i?)3<6*#wnM^{{bcLbFbP_&1TRhGphPSVm&M{~Fr2-el5}K?1F~_yN^V@j zzn%WxMfc>m1@3Ts(mqS_CO41AnGz{+=ro8Xm{#{r#)d4wQkV5ZKe5a#)*n8evE^Ur zJ>Fk>zGh~;93Mx+R;gi;GkhV2%yP_s!?)>UKy`Hbd|wZP+3quj8wbq9isFgsA5rDh=55G&498)e)gjZtMhFPk z27lP3+c(}e^M4S3cQV=BMO75JVnds6>Aq&Jw$BR2Jd-Tky}9b{hWT>3E8*8KB0QET zN)+%UjZx@dEMAGam=lFf~Ppl&jkr6+2Y82#l`WZW*9 zrE74hyovG@)_8Q+-wP0;!3N4EJh|Q?!YY38FnRryYbSw7;os@!+l`2>%^et@Z+A@_ zwINGx`m27_U!IbhK1_dI;=I{BM{hCafyk0QK5T=7OVRri3I%81(!)5q39l+?**7e8 zY*U^9%fbPuyKr&B9@%;X;cZ4*t-3;oma^SM1L0cAd$iEp?%z!Jl?!19&(y+w)%6g=^Z#jNtcMwG*H}DZ1VM5 z)QvP-vp#L%*t>O(^`afyR8|myhWFreX9f_%lf(5Uf!KTw%sa+f1Q6S;%`v9^1mrqG zY`b`fapYS*a9S0jR8#5U!wNGrC9)Be0juF7wJ3kK)%kiu*hiH50CQ^A(7RY}u;$6D zr%IH=>ez!70#UgBLcH$5q#?HI?8slzp{zZs0QRvg8yYN%%`|8?k|>_*&T>|wehmtQ zI7yq)rU_zzHkweiDrZ5Fx+9#GIHZ+QxtBAZ0bZnF>>-i6y%83NjBF{pTOsM>R*fqz ziK=WoUCsn;17nujn*u(hJPhYQDq_)hvILpG+_j*cqN_Oyui$MvcO&i6lUD;+yF;$f zj@o)ni$wN+rz}4LztR~evO!7g|Ka3yB1o*SGE)dj(6mC%#83?fV_LicN%1)*FREAl z8jHlqo!to+>#?G1wTl&?a6PRI%EVDkZe^ zyOj+oNlRpHx_rK}W1j4aUl^+Q5sdg_1~u%4_ZQNDqaH|rXaMi++u}u&O695@=i%K3iO2%Oc+%%wIBe|GYWoq8MWvV=CWA4C*K_Y!N z)%Fkx9EIdkw4^pr3KzNh{T2UEw16zJejTwuG-E?tet>(uchpRrm^rk z1F7n{O?l;b1!CXzLQ+{C1IBm_1Amsnw^QFA!(E^uKLTi@7RKe>gHk)|gjS!Zoc0}} zth%;hV63SCCyVqrgbSt>|A-tG7}P%?x!PQEKw|r3lCH$y`CFnEOQ&P=Bq{JT%J5E%lky%fJ(8t}7olGIqH;E5?HJgF87*Vs(TY$-W27$3?UQ`sHQ7)t^pSch$P z5?Wsz05)fgu`zSxXE8okEvW~nmQdYLtDu!MkBJ$WnIN(#VW2T=j=P!Jvi*ytJwrp+ zT%e|DDG^MN6KuEfF`J~+UZd0kn@BH`J#Tsyv9X%~BdBH!v(VkRaC&Y;%#tc!C8EglMhk! z=_hdi)-;X_ijPXws%7SoX5A>QNBm$Aw?jHBU51r`hTDrtObqRVMb_+`qF~{kz3yn^ zI-I<~FLFONNZGG`!N5rJ@;Jd@O3TQ=o`f-epf7J8l4)SS@@T1UOl#T^7@Xx8$?P@G zcZ)KB;W9pCjzoHa{K!10ZYC{AS}sD-(KxFQaRnkPu@5To6axvea3bY@-! zU5iCM;>p2mAdv(CV7|RE5D$g8SKqR9%GW7!$pheTA%T8Y^HqG{fy_666`8_{jbcP4 z&?DjN67eX~BMD;O+i`S?9#?hft4nahn9cdV$ulJjMZ(dfsM7WR3a2 z8>#mJVaw)#?cmI@LACv&?O;uVv%OXV)yB_QJ0|;2i_hl$!Q=0vSeMUn)cFy9rJmkI zAJdL>b!}$DA~^l&Mq4%inYEqPDcUMPTElQ|W1AMs@GdJVAQut`)ob49hCBZQ_4A9n zPT(KxgDgjun6K};*~05kUdD_CD>n(Qn6C>R6tY9^7ukvBn4mcG?^vQHIk@-(82U;6 zhlmA`bWJMJsn*#O^eUOOLh%57x@y1RGV`9?Z^_|^aRAt52_cqZqaRDM;*Ys1Yqa8y+>cc`0&qZ%>3d$V$ML$PrvbPpQEejVsv?nPA9b6Lv zpTKY}fz7ssNp8W?9erf_^?7a#A+|D^^0B|p-|1;imNk~8)qlyUd}*dUKhHbAipyB4 zyZlRJsn(P8M!&F0{ui@&cQG|6lNGo@Q}Sjzgj60Jy4crmy?3ByI1OgizY*65n_&WG z!c>HoIo{V`Y|e&kJ^Hwem-_-Dmg~hTfo~WTwfKHaLP#78nH1eMHbh_+_u z62UtaDtmg5_DDe7`ZaW1`LF7fPlDuozL5iO!e0`jfvR!zQm0-acP3(J zm=QLGlIK4_v7KyRRzT^LcDE7Jqm_=2vLzqnkg=o1E)|%ilJU<|UV8MFaCQ=$rD_R} zBR#x&L&Nr5E$?df^be9d5~p|~GWDYA@3vDpIO%f6CBN!X+@NxP_MgD?-3{#WKOb-1 z()ZCvd4UtSafMzbU79%@8%^PQx+PQalZ!?r)Fg1s@oL1sE)DxyB7bN*yze(m@KWlKqTF?zSf#dy0{$Z>DFo5xPk=C(SE<52`*@>{S; z9i1%C2uRjE@R8Ne^V6zjuw;MsGqUJ%*3d(=TK162Jr!io`E}LOxV@`u&}n?9Nt2%X z@tftq27IFwc7t!gJM3PCVADO{O}6_NDz|}xoj3P+N-kK1tP7*SjB|YA;AxD0AX`ga z4b+%GPH}lBBw24AQAG#HHAvG zGHRf;yHl^kD`&fBx)#coXRs#+wd;t7M~AHPqJ3)1wr052B;{-SJN`Z;pB~`MUrU*f zoQ{>ui->iV`1ie+{*esVN-stHigo-#21dZzv2b)m03j%hBvUN`@AaVkj6mM)pe&iI z)sIDe5yLE^J9TI``x&VQ_LN_k@quE|%v%3?lx+nHfY}?ollCzJJUw_-g4MG(%K2gDtOSR@to z3O3e{%~VSm6n!-=S()t9t&v21^C2`uHiKB0IrSFY+l8hh=jc(=x2$WZ_K*=ge1UmN|$_I`#Pc~^5jq+u-T*$KB4A_&V`3po>sRfM(pp>`NKUGx|UpQg|L8tp349KsTD5v|68r_cXZw4N_n>VNJ- z#11w?a6`68A_ut17-dgEg<)?|c#_4B!%={P-30jUOj{u%YtX`!lg&WQi3=Iy3^5Ti zDX!eY4Pc#y^c_E2ViJyGG9i+>tT{aUw2p6%^Tb))d}{#GwkYBtIBV2LKo-f$gt06y z1hL^wHcIzX+>F+)6+~c!Gm?+VXo&P`NgBzR;jJ=yh(wD07kX$*+7t^9`?jVe`26 zuTT;dYAHTUBBe2C{ZRXN$b(Sn=gNc<6-x=YxYdI7(sB`nha@`8KmMVhrJ!^>Zc`fe zY2-MkO3MV}Fj;Q5OIVH8r6wbHS$tTH)wx7KT(C*b0qEoA<^5ugs@8tL zlH1c}pzq~zUMpun?=J6EAMF!Sz{y>?3h1&em4Y^MI(v%Slcgl;;u)NLVrUT3Y>wQ! z>rWYNkDxaze3_R3{+kz*5Wn9WnvvetXba!yVsu$$NsUI?fsQTK&n|5Igc8uiOkRb?idqICdSEaEQ5psa0h8O)c{=K(*32*}^%5SDh zLrSGN=X;|3b!7PR0sX$;EmJBx7*#w3OkO+k)OC3P&KC`5bg9P;e0>RPpLu<*Vng;G z8;BqwobPbp!QD-ivIy#&4bkF0JUZPy+_!y>ZzC~uQ37R&$R~+D$$clGtq8wZ<49iU zqo|cMyf7_@!xJ&{1w8gz!J~olZg*0cGE(^Aqjhu)nydfLLs5n&F(8pU-sV@ zjbioD`p-^bG^|<3wKGbzJKenlw(k(;oD!ccdqI7R10W?r{guNmii{y8BpabN#Yge6 zy4N|u6x@(amgkbG7pVLeje8c+bTCYYU~U6ChdWj~UJxmwq)mCA=+BWCvp;pzC~|KR z$nO=HBgL|PvzbN1!(BUL7ITN213CHO@$vuU^Amf~fK{OXRvGXJw zc=>1bk*H@;)qY32@zY5tUqv-w2~@3`Dx>E1(L}?H-&e)*@Oh=qK9UEEyTq&?Cbmt) z!Wry$Go%`g9Db9*I}UP1?J-2H3>~XftOCd6GK3!>C&*W5Ip=cU?5a*W=}J|)x~r?d zByZlQ>JI*9gyy_VCTb@)S`&q$X^2S0B6cUYsnqtALNzGPmareD6Yf)Bw7j_4VcNi{ z>8Z>``NG(Lk^f8{P3(6}X6&ytA!j3%m{cQu5hj7W6rBe~R$%=aUGc@;%vX<85;Q6kcTB5R%ccBBLD(DHWF3f$JSV`JJ=oGM=LF;P|Z z1a(&QdHHx>Pr~)-EhUZx9&e^tu0Ve#Q3F(0yaFg6x0HnaEDJu@X50Y{b7E(c; zH6A4whZF{x9*=4IgHVi#`sqb7O0M3dS#ol6fM)r+Ve4)6@i1{$`Xqt0_CECfIAAQv z9d1)A{BP@h?>uzEw`O)o!`{QE7@f8fFW%v&r4FkZ7Lsyl7|nnXj&ddgK8fbv8sT$LFv&PF{*$V*-N|%&{)H= zcrOL(Eh*UZS8!*3wuMEgIb?M{?h44Ay&#Zr?hm}d;NqNK`KpL>j4&E0**w-m7fB@J z^e`+SG@TtNb!RVX?JW?Oo;x5QRQPBT7Y7wEf1tQf&_sv+&lNxW#06qx>E)y69`#CO z!ckwV+0pytR@Z=HvnG132u=6nXqq42LmYn)=x4epC?VtS3^zSOAE4)PB=}GAOc)L6 zr7Ca3Q{d0IX>JwSr7HJ>o@NHBuLzI_<;6poCKj^qGwAGQ#3LU6+ZnmIito(pXqR=% zD)W9{JhjbTsroNIS0_goU#DeqY2p6LScrPmqLI3t!NSJ<$Utw2Nn|A-yWlcq<-{tm zywfKND*wDkyA3vG=n$rjB>im^r(G{1^7GC>Vn`mYt&&i*h%`t1 zWJY(n`6VlHs=DIryUOIIDswe&$~jRHufv7%xH3#~@21(|NPJqLwP2wx`dW+7yGCIG zdmQDvfM6x_pp88+4ctWzd{qwohKtH`7@M76G*4cC^vh(BAmSrAmB7v^4;f4nYXrSh zDPcx8R0DOCt$s48m1i<0z{OXHf3fOKqrxhNxe{A+xjaQPR8Y6I>1tz;f?5v{p3BBS zZ!_SIb)$z>A^nayr08&38#25xrGFbjx-**55wp-=X8@`LEBc4pktBcSw)yaJtCn4)^hjd|KCgT}YSHp3|z_l!IiU$fV zpd+k9ZGQ*Y`)YpWO)FUPM$}(HYb?S8{{qe>181}YdH`OdH!%ixhYIp1XL)&2F zW#A`z883=D`~Ta1-FBJ>n@m@Hslo{M++Xv)mNY#v)Rg zp;9p^I2m{ea=gE#p~!nHf7&EvIV;nAPM{?%Q~W6`; z&idyfZI+X6o;cu%tWaGx0eJNX zT5JMzJT%JK9SBIvXKBmlt!1tCV%;W_9qTFY3X!1gKj(+itBK*R5L&BZXe7n}HY*T}^#%|iGavTev_v&z=z5x7WG{ z4+CA(#%FJwh)t@NIR_9&C7V1{$kYu};rofIhSq|rxMEIFW36yTtuX&?xFfedDn|>k zP=nPVv#6P%SgF=W#AHPSe{UU%I9NogVoSnO4 z`KI`q6Ib1to1CLho6ax59D!TtO`K+_e#BhLD3&0)ecHObe@qDS8W-zydoFc6-^t0_ zavHJg(5<#svApGLQS<8X8a3c04VY2_8GR>!0=9R0uZgdWApVytN$8IN!12 zz1G5nyfwwZNN%7%y>S=n)?-XFEfL<73X1@x;;b3H!AZwh z*Lww%zU=V8MdJkD=`iNr0RO0N8_@F-8>0bdNJ#uDCf^u`!i}^}->d=4{F? zFDB(7Cmp#~QNxv4M_+Xh4{KD^Y3H1Hs&j6IPCQtS&Y$I&Zhp9xl$n`rzmZd+$Bf^< zi#FA_zvofL+8Rw9WLlEnJV7wr5G!k+#v4S92g|p~*(#_dKT)BS-xo-g%>L`kiG}BO zgB`iWVrMP5b1qW|A<5JeijI0A|6oZTeSHOBW29wQl!SW3ep867*`bzgnZN{}0~ zZx}rDFrdd0*jw(I$SQu?$ZIxppwX~{TLaeKHzgwA-F=e`YUNvuCWb3YE zGkH3qyC7+z?u_P&i!TL!A(pndnOh8Q;3;2m4-WmZ`EgsB(EpWmE#;1BB;_`bi9N25 zWK?dO8b)+oPXr<(Cf>nRjNeSu{PyveZW@!g?sF2_q1Nsmna}2rZo}8JX5rD3$8G#3 zn9`(B8VF`OAoO7W#_H1%)x~}KO{W*>M-|^Sk?QEVJd5r+RFn4nUfLf++^bT%qS7Jz zo)vv*7G|Wna*dBNGR*})m1#3dM7<;J_J1Dys@)9eO0lQosmGM!^<+LArKR8wSz7Ri z>}`0X_VuWv9Nid7mkg0exr1)9HUk(cRw)AXnG6?WFRKYXJ!f33lPfPCcCp`Y@YKW( zJG9pd$DSO`7b^)$^*%9s{7~_z6|kx^=*B~!S-n_-=*yF|w)b7ZX6>bA+l!A~@MN{S zQ!Uy%QqbebOFHoVZ#aV+vAJEjuc1I(0{uJ=-pVxOvYOEiLiQKCBl1^5b*1}Nwbi@- zozUDaENhle$h3DP)R%aP&Qx$y%QJP$n?ga=2LgO(vR&<~T+uvTGM z70lJ1YilM&s5)@a3V{(Q!MX`a*3< zBsvj}#^I_lKfF)=dJpz>t=Y_-Ts@S+_9{C?{r2`;I{o`Jz1YBGX47Sr&wc7_nRlGW zQi5iIv|OT?cvL9!*Sz7+it3VDG7OitV2EXmexQtT>6X>xcLSDVpI%LM#0)H#Vy5lg z5yaB_Aaot==5$;pwYt+8e2dYh-k6X1SV3fFbMhp2_Eh=ynv}`$wUNoS%zsYbH7S$S z4S0mX4IBfF)ak57sm)Tfb4TN&n~RB(S2{B?(OF~{;zq~9QH^3eEAkGSp?9PBE^~GR zJTfP#!Z~TmrB}BmS{y4rBMx!EFVMD`-If+3JTH`#6(PL8x#y#%>v9sx-&+OYL8bZxkeHTYJ81U51v+}+-zz+1;3m5g0|Rp!zYQ%Ig01{ z5g+enb=sRLcQ^EDhzn>|WS(GmGVQmL{?56PPicaguF69h0@gM^~ zfx4qpQt}#FIvQC3R*7Gfa$7D^sZ=D6Z@rtw+*#g^X2XTY$Csmc<#kIzyBqujE(eze zQ&insvScfFQIqbZ%3ryz!su!6FZ+2ea0XeNJWg&bYsaVM9umjgtqD@oL0$3Xsc&x% z`T_LC(?VY90WUkd)v-rk*!e#)v-xWAN?(XX->Ct#yjd?cbLHrj=JQi%;u5|W->US| zr1}W1Ujv}pBEC>2gcobDCJnUDodws#NZYh+Lm6e{SJlRpC}QMU$Ox z^tI<^mYl8vVRs60@slt2-Kzryj9t>}H47=T-m2~!!CEwPMTowtfu8==zp!f}nCLj# zV>C&bc=eBJoZFxv&7fdXg@(9`bGocx@R@x?6#R$KCJJfq_jS*UO#19 zj}y>Y&BCnYhM2*+(}KjY^GpD%V~rX^Xd~IToJ2!6G3b4n zIne91mVFm;u|I?hT!2d=;Zf9r6%4}u)t0DK^a3Er< z-)(qBbvN-abRrPWk5G`jvY9zIQDjhJ%cLG7-r|ixf)r;dR&!F8w{UMlH0{i_!~4YN zh5xYm3GXoi4)@e9&0n;h$uSS9BJ~#n5+i0r4hNB|8TiZI5g9O10g?r_26_|GpGt5! zl~_R^!S+j<1)Pi_$Y+SQIdyALs2MPqBIxuxqzof~JDCgXC&y8QFldFbHDfL^WbXmS zfA$P*VsFcoQ?WpbI%O`7(|Uu9`lQHGY=t;kU;t4Rt0r%Zg^$sBiPTG z&6)`u!}zvljXgD1EBoX~iy?hr2<9Vs^mbslqhqW29^~&cjD|G0)khP7w8aZv-Lmck z=j#sH^f4k(`*xQY;Vi;v6cy>em{;MXG#n^@Iu znd3aCwp%DE7NCMFL>@!fDM{+ujV^`*Hjp8kv`?6S1c8b6p6GnUE;7&^=EMnU7W*>L zpvI0DvjOvu8a3qJ`cKR~hcmXwPM zy2P;6*zqDQxz9vekd@a*Xpb`r8E1M-yM6pmAC$esqMg(}vB6;ah*MU+u-C;*+#x%H z7`h5fZBtY|JLDgk{;=qVes-u5`+eEOv>BgeLIyZ=c{f<_Y&P3<7%eGdQVi0>+mt2& zbmOAoM?$@QlC%K6C0PDSe=J<9>8v|SOCJ2gb_{JWJQ;l?;;|s8c^ehDmrkBE4$TcZ zz8$kpTV@r{56h=)N^Z-}9)w)5AB57CyaOxil8H+UW2`dSznJr*6hs$Plnsds&EVtg zDm(?lt$(r6jf94Skf;YhhSPdm`+kZeZ@9}^Ggl<%{{*oQCJ$l%q317dRp&BKpsAP6 z$qdrg>NH=LaT%q(8*_gfW^={U{Pf@*V^o~`BZvW-+P9c{n51jdYs{b!5{j-QnQ~yN zK54)rUh-(R$6ohye|mJNoR#-V2xA^X1Y5Glnh{+!>~hc+ou@Zxm6OeF~Ck1;;0PY`kv%?+7wE?f;Fk8ywc zhatJYwn2|`zf+CmV!DS*bHnn7$k*VCIxV&kCSVKHAuL7UHtvrEfnLV*skZ=;NomxX z*}f=m%XONEibvPI@yC=8wk1@--NcMKiLzc(YfQYU$t80Xj8)Dw(MB{5l|WkYWDtJ? zDP$95Bv>^4;N0ds*u{`n1Q-RIB2uGKe%Nq>9jA%e9IJ^j%mJ#WtDvYj##)MVa{AJy zz{|)1B^4U@0;0wk;(F9V4>AAFN5P;~p!H~E&Jptf>%XtHsQ36fC5+&e$_AXFx+biI z=Hl9rAo~b3Bcy(gBiznBdnB!QNLZ&GMBBIgK;y>lTE^;t@!YmOa8t4pYujYwPFE!g$R@BGN-CKB(?_Z} z`fc%0FH)xMRm_;tQy=$7RG@pMaM`2ovE%w-G^cs|*sGZ9be=9rXP24FD{Y_9o-HnJ zrEC*=#rD<*sL@m6o38YNvjAfSrKZUA^aMuF(9n`lGCjqi$^`&9LGz`k!ej{Mq-tDI zQfNC=C6r)7EMG23!qaxju@lHCiKCf^voswsj5p*5mJm4oT|I+dR7gpW>OQcbqAZrE zAT-H8lzj&XG4Xx~)$-_peoU%{XN_)9bNt|*+CX;ARf=*mKv`F%Nqh3>iZ1f&41a^? zZ&|vyAxaLGuzi6psPmA)tlqew=H?PAl{*W%!FxV+kuic#F4($cK2{CqyF{9)sK{)m z;npI&3+mp5O{>Psh!b+-uPB|yT#D)mH^s^W5H{M!eTQdBY5}?SUES;v7mQ$8d!3hw z%S{6FJap9cFB*05RXU8Un)T0L_=c3%f#&1|al{Q9!dm?!+ptjyqLSVytfeTiDD{Gt)=?l7{2 zLafq9%`z8<3~~yqP32dRx8mI^|2-n;-~ZlRU+DCtSshG$l|#E|4w9f3R5*SX&mcUj z+qtEr&y!Pmi6R$eUBNuY(V^>b>ONH_p2ln|CPN9at|A!+p}A!0<-=bVA>CZNGGT@J zITRmYz=8^FsI=nve*I=+zd{6q|WCJ~;DfYl$m93A19WMjEnNL2TsjL|CeQHT`b` z>jG$FX3#5$ziOAdd9>8;%7K3vm7Zv`wudorjs25Jtn5tw+g0HE4i?%2Q+)@gIagM{Y+=v6_gRstmoGTW##%ZJp7f0%))*F z8a(GX6_qIT_(58FDI}czykZbWm#9HmvuEX4Q7pg+`sH@J&MfO`r1ZIcVKmOxG|MMw zzj&I`53oY|ruz*Q9}Q@@%KJd6H-BZHI10YTad@VqP!;#2mPGn2Z|wit$W<}@tezX* z^XC|k=P}RTS7ZDYDFp#7VOg#l$|XXnRYns&HJ5&G#ID3g1y$tDWSh}{rKBbnTFP0Qt-5(}Q<9G}+zhamJKl=R$ zXDk7FTyVBNw`*CD2O`h9zFxfuZfz+kW2-V-gL7L+Y-B}TO{lCitj+n6AgV(gRGC(| zk>Ts;5&l_;T&W=c$+H6pwx#dzf0vmnq8=fP7h;*4r5!S ztS0td>7mi6-U4qujzv*ECHc~ZAq}TM&rw@)>dp|f{$T5VjGacD1;UrR;wvPKEX3d1 z=o6~ep1AVEu#8PQQQRj*zh`vI>N&CG`ivx>L{xG3l65`Nw<5Gv^AsYOAXiQou|7#U-l>r%3W!NqnI{19!5(|gB z(M83&8a-&M?a6<37E}6`!B&v=1NW; z(b2*RnL&YdkW_wPov(cV$Ll4m;EOP9A0*$7*BA+l3lgW6V2I{K4F`*s zc`^|XEFyQ+zmMUuymxboZ>3kh^Om`*r(;%1n%{;Z^b9~w>zL)waL=*AUdVw6LdkiO z^>HQU<*#Ds_uPHn5rx?*A^*C(D=9KH=lWz^NNJE%yfg|={KIf2S#Jd)(tV< z5+S4gx^w5`ksi$WH#BT)Gbbt-EoYpGR&Y5<&y+sk<2OKmNZuQ<*#-H#IwDB!0? z5ROHzCWDz;&a0M7ciid6}uWL{{ZafbK(X307rIFfbC#x2mo>qOr`m4M%aZWN&rnYIn;4= z#%XLkM3u6vxrXEBF4QsJxMIG# zEDJv9t+Zp#NWVZ}56{3HDfwMc+?0FmywPR}dL7Ad7g2)u@(r_}%jU$`cKm)8IXTJ#RF^*UI;zo*p;Wi9mO-pBdi z7#u6ua$Fl>C-V z+4=q<;XW?wkTpn;Gn4Et(l|4ni?C=!0L|lmeFURV%jO`x$UQm`-9kqVZv|ZKgW4kX z`g_5irsJ96{q?YEM$p@9kR2^%pUBR8wn^6h!|2%itO-6~<@foglEmQkhva??rORr5 zB=z-pCDsjws(qBo`d8IuebMk5uPdJ?)|l{CLErP{E`$CaM`yvgB`qZ?pXyLE`7`xy z5hjZz&VWCk`WHY^(I3$3XTE(~ES-dzbFbfckT|-a=#aPrLBo@sH4hD-W%RJ_Bl_=d zf4gV}=q90)-7BX;*(Lwc%J1>HUSX?3=(lE(iP-)QnN)8ltNQ=RAJxG-`;dP_V=%AI zgQ?P~g|_0>(g9Q$C~l1sh{O~)bo(h`G7V7nGro4YZkKBdDK!^6R5|4Lvv^PLS1jKB z)V#82pYe|STp44p_4{f;_g>?FFDL=1&npE}Xx2m~kD((Lp?Tp6K;DSCdBf_1@#TOH z;5z9nWq@W6)8=L7=d*YV0NBci;yFjXk4-^oBjwz5R=;vn1QS!@!c^3z8b0k5D9j0kVyWdz- zb|)$-3Bh8`WtZ{GKu1AzN(0~YX&Q3hZkBQ2#3Z*^9<`a|EY#j-co?m+m)7bLjlWnP zupZe$^=czdPV`1c#zyvL4wnW-^WX|!V(Irs76j#~e0juc5RklZ=l^Ar*r)O#f6L`3(X-tGvOu>4qh7Z1KLwE8 z&wn+vh$>3zH+Z_YXBN3~tf^D@$I7j&G(1n$B>#~WYDBk8P*wm8%1G!e_eWJoE&gK& zi4gUt26T{cNkyfNCQj##3=Qpq*_l0WlOss>+$OJG^R4g<%}b#I{T|$+eaPdgz>;C) z^c%l)C`DNpUtQX}HFyd?ZvZc^M}_ySQkL@~ar*s7$TZ&9I(zB0z-f6vil^aoqPq=7L+hCb%oR}rAw+6<>i;EyU-eQW^$yTg_>+-~8qa^APC~)(#3dG*8bnd;?{fB`_9R(W@Q)C4Ns;p$$}A#!L`0 z|GNc%0b&I3m8I1?Apq#;3bC_&PLDzE`-vlw=Vk5!6uvj?$(Yr&J8v-%F1)+>UkrcI z>zl4&U8>L99ywy2cLjhv#<+vGCV*uEcl+qH&PEwr=bH+mbKqpwKanz%u1XrAN_d>u zu_+bb+sxgzm^&?~`G9!NM>}oF`M&JO@GGy|UZ$0OA`h;llN8*H)vDXd*KyzIw@>1J>4z%NECAHt~rqMh~ z-q@Tw7wRiph4T$RjWNByz;19V=B7!#`opbM!g6%v+NJ= z-?Xc1XD}5)C%h{#!%c7*6`#a*}5*hX^<4F)tW`M{Y^j`?Dry!+|(Z3 z{TR?3L#EJZd>!O_(cx!&3b0o}KNoD1E`&4I=9y@REI+}roy>zb3xu%$))OpPkaqGAq!(*S{=o zdspC5Dz0dpa+xg(Ly3~%s>rMA5`Snk7Ib{fO0#eRa+&C~P7_RiEHm`A_W28*K97GG zQyy<&waYkc6KooSkfd(%`&xhz&_yYBFM zm9@DOSod9oy{*(fV}rglKZn10>FP?|nZnWKGYuXN!z7d+%IsnlQpsbgkO1e=x!3*P(4DD?2HtIIn%b$X|Dj zDyNy)&j0Xw;J_c(?INpPx$ZT-ew5;dG@!RKUU=i*p#vNKXmqak?P$OyRzOMgp@yf~ zqkW^j@}db=NiD(nM5i{?a91FH`q<5@>o@mbjE{fMZ6w>X7v+y$P>w3BQvHP7Z+yIE zx_<5r%n@_*l_1^(AC7dNCL0a#mQ`N5s)EE*qNp(|QVKeLexA z4=W%id2kQ9wK0hj6kih zJ?=J3RO)>F^#6&}XV-x~63snvc0Sio+}y!4LtQXrhgr@?r_erFz^LKgyv{xK0w5{V z0cjjtV-^U@vcIosT2n7uFAnInfQ z>G>M*&6%b6@*n1~0%k8I2In*a>QPXn{D~{bKlu(mMp3+mb5?Gvcg;81<=Y&cHu# znQ~N%QK{4Iv+weg&PNO2d|7sj({;bXJa9VuLTj@j02j$PJeF6OS`xvRA*vc3HZ_4g z{?k5FJ$@#vyR{+D^Z*fd*ee!LX%tz^*>g?B6wjqp!@~%Nh>uH$oQa7mT)b+J!=jcw zOz^+TGh47hi9BrMV{^9(1q5myTaNb=d#%5{;?-R&Z2s`K9b-LWb}bxbynPuSz0<7) zi9N|qm3}&;+l$RDtd@x{6oqSLcpr0*q>8kj zjok=HVfG+|+VR99vyX^28~%XRn1SG%dK{};d68S$av#sAr9)e*-JH70FJ)|a=upGa zmM9m8SCpnQLFZB5FV=@ytz>YmImf@%rqwaB<)SjF9)D`@FseM=xNu8-yI?SmDEDN- zWNJY15^aRpNPgMq@owLa?VN|)0*!UoLAA8D8GfNNaLQRt4zyPW=A7# zX&=zl?PcHxRo3ANjl{8o3NlN5AjSZk?MqeNFo@ILy?Nk5sa~#XZuI&Mp@G#9H+_TA zqwhj{fw-8%kE~H&bL{ghH4*?v(qQuD5{OEvFDOZK>`|GZrpun~;i&Qp4K(8K)o4n2 za;Qb16;>?}vm9R3n+w9CX<7snvxBbT^GLLQOn;NZ%`*zy$D#cV94Z*|mUB1JuhT9S zrK~cwsuMr_V>DPiUMEBZ1w}YyLK(|9K=-hooIFX}vQW;b;9hvnQVuiY*BA|FLcM07 zxNO4Cvaw-KtH?oPnQ*Y$c*xxHu&(?adUE7s$X^~Pk_;(Ls(_i(eJ-*-7&65Aj8DFX z7pER2dQ^$oZm>K`!Q`}*RJQ_A>lXiqU02GQMgK5KN22lwQkY`#k~LX7BB^G>(nQFj z!FZ{9nMuy&ucE;?)`0D}No_OS}Kwd|dm9wK!g;CPxkw*H{x&*6Rzzo-} z0?1GG8qlUB^ld1b>qM9XEX$}sGTPBuvQc;uaW5rO#ZC3m@5_OqNS|Lyhn{7mnjLax z)>N)p(`f(|=A$8hcldNnZ7^PLNLP6jZ`vvKu&Fq2v-W&tLhdAe7QtDI~Xb(2}m4xBjEh?4~Wfe)V!nzogq49iV`Df34{0smCbYKg3!{PPZ`4uVkwRK)rAneR&z?pY<{Izt7IQkDd_-;bzi5TGo z&XZa*6^&Beq_Qyvn|+7M@hGF9s*5(WP%>tFf*xauvbsy~qAO!mfdloi-68PqC{7vo zTMqk7V$?w)#>gR%>W4yz3UXF)`a=E4n)zY0qeId2ASTy0e}P>=IBiWV!@kU37*{aS zHA+mYBKv~XAHfzop+ss#?)>M&mio-QjdX1{ zA~&O5lR!~1R<|IdK+!C#+pt7fJo|<|qG~w2xjaN1s|~R|IT18PlD5&)Z^plw2Z}ZxuY5ikDitOojP^K*kBi^A!WD!}d1{p@hHVrP$-UGku z1ornp8DzD9Q+QSY>OJ>l=(T{F-)=D2yOmsN=Qg~?slY1F06P91>pxc`zKbC}U$3#c zJ~|&yWS?yWK7^~hz>Z+Q*Wf=nKCec8fNS)AR&qla&;0&gKA1%&3qBw0uH?Qmw#-0Z ze%(7xaSSE_%Bu5J)^#@N`mR^te%?E7m0@skHg)3Se%A%a2qgg5{F4=m3I$vy!&b?- zO){M~ng##a9iKsr$NywHl;lC&H1LDfsvrQW?7@IZTrI7J*UGjCu7dC~QHumD+E<66 zM;$RJj<*`&Rv6H@aBw+@xg#(fS=4D9pR}R3yxsf|K)0pc*!JIXg@0r4YzyA-U-r?f zYxyLQZM#k2>zAg*VMzb#nY`WshKu`_Wc94%nm9U!%~g?gqBdfsL1V{_@Uk!<8@Mm~ zub(TNPQ7}Lc}LDSCO*v$!Po$q3r@86EY@nKl@4S?KHJ(~+k4aV&_L^?G`U@)?2%=- zBr`RJBuHzeEnkj5*ny27D$q?OHuc7=^JrGR#+ozWikH#ow@~na#T+2!pYn8r)y?ZrlCx+|)KSI8#@5Fbx*T4}gb( zVX$J>m=q%{D=ueSXbYlNLZF8?sHoTQJO+onyT!9NLOaVkp3b}7jU;K+A{mhE@s$s0 z^J6gZwv3n^Qsr|!3qA>(8jft-Y^E1D(V6|)%tw4DKN(mPsGdsRzmZ5cm*JKCkr`r( z@>R#xC9RVG$aqdma|xC0@v&PfxA*HnR;xuz+0C&n8>8U0e>TZnX6RE2D=&#F-FXgCoZ>Dz)$^Y`)EPx0i;(JaCH`0GeCsi73DM7=Q6oE`QN}oIn+tGuQ;3No^#j1j2X&`XI~ng*4qL__9aO; z-#cw}Yy$bSrA%Plx;x6Y44dfz^s6FWrAtB8xMt3|;@?eNUy>;>kv$y@3pXoj%NQ<9SA zQr<`TO*dBS5?+~$vE*C7c8;n+MSWfauaHoQ*Asab8I4{~;Rb|nlSRq0J&8`#kHd=Q z?LEnkaz*e%5Q!*rjx18x>CrK1RR5b%l;@#5eK9?;G6e0P91tR`0aQ)ZUHNTC-$!lw zE)c$mPp-LByuGPI*a2PO`t5;cr#^1Z;2yAP57n>JWdxb0uBL4T9@}t*)jLK10z!Bx zXAU%D?K4HK>Gv}4>WEeCn@sK0*&OeGpX)7yYj^rM(Q8roYF_aFN7Zu8}6nJ_w^Am~~iXSu)9 zBr(ryg_Ypu^*7;Lxi9B8HQ0)!Y;P`4L7f)lGqzNCwJP#cJGHy_wFf{M!W_d@d3hgP zWZu#TB;2=}jEK|RRf_4!C)ueUO7(Tdoma+7tf?+$EsqpiiU<&9lbmAOczUlmIQry44*j|+>WjE~q1fXy8= z2v6WUnB9a$Cp*^t>ai*IwUP<~*T=Xg;YVQO5hSAYqxy0EL_mMIq6%8^u@VQ-p16xZ zH8q~v6MDpfzjBZF;d|gEPqLPoxy#s^WCQDh5td9?a}husg(gjfvhaPeP@1jDLcLqT z1LQ`!aY_KZq@$zkMz^c=h*9%MZR#Hz_=Br(={vlT^+Xj&5i!YEofvX9r_BNA9Y*B) zHuJ2)vVAXra;FXDPv6;HSktjdldI;z&GY8n<=CMkjBj^0L4q_O%OPP5?T_#^a+{-+ zf5zd;J)srfjXD?2<=SngLm^coFF?>$)}67{8w%q!6-l~m1)qc&Ns7K0S$uE=ZBPb? zJ~M-#xhnmln$^^>MJ?(r7fuI+QF)fQvSu917~Wg8Qqflk*KEj~g)Vw0~G*( z=+6Hn5&mD9Ogl1h(7XLdAndXsQh)j@5Kd0NMAha;gq5p56ypeOU%iDgW+E;GJaeo6 zgOtQBh`0`5rn$CmdNuYI^cD9r>cf6BmU}2UeeTI-146-dXB1>S$M5X?R8`*IQBD^P zh7;Q2I(K-^2{<9tv8w}q%N?}L-3C|ShOMzc5x0wx{|7F=rO&Km*{s(cho3#<&;v;j zXSzTiV89NgmpG*2)*4|d08wk(A6~R8(Iab98W_it6BDd~-S2Q+R_}CXm(kCjJvUm9 zG4PPn?>X{dA+<{pL$6s0*s+;Q$+^BD--DZBv7*L!bG5o%_{d!pk<}qN^ZUWWjG{>gBIqM(V(^nxN9$ zGsJot52>fa?2E(fTcWTi<x(C$0nec8acUL~Uag!3l$oxEJ1`!keh*_8jIX|(?O(QH32vOp9 zals7_d3(01gb`s7wb8>VDLqtNcy)11h8g%(KAFW(il}XQSpiRDte2BI&%;y~xbV*0 z`1jx@i|b^ud1gwu+3`ln@*Kq`*xVF1U3Ec$~BPcc?S`o7X#VR^A9^vgcJclgwTXL(SvENCP<9rArQxdm1x6Q zK=I!+Mg!2g7=3GK!>m@dmE=J4{qQx77P{zmpF6M9X>A@iH8rTBleHE%Pd=Gu!v>KB7>u!M_3*kZJrSXiQGC!(hvWgKdLLm(k_WcS-l z;0ttluDi?p?z@al0Zk}!!9OqV67kR(omS*piJPh_0wlzq)GLLhwkU#F~7ksvsBCuA6A%-XkFW<(D z3Xv@NYmKbj`2jPMk}zSH0Tr|_w)R9F(NMupK8-A%zIRE15Ya$K!GvQ(`6uP9lJT#n zxply^@>SnOJHID@4M85C9Zw`cE;Na;09^N`KnIKs;{T!T8-qLvf<4E!wPRa5wr$(C zZQI^4c04<_ZQHi3|IK^%?mpZ_+=sik?&$8!>WZ$e>d30Dtju4wQV**+dve;*P!AYe ziOg~07mklLD_Q-8pXy4fu^g~d4uF8Oo>397O)MN5)n*n2PNHH~*h!*-Nsvhlgh-Q7 z3|QA0^H9r939Cerr^KFdl9)4%7+8uQS`rmw($u+;7!nbN;FuN|#*W|s#WN>7fXjez zvD`oAG7Nx6uu>)~?UnFq)ne7yAbcw9mB48=`VaEAupt$%IgOW`vRBI3YBR*m@m9&vPTDeb6kg-GZfWe*|h+V{RLA--m%m&3< zKCC_t7<(W=6p(eM-7V6#Fs>j6p15GJgKBw3;ta+}LnmkMKX4R3!Qk!wL4flIj@j^J z$|iNd%icT(Su)DhtuLX`Pk~{}w!JO|jGcZ_~OmfR>o`>i-C-iq9^Ja@gE43G1^KUi6<>mtw15Vz}WvU_R0 z!(kjm50P+O<@j4J6~){3VWm6dnaqW-K;%en;P$yABjwIg>p)vG*534Yck0rsn%aLb z@=pwBJ`TW=zbTDJPT)%}t??f&oZLj`b zfl$)jc9efc;pAalqRzi+D6GSKzxT9`rPby)JgkX9cT+nFeD_@Wz} zNi}t~|EsC|yW;Nx$e#)e6}4Jg1LlMC6qTA;{~9tC9Q+w2 z-nX~vYxFtu)iz}t-?%A*DPG`WBe}i~S@f9K7@w_8kq+DoQh!{C)>5`17uoNTxx~0Q z7nebRRa27~Xs&D_M<8X+j2PBUqqkVFY|S5wY#>>jzemqyk!=p8$Xur`6#K;0Uq_}2PBNPecwhCR>U`I`!|1tB6n6|GZpZ=rg zm(gwh62}GzsJ8vBo$)MwN?NC!N_kQe(A7F635s@Ja#X@DO`B55kY=6?rZuylYxufe zmnY1jXmQqhaTM6!+BxXvj|u3^0z}6uXqstsW#dUL>{lyJ+=NlK!=?aTbZF#tB<`Tk zeI`?m?tZ1m6vmNwo=oxW_^X>Ry2{>>58Kv|ZKoJu>lu)e>9Wd$vgi0QO|N59^4QuY2)CO~ z!Dsf}OcShu^a;8+f@0&tt_sJZXjXz*FCZFc?;eNlJ3fRr>ed;u<_7;Ptd}<&#o!Q3 z`P_BjlBcmSU$Q;K!m(+VvBH~OP|a-z&B%QdX#qIBESZx-{g|uU9<}_x1!maPVzO>tqEz?Wl zC??V_gk{1oN}l~ri#)yo&acg3qa9m2tlK6{?T?AdYiNAHA3o1zR@sHB>R(S=%5eW) z4m&I>CvYBrHW|UNZ0WT*=rn@Znt4zy?Ws%DaFOW`prePkBMo2)^OP0lCz&jt>plXiGsFqTJ z>Z13du*gTrMwQI)HUaT{6u-vhy!$0KY-iTW~3rViC5I z%d5g~aG5XQaVOp^P^M2p494LkJ5$NefoLek=YY4f={JLCbKImuNMYar)49l%u?G(5 zG|+YLA&m22Tlt!^Fir-Jo?|kNr`U@ml{$zZwL4z0lAJ}5=%$Tn5Tcs)pql1Wqq2Y` z)t5S$?e*Fw5t>LY`eN`Ej838n+i9@N?%uWB@TK|=(wW=N>E@wScR>=+$2gKYw~=01 z)3}hlI?t*+y-KTT)g?`JmtOhFLo&cThrjgNlZ11^6Nq884YfrXUc${p{k~Lvg6F&kpRdgf+(jwN($x(L+m;B8q?d60==uFkuxwmkosi3o3wJmQwDC2opWF4b`OafPk-(ufj3I71_PHY zcr*f8tUAk(lnZS+tq3y1S6q={pj{mk71laRWrdorXw#f0OdCARX1`}VI~A;KHFhHx zWNIH5^idbL3r6}Xs_`tQnKU{2mumSY8?+%k)ELzYqnpCdgv+m1U_KwmUo!S14`-MT+}Pv~ zl#IJv5g-|Z8x9z+4P%$%0froZb|!b(VkpK)bNZSHP^0|&JbPeIARhH{{`8vGb#>AG z@j=fE%^erLi~8eyG{ft!`5Q7vpesnfeYefL{DiwJJzwbl$Hj;2{GglFhl)DqTT4wtBfry8%8v#gP|Itj%ON(-{`IGRl_ zxo5QsUA>|x(a!*yYe2@z%>ENHVV4`=RfYA@<8F2bH z(a{u`D#L}^KRK-^1W&2gRx97clfAccOn&J(D(|!sWm3fy#EONnL~^n^u0KMuz(2{$ zp-)Hayy}P*P!|a2i(`3~ZXMO%=1UMP3T*n7G6k<|JlO&s*l&z5z41vv00Q}%QX-FS z*w-C<`>zd38KW#Lx%k{J2lUVf?TkUB9f*NQ{@(^@5OqHs z*u5(bE9aAUrg)}d?{h~y`wlwuz5cg$h<^Zi|FnAmaq^kRG|Bk}zpEKa2q})cxse1P zSxI(8i7~(#WLj$%Z8j@Y<2}5buF3v9g}T~gcXJatj^Oz6;m9WNEAP!h)RIZ*5p8`p z+n$FXD!1+DY1_QAJp&u_cbj(NY-WRve|J)wq;mXa!MZy7t%(N4DSe8jgtulix-J>; z7?Ws|JXTbHYDDf>kKt%nS;Sx~iKn|ixXho)lg^Wj60b~dT@YZda43%-DY`kcPR#`_ zgINL;Z~x$ONToUWi*C6ra>*u>a8QC(6r&=~#=_Yl%TtqXU#e)Lbb4;}P zY+NX)N@qGLep4k2(q;UUmPK2)c9f=OUePQfPop%?G;Gj|jl?+vdv77ARC$@78vZDy zF{M5Ku1|`{yk!T*TDf6<>LAg}RkmOHskU{UQUg~yF;PUVNpkx6XAwbGg8Z_x9+L(g zrR)r7$b_)Uz>mUI89*H_UD7>=Cig|t-|e|x*0CSxV|V80GeOxZWShqMAirXsl;L;0 zQ>6DHe9<)7-HBMSGOqS|K|=V5dr?)AvUF3DQbAoT{_F8?@OPxEf?3PPO@6RbGn+5i zuSS83&oHl2g{DvI)1)umCN*~sETZaW_aVo*#!0pzHMBq{oyTmQLtW7!sA}LWVgY|N z(OclxV|M-wEjz-7BZzvrYl!-|avGASe5(}d05656=D^9ZOTvZ)GOBffV+F(n<<8Ja zs#W3R2w9VL1O~Ux?wREd+Oidy?!wEC?=F|7&yjSi6RB$*scV&~YuT#FZmZip;+ou- z4R#lok9yp64~1JLx|sgrk2%9d^oJYHl@0Nu_+vAlNeh}MIB;c0cYdpz0rn*x^SnIk z57lTZeB8tL88%yq1u8b4f9t;fDNuLel4;7}(XhnD#}$`X?E&}VJ#3r~iqhy+rdBRjN4My!Vo7kvIQ!hUsyUf6}tCKlabDzTQXo-6PfBCxLC(yjYP$j^ERFVlk4y(|e>1D?*$A zUFXKZBb9vB9NO-r>No)g!wC|5ne0;^lBXe~id7#NG-0_*b5D+?y5dBuFsS`LFX{PU z_kFgr6#pG|xwnᚊ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 z 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

    oLzev}G|`L6E$W3RQaFe}co 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

    >+*2<3SKbW~ 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 bmv Date: Tue, 28 Jan 2025 16:13:52 +0000 Subject: [PATCH 183/397] cmd/go: refine GOAUTH user parsing to be more strict This CL enhances the parsing of GOAUTH user based authentication for improved security. Updates: #26232 Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest,gotip-windows-amd64-longtest Change-Id: Ica57952924020b7bd2670610af8de8ce52dbe92f Reviewed-on: https://go-review.googlesource.com/c/go/+/644995 Auto-Submit: Sam Thanawalla Reviewed-by: Damien Neil LUCI-TryBot-Result: Go LUCI --- src/cmd/go/alldocs.go | 3 +- src/cmd/go/internal/auth/httputils.go | 173 ++++++++++++++++++++++ src/cmd/go/internal/auth/userauth.go | 91 +++++------- src/cmd/go/internal/auth/userauth_test.go | 56 ++++++- src/cmd/go/internal/help/helpdoc.go | 3 +- 5 files changed, 266 insertions(+), 60 deletions(-) create mode 100644 src/cmd/go/internal/auth/httputils.go diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index 830bac2b2f8965..2220863b8edce4 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -2632,8 +2632,7 @@ // Content-Type: text/plain; charset=utf-8 // Date: Thu, 07 Nov 2024 18:43:09 GMT // -// Note: at least for HTTP 1.1, the contents written to stdin can be parsed -// as an HTTP response. +// Note: it is safe to use net/http.ReadResponse to parse this input. // // Before the first HTTPS fetch, the go command will invoke each GOAUTH // command in the list with no additional arguments and no input. diff --git a/src/cmd/go/internal/auth/httputils.go b/src/cmd/go/internal/auth/httputils.go new file mode 100644 index 00000000000000..b8629546d5bf3e --- /dev/null +++ b/src/cmd/go/internal/auth/httputils.go @@ -0,0 +1,173 @@ +// Copyright 2019 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. + +// Code copied from x/net/http/httpguts/httplex.go +package auth + +var isTokenTable = [256]bool{ + '!': true, + '#': true, + '$': true, + '%': true, + '&': true, + '\'': true, + '*': true, + '+': true, + '-': true, + '.': true, + '0': true, + '1': true, + '2': true, + '3': true, + '4': true, + '5': true, + '6': true, + '7': true, + '8': true, + '9': true, + 'A': true, + 'B': true, + 'C': true, + 'D': true, + 'E': true, + 'F': true, + 'G': true, + 'H': true, + 'I': true, + 'J': true, + 'K': true, + 'L': true, + 'M': true, + 'N': true, + 'O': true, + 'P': true, + 'Q': true, + 'R': true, + 'S': true, + 'T': true, + 'U': true, + 'W': true, + 'V': true, + 'X': true, + 'Y': true, + 'Z': true, + '^': true, + '_': true, + '`': true, + 'a': true, + 'b': true, + 'c': true, + 'd': true, + 'e': true, + 'f': true, + 'g': true, + 'h': true, + 'i': true, + 'j': true, + 'k': true, + 'l': true, + 'm': true, + 'n': true, + 'o': true, + 'p': true, + 'q': true, + 'r': true, + 's': true, + 't': true, + 'u': true, + 'v': true, + 'w': true, + 'x': true, + 'y': true, + 'z': true, + '|': true, + '~': true, +} + +// isLWS reports whether b is linear white space, according +// to http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2 +// +// LWS = [CRLF] 1*( SP | HT ) +func isLWS(b byte) bool { return b == ' ' || b == '\t' } + +// isCTL reports whether b is a control byte, according +// to http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2 +// +// CTL = +func isCTL(b byte) bool { + const del = 0x7f // a CTL + return b < ' ' || b == del +} + +// validHeaderFieldName reports whether v is a valid HTTP/1.x header name. +// HTTP/2 imposes the additional restriction that uppercase ASCII +// letters are not allowed. +// +// RFC 7230 says: +// +// header-field = field-name ":" OWS field-value OWS +// field-name = token +// token = 1*tchar +// tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." / +// "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA +func validHeaderFieldName(v string) bool { + if len(v) == 0 { + return false + } + for i := 0; i < len(v); i++ { + if !isTokenTable[v[i]] { + return false + } + } + return true +} + +// validHeaderFieldValue reports whether v is a valid "field-value" according to +// http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 : +// +// message-header = field-name ":" [ field-value ] +// field-value = *( field-content | LWS ) +// field-content = +// +// http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2 : +// +// TEXT = +// LWS = [CRLF] 1*( SP | HT ) +// CTL = +// +// RFC 7230 says: +// +// field-value = *( field-content / obs-fold ) +// obj-fold = N/A to http2, and deprecated +// field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] +// field-vchar = VCHAR / obs-text +// obs-text = %x80-FF +// VCHAR = "any visible [USASCII] character" +// +// http2 further says: "Similarly, HTTP/2 allows header field values +// that are not valid. While most of the values that can be encoded +// will not alter header field parsing, carriage return (CR, ASCII +// 0xd), line feed (LF, ASCII 0xa), and the zero character (NUL, ASCII +// 0x0) might be exploited by an attacker if they are translated +// verbatim. Any request or response that contains a character not +// permitted in a header field value MUST be treated as malformed +// (Section 8.1.2.6). Valid characters are defined by the +// field-content ABNF rule in Section 3.2 of [RFC7230]." +// +// This function does not (yet?) properly handle the rejection of +// strings that begin or end with SP or HTAB. +func validHeaderFieldValue(v string) bool { + for i := 0; i < len(v); i++ { + b := v[i] + if isCTL(b) && !isLWS(b) { + return false + } + } + return true +} diff --git a/src/cmd/go/internal/auth/userauth.go b/src/cmd/go/internal/auth/userauth.go index 0e54a83e318731..1a60693a9cd940 100644 --- a/src/cmd/go/internal/auth/userauth.go +++ b/src/cmd/go/internal/auth/userauth.go @@ -6,14 +6,11 @@ package auth import ( - "bufio" - "bytes" "cmd/internal/quoted" "fmt" - "io" "maps" "net/http" - "net/textproto" + "net/url" "os/exec" "strings" ) @@ -42,7 +39,7 @@ func runAuthCommand(command string, url string, res *http.Response) (map[string] if err != nil { return nil, fmt.Errorf("could not run command %s: %v\n%s", command, err, cmd.Stderr) } - credentials, err := parseUserAuth(bytes.NewReader(out)) + credentials, err := parseUserAuth(string(out)) if err != nil { return nil, fmt.Errorf("cannot parse output of GOAUTH command %s: %v", command, err) } @@ -54,53 +51,47 @@ func runAuthCommand(command string, url string, res *http.Response) (map[string] // or an error if the data does not follow the expected format. // Returns an nil error and an empty map if the data is empty. // See the expected format in 'go help goauth'. -func parseUserAuth(data io.Reader) (map[string]http.Header, error) { +func parseUserAuth(data string) (map[string]http.Header, error) { credentials := make(map[string]http.Header) - reader := textproto.NewReader(bufio.NewReader(data)) - for { - // Return the processed credentials if the reader is at EOF. - if _, err := reader.R.Peek(1); err == io.EOF { - return credentials, nil + for data != "" { + var line string + var ok bool + var urls []string + // Parse URLS first. + for { + line, data, ok = strings.Cut(data, "\n") + if !ok { + return nil, fmt.Errorf("invalid format: missing empty line after URLs") + } + if line == "" { + break + } + u, err := url.ParseRequestURI(line) + if err != nil { + return nil, fmt.Errorf("could not parse URL %s: %v", line, err) + } + urls = append(urls, u.String()) } - urls, err := readURLs(reader) - if err != nil { - return nil, err - } - if len(urls) == 0 { - return nil, fmt.Errorf("invalid format: expected url prefix") - } - mimeHeader, err := reader.ReadMIMEHeader() - if err != nil { - return nil, err - } - header := http.Header(mimeHeader) - // Process the block (urls and headers). - credentialMap := mapHeadersToPrefixes(urls, header) - maps.Copy(credentials, credentialMap) - } -} - -// readURLs reads URL prefixes from the given reader until an empty line -// is encountered or an error occurs. It returns the list of URLs or an error -// if the format is invalid. -func readURLs(reader *textproto.Reader) (urls []string, err error) { - for { - line, err := reader.ReadLine() - if err != nil { - return nil, err - } - trimmedLine := strings.TrimSpace(line) - if trimmedLine != line { - return nil, fmt.Errorf("invalid format: leading or trailing white space") - } - if strings.HasPrefix(line, "https://") { - urls = append(urls, line) - } else if line == "" { - return urls, nil - } else { - return nil, fmt.Errorf("invalid format: expected url prefix or empty line") + // Parse Headers second. + header := make(http.Header) + for { + line, data, ok = strings.Cut(data, "\n") + if !ok { + return nil, fmt.Errorf("invalid format: missing empty line after headers") + } + if line == "" { + break + } + name, value, ok := strings.Cut(line, ": ") + value = strings.TrimSpace(value) + if !ok || !validHeaderFieldName(name) || !validHeaderFieldValue(value) { + return nil, fmt.Errorf("invalid format: invalid header line") + } + header.Add(name, value) } + maps.Copy(credentials, mapHeadersToPrefixes(urls, header)) } + return credentials, nil } // mapHeadersToPrefixes returns a mapping of prefix → http.Header without @@ -127,8 +118,8 @@ func buildCommand(command string) (*exec.Cmd, error) { func writeResponseToStdin(cmd *exec.Cmd, res *http.Response) error { var output strings.Builder output.WriteString(res.Proto + " " + res.Status + "\n") - if err := res.Header.Write(&output); err != nil { - return err + for k, v := range res.Header { + output.WriteString(k + ": " + strings.Join(v, ", ") + "\n") } output.WriteString("\n") cmd.Stdin = strings.NewReader(output.String()) diff --git a/src/cmd/go/internal/auth/userauth_test.go b/src/cmd/go/internal/auth/userauth_test.go index 91a5bb76ecd3bc..1b281ed3cdef45 100644 --- a/src/cmd/go/internal/auth/userauth_test.go +++ b/src/cmd/go/internal/auth/userauth_test.go @@ -7,7 +7,6 @@ package auth import ( "net/http" "reflect" - "strings" "testing" ) @@ -40,7 +39,7 @@ Data: Test567 "Test567", }, } - credentials, err := parseUserAuth(strings.NewReader(data)) + credentials, err := parseUserAuth(data) if err != nil { t.Errorf("parseUserAuth(%s): %v", data, err) } @@ -100,10 +99,55 @@ Authorization: Basic GVuc2VzYW1lYWxhZGRpbjpvc Authorization: Basic 1lYWxhZGRplW1lYWxhZGRpbs Data: Test567 +`, + // Continuation in URL line + `https://example.com/ + Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l +`, + + // Continuation in header line + `https://example.com + +Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l + Authorization: Basic jpvcGVuc2VzYW1lYWxhZGRpb +`, + + // Continuation in multiple header lines + `https://example.com + +Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l + Authorization: Basic jpvcGVuc2VzYW1lYWxhZGRpb + Authorization: Basic dGhpc2lzYWxvbmdzdHJpbmc= +`, + + // Continuation with mixed spacing + `https://example.com + +Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l + Authorization: Basic jpvcGVuc2VzYW1lYWxhZGRpb +`, + + // Continuation with tab character + `https://example.com + +Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l + Authorization: Basic jpvcGVuc2VzYW1lYWxhZGRpb +`, + // Continuation at the start of a block + ` https://example.com + +Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l +`, + + // Continuation after a blank line + `https://example.com + + +Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l `, } for _, tc := range testCases { - if credentials, err := parseUserAuth(strings.NewReader(tc)); err == nil { + if credentials, err := parseUserAuth(tc); err == nil { t.Errorf("parseUserAuth(%s) should have failed, but got: %v", tc, credentials) } } @@ -132,7 +176,7 @@ Data: Test567 "Test567", }, } - credentials, err := parseUserAuth(strings.NewReader(data)) + credentials, err := parseUserAuth(data) if err != nil { t.Errorf("parseUserAuth(%s): %v", data, err) } @@ -146,7 +190,7 @@ func TestParseUserAuthEmptyHeader(t *testing.T) { data := "https://example.com\n\n\n" // Build the expected header header := http.Header{} - credentials, err := parseUserAuth(strings.NewReader(data)) + credentials, err := parseUserAuth(data) if err != nil { t.Errorf("parseUserAuth(%s): %v", data, err) } @@ -159,7 +203,7 @@ func TestParseUserAuthEmptyHeader(t *testing.T) { func TestParseUserAuthEmpty(t *testing.T) { data := `` // Build the expected header - credentials, err := parseUserAuth(strings.NewReader(data)) + credentials, err := parseUserAuth(data) if err != nil { t.Errorf("parseUserAuth(%s) should have succeeded", data) } diff --git a/src/cmd/go/internal/help/helpdoc.go b/src/cmd/go/internal/help/helpdoc.go index 23459ef15413e3..ccc04c25d27d7e 100644 --- a/src/cmd/go/internal/help/helpdoc.go +++ b/src/cmd/go/internal/help/helpdoc.go @@ -1050,8 +1050,7 @@ command Content-Type: text/plain; charset=utf-8 Date: Thu, 07 Nov 2024 18:43:09 GMT - Note: at least for HTTP 1.1, the contents written to stdin can be parsed - as an HTTP response. + Note: it is safe to use net/http.ReadResponse to parse this input. Before the first HTTPS fetch, the go command will invoke each GOAUTH command in the list with no additional arguments and no input. From 77d20838e9cc3ad4f9c167db245752569d7ffc48 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Fri, 31 Jan 2025 15:06:15 +0000 Subject: [PATCH 184/397] cmd: update golang.org/x/tools to CL 645697, and revendor go get golang.org/x/tools@9874647 # CL 645697 go mod tidy go mod vendor Fixes #71485 Change-Id: I72d8f82abd0c6e05f2698d8a372bf9485002d1b3 Reviewed-on: https://go-review.googlesource.com/c/go/+/645336 Reviewed-by: Carlos Amedee Auto-Submit: Robert Findley TryBot-Bypass: Robert Findley --- src/cmd/go.mod | 2 +- src/cmd/go.sum | 4 +- .../tools/go/analysis/passes/printf/printf.go | 48 +++++++++++++------ src/cmd/vendor/modules.txt | 2 +- 4 files changed, 38 insertions(+), 18 deletions(-) diff --git a/src/cmd/go.mod b/src/cmd/go.mod index b29321de7b4244..9c29c3ac74d197 100644 --- a/src/cmd/go.mod +++ b/src/cmd/go.mod @@ -11,7 +11,7 @@ require ( golang.org/x/sys v0.28.0 golang.org/x/telemetry v0.0.0-20241204182053-c0ac0e154df3 golang.org/x/term v0.27.0 - golang.org/x/tools v0.28.0 + golang.org/x/tools v0.28.1-0.20250131145412-98746475647e ) require ( diff --git a/src/cmd/go.sum b/src/cmd/go.sum index 5c262454d5b653..593063a9daa351 100644 --- a/src/cmd/go.sum +++ b/src/cmd/go.sum @@ -22,7 +22,7 @@ golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8= -golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw= +golang.org/x/tools v0.28.1-0.20250131145412-98746475647e h1:6Kzwg7JxW2HRWToKpIKqlpF8l8XMasoALX3OcAMdgL8= +golang.org/x/tools v0.28.1-0.20250131145412-98746475647e/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw= rsc.io/markdown v0.0.0-20240306144322-0bf8f97ee8ef h1:mqLYrXCXYEZOop9/Dbo6RPX11539nwiCNBb1icVPmw8= rsc.io/markdown v0.0.0-20240306144322-0bf8f97ee8ef/go.mod h1:8xcPgWmwlZONN1D9bjxtHEjrUtSEa3fakVF8iaewYKQ= diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go index 171ad2013722c4..011ea8bef62925 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go @@ -25,6 +25,7 @@ import ( "golang.org/x/tools/go/ast/inspector" "golang.org/x/tools/go/types/typeutil" "golang.org/x/tools/internal/typeparams" + "golang.org/x/tools/internal/versions" ) func init() { @@ -108,12 +109,12 @@ func (f *isWrapper) String() string { } } -func run(pass *analysis.Pass) (interface{}, error) { +func run(pass *analysis.Pass) (any, error) { res := &Result{ funcs: make(map[*types.Func]Kind), } findPrintfLike(pass, res) - checkCall(pass) + checkCalls(pass) return res, nil } @@ -182,7 +183,7 @@ func maybePrintfWrapper(info *types.Info, decl ast.Decl) *printfWrapper { } // findPrintfLike scans the entire package to find printf-like functions. -func findPrintfLike(pass *analysis.Pass, res *Result) (interface{}, error) { +func findPrintfLike(pass *analysis.Pass, res *Result) (any, error) { // Gather potential wrappers and call graph between them. byObj := make(map[*types.Func]*printfWrapper) var wrappers []*printfWrapper @@ -409,20 +410,29 @@ func stringConstantExpr(pass *analysis.Pass, expr ast.Expr) (string, bool) { return "", false } -// checkCall triggers the print-specific checks if the call invokes a print function. -func checkCall(pass *analysis.Pass) { +// checkCalls triggers the print-specific checks for calls that invoke a print +// function. +func checkCalls(pass *analysis.Pass) { inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) nodeFilter := []ast.Node{ + (*ast.File)(nil), (*ast.CallExpr)(nil), } + + var fileVersion string // for selectively suppressing checks; "" if unknown. inspect.Preorder(nodeFilter, func(n ast.Node) { - call := n.(*ast.CallExpr) - fn, kind := printfNameAndKind(pass, call) - switch kind { - case KindPrintf, KindErrorf: - checkPrintf(pass, kind, call, fn) - case KindPrint: - checkPrint(pass, call, fn) + switch n := n.(type) { + case *ast.File: + fileVersion = versions.Lang(versions.FileVersion(pass.TypesInfo, n)) + + case *ast.CallExpr: + fn, kind := printfNameAndKind(pass, n) + switch kind { + case KindPrintf, KindErrorf: + checkPrintf(pass, fileVersion, kind, n, fn) + case KindPrint: + checkPrint(pass, n, fn) + } } }) } @@ -503,7 +513,7 @@ type formatState struct { } // checkPrintf checks a call to a formatted print routine such as Printf. -func checkPrintf(pass *analysis.Pass, kind Kind, call *ast.CallExpr, fn *types.Func) { +func checkPrintf(pass *analysis.Pass, fileVersion string, kind Kind, call *ast.CallExpr, fn *types.Func) { idx := formatStringIndex(pass, call) if idx < 0 || idx >= len(call.Args) { return @@ -517,7 +527,17 @@ func checkPrintf(pass *analysis.Pass, kind Kind, call *ast.CallExpr, fn *types.F // non-constant format string and no arguments: // if msg contains "%", misformatting occurs. // Report the problem and suggest a fix: fmt.Printf("%s", msg). - if !suppressNonconstants && idx == len(call.Args)-1 { + // + // However, as described in golang/go#71485, this analysis can produce a + // significant number of diagnostics in existing code, and the bugs it + // finds are sometimes unlikely or inconsequential, and may not be worth + // fixing for some users. Gating on language version allows us to avoid + // breaking existing tests and CI scripts. + if !suppressNonconstants && + idx == len(call.Args)-1 && + fileVersion != "" && // fail open + versions.AtLeast(fileVersion, "go1.24") { + pass.Report(analysis.Diagnostic{ Pos: formatArg.Pos(), End: formatArg.End(), diff --git a/src/cmd/vendor/modules.txt b/src/cmd/vendor/modules.txt index 281989b1e2c5c2..118646d75c4ccb 100644 --- a/src/cmd/vendor/modules.txt +++ b/src/cmd/vendor/modules.txt @@ -73,7 +73,7 @@ golang.org/x/text/internal/tag golang.org/x/text/language golang.org/x/text/transform golang.org/x/text/unicode/norm -# golang.org/x/tools v0.28.0 +# golang.org/x/tools v0.28.1-0.20250131145412-98746475647e ## explicit; go 1.22.0 golang.org/x/tools/cmd/bisect golang.org/x/tools/cover From 37f27fbecd422da9fefb8ae1cc601bc5b4fec44b Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Sun, 17 Nov 2024 17:17:50 -0500 Subject: [PATCH 185/397] cmd/go: enable fips test and fix caching bug Enable the cmd/go fips test now that v1.0.0.zip has been checked in. Will still need to enable the alias half when the alias is checked in. Also fix a problem that was causing spurious failures, by fixing repeated unpackings and also disabling modindex reads of the virtual fips140 snapshot directories. Fixes #71491. Change-Id: I7fa21e9bde07ff4eb6c3483e99d49316ee0ea7f0 Reviewed-on: https://go-review.googlesource.com/c/go/+/645835 Reviewed-by: Michael Matloob Reviewed-by: Sam Thanawalla LUCI-TryBot-Result: Go LUCI --- src/cmd/go/internal/modfetch/cache.go | 7 +++++++ src/cmd/go/internal/modindex/read.go | 11 +++++++---- src/cmd/go/testdata/script/fipssnap.txt | 9 +++------ 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/cmd/go/internal/modfetch/cache.go b/src/cmd/go/internal/modfetch/cache.go index 02d3849314a75a..9c34581a910a4a 100644 --- a/src/cmd/go/internal/modfetch/cache.go +++ b/src/cmd/go/internal/modfetch/cache.go @@ -113,6 +113,13 @@ func DownloadDir(ctx context.Context, m module.Version) (string, error) { return dir, err } + // Special case: ziphash is not required for the golang.org/fips140 module, + // because it is unpacked from a file in GOROOT, not downloaded. + // We've already checked that it's not a partial unpacking, so we're happy. + if m.Path == "golang.org/fips140" { + return dir, nil + } + // Check if a .ziphash file exists. It should be created before the // zip is extracted, but if it was deleted (by another program?), we need // to re-calculate it. Note that checkMod will repopulate the ziphash diff --git a/src/cmd/go/internal/modindex/read.go b/src/cmd/go/internal/modindex/read.go index 4c1fbd835961f6..76216f35ba149f 100644 --- a/src/cmd/go/internal/modindex/read.go +++ b/src/cmd/go/internal/modindex/read.go @@ -33,10 +33,7 @@ import ( "cmd/internal/par" ) -// enabled is used to flag off the behavior of the module index on tip. -// It will be removed before the release. -// TODO(matloob): Remove enabled once we have more confidence on the -// module index. +// enabled is used to flag off the behavior of the module index on tip, for debugging. var enabled = godebug.New("#goindex").Value() != "0" // Module represents and encoded module index file. It is used to @@ -126,6 +123,7 @@ var ErrNotIndexed = errors.New("not in module index") var ( errDisabled = fmt.Errorf("%w: module indexing disabled", ErrNotIndexed) errNotFromModuleCache = fmt.Errorf("%w: not from module cache", ErrNotIndexed) + errFIPS140 = fmt.Errorf("%w: fips140 snapshots not indexed", ErrNotIndexed) ) // GetPackage returns the IndexPackage for the directory at the given path. @@ -143,6 +141,11 @@ func GetPackage(modroot, pkgdir string) (*IndexPackage, error) { if cfg.BuildContext.Compiler == "gccgo" && str.HasPathPrefix(modroot, cfg.GOROOTsrc) { return nil, err // gccgo has no sources for GOROOT packages. } + // The pkgdir for fips140 has been replaced in the fsys overlay, + // but the module index does not see that. Do not try to use the module index. + if strings.Contains(filepath.ToSlash(pkgdir), "internal/fips140/v") { + return nil, errFIPS140 + } return openIndexPackage(modroot, pkgdir) } diff --git a/src/cmd/go/testdata/script/fipssnap.txt b/src/cmd/go/testdata/script/fipssnap.txt index 465f304c46c126..9888bc82f11d81 100644 --- a/src/cmd/go/testdata/script/fipssnap.txt +++ b/src/cmd/go/testdata/script/fipssnap.txt @@ -1,10 +1,6 @@ -## Note: Need a snapshot in lib/fips140 to run this test. -## For local testing, can run 'cd lib/fips140; make v0.0.1.test' -## and then remove the skip. -env snap=v0.0.1 +env snap=v1.0.0 env alias=inprocess -skip 'no snapshots yet' env GOFIPS140=$snap # Go+BoringCrypto conflicts with GOFIPS140. @@ -27,7 +23,8 @@ stdout crypto/internal/fips140/$snap/sha256 ! stdout crypto/internal/fips140/check # again with GOFIPS140=$alias -env GOFIPS140=$alias +# TODO: enable when we add inprocess.txt +# env GOFIPS140=$alias # default GODEBUG includes fips140=on go list -f '{{.DefaultGODEBUG}}' From 9da530f11ac8331e9326290e42e9a39e7bd56d35 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Mon, 3 Feb 2025 09:59:25 -0500 Subject: [PATCH 186/397] internal/goversion: update Version to 1.25 Go 1.25 is in the process of being opened for development (to be eventually released). This change marks the very beginning of its development cycle, updating the Version value accordingly. For #40705. For #70525. Change-Id: If673d4aeddc376fefe6bddc3ec2704ca91245777 Reviewed-on: https://go-review.googlesource.com/c/go/+/646155 Reviewed-by: Carlos Amedee LUCI-TryBot-Result: Go LUCI --- src/internal/goversion/goversion.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/internal/goversion/goversion.go b/src/internal/goversion/goversion.go index de2bcf4c82eb33..18703a64eaa922 100644 --- a/src/internal/goversion/goversion.go +++ b/src/internal/goversion/goversion.go @@ -9,4 +9,4 @@ package goversion // // It should be updated at the start of each development cycle to be // the version of the next Go 1.x release. See go.dev/issue/40705. -const Version = 24 +const Version = 25 From e2f342fc51a70351205af839dff2749bc7a977e2 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Mon, 3 Feb 2025 10:25:05 -0500 Subject: [PATCH 187/397] doc: initialize next directory for Go 1.25 Following the "For the release team" steps in README: cd doc cp -R initial/ next $EDITOR next/1-intro.md For #70525 Change-Id: I31c271d95ccd72123f531fde4e72929ec7b310d9 Reviewed-on: https://go-review.googlesource.com/c/go/+/646195 Reviewed-by: Carlos Amedee LUCI-TryBot-Result: Go LUCI --- doc/next/1-intro.md | 8 ++++++++ doc/next/2-language.md | 3 +++ doc/next/3-tools.md | 6 ++++++ doc/next/4-runtime.md | 1 + doc/next/5-toolchain.md | 7 +++++++ doc/next/6-stdlib/0-heading.md | 2 ++ doc/next/6-stdlib/99-minor/0-heading.md | 3 +++ doc/next/6-stdlib/99-minor/README | 1 + doc/next/7-ports.md | 2 ++ 9 files changed, 33 insertions(+) create mode 100644 doc/next/1-intro.md create mode 100644 doc/next/2-language.md create mode 100644 doc/next/3-tools.md create mode 100644 doc/next/4-runtime.md create mode 100644 doc/next/5-toolchain.md create mode 100644 doc/next/6-stdlib/0-heading.md create mode 100644 doc/next/6-stdlib/99-minor/0-heading.md create mode 100644 doc/next/6-stdlib/99-minor/README create mode 100644 doc/next/7-ports.md diff --git a/doc/next/1-intro.md b/doc/next/1-intro.md new file mode 100644 index 00000000000000..77a9aed59f244c --- /dev/null +++ b/doc/next/1-intro.md @@ -0,0 +1,8 @@ + + +## DRAFT RELEASE NOTES — Introduction to Go 1.N {#introduction} + +**Go 1.25 is not yet released. These are work-in-progress release notes. +Go 1.25 is expected to be released in August 2025.** diff --git a/doc/next/2-language.md b/doc/next/2-language.md new file mode 100644 index 00000000000000..61030bd67606b0 --- /dev/null +++ b/doc/next/2-language.md @@ -0,0 +1,3 @@ +## Changes to the language {#language} + + diff --git a/doc/next/3-tools.md b/doc/next/3-tools.md new file mode 100644 index 00000000000000..5638f240a5b127 --- /dev/null +++ b/doc/next/3-tools.md @@ -0,0 +1,6 @@ +## Tools {#tools} + +### Go command {#go-command} + +### Cgo {#cgo} + diff --git a/doc/next/4-runtime.md b/doc/next/4-runtime.md new file mode 100644 index 00000000000000..1f8e445e0b10de --- /dev/null +++ b/doc/next/4-runtime.md @@ -0,0 +1 @@ +## Runtime {#runtime} diff --git a/doc/next/5-toolchain.md b/doc/next/5-toolchain.md new file mode 100644 index 00000000000000..0f4a816479754c --- /dev/null +++ b/doc/next/5-toolchain.md @@ -0,0 +1,7 @@ +## Compiler {#compiler} + +## Assembler {#assembler} + +## Linker {#linker} + + diff --git a/doc/next/6-stdlib/0-heading.md b/doc/next/6-stdlib/0-heading.md new file mode 100644 index 00000000000000..a992170d433326 --- /dev/null +++ b/doc/next/6-stdlib/0-heading.md @@ -0,0 +1,2 @@ +## Standard library {#library} + diff --git a/doc/next/6-stdlib/99-minor/0-heading.md b/doc/next/6-stdlib/99-minor/0-heading.md new file mode 100644 index 00000000000000..a98105e8ccba7f --- /dev/null +++ b/doc/next/6-stdlib/99-minor/0-heading.md @@ -0,0 +1,3 @@ +### Minor changes to the library {#minor_library_changes} + + diff --git a/doc/next/6-stdlib/99-minor/README b/doc/next/6-stdlib/99-minor/README new file mode 100644 index 00000000000000..fac778de050642 --- /dev/null +++ b/doc/next/6-stdlib/99-minor/README @@ -0,0 +1 @@ +API changes and other small changes to the standard library go here. diff --git a/doc/next/7-ports.md b/doc/next/7-ports.md new file mode 100644 index 00000000000000..8bea3f8fbc33f9 --- /dev/null +++ b/doc/next/7-ports.md @@ -0,0 +1,2 @@ +## Ports {#ports} + From e5ae12ab82e09539b77cfba3fa1c4c31f5b948db Mon Sep 17 00:00:00 2001 From: alirezaarzehgar Date: Tue, 21 Jan 2025 00:24:28 +0330 Subject: [PATCH 188/397] net/url: add panic to unhex for imposible error case Change-Id: I9f39b3d2a1a0a3e510afc874dd071302b2b0c89e Reviewed-on: https://go-review.googlesource.com/c/go/+/643555 Reviewed-by: Damien Neil LUCI-TryBot-Result: Go LUCI Reviewed-by: Ian Lance Taylor Auto-Submit: Ian Lance Taylor --- src/net/url/url.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/net/url/url.go b/src/net/url/url.go index 8a8de1c6a8bdb5..3acde9fb0f3334 100644 --- a/src/net/url/url.go +++ b/src/net/url/url.go @@ -67,8 +67,9 @@ func unhex(c byte) byte { return c - 'a' + 10 case 'A' <= c && c <= 'F': return c - 'A' + 10 + default: + panic("invalid hex character") } - return 0 } type encoding int From caedd0a8f754907300f4dfc5bd7e62213775a36b Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 30 Jan 2025 18:25:45 -0800 Subject: [PATCH 189/397] cmd/go/internal/auth: reduce to a single package coment Change-Id: I4c3cf840fe71dfa677732d445c24233e11110dd1 Reviewed-on: https://go-review.googlesource.com/c/go/+/645556 Reviewed-by: Sam Thanawalla Auto-Submit: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Reviewed-by: Damien Neil --- src/cmd/go/internal/auth/gitauth.go | 1 + src/cmd/go/internal/auth/httputils.go | 1 + src/cmd/go/internal/auth/userauth.go | 1 - 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cmd/go/internal/auth/gitauth.go b/src/cmd/go/internal/auth/gitauth.go index b28cb54453517c..29d2852814b450 100644 --- a/src/cmd/go/internal/auth/gitauth.go +++ b/src/cmd/go/internal/auth/gitauth.go @@ -6,6 +6,7 @@ // // See https://git-scm.com/docs/gitcredentials or run 'man gitcredentials' for // information on how to configure 'git credential'. + package auth import ( diff --git a/src/cmd/go/internal/auth/httputils.go b/src/cmd/go/internal/auth/httputils.go index b8629546d5bf3e..7f7bf03669ecad 100644 --- a/src/cmd/go/internal/auth/httputils.go +++ b/src/cmd/go/internal/auth/httputils.go @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. // Code copied from x/net/http/httpguts/httplex.go + package auth var isTokenTable = [256]bool{ diff --git a/src/cmd/go/internal/auth/userauth.go b/src/cmd/go/internal/auth/userauth.go index 1a60693a9cd940..2649a9c271dce3 100644 --- a/src/cmd/go/internal/auth/userauth.go +++ b/src/cmd/go/internal/auth/userauth.go @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package auth provides access to user-provided authentication credentials. package auth import ( From 5aa3d162d526af778c47695ec03b8c8b0ddd7843 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 30 Jan 2025 13:36:00 -0800 Subject: [PATCH 190/397] cmd/go/internal/modindex: correct isDir doc comment Change-Id: Ic7e272b14a24f78b9ef3ca8e0706775bc9f2a3f2 Reviewed-on: https://go-review.googlesource.com/c/go/+/645715 Reviewed-by: Michael Matloob LUCI-TryBot-Result: Go LUCI Reviewed-by: Ian Lance Taylor Auto-Submit: Ian Lance Taylor --- src/cmd/go/internal/modindex/build.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/go/internal/modindex/build.go b/src/cmd/go/internal/modindex/build.go index b4dacb0f523a8d..542d6fbbbba390 100644 --- a/src/cmd/go/internal/modindex/build.go +++ b/src/cmd/go/internal/modindex/build.go @@ -133,7 +133,7 @@ func (ctxt *Context) isAbsPath(path string) bool { return filepath.IsAbs(path) } -// isDir calls ctxt.IsDir (if not nil) or else uses fsys.Stat. +// isDir reports whether path is a directory. func isDir(path string) bool { fi, err := fsys.Stat(path) return err == nil && fi.IsDir() From 4f11d5879a01e64cb8bd59911bb205ffedd4f265 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 31 Jan 2025 12:39:19 -0800 Subject: [PATCH 191/397] crypto/internal/cryptotest: print stderr if go tool fails Trying to find out why "go env GOMODCACHE" is failing on the Windows longtest builder. For #71508 Change-Id: I0642d5a5d85a549c6edde0be5bed8f0a16cca200 Cq-Include-Trybots: luci.golang.try:gotip-windows-amd64-longtest Reviewed-on: https://go-review.googlesource.com/c/go/+/645895 Reviewed-by: Roland Shoemaker Auto-Submit: Ian Lance Taylor Reviewed-by: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI --- src/crypto/internal/cryptotest/fetchmodule.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/crypto/internal/cryptotest/fetchmodule.go b/src/crypto/internal/cryptotest/fetchmodule.go index 740b17b00156e0..37f2a094972b9d 100644 --- a/src/crypto/internal/cryptotest/fetchmodule.go +++ b/src/crypto/internal/cryptotest/fetchmodule.go @@ -9,6 +9,7 @@ import ( "encoding/json" "internal/testenv" "os" + "os/exec" "testing" ) @@ -23,7 +24,11 @@ func FetchModule(t *testing.T, module, version string) string { // instead. (For example, run.bash sets GOPATH=/nonexist-gopath.) out, err := testenv.Command(t, goTool, "env", "GOMODCACHE").Output() if err != nil { - t.Fatalf("%s env GOMODCACHE: %v\n%s", goTool, err, out) + t.Errorf("%s env GOMODCACHE: %v\n%s", goTool, err, out) + if ee, ok := err.(*exec.ExitError); ok { + t.Logf("%s", ee.Stderr) + } + t.FailNow() } modcacheOk := false if gomodcache := string(bytes.TrimSpace(out)); gomodcache != "" { From b25b5f3ff4e671aa4f5897c788137fe91f62cf57 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Tue, 27 Aug 2024 21:02:02 +0000 Subject: [PATCH 192/397] runtime: fix GODEBUG=gccheckmark=1 and add smoke test This change fixes GODEBUG=gccheckmark=1 which seems to have bit-rotted. Because the root jobs weren't being reset, it wasn't doing anything. Then, it turned out that checkmark mode would queue up noscan objects in workbufs, which caused it to fail. Then it turned out checkmark mode was broken with user arenas, since their heap arenas are not registered anywhere. Then, it turned out that checkmark mode could just not run properly if the goroutine's preemption flag was set (since sched.gcwaiting is true during the STW). And lastly, it turned out that async preemption could cause erroneous checkmark failures. This change fixes all these issues and adds a simple smoke test to dist to run the runtime tests under gccheckmark, which exercises all of these issues. Fixes #69074. Fixes #69377. Fixes #69376. Change-Id: Iaa0bb7b9e63ed4ba34d222b47510d6292ce168bc Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest Reviewed-on: https://go-review.googlesource.com/c/go/+/608915 LUCI-TryBot-Result: Go LUCI Auto-Submit: Michael Knyszek Reviewed-by: Carlos Amedee --- src/cmd/dist/test.go | 12 +++++++++-- src/runtime/arena.go | 2 +- src/runtime/malloc.go | 45 ++++++++++++++++++--------------------- src/runtime/mcheckmark.go | 18 +++++++++++++--- src/runtime/mgc.go | 13 +++++++++-- src/runtime/mgcmark.go | 16 +++++++------- src/runtime/mheap.go | 27 +++++++++++++++-------- src/runtime/runtime1.go | 17 +++++++++++++++ 8 files changed, 101 insertions(+), 49 deletions(-) diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index 0c992118f4287b..58e87f16c05024 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -752,8 +752,8 @@ func (t *tester) registerTests() { }) } - // GODEBUG=gcstoptheworld=2 tests. We only run these in long-test - // mode (with GO_TEST_SHORT=0) because this is just testing a + // GC debug mode tests. We only run these in long-test mode + // (with GO_TEST_SHORT=0) because this is just testing a // non-critical debug setting. if !t.compileOnly && !t.short { t.registerTest("GODEBUG=gcstoptheworld=2 archive/zip", @@ -764,6 +764,14 @@ func (t *tester) registerTests() { env: []string{"GODEBUG=gcstoptheworld=2"}, pkg: "archive/zip", }) + t.registerTest("GODEBUG=gccheckmark=1 runtime", + &goTest{ + variant: "runtime:gcstoptheworld2", + timeout: 300 * time.Second, + short: true, + env: []string{"GODEBUG=gccheckmark=1"}, + pkg: "runtime", + }) } // morestack tests. We only run these in long-test mode diff --git a/src/runtime/arena.go b/src/runtime/arena.go index 0ffc74e8720550..34821491d54d4c 100644 --- a/src/runtime/arena.go +++ b/src/runtime/arena.go @@ -1008,7 +1008,7 @@ func (h *mheap) allocUserArenaChunk() *mspan { // is mapped contiguously. hintList = &h.arenaHints } - v, size := h.sysAlloc(userArenaChunkBytes, hintList, false) + v, size := h.sysAlloc(userArenaChunkBytes, hintList, &mheap_.userArenaArenas) if size%userArenaChunkBytes != 0 { throw("sysAlloc size is not divisible by userArenaChunkBytes") } diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index 73d663f7f59e67..60ea2f5188019c 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -640,14 +640,13 @@ func mallocinit() { // hintList is a list of hint addresses for where to allocate new // heap arenas. It must be non-nil. // -// register indicates whether the heap arena should be registered -// in allArenas. -// // sysAlloc returns a memory region in the Reserved state. This region must // be transitioned to Prepared and then Ready before use. // +// arenaList is the list the arena should be added to. +// // h must be locked. -func (h *mheap) sysAlloc(n uintptr, hintList **arenaHint, register bool) (v unsafe.Pointer, size uintptr) { +func (h *mheap) sysAlloc(n uintptr, hintList **arenaHint, arenaList *[]arenaIdx) (v unsafe.Pointer, size uintptr) { assertLockHeld(&h.lock) n = alignUp(n, heapArenaBytes) @@ -790,27 +789,25 @@ mapped: } // Register the arena in allArenas if requested. - if register { - if len(h.allArenas) == cap(h.allArenas) { - size := 2 * uintptr(cap(h.allArenas)) * goarch.PtrSize - if size == 0 { - size = physPageSize - } - newArray := (*notInHeap)(persistentalloc(size, goarch.PtrSize, &memstats.gcMiscSys)) - if newArray == nil { - throw("out of memory allocating allArenas") - } - oldSlice := h.allArenas - *(*notInHeapSlice)(unsafe.Pointer(&h.allArenas)) = notInHeapSlice{newArray, len(h.allArenas), int(size / goarch.PtrSize)} - copy(h.allArenas, oldSlice) - // Do not free the old backing array because - // there may be concurrent readers. Since we - // double the array each time, this can lead - // to at most 2x waste. + if len((*arenaList)) == cap((*arenaList)) { + size := 2 * uintptr(cap((*arenaList))) * goarch.PtrSize + if size == 0 { + size = physPageSize } - h.allArenas = h.allArenas[:len(h.allArenas)+1] - h.allArenas[len(h.allArenas)-1] = ri - } + newArray := (*notInHeap)(persistentalloc(size, goarch.PtrSize, &memstats.gcMiscSys)) + if newArray == nil { + throw("out of memory allocating allArenas") + } + oldSlice := (*arenaList) + *(*notInHeapSlice)(unsafe.Pointer(&(*arenaList))) = notInHeapSlice{newArray, len((*arenaList)), int(size / goarch.PtrSize)} + copy((*arenaList), oldSlice) + // Do not free the old backing array because + // there may be concurrent readers. Since we + // double the array each time, this can lead + // to at most 2x waste. + } + (*arenaList) = (*arenaList)[:len((*arenaList))+1] + (*arenaList)[len((*arenaList))-1] = ri // Store atomically just in case an object from the // new heap arena becomes visible before the heap lock diff --git a/src/runtime/mcheckmark.go b/src/runtime/mcheckmark.go index f5560cf50f1fdc..03d769e7d3e901 100644 --- a/src/runtime/mcheckmark.go +++ b/src/runtime/mcheckmark.go @@ -39,7 +39,7 @@ func startCheckmarks() { assertWorldStopped() // Clear all checkmarks. - for _, ai := range mheap_.allArenas { + clearCheckmarks := func(ai arenaIdx) { arena := mheap_.arenas[ai.l1()][ai.l2()] bitmap := arena.checkmarks @@ -55,6 +55,13 @@ func startCheckmarks() { clear(bitmap.b[:]) } } + for _, ai := range mheap_.heapArenas { + clearCheckmarks(ai) + } + for _, ai := range mheap_.userArenaArenas { + clearCheckmarks(ai) + } + // Enable checkmarking. useCheckmark = true } @@ -88,8 +95,13 @@ func setCheckmark(obj, base, off uintptr, mbits markBits) bool { ai := arenaIndex(obj) arena := mheap_.arenas[ai.l1()][ai.l2()] - arenaWord := (obj / heapArenaBytes / 8) % uintptr(len(arena.checkmarks.b)) - mask := byte(1 << ((obj / heapArenaBytes) % 8)) + if arena == nil { + // Non-heap pointer. + return false + } + wordIdx := (obj - alignDown(obj, heapArenaBytes)) / goarch.PtrSize + arenaWord := wordIdx / 8 + mask := byte(1 << (wordIdx % 8)) bytep := &arena.checkmarks.b[arenaWord] if atomic.Load8(bytep)&mask != 0 { diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go index 48001cfdb94631..d7d97ad244a8a4 100644 --- a/src/runtime/mgc.go +++ b/src/runtime/mgc.go @@ -1056,13 +1056,22 @@ func gcMarkTermination(stw worldStop) { // mark using checkmark bits, to check that we // didn't forget to mark anything during the // concurrent mark process. + // + // Turn off gcwaiting because that will force + // gcDrain to return early if this goroutine + // happens to have its preemption flag set. + // This is fine because the world is stopped. + // Restore it after we're done just to be safe. + sched.gcwaiting.Store(false) startCheckmarks() gcResetMarkState() + gcMarkRootPrepare() gcw := &getg().m.p.ptr().gcw gcDrain(gcw, 0) wbBufFlush1(getg().m.p.ptr()) gcw.dispose() endCheckmarks() + sched.gcwaiting.Store(true) } // marking is complete so we can turn the write barrier off @@ -1684,7 +1693,7 @@ func gcSweep(mode gcMode) bool { mheap_.sweepgen += 2 sweep.active.reset() mheap_.pagesSwept.Store(0) - mheap_.sweepArenas = mheap_.allArenas + mheap_.sweepArenas = mheap_.heapArenas mheap_.reclaimIndex.Store(0) mheap_.reclaimCredit.Store(0) unlock(&mheap_.lock) @@ -1747,7 +1756,7 @@ func gcResetMarkState() { // Clear page marks. This is just 1MB per 64GB of heap, so the // time here is pretty trivial. lock(&mheap_.lock) - arenas := mheap_.allArenas + arenas := mheap_.heapArenas unlock(&mheap_.lock) for _, ai := range arenas { ha := mheap_.arenas[ai.l1()][ai.l2()] diff --git a/src/runtime/mgcmark.go b/src/runtime/mgcmark.go index 823b2bd7df9a04..92ef215ee094d8 100644 --- a/src/runtime/mgcmark.go +++ b/src/runtime/mgcmark.go @@ -89,9 +89,9 @@ func gcMarkRootPrepare() { // // Break up the work into arenas, and further into chunks. // - // Snapshot allArenas as markArenas. This snapshot is safe because allArenas + // Snapshot heapArenas as markArenas. This snapshot is safe because heapArenas // is append-only. - mheap_.markArenas = mheap_.allArenas[:len(mheap_.allArenas):len(mheap_.allArenas)] + mheap_.markArenas = mheap_.heapArenas[:len(mheap_.heapArenas):len(mheap_.heapArenas)] work.nSpanRoots = len(mheap_.markArenas) * (pagesPerArena / pagesPerSpanRoot) // Scan stacks. @@ -1614,13 +1614,13 @@ func greyobject(obj, base, off uintptr, span *mspan, gcw *gcWork, objIndex uintp if arena.pageMarks[pageIdx]&pageMask == 0 { atomic.Or8(&arena.pageMarks[pageIdx], pageMask) } + } - // If this is a noscan object, fast-track it to black - // instead of greying it. - if span.spanclass.noscan() { - gcw.bytesMarked += uint64(span.elemsize) - return - } + // If this is a noscan object, fast-track it to black + // instead of greying it. + if span.spanclass.noscan() { + gcw.bytesMarked += uint64(span.elemsize) + return } // We're adding obj to P's local workbuf, so it's likely diff --git a/src/runtime/mheap.go b/src/runtime/mheap.go index e058dd848925a4..21ae5b1a3b5a1b 100644 --- a/src/runtime/mheap.go +++ b/src/runtime/mheap.go @@ -108,9 +108,9 @@ type mheap struct { // Page reclaimer state - // reclaimIndex is the page index in allArenas of next page to + // reclaimIndex is the page index in heapArenas of next page to // reclaim. Specifically, it refers to page (i % - // pagesPerArena) of arena allArenas[i / pagesPerArena]. + // pagesPerArena) of arena heapArenas[i / pagesPerArena]. // // If this is >= 1<<63, the page reclaimer is done scanning // the page marks. @@ -165,22 +165,31 @@ type mheap struct { // (the actual arenas). This is only used on 32-bit. arena linearAlloc - // allArenas is the arenaIndex of every mapped arena. This can - // be used to iterate through the address space. + // heapArenas is the arenaIndex of every mapped arena mapped for the heap. + // This can be used to iterate through the heap address space. // // Access is protected by mheap_.lock. However, since this is // append-only and old backing arrays are never freed, it is // safe to acquire mheap_.lock, copy the slice header, and // then release mheap_.lock. - allArenas []arenaIdx + heapArenas []arenaIdx - // sweepArenas is a snapshot of allArenas taken at the + // userArenaArenas is the arenaIndex of every mapped arena mapped for + // user arenas. + // + // Access is protected by mheap_.lock. However, since this is + // append-only and old backing arrays are never freed, it is + // safe to acquire mheap_.lock, copy the slice header, and + // then release mheap_.lock. + userArenaArenas []arenaIdx + + // sweepArenas is a snapshot of heapArenas taken at the // beginning of the sweep cycle. This can be read safely by // simply blocking GC (by disabling preemption). sweepArenas []arenaIdx - // markArenas is a snapshot of allArenas taken at the beginning - // of the mark cycle. Because allArenas is append-only, neither + // markArenas is a snapshot of heapArenas taken at the beginning + // of the mark cycle. Because heapArenas is append-only, neither // this slice nor its contents will change during the mark, so // it can be read safely. markArenas []arenaIdx @@ -1494,7 +1503,7 @@ func (h *mheap) grow(npage uintptr) (uintptr, bool) { // Not enough room in the current arena. Allocate more // arena space. This may not be contiguous with the // current arena, so we have to request the full ask. - av, asize := h.sysAlloc(ask, &h.arenaHints, true) + av, asize := h.sysAlloc(ask, &h.arenaHints, &h.heapArenas) if av == nil { inUse := gcController.heapFree.load() + gcController.heapReleased.load() + gcController.heapInUse.load() print("runtime: out of memory: cannot allocate ", ask, "-byte block (", inUse, " in use)\n") diff --git a/src/runtime/runtime1.go b/src/runtime/runtime1.go index b47c589075ff60..fb16f6daefda40 100644 --- a/src/runtime/runtime1.go +++ b/src/runtime/runtime1.go @@ -440,6 +440,23 @@ func parsedebugvars() { debug.malloc = (debug.inittrace | debug.sbrk) != 0 debug.profstackdepth = min(debug.profstackdepth, maxProfStackDepth) + // Disable async preemption in checkmark mode. The following situation is + // problematic with checkmark mode: + // + // - The GC doesn't mark object A because it is truly dead. + // - The GC stops the world, asynchronously preempting G1 which has a reference + // to A in its top stack frame + // - During the stop the world, we run the second checkmark GC. It marks the roots + // and discovers A through G1. + // - Checkmark mode reports a failure since there's a discrepancy in mark metadata. + // + // We could disable just conservative scanning during the checkmark scan, which is + // safe but makes checkmark slightly less powerful, but that's a lot more invasive + // than just disabling async preemption altogether. + if debug.gccheckmark > 0 { + debug.asyncpreemptoff = 1 + } + setTraceback(gogetenv("GOTRACEBACK")) traceback_env = traceback_cache } From 4ac729283c807cdbe0f6c7041f21606019b722cf Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 7 Jan 2025 10:15:19 -0800 Subject: [PATCH 193/397] go/types, types2: don't register interface methods in Info.Types map Methods declared in an interface have a signature and FuncType in the AST, but they do not express a syntactic function type expression. Treat them like ordinary function/method declarations and do not record them in the Info.Types map. This removes an inconsistency in the way function types are recorded. Follow-up on CL 640776. For #70908. Change-Id: I60848f209b40b008039c014fb8b7b279361487b9 Reviewed-on: https://go-review.googlesource.com/c/go/+/640596 LUCI-TryBot-Result: Go LUCI Reviewed-by: Robert Griesemer Auto-Submit: Robert Griesemer Reviewed-by: Alan Donovan --- src/cmd/compile/internal/types2/interface.go | 18 ++++++++++-------- src/go/types/interface.go | 18 ++++++++++-------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/cmd/compile/internal/types2/interface.go b/src/cmd/compile/internal/types2/interface.go index 4072098e05234d..67f5b98a835cd9 100644 --- a/src/cmd/compile/internal/types2/interface.go +++ b/src/cmd/compile/internal/types2/interface.go @@ -137,17 +137,19 @@ func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType name := f.Name.Value if name == "_" { check.error(f.Name, BlankIfaceMethod, "methods must have a unique non-blank name") - continue // ignore + continue // ignore method } - typ := check.typ(f.Type) - sig, _ := typ.(*Signature) - if sig == nil { - if isValid(typ) { - check.errorf(f.Type, InvalidSyntaxTree, "%s is not a method signature", typ) - } - continue // ignore + // Type-check method declaration. + // Note: Don't call check.typ(f.Type) as that would record + // the method incorrectly as a type expression in Info.Types. + ftyp, _ := f.Type.(*syntax.FuncType) + if ftyp == nil { + check.errorf(f.Type, InvalidSyntaxTree, "%s is not a method signature", f.Type) + continue // ignore method } + sig := new(Signature) + check.funcType(sig, nil, nil, ftyp) // use named receiver type if available (for better error messages) var recvTyp Type = ityp diff --git a/src/go/types/interface.go b/src/go/types/interface.go index 01bbb08e0efe55..e5ca042e7509fc 100644 --- a/src/go/types/interface.go +++ b/src/go/types/interface.go @@ -176,17 +176,19 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d name := f.Names[0] if name.Name == "_" { check.error(name, BlankIfaceMethod, "methods must have a unique non-blank name") - continue // ignore + continue // ignore method } - typ := check.typ(f.Type) - sig, _ := typ.(*Signature) - if sig == nil { - if isValid(typ) { - check.errorf(f.Type, InvalidSyntaxTree, "%s is not a method signature", typ) - } - continue // ignore + // Type-check method declaration. + // Note: Don't call check.typ(f.Type) as that would record + // the method incorrectly as a type expression in Info.Types. + ftyp, _ := f.Type.(*ast.FuncType) + if ftyp == nil { + check.errorf(f.Type, InvalidSyntaxTree, "%s is not a method signature", f.Type) + continue // ignore method } + sig := new(Signature) + check.funcType(sig, nil, ftyp) // The go/parser doesn't accept method type parameters but an ast.FuncType may have them. if sig.tparams != nil { From 9d6af4082b4ee0dc912a5cd108581f6eefd778a5 Mon Sep 17 00:00:00 2001 From: Roland Shoemaker Date: Fri, 24 Jan 2025 10:38:45 -0800 Subject: [PATCH 194/397] crypto/tls: disable additional SSLv2 bogo tests We don't support SSLv2, at all. Change-Id: Icd0579b81393fbd82bf5b4d961470928faa7d09d Reviewed-on: https://go-review.googlesource.com/c/go/+/644017 Reviewed-by: Neal Patel Auto-Submit: Roland Shoemaker LUCI-TryBot-Result: Go LUCI --- src/crypto/tls/bogo_config.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/crypto/tls/bogo_config.json b/src/crypto/tls/bogo_config.json index 32969a3fb5a865..6472512158c444 100644 --- a/src/crypto/tls/bogo_config.json +++ b/src/crypto/tls/bogo_config.json @@ -42,6 +42,7 @@ "*-SignDefault-*": "TODO, partially it encodes BoringSSL defaults, partially we might be missing some implicit behavior of a missing flag", + "V2ClientHello-*": "We don't support SSLv2", "SendV2ClientHello*": "We don't support SSLv2", "*QUIC*": "No QUIC support", "Compliance-fips*": "No FIPS", From bf351677c4c134f15d28cf5352964838609de129 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 10 Jan 2025 16:22:20 -0800 Subject: [PATCH 195/397] cmd/cgo: add C declaration parameter unused attribute Fixes #71225 Change-Id: I3e60fdf632f2aa0e63b24225f13e4ace49906925 Reviewed-on: https://go-review.googlesource.com/c/go/+/642196 Reviewed-by: David Chase LUCI-TryBot-Result: Go LUCI Auto-Submit: Ian Lance Taylor Reviewed-by: Ian Lance Taylor --- src/cmd/cgo/out.go | 2 +- test/fixedbugs/issue71225.go | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 test/fixedbugs/issue71225.go diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index 5e67cc2d334598..b3e4c7ccdf0cf3 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -1094,7 +1094,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) { // This unpacks the argument struct above and calls the Go function. fmt.Fprintf(fgo2, "func _cgoexp%s_%s(a *%s) {\n", cPrefix, exp.ExpName, gotype) - fmt.Fprintf(fm, "void _cgoexp%s_%s(void* p){}\n", cPrefix, exp.ExpName) + fmt.Fprintf(fm, "void _cgoexp%s_%s(void* p __attribute__((unused))){}\n", cPrefix, exp.ExpName) fmt.Fprintf(fgo2, "\t") diff --git a/test/fixedbugs/issue71225.go b/test/fixedbugs/issue71225.go new file mode 100644 index 00000000000000..8a6b313edaa28c --- /dev/null +++ b/test/fixedbugs/issue71225.go @@ -0,0 +1,19 @@ +// build + +//go:build cgo + +// Copyright 2025 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +// #cgo CFLAGS: -Werror -Wunused-parameter +import "C" + +func main() { +} + +//export Fn +func Fn() { +} From 6adf54a3ebca857ae529b78c03945750731042ed Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 10 Jan 2025 16:35:24 -0800 Subject: [PATCH 196/397] cmd/cgo: declare _GoString{Len,Ptr} in _cgo_export.h Fixes #71226 Change-Id: I91c46a4310a9c7a9fcd1e3a131ca16e46949edb3 Reviewed-on: https://go-review.googlesource.com/c/go/+/642235 Auto-Submit: Ian Lance Taylor Reviewed-by: David Chase LUCI-TryBot-Result: Go LUCI Reviewed-by: Ian Lance Taylor --- src/cmd/cgo/out.go | 2 ++ test/fixedbugs/issue71226.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 test/fixedbugs/issue71226.go diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index b3e4c7ccdf0cf3..36a0267713eea8 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -1938,6 +1938,8 @@ const builtinExportProlog = ` #ifndef GO_CGO_GOSTRING_TYPEDEF typedef struct { const char *p; ptrdiff_t n; } _GoString_; +extern size_t _GoStringLen(_GoString_ s); +extern const char *_GoStringPtr(_GoString_ s); #endif #endif diff --git a/test/fixedbugs/issue71226.go b/test/fixedbugs/issue71226.go new file mode 100644 index 00000000000000..704814b6013b45 --- /dev/null +++ b/test/fixedbugs/issue71226.go @@ -0,0 +1,29 @@ +// build + +//go:build cgo + +// Copyright 2025 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +/* +#cgo CFLAGS: -Werror -Wimplicit-function-declaration + +#include + +static void CFn(_GoString_ gostr) { + printf("%.*s\n", _GoStringLen(gostr), _GoStringPtr(gostr)); +} +*/ +import "C" + +func main() { + C.CFn("hello, world") +} + +// The bug only occurs if there is an exported function. +//export Fn +func Fn() { +} From cc874072f3778a2b2cbe972b703dd6552ae63831 Mon Sep 17 00:00:00 2001 From: Eng Zer Jun Date: Sun, 12 Jan 2025 18:02:45 +0800 Subject: [PATCH 197/397] math/big: use built-in max function Change-Id: I65721039dab311762e55c6a60dd75b82f6b4622f Reviewed-on: https://go-review.googlesource.com/c/go/+/642335 Reviewed-by: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Reviewed-by: Robert Griesemer Auto-Submit: Ian Lance Taylor --- src/math/big/float.go | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/src/math/big/float.go b/src/math/big/float.go index 813c4ebfa7477f..e1d20d8bb4c008 100644 --- a/src/math/big/float.go +++ b/src/math/big/float.go @@ -602,7 +602,7 @@ func (z *Float) SetInt(x *Int) *Float { // are many trailing 0's. bits := uint32(x.BitLen()) if z.prec == 0 { - z.prec = umax32(bits, 64) + z.prec = max(bits, 64) } z.acc = Exact z.neg = x.neg @@ -628,7 +628,7 @@ func (z *Float) SetRat(x *Rat) *Float { a.SetInt(x.Num()) b.SetInt(x.Denom()) if z.prec == 0 { - z.prec = umax32(a.prec, b.prec) + z.prec = max(a.prec, b.prec) } return z.Quo(&a, &b) } @@ -1451,7 +1451,7 @@ func (z *Float) Add(x, y *Float) *Float { } if z.prec == 0 { - z.prec = umax32(x.prec, y.prec) + z.prec = max(x.prec, y.prec) } if x.form == finite && y.form == finite { @@ -1525,7 +1525,7 @@ func (z *Float) Sub(x, y *Float) *Float { } if z.prec == 0 { - z.prec = umax32(x.prec, y.prec) + z.prec = max(x.prec, y.prec) } if x.form == finite && y.form == finite { @@ -1592,7 +1592,7 @@ func (z *Float) Mul(x, y *Float) *Float { } if z.prec == 0 { - z.prec = umax32(x.prec, y.prec) + z.prec = max(x.prec, y.prec) } z.neg = x.neg != y.neg @@ -1637,7 +1637,7 @@ func (z *Float) Quo(x, y *Float) *Float { } if z.prec == 0 { - z.prec = umax32(x.prec, y.prec) + z.prec = max(x.prec, y.prec) } z.neg = x.neg != y.neg @@ -1724,10 +1724,3 @@ func (x *Float) ord() int { } return m } - -func umax32(x, y uint32) uint32 { - if x > y { - return x - } - return y -} From 9896da303a74c7af02f711fbb49ac08e4ef3590b Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Tue, 14 Jan 2025 11:26:06 +0100 Subject: [PATCH 198/397] internal/poll: use ignoringEINTR2 in (*FD).Pread Change-Id: I2af5f3f039b6c0e8e77484bd6b2cdb88e919a85d Reviewed-on: https://go-review.googlesource.com/c/go/+/641759 Auto-Submit: Ian Lance Taylor Reviewed-by: Cherry Mui LUCI-TryBot-Result: Go LUCI Auto-Submit: Tobias Klauser Reviewed-by: Ian Lance Taylor --- src/internal/poll/fd_unix.go | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/internal/poll/fd_unix.go b/src/internal/poll/fd_unix.go index 2535a3ae4dd43b..31e6e21120fde3 100644 --- a/src/internal/poll/fd_unix.go +++ b/src/internal/poll/fd_unix.go @@ -183,16 +183,9 @@ func (fd *FD) Pread(p []byte, off int64) (int, error) { if fd.IsStream && len(p) > maxRW { p = p[:maxRW] } - var ( - n int - err error - ) - for { - n, err = syscall.Pread(fd.Sysfd, p, off) - if err != syscall.EINTR { - break - } - } + n, err := ignoringEINTR2(func() (int, error) { + return syscall.Pread(fd.Sysfd, p, off) + }) if err != nil { n = 0 } From f7b8dd9033663944e3b563afaeb55dace4c060fc Mon Sep 17 00:00:00 2001 From: Roxy Light Date: Tue, 16 Jul 2024 10:21:30 -0700 Subject: [PATCH 199/397] io/fs: add ReadLinkFS interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added implementations for *io/fs.subFS, os.DirFS, and testing/fstest.MapFS. Amended testing/fstest.TestFS to check behavior. Addressed TODOs in archive/tar and os.CopyFS around symbolic links. I am deliberately not changing archive/zip in this CL, since it currently does not resolve symlinks as part of its filesystem implementation. I am unsure of the compatibility restrictions on doing so, so figured it would be better to address independently. testing/fstest.MapFS now includes resolution of symlinks, with MapFile.Data storing the symlink data. The behavior change there seemed less intrusive, especially given its intended usage in tests, and it is especially helpful in testing the io/fs function implementations. Fixes #49580 Change-Id: I58ec6915e8cc97341cdbfd9c24c67d1b60139447 Reviewed-on: https://go-review.googlesource.com/c/go/+/385534 LUCI-TryBot-Result: Go LUCI Reviewed-by: Dmitri Shuralyov Reviewed-by: Daniel Martí Reviewed-by: Bryan Mills Reviewed-by: Cherry Mui Reviewed-by: Quim Muntal Reviewed-by: Funda Secgin --- api/next/49580.txt | 8 + .../6-stdlib/99-minor/archive/tar/49580.md | 2 + doc/next/6-stdlib/99-minor/io/fs/49580.md | 1 + doc/next/6-stdlib/99-minor/os/49580.md | 2 + .../6-stdlib/99-minor/testing/fstest/49580.md | 3 + src/archive/tar/writer.go | 14 +- src/archive/tar/writer_test.go | 32 ++-- src/io/fs/readlink.go | 45 +++++ src/io/fs/readlink_test.go | 106 ++++++++++++ src/io/fs/sub.go | 33 +++- src/io/fs/walk_test.go | 41 +++++ src/os/dir.go | 60 +++---- src/os/file.go | 31 +++- src/os/file_test.go | 156 ++++++++++++++++++ src/os/os_test.go | 8 +- src/testing/fstest/mapfs.go | 115 ++++++++++++- src/testing/fstest/mapfs_test.go | 66 ++++++++ src/testing/fstest/testfs.go | 29 +++- src/testing/fstest/testfs_test.go | 3 + 19 files changed, 688 insertions(+), 67 deletions(-) create mode 100644 api/next/49580.txt create mode 100644 doc/next/6-stdlib/99-minor/archive/tar/49580.md create mode 100644 doc/next/6-stdlib/99-minor/io/fs/49580.md create mode 100644 doc/next/6-stdlib/99-minor/os/49580.md create mode 100644 doc/next/6-stdlib/99-minor/testing/fstest/49580.md create mode 100644 src/io/fs/readlink.go create mode 100644 src/io/fs/readlink_test.go create mode 100644 src/os/file_test.go diff --git a/api/next/49580.txt b/api/next/49580.txt new file mode 100644 index 00000000000000..ce213cc9ca6816 --- /dev/null +++ b/api/next/49580.txt @@ -0,0 +1,8 @@ +pkg io/fs, func Lstat(FS, string) (FileInfo, error) #49580 +pkg io/fs, func ReadLink(FS, string) (string, error) #49580 +pkg io/fs, type ReadLinkFS interface { Lstat, Open, ReadLink } #49580 +pkg io/fs, type ReadLinkFS interface, Lstat(string) (FileInfo, error) #49580 +pkg io/fs, type ReadLinkFS interface, Open(string) (File, error) #49580 +pkg io/fs, type ReadLinkFS interface, ReadLink(string) (string, error) #49580 +pkg testing/fstest, method (MapFS) Lstat(string) (fs.FileInfo, error) #49580 +pkg testing/fstest, method (MapFS) ReadLink(string) (string, error) #49580 diff --git a/doc/next/6-stdlib/99-minor/archive/tar/49580.md b/doc/next/6-stdlib/99-minor/archive/tar/49580.md new file mode 100644 index 00000000000000..8fa43681fa4163 --- /dev/null +++ b/doc/next/6-stdlib/99-minor/archive/tar/49580.md @@ -0,0 +1,2 @@ +The [*Writer.AddFS] implementation now supports symbolic links +for filesystems that implement [io/fs.ReadLinkFS]. diff --git a/doc/next/6-stdlib/99-minor/io/fs/49580.md b/doc/next/6-stdlib/99-minor/io/fs/49580.md new file mode 100644 index 00000000000000..c1cba5a3957dcb --- /dev/null +++ b/doc/next/6-stdlib/99-minor/io/fs/49580.md @@ -0,0 +1 @@ +A new [ReadLinkFS] interface provides the ability to read symbolic links in a filesystem. diff --git a/doc/next/6-stdlib/99-minor/os/49580.md b/doc/next/6-stdlib/99-minor/os/49580.md new file mode 100644 index 00000000000000..18d8831e7be6ef --- /dev/null +++ b/doc/next/6-stdlib/99-minor/os/49580.md @@ -0,0 +1,2 @@ +The filesystem returned by [DirFS] implements the new [io/fs.ReadLinkFS] interface. +[CopyFS] supports symlinks when copying filesystems that implement [io/fs.ReadLinkFS]. diff --git a/doc/next/6-stdlib/99-minor/testing/fstest/49580.md b/doc/next/6-stdlib/99-minor/testing/fstest/49580.md new file mode 100644 index 00000000000000..5b3c0d6a84eb22 --- /dev/null +++ b/doc/next/6-stdlib/99-minor/testing/fstest/49580.md @@ -0,0 +1,3 @@ +[MapFS] implements the new [io/fs.ReadLinkFS] interface. +[TestFS] will verify the functionality of the [io/fs.ReadLinkFS] interface if implemented. +[TestFS] will no longer follow symlinks to avoid unbounded recursion. diff --git a/src/archive/tar/writer.go b/src/archive/tar/writer.go index f966c5b4c648f5..336c9fd758e733 100644 --- a/src/archive/tar/writer.go +++ b/src/archive/tar/writer.go @@ -415,11 +415,17 @@ func (tw *Writer) AddFS(fsys fs.FS) error { if err != nil { return err } - // TODO(#49580): Handle symlinks when fs.ReadLinkFS is available. - if !d.IsDir() && !info.Mode().IsRegular() { + linkTarget := "" + if typ := d.Type(); typ == fs.ModeSymlink { + var err error + linkTarget, err = fs.ReadLink(fsys, name) + if err != nil { + return err + } + } else if !typ.IsRegular() && typ != fs.ModeDir { return errors.New("tar: cannot add non-regular file") } - h, err := FileInfoHeader(info, "") + h, err := FileInfoHeader(info, linkTarget) if err != nil { return err } @@ -430,7 +436,7 @@ func (tw *Writer) AddFS(fsys fs.FS) error { if err := tw.WriteHeader(h); err != nil { return err } - if d.IsDir() { + if !d.Type().IsRegular() { return nil } f, err := fsys.Open(name) diff --git a/src/archive/tar/writer_test.go b/src/archive/tar/writer_test.go index 7b10bf6a700d7f..9e484432ea90b6 100644 --- a/src/archive/tar/writer_test.go +++ b/src/archive/tar/writer_test.go @@ -1342,6 +1342,7 @@ func TestWriterAddFS(t *testing.T) { "emptyfolder": {Mode: 0o755 | os.ModeDir}, "file.go": {Data: []byte("hello")}, "subfolder/another.go": {Data: []byte("world")}, + "symlink.go": {Mode: 0o777 | os.ModeSymlink, Data: []byte("file.go")}, // Notably missing here is the "subfolder" directory. This makes sure even // if we don't have a subfolder directory listed. } @@ -1370,7 +1371,7 @@ func TestWriterAddFS(t *testing.T) { for _, name := range names { entriesLeft-- - entryInfo, err := fsys.Stat(name) + entryInfo, err := fsys.Lstat(name) if err != nil { t.Fatalf("getting entry info error: %v", err) } @@ -1396,18 +1397,23 @@ func TestWriterAddFS(t *testing.T) { name, entryInfo.Mode(), hdr.FileInfo().Mode()) } - if entryInfo.IsDir() { - continue - } - - data, err := io.ReadAll(tr) - if err != nil { - t.Fatal(err) - } - origdata := fsys[name].Data - if string(data) != string(origdata) { - t.Fatalf("test fs has file content %v; archive header has %v", - data, origdata) + switch entryInfo.Mode().Type() { + case fs.ModeDir: + // No additional checks necessary. + case fs.ModeSymlink: + origtarget := string(fsys[name].Data) + if hdr.Linkname != origtarget { + t.Fatalf("test fs has link content %s; archive header %v", origtarget, hdr.Linkname) + } + default: + data, err := io.ReadAll(tr) + if err != nil { + t.Fatal(err) + } + origdata := fsys[name].Data + if string(data) != string(origdata) { + t.Fatalf("test fs has file content %v; archive header has %v", origdata, data) + } } } if entriesLeft > 0 { diff --git a/src/io/fs/readlink.go b/src/io/fs/readlink.go new file mode 100644 index 00000000000000..64340b9fb4c57b --- /dev/null +++ b/src/io/fs/readlink.go @@ -0,0 +1,45 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package fs + +// ReadLinkFS is the interface implemented by a file system +// that supports reading symbolic links. +type ReadLinkFS interface { + FS + + // ReadLink returns the destination of the named symbolic link. + // If there is an error, it should be of type [*PathError]. + ReadLink(name string) (string, error) + + // Lstat returns a [FileInfo] describing the named file. + // If the file is a symbolic link, the returned [FileInfo] describes the symbolic link. + // Lstat makes no attempt to follow the link. + // If there is an error, it should be of type [*PathError]. + Lstat(name string) (FileInfo, error) +} + +// ReadLink returns the destination of the named symbolic link. +// +// If fsys does not implement [ReadLinkFS], then ReadLink returns an error. +func ReadLink(fsys FS, name string) (string, error) { + sym, ok := fsys.(ReadLinkFS) + if !ok { + return "", &PathError{Op: "readlink", Path: name, Err: ErrInvalid} + } + return sym.ReadLink(name) +} + +// Lstat returns a [FileInfo] describing the named file. +// If the file is a symbolic link, the returned [FileInfo] describes the symbolic link. +// Lstat makes no attempt to follow the link. +// +// If fsys does not implement [ReadLinkFS], then Lstat is identical to [Stat]. +func Lstat(fsys FS, name string) (FileInfo, error) { + sym, ok := fsys.(ReadLinkFS) + if !ok { + return Stat(fsys, name) + } + return sym.Lstat(name) +} diff --git a/src/io/fs/readlink_test.go b/src/io/fs/readlink_test.go new file mode 100644 index 00000000000000..3932c7b7785daf --- /dev/null +++ b/src/io/fs/readlink_test.go @@ -0,0 +1,106 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package fs_test + +import ( + . "io/fs" + "testing" + "testing/fstest" +) + +func TestReadLink(t *testing.T) { + testFS := fstest.MapFS{ + "foo": { + Data: []byte("bar"), + Mode: ModeSymlink | 0o777, + }, + "bar": { + Data: []byte("Hello, World!\n"), + Mode: 0o644, + }, + + "dir/parentlink": { + Data: []byte("../bar"), + Mode: ModeSymlink | 0o777, + }, + "dir/link": { + Data: []byte("file"), + Mode: ModeSymlink | 0o777, + }, + "dir/file": { + Data: []byte("Hello, World!\n"), + Mode: 0o644, + }, + } + + check := func(fsys FS, name string, want string) { + t.Helper() + got, err := ReadLink(fsys, name) + if got != want || err != nil { + t.Errorf("ReadLink(%q) = %q, %v; want %q, ", name, got, err, want) + } + } + + check(testFS, "foo", "bar") + check(testFS, "dir/parentlink", "../bar") + check(testFS, "dir/link", "file") + + // Test that ReadLink on Sub works. + sub, err := Sub(testFS, "dir") + if err != nil { + t.Fatal(err) + } + + check(sub, "link", "file") + check(sub, "parentlink", "../bar") +} + +func TestLstat(t *testing.T) { + testFS := fstest.MapFS{ + "foo": { + Data: []byte("bar"), + Mode: ModeSymlink | 0o777, + }, + "bar": { + Data: []byte("Hello, World!\n"), + Mode: 0o644, + }, + + "dir/parentlink": { + Data: []byte("../bar"), + Mode: ModeSymlink | 0o777, + }, + "dir/link": { + Data: []byte("file"), + Mode: ModeSymlink | 0o777, + }, + "dir/file": { + Data: []byte("Hello, World!\n"), + Mode: 0o644, + }, + } + + check := func(fsys FS, name string, want FileMode) { + t.Helper() + info, err := Lstat(fsys, name) + var got FileMode + if err == nil { + got = info.Mode() + } + if got != want || err != nil { + t.Errorf("Lstat(%q) = %v, %v; want %v, ", name, got, err, want) + } + } + + check(testFS, "foo", ModeSymlink|0o777) + check(testFS, "bar", 0o644) + + // Test that Lstat on Sub works. + sub, err := Sub(testFS, "dir") + if err != nil { + t.Fatal(err) + } + check(sub, "link", ModeSymlink|0o777) +} diff --git a/src/io/fs/sub.go b/src/io/fs/sub.go index 70ac62307778ed..376d561bad8447 100644 --- a/src/io/fs/sub.go +++ b/src/io/fs/sub.go @@ -23,7 +23,8 @@ type SubFS interface { // Otherwise, if fs implements [SubFS], Sub returns fsys.Sub(dir). // Otherwise, Sub returns a new [FS] implementation sub that, // in effect, implements sub.Open(name) as fsys.Open(path.Join(dir, name)). -// The implementation also translates calls to ReadDir, ReadFile, and Glob appropriately. +// The implementation also translates calls to ReadDir, ReadFile, +// ReadLink, Lstat, and Glob appropriately. // // Note that Sub(os.DirFS("/"), "prefix") is equivalent to os.DirFS("/prefix") // and that neither of them guarantees to avoid operating system @@ -44,6 +45,12 @@ func Sub(fsys FS, dir string) (FS, error) { return &subFS{fsys, dir}, nil } +var _ FS = (*subFS)(nil) +var _ ReadDirFS = (*subFS)(nil) +var _ ReadFileFS = (*subFS)(nil) +var _ ReadLinkFS = (*subFS)(nil) +var _ GlobFS = (*subFS)(nil) + type subFS struct { fsys FS dir string @@ -105,6 +112,30 @@ func (f *subFS) ReadFile(name string) ([]byte, error) { return data, f.fixErr(err) } +func (f *subFS) ReadLink(name string) (string, error) { + full, err := f.fullName("readlink", name) + if err != nil { + return "", err + } + target, err := ReadLink(f.fsys, full) + if err != nil { + return "", f.fixErr(err) + } + return target, nil +} + +func (f *subFS) Lstat(name string) (FileInfo, error) { + full, err := f.fullName("lstat", name) + if err != nil { + return nil, err + } + info, err := Lstat(f.fsys, full) + if err != nil { + return nil, f.fixErr(err) + } + return info, nil +} + func (f *subFS) Glob(pattern string) ([]string, error) { // Check pattern is well-formed. if _, err := path.Match(pattern, ""); err != nil { diff --git a/src/io/fs/walk_test.go b/src/io/fs/walk_test.go index a5fc715e155dbb..91f195f7be3df2 100644 --- a/src/io/fs/walk_test.go +++ b/src/io/fs/walk_test.go @@ -110,6 +110,47 @@ func TestWalkDir(t *testing.T) { }) } +func TestWalkDirSymlink(t *testing.T) { + fsys := fstest.MapFS{ + "link": {Data: []byte("dir"), Mode: ModeSymlink}, + "dir/a": {}, + "dir/b/c": {}, + "dir/d": {Data: []byte("b"), Mode: ModeSymlink}, + } + + wantTypes := map[string]FileMode{ + "link": ModeDir, + "link/a": 0, + "link/b": ModeDir, + "link/b/c": 0, + "link/d": ModeSymlink, + } + marks := make(map[string]int) + walkFn := func(path string, entry DirEntry, err error) error { + marks[path]++ + if want, ok := wantTypes[path]; !ok { + t.Errorf("Unexpected path %q in walk", path) + } else if got := entry.Type(); got != want { + t.Errorf("%s entry type = %v; want %v", path, got, want) + } + if err != nil { + t.Errorf("Walking %s: %v", path, err) + } + return nil + } + + // Expect no errors. + err := WalkDir(fsys, "link", walkFn) + if err != nil { + t.Fatalf("no error expected, found: %s", err) + } + for path := range wantTypes { + if got := marks[path]; got != 1 { + t.Errorf("%s visited %d times; expected 1", path, got) + } + } +} + func TestIssue51617(t *testing.T) { dir := t.TempDir() for _, sub := range []string{"a", filepath.Join("a", "bad"), filepath.Join("a", "next")} { diff --git a/src/os/dir.go b/src/os/dir.go index 939b208d8c0a2b..cc3fd602afe10e 100644 --- a/src/os/dir.go +++ b/src/os/dir.go @@ -140,9 +140,6 @@ func ReadDir(name string) ([]DirEntry, error) { // already exists in the destination, CopyFS will return an error // such that errors.Is(err, fs.ErrExist) will be true. // -// Symbolic links in fsys are not supported. A *PathError with Err set -// to ErrInvalid is returned when copying from a symbolic link. -// // Symbolic links in dir are followed. // // New files added to fsys (including if dir is a subdirectory of fsys) @@ -160,35 +157,38 @@ func CopyFS(dir string, fsys fs.FS) error { return err } newPath := joinPath(dir, fpath) - if d.IsDir() { - return MkdirAll(newPath, 0777) - } - // TODO(panjf2000): handle symlinks with the help of fs.ReadLinkFS - // once https://go.dev/issue/49580 is done. - // we also need filepathlite.IsLocal from https://go.dev/cl/564295. - if !d.Type().IsRegular() { + switch d.Type() { + case ModeDir: + return MkdirAll(newPath, 0777) + case ModeSymlink: + target, err := fs.ReadLink(fsys, path) + if err != nil { + return err + } + return Symlink(target, newPath) + case 0: + r, err := fsys.Open(path) + if err != nil { + return err + } + defer r.Close() + info, err := r.Stat() + if err != nil { + return err + } + w, err := OpenFile(newPath, O_CREATE|O_EXCL|O_WRONLY, 0666|info.Mode()&0777) + if err != nil { + return err + } + + if _, err := io.Copy(w, r); err != nil { + w.Close() + return &PathError{Op: "Copy", Path: newPath, Err: err} + } + return w.Close() + default: return &PathError{Op: "CopyFS", Path: path, Err: ErrInvalid} } - - r, err := fsys.Open(path) - if err != nil { - return err - } - defer r.Close() - info, err := r.Stat() - if err != nil { - return err - } - w, err := OpenFile(newPath, O_CREATE|O_EXCL|O_WRONLY, 0666|info.Mode()&0777) - if err != nil { - return err - } - - if _, err := io.Copy(w, r); err != nil { - w.Close() - return &PathError{Op: "Copy", Path: newPath, Err: err} - } - return w.Close() }) } diff --git a/src/os/file.go b/src/os/file.go index a5063680f90589..1d4382e4861f6a 100644 --- a/src/os/file.go +++ b/src/os/file.go @@ -700,12 +700,17 @@ func (f *File) SyscallConn() (syscall.RawConn, error) { // // The directory dir must not be "". // -// The result implements [io/fs.StatFS], [io/fs.ReadFileFS] and -// [io/fs.ReadDirFS]. +// The result implements [io/fs.StatFS], [io/fs.ReadFileFS], [io/fs.ReadDirFS], and +// [io/fs.ReadLinkFS]. func DirFS(dir string) fs.FS { return dirFS(dir) } +var _ fs.StatFS = dirFS("") +var _ fs.ReadFileFS = dirFS("") +var _ fs.ReadDirFS = dirFS("") +var _ fs.ReadLinkFS = dirFS("") + type dirFS string func (dir dirFS) Open(name string) (fs.File, error) { @@ -777,6 +782,28 @@ func (dir dirFS) Stat(name string) (fs.FileInfo, error) { return f, nil } +func (dir dirFS) Lstat(name string) (fs.FileInfo, error) { + fullname, err := dir.join(name) + if err != nil { + return nil, &PathError{Op: "lstat", Path: name, Err: err} + } + f, err := Lstat(fullname) + if err != nil { + // See comment in dirFS.Open. + err.(*PathError).Path = name + return nil, err + } + return f, nil +} + +func (dir dirFS) ReadLink(name string) (string, error) { + fullname, err := dir.join(name) + if err != nil { + return "", &PathError{Op: "readlink", Path: name, Err: err} + } + return Readlink(fullname) +} + // join returns the path for name in dir. func (dir dirFS) join(name string) (string, error) { if dir == "" { diff --git a/src/os/file_test.go b/src/os/file_test.go new file mode 100644 index 00000000000000..f56a34da3e080f --- /dev/null +++ b/src/os/file_test.go @@ -0,0 +1,156 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package os_test + +import ( + "internal/testenv" + "io/fs" + . "os" + "path/filepath" + "testing" +) + +func TestDirFSReadLink(t *testing.T) { + testenv.MustHaveSymlink(t) + + root := t.TempDir() + subdir := filepath.Join(root, "dir") + if err := Mkdir(subdir, 0o777); err != nil { + t.Fatal(err) + } + links := map[string]string{ + filepath.Join(root, "parent-link"): filepath.Join("..", "foo"), + filepath.Join(root, "sneaky-parent-link"): filepath.Join("dir", "..", "..", "foo"), + filepath.Join(root, "abs-link"): filepath.Join(root, "foo"), + filepath.Join(root, "rel-link"): "foo", + filepath.Join(root, "rel-sub-link"): filepath.Join("dir", "foo"), + filepath.Join(subdir, "parent-link"): filepath.Join("..", "foo"), + } + for newname, oldname := range links { + if err := Symlink(oldname, newname); err != nil { + t.Fatal(err) + } + } + + fsys := DirFS(root) + want := map[string]string{ + "rel-link": "foo", + "rel-sub-link": filepath.Join("dir", "foo"), + "dir/parent-link": filepath.Join("..", "foo"), + "parent-link": filepath.Join("..", "foo"), + "sneaky-parent-link": filepath.Join("dir", "..", "..", "foo"), + "abs-link": filepath.Join(root, "foo"), + } + for name, want := range want { + got, err := fs.ReadLink(fsys, name) + if got != want || err != nil { + t.Errorf("fs.ReadLink(fsys, %q) = %q, %v; want %q, ", name, got, err, want) + } + } +} + +func TestDirFSLstat(t *testing.T) { + testenv.MustHaveSymlink(t) + + root := t.TempDir() + subdir := filepath.Join(root, "dir") + if err := Mkdir(subdir, 0o777); err != nil { + t.Fatal(err) + } + if err := Symlink("dir", filepath.Join(root, "link")); err != nil { + t.Fatal(err) + } + + fsys := DirFS(root) + want := map[string]fs.FileMode{ + "link": fs.ModeSymlink, + "dir": fs.ModeDir, + } + for name, want := range want { + info, err := fs.Lstat(fsys, name) + var got fs.FileMode + if info != nil { + got = info.Mode().Type() + } + if got != want || err != nil { + t.Errorf("fs.Lstat(fsys, %q).Mode().Type() = %v, %v; want %v, ", name, got, err, want) + } + } +} + +func TestDirFSWalkDir(t *testing.T) { + testenv.MustHaveSymlink(t) + + root := t.TempDir() + subdir := filepath.Join(root, "dir") + if err := Mkdir(subdir, 0o777); err != nil { + t.Fatal(err) + } + if err := Symlink("dir", filepath.Join(root, "link")); err != nil { + t.Fatal(err) + } + if err := WriteFile(filepath.Join(root, "dir", "a"), nil, 0o666); err != nil { + t.Fatal(err) + } + fsys := DirFS(root) + + t.Run("SymlinkRoot", func(t *testing.T) { + wantTypes := map[string]fs.FileMode{ + "link": fs.ModeDir, + "link/a": 0, + } + marks := make(map[string]int) + err := fs.WalkDir(fsys, "link", func(path string, entry fs.DirEntry, err error) error { + marks[path]++ + if want, ok := wantTypes[path]; !ok { + t.Errorf("Unexpected path %q in walk", path) + } else if got := entry.Type(); got != want { + t.Errorf("%s entry type = %v; want %v", path, got, want) + } + if err != nil { + t.Errorf("%s: %v", path, err) + } + return nil + }) + if err != nil { + t.Fatal(err) + } + for path := range wantTypes { + if got := marks[path]; got != 1 { + t.Errorf("%s visited %d times; expected 1", path, got) + } + } + }) + + t.Run("SymlinkPresent", func(t *testing.T) { + wantTypes := map[string]fs.FileMode{ + ".": fs.ModeDir, + "dir": fs.ModeDir, + "dir/a": 0, + "link": fs.ModeSymlink, + } + marks := make(map[string]int) + err := fs.WalkDir(fsys, ".", func(path string, entry fs.DirEntry, err error) error { + marks[path]++ + if want, ok := wantTypes[path]; !ok { + t.Errorf("Unexpected path %q in walk", path) + } else if got := entry.Type(); got != want { + t.Errorf("%s entry type = %v; want %v", path, got, want) + } + if err != nil { + t.Errorf("%s: %v", path, err) + } + return nil + }) + if err != nil { + t.Fatal(err) + } + for path := range wantTypes { + if got := marks[path]; got != 1 { + t.Errorf("%s visited %d times; expected 1", path, got) + } + } + }) +} diff --git a/src/os/os_test.go b/src/os/os_test.go index 1e2db94dea28ab..6bb89f58708575 100644 --- a/src/os/os_test.go +++ b/src/os/os_test.go @@ -3725,13 +3725,9 @@ func TestCopyFSWithSymlinks(t *testing.T) { t.Fatalf("Mkdir: %v", err) } - // TODO(panjf2000): symlinks are currently not supported, and a specific error - // will be returned. Verify that error and skip the subsequent test, - // revisit this once #49580 is closed. - if err := CopyFS(tmpDupDir, fsys); !errors.Is(err, ErrInvalid) { - t.Fatalf("got %v, want ErrInvalid", err) + if err := CopyFS(tmpDupDir, fsys); err != nil { + t.Fatalf("CopyFS: %v", err) } - t.Skip("skip the subsequent test and wait for #49580") forceMFTUpdateOnWindows(t, tmpDupDir) tmpFsys := DirFS(tmpDupDir) diff --git a/src/testing/fstest/mapfs.go b/src/testing/fstest/mapfs.go index 5e3720b0ed6e07..5ce03985e1ee5f 100644 --- a/src/testing/fstest/mapfs.go +++ b/src/testing/fstest/mapfs.go @@ -15,7 +15,7 @@ import ( // A MapFS is a simple in-memory file system for use in tests, // represented as a map from path names (arguments to Open) -// to information about the files or directories they represent. +// to information about the files, directories, or symbolic links they represent. // // The map need not include parent directories for files contained // in the map; those will be synthesized if needed. @@ -34,21 +34,27 @@ type MapFS map[string]*MapFile // A MapFile describes a single file in a [MapFS]. type MapFile struct { - Data []byte // file content + Data []byte // file content or symlink destination Mode fs.FileMode // fs.FileInfo.Mode ModTime time.Time // fs.FileInfo.ModTime Sys any // fs.FileInfo.Sys } var _ fs.FS = MapFS(nil) +var _ fs.ReadLinkFS = MapFS(nil) var _ fs.File = (*openMapFile)(nil) -// Open opens the named file. +// Open opens the named file after following any symbolic links. func (fsys MapFS) Open(name string) (fs.File, error) { if !fs.ValidPath(name) { return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrNotExist} } - file := fsys[name] + realName, ok := fsys.resolveSymlinks(name) + if !ok { + return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrNotExist} + } + + file := fsys[realName] if file != nil && file.Mode&fs.ModeDir == 0 { // Ordinary file return &openMapFile{name, mapFileInfo{path.Base(name), file}, 0}, nil @@ -59,10 +65,8 @@ func (fsys MapFS) Open(name string) (fs.File, error) { // But file can also be non-nil, in case the user wants to set metadata for the directory explicitly. // Either way, we need to construct the list of children of this directory. var list []mapFileInfo - var elem string var need = make(map[string]bool) - if name == "." { - elem = "." + if realName == "." { for fname, f := range fsys { i := strings.Index(fname, "/") if i < 0 { @@ -74,8 +78,7 @@ func (fsys MapFS) Open(name string) (fs.File, error) { } } } else { - elem = name[strings.LastIndex(name, "/")+1:] - prefix := name + "/" + prefix := realName + "/" for fname, f := range fsys { if strings.HasPrefix(fname, prefix) { felem := fname[len(prefix):] @@ -107,9 +110,103 @@ func (fsys MapFS) Open(name string) (fs.File, error) { if file == nil { file = &MapFile{Mode: fs.ModeDir | 0555} } + var elem string + if name == "." { + elem = "." + } else { + elem = name[strings.LastIndex(name, "/")+1:] + } return &mapDir{name, mapFileInfo{elem, file}, list, 0}, nil } +func (fsys MapFS) resolveSymlinks(name string) (_ string, ok bool) { + // Fast path: if a symlink is in the map, resolve it. + if file := fsys[name]; file != nil && file.Mode.Type() == fs.ModeSymlink { + target := string(file.Data) + if path.IsAbs(target) { + return "", false + } + return fsys.resolveSymlinks(path.Join(path.Dir(name), target)) + } + + // Check if each parent directory (starting at root) is a symlink. + for i := 0; i < len(name); { + j := strings.Index(name[i:], "/") + var dir string + if j < 0 { + dir = name + i = len(name) + } else { + dir = name[:i+j] + i += j + } + if file := fsys[dir]; file != nil && file.Mode.Type() == fs.ModeSymlink { + target := string(file.Data) + if path.IsAbs(target) { + return "", false + } + return fsys.resolveSymlinks(path.Join(path.Dir(dir), target) + name[i:]) + } + i += len("/") + } + return name, fs.ValidPath(name) +} + +// ReadLink returns the destination of the named symbolic link. +func (fsys MapFS) ReadLink(name string) (string, error) { + info, err := fsys.lstat(name) + if err != nil { + return "", &fs.PathError{Op: "readlink", Path: name, Err: err} + } + if info.f.Mode.Type() != fs.ModeSymlink { + return "", &fs.PathError{Op: "readlink", Path: name, Err: fs.ErrInvalid} + } + return string(info.f.Data), nil +} + +// Lstat returns a FileInfo describing the named file. +// If the file is a symbolic link, the returned FileInfo describes the symbolic link. +// Lstat makes no attempt to follow the link. +func (fsys MapFS) Lstat(name string) (fs.FileInfo, error) { + info, err := fsys.lstat(name) + if err != nil { + return nil, &fs.PathError{Op: "lstat", Path: name, Err: err} + } + return info, nil +} + +func (fsys MapFS) lstat(name string) (*mapFileInfo, error) { + if !fs.ValidPath(name) { + return nil, fs.ErrNotExist + } + realDir, ok := fsys.resolveSymlinks(path.Dir(name)) + if !ok { + return nil, fs.ErrNotExist + } + elem := path.Base(name) + realName := path.Join(realDir, elem) + + file := fsys[realName] + if file != nil { + return &mapFileInfo{elem, file}, nil + } + + if realName == "." { + return &mapFileInfo{elem, &MapFile{Mode: fs.ModeDir | 0555}}, nil + } + // Maybe a directory. + prefix := realName + "/" + for fname := range fsys { + if strings.HasPrefix(fname, prefix) { + return &mapFileInfo{elem, &MapFile{Mode: fs.ModeDir | 0555}}, nil + } + } + // If the directory name is not in the map, + // and there are no children of the name in the map, + // then the directory is treated as not existing. + return nil, fs.ErrNotExist +} + // fsOnly is a wrapper that hides all but the fs.FS methods, // to avoid an infinite recursion when implementing special // methods in terms of helpers that would use them. diff --git a/src/testing/fstest/mapfs_test.go b/src/testing/fstest/mapfs_test.go index 6381a2e56c99b3..e7ff4180ecc5e4 100644 --- a/src/testing/fstest/mapfs_test.go +++ b/src/testing/fstest/mapfs_test.go @@ -57,3 +57,69 @@ func TestMapFSFileInfoName(t *testing.T) { t.Errorf("MapFS FileInfo.Name want:\n%s\ngot:\n%s\n", want, got) } } + +func TestMapFSSymlink(t *testing.T) { + const fileContent = "If a program is too slow, it must have a loop.\n" + m := MapFS{ + "fortune/k/ken.txt": {Data: []byte(fileContent)}, + "dirlink": {Data: []byte("fortune/k"), Mode: fs.ModeSymlink}, + "linklink": {Data: []byte("dirlink"), Mode: fs.ModeSymlink}, + "ken.txt": {Data: []byte("dirlink/ken.txt"), Mode: fs.ModeSymlink}, + } + if err := TestFS(m, "fortune/k/ken.txt", "dirlink", "ken.txt", "linklink"); err != nil { + t.Error(err) + } + + gotData, err := fs.ReadFile(m, "ken.txt") + if string(gotData) != fileContent || err != nil { + t.Errorf("fs.ReadFile(m, \"ken.txt\") = %q, %v; want %q, ", gotData, err, fileContent) + } + gotLink, err := fs.ReadLink(m, "dirlink") + if want := "fortune/k"; gotLink != want || err != nil { + t.Errorf("fs.ReadLink(m, \"dirlink\") = %q, %v; want %q, ", gotLink, err, fileContent) + } + gotInfo, err := fs.Lstat(m, "dirlink") + if err != nil { + t.Errorf("fs.Lstat(m, \"dirlink\") = _, %v; want _, ", err) + } else { + if got, want := gotInfo.Name(), "dirlink"; got != want { + t.Errorf("fs.Lstat(m, \"dirlink\").Name() = %q; want %q", got, want) + } + if got, want := gotInfo.Mode(), fs.ModeSymlink; got != want { + t.Errorf("fs.Lstat(m, \"dirlink\").Mode() = %v; want %v", got, want) + } + } + gotInfo, err = fs.Stat(m, "dirlink") + if err != nil { + t.Errorf("fs.Stat(m, \"dirlink\") = _, %v; want _, ", err) + } else { + if got, want := gotInfo.Name(), "dirlink"; got != want { + t.Errorf("fs.Stat(m, \"dirlink\").Name() = %q; want %q", got, want) + } + if got, want := gotInfo.Mode(), fs.ModeDir|0555; got != want { + t.Errorf("fs.Stat(m, \"dirlink\").Mode() = %v; want %v", got, want) + } + } + gotInfo, err = fs.Lstat(m, "linklink") + if err != nil { + t.Errorf("fs.Lstat(m, \"linklink\") = _, %v; want _, ", err) + } else { + if got, want := gotInfo.Name(), "linklink"; got != want { + t.Errorf("fs.Lstat(m, \"linklink\").Name() = %q; want %q", got, want) + } + if got, want := gotInfo.Mode(), fs.ModeSymlink; got != want { + t.Errorf("fs.Lstat(m, \"linklink\").Mode() = %v; want %v", got, want) + } + } + gotInfo, err = fs.Stat(m, "linklink") + if err != nil { + t.Errorf("fs.Stat(m, \"linklink\") = _, %v; want _, ", err) + } else { + if got, want := gotInfo.Name(), "linklink"; got != want { + t.Errorf("fs.Stat(m, \"linklink\").Name() = %q; want %q", got, want) + } + if got, want := gotInfo.Mode(), fs.ModeDir|0555; got != want { + t.Errorf("fs.Stat(m, \"linklink\").Mode() = %v; want %v", got, want) + } + } +} diff --git a/src/testing/fstest/testfs.go b/src/testing/fstest/testfs.go index affdfa64291ba8..1fb84b892842cb 100644 --- a/src/testing/fstest/testfs.go +++ b/src/testing/fstest/testfs.go @@ -20,6 +20,9 @@ import ( // TestFS tests a file system implementation. // It walks the entire tree of files in fsys, // opening and checking that each file behaves correctly. +// Symbolic links are not followed, +// but their Lstat values are checked +// if the file system implements [fs.ReadLinkFS]. // It also checks that the file system contains at least the expected files. // As a special case, if no expected files are listed, fsys must be empty. // Otherwise, fsys must contain at least the listed files; it can also contain others. @@ -156,9 +159,14 @@ func (t *fsTester) checkDir(dir string) { path := prefix + name t.checkStat(path, info) t.checkOpen(path) - if info.IsDir() { + switch info.Type() { + case fs.ModeDir: t.checkDir(path) - } else { + case fs.ModeSymlink: + // No further processing. + // Avoid following symlinks to avoid potentially unbounded recursion. + t.files = append(t.files, path) + default: t.checkFile(path) } } @@ -440,6 +448,23 @@ func (t *fsTester) checkStat(path string, entry fs.DirEntry) { t.errorf("%s: fsys.Stat(...) = %s\n\twant %s", path, finfo2, finfo) } } + + if fsys, ok := t.fsys.(fs.ReadLinkFS); ok { + info2, err := fsys.Lstat(path) + if err != nil { + t.errorf("%s: fsys.Lstat: %v", path, err) + return + } + fientry2 := formatInfoEntry(info2) + if fentry != fientry2 { + t.errorf("%s: mismatch:\n\tentry = %s\n\tfsys.Lstat(...) = %s", path, fentry, fientry2) + } + feinfo := formatInfo(einfo) + finfo2 := formatInfo(info2) + if feinfo != finfo2 { + t.errorf("%s: mismatch:\n\tentry.Info() = %s\n\tfsys.Lstat(...) = %s\n", path, feinfo, finfo2) + } + } } // checkDirList checks that two directory lists contain the same files and file info. diff --git a/src/testing/fstest/testfs_test.go b/src/testing/fstest/testfs_test.go index 2ef1053a01a646..d6d6d89b89fdaa 100644 --- a/src/testing/fstest/testfs_test.go +++ b/src/testing/fstest/testfs_test.go @@ -28,6 +28,9 @@ func TestSymlink(t *testing.T) { if err := os.Symlink(filepath.Join(tmp, "hello"), filepath.Join(tmp, "hello.link")); err != nil { t.Fatal(err) } + if err := os.Symlink("hello", filepath.Join(tmp, "hello_rel.link")); err != nil { + t.Fatal(err) + } if err := TestFS(tmpfs, "hello", "hello.link"); err != nil { t.Fatal(err) From f7dbbf251980763609a65efe15ef9f8ed0cc5a95 Mon Sep 17 00:00:00 2001 From: Jakub Ciolek Date: Sat, 11 Jan 2025 17:56:04 +0100 Subject: [PATCH 200/397] cmd/compile: distribute 8 and 16-bit multiplication Expand the existing rule to cover 8 and 16 bit variants. compilecmp linux/amd64: time time.parseStrictRFC3339.func1 80 -> 70 (-12.50%) time.Time.appendStrictRFC3339.func1 80 -> 70 (-12.50%) time.Time.appendStrictRFC3339 439 -> 428 (-2.51%) time [cmd/compile] time.parseStrictRFC3339.func1 80 -> 70 (-12.50%) time.Time.appendStrictRFC3339.func1 80 -> 70 (-12.50%) time.Time.appendStrictRFC3339 439 -> 428 (-2.51%) linux/arm64: time time.parseStrictRFC3339.func1 changed time.Time.appendStrictRFC3339.func1 changed time.Time.appendStrictRFC3339 416 -> 400 (-3.85%) time [cmd/compile] time.Time.appendStrictRFC3339 416 -> 400 (-3.85%) time.parseStrictRFC3339.func1 changed time.Time.appendStrictRFC3339.func1 changed Change-Id: I0ad3b2363a9fe8c322dd05fbc13bf151a146d8cb Reviewed-on: https://go-review.googlesource.com/c/go/+/641756 Auto-Submit: Keith Randall LUCI-TryBot-Result: Go LUCI Reviewed-by: Cherry Mui Reviewed-by: Keith Randall Reviewed-by: Keith Randall --- .../compile/internal/ssa/_gen/generic.rules | 4 ++ .../compile/internal/ssa/rewritegeneric.go | 68 +++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/src/cmd/compile/internal/ssa/_gen/generic.rules b/src/cmd/compile/internal/ssa/_gen/generic.rules index 9e2e8772c154ab..8ad246830e386f 100644 --- a/src/cmd/compile/internal/ssa/_gen/generic.rules +++ b/src/cmd/compile/internal/ssa/_gen/generic.rules @@ -353,6 +353,10 @@ (Add64 (Const64 [c*d]) (Mul64 (Const64 [c]) x)) (Mul32 (Const32 [c]) (Add32 (Const32 [d]) x)) => (Add32 (Const32 [c*d]) (Mul32 (Const32 [c]) x)) +(Mul16 (Const16 [c]) (Add16 (Const16 [d]) x)) => + (Add16 (Const16 [c*d]) (Mul16 (Const16 [c]) x)) +(Mul8 (Const8 [c]) (Add8 (Const8 [d]) x)) => + (Add8 (Const8 [c*d]) (Mul8 (Const8 [c]) x)) // Rewrite x*y ± x*z to x*(y±z) (Add(64|32|16|8) (Mul(64|32|16|8) x y) (Mul(64|32|16|8) x z)) diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go index 4cb287c9b7a0ed..fa771bf27ddea0 100644 --- a/src/cmd/compile/internal/ssa/rewritegeneric.go +++ b/src/cmd/compile/internal/ssa/rewritegeneric.go @@ -18194,6 +18194,40 @@ func rewriteValuegeneric_OpMul16(v *Value) bool { } break } + // match: (Mul16 (Const16 [c]) (Add16 (Const16 [d]) x)) + // result: (Add16 (Const16 [c*d]) (Mul16 (Const16 [c]) x)) + for { + for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { + if v_0.Op != OpConst16 { + continue + } + t := v_0.Type + c := auxIntToInt16(v_0.AuxInt) + if v_1.Op != OpAdd16 || v_1.Type != t { + continue + } + _ = v_1.Args[1] + v_1_0 := v_1.Args[0] + v_1_1 := v_1.Args[1] + for _i1 := 0; _i1 <= 1; _i1, v_1_0, v_1_1 = _i1+1, v_1_1, v_1_0 { + if v_1_0.Op != OpConst16 || v_1_0.Type != t { + continue + } + d := auxIntToInt16(v_1_0.AuxInt) + x := v_1_1 + v.reset(OpAdd16) + v0 := b.NewValue0(v.Pos, OpConst16, t) + v0.AuxInt = int16ToAuxInt(c * d) + v1 := b.NewValue0(v.Pos, OpMul16, t) + v2 := b.NewValue0(v.Pos, OpConst16, t) + v2.AuxInt = int16ToAuxInt(c) + v1.AddArg2(v2, x) + v.AddArg2(v0, v1) + return true + } + } + break + } // match: (Mul16 (Const16 [0]) _) // result: (Const16 [0]) for { @@ -18917,6 +18951,40 @@ func rewriteValuegeneric_OpMul8(v *Value) bool { } break } + // match: (Mul8 (Const8 [c]) (Add8 (Const8 [d]) x)) + // result: (Add8 (Const8 [c*d]) (Mul8 (Const8 [c]) x)) + for { + for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { + if v_0.Op != OpConst8 { + continue + } + t := v_0.Type + c := auxIntToInt8(v_0.AuxInt) + if v_1.Op != OpAdd8 || v_1.Type != t { + continue + } + _ = v_1.Args[1] + v_1_0 := v_1.Args[0] + v_1_1 := v_1.Args[1] + for _i1 := 0; _i1 <= 1; _i1, v_1_0, v_1_1 = _i1+1, v_1_1, v_1_0 { + if v_1_0.Op != OpConst8 || v_1_0.Type != t { + continue + } + d := auxIntToInt8(v_1_0.AuxInt) + x := v_1_1 + v.reset(OpAdd8) + v0 := b.NewValue0(v.Pos, OpConst8, t) + v0.AuxInt = int8ToAuxInt(c * d) + v1 := b.NewValue0(v.Pos, OpMul8, t) + v2 := b.NewValue0(v.Pos, OpConst8, t) + v2.AuxInt = int8ToAuxInt(c) + v1.AddArg2(v2, x) + v.AddArg2(v0, v1) + return true + } + } + break + } // match: (Mul8 (Const8 [0]) _) // result: (Const8 [0]) for { From e57769d5ad251a26d7676cd7a63e5332b26a35f0 Mon Sep 17 00:00:00 2001 From: Jakub Ciolek Date: Tue, 7 Jan 2025 07:00:24 +0100 Subject: [PATCH 201/397] cmd/compile: on AMD64, prefer XOR/AND for (x & 1) == 0 check It's shorter to encode. Additionally, XOR and AND generally have higher throughput than BT/SET*. compilecmp: runtime runtime.(*sweepClass).split 58 -> 56 (-3.45%) runtime.sweepClass.split 14 -> 11 (-21.43%) runtime [cmd/compile] runtime.(*sweepClass).split 58 -> 56 (-3.45%) runtime.sweepClass.split 14 -> 11 (-21.43%) strconv strconv.ryuFtoaShortest changed strconv [cmd/compile] strconv.ryuFtoaShortest changed math/big math/big.(*Int).MulRange 255 -> 252 (-1.18%) testing/quick testing/quick.sizedValue changed internal/fuzz internal/fuzz.(*pcgRand).bool 69 -> 70 (+1.45%) cmd/internal/obj/x86 cmd/internal/obj/x86.(*AsmBuf).asmevex changed math/big [cmd/compile] math/big.(*Int).MulRange 255 -> 252 (-1.18%) cmd/internal/obj/x86 [cmd/compile] cmd/internal/obj/x86.(*AsmBuf).asmevex changed net/http net/http.(*http2stream).isPushed 11 -> 10 (-9.09%) cmd/vendor/github.com/google/pprof/internal/binutils cmd/vendor/github.com/google/pprof/internal/binutils.(*file).computeBase changed Change-Id: I9cb2987eb263c85ee4e93d6f8455c91a55273173 Reviewed-on: https://go-review.googlesource.com/c/go/+/640975 Reviewed-by: Cherry Mui Reviewed-by: Keith Randall Reviewed-by: Keith Randall Auto-Submit: Keith Randall LUCI-TryBot-Result: Go LUCI --- src/cmd/compile/internal/ssa/_gen/AMD64.rules | 2 ++ src/cmd/compile/internal/ssa/rewriteAMD64.go | 32 +++++++++++++++++++ test/codegen/bool.go | 2 ++ 3 files changed, 36 insertions(+) diff --git a/src/cmd/compile/internal/ssa/_gen/AMD64.rules b/src/cmd/compile/internal/ssa/_gen/AMD64.rules index ce9a6e99140a29..716f4f1c32d153 100644 --- a/src/cmd/compile/internal/ssa/_gen/AMD64.rules +++ b/src/cmd/compile/internal/ssa/_gen/AMD64.rules @@ -629,6 +629,8 @@ // x & 1 != 0 -> x & 1 (SETNE (TEST(B|W)const [1] x)) => (AND(L|L)const [1] x) (SETB (BT(L|Q)const [0] x)) => (AND(L|Q)const [1] x) +// x & 1 == 0 -> (x & 1) ^ 1 +(SETAE (BT(L|Q)const [0] x)) => (XORLconst [1] (ANDLconst [1] x)) // Recognize bit tests: a&(1< [1] x)) + for { + if v_0.Op != OpAMD64BTLconst || auxIntToInt8(v_0.AuxInt) != 0 { + break + } + x := v_0.Args[0] + v.reset(OpAMD64XORLconst) + v.AuxInt = int32ToAuxInt(1) + v0 := b.NewValue0(v.Pos, OpAMD64ANDLconst, typ.Bool) + v0.AuxInt = int32ToAuxInt(1) + v0.AddArg(x) + v.AddArg(v0) + return true + } + // match: (SETAE (BTQconst [0] x)) + // result: (XORLconst [1] (ANDLconst [1] x)) + for { + if v_0.Op != OpAMD64BTQconst || auxIntToInt8(v_0.AuxInt) != 0 { + break + } + x := v_0.Args[0] + v.reset(OpAMD64XORLconst) + v.AuxInt = int32ToAuxInt(1) + v0 := b.NewValue0(v.Pos, OpAMD64ANDLconst, typ.Bool) + v0.AuxInt = int32ToAuxInt(1) + v0.AddArg(x) + v.AddArg(v0) + return true + } // match: (SETAE (InvertFlags x)) // result: (SETBE x) for { diff --git a/test/codegen/bool.go b/test/codegen/bool.go index 164ca1b2246aa3..2024759a5c530f 100644 --- a/test/codegen/bool.go +++ b/test/codegen/bool.go @@ -47,6 +47,7 @@ func convertNeqBool32(x uint32) bool { func convertEqBool32(x uint32) bool { // ppc64x:"RLDICL",-"CMPW","XOR",-"ISEL" + // amd64:"ANDL","XORL",-"BTL",-"SETCC" return x&1 == 0 } @@ -57,6 +58,7 @@ func convertNeqBool64(x uint64) bool { func convertEqBool64(x uint64) bool { // ppc64x:"RLDICL","XOR",-"CMP",-"ISEL" + // amd64:"ANDL","XORL",-"BTL",-"SETCC" return x&1 == 0 } From 1118da25148d20f0fc275dd7ce7a08bd4ac4bdf2 Mon Sep 17 00:00:00 2001 From: Diego Lara Date: Fri, 31 Jan 2025 20:57:20 +0000 Subject: [PATCH 202/397] text/template improved comparison error addresses issue #71421 Addresses issue #71421, improves the error message given for comparison. Previous error message did not specify the types causing conflict, just said incompatible types, new error message specifies the two types causing the issue. Change-Id: I9d940ab7573c2763a9d052445140ecd6d38cde5e GitHub-Last-Rev: 6fe7d8101317ea616fd9a8f3f430874b5f946d3e GitHub-Pull-Request: golang/go#71431 Reviewed-on: https://go-review.googlesource.com/c/go/+/644175 Reviewed-by: Cherry Mui Reviewed-by: Rob Pike Auto-Submit: Ian Lance Taylor Reviewed-by: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI --- src/text/template/funcs.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/text/template/funcs.go b/src/text/template/funcs.go index 7d63cf8b7bb6db..4d733135fe5a85 100644 --- a/src/text/template/funcs.go +++ b/src/text/template/funcs.go @@ -409,7 +409,6 @@ func not(arg reflect.Value) bool { var ( errBadComparisonType = errors.New("invalid type for comparison") - errBadComparison = errors.New("incompatible types for comparison") errNoComparison = errors.New("missing argument for comparison") ) @@ -487,7 +486,7 @@ func eq(arg1 reflect.Value, arg2 ...reflect.Value) (bool, error) { truth = arg.Int() >= 0 && arg1.Uint() == uint64(arg.Int()) default: if arg1.IsValid() && arg.IsValid() { - return false, errBadComparison + return false, fmt.Errorf("incompatible types for comparison: %v and %v", arg1.Type(), arg.Type()) } } } else { @@ -553,7 +552,7 @@ func lt(arg1, arg2 reflect.Value) (bool, error) { case k1 == uintKind && k2 == intKind: truth = arg2.Int() >= 0 && arg1.Uint() < uint64(arg2.Int()) default: - return false, errBadComparison + return false, fmt.Errorf("incompatible types for comparison: %v and %v", arg1.Type(), arg2.Type()) } } else { switch k1 { From 52e32ad79e50742f0d793d60eb52caab53a67061 Mon Sep 17 00:00:00 2001 From: qmuntal Date: Wed, 22 Jan 2025 12:26:10 +0100 Subject: [PATCH 203/397] crypto/x509/internal/macos: remove unused types and functions Some of the types and functions in the macos package are unused since CL 353132. They can be removed. Change-Id: Ifb7c9619d3c77b83852e785b82877dfa3ca8fe6f Reviewed-on: https://go-review.googlesource.com/c/go/+/643277 Auto-Submit: Roland Shoemaker Reviewed-by: Filippo Valsorda LUCI-TryBot-Result: Go LUCI Reviewed-by: Roland Shoemaker Reviewed-by: Cherry Mui --- src/crypto/x509/internal/macos/security.go | 92 ---------------------- src/crypto/x509/internal/macos/security.s | 6 -- 2 files changed, 98 deletions(-) diff --git a/src/crypto/x509/internal/macos/security.go b/src/crypto/x509/internal/macos/security.go index a6972c0c09dfe2..497ba6e824cd93 100644 --- a/src/crypto/x509/internal/macos/security.go +++ b/src/crypto/x509/internal/macos/security.go @@ -20,37 +20,6 @@ import ( // Based on https://opensource.apple.com/source/Security/Security-59306.41.2/base/Security.h -type SecTrustSettingsResult int32 - -const ( - SecTrustSettingsResultInvalid SecTrustSettingsResult = iota - SecTrustSettingsResultTrustRoot - SecTrustSettingsResultTrustAsRoot - SecTrustSettingsResultDeny - SecTrustSettingsResultUnspecified -) - -type SecTrustResultType int32 - -const ( - SecTrustResultInvalid SecTrustResultType = iota - SecTrustResultProceed - SecTrustResultConfirm // deprecated - SecTrustResultDeny - SecTrustResultUnspecified - SecTrustResultRecoverableTrustFailure - SecTrustResultFatalTrustFailure - SecTrustResultOtherError -) - -type SecTrustSettingsDomain int32 - -const ( - SecTrustSettingsDomainUser SecTrustSettingsDomain = iota - SecTrustSettingsDomainAdmin - SecTrustSettingsDomainSystem -) - const ( // various macOS error codes that can be returned from // SecTrustEvaluateWithError that we can map to Go cert @@ -69,54 +38,6 @@ func (s OSStatus) Error() string { return s.call + " error: " + strconv.Itoa(int(s.status)) } -// Dictionary keys are defined as build-time strings with CFSTR, but the Go -// linker's internal linking mode can't handle CFSTR relocations. Create our -// own dynamic strings instead and just never release them. -// -// Note that this might be the only thing that can break over time if -// these values change, as the ABI arguably requires using the strings -// pointed to by the symbols, not values that happen to be equal to them. - -var SecTrustSettingsResultKey = StringToCFString("kSecTrustSettingsResult") -var SecTrustSettingsPolicy = StringToCFString("kSecTrustSettingsPolicy") -var SecTrustSettingsPolicyString = StringToCFString("kSecTrustSettingsPolicyString") -var SecPolicyOid = StringToCFString("SecPolicyOid") -var SecPolicyAppleSSL = StringToCFString("1.2.840.113635.100.1.3") // defined by POLICYMACRO - -var ErrNoTrustSettings = errors.New("no trust settings found") - -const errSecNoTrustSettings = -25263 - -//go:cgo_import_dynamic x509_SecTrustSettingsCopyCertificates SecTrustSettingsCopyCertificates "/System/Library/Frameworks/Security.framework/Versions/A/Security" - -func SecTrustSettingsCopyCertificates(domain SecTrustSettingsDomain) (certArray CFRef, err error) { - ret := syscall(abi.FuncPCABI0(x509_SecTrustSettingsCopyCertificates_trampoline), uintptr(domain), - uintptr(unsafe.Pointer(&certArray)), 0, 0, 0, 0) - if int32(ret) == errSecNoTrustSettings { - return 0, ErrNoTrustSettings - } else if ret != 0 { - return 0, OSStatus{"SecTrustSettingsCopyCertificates", int32(ret)} - } - return certArray, nil -} -func x509_SecTrustSettingsCopyCertificates_trampoline() - -const errSecItemNotFound = -25300 - -//go:cgo_import_dynamic x509_SecTrustSettingsCopyTrustSettings SecTrustSettingsCopyTrustSettings "/System/Library/Frameworks/Security.framework/Versions/A/Security" - -func SecTrustSettingsCopyTrustSettings(cert CFRef, domain SecTrustSettingsDomain) (trustSettings CFRef, err error) { - ret := syscall(abi.FuncPCABI0(x509_SecTrustSettingsCopyTrustSettings_trampoline), uintptr(cert), uintptr(domain), - uintptr(unsafe.Pointer(&trustSettings)), 0, 0, 0) - if int32(ret) == errSecItemNotFound { - return 0, ErrNoTrustSettings - } else if ret != 0 { - return 0, OSStatus{"SecTrustSettingsCopyTrustSettings", int32(ret)} - } - return trustSettings, nil -} -func x509_SecTrustSettingsCopyTrustSettings_trampoline() - //go:cgo_import_dynamic x509_SecTrustCreateWithCertificates SecTrustCreateWithCertificates "/System/Library/Frameworks/Security.framework/Versions/A/Security" func SecTrustCreateWithCertificates(certs CFRef, policies CFRef) (CFRef, error) { @@ -184,19 +105,6 @@ func SecTrustEvaluate(trustObj CFRef) (CFRef, error) { } func x509_SecTrustEvaluate_trampoline() -//go:cgo_import_dynamic x509_SecTrustGetResult SecTrustGetResult "/System/Library/Frameworks/Security.framework/Versions/A/Security" - -func SecTrustGetResult(trustObj CFRef, result CFRef) (CFRef, CFRef, error) { - var chain, info CFRef - ret := syscall(abi.FuncPCABI0(x509_SecTrustGetResult_trampoline), uintptr(trustObj), uintptr(unsafe.Pointer(&result)), - uintptr(unsafe.Pointer(&chain)), uintptr(unsafe.Pointer(&info)), 0, 0) - if int32(ret) != 0 { - return 0, 0, OSStatus{"SecTrustGetResult", int32(ret)} - } - return chain, info, nil -} -func x509_SecTrustGetResult_trampoline() - //go:cgo_import_dynamic x509_SecTrustEvaluateWithError SecTrustEvaluateWithError "/System/Library/Frameworks/Security.framework/Versions/A/Security" func SecTrustEvaluateWithError(trustObj CFRef) (int, error) { diff --git a/src/crypto/x509/internal/macos/security.s b/src/crypto/x509/internal/macos/security.s index ed726f1127c8ce..dc630eccb7fe41 100644 --- a/src/crypto/x509/internal/macos/security.s +++ b/src/crypto/x509/internal/macos/security.s @@ -9,10 +9,6 @@ // The trampolines are ABIInternal as they are address-taken in // Go code. -TEXT ·x509_SecTrustSettingsCopyCertificates_trampoline(SB),NOSPLIT,$0-0 - JMP x509_SecTrustSettingsCopyCertificates(SB) -TEXT ·x509_SecTrustSettingsCopyTrustSettings_trampoline(SB),NOSPLIT,$0-0 - JMP x509_SecTrustSettingsCopyTrustSettings(SB) TEXT ·x509_SecTrustCreateWithCertificates_trampoline(SB),NOSPLIT,$0-0 JMP x509_SecTrustCreateWithCertificates(SB) TEXT ·x509_SecCertificateCreateWithData_trampoline(SB),NOSPLIT,$0-0 @@ -23,8 +19,6 @@ TEXT ·x509_SecTrustSetVerifyDate_trampoline(SB),NOSPLIT,$0-0 JMP x509_SecTrustSetVerifyDate(SB) TEXT ·x509_SecTrustEvaluate_trampoline(SB),NOSPLIT,$0-0 JMP x509_SecTrustEvaluate(SB) -TEXT ·x509_SecTrustGetResult_trampoline(SB),NOSPLIT,$0-0 - JMP x509_SecTrustGetResult(SB) TEXT ·x509_SecTrustEvaluateWithError_trampoline(SB),NOSPLIT,$0-0 JMP x509_SecTrustEvaluateWithError(SB) TEXT ·x509_SecTrustGetCertificateCount_trampoline(SB),NOSPLIT,$0-0 From 691b7ff1c7b92403dc6a5194ccf5e77f65dbb2bb Mon Sep 17 00:00:00 2001 From: Jakub Ciolek Date: Wed, 13 Nov 2024 11:34:50 +0100 Subject: [PATCH 204/397] internal/fuzz: use a lookup table for SnapshotCoverage Previously, the implementation used bit manipulation to approximate counters to the nearest power of two. Given the 0-255 range of byte, we can precompute values at initialization and use a lookup table, reducing runtime computation. Benchmarks show an 18% performance gain on AMD64 and 5% on ARM64. * net/netip/FuzzParse (n=10, t=60s, state reset per run) * AMD64 (Intel Alder Lake i5-12600k): 17,349,217 -> 20,487,756 execs/s * ARM64 (M3 Pro): 19,606,471 -> 20,657,041 execs/s * compress/gzip/FuzzReader (n=10, t=60s, mature corpus) * AMD64 (Intel Alder Lake i5-12600k): 5,655,956 -> 6,707,035 execs/s Change-Id: If11f7fe866f54c7cd2c5a48e251c027b67980df7 Reviewed-on: https://go-review.googlesource.com/c/go/+/627378 Reviewed-by: Cherry Mui LUCI-TryBot-Result: Go LUCI Reviewed-by: Roland Shoemaker Auto-Submit: Roland Shoemaker --- src/internal/fuzz/coverage.go | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/internal/fuzz/coverage.go b/src/internal/fuzz/coverage.go index e214a7bf3e1846..8b39949b5dd622 100644 --- a/src/internal/fuzz/coverage.go +++ b/src/internal/fuzz/coverage.go @@ -23,11 +23,7 @@ func ResetCoverage() { func SnapshotCoverage() { cov := coverage() for i, b := range cov { - b |= b >> 1 - b |= b >> 2 - b |= b >> 4 - b -= b >> 1 - coverageSnapshot[i] = b + coverageSnapshot[i] = pow2Table[b] } } @@ -102,4 +98,18 @@ var ( // the 8-bit coverage counters reside in memory. They're known to cmd/link, // which specially assigns their addresses for this purpose. _counters, _ecounters [0]byte + + // lookup table for faster power of two rounding + pow2Table [256]byte ) + +func init() { + for i := range pow2Table { + b := byte(i) + b |= b >> 1 + b |= b >> 2 + b |= b >> 4 + b -= b >> 1 + pow2Table[i] = b + } +} From 3a81ebea0de65aa877f46afb80575ec67b7d9170 Mon Sep 17 00:00:00 2001 From: cuishuang Date: Wed, 1 Jan 2025 09:08:26 +0800 Subject: [PATCH 205/397] net/http: use strings.FieldsFuncSeq to reduce memory allocations After using strings.FieldsFuncSeq, the number of memory allocations has been reduced from 2 to 0. The following is the complete benchamark code and results: package main import ( "strings" "testing" ) func isSlashRune(r rune) bool { return r == '/' || r == '\\' } func containsDotDotLoop(v string) bool { if !strings.Contains(v, "..") { return false } for _, ent := range strings.FieldsFunc(v, isSlashRune) { if ent == ".." { return true } } return false } func containsDotDotSeq(v string) bool { if !strings.Contains(v, "..") { return false } for ent := range strings.FieldsFuncSeq(v, isSlashRune) { if ent == ".." { return true } } return false } func BenchmarkDotDot(b *testing.B) { testCases := []string{ "/path/to/somewhere", "/path/../to/somewhere", "/really/long/path/with/many/segments", "../../../deep/path", } b.Run("Loop", func(b *testing.B) { for i := 0; i < b.N; i++ { for _, tc := range testCases { containsDotDotLoop(tc) } } }) b.Run("Seq", func(b *testing.B) { for i := 0; i < b.N; i++ { for _, tc := range testCases { containsDotDotSeq(tc) } } }) } go test -bench=. -benchmem goos: darwin goarch: arm64 pkg: bc cpu: Apple M1 BenchmarkDotDot/Loop-8 6133270 193.7 ns/op 144 B/op 2 allocs/op BenchmarkDotDot/Seq-8 23172360 51.19 ns/op 0 B/op 0 allocs/op PASS ok bc 2.633s Change-Id: I529c296e701b22710e21b53877aa798799980a3b Reviewed-on: https://go-review.googlesource.com/c/go/+/639536 Reviewed-by: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Auto-Submit: Ian Lance Taylor Reviewed-by: Cherry Mui --- src/net/http/fs.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/net/http/fs.go b/src/net/http/fs.go index 3a716fbd2cc7f8..e990f196d6d904 100644 --- a/src/net/http/fs.go +++ b/src/net/http/fs.go @@ -854,7 +854,7 @@ func containsDotDot(v string) bool { if !strings.Contains(v, "..") { return false } - for _, ent := range strings.FieldsFunc(v, isSlashRune) { + for ent := range strings.FieldsFuncSeq(v, isSlashRune) { if ent == ".." { return true } From 3caf5bd09e84f77cc5e0394819d57a1beca87fcb Mon Sep 17 00:00:00 2001 From: Sean Liao Date: Sat, 1 Feb 2025 16:42:22 +0000 Subject: [PATCH 206/397] text/scanner: add required ScanComments in example Fixes #71133 Change-Id: I11f792bf4cb275e7bc3585cd92a4b327a3b6e368 Reviewed-on: https://go-review.googlesource.com/c/go/+/646036 Reviewed-by: Ian Lance Taylor Auto-Submit: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Reviewed-by: Cherry Mui --- src/text/scanner/scanner.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/text/scanner/scanner.go b/src/text/scanner/scanner.go index 6ae7a9b987423b..316fb4380f753c 100644 --- a/src/text/scanner/scanner.go +++ b/src/text/scanner/scanner.go @@ -50,7 +50,7 @@ func (pos Position) String() string { // to configure a [Scanner] such that it only recognizes (Go) identifiers, // integers, and skips comments, set the Scanner's Mode field to: // -// ScanIdents | ScanInts | SkipComments +// ScanIdents | ScanInts | ScanComments | SkipComments // // With the exceptions of comments, which are skipped if SkipComments is // set, unrecognized tokens are not ignored. Instead, the scanner simply From 39ceaf79614ac7a8874c086ec3c012464f710aca Mon Sep 17 00:00:00 2001 From: cuishuang Date: Wed, 1 Jan 2025 00:17:54 +0800 Subject: [PATCH 207/397] all: use slices.Contains to simplify code Change-Id: I9ef075bbb0e3c65f3c2a9d49e599ef50b18aa9be Reviewed-on: https://go-review.googlesource.com/c/go/+/639535 LUCI-TryBot-Result: Go LUCI Reviewed-by: Cherry Mui Auto-Submit: Ian Lance Taylor Reviewed-by: Ian Lance Taylor --- src/cmd/dist/test.go | 8 ++------ src/cmd/go/internal/modindex/build.go | 20 +++---------------- src/crypto/tls/handshake_server_tls13.go | 7 +------ src/go/build/build.go | 19 ++---------------- .../reflectlite/reflect_mirror_test.go | 8 ++------ src/internal/trace/order.go | 8 ++------ src/os/user/user_test.go | 12 ++--------- src/os/user/user_windows_test.go | 3 ++- src/syscall/syscall_linux.go | 8 ++------ 9 files changed, 18 insertions(+), 75 deletions(-) diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index 58e87f16c05024..ba273d79234b3a 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -18,6 +18,7 @@ import ( "reflect" "regexp" "runtime" + "slices" "strconv" "strings" "time" @@ -280,12 +281,7 @@ func (t *tester) shouldRunTest(name string) bool { if len(t.runNames) == 0 { return true } - for _, runName := range t.runNames { - if runName == name { - return true - } - } - return false + return slices.Contains(t.runNames, name) } func (t *tester) maybeLogMetadata() error { diff --git a/src/cmd/go/internal/modindex/build.go b/src/cmd/go/internal/modindex/build.go index 542d6fbbbba390..d7e09fed25f43a 100644 --- a/src/cmd/go/internal/modindex/build.go +++ b/src/cmd/go/internal/modindex/build.go @@ -21,6 +21,7 @@ import ( "io" "io/fs" "path/filepath" + "slices" "sort" "strings" "unicode" @@ -887,23 +888,8 @@ func (ctxt *Context) matchTag(name string, allTags map[string]bool) bool { } // other tags - for _, tag := range ctxt.BuildTags { - if tag == name { - return true - } - } - for _, tag := range ctxt.ToolTags { - if tag == name { - return true - } - } - for _, tag := range ctxt.ReleaseTags { - if tag == name { - return true - } - } - - return false + return slices.Contains(ctxt.BuildTags, name) || slices.Contains(ctxt.ToolTags, name) || + slices.Contains(ctxt.ReleaseTags, name) } // goodOSArchFile returns false if the name contains a $GOOS or $GOARCH diff --git a/src/crypto/tls/handshake_server_tls13.go b/src/crypto/tls/handshake_server_tls13.go index 76fff6974e7403..b6d455cd397e31 100644 --- a/src/crypto/tls/handshake_server_tls13.go +++ b/src/crypto/tls/handshake_server_tls13.go @@ -949,12 +949,7 @@ func (hs *serverHandshakeStateTLS13) shouldSendSessionTickets() bool { } // Don't send tickets the client wouldn't use. See RFC 8446, Section 4.2.9. - for _, pskMode := range hs.clientHello.pskModes { - if pskMode == pskModeDHE { - return true - } - } - return false + return slices.Contains(hs.clientHello.pskModes, pskModeDHE) } func (hs *serverHandshakeStateTLS13) sendSessionTickets() error { diff --git a/src/go/build/build.go b/src/go/build/build.go index 9ffffda08a99b1..0e5c7e512d794c 100644 --- a/src/go/build/build.go +++ b/src/go/build/build.go @@ -1985,23 +1985,8 @@ func (ctxt *Context) matchTag(name string, allTags map[string]bool) bool { } // other tags - for _, tag := range ctxt.BuildTags { - if tag == name { - return true - } - } - for _, tag := range ctxt.ToolTags { - if tag == name { - return true - } - } - for _, tag := range ctxt.ReleaseTags { - if tag == name { - return true - } - } - - return false + return slices.Contains(ctxt.BuildTags, name) || slices.Contains(ctxt.ToolTags, name) || + slices.Contains(ctxt.ReleaseTags, name) } // goodOSArchFile returns false if the name contains a $GOOS or $GOARCH diff --git a/src/internal/reflectlite/reflect_mirror_test.go b/src/internal/reflectlite/reflect_mirror_test.go index c87573903454ed..8d13641516341a 100644 --- a/src/internal/reflectlite/reflect_mirror_test.go +++ b/src/internal/reflectlite/reflect_mirror_test.go @@ -13,6 +13,7 @@ import ( "os" "path/filepath" "runtime" + "slices" "strings" "sync" "testing" @@ -40,12 +41,7 @@ func newVisitor() visitor { return v } func (v visitor) filter(name string) bool { - for _, typeName := range typeNames { - if typeName == name { - return true - } - } - return false + return slices.Contains(typeNames, name) } func (v visitor) Visit(n ast.Node) ast.Visitor { diff --git a/src/internal/trace/order.go b/src/internal/trace/order.go index d0818a500c03c8..8a1261330175ac 100644 --- a/src/internal/trace/order.go +++ b/src/internal/trace/order.go @@ -6,6 +6,7 @@ package trace import ( "fmt" + "slices" "strings" "internal/trace/event" @@ -1254,12 +1255,7 @@ func (s *rangeState) activeRange(typ rangeType, isInitialGen bool) error { // hasRange returns true if a special time range on the goroutine as in progress. func (s *rangeState) hasRange(typ rangeType) bool { - for _, ftyp := range s.inFlight { - if ftyp == typ { - return true - } - } - return false + return slices.Contains(s.inFlight, typ) } // endRange ends a special range in time on the goroutine. diff --git a/src/os/user/user_test.go b/src/os/user/user_test.go index 31486aed033819..0e06369bf5a5da 100644 --- a/src/os/user/user_test.go +++ b/src/os/user/user_test.go @@ -6,6 +6,7 @@ package user import ( "os" + "slices" "testing" ) @@ -178,16 +179,7 @@ func TestGroupIds(t *testing.T) { if err != nil { t.Fatalf("%+v.GroupIds(): %v", user, err) } - if !containsID(gids, user.Gid) { + if !slices.Contains(gids, user.Gid) { t.Errorf("%+v.GroupIds() = %v; does not contain user GID %s", user, gids, user.Gid) } } - -func containsID(ids []string, id string) bool { - for _, x := range ids { - if x == id { - return true - } - } - return false -} diff --git a/src/os/user/user_windows_test.go b/src/os/user/user_windows_test.go index c71503372e0107..7dca2fc5f94a16 100644 --- a/src/os/user/user_windows_test.go +++ b/src/os/user/user_windows_test.go @@ -14,6 +14,7 @@ import ( "os" "os/exec" "runtime" + "slices" "strconv" "syscall" "testing" @@ -205,7 +206,7 @@ func TestGroupIdsTestUser(t *testing.T) { if err != nil { t.Fatalf("%+v.GroupIds(): %v", user, err) } - if !containsID(gids, user.Gid) { + if !slices.Contains(gids, user.Gid) { t.Errorf("%+v.GroupIds() = %v; does not contain user GID %s", user, gids, user.Gid) } } diff --git a/src/syscall/syscall_linux.go b/src/syscall/syscall_linux.go index 003f7a538c581f..57d84748fe56d7 100644 --- a/src/syscall/syscall_linux.go +++ b/src/syscall/syscall_linux.go @@ -15,6 +15,7 @@ import ( "internal/itoa" runtimesyscall "internal/runtime/syscall" "runtime" + "slices" "unsafe" ) @@ -134,12 +135,7 @@ func isGroupMember(gid int) bool { return false } - for _, g := range groups { - if g == gid { - return true - } - } - return false + return slices.Contains(groups, gid) } func isCapDacOverrideSet() bool { From 66e6f5c9202ae98c3e1d3830972cd13559fb28f2 Mon Sep 17 00:00:00 2001 From: Michael Matloob Date: Tue, 3 Sep 2024 11:19:39 -0400 Subject: [PATCH 208/397] cmd/doc: add support for starting pkgsite instance for docs This change adds a new flag "-http" to cmd/doc which enables starting a pkgsite instance. -http will start a pkgsite instance and navigate to the page for the requested package, at the anchor for the item requested. For #68106 Change-Id: Ic1c113795cb2e1035e99c89c8e972c799342385b Reviewed-on: https://go-review.googlesource.com/c/go/+/628175 LUCI-TryBot-Result: Go LUCI Reviewed-by: Sam Thanawalla Reviewed-by: Jonathan Amsterdam Reviewed-by: Alan Donovan --- src/cmd/doc/main.go | 99 +++++++++++++++++++++++++++++++++++ src/cmd/doc/signal_notunix.go | 13 +++++ src/cmd/doc/signal_unix.go | 14 +++++ 3 files changed, 126 insertions(+) create mode 100644 src/cmd/doc/signal_notunix.go create mode 100644 src/cmd/doc/signal_unix.go diff --git a/src/cmd/doc/main.go b/src/cmd/doc/main.go index 502de097f50688..a199991c21d42e 100644 --- a/src/cmd/doc/main.go +++ b/src/cmd/doc/main.go @@ -44,17 +44,26 @@ package main import ( "bytes" + "context" + "errors" "flag" "fmt" "go/build" "go/token" "io" "log" + "net" + "net/http" "os" + "os/exec" + "os/signal" "path" "path/filepath" "strings" + "time" + "cmd/internal/browser" + "cmd/internal/quoted" "cmd/internal/telemetry/counter" ) @@ -66,6 +75,7 @@ var ( showCmd bool // -cmd flag showSrc bool // -src flag short bool // -short flag + serveHTTP bool // -http flag ) // usage is a replacement usage function for the flags package. @@ -107,6 +117,7 @@ func do(writer io.Writer, flagSet *flag.FlagSet, args []string) (err error) { flagSet.BoolVar(&showCmd, "cmd", false, "show symbols with package docs even if package is a command") flagSet.BoolVar(&showSrc, "src", false, "show source code for symbol") flagSet.BoolVar(&short, "short", false, "one-line representation for each symbol") + flagSet.BoolVar(&serveHTTP, "http", false, "serve HTML docs over HTTP") flagSet.Parse(args) counter.Inc("doc/invocations") counter.CountFlags("doc/flag:", *flag.CommandLine) @@ -152,6 +163,9 @@ func do(writer io.Writer, flagSet *flag.FlagSet, args []string) (err error) { panic(e) }() + if serveHTTP { + return doPkgsite(pkg, symbol, method) + } switch { case symbol == "": pkg.packageDoc() // The package exists, so we got some output. @@ -168,6 +182,91 @@ func do(writer io.Writer, flagSet *flag.FlagSet, args []string) (err error) { } } +func doPkgsite(pkg *Package, symbol, method string) error { + ctx := context.Background() + + cmdline := "go run golang.org/x/pkgsite/cmd/pkgsite@latest -gorepo=" + buildCtx.GOROOT + words, err := quoted.Split(cmdline) + port, err := pickUnusedPort() + if err != nil { + return fmt.Errorf("failed to find port for documentation server: %v", err) + } + addr := fmt.Sprintf("localhost:%d", port) + words = append(words, fmt.Sprintf("-http=%s", addr)) + cmd := exec.CommandContext(context.Background(), words[0], words[1:]...) + cmd.Stdout = os.Stderr + cmd.Stderr = os.Stderr + // Turn off the default signal handler for SIGINT (and SIGQUIT on Unix) + // and instead wait for the child process to handle the signal and + // exit before exiting ourselves. + signal.Ignore(signalsToIgnore...) + + if err := cmd.Start(); err != nil { + return fmt.Errorf("starting pkgsite: %v", err) + } + + // Wait for pkgsite to became available. + if !waitAvailable(ctx, addr) { + cmd.Cancel() + cmd.Wait() + return errors.New("could not connect to local documentation server") + } + + // Open web browser. + path := path.Join("http://"+addr, pkg.build.ImportPath) + object := symbol + if symbol != "" && method != "" { + object = symbol + "." + method + } + if object != "" { + path = path + "#" + object + } + if ok := browser.Open(path); !ok { + cmd.Cancel() + cmd.Wait() + return errors.New("failed to open browser") + } + + // Wait for child to terminate. We expect the child process to receive signals from + // this terminal and terminate in a timely manner, so this process will terminate + // soon after. + return cmd.Wait() +} + +// pickUnusedPort finds an unused port by trying to listen on port 0 +// and letting the OS pick a port, then closing that connection and +// returning that port number. +// This is inherently racy. +func pickUnusedPort() (int, error) { + l, err := net.Listen("tcp", "localhost:0") + if err != nil { + return 0, err + } + port := l.Addr().(*net.TCPAddr).Port + if err := l.Close(); err != nil { + return 0, err + } + return port, nil +} + +func waitAvailable(ctx context.Context, addr string) bool { + ctx, cancel := context.WithTimeout(ctx, 15*time.Second) + defer cancel() + for ctx.Err() == nil { + req, err := http.NewRequestWithContext(ctx, "HEAD", "http://"+addr, nil) + if err != nil { + log.Println(err) + return false + } + resp, err := http.DefaultClient.Do(req) + if err == nil { + resp.Body.Close() + return true + } + } + return false +} + // failMessage creates a nicely formatted error message when there is no result to show. func failMessage(paths []string, symbol, method string) error { var b bytes.Buffer diff --git a/src/cmd/doc/signal_notunix.go b/src/cmd/doc/signal_notunix.go new file mode 100644 index 00000000000000..3b8fa9e080354d --- /dev/null +++ b/src/cmd/doc/signal_notunix.go @@ -0,0 +1,13 @@ +// Copyright 2012 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. + +//go:build plan9 || windows + +package main + +import ( + "os" +) + +var signalsToIgnore = []os.Signal{os.Interrupt} diff --git a/src/cmd/doc/signal_unix.go b/src/cmd/doc/signal_unix.go new file mode 100644 index 00000000000000..52431c221b5ba1 --- /dev/null +++ b/src/cmd/doc/signal_unix.go @@ -0,0 +1,14 @@ +// Copyright 2012 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. + +//go:build unix || js || wasip1 + +package main + +import ( + "os" + "syscall" +) + +var signalsToIgnore = []os.Signal{os.Interrupt, syscall.SIGQUIT} From 77f5ecef3a4f30644eadb922a8ba5deb76fa8e07 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 13 Jan 2025 10:24:50 -0800 Subject: [PATCH 209/397] all: run gofmt Change-Id: I0af1903ed1e4f2bf4ea273847b024520c577ef6d Reviewed-on: https://go-review.googlesource.com/c/go/+/642496 Reviewed-by: Dmitri Shuralyov LUCI-TryBot-Result: Go LUCI Reviewed-by: Dmitri Shuralyov Reviewed-by: Cherry Mui Auto-Submit: Ian Lance Taylor --- src/cmd/internal/objabi/path_test.go | 36 +++++++++++++------------- src/cmd/internal/pgo/deserialize.go | 2 +- src/cmd/internal/pgo/pgo.go | 1 - src/cmd/internal/pgo/serialize_test.go | 20 +++++++------- src/encoding/xml/xml_test.go | 4 +-- src/reflect/all_test.go | 4 +-- src/runtime/traceback_system_test.go | 4 +-- 7 files changed, 35 insertions(+), 36 deletions(-) diff --git a/src/cmd/internal/objabi/path_test.go b/src/cmd/internal/objabi/path_test.go index 2f57882efad8b4..676f794292ab0d 100644 --- a/src/cmd/internal/objabi/path_test.go +++ b/src/cmd/internal/objabi/path_test.go @@ -12,24 +12,24 @@ import ( ) var escapeTests = []struct { - Path string - Escaped string - }{ - {"foo/bar/v1", "foo/bar/v1"}, - {"foo/bar/v.1", "foo/bar/v%2e1"}, - {"f.o.o/b.a.r/v1", "f.o.o/b.a.r/v1"}, - {"f.o.o/b.a.r/v.1", "f.o.o/b.a.r/v%2e1"}, - {"f.o.o/b.a.r/v..1", "f.o.o/b.a.r/v%2e%2e1"}, - {"f.o.o/b.a.r/v..1.", "f.o.o/b.a.r/v%2e%2e1%2e"}, - {"f.o.o/b.a.r/v%1", "f.o.o/b.a.r/v%251"}, - {"runtime", "runtime"}, - {"sync/atomic", "sync/atomic"}, - {"golang.org/x/tools/godoc", "golang.org/x/tools/godoc"}, - {"foo.bar/baz.quux", "foo.bar/baz%2equux"}, - {"", ""}, - {"%foo%bar", "%25foo%25bar"}, - {"\x01\x00\x7F☺", "%01%00%7f%e2%98%ba"}, - } + Path string + Escaped string +}{ + {"foo/bar/v1", "foo/bar/v1"}, + {"foo/bar/v.1", "foo/bar/v%2e1"}, + {"f.o.o/b.a.r/v1", "f.o.o/b.a.r/v1"}, + {"f.o.o/b.a.r/v.1", "f.o.o/b.a.r/v%2e1"}, + {"f.o.o/b.a.r/v..1", "f.o.o/b.a.r/v%2e%2e1"}, + {"f.o.o/b.a.r/v..1.", "f.o.o/b.a.r/v%2e%2e1%2e"}, + {"f.o.o/b.a.r/v%1", "f.o.o/b.a.r/v%251"}, + {"runtime", "runtime"}, + {"sync/atomic", "sync/atomic"}, + {"golang.org/x/tools/godoc", "golang.org/x/tools/godoc"}, + {"foo.bar/baz.quux", "foo.bar/baz%2equux"}, + {"", ""}, + {"%foo%bar", "%25foo%25bar"}, + {"\x01\x00\x7F☺", "%01%00%7f%e2%98%ba"}, +} func TestPathToPrefix(t *testing.T) { for _, tc := range escapeTests { diff --git a/src/cmd/internal/pgo/deserialize.go b/src/cmd/internal/pgo/deserialize.go index 4b075b8daf7fdd..dd26da2aa9929b 100644 --- a/src/cmd/internal/pgo/deserialize.go +++ b/src/cmd/internal/pgo/deserialize.go @@ -8,8 +8,8 @@ import ( "bufio" "fmt" "io" - "strings" "strconv" + "strings" ) // IsSerialized returns true if r is a serialized Profile. diff --git a/src/cmd/internal/pgo/pgo.go b/src/cmd/internal/pgo/pgo.go index 1d2cb880f744f8..3a0e01e8c27718 100644 --- a/src/cmd/internal/pgo/pgo.go +++ b/src/cmd/internal/pgo/pgo.go @@ -52,4 +52,3 @@ func emptyProfile() *Profile { func WeightInPercentage(value int64, total int64) float64 { return (float64(value) / float64(total)) * 100 } - diff --git a/src/cmd/internal/pgo/serialize_test.go b/src/cmd/internal/pgo/serialize_test.go index b24163d1e29432..9aef67c3670467 100644 --- a/src/cmd/internal/pgo/serialize_test.go +++ b/src/cmd/internal/pgo/serialize_test.go @@ -67,25 +67,25 @@ func TestRoundTrip(t *testing.T) { NamedEdgeMap: NamedEdgeMap{ ByWeight: []NamedCallEdge{ { - CallerName: "a", - CalleeName: "b", + CallerName: "a", + CalleeName: "b", CallSiteOffset: 14, }, { - CallerName: "c", - CalleeName: "d", + CallerName: "c", + CalleeName: "d", CallSiteOffset: 15, }, }, Weight: map[NamedCallEdge]int64{ { - CallerName: "a", - CalleeName: "b", + CallerName: "a", + CalleeName: "b", CallSiteOffset: 14, }: 2, { - CallerName: "c", - CalleeName: "d", + CallerName: "c", + CalleeName: "d", CallSiteOffset: 15, }: 1, }, @@ -157,8 +157,8 @@ func constructFuzzProfile(t *testing.T, b []byte) *Profile { } edge := NamedCallEdge{ - CallerName: caller, - CalleeName: callee, + CallerName: caller, + CalleeName: callee, CallSiteOffset: int(line), } diff --git a/src/encoding/xml/xml_test.go b/src/encoding/xml/xml_test.go index fc3c15eff1b689..10cefa068fec87 100644 --- a/src/encoding/xml/xml_test.go +++ b/src/encoding/xml/xml_test.go @@ -640,11 +640,11 @@ func TestIssue68387(t *testing.T) { if tok3, err = dec.RawToken(); err != io.EOF || tok3 != nil { t.Fatalf("Missed EOF") } - s := StartElement{Name{"", "item"}, []Attr{Attr{Name{"","b"}, "]]>"}}} + s := StartElement{Name{"", "item"}, []Attr{Attr{Name{"", "b"}, "]]>"}}} if !reflect.DeepEqual(tok1.(StartElement), s) { t.Error("Wrong start element") } - e := EndElement{Name{"","item"}} + e := EndElement{Name{"", "item"}} if tok2.(EndElement) != e { t.Error("Wrong end element") } diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index b2f70c13697735..3d1e410dac6323 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -6322,12 +6322,12 @@ func TestMapOfGCBigKey(t *testing.T) { const n = 100 m := MakeMap(mt) for i := 0; i < n; i++ { - kv := KV{int64(i), int64(i+1)} + kv := KV{int64(i), int64(i + 1)} m.SetMapIndex(ValueOf(kv), ValueOf(kv)) } for i := 0; i < n; i++ { - kv := KV{int64(i), int64(i+1)} + kv := KV{int64(i), int64(i + 1)} elem := m.MapIndex(ValueOf(kv)).Interface().(KV) if elem != kv { t.Errorf("lost m[%v] = %v, want %v", kv, elem, kv) diff --git a/src/runtime/traceback_system_test.go b/src/runtime/traceback_system_test.go index af20f54a0946fc..3a3f33bbd41005 100644 --- a/src/runtime/traceback_system_test.go +++ b/src/runtime/traceback_system_test.go @@ -129,7 +129,7 @@ func TestTracebackSystem(t *testing.T) { t.Skip("Can't read source code for this file on Android") } - tests := []struct{ + tests := []struct { name string want string }{ @@ -326,7 +326,7 @@ func parseStackPCs(crash string) ([]uintptr, error) { continue } - pc = pc-parentSentinel+childSentinel + pc = pc - parentSentinel + childSentinel // If the previous frame was sigpanic, then this frame // was a trap (e.g., SIGSEGV). From 82337de9f2157a132257b2e2fe5ae8f1ad57ff20 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 3 Feb 2025 09:50:38 -0800 Subject: [PATCH 210/397] test/issue71226: add cast to avoid clang error Change-Id: I2d8ecb7b5f48943697d454d09947fdb1817809d0 Reviewed-on: https://go-review.googlesource.com/c/go/+/646295 TryBot-Bypass: Ian Lance Taylor Reviewed-by: Ian Lance Taylor Auto-Submit: Ian Lance Taylor Reviewed-by: Robert Griesemer Auto-Submit: Ian Lance Taylor --- test/fixedbugs/issue71226.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/fixedbugs/issue71226.go b/test/fixedbugs/issue71226.go index 704814b6013b45..5df05e3b29c86d 100644 --- a/test/fixedbugs/issue71226.go +++ b/test/fixedbugs/issue71226.go @@ -14,7 +14,7 @@ package main #include static void CFn(_GoString_ gostr) { - printf("%.*s\n", _GoStringLen(gostr), _GoStringPtr(gostr)); + printf("%.*s\n", (int)(_GoStringLen(gostr)), _GoStringPtr(gostr)); } */ import "C" From 439d39a719da12c213aeb69a09c5aaef83d9df67 Mon Sep 17 00:00:00 2001 From: Sean Liao Date: Sun, 1 Dec 2024 20:06:26 +0000 Subject: [PATCH 211/397] all: replace reflect.Value.Type.Kind with reflect.Value.Kind Fixes #46107 Change-Id: I170f3cacda652752cd740e04b565a616a0e43fd1 Reviewed-on: https://go-review.googlesource.com/c/go/+/632635 Reviewed-by: Rob Pike Reviewed-by: Cherry Mui Commit-Queue: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Reviewed-by: Ian Lance Taylor Auto-Submit: Ian Lance Taylor --- src/cmd/fix/cftype.go | 4 ++-- src/encoding/gob/decoder.go | 2 +- src/encoding/gob/encode.go | 2 +- src/encoding/xml/read.go | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/cmd/fix/cftype.go b/src/cmd/fix/cftype.go index d4fcc4485e5791..04ece9fe5b4079 100644 --- a/src/cmd/fix/cftype.go +++ b/src/cmd/fix/cftype.go @@ -67,14 +67,14 @@ func typefix(f *ast.File, badType func(string) bool) bool { return } v := reflect.ValueOf(n) - if v.Type().Kind() != reflect.Pointer { + if v.Kind() != reflect.Pointer { return } if v.IsNil() { return } v = v.Elem() - if v.Type().Kind() != reflect.Struct { + if v.Kind() != reflect.Struct { return } for i := 0; i < v.NumField(); i++ { diff --git a/src/encoding/gob/decoder.go b/src/encoding/gob/decoder.go index eae307838e201e..c35398d1054e9e 100644 --- a/src/encoding/gob/decoder.go +++ b/src/encoding/gob/decoder.go @@ -199,7 +199,7 @@ func (dec *Decoder) Decode(e any) error { value := reflect.ValueOf(e) // If e represents a value as opposed to a pointer, the answer won't // get back to the caller. Make sure it's a pointer. - if value.Type().Kind() != reflect.Pointer { + if value.Kind() != reflect.Pointer { dec.err = errors.New("gob: attempt to decode into a non-pointer") return dec.err } diff --git a/src/encoding/gob/encode.go b/src/encoding/gob/encode.go index 5f4d2539faafe3..ed3494218ce70e 100644 --- a/src/encoding/gob/encode.go +++ b/src/encoding/gob/encode.go @@ -662,7 +662,7 @@ func (enc *Encoder) encode(b *encBuffer, value reflect.Value, ut *userTypeInfo) for i := 0; i < indir; i++ { value = reflect.Indirect(value) } - if ut.externalEnc == 0 && value.Type().Kind() == reflect.Struct { + if ut.externalEnc == 0 && value.Kind() == reflect.Struct { enc.encodeStruct(b, engine, value) } else { enc.encodeSingle(b, engine, value) diff --git a/src/encoding/xml/read.go b/src/encoding/xml/read.go index 3cc4968c762f3b..af25c20f0618dc 100644 --- a/src/encoding/xml/read.go +++ b/src/encoding/xml/read.go @@ -280,7 +280,7 @@ func (d *Decoder) unmarshalAttr(val reflect.Value, attr Attr) error { } } - if val.Type().Kind() == reflect.Slice && val.Type().Elem().Kind() != reflect.Uint8 { + if val.Kind() == reflect.Slice && val.Type().Elem().Kind() != reflect.Uint8 { // Slice of element values. // Grow slice. n := val.Len() From 26c59d3153a7662875e1dd7c02c6ae36b9bc269b Mon Sep 17 00:00:00 2001 From: qmuntal Date: Tue, 17 Dec 2024 10:51:36 +0100 Subject: [PATCH 212/397] crypto/internal/fips140/sha3/_asm: remove unnecessary x/crypto dependency There is no need to blank-import golang.org/x/crypto/sha3, as we are not using any crypto.SHA3 variant in the code. Change-Id: Ia5455647f737371fc4ec0972bf9a90d5ee854495 Reviewed-on: https://go-review.googlesource.com/c/go/+/637055 Reviewed-by: Filippo Valsorda Reviewed-by: Cherry Mui Reviewed-by: Dmitri Shuralyov LUCI-TryBot-Result: Go LUCI --- src/crypto/internal/fips140/sha3/_asm/go.mod | 6 +----- src/crypto/internal/fips140/sha3/_asm/go.sum | 4 ---- src/crypto/internal/fips140/sha3/_asm/keccakf_amd64_asm.go | 1 - 3 files changed, 1 insertion(+), 10 deletions(-) diff --git a/src/crypto/internal/fips140/sha3/_asm/go.mod b/src/crypto/internal/fips140/sha3/_asm/go.mod index 265a88d077dd1f..39e83acc943061 100644 --- a/src/crypto/internal/fips140/sha3/_asm/go.mod +++ b/src/crypto/internal/fips140/sha3/_asm/go.mod @@ -2,14 +2,10 @@ module sha3/_asm go 1.22 -require ( - github.com/mmcloughlin/avo v0.6.0 - golang.org/x/crypto v0.25.0 -) +require github.com/mmcloughlin/avo v0.6.0 require ( golang.org/x/mod v0.19.0 // indirect golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.22.0 // indirect golang.org/x/tools v0.23.0 // indirect ) diff --git a/src/crypto/internal/fips140/sha3/_asm/go.sum b/src/crypto/internal/fips140/sha3/_asm/go.sum index a2552b8eb9ad32..9e8f35f70fc70d 100644 --- a/src/crypto/internal/fips140/sha3/_asm/go.sum +++ b/src/crypto/internal/fips140/sha3/_asm/go.sum @@ -1,12 +1,8 @@ github.com/mmcloughlin/avo v0.6.0 h1:QH6FU8SKoTLaVs80GA8TJuLNkUYl4VokHKlPhVDg4YY= github.com/mmcloughlin/avo v0.6.0/go.mod h1:8CoAGaCSYXtCPR+8y18Y9aB/kxb8JSS6FRI7mSkvD+8= -golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= -golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= -golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= diff --git a/src/crypto/internal/fips140/sha3/_asm/keccakf_amd64_asm.go b/src/crypto/internal/fips140/sha3/_asm/keccakf_amd64_asm.go index 02242c9a015d57..5e59b11fc87a3b 100644 --- a/src/crypto/internal/fips140/sha3/_asm/keccakf_amd64_asm.go +++ b/src/crypto/internal/fips140/sha3/_asm/keccakf_amd64_asm.go @@ -13,7 +13,6 @@ import ( . "github.com/mmcloughlin/avo/build" . "github.com/mmcloughlin/avo/operand" . "github.com/mmcloughlin/avo/reg" - _ "golang.org/x/crypto/sha3" ) //go:generate go run . -out ../sha3_amd64.s From 41298239cf8b0de14fd3ac43e4af65fad6ab5cc4 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 28 Jan 2025 11:27:22 -0800 Subject: [PATCH 213/397] all: remove coverageredesign experiment The coverageredesign experiment was turned on by default by CL 436236 in September, 2022. We've documented it and people are using it. This CL removes the ability to turn off the experiment. This removes some old code that is no longer being executed. For #51430 Change-Id: I88d4998c8b5ea98eef8145d7ca6ebd96f64fbc2b Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest,gotip-darwin-amd64-longtest,gotip-linux-arm64-longtest,gotip-windows-amd64-longtest Reviewed-on: https://go-review.googlesource.com/c/go/+/644997 LUCI-TryBot-Result: Go LUCI Reviewed-by: Ian Lance Taylor Auto-Submit: Ian Lance Taylor Reviewed-by: Than McIntosh Reviewed-by: Cherry Mui Commit-Queue: Ian Lance Taylor --- src/cmd/compile/internal/test/inl_test.go | 4 - src/cmd/covdata/tool_test.go | 4 - src/cmd/go/alldocs.go | 1 - src/cmd/go/internal/help/helpdoc.go | 1 - src/cmd/go/internal/list/list.go | 6 +- src/cmd/go/internal/load/pkg.go | 97 +++------- src/cmd/go/internal/load/test.go | 171 +----------------- src/cmd/go/internal/run/run.go | 6 +- src/cmd/go/internal/test/test.go | 10 +- src/cmd/go/internal/work/build.go | 35 +--- src/cmd/go/internal/work/exec.go | 81 +++------ .../script/cover_build_cmdline_pkgs.txt | 1 - .../script/cover_build_pkg_select.txt | 3 - .../go/testdata/script/cover_build_simple.txt | 3 - .../script/cover_coverpkg_partial.txt | 1 - .../script/cover_coverpkg_with_init.txt | 1 - src/cmd/go/testdata/script/cover_list.txt | 1 - .../script/cover_main_import_path.txt | 1 - .../go/testdata/script/cover_statements.txt | 15 +- .../script/cover_sync_atomic_import.txt | 1 - .../testdata/script/cover_test_pkgselect.txt | 3 - .../testdata/script/cover_var_init_order.txt | 3 - .../go/testdata/script/testing_coverage.txt | 1 - src/cmd/internal/cov/read_test.go | 4 - src/internal/buildcfg/exp.go | 13 +- src/internal/coverage/cfile/emitdata_test.go | 7 - src/internal/coverage/cfile/ts_test.go | 7 - .../goexperiment/exp_coverageredesign_off.go | 8 - .../goexperiment/exp_coverageredesign_on.go | 8 - src/internal/goexperiment/flags.go | 4 - src/testing/cover.go | 87 --------- src/testing/newcover.go | 41 +++-- src/testing/testing.go | 8 +- 33 files changed, 106 insertions(+), 531 deletions(-) delete mode 100644 src/internal/goexperiment/exp_coverageredesign_off.go delete mode 100644 src/internal/goexperiment/exp_coverageredesign_on.go diff --git a/src/cmd/compile/internal/test/inl_test.go b/src/cmd/compile/internal/test/inl_test.go index 9a1a8bb1059ca6..f1f6c34bfc8f9a 100644 --- a/src/cmd/compile/internal/test/inl_test.go +++ b/src/cmd/compile/internal/test/inl_test.go @@ -375,10 +375,6 @@ func TestIssue56044(t *testing.T) { if testing.Short() { t.Skipf("skipping test: too long for short mode") } - if !goexperiment.CoverageRedesign { - t.Skipf("skipping new coverage tests (experiment not enabled)") - } - testenv.MustHaveGoBuild(t) modes := []string{"-covermode=set", "-covermode=atomic"} diff --git a/src/cmd/covdata/tool_test.go b/src/cmd/covdata/tool_test.go index 757a245047eddf..730adf4c8e62e0 100644 --- a/src/cmd/covdata/tool_test.go +++ b/src/cmd/covdata/tool_test.go @@ -9,7 +9,6 @@ import ( "flag" "fmt" "internal/coverage/pods" - "internal/goexperiment" "internal/testenv" "log" "os" @@ -150,9 +149,6 @@ const debugWorkDir = false func TestCovTool(t *testing.T) { testenv.MustHaveGoBuild(t) - if !goexperiment.CoverageRedesign { - t.Skipf("stubbed out due to goexperiment.CoverageRedesign=false") - } dir := tempDir(t) if testing.Short() { t.Skip() diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index 2220863b8edce4..b9cf7202c22337 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -2484,7 +2484,6 @@ // GOCOVERDIR // Directory into which to write code coverage data files // generated by running a "go build -cover" binary. -// Requires that GOEXPERIMENT=coverageredesign is enabled. // // Special-purpose environment variables: // diff --git a/src/cmd/go/internal/help/helpdoc.go b/src/cmd/go/internal/help/helpdoc.go index ccc04c25d27d7e..d2f0fd173beef9 100644 --- a/src/cmd/go/internal/help/helpdoc.go +++ b/src/cmd/go/internal/help/helpdoc.go @@ -657,7 +657,6 @@ Environment variables for use with code coverage: GOCOVERDIR Directory into which to write code coverage data files generated by running a "go build -cover" binary. - Requires that GOEXPERIMENT=coverageredesign is enabled. Special-purpose environment variables: diff --git a/src/cmd/go/internal/list/list.go b/src/cmd/go/internal/list/list.go index 04fdadef3fde69..d6cba5a4e0640f 100644 --- a/src/cmd/go/internal/list/list.go +++ b/src/cmd/go/internal/list/list.go @@ -347,9 +347,7 @@ func init() { CmdList.Run = runList // break init cycle // Omit build -json because list has its own -json work.AddBuildFlags(CmdList, work.OmitJSONFlag) - if cfg.Experiment != nil && cfg.Experiment.CoverageRedesign { - work.AddCoverFlags(CmdList, nil) - } + work.AddCoverFlags(CmdList, nil) CmdList.Flag.Var(&listJsonFields, "json", "") } @@ -728,7 +726,7 @@ func runList(ctx context.Context, cmd *base.Command, args []string) { b.IsCmdList = true b.NeedExport = *listExport b.NeedCompiledGoFiles = *listCompiled - if cfg.Experiment.CoverageRedesign && cfg.BuildCover { + if cfg.BuildCover { load.PrepareForCoverageBuild(pkgs) } a := &work.Action{} diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go index 15f6b2e87b916b..0c4639ce82c321 100644 --- a/src/cmd/go/internal/load/pkg.go +++ b/src/cmd/go/internal/load/pkg.go @@ -8,7 +8,6 @@ package load import ( "bytes" "context" - "crypto/sha256" "encoding/json" "errors" "fmt" @@ -218,27 +217,26 @@ func (p *Package) IsTestOnly() bool { type PackageInternal struct { // Unexported fields are not part of the public API. Build *build.Package - Imports []*Package // this package's direct imports - CompiledImports []string // additional Imports necessary when using CompiledGoFiles (all from standard library); 1:1 with the end of PackagePublic.Imports - RawImports []string // this package's original imports as they appear in the text of the program; 1:1 with the end of PackagePublic.Imports - ForceLibrary bool // this package is a library (even if named "main") - CmdlineFiles bool // package built from files listed on command line - CmdlinePkg bool // package listed on command line - CmdlinePkgLiteral bool // package listed as literal on command line (not via wildcard) - Local bool // imported via local path (./ or ../) - LocalPrefix string // interpret ./ and ../ imports relative to this prefix - ExeName string // desired name for temporary executable - FuzzInstrument bool // package should be instrumented for fuzzing - Cover CoverSetup // coverage mode and other setup info of -cover is being applied to this package - CoverVars map[string]*CoverVar // variables created by coverage analysis - OmitDebug bool // tell linker not to write debug information - GobinSubdir bool // install target would be subdir of GOBIN - BuildInfo *debug.BuildInfo // add this info to package main - TestmainGo *[]byte // content for _testmain.go - Embed map[string][]string // //go:embed comment mapping - OrigImportPath string // original import path before adding '_test' suffix - PGOProfile string // path to PGO profile - ForMain string // the main package if this package is built specifically for it + Imports []*Package // this package's direct imports + CompiledImports []string // additional Imports necessary when using CompiledGoFiles (all from standard library); 1:1 with the end of PackagePublic.Imports + RawImports []string // this package's original imports as they appear in the text of the program; 1:1 with the end of PackagePublic.Imports + ForceLibrary bool // this package is a library (even if named "main") + CmdlineFiles bool // package built from files listed on command line + CmdlinePkg bool // package listed on command line + CmdlinePkgLiteral bool // package listed as literal on command line (not via wildcard) + Local bool // imported via local path (./ or ../) + LocalPrefix string // interpret ./ and ../ imports relative to this prefix + ExeName string // desired name for temporary executable + FuzzInstrument bool // package should be instrumented for fuzzing + Cover CoverSetup // coverage mode and other setup info of -cover is being applied to this package + OmitDebug bool // tell linker not to write debug information + GobinSubdir bool // install target would be subdir of GOBIN + BuildInfo *debug.BuildInfo // add this info to package main + TestmainGo *[]byte // content for _testmain.go + Embed map[string][]string // //go:embed comment mapping + OrigImportPath string // original import path before adding '_test' suffix + PGOProfile string // path to PGO profile + ForMain string // the main package if this package is built specifically for it Asmflags []string // -asmflags for this package Gcflags []string // -gcflags for this package @@ -372,12 +370,6 @@ func (p *Package) Resolve(imports []string) []string { return all } -// CoverVar holds the name of the generated coverage variables targeting the named file. -type CoverVar struct { - File string // local file name - Var string // name of count struct -} - // CoverSetup holds parameters related to coverage setup for a given package (covermode, etc). type CoverSetup struct { Mode string // coverage mode for this package @@ -2627,7 +2619,7 @@ func LinkerDeps(p *Package) ([]string, error) { deps = append(deps, "runtime/asan") } // Building for coverage forces an import of runtime/coverage. - if cfg.BuildCover && cfg.Experiment.CoverageRedesign { + if cfg.BuildCover { deps = append(deps, "runtime/coverage") } @@ -3568,14 +3560,6 @@ func SelectCoverPackages(roots []*Package, match []func(*Package) bool, op strin if cfg.BuildCoverMode == "atomic" { EnsureImport(p, "sync/atomic") } - - // Generate covervars if using legacy coverage design. - if !cfg.Experiment.CoverageRedesign { - var coverFiles []string - coverFiles = append(coverFiles, p.GoFiles...) - coverFiles = append(coverFiles, p.CgoFiles...) - p.Internal.CoverVars = DeclareCoverVars(p, coverFiles...) - } } // Warn about -coverpkg arguments that are not actually used. @@ -3587,42 +3571,3 @@ func SelectCoverPackages(roots []*Package, match []func(*Package) bool, op strin return covered } - -// DeclareCoverVars attaches the required cover variables names -// to the files, to be used when annotating the files. This -// function only called when using legacy coverage test/build -// (e.g. GOEXPERIMENT=coverageredesign is off). -func DeclareCoverVars(p *Package, files ...string) map[string]*CoverVar { - coverVars := make(map[string]*CoverVar) - coverIndex := 0 - // We create the cover counters as new top-level variables in the package. - // We need to avoid collisions with user variables (GoCover_0 is unlikely but still) - // and more importantly with dot imports of other covered packages, - // so we append 12 hex digits from the SHA-256 of the import path. - // The point is only to avoid accidents, not to defeat users determined to - // break things. - sum := sha256.Sum256([]byte(p.ImportPath)) - h := fmt.Sprintf("%x", sum[:6]) - for _, file := range files { - if base.IsTestFile(file) { - continue - } - // For a package that is "local" (imported via ./ import or command line, outside GOPATH), - // we record the full path to the file name. - // Otherwise we record the import path, then a forward slash, then the file name. - // This makes profiles within GOPATH file system-independent. - // These names appear in the cmd/cover HTML interface. - var longFile string - if p.Internal.Local { - longFile = filepath.Join(p.Dir, file) - } else { - longFile = pathpkg.Join(p.ImportPath, file) - } - coverVars[file] = &CoverVar{ - File: longFile, - Var: fmt.Sprintf("GoCover_%d_%x", coverIndex, h), - } - coverIndex++ - } - return coverVars -} diff --git a/src/cmd/go/internal/load/test.go b/src/cmd/go/internal/load/test.go index ddd14a03046016..f895e3a2461d9e 100644 --- a/src/cmd/go/internal/load/test.go +++ b/src/cmd/go/internal/load/test.go @@ -23,7 +23,6 @@ import ( "unicode" "unicode/utf8" - "cmd/go/internal/cfg" "cmd/go/internal/fsys" "cmd/go/internal/str" "cmd/go/internal/trace" @@ -42,7 +41,6 @@ type TestCover struct { Local bool Pkgs []*Package Paths []string - Vars []coverInfo } // TestPackagesFor is like TestPackagesAndErrors but it returns @@ -309,7 +307,7 @@ func TestPackagesAndErrors(ctx context.Context, done func(), opts PackageOpts, p // Also the linker introduces implicit dependencies reported by LinkerDeps. stk.Push(ImportInfo{Pkg: "testmain"}) deps := TestMainDeps // cap==len, so safe for append - if cover != nil && cfg.Experiment.CoverageRedesign { + if cover != nil { deps = append(deps, "internal/coverage/cfile") } ldDeps, err := LinkerDeps(p) @@ -334,22 +332,6 @@ func TestPackagesAndErrors(ctx context.Context, done func(), opts PackageOpts, p stk.Pop() parallelizablePart := func() { - if cover != nil && cover.Pkgs != nil && !cfg.Experiment.CoverageRedesign { - // Add imports, but avoid duplicates. - seen := map[*Package]bool{p: true, ptest: true} - for _, p1 := range pmain.Internal.Imports { - seen[p1] = true - } - for _, p1 := range cover.Pkgs { - if seen[p1] { - // Don't add duplicate imports. - continue - } - seen[p1] = true - pmain.Internal.Imports = append(pmain.Internal.Imports, p1) - } - } - allTestImports := make([]*Package, 0, len(pmain.Internal.Imports)+len(imports)+len(ximports)) allTestImports = append(allTestImports, pmain.Internal.Imports...) allTestImports = append(allTestImports, imports...) @@ -397,35 +379,19 @@ func TestPackagesAndErrors(ctx context.Context, done func(), opts PackageOpts, p } if cover != nil { - if cfg.Experiment.CoverageRedesign { - // Here ptest needs to inherit the proper coverage mode (since - // it contains p's Go files), whereas pmain contains only - // test harness code (don't want to instrument it, and - // we don't want coverage hooks in the pkg init). - ptest.Internal.Cover.Mode = p.Internal.Cover.Mode - pmain.Internal.Cover.Mode = "testmain" - } + // Here ptest needs to inherit the proper coverage mode (since + // it contains p's Go files), whereas pmain contains only + // test harness code (don't want to instrument it, and + // we don't want coverage hooks in the pkg init). + ptest.Internal.Cover.Mode = p.Internal.Cover.Mode + pmain.Internal.Cover.Mode = "testmain" + // Should we apply coverage analysis locally, only for this // package and only for this test? Yes, if -cover is on but // -coverpkg has not specified a list of packages for global // coverage. if cover.Local { ptest.Internal.Cover.Mode = cover.Mode - - if !cfg.Experiment.CoverageRedesign { - var coverFiles []string - coverFiles = append(coverFiles, ptest.GoFiles...) - coverFiles = append(coverFiles, ptest.CgoFiles...) - ptest.Internal.CoverVars = DeclareCoverVars(ptest, coverFiles...) - } - } - - if !cfg.Experiment.CoverageRedesign { - for _, cp := range pmain.Internal.Imports { - if len(cp.Internal.CoverVars) > 0 { - t.Cover.Vars = append(t.Cover.Vars, coverInfo{cp, cp.Internal.CoverVars}) - } - } } } @@ -625,11 +591,6 @@ func isTest(name, prefix string) bool { return !unicode.IsLower(rune) } -type coverInfo struct { - Package *Package - Vars map[string]*CoverVar -} - // loadTestFuncs returns the testFuncs describing the tests that will be run. // The returned testFuncs is always non-nil, even if an error occurred while // processing test files. @@ -655,9 +616,6 @@ func loadTestFuncs(ptest *Package) (*testFuncs, error) { func formatTestmain(t *testFuncs) ([]byte, error) { var buf bytes.Buffer tmpl := testmainTmpl - if cfg.Experiment.CoverageRedesign { - tmpl = testmainTmplNewCoverage - } if err := tmpl.Execute(&buf, t); err != nil { return nil, err } @@ -825,119 +783,6 @@ var testmainTmpl = lazytemplate.New("main", ` package main -import ( - "os" -{{if .TestMain}} - "reflect" -{{end}} - "testing" - "testing/internal/testdeps" - -{{if .ImportTest}} - {{if .NeedTest}}_test{{else}}_{{end}} {{.Package.ImportPath | printf "%q"}} -{{end}} -{{if .ImportXtest}} - {{if .NeedXtest}}_xtest{{else}}_{{end}} {{.Package.ImportPath | printf "%s_test" | printf "%q"}} -{{end}} -{{if .Cover}} -{{range $i, $p := .Cover.Vars}} - _cover{{$i}} {{$p.Package.ImportPath | printf "%q"}} -{{end}} -{{end}} -) - -var tests = []testing.InternalTest{ -{{range .Tests}} - {"{{.Name}}", {{.Package}}.{{.Name}}}, -{{end}} -} - -var benchmarks = []testing.InternalBenchmark{ -{{range .Benchmarks}} - {"{{.Name}}", {{.Package}}.{{.Name}}}, -{{end}} -} - -var fuzzTargets = []testing.InternalFuzzTarget{ -{{range .FuzzTargets}} - {"{{.Name}}", {{.Package}}.{{.Name}}}, -{{end}} -} - -var examples = []testing.InternalExample{ -{{range .Examples}} - {"{{.Name}}", {{.Package}}.{{.Name}}, {{.Output | printf "%q"}}, {{.Unordered}}}, -{{end}} -} - -func init() { - testdeps.ImportPath = {{.ImportPath | printf "%q"}} -} - -{{if .Cover}} - -// Only updated by init functions, so no need for atomicity. -var ( - coverCounters = make(map[string][]uint32) - coverBlocks = make(map[string][]testing.CoverBlock) -) - -func init() { - {{range $i, $p := .Cover.Vars}} - {{range $file, $cover := $p.Vars}} - coverRegisterFile({{printf "%q" $cover.File}}, _cover{{$i}}.{{$cover.Var}}.Count[:], _cover{{$i}}.{{$cover.Var}}.Pos[:], _cover{{$i}}.{{$cover.Var}}.NumStmt[:]) - {{end}} - {{end}} -} - -func coverRegisterFile(fileName string, counter []uint32, pos []uint32, numStmts []uint16) { - if 3*len(counter) != len(pos) || len(counter) != len(numStmts) { - panic("coverage: mismatched sizes") - } - if coverCounters[fileName] != nil { - // Already registered. - return - } - coverCounters[fileName] = counter - block := make([]testing.CoverBlock, len(counter)) - for i := range counter { - block[i] = testing.CoverBlock{ - Line0: pos[3*i+0], - Col0: uint16(pos[3*i+2]), - Line1: pos[3*i+1], - Col1: uint16(pos[3*i+2]>>16), - Stmts: numStmts[i], - } - } - coverBlocks[fileName] = block -} -{{end}} - -func main() { -{{if .Cover}} - testing.RegisterCover(testing.Cover{ - Mode: {{printf "%q" .Cover.Mode}}, - Counters: coverCounters, - Blocks: coverBlocks, - CoveredPackages: {{printf "%q" .Covered}}, - }) -{{end}} - m := testing.MainStart(testdeps.TestDeps{}, tests, benchmarks, fuzzTargets, examples) -{{with .TestMain}} - {{.Package}}.{{.Name}}(m) - os.Exit(int(reflect.ValueOf(m).Elem().FieldByName("exitCode").Int())) -{{else}} - os.Exit(m.Run()) -{{end}} -} - -`) - -var testmainTmplNewCoverage = lazytemplate.New("main", ` -// Code generated by 'go test'. DO NOT EDIT. - -package main - import ( "os" {{if .TestMain}} diff --git a/src/cmd/go/internal/run/run.go b/src/cmd/go/internal/run/run.go index 5067cb28354fd8..b81b1a007bd79d 100644 --- a/src/cmd/go/internal/run/run.go +++ b/src/cmd/go/internal/run/run.go @@ -66,9 +66,7 @@ func init() { CmdRun.Run = runRun // break init loop work.AddBuildFlags(CmdRun, work.DefaultBuildFlags) - if cfg.Experiment != nil && cfg.Experiment.CoverageRedesign { - work.AddCoverFlags(CmdRun, nil) - } + work.AddCoverFlags(CmdRun, nil) CmdRun.Flag.Var((*base.StringsFlag)(&work.ExecCmd), "exec", "") } @@ -141,7 +139,7 @@ func runRun(ctx context.Context, cmd *base.Command, args []string) { cmdArgs := args[i:] load.CheckPackageErrors([]*load.Package{p}) - if cfg.Experiment.CoverageRedesign && cfg.BuildCover { + if cfg.BuildCover { load.PrepareForCoverageBuild([]*load.Package{p}) } diff --git a/src/cmd/go/internal/test/test.go b/src/cmd/go/internal/test/test.go index 90f2d88d6b8a45..e3cd50d59c88fb 100644 --- a/src/cmd/go/internal/test/test.go +++ b/src/cmd/go/internal/test/test.go @@ -867,7 +867,7 @@ func runTest(ctx context.Context, cmd *base.Command, args []string) { // patterns. plist := load.TestPackageList(ctx, pkgOpts, pkgs) testCoverPkgs = load.SelectCoverPackages(plist, match, "test") - if cfg.Experiment.CoverageRedesign && len(testCoverPkgs) > 0 { + if len(testCoverPkgs) > 0 { // create a new singleton action that will collect up the // meta-data files from all of the packages mentioned in // "-coverpkg" and write them to a summary file. This new @@ -984,9 +984,7 @@ func runTest(ctx context.Context, cmd *base.Command, args []string) { // later package. Note that if -coverpkg is in effect // p.Internal.Cover.GenMeta will wind up being set for // all matching packages. - if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 && - cfg.BuildCoverPkg == nil && - cfg.Experiment.CoverageRedesign { + if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 && cfg.BuildCoverPkg == nil { p.Internal.Cover.GenMeta = true } } @@ -1092,7 +1090,7 @@ var windowsBadWords = []string{ func builderTest(b *work.Builder, ctx context.Context, pkgOpts load.PackageOpts, p *load.Package, imported bool, writeCoverMetaAct *work.Action) (buildAction, runAction, printAction *work.Action, perr *load.Package, err error) { if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 { - if cfg.BuildCover && cfg.Experiment.CoverageRedesign { + if cfg.BuildCover { if p.Internal.Cover.GenMeta { p.Internal.Cover.Mode = cfg.BuildCoverMode } @@ -1487,7 +1485,7 @@ func (r *runTestActor) Act(b *work.Builder, ctx context.Context, a *work.Action) if p := a.Package; len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 { reportNoTestFiles := true - if cfg.BuildCover && cfg.Experiment.CoverageRedesign && p.Internal.Cover.GenMeta { + if cfg.BuildCover && p.Internal.Cover.GenMeta { if err := sh.Mkdir(a.Objdir); err != nil { return err } diff --git a/src/cmd/go/internal/work/build.go b/src/cmd/go/internal/work/build.go index 3508d51fbb0452..873feb8a2604ae 100644 --- a/src/cmd/go/internal/work/build.go +++ b/src/cmd/go/internal/work/build.go @@ -247,10 +247,8 @@ func init() { AddBuildFlags(CmdBuild, DefaultBuildFlags) AddBuildFlags(CmdInstall, DefaultBuildFlags) - if cfg.Experiment != nil && cfg.Experiment.CoverageRedesign { - AddCoverFlags(CmdBuild, nil) - AddCoverFlags(CmdInstall, nil) - } + AddCoverFlags(CmdBuild, nil) + AddCoverFlags(CmdInstall, nil) } // Note that flags consulted by other parts of the code @@ -361,26 +359,13 @@ func AddBuildFlags(cmd *base.Command, mask BuildFlagMask) { cmd.Flag.StringVar(&cfg.DebugTrace, "debug-trace", "", "") } -// AddCoverFlags adds coverage-related flags to "cmd". If the -// CoverageRedesign experiment is enabled, we add -cover{mode,pkg} to -// the build command and only -coverprofile to the test command. If -// the CoverageRedesign experiment is disabled, -cover* flags are -// added only to the test command. +// AddCoverFlags adds coverage-related flags to "cmd". +// We add -cover{mode,pkg} to the build command and only +// -coverprofile to the test command. func AddCoverFlags(cmd *base.Command, coverProfileFlag *string) { - addCover := false - if cfg.Experiment != nil && cfg.Experiment.CoverageRedesign { - // New coverage enabled: both build and test commands get - // coverage flags. - addCover = true - } else { - // New coverage disabled: only test command gets cover flags. - addCover = coverProfileFlag != nil - } - if addCover { - cmd.Flag.BoolVar(&cfg.BuildCover, "cover", false, "") - cmd.Flag.Var(coverFlag{(*coverModeFlag)(&cfg.BuildCoverMode)}, "covermode", "") - cmd.Flag.Var(coverFlag{commaListFlag{&cfg.BuildCoverPkg}}, "coverpkg", "") - } + cmd.Flag.BoolVar(&cfg.BuildCover, "cover", false, "") + cmd.Flag.Var(coverFlag{(*coverModeFlag)(&cfg.BuildCoverMode)}, "covermode", "") + cmd.Flag.Var(coverFlag{commaListFlag{&cfg.BuildCoverPkg}}, "coverpkg", "") if coverProfileFlag != nil { cmd.Flag.Var(coverFlag{V: stringFlag{coverProfileFlag}}, "coverprofile", "") } @@ -515,7 +500,7 @@ func runBuild(ctx context.Context, cmd *base.Command, args []string) { cfg.BuildO = "" } - if cfg.Experiment.CoverageRedesign && cfg.BuildCover { + if cfg.BuildCover { load.PrepareForCoverageBuild(pkgs) } @@ -732,7 +717,7 @@ func runInstall(ctx context.Context, cmd *base.Command, args []string) { } load.CheckPackageErrors(pkgs) - if cfg.Experiment.CoverageRedesign && cfg.BuildCover { + if cfg.BuildCover { load.PrepareForCoverageBuild(pkgs) } diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go index 7b073165d5fe25..c79d6f73ef4a9d 100644 --- a/src/cmd/go/internal/work/exec.go +++ b/src/cmd/go/internal/work/exec.go @@ -647,31 +647,18 @@ OverlayLoop: var sourceFile string var coverFile string - var key string if base, found := strings.CutSuffix(file, ".cgo1.go"); found { // cgo files have absolute paths base = filepath.Base(base) sourceFile = file coverFile = objdir + base + ".cgo1.go" - key = base + ".go" } else { sourceFile = filepath.Join(p.Dir, file) coverFile = objdir + file - key = file } coverFile = strings.TrimSuffix(coverFile, ".go") + ".cover.go" - if cfg.Experiment.CoverageRedesign { - infiles = append(infiles, sourceFile) - outfiles = append(outfiles, coverFile) - } else { - cover := p.Internal.CoverVars[key] - if cover == nil { - continue // Not covering this file. - } - if err := b.cover(a, coverFile, sourceFile, cover.Var); err != nil { - return err - } - } + infiles = append(infiles, sourceFile) + outfiles = append(outfiles, coverFile) if i < len(gofiles) { gofiles[i] = coverFile } else { @@ -679,36 +666,27 @@ OverlayLoop: } } - if cfg.Experiment.CoverageRedesign { - if len(infiles) != 0 { - // Coverage instrumentation creates new top level - // variables in the target package for things like - // meta-data containers, counter vars, etc. To avoid - // collisions with user variables, suffix the var name - // with 12 hex digits from the SHA-256 hash of the - // import path. Choice of 12 digits is historical/arbitrary, - // we just need enough of the hash to avoid accidents, - // as opposed to precluding determined attempts by - // users to break things. - sum := sha256.Sum256([]byte(a.Package.ImportPath)) - coverVar := fmt.Sprintf("goCover_%x_", sum[:6]) - mode := a.Package.Internal.Cover.Mode - if mode == "" { - panic("covermode should be set at this point") - } - if newoutfiles, err := b.cover2(a, infiles, outfiles, coverVar, mode); err != nil { - return err - } else { - outfiles = newoutfiles - gofiles = append([]string{newoutfiles[0]}, gofiles...) - } + if len(infiles) != 0 { + // Coverage instrumentation creates new top level + // variables in the target package for things like + // meta-data containers, counter vars, etc. To avoid + // collisions with user variables, suffix the var name + // with 12 hex digits from the SHA-256 hash of the + // import path. Choice of 12 digits is historical/arbitrary, + // we just need enough of the hash to avoid accidents, + // as opposed to precluding determined attempts by + // users to break things. + sum := sha256.Sum256([]byte(a.Package.ImportPath)) + coverVar := fmt.Sprintf("goCover_%x_", sum[:6]) + mode := a.Package.Internal.Cover.Mode + if mode == "" { + panic("covermode should be set at this point") + } + if newoutfiles, err := b.cover(a, infiles, outfiles, coverVar, mode); err != nil { + return err } else { - // If there are no input files passed to cmd/cover, - // then we don't want to pass -covercfg when building - // the package with the compiler, so set covermode to - // the empty string so as to signal that we need to do - // that. - p.Internal.Cover.Mode = "" + outfiles = newoutfiles + gofiles = append([]string{newoutfiles[0]}, gofiles...) } if ba, ok := a.Actor.(*buildActor); ok && ba.covMetaFileName != "" { b.cacheObjdirFile(a, cache.Default(), ba.covMetaFileName) @@ -1909,26 +1887,13 @@ func (b *Builder) installHeader(ctx context.Context, a *Action) error { // cover runs, in effect, // -// go tool cover -mode=b.coverMode -var="varName" -o dst.go src.go -func (b *Builder) cover(a *Action, dst, src string, varName string) error { - return b.Shell(a).run(a.Objdir, "", nil, - cfg.BuildToolexec, - base.Tool("cover"), - "-mode", a.Package.Internal.Cover.Mode, - "-var", varName, - "-o", dst, - src) -} - -// cover2 runs, in effect, -// // go tool cover -pkgcfg= -mode=b.coverMode -var="varName" -o // // Return value is an updated output files list; in addition to the // regular outputs (instrumented source files) the cover tool also // writes a separate file (appearing first in the list of outputs) // that will contain coverage counters and meta-data. -func (b *Builder) cover2(a *Action, infiles, outfiles []string, varName string, mode string) ([]string, error) { +func (b *Builder) cover(a *Action, infiles, outfiles []string, varName string, mode string) ([]string, error) { pkgcfg := a.Objdir + "pkgcfg.txt" covoutputs := a.Objdir + "coveroutfiles.txt" odir := filepath.Dir(outfiles[0]) diff --git a/src/cmd/go/testdata/script/cover_build_cmdline_pkgs.txt b/src/cmd/go/testdata/script/cover_build_cmdline_pkgs.txt index e14a0784f2bc9d..ba382639e9cdf2 100644 --- a/src/cmd/go/testdata/script/cover_build_cmdline_pkgs.txt +++ b/src/cmd/go/testdata/script/cover_build_cmdline_pkgs.txt @@ -5,7 +5,6 @@ # inside and outside the standard library. [short] skip -[!GOEXPERIMENT:coverageredesign] skip # Compile an object. go tool compile -p tiny tiny/tiny.go tiny/tiny2.go diff --git a/src/cmd/go/testdata/script/cover_build_pkg_select.txt b/src/cmd/go/testdata/script/cover_build_pkg_select.txt index 447ca7788c13ea..3a59e72e88317a 100644 --- a/src/cmd/go/testdata/script/cover_build_pkg_select.txt +++ b/src/cmd/go/testdata/script/cover_build_pkg_select.txt @@ -3,9 +3,6 @@ [short] skip -# Skip if new coverage is not enabled. -[!GOEXPERIMENT:coverageredesign] skip - #------------------------------------------- # Build for coverage. diff --git a/src/cmd/go/testdata/script/cover_build_simple.txt b/src/cmd/go/testdata/script/cover_build_simple.txt index b61e631abd9339..ee451a68ab18bf 100644 --- a/src/cmd/go/testdata/script/cover_build_simple.txt +++ b/src/cmd/go/testdata/script/cover_build_simple.txt @@ -2,9 +2,6 @@ [short] skip -# Hard-wire new coverage for this test. -env GOEXPERIMENT=coverageredesign - # Build for coverage. go build -gcflags=-m -o example.exe -cover example/main & [race] go build -o examplewithrace.exe -race -cover example/main & diff --git a/src/cmd/go/testdata/script/cover_coverpkg_partial.txt b/src/cmd/go/testdata/script/cover_coverpkg_partial.txt index ef7a4dd2aac48f..efdfe2f27d85bc 100644 --- a/src/cmd/go/testdata/script/cover_coverpkg_partial.txt +++ b/src/cmd/go/testdata/script/cover_coverpkg_partial.txt @@ -16,7 +16,6 @@ # [short] skip -[!GOEXPERIMENT:coverageredesign] skip # Test all packages with -coverpkg=./... go test -coverprofile=cov.p -coverpkg=./... ./... diff --git a/src/cmd/go/testdata/script/cover_coverpkg_with_init.txt b/src/cmd/go/testdata/script/cover_coverpkg_with_init.txt index 7a89102547adb2..bb5bcfa823979f 100644 --- a/src/cmd/go/testdata/script/cover_coverpkg_with_init.txt +++ b/src/cmd/go/testdata/script/cover_coverpkg_with_init.txt @@ -5,7 +5,6 @@ # do not, some have tests and some do not. [short] skip -[!GOEXPERIMENT:coverageredesign] skip # Verify correct statements percentages. We have a total of 10 # statements in the packages matched by "./..."; package "a" (for diff --git a/src/cmd/go/testdata/script/cover_list.txt b/src/cmd/go/testdata/script/cover_list.txt index 1b1f3266622155..7ecc5c05ebfb85 100644 --- a/src/cmd/go/testdata/script/cover_list.txt +++ b/src/cmd/go/testdata/script/cover_list.txt @@ -3,7 +3,6 @@ # build arguments (such as -cover, -covermode). See issue #57785. [short] skip -[!GOEXPERIMENT:coverageredesign] skip env GOBIN=$WORK/bin diff --git a/src/cmd/go/testdata/script/cover_main_import_path.txt b/src/cmd/go/testdata/script/cover_main_import_path.txt index e8696e27e23bae..3a2f3c3ee28fee 100644 --- a/src/cmd/go/testdata/script/cover_main_import_path.txt +++ b/src/cmd/go/testdata/script/cover_main_import_path.txt @@ -4,7 +4,6 @@ # the "main" package is handled. See issue 57169 for details. [short] skip -[!GOEXPERIMENT:coverageredesign] skip # Build this program with -cover and run to collect a profile. diff --git a/src/cmd/go/testdata/script/cover_statements.txt b/src/cmd/go/testdata/script/cover_statements.txt index 030177cb8b4acf..f0391ede22d064 100644 --- a/src/cmd/go/testdata/script/cover_statements.txt +++ b/src/cmd/go/testdata/script/cover_statements.txt @@ -10,35 +10,32 @@ env GOCACHE=$WORK/cache # Initial run with simple coverage. go test -cover ./pkg1 ./pkg2 ./pkg3 ./pkg4 -[!GOEXPERIMENT:coverageredesign] stdout 'pkg1 \[no test files\]' -[GOEXPERIMENT:coverageredesign] stdout 'pkg1 coverage: 0.0% of statements' +stdout 'pkg1 coverage: 0.0% of statements' stdout 'pkg2 \S+ coverage: 0.0% of statements \[no tests to run\]' stdout 'pkg3 \S+ coverage: 100.0% of statements' stdout 'pkg4 \S+ coverage: \[no statements\]' # Second run to make sure that caching works properly. go test -x -cover ./pkg1 ./pkg2 ./pkg3 ./pkg4 -[!GOEXPERIMENT:coverageredesign] stdout 'pkg1 \[no test files\]' -[GOEXPERIMENT:coverageredesign] stdout 'pkg1 coverage: 0.0% of statements' +stdout 'pkg1 coverage: 0.0% of statements' stdout 'pkg2 \S+ coverage: 0.0% of statements \[no tests to run\]' stdout 'pkg3 \S+ coverage: 100.0% of statements' stdout 'pkg4 \S+ coverage: \[no statements\]' -[GOEXPERIMENT:coverageredesign] ! stderr 'link(\.exe"?)? -' +! stderr 'link(\.exe"?)? -' ! stderr 'compile(\.exe"?)? -' ! stderr 'cover(\.exe"?)? -' -[GOEXPERIMENT:coverageredesign] stderr 'covdata(\.exe"?)? percent' +stderr 'covdata(\.exe"?)? percent' # Now add in -coverprofile. go test -cover -coverprofile=cov.dat ./pkg1 ./pkg2 ./pkg3 ./pkg4 -[!GOEXPERIMENT:coverageredesign] stdout 'pkg1 \[no test files\]' -[GOEXPERIMENT:coverageredesign] stdout 'pkg1 coverage: 0.0% of statements' +stdout 'pkg1 coverage: 0.0% of statements' stdout 'pkg2 \S+ coverage: 0.0% of statements \[no tests to run\]' stdout 'pkg3 \S+ coverage: 100.0% of statements' stdout 'pkg4 \S+ coverage: \[no statements\]' # Validate go tool cover -func=cov.dat -[GOEXPERIMENT:coverageredesign] stdout 'pkg1/a.go:5:\s+F\s+0.0%' +stdout 'pkg1/a.go:5:\s+F\s+0.0%' -- go.mod -- module m diff --git a/src/cmd/go/testdata/script/cover_sync_atomic_import.txt b/src/cmd/go/testdata/script/cover_sync_atomic_import.txt index a098979797acf3..7beea137e2d637 100644 --- a/src/cmd/go/testdata/script/cover_sync_atomic_import.txt +++ b/src/cmd/go/testdata/script/cover_sync_atomic_import.txt @@ -1,6 +1,5 @@ [short] skip [compiler:gccgo] skip # gccgo has no cover tool -[!GOEXPERIMENT:coverageredesign] skip go test -short -cover -covermode=atomic -coverpkg=coverdep/p1 coverdep diff --git a/src/cmd/go/testdata/script/cover_test_pkgselect.txt b/src/cmd/go/testdata/script/cover_test_pkgselect.txt index 97a1d2cbbb0c85..8e47d142d41ccb 100644 --- a/src/cmd/go/testdata/script/cover_test_pkgselect.txt +++ b/src/cmd/go/testdata/script/cover_test_pkgselect.txt @@ -1,9 +1,6 @@ [short] skip -# Hard-wire new coverage for this test. -env GOEXPERIMENT=coverageredesign - # Baseline run. go test -cover example/foo stdout 'coverage: 50.0% of statements$' diff --git a/src/cmd/go/testdata/script/cover_var_init_order.txt b/src/cmd/go/testdata/script/cover_var_init_order.txt index 37e07b71f657d5..a9ee63c78c891e 100644 --- a/src/cmd/go/testdata/script/cover_var_init_order.txt +++ b/src/cmd/go/testdata/script/cover_var_init_order.txt @@ -4,9 +4,6 @@ [short] skip -# Skip if new coverage is turned off. -[!GOEXPERIMENT:coverageredesign] skip - go test -cover example -- go.mod -- diff --git a/src/cmd/go/testdata/script/testing_coverage.txt b/src/cmd/go/testdata/script/testing_coverage.txt index 6cf6adbbd7a49f..bf4dc83107b3b9 100644 --- a/src/cmd/go/testdata/script/testing_coverage.txt +++ b/src/cmd/go/testdata/script/testing_coverage.txt @@ -2,7 +2,6 @@ # Rudimentary test of testing.Coverage(). [short] skip -[!GOEXPERIMENT:coverageredesign] skip # Simple test. go test -v -cover -count=1 diff --git a/src/cmd/internal/cov/read_test.go b/src/cmd/internal/cov/read_test.go index fa2151a09ed2ed..cef03fa323e6e8 100644 --- a/src/cmd/internal/cov/read_test.go +++ b/src/cmd/internal/cov/read_test.go @@ -11,7 +11,6 @@ import ( "internal/coverage/decodecounter" "internal/coverage/decodemeta" "internal/coverage/pods" - "internal/goexperiment" "internal/testenv" "os" "path/filepath" @@ -45,9 +44,6 @@ func (v *visitor) Finish() func TestIssue58411(t *testing.T) { testenv.MustHaveGoBuild(t) - if !goexperiment.CoverageRedesign { - t.Skipf("skipping since this test requires 'go build -cover'") - } // Build a tiny test program with -cover. Smallness is important; // it is one of the factors that triggers issue 58411. diff --git a/src/internal/buildcfg/exp.go b/src/internal/buildcfg/exp.go index 332c9afa576bb5..9c9ec2c711c150 100644 --- a/src/internal/buildcfg/exp.go +++ b/src/internal/buildcfg/exp.go @@ -74,13 +74,12 @@ func ParseGOEXPERIMENT(goos, goarch, goexp string) (*ExperimentFlags, error) { } baseline := goexperiment.Flags{ - RegabiWrappers: regabiSupported, - RegabiArgs: regabiSupported, - CoverageRedesign: true, - AliasTypeParams: true, - SwissMap: true, - SpinbitMutex: haveXchg8, - SyncHashTrieMap: true, + RegabiWrappers: regabiSupported, + RegabiArgs: regabiSupported, + AliasTypeParams: true, + SwissMap: true, + SpinbitMutex: haveXchg8, + SyncHashTrieMap: true, } // Start with the statically enabled set of experiments. diff --git a/src/internal/coverage/cfile/emitdata_test.go b/src/internal/coverage/cfile/emitdata_test.go index c522048173e4c7..d127c6b2a976ba 100644 --- a/src/internal/coverage/cfile/emitdata_test.go +++ b/src/internal/coverage/cfile/emitdata_test.go @@ -7,7 +7,6 @@ package cfile import ( "fmt" "internal/coverage" - "internal/goexperiment" "internal/platform" "internal/testenv" "os" @@ -25,9 +24,6 @@ func TestCoverageApis(t *testing.T) { if testing.Short() { t.Skipf("skipping test: too long for short mode") } - if !goexperiment.CoverageRedesign { - t.Skipf("skipping new coverage tests (experiment not enabled)") - } testenv.MustHaveGoBuild(t) dir := t.TempDir() if fixedTestDir { @@ -465,9 +461,6 @@ func TestIssue56006EmitDataRaceCoverRunningGoroutine(t *testing.T) { if testing.Short() { t.Skipf("skipping test: too long for short mode") } - if !goexperiment.CoverageRedesign { - t.Skipf("skipping new coverage tests (experiment not enabled)") - } // This test requires "go test -race -cover", meaning that we need // go build, go run, and "-race" support. diff --git a/src/internal/coverage/cfile/ts_test.go b/src/internal/coverage/cfile/ts_test.go index d3441821a436d3..d106d3b132ce0a 100644 --- a/src/internal/coverage/cfile/ts_test.go +++ b/src/internal/coverage/cfile/ts_test.go @@ -8,7 +8,6 @@ import ( "encoding/json" "flag" "internal/coverage" - "internal/goexperiment" "internal/testenv" "os" "os/exec" @@ -32,9 +31,6 @@ func testGoCoverDir(t *testing.T) string { // relying on other test paths will provide a better signal when // running "go test -cover" for this package). func TestTestSupport(t *testing.T) { - if !goexperiment.CoverageRedesign { - return - } if testing.CoverMode() == "" { return } @@ -128,9 +124,6 @@ func genAuxMeta(t *testing.T, dstdir string) (string, string) { } func TestAuxMetaDataFiles(t *testing.T) { - if !goexperiment.CoverageRedesign { - return - } if testing.CoverMode() == "" { return } diff --git a/src/internal/goexperiment/exp_coverageredesign_off.go b/src/internal/goexperiment/exp_coverageredesign_off.go deleted file mode 100644 index 2c33177322d1f4..00000000000000 --- a/src/internal/goexperiment/exp_coverageredesign_off.go +++ /dev/null @@ -1,8 +0,0 @@ -// Code generated by mkconsts.go. DO NOT EDIT. - -//go:build !goexperiment.coverageredesign - -package goexperiment - -const CoverageRedesign = false -const CoverageRedesignInt = 0 diff --git a/src/internal/goexperiment/exp_coverageredesign_on.go b/src/internal/goexperiment/exp_coverageredesign_on.go deleted file mode 100644 index 3fc6c2f70a9ab5..00000000000000 --- a/src/internal/goexperiment/exp_coverageredesign_on.go +++ /dev/null @@ -1,8 +0,0 @@ -// Code generated by mkconsts.go. DO NOT EDIT. - -//go:build goexperiment.coverageredesign - -package goexperiment - -const CoverageRedesign = true -const CoverageRedesignInt = 1 diff --git a/src/internal/goexperiment/flags.go b/src/internal/goexperiment/flags.go index 948ed5c802801c..dff5255e000992 100644 --- a/src/internal/goexperiment/flags.go +++ b/src/internal/goexperiment/flags.go @@ -83,10 +83,6 @@ type Flags struct { // by default. HeapMinimum512KiB bool - // CoverageRedesign enables the new compiler-based code coverage - // tooling. - CoverageRedesign bool - // Arenas causes the "arena" standard library package to be visible // to the outside world. Arenas bool diff --git a/src/testing/cover.go b/src/testing/cover.go index 6ad43ab9ff4a8b..74c97d471e29d1 100644 --- a/src/testing/cover.go +++ b/src/testing/cover.go @@ -6,13 +6,6 @@ package testing -import ( - "fmt" - "internal/goexperiment" - "os" - "sync/atomic" -) - // CoverBlock records the coverage data for a single basic block. // The fields are 1-indexed, as in an editor: The opening line of // the file is number 1, for example. Columns are measured @@ -27,8 +20,6 @@ type CoverBlock struct { Stmts uint16 // Number of statements included in this block. } -var cover Cover - // Cover records information about test coverage checking. // NOTE: This struct is internal to the testing infrastructure and may change. // It is not covered (yet) by the Go 1 compatibility guidelines. @@ -39,86 +30,8 @@ type Cover struct { CoveredPackages string } -// Coverage reports the current code coverage as a fraction in the range [0, 1]. -// If coverage is not enabled, Coverage returns 0. -// -// When running a large set of sequential test cases, checking Coverage after each one -// can be useful for identifying which test cases exercise new code paths. -// It is not a replacement for the reports generated by 'go test -cover' and -// 'go tool cover'. -func Coverage() float64 { - if goexperiment.CoverageRedesign { - return coverage2() - } - var n, d int64 - for _, counters := range cover.Counters { - for i := range counters { - if atomic.LoadUint32(&counters[i]) > 0 { - n++ - } - d++ - } - } - if d == 0 { - return 0 - } - return float64(n) / float64(d) -} - // RegisterCover records the coverage data accumulators for the tests. // NOTE: This function is internal to the testing infrastructure and may change. // It is not covered (yet) by the Go 1 compatibility guidelines. func RegisterCover(c Cover) { - cover = c -} - -// mustBeNil checks the error and, if present, reports it and exits. -func mustBeNil(err error) { - if err != nil { - fmt.Fprintf(os.Stderr, "testing: %s\n", err) - os.Exit(2) - } -} - -// coverReport reports the coverage percentage and writes a coverage profile if requested. -func coverReport() { - if goexperiment.CoverageRedesign { - coverReport2() - return - } - var f *os.File - var err error - if *coverProfile != "" { - f, err = os.Create(toOutputDir(*coverProfile)) - mustBeNil(err) - fmt.Fprintf(f, "mode: %s\n", cover.Mode) - defer func() { mustBeNil(f.Close()) }() - } - - var active, total int64 - var count uint32 - for name, counts := range cover.Counters { - blocks := cover.Blocks[name] - for i := range counts { - stmts := int64(blocks[i].Stmts) - total += stmts - count = atomic.LoadUint32(&counts[i]) // For -mode=atomic. - if count > 0 { - active += stmts - } - if f != nil { - _, err := fmt.Fprintf(f, "%s:%d.%d,%d.%d %d %d\n", name, - blocks[i].Line0, blocks[i].Col0, - blocks[i].Line1, blocks[i].Col1, - stmts, - count) - mustBeNil(err) - } - } - } - if total == 0 { - fmt.Println("coverage: [no statements]") - return - } - fmt.Printf("coverage: %.1f%% of statements%s\n", 100*float64(active)/float64(total), cover.CoveredPackages) } diff --git a/src/testing/newcover.go b/src/testing/newcover.go index ad2f622640e4d9..5a8d728831027f 100644 --- a/src/testing/newcover.go +++ b/src/testing/newcover.go @@ -8,49 +8,52 @@ package testing import ( "fmt" - "internal/goexperiment" "os" _ "unsafe" // for linkname ) -// cover2 variable stores the current coverage mode and a +// cover variable stores the current coverage mode and a // tear-down function to be called at the end of the testing run. -var cover2 struct { +var cover struct { mode string tearDown func(coverprofile string, gocoverdir string) (string, error) snapshotcov func() float64 } -// registerCover2 is invoked during "go test -cover" runs. +// registerCover is invoked during "go test -cover" runs. // It is used to record a 'tear down' function // (to be called when the test is complete) and the coverage mode. -func registerCover2(mode string, tearDown func(coverprofile string, gocoverdir string) (string, error), snapcov func() float64) { +func registerCover(mode string, tearDown func(coverprofile string, gocoverdir string) (string, error), snapcov func() float64) { if mode == "" { return } - cover2.mode = mode - cover2.tearDown = tearDown - cover2.snapshotcov = snapcov + cover.mode = mode + cover.tearDown = tearDown + cover.snapshotcov = snapcov } -// coverReport2 invokes a callback in _testmain.go that will +// coverReport reports the coverage percentage and +// writes a coverage profile if requested. +// This invokes a callback in _testmain.go that will // emit coverage data at the point where test execution is complete, // for "go test -cover" runs. -func coverReport2() { - if !goexperiment.CoverageRedesign { - panic("unexpected") - } - if errmsg, err := cover2.tearDown(*coverProfile, *gocoverdir); err != nil { +func coverReport() { + if errmsg, err := cover.tearDown(*coverProfile, *gocoverdir); err != nil { fmt.Fprintf(os.Stderr, "%s: %v\n", errmsg, err) os.Exit(2) } } -// coverage2 returns a rough "coverage percentage so far" -// number to support the testing.Coverage() function. -func coverage2() float64 { - if cover2.mode == "" { +// Coverage reports the current code coverage as a fraction in the range [0, 1]. +// If coverage is not enabled, Coverage returns 0. +// +// When running a large set of sequential test cases, checking Coverage after each one +// can be useful for identifying which test cases exercise new code paths. +// It is not a replacement for the reports generated by 'go test -cover' and +// 'go tool cover'. +func Coverage() float64 { + if cover.mode == "" { return 0.0 } - return cover2.snapshotcov() + return cover.snapshotcov() } diff --git a/src/testing/testing.go b/src/testing/testing.go index 3833bfc84be49f..2bfa4b6db07992 100644 --- a/src/testing/testing.go +++ b/src/testing/testing.go @@ -403,7 +403,6 @@ import ( "errors" "flag" "fmt" - "internal/goexperiment" "internal/race" "io" "math/rand" @@ -700,10 +699,7 @@ func Testing() bool { // values are "set", "count", or "atomic". The return value will be // empty if test coverage is not enabled. func CoverMode() string { - if goexperiment.CoverageRedesign { - return cover2.mode - } - return cover.Mode + return cover.mode } // Verbose reports whether the -test.v flag is set. @@ -2021,7 +2017,7 @@ type testDeps interface { // It is not meant to be called directly and is not subject to the Go 1 compatibility document. // It may change signature from release to release. func MainStart(deps testDeps, tests []InternalTest, benchmarks []InternalBenchmark, fuzzTargets []InternalFuzzTarget, examples []InternalExample) *M { - registerCover2(deps.InitRuntimeCoverage()) + registerCover(deps.InitRuntimeCoverage()) Init() return &M{ deps: deps, From c1a5889edbd3e499df10db5ed1d8006c73de5792 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 18 Dec 2024 14:28:16 -0800 Subject: [PATCH 214/397] net, internal/routebsd: move vendored x/net/route to internal This is a simple move of the contents of the vendored x/net/route to internal/routebsd. I've also added some test files that were not previously vendored. This next CL will simplify the new internal/routebsd, removing the code that is not needed by the new package. This is a step toward simplifying the x/net/route package by permitting it to import x/sys/unix. Change-Id: I4d13df11fa9738cd68876b2ea456d03f82d8d64a Reviewed-on: https://go-review.googlesource.com/c/go/+/637695 Commit-Queue: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Commit-Queue: Ian Lance Taylor Auto-Submit: Ian Lance Taylor Auto-Submit: Ian Lance Taylor Reviewed-by: Damien Neil Reviewed-by: Ian Lance Taylor --- src/go/build/deps_test.go | 8 +- .../route => internal/routebsd}/address.go | 2 +- src/internal/routebsd/address_darwin_test.go | 170 ++++++++ src/internal/routebsd/address_test.go | 104 +++++ .../net/route => internal/routebsd}/binary.go | 2 +- .../x/net/route => internal/routebsd}/empty.s | 0 .../route => internal/routebsd}/interface.go | 2 +- .../routebsd}/interface_announce.go | 2 +- .../routebsd}/interface_classic.go | 2 +- .../routebsd}/interface_freebsd.go | 2 +- .../routebsd}/interface_multicast.go | 2 +- .../routebsd}/interface_openbsd.go | 2 +- .../route => internal/routebsd}/message.go | 2 +- src/internal/routebsd/message_darwin_test.go | 37 ++ src/internal/routebsd/message_freebsd_test.go | 91 +++++ src/internal/routebsd/message_test.go | 238 +++++++++++ .../net/route => internal/routebsd}/route.go | 2 +- .../routebsd}/route_classic.go | 2 +- .../routebsd}/route_openbsd.go | 2 +- src/internal/routebsd/route_test.go | 382 ++++++++++++++++++ .../x/net/route => internal/routebsd}/sys.go | 2 +- .../route => internal/routebsd}/sys_darwin.go | 2 +- .../routebsd}/sys_dragonfly.go | 2 +- .../routebsd}/sys_freebsd.go | 2 +- .../route => internal/routebsd}/sys_netbsd.go | 2 +- .../routebsd}/sys_openbsd.go | 2 +- .../route => internal/routebsd}/syscall.go | 2 +- .../routebsd}/zsys_darwin.go | 2 +- .../routebsd}/zsys_dragonfly.go | 2 +- .../routebsd}/zsys_freebsd_386.go | 2 +- .../routebsd}/zsys_freebsd_amd64.go | 2 +- .../routebsd}/zsys_freebsd_arm.go | 2 +- .../routebsd}/zsys_freebsd_arm64.go | 2 +- .../routebsd}/zsys_freebsd_riscv64.go | 2 +- .../routebsd}/zsys_netbsd.go | 2 +- .../routebsd}/zsys_openbsd.go | 2 +- src/net/interface_bsd.go | 21 +- src/net/interface_bsdvar.go | 9 +- src/net/interface_darwin.go | 19 +- src/net/interface_freebsd.go | 19 +- src/vendor/modules.txt | 1 - 41 files changed, 1087 insertions(+), 68 deletions(-) rename src/{vendor/golang.org/x/net/route => internal/routebsd}/address.go (99%) create mode 100644 src/internal/routebsd/address_darwin_test.go create mode 100644 src/internal/routebsd/address_test.go rename src/{vendor/golang.org/x/net/route => internal/routebsd}/binary.go (99%) rename src/{vendor/golang.org/x/net/route => internal/routebsd}/empty.s (100%) rename src/{vendor/golang.org/x/net/route => internal/routebsd}/interface.go (99%) rename src/{vendor/golang.org/x/net/route => internal/routebsd}/interface_announce.go (97%) rename src/{vendor/golang.org/x/net/route => internal/routebsd}/interface_classic.go (98%) rename src/{vendor/golang.org/x/net/route => internal/routebsd}/interface_freebsd.go (99%) rename src/{vendor/golang.org/x/net/route => internal/routebsd}/interface_multicast.go (97%) rename src/{vendor/golang.org/x/net/route => internal/routebsd}/interface_openbsd.go (99%) rename src/{vendor/golang.org/x/net/route => internal/routebsd}/message.go (98%) create mode 100644 src/internal/routebsd/message_darwin_test.go create mode 100644 src/internal/routebsd/message_freebsd_test.go create mode 100644 src/internal/routebsd/message_test.go rename src/{vendor/golang.org/x/net/route => internal/routebsd}/route.go (99%) rename src/{vendor/golang.org/x/net/route => internal/routebsd}/route_classic.go (99%) rename src/{vendor/golang.org/x/net/route => internal/routebsd}/route_openbsd.go (99%) create mode 100644 src/internal/routebsd/route_test.go rename src/{vendor/golang.org/x/net/route => internal/routebsd}/sys.go (98%) rename src/{vendor/golang.org/x/net/route => internal/routebsd}/sys_darwin.go (99%) rename src/{vendor/golang.org/x/net/route => internal/routebsd}/sys_dragonfly.go (99%) rename src/{vendor/golang.org/x/net/route => internal/routebsd}/sys_freebsd.go (99%) rename src/{vendor/golang.org/x/net/route => internal/routebsd}/sys_netbsd.go (99%) rename src/{vendor/golang.org/x/net/route => internal/routebsd}/sys_openbsd.go (99%) rename src/{vendor/golang.org/x/net/route => internal/routebsd}/syscall.go (95%) rename src/{vendor/golang.org/x/net/route => internal/routebsd}/zsys_darwin.go (96%) rename src/{vendor/golang.org/x/net/route => internal/routebsd}/zsys_dragonfly.go (96%) rename src/{vendor/golang.org/x/net/route => internal/routebsd}/zsys_freebsd_386.go (98%) rename src/{vendor/golang.org/x/net/route => internal/routebsd}/zsys_freebsd_amd64.go (98%) rename src/{vendor/golang.org/x/net/route => internal/routebsd}/zsys_freebsd_arm.go (98%) rename src/{vendor/golang.org/x/net/route => internal/routebsd}/zsys_freebsd_arm64.go (98%) rename src/{vendor/golang.org/x/net/route => internal/routebsd}/zsys_freebsd_riscv64.go (98%) rename src/{vendor/golang.org/x/net/route => internal/routebsd}/zsys_netbsd.go (95%) rename src/{vendor/golang.org/x/net/route => internal/routebsd}/zsys_openbsd.go (92%) diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index e3e01077c18b17..e96578f8d38462 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -388,12 +388,14 @@ var depsRules = ` os < golang.org/x/net/dns/dnsmessage, - golang.org/x/net/lif, - golang.org/x/net/route; + golang.org/x/net/lif; internal/bytealg, internal/itoa, math/bits, slices, strconv, unique < net/netip; + os, net/netip + < internal/routebsd; + # net is unavoidable when doing any networking, # so large dependencies must be kept out. # This is a long-looking list but most of these @@ -401,10 +403,10 @@ var depsRules = ` CGO, golang.org/x/net/dns/dnsmessage, golang.org/x/net/lif, - golang.org/x/net/route, internal/godebug, internal/nettrace, internal/poll, + internal/routebsd, internal/singleflight, net/netip, os, diff --git a/src/vendor/golang.org/x/net/route/address.go b/src/internal/routebsd/address.go similarity index 99% rename from src/vendor/golang.org/x/net/route/address.go rename to src/internal/routebsd/address.go index b649f431410159..9479bb10e3a384 100644 --- a/src/vendor/golang.org/x/net/route/address.go +++ b/src/internal/routebsd/address.go @@ -4,7 +4,7 @@ //go:build darwin || dragonfly || freebsd || netbsd || openbsd -package route +package routebsd import ( "runtime" diff --git a/src/internal/routebsd/address_darwin_test.go b/src/internal/routebsd/address_darwin_test.go new file mode 100644 index 00000000000000..02a407a0c77a51 --- /dev/null +++ b/src/internal/routebsd/address_darwin_test.go @@ -0,0 +1,170 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package routebsd + +import ( + "reflect" + "syscall" + "testing" +) + +type parseAddrsOnDarwinTest struct { + attrs uint + fn func(int, []byte) (int, Addr, error) + b []byte + as []Addr +} + +var parseAddrsOnDarwinLittleEndianTests = []parseAddrsOnDarwinTest{ + { + syscall.RTA_DST | syscall.RTA_GATEWAY | syscall.RTA_NETMASK, + parseKernelInetAddr, + []byte{ + 0x10, 0x2, 0x0, 0x0, 0xc0, 0xa8, 0x56, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + + 0x14, 0x12, 0x4, 0x0, 0x6, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + + 0x7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + []Addr{ + &Inet4Addr{IP: [4]byte{192, 168, 86, 0}}, + &LinkAddr{Index: 4}, + &Inet4Addr{IP: [4]byte{255, 255, 255, 255}}, + nil, + nil, + nil, + nil, + nil, + }, + }, + { + syscall.RTA_DST | syscall.RTA_GATEWAY | syscall.RTA_NETMASK, + parseKernelInetAddr, + []byte{ + 0x10, 0x02, 0x00, 0x00, 0x64, 0x71, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x14, 0x12, 0x21, 0x00, 0x01, 0x08, 0x00, 0x00, + 0x75, 0x74, 0x75, 0x6e, 0x34, 0x33, 0x31, 0x39, + 0x00, 0x00, 0x00, 0x00, + + 0x06, 0x02, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + }, + []Addr{ + &Inet4Addr{IP: [4]byte{100, 113, 0, 0}}, + &LinkAddr{Index: 33, Name: "utun4319"}, + &Inet4Addr{IP: [4]byte{255, 255, 0, 0}}, + nil, + nil, + nil, + nil, + nil, + }, + }, + // route -n add -inet6 fd84:1b4e:6281:: -prefixlen 48 fe80::f22f:4bff:fe09:3bff%utun4319 + // gw fe80:0000:0000:0000:f22f:4bff:fe09:3bff + { + syscall.RTA_DST | syscall.RTA_GATEWAY | syscall.RTA_NETMASK, + parseKernelInetAddr, + []byte{ + 0x1c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfd, 0x84, 0x1b, 0x4e, 0x62, 0x81, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + + 0x1c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0x80, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, + 0xf2, 0x2f, 0x4b, 0xff, 0xfe, 0x09, 0x3b, 0xff, + 0x00, 0x00, 0x00, 0x00, + + 0x0e, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + }, + []Addr{ + &Inet6Addr{IP: [16]byte{0xfd, 0x84, 0x1b, 0x4e, 0x62, 0x81}}, + &Inet6Addr{IP: [16]byte{0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x2f, 0x4b, 0xff, 0xfe, 0x09, 0x3b, 0xff}, ZoneID: 33}, + &Inet6Addr{IP: [16]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, + nil, + nil, + nil, + nil, + nil, + }, + }, + // golang/go#70528, the kernel can produce addresses of length 0 + { + syscall.RTA_DST | syscall.RTA_GATEWAY | syscall.RTA_NETMASK, + parseKernelInetAddr, + []byte{ + 0x00, 0x1e, 0x00, 0x00, + + 0x1c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0x80, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, + 0xf2, 0x2f, 0x4b, 0xff, 0xfe, 0x09, 0x3b, 0xff, + 0x00, 0x00, 0x00, 0x00, + + 0x0e, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + }, + []Addr{ + nil, + &Inet6Addr{IP: [16]byte{0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x2f, 0x4b, 0xff, 0xfe, 0x09, 0x3b, 0xff}, ZoneID: 33}, + &Inet6Addr{IP: [16]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, + nil, + nil, + nil, + nil, + nil, + }, + }, + // Additional case: golang/go/issues/70528#issuecomment-2498692877 + { + syscall.RTA_DST | syscall.RTA_GATEWAY | syscall.RTA_NETMASK, + parseKernelInetAddr, + []byte{ + 0x84, 0x00, 0x05, 0x04, 0x01, 0x00, 0x00, 0x00, 0x03, 0x08, 0x00, 0x01, 0x15, 0x00, 0x00, 0x00, + 0x1B, 0x01, 0x00, 0x00, 0xF5, 0x5A, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x14, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + }, + []Addr{ + &Inet4Addr{IP: [4]byte{0x0, 0x0, 0x0, 0x0}}, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + }, + }, +} + +func TestParseAddrsOnDarwin(t *testing.T) { + tests := parseAddrsOnDarwinLittleEndianTests + if nativeEndian != littleEndian { + t.Skip("no test for non-little endian machine yet") + } + + for i, tt := range tests { + as, err := parseAddrs(tt.attrs, tt.fn, tt.b) + if err != nil { + t.Error(i, err) + continue + } + if !reflect.DeepEqual(as, tt.as) { + t.Errorf("#%d: got %+v; want %+v", i, as, tt.as) + continue + } + } +} diff --git a/src/internal/routebsd/address_test.go b/src/internal/routebsd/address_test.go new file mode 100644 index 00000000000000..c230bb2f1cca3b --- /dev/null +++ b/src/internal/routebsd/address_test.go @@ -0,0 +1,104 @@ +// Copyright 2016 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. + +//go:build darwin || dragonfly || freebsd || netbsd || openbsd + +package routebsd + +import ( + "reflect" + "syscall" + "testing" +) + +type parseAddrsTest struct { + attrs uint + fn func(int, []byte) (int, Addr, error) + b []byte + as []Addr +} + +var parseAddrsLittleEndianTests = []parseAddrsTest{ + { + syscall.RTA_DST | syscall.RTA_GATEWAY | syscall.RTA_NETMASK | syscall.RTA_BRD, + parseKernelInetAddr, + []byte{ + 0x38, 0x12, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + + 0x38, 0x12, 0x2, 0x0, 0x6, 0x3, 0x6, 0x0, + 0x65, 0x6d, 0x31, 0x0, 0xc, 0x29, 0x66, 0x2c, + 0xdc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + + 0x10, 0x2, 0x0, 0x0, 0xac, 0x10, 0xdc, 0xb4, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + + 0x10, 0x2, 0x0, 0x0, 0xac, 0x10, 0xdc, 0xff, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + }, + []Addr{ + &LinkAddr{Index: 0}, + &LinkAddr{Index: 2, Name: "em1", Addr: []byte{0x00, 0x0c, 0x29, 0x66, 0x2c, 0xdc}}, + &Inet4Addr{IP: [4]byte{172, 16, 220, 180}}, + nil, + nil, + nil, + nil, + &Inet4Addr{IP: [4]byte{172, 16, 220, 255}}, + }, + }, + { + syscall.RTA_NETMASK | syscall.RTA_IFP | syscall.RTA_IFA, + parseKernelInetAddr, + []byte{ + 0x7, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, + + 0x18, 0x12, 0xa, 0x0, 0x87, 0x8, 0x0, 0x0, + 0x76, 0x6c, 0x61, 0x6e, 0x35, 0x36, 0x38, 0x32, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + + 0x10, 0x2, 0x0, 0x0, 0xa9, 0xfe, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + }, + []Addr{ + nil, + nil, + &Inet4Addr{IP: [4]byte{255, 255, 255, 0}}, + nil, + &LinkAddr{Index: 10, Name: "vlan5682"}, + &Inet4Addr{IP: [4]byte{169, 254, 0, 1}}, + nil, + nil, + }, + }, +} + +func TestParseAddrs(t *testing.T) { + tests := parseAddrsLittleEndianTests + if nativeEndian != littleEndian { + t.Skip("no test for non-little endian machine yet") + } + + for i, tt := range tests { + as, err := parseAddrs(tt.attrs, tt.fn, tt.b) + if err != nil { + t.Error(i, err) + continue + } + as = as[:8] // the list varies between operating systems + if !reflect.DeepEqual(as, tt.as) { + t.Errorf("#%d: got %+v; want %+v", i, as, tt.as) + continue + } + } +} diff --git a/src/vendor/golang.org/x/net/route/binary.go b/src/internal/routebsd/binary.go similarity index 99% rename from src/vendor/golang.org/x/net/route/binary.go rename to src/internal/routebsd/binary.go index db3f7e0c2a5ed4..66b234c4f2c8a0 100644 --- a/src/vendor/golang.org/x/net/route/binary.go +++ b/src/internal/routebsd/binary.go @@ -4,7 +4,7 @@ //go:build darwin || dragonfly || freebsd || netbsd || openbsd -package route +package routebsd // This file contains duplicates of encoding/binary package. // diff --git a/src/vendor/golang.org/x/net/route/empty.s b/src/internal/routebsd/empty.s similarity index 100% rename from src/vendor/golang.org/x/net/route/empty.s rename to src/internal/routebsd/empty.s diff --git a/src/vendor/golang.org/x/net/route/interface.go b/src/internal/routebsd/interface.go similarity index 99% rename from src/vendor/golang.org/x/net/route/interface.go rename to src/internal/routebsd/interface.go index 0aa70555ca6aef..a1523329b143ac 100644 --- a/src/vendor/golang.org/x/net/route/interface.go +++ b/src/internal/routebsd/interface.go @@ -4,7 +4,7 @@ //go:build darwin || dragonfly || freebsd || netbsd || openbsd -package route +package routebsd // An InterfaceMessage represents an interface message. type InterfaceMessage struct { diff --git a/src/vendor/golang.org/x/net/route/interface_announce.go b/src/internal/routebsd/interface_announce.go similarity index 97% rename from src/vendor/golang.org/x/net/route/interface_announce.go rename to src/internal/routebsd/interface_announce.go index 70614c1b1a17ef..834f8d35185e9f 100644 --- a/src/vendor/golang.org/x/net/route/interface_announce.go +++ b/src/internal/routebsd/interface_announce.go @@ -4,7 +4,7 @@ //go:build dragonfly || freebsd || netbsd -package route +package routebsd func (w *wireFormat) parseInterfaceAnnounceMessage(_ RIBType, b []byte) (Message, error) { if len(b) < w.bodyOff { diff --git a/src/vendor/golang.org/x/net/route/interface_classic.go b/src/internal/routebsd/interface_classic.go similarity index 98% rename from src/vendor/golang.org/x/net/route/interface_classic.go rename to src/internal/routebsd/interface_classic.go index be1bf2652e675a..9d706a50dc29c8 100644 --- a/src/vendor/golang.org/x/net/route/interface_classic.go +++ b/src/internal/routebsd/interface_classic.go @@ -4,7 +4,7 @@ //go:build darwin || dragonfly || netbsd -package route +package routebsd import ( "runtime" diff --git a/src/vendor/golang.org/x/net/route/interface_freebsd.go b/src/internal/routebsd/interface_freebsd.go similarity index 99% rename from src/vendor/golang.org/x/net/route/interface_freebsd.go rename to src/internal/routebsd/interface_freebsd.go index 14d251c94f9084..4a3ad8e30be051 100644 --- a/src/vendor/golang.org/x/net/route/interface_freebsd.go +++ b/src/internal/routebsd/interface_freebsd.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package route +package routebsd import "syscall" diff --git a/src/vendor/golang.org/x/net/route/interface_multicast.go b/src/internal/routebsd/interface_multicast.go similarity index 97% rename from src/vendor/golang.org/x/net/route/interface_multicast.go rename to src/internal/routebsd/interface_multicast.go index 2ee37b9c749aef..c00199cf494201 100644 --- a/src/vendor/golang.org/x/net/route/interface_multicast.go +++ b/src/internal/routebsd/interface_multicast.go @@ -4,7 +4,7 @@ //go:build darwin || dragonfly || freebsd -package route +package routebsd func (w *wireFormat) parseInterfaceMulticastAddrMessage(_ RIBType, b []byte) (Message, error) { if len(b) < w.bodyOff { diff --git a/src/vendor/golang.org/x/net/route/interface_openbsd.go b/src/internal/routebsd/interface_openbsd.go similarity index 99% rename from src/vendor/golang.org/x/net/route/interface_openbsd.go rename to src/internal/routebsd/interface_openbsd.go index d369409a725227..208ff78425a94a 100644 --- a/src/vendor/golang.org/x/net/route/interface_openbsd.go +++ b/src/internal/routebsd/interface_openbsd.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package route +package routebsd import "syscall" diff --git a/src/vendor/golang.org/x/net/route/message.go b/src/internal/routebsd/message.go similarity index 98% rename from src/vendor/golang.org/x/net/route/message.go rename to src/internal/routebsd/message.go index dc8bfc5b3aa728..f8666b66486ada 100644 --- a/src/vendor/golang.org/x/net/route/message.go +++ b/src/internal/routebsd/message.go @@ -4,7 +4,7 @@ //go:build darwin || dragonfly || freebsd || netbsd || openbsd -package route +package routebsd // A Message represents a routing message. type Message interface { diff --git a/src/internal/routebsd/message_darwin_test.go b/src/internal/routebsd/message_darwin_test.go new file mode 100644 index 00000000000000..a7fbdecf5d1e90 --- /dev/null +++ b/src/internal/routebsd/message_darwin_test.go @@ -0,0 +1,37 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package routebsd + +import ( + "syscall" + "testing" +) + +func TestFetchAndParseRIBOnDarwin(t *testing.T) { + for _, typ := range []RIBType{syscall.NET_RT_FLAGS, syscall.NET_RT_DUMP2, syscall.NET_RT_IFLIST2} { + var lastErr error + var ms []Message + for _, af := range []int{syscall.AF_UNSPEC, syscall.AF_INET, syscall.AF_INET6} { + rs, err := fetchAndParseRIB(af, typ) + if err != nil { + lastErr = err + continue + } + ms = append(ms, rs...) + } + if len(ms) == 0 && lastErr != nil { + t.Error(typ, lastErr) + continue + } + ss, err := msgs(ms).validate() + if err != nil { + t.Error(typ, err) + continue + } + for _, s := range ss { + t.Log(s) + } + } +} diff --git a/src/internal/routebsd/message_freebsd_test.go b/src/internal/routebsd/message_freebsd_test.go new file mode 100644 index 00000000000000..f165e7c0e7fa57 --- /dev/null +++ b/src/internal/routebsd/message_freebsd_test.go @@ -0,0 +1,91 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package routebsd + +import ( + "syscall" + "testing" +) + +func TestFetchAndParseRIBOnFreeBSD(t *testing.T) { + for _, typ := range []RIBType{syscall.NET_RT_IFMALIST} { + var lastErr error + var ms []Message + for _, af := range []int{syscall.AF_UNSPEC, syscall.AF_INET, syscall.AF_INET6} { + rs, err := fetchAndParseRIB(af, typ) + if err != nil { + lastErr = err + continue + } + ms = append(ms, rs...) + } + if len(ms) == 0 && lastErr != nil { + t.Error(typ, lastErr) + continue + } + ss, err := msgs(ms).validate() + if err != nil { + t.Error(typ, err) + continue + } + for _, s := range ss { + t.Log(s) + } + } +} + +func TestFetchAndParseRIBOnFreeBSD10AndAbove(t *testing.T) { + if _, err := FetchRIB(syscall.AF_UNSPEC, syscall.NET_RT_IFLISTL, 0); err != nil { + t.Skip("NET_RT_IFLISTL not supported") + } + if compatFreeBSD32 { + t.Skip("NET_RT_IFLIST vs. NET_RT_IFLISTL doesn't work for 386 emulation on amd64") + } + + var tests = [2]struct { + typ RIBType + b []byte + msgs []Message + ss []string + }{ + {typ: syscall.NET_RT_IFLIST}, + {typ: syscall.NET_RT_IFLISTL}, + } + for i := range tests { + var lastErr error + for _, af := range []int{syscall.AF_UNSPEC, syscall.AF_INET, syscall.AF_INET6} { + rs, err := fetchAndParseRIB(af, tests[i].typ) + if err != nil { + lastErr = err + continue + } + tests[i].msgs = append(tests[i].msgs, rs...) + } + if len(tests[i].msgs) == 0 && lastErr != nil { + t.Error(tests[i].typ, lastErr) + continue + } + tests[i].ss, lastErr = msgs(tests[i].msgs).validate() + if lastErr != nil { + t.Error(tests[i].typ, lastErr) + continue + } + for _, s := range tests[i].ss { + t.Log(s) + } + } + for i := len(tests) - 1; i > 0; i-- { + if len(tests[i].ss) != len(tests[i-1].ss) { + t.Errorf("got %v; want %v", tests[i].ss, tests[i-1].ss) + continue + } + for j, s1 := range tests[i].ss { + s0 := tests[i-1].ss[j] + if s1 != s0 { + t.Errorf("got %s; want %s", s1, s0) + } + } + } +} diff --git a/src/internal/routebsd/message_test.go b/src/internal/routebsd/message_test.go new file mode 100644 index 00000000000000..9d0d7284fcc001 --- /dev/null +++ b/src/internal/routebsd/message_test.go @@ -0,0 +1,238 @@ +// Copyright 2016 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. + +//go:build darwin || dragonfly || freebsd || netbsd || openbsd + +package routebsd + +import ( + "os" + "syscall" + "testing" + "time" +) + +func TestFetchAndParseRIB(t *testing.T) { + for _, typ := range []RIBType{syscall.NET_RT_DUMP, syscall.NET_RT_IFLIST} { + var lastErr error + var ms []Message + for _, af := range []int{syscall.AF_UNSPEC, syscall.AF_INET, syscall.AF_INET6} { + rs, err := fetchAndParseRIB(af, typ) + if err != nil { + lastErr = err + continue + } + ms = append(ms, rs...) + } + if len(ms) == 0 && lastErr != nil { + t.Error(typ, lastErr) + continue + } + ss, err := msgs(ms).validate() + if err != nil { + t.Error(typ, err) + continue + } + for _, s := range ss { + t.Log(typ, s) + } + } +} + +var ( + rtmonSock int + rtmonErr error +) + +func init() { + // We need to keep rtmonSock alive to avoid treading on + // recycled socket descriptors. + rtmonSock, rtmonErr = syscall.Socket(syscall.AF_ROUTE, syscall.SOCK_RAW, syscall.AF_UNSPEC) +} + +// TestMonitorAndParseRIB leaks a worker goroutine and a socket +// descriptor but that's intentional. +func TestMonitorAndParseRIB(t *testing.T) { + if testing.Short() || os.Getuid() != 0 { + t.Skip("must be root") + } + + if rtmonErr != nil { + t.Fatal(rtmonErr) + } + + // We suppose that using an IPv4 link-local address and the + // dot1Q ID for Token Ring and FDDI doesn't harm anyone. + pv := &propVirtual{addr: "169.254.0.1", mask: "255.255.255.0"} + if err := pv.configure(1002); err != nil { + t.Skip(err) + } + if err := pv.setup(); err != nil { + t.Skip(err) + } + pv.teardown() + + go func() { + b := make([]byte, os.Getpagesize()) + for { + // There's no easy way to unblock this read + // call because the routing message exchange + // over routing socket is a connectionless + // message-oriented protocol, no control plane + // for signaling connectivity, and we cannot + // use the net package of standard library due + // to the lack of support for routing socket + // and circular dependency. + n, err := syscall.Read(rtmonSock, b) + if err != nil { + return + } + ms, err := ParseRIB(0, b[:n]) + if err != nil { + t.Error(err) + return + } + ss, err := msgs(ms).validate() + if err != nil { + t.Error(err) + return + } + for _, s := range ss { + t.Log(s) + } + } + }() + + for _, vid := range []int{1002, 1003, 1004, 1005} { + pv := &propVirtual{addr: "169.254.0.1", mask: "255.255.255.0"} + if err := pv.configure(vid); err != nil { + t.Fatal(err) + } + if err := pv.setup(); err != nil { + t.Fatal(err) + } + time.Sleep(200 * time.Millisecond) + if err := pv.teardown(); err != nil { + t.Fatal(err) + } + time.Sleep(200 * time.Millisecond) + } +} + +func TestParseRIBWithFuzz(t *testing.T) { + for _, fuzz := range []string{ + "0\x00\x05\x050000000000000000" + + "00000000000000000000" + + "00000000000000000000" + + "00000000000000000000" + + "0000000000000\x02000000" + + "00000000", + "\x02\x00\x05\f0000000000000000" + + "0\x0200000000000000", + "\x02\x00\x05\x100000000000000\x1200" + + "0\x00\xff\x00", + "\x02\x00\x05\f0000000000000000" + + "0\x12000\x00\x02\x0000", + "\x00\x00\x00\x01\x00", + "00000", + } { + for typ := RIBType(0); typ < 256; typ++ { + ParseRIB(typ, []byte(fuzz)) + } + } +} + +func TestRouteMessage(t *testing.T) { + s, err := syscall.Socket(syscall.AF_ROUTE, syscall.SOCK_RAW, syscall.AF_UNSPEC) + if err != nil { + t.Fatal(err) + } + defer syscall.Close(s) + + var ms []RouteMessage + for _, af := range []int{syscall.AF_INET, syscall.AF_INET6} { + if _, err := fetchAndParseRIB(af, syscall.NET_RT_DUMP); err != nil { + t.Log(err) + continue + } + switch af { + case syscall.AF_INET: + ms = append(ms, []RouteMessage{ + { + Type: syscall.RTM_GET, + Addrs: []Addr{ + syscall.RTAX_DST: &Inet4Addr{IP: [4]byte{127, 0, 0, 1}}, + syscall.RTAX_GATEWAY: nil, + syscall.RTAX_NETMASK: nil, + syscall.RTAX_GENMASK: nil, + syscall.RTAX_IFP: &LinkAddr{}, + syscall.RTAX_IFA: &Inet4Addr{}, + syscall.RTAX_AUTHOR: nil, + syscall.RTAX_BRD: &Inet4Addr{}, + }, + }, + { + Type: syscall.RTM_GET, + Addrs: []Addr{ + syscall.RTAX_DST: &Inet4Addr{IP: [4]byte{127, 0, 0, 1}}, + }, + }, + }...) + case syscall.AF_INET6: + ms = append(ms, []RouteMessage{ + { + Type: syscall.RTM_GET, + Addrs: []Addr{ + syscall.RTAX_DST: &Inet6Addr{IP: [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}, + syscall.RTAX_GATEWAY: nil, + syscall.RTAX_NETMASK: nil, + syscall.RTAX_GENMASK: nil, + syscall.RTAX_IFP: &LinkAddr{}, + syscall.RTAX_IFA: &Inet6Addr{}, + syscall.RTAX_AUTHOR: nil, + syscall.RTAX_BRD: &Inet6Addr{}, + }, + }, + { + Type: syscall.RTM_GET, + Addrs: []Addr{ + syscall.RTAX_DST: &Inet6Addr{IP: [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}, + }, + }, + }...) + } + } + for i, m := range ms { + m.ID = uintptr(os.Getpid()) + m.Seq = i + 1 + wb, err := m.Marshal() + if err != nil { + t.Fatalf("%v: %v", m, err) + } + if _, err := syscall.Write(s, wb); err != nil { + t.Fatalf("%v: %v", m, err) + } + rb := make([]byte, os.Getpagesize()) + n, err := syscall.Read(s, rb) + if err != nil { + t.Fatalf("%v: %v", m, err) + } + rms, err := ParseRIB(0, rb[:n]) + if err != nil { + t.Fatalf("%v: %v", m, err) + } + for _, rm := range rms { + if rm, ok := rm.(*RouteMessage); ok && rm.Err != nil { + t.Errorf("%v: %v", m, rm.Err) + } + } + ss, err := msgs(rms).validate() + if err != nil { + t.Fatalf("%v: %v", m, err) + } + for _, s := range ss { + t.Log(s) + } + } +} diff --git a/src/vendor/golang.org/x/net/route/route.go b/src/internal/routebsd/route.go similarity index 99% rename from src/vendor/golang.org/x/net/route/route.go rename to src/internal/routebsd/route.go index ca2ce2b88764cb..d519c295fe71ff 100644 --- a/src/vendor/golang.org/x/net/route/route.go +++ b/src/internal/routebsd/route.go @@ -10,7 +10,7 @@ // The package supports any version of Darwin, any version of // DragonFly BSD, FreeBSD 7 and above, NetBSD 6 and above, and OpenBSD // 5.6 and above. -package route +package routebsd import ( "errors" diff --git a/src/vendor/golang.org/x/net/route/route_classic.go b/src/internal/routebsd/route_classic.go similarity index 99% rename from src/vendor/golang.org/x/net/route/route_classic.go rename to src/internal/routebsd/route_classic.go index e273fe39ab32e1..0d105d7bd43734 100644 --- a/src/vendor/golang.org/x/net/route/route_classic.go +++ b/src/internal/routebsd/route_classic.go @@ -4,7 +4,7 @@ //go:build darwin || dragonfly || freebsd || netbsd -package route +package routebsd import ( "runtime" diff --git a/src/vendor/golang.org/x/net/route/route_openbsd.go b/src/internal/routebsd/route_openbsd.go similarity index 99% rename from src/vendor/golang.org/x/net/route/route_openbsd.go rename to src/internal/routebsd/route_openbsd.go index f848fb1f2453ae..e125b890067ac9 100644 --- a/src/vendor/golang.org/x/net/route/route_openbsd.go +++ b/src/internal/routebsd/route_openbsd.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package route +package routebsd import ( "syscall" diff --git a/src/internal/routebsd/route_test.go b/src/internal/routebsd/route_test.go new file mode 100644 index 00000000000000..2ac5fee9bdd64b --- /dev/null +++ b/src/internal/routebsd/route_test.go @@ -0,0 +1,382 @@ +// Copyright 2016 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. + +//go:build darwin || dragonfly || freebsd || netbsd || openbsd + +package routebsd + +import ( + "fmt" + "os/exec" + "runtime" + "syscall" +) + +func (m *RouteMessage) String() string { + return fmt.Sprintf("%s", addrAttrs(nativeEndian.Uint32(m.raw[12:16]))) +} + +func (m *InterfaceMessage) String() string { + var attrs addrAttrs + if runtime.GOOS == "openbsd" { + attrs = addrAttrs(nativeEndian.Uint32(m.raw[12:16])) + } else { + attrs = addrAttrs(nativeEndian.Uint32(m.raw[4:8])) + } + return fmt.Sprintf("%s", attrs) +} + +func (m *InterfaceAddrMessage) String() string { + var attrs addrAttrs + if runtime.GOOS == "openbsd" { + attrs = addrAttrs(nativeEndian.Uint32(m.raw[12:16])) + } else { + attrs = addrAttrs(nativeEndian.Uint32(m.raw[4:8])) + } + return fmt.Sprintf("%s", attrs) +} + +func (m *InterfaceMulticastAddrMessage) String() string { + return fmt.Sprintf("%s", addrAttrs(nativeEndian.Uint32(m.raw[4:8]))) +} + +func (m *InterfaceAnnounceMessage) String() string { + what := "" + switch m.What { + case 0: + what = "arrival" + case 1: + what = "departure" + } + return fmt.Sprintf("(%d %s %s)", m.Index, m.Name, what) +} + +func (m *InterfaceMetrics) String() string { + return fmt.Sprintf("(type=%d mtu=%d)", m.Type, m.MTU) +} + +func (m *RouteMetrics) String() string { + return fmt.Sprintf("(pmtu=%d)", m.PathMTU) +} + +type addrAttrs uint + +var addrAttrNames = [...]string{ + "dst", + "gateway", + "netmask", + "genmask", + "ifp", + "ifa", + "author", + "brd", + "df:mpls1-n:tag-o:src", // mpls1 for dragonfly, tag for netbsd, src for openbsd + "df:mpls2-o:srcmask", // mpls2 for dragonfly, srcmask for openbsd + "df:mpls3-o:label", // mpls3 for dragonfly, label for openbsd + "o:bfd", // bfd for openbsd + "o:dns", // dns for openbsd + "o:static", // static for openbsd + "o:search", // search for openbsd +} + +func (attrs addrAttrs) String() string { + var s string + for i, name := range addrAttrNames { + if attrs&(1<" + } + return s +} + +type msgs []Message + +func (ms msgs) validate() ([]string, error) { + var ss []string + for _, m := range ms { + switch m := m.(type) { + case *RouteMessage: + if err := addrs(m.Addrs).match(addrAttrs(nativeEndian.Uint32(m.raw[12:16]))); err != nil { + return nil, err + } + sys := m.Sys() + if sys == nil { + return nil, fmt.Errorf("no sys for %s", m.String()) + } + ss = append(ss, m.String()+" "+syss(sys).String()+" "+addrs(m.Addrs).String()) + case *InterfaceMessage: + var attrs addrAttrs + if runtime.GOOS == "openbsd" { + attrs = addrAttrs(nativeEndian.Uint32(m.raw[12:16])) + } else { + attrs = addrAttrs(nativeEndian.Uint32(m.raw[4:8])) + } + if err := addrs(m.Addrs).match(attrs); err != nil { + return nil, err + } + sys := m.Sys() + if sys == nil { + return nil, fmt.Errorf("no sys for %s", m.String()) + } + ss = append(ss, m.String()+" "+syss(sys).String()+" "+addrs(m.Addrs).String()) + case *InterfaceAddrMessage: + var attrs addrAttrs + if runtime.GOOS == "openbsd" { + attrs = addrAttrs(nativeEndian.Uint32(m.raw[12:16])) + } else { + attrs = addrAttrs(nativeEndian.Uint32(m.raw[4:8])) + } + if err := addrs(m.Addrs).match(attrs); err != nil { + return nil, err + } + ss = append(ss, m.String()+" "+addrs(m.Addrs).String()) + case *InterfaceMulticastAddrMessage: + if err := addrs(m.Addrs).match(addrAttrs(nativeEndian.Uint32(m.raw[4:8]))); err != nil { + return nil, err + } + ss = append(ss, m.String()+" "+addrs(m.Addrs).String()) + case *InterfaceAnnounceMessage: + ss = append(ss, m.String()) + default: + ss = append(ss, fmt.Sprintf("%+v", m)) + } + } + return ss, nil +} + +type syss []Sys + +func (sys syss) String() string { + var s string + for _, sy := range sys { + switch sy := sy.(type) { + case *InterfaceMetrics: + if len(s) > 0 { + s += " " + } + s += sy.String() + case *RouteMetrics: + if len(s) > 0 { + s += " " + } + s += sy.String() + } + } + return s +} + +type addrFamily int + +func (af addrFamily) String() string { + switch af { + case syscall.AF_UNSPEC: + return "unspec" + case syscall.AF_LINK: + return "link" + case syscall.AF_INET: + return "inet4" + case syscall.AF_INET6: + return "inet6" + default: + return fmt.Sprintf("%d", af) + } +} + +const hexDigit = "0123456789abcdef" + +type llAddr []byte + +func (a llAddr) String() string { + if len(a) == 0 { + return "" + } + buf := make([]byte, 0, len(a)*3-1) + for i, b := range a { + if i > 0 { + buf = append(buf, ':') + } + buf = append(buf, hexDigit[b>>4]) + buf = append(buf, hexDigit[b&0xF]) + } + return string(buf) +} + +type ipAddr []byte + +func (a ipAddr) String() string { + if len(a) == 0 { + return "" + } + if len(a) == 4 { + return fmt.Sprintf("%d.%d.%d.%d", a[0], a[1], a[2], a[3]) + } + if len(a) == 16 { + return fmt.Sprintf("%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]) + } + s := make([]byte, len(a)*2) + for i, tn := range a { + s[i*2], s[i*2+1] = hexDigit[tn>>4], hexDigit[tn&0xf] + } + return string(s) +} + +func (a *LinkAddr) String() string { + name := a.Name + if name == "" { + name = "" + } + lla := llAddr(a.Addr).String() + if lla == "" { + lla = "" + } + return fmt.Sprintf("(%v %d %s %s)", addrFamily(a.Family()), a.Index, name, lla) +} + +func (a *Inet4Addr) String() string { + return fmt.Sprintf("(%v %v)", addrFamily(a.Family()), ipAddr(a.IP[:])) +} + +func (a *Inet6Addr) String() string { + return fmt.Sprintf("(%v %v %d)", addrFamily(a.Family()), ipAddr(a.IP[:]), a.ZoneID) +} + +func (a *DefaultAddr) String() string { + return fmt.Sprintf("(%v %s)", addrFamily(a.Family()), ipAddr(a.Raw[2:]).String()) +} + +type addrs []Addr + +func (as addrs) String() string { + var s string + for _, a := range as { + if a == nil { + continue + } + if len(s) > 0 { + s += " " + } + switch a := a.(type) { + case *LinkAddr: + s += a.String() + case *Inet4Addr: + s += a.String() + case *Inet6Addr: + s += a.String() + case *DefaultAddr: + s += a.String() + } + } + if s == "" { + return "" + } + return s +} + +func (as addrs) match(attrs addrAttrs) error { + var ts addrAttrs + af := syscall.AF_UNSPEC + for i := range as { + if as[i] != nil { + ts |= 1 << uint(i) + } + switch as[i].(type) { + case *Inet4Addr: + if af == syscall.AF_UNSPEC { + af = syscall.AF_INET + } + if af != syscall.AF_INET { + return fmt.Errorf("got %v; want %v", addrs(as), addrFamily(af)) + } + case *Inet6Addr: + if af == syscall.AF_UNSPEC { + af = syscall.AF_INET6 + } + if af != syscall.AF_INET6 { + return fmt.Errorf("got %v; want %v", addrs(as), addrFamily(af)) + } + } + } + if ts != attrs && ts > attrs { + return fmt.Errorf("%v not included in %v", ts, attrs) + } + return nil +} + +func fetchAndParseRIB(af int, typ RIBType) ([]Message, error) { + b, err := FetchRIB(af, typ, 0) + if err != nil { + return nil, fmt.Errorf("%v %d %v", addrFamily(af), typ, err) + } + ms, err := ParseRIB(typ, b) + if err != nil { + return nil, fmt.Errorf("%v %d %v", addrFamily(af), typ, err) + } + return ms, nil +} + +// propVirtual is a proprietary virtual network interface. +type propVirtual struct { + name string + addr, mask string + setupCmds []*exec.Cmd + teardownCmds []*exec.Cmd +} + +func (pv *propVirtual) setup() error { + for _, cmd := range pv.setupCmds { + if err := cmd.Run(); err != nil { + pv.teardown() + return err + } + } + return nil +} + +func (pv *propVirtual) teardown() error { + for _, cmd := range pv.teardownCmds { + if err := cmd.Run(); err != nil { + return err + } + } + return nil +} + +func (pv *propVirtual) configure(suffix int) error { + if runtime.GOOS == "openbsd" { + pv.name = fmt.Sprintf("vether%d", suffix) + } else { + pv.name = fmt.Sprintf("vlan%d", suffix) + } + xname, err := exec.LookPath("ifconfig") + if err != nil { + return err + } + pv.setupCmds = append(pv.setupCmds, &exec.Cmd{ + Path: xname, + Args: []string{"ifconfig", pv.name, "create"}, + }) + if runtime.GOOS == "netbsd" { + // NetBSD requires an underlying dot1Q-capable network + // interface. + pv.setupCmds = append(pv.setupCmds, &exec.Cmd{ + Path: xname, + Args: []string{"ifconfig", pv.name, "vlan", fmt.Sprintf("%d", suffix&0xfff), "vlanif", "wm0"}, + }) + } + pv.setupCmds = append(pv.setupCmds, &exec.Cmd{ + Path: xname, + Args: []string{"ifconfig", pv.name, "inet", pv.addr, "netmask", pv.mask}, + }) + pv.teardownCmds = append(pv.teardownCmds, &exec.Cmd{ + Path: xname, + Args: []string{"ifconfig", pv.name, "destroy"}, + }) + return nil +} diff --git a/src/vendor/golang.org/x/net/route/sys.go b/src/internal/routebsd/sys.go similarity index 98% rename from src/vendor/golang.org/x/net/route/sys.go rename to src/internal/routebsd/sys.go index fcebee58ec6da2..69ef7b78716b1e 100644 --- a/src/vendor/golang.org/x/net/route/sys.go +++ b/src/internal/routebsd/sys.go @@ -4,7 +4,7 @@ //go:build darwin || dragonfly || freebsd || netbsd || openbsd -package route +package routebsd import ( "syscall" diff --git a/src/vendor/golang.org/x/net/route/sys_darwin.go b/src/internal/routebsd/sys_darwin.go similarity index 99% rename from src/vendor/golang.org/x/net/route/sys_darwin.go rename to src/internal/routebsd/sys_darwin.go index c8c4eecb8e9c6d..2d8424a1c9b379 100644 --- a/src/vendor/golang.org/x/net/route/sys_darwin.go +++ b/src/internal/routebsd/sys_darwin.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package route +package routebsd import "syscall" diff --git a/src/vendor/golang.org/x/net/route/sys_dragonfly.go b/src/internal/routebsd/sys_dragonfly.go similarity index 99% rename from src/vendor/golang.org/x/net/route/sys_dragonfly.go rename to src/internal/routebsd/sys_dragonfly.go index 577fb16eb4bb53..a3ee0ff73f3ee5 100644 --- a/src/vendor/golang.org/x/net/route/sys_dragonfly.go +++ b/src/internal/routebsd/sys_dragonfly.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package route +package routebsd import ( "syscall" diff --git a/src/vendor/golang.org/x/net/route/sys_freebsd.go b/src/internal/routebsd/sys_freebsd.go similarity index 99% rename from src/vendor/golang.org/x/net/route/sys_freebsd.go rename to src/internal/routebsd/sys_freebsd.go index 0a66dcedb386d9..6136e66385977b 100644 --- a/src/vendor/golang.org/x/net/route/sys_freebsd.go +++ b/src/internal/routebsd/sys_freebsd.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package route +package routebsd import ( "syscall" diff --git a/src/vendor/golang.org/x/net/route/sys_netbsd.go b/src/internal/routebsd/sys_netbsd.go similarity index 99% rename from src/vendor/golang.org/x/net/route/sys_netbsd.go rename to src/internal/routebsd/sys_netbsd.go index be4460e13f044c..3a33174454db4b 100644 --- a/src/vendor/golang.org/x/net/route/sys_netbsd.go +++ b/src/internal/routebsd/sys_netbsd.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package route +package routebsd import "syscall" diff --git a/src/vendor/golang.org/x/net/route/sys_openbsd.go b/src/internal/routebsd/sys_openbsd.go similarity index 99% rename from src/vendor/golang.org/x/net/route/sys_openbsd.go rename to src/internal/routebsd/sys_openbsd.go index 7f4f93cbea088d..aaeb7284754adf 100644 --- a/src/vendor/golang.org/x/net/route/sys_openbsd.go +++ b/src/internal/routebsd/sys_openbsd.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package route +package routebsd import ( "syscall" diff --git a/src/vendor/golang.org/x/net/route/syscall.go b/src/internal/routebsd/syscall.go similarity index 95% rename from src/vendor/golang.org/x/net/route/syscall.go rename to src/internal/routebsd/syscall.go index 0ed53750a22f8a..559aa7dfdc613e 100644 --- a/src/vendor/golang.org/x/net/route/syscall.go +++ b/src/internal/routebsd/syscall.go @@ -4,7 +4,7 @@ //go:build darwin || dragonfly || freebsd || netbsd || openbsd -package route +package routebsd import _ "unsafe" // for linkname diff --git a/src/vendor/golang.org/x/net/route/zsys_darwin.go b/src/internal/routebsd/zsys_darwin.go similarity index 96% rename from src/vendor/golang.org/x/net/route/zsys_darwin.go rename to src/internal/routebsd/zsys_darwin.go index 56a0c66f44f202..3e6cbb0b0d6b08 100644 --- a/src/vendor/golang.org/x/net/route/zsys_darwin.go +++ b/src/internal/routebsd/zsys_darwin.go @@ -1,7 +1,7 @@ // Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs defs_darwin.go -package route +package routebsd const ( sizeofIfMsghdrDarwin15 = 0x70 diff --git a/src/vendor/golang.org/x/net/route/zsys_dragonfly.go b/src/internal/routebsd/zsys_dragonfly.go similarity index 96% rename from src/vendor/golang.org/x/net/route/zsys_dragonfly.go rename to src/internal/routebsd/zsys_dragonfly.go index f7c7a60cd64220..41e74d53ae7e4c 100644 --- a/src/vendor/golang.org/x/net/route/zsys_dragonfly.go +++ b/src/internal/routebsd/zsys_dragonfly.go @@ -1,7 +1,7 @@ // Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs defs_dragonfly.go -package route +package routebsd const ( sizeofIfMsghdrDragonFlyBSD4 = 0xb0 diff --git a/src/vendor/golang.org/x/net/route/zsys_freebsd_386.go b/src/internal/routebsd/zsys_freebsd_386.go similarity index 98% rename from src/vendor/golang.org/x/net/route/zsys_freebsd_386.go rename to src/internal/routebsd/zsys_freebsd_386.go index 3f985c7ee90c1d..2a85855477dd2e 100644 --- a/src/vendor/golang.org/x/net/route/zsys_freebsd_386.go +++ b/src/internal/routebsd/zsys_freebsd_386.go @@ -1,7 +1,7 @@ // Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs defs_freebsd.go -package route +package routebsd const ( sizeofIfMsghdrlFreeBSD10 = 0x68 diff --git a/src/vendor/golang.org/x/net/route/zsys_freebsd_amd64.go b/src/internal/routebsd/zsys_freebsd_amd64.go similarity index 98% rename from src/vendor/golang.org/x/net/route/zsys_freebsd_amd64.go rename to src/internal/routebsd/zsys_freebsd_amd64.go index 929339369829dc..ea7b959f052238 100644 --- a/src/vendor/golang.org/x/net/route/zsys_freebsd_amd64.go +++ b/src/internal/routebsd/zsys_freebsd_amd64.go @@ -1,7 +1,7 @@ // Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs defs_freebsd.go -package route +package routebsd const ( sizeofIfMsghdrlFreeBSD10 = 0xb0 diff --git a/src/vendor/golang.org/x/net/route/zsys_freebsd_arm.go b/src/internal/routebsd/zsys_freebsd_arm.go similarity index 98% rename from src/vendor/golang.org/x/net/route/zsys_freebsd_arm.go rename to src/internal/routebsd/zsys_freebsd_arm.go index a2bdb4ad3b58ea..1c3d653c869bbe 100644 --- a/src/vendor/golang.org/x/net/route/zsys_freebsd_arm.go +++ b/src/internal/routebsd/zsys_freebsd_arm.go @@ -1,7 +1,7 @@ // Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs defs_freebsd.go -package route +package routebsd const ( sizeofIfMsghdrlFreeBSD10 = 0x68 diff --git a/src/vendor/golang.org/x/net/route/zsys_freebsd_arm64.go b/src/internal/routebsd/zsys_freebsd_arm64.go similarity index 98% rename from src/vendor/golang.org/x/net/route/zsys_freebsd_arm64.go rename to src/internal/routebsd/zsys_freebsd_arm64.go index 929339369829dc..ea7b959f052238 100644 --- a/src/vendor/golang.org/x/net/route/zsys_freebsd_arm64.go +++ b/src/internal/routebsd/zsys_freebsd_arm64.go @@ -1,7 +1,7 @@ // Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs defs_freebsd.go -package route +package routebsd const ( sizeofIfMsghdrlFreeBSD10 = 0xb0 diff --git a/src/vendor/golang.org/x/net/route/zsys_freebsd_riscv64.go b/src/internal/routebsd/zsys_freebsd_riscv64.go similarity index 98% rename from src/vendor/golang.org/x/net/route/zsys_freebsd_riscv64.go rename to src/internal/routebsd/zsys_freebsd_riscv64.go index 929339369829dc..ea7b959f052238 100644 --- a/src/vendor/golang.org/x/net/route/zsys_freebsd_riscv64.go +++ b/src/internal/routebsd/zsys_freebsd_riscv64.go @@ -1,7 +1,7 @@ // Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs defs_freebsd.go -package route +package routebsd const ( sizeofIfMsghdrlFreeBSD10 = 0xb0 diff --git a/src/vendor/golang.org/x/net/route/zsys_netbsd.go b/src/internal/routebsd/zsys_netbsd.go similarity index 95% rename from src/vendor/golang.org/x/net/route/zsys_netbsd.go rename to src/internal/routebsd/zsys_netbsd.go index eaffe8c40804cb..f072c311dee870 100644 --- a/src/vendor/golang.org/x/net/route/zsys_netbsd.go +++ b/src/internal/routebsd/zsys_netbsd.go @@ -1,7 +1,7 @@ // Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs defs_netbsd.go -package route +package routebsd const ( sizeofIfMsghdrNetBSD7 = 0x98 diff --git a/src/vendor/golang.org/x/net/route/zsys_openbsd.go b/src/internal/routebsd/zsys_openbsd.go similarity index 92% rename from src/vendor/golang.org/x/net/route/zsys_openbsd.go rename to src/internal/routebsd/zsys_openbsd.go index b11b8126801b68..2bb764125420dc 100644 --- a/src/vendor/golang.org/x/net/route/zsys_openbsd.go +++ b/src/internal/routebsd/zsys_openbsd.go @@ -1,7 +1,7 @@ // Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs defs_openbsd.go -package route +package routebsd const ( sizeofRtMsghdr = 0x60 diff --git a/src/net/interface_bsd.go b/src/net/interface_bsd.go index 9b2b42addbb609..687af00170cc74 100644 --- a/src/net/interface_bsd.go +++ b/src/net/interface_bsd.go @@ -7,9 +7,8 @@ package net import ( + "internal/routebsd" "syscall" - - "golang.org/x/net/route" ) // If the ifindex is zero, interfaceTable returns mappings of all @@ -28,19 +27,19 @@ func interfaceTable(ifindex int) ([]Interface, error) { n = 0 for _, m := range msgs { switch m := m.(type) { - case *route.InterfaceMessage: + case *routebsd.InterfaceMessage: if ifindex != 0 && ifindex != m.Index { continue } ift[n].Index = m.Index ift[n].Name = m.Name ift[n].Flags = linkFlags(m.Flags) - if sa, ok := m.Addrs[syscall.RTAX_IFP].(*route.LinkAddr); ok && len(sa.Addr) > 0 { + if sa, ok := m.Addrs[syscall.RTAX_IFP].(*routebsd.LinkAddr); ok && len(sa.Addr) > 0 { ift[n].HardwareAddr = make([]byte, len(sa.Addr)) copy(ift[n].HardwareAddr, sa.Addr) } for _, sys := range m.Sys() { - if imx, ok := sys.(*route.InterfaceMetrics); ok { + if imx, ok := sys.(*routebsd.InterfaceMetrics); ok { ift[n].MTU = imx.MTU break } @@ -92,27 +91,27 @@ func interfaceAddrTable(ifi *Interface) ([]Addr, error) { ifat := make([]Addr, 0, len(msgs)) for _, m := range msgs { switch m := m.(type) { - case *route.InterfaceAddrMessage: + case *routebsd.InterfaceAddrMessage: if index != 0 && index != m.Index { continue } var mask IPMask switch sa := m.Addrs[syscall.RTAX_NETMASK].(type) { - case *route.Inet4Addr: + case *routebsd.Inet4Addr: mask = IPv4Mask(sa.IP[0], sa.IP[1], sa.IP[2], sa.IP[3]) - case *route.Inet6Addr: + case *routebsd.Inet6Addr: mask = make(IPMask, IPv6len) copy(mask, sa.IP[:]) } var ip IP switch sa := m.Addrs[syscall.RTAX_IFA].(type) { - case *route.Inet4Addr: + case *routebsd.Inet4Addr: ip = IPv4(sa.IP[0], sa.IP[1], sa.IP[2], sa.IP[3]) - case *route.Inet6Addr: + case *routebsd.Inet6Addr: ip = make(IP, IPv6len) copy(ip, sa.IP[:]) } - if ip != nil && mask != nil { // NetBSD may contain route.LinkAddr + if ip != nil && mask != nil { // NetBSD may contain routebsd.LinkAddr ifat = append(ifat, &IPNet{IP: ip, Mask: mask}) } } diff --git a/src/net/interface_bsdvar.go b/src/net/interface_bsdvar.go index e9bea3d3798a06..3946921232778c 100644 --- a/src/net/interface_bsdvar.go +++ b/src/net/interface_bsdvar.go @@ -7,17 +7,16 @@ package net import ( + "internal/routebsd" "syscall" - - "golang.org/x/net/route" ) -func interfaceMessages(ifindex int) ([]route.Message, error) { - rib, err := route.FetchRIB(syscall.AF_UNSPEC, syscall.NET_RT_IFLIST, ifindex) +func interfaceMessages(ifindex int) ([]routebsd.Message, error) { + rib, err := routebsd.FetchRIB(syscall.AF_UNSPEC, syscall.NET_RT_IFLIST, ifindex) if err != nil { return nil, err } - return route.ParseRIB(syscall.NET_RT_IFLIST, rib) + return routebsd.ParseRIB(syscall.NET_RT_IFLIST, rib) } // interfaceMulticastAddrTable returns addresses for a specific diff --git a/src/net/interface_darwin.go b/src/net/interface_darwin.go index bb4fd73a987670..45f1363025f7ce 100644 --- a/src/net/interface_darwin.go +++ b/src/net/interface_darwin.go @@ -5,42 +5,41 @@ package net import ( + "internal/routebsd" "syscall" - - "golang.org/x/net/route" ) -func interfaceMessages(ifindex int) ([]route.Message, error) { - rib, err := route.FetchRIB(syscall.AF_UNSPEC, syscall.NET_RT_IFLIST, ifindex) +func interfaceMessages(ifindex int) ([]routebsd.Message, error) { + rib, err := routebsd.FetchRIB(syscall.AF_UNSPEC, syscall.NET_RT_IFLIST, ifindex) if err != nil { return nil, err } - return route.ParseRIB(syscall.NET_RT_IFLIST, rib) + return routebsd.ParseRIB(syscall.NET_RT_IFLIST, rib) } // interfaceMulticastAddrTable returns addresses for a specific // interface. func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) { - rib, err := route.FetchRIB(syscall.AF_UNSPEC, syscall.NET_RT_IFLIST2, ifi.Index) + rib, err := routebsd.FetchRIB(syscall.AF_UNSPEC, syscall.NET_RT_IFLIST2, ifi.Index) if err != nil { return nil, err } - msgs, err := route.ParseRIB(syscall.NET_RT_IFLIST2, rib) + msgs, err := routebsd.ParseRIB(syscall.NET_RT_IFLIST2, rib) if err != nil { return nil, err } ifmat := make([]Addr, 0, len(msgs)) for _, m := range msgs { switch m := m.(type) { - case *route.InterfaceMulticastAddrMessage: + case *routebsd.InterfaceMulticastAddrMessage: if ifi.Index != m.Index { continue } var ip IP switch sa := m.Addrs[syscall.RTAX_IFA].(type) { - case *route.Inet4Addr: + case *routebsd.Inet4Addr: ip = IPv4(sa.IP[0], sa.IP[1], sa.IP[2], sa.IP[3]) - case *route.Inet6Addr: + case *routebsd.Inet6Addr: ip = make(IP, IPv6len) copy(ip, sa.IP[:]) } diff --git a/src/net/interface_freebsd.go b/src/net/interface_freebsd.go index 8536bd3cf6482b..fda7a86a2f36b9 100644 --- a/src/net/interface_freebsd.go +++ b/src/net/interface_freebsd.go @@ -5,42 +5,41 @@ package net import ( + "internal/routebsd" "syscall" - - "golang.org/x/net/route" ) -func interfaceMessages(ifindex int) ([]route.Message, error) { - rib, err := route.FetchRIB(syscall.AF_UNSPEC, route.RIBTypeInterface, ifindex) +func interfaceMessages(ifindex int) ([]routebsd.Message, error) { + rib, err := routebsd.FetchRIB(syscall.AF_UNSPEC, routebsd.RIBTypeInterface, ifindex) if err != nil { return nil, err } - return route.ParseRIB(route.RIBTypeInterface, rib) + return routebsd.ParseRIB(routebsd.RIBTypeInterface, rib) } // interfaceMulticastAddrTable returns addresses for a specific // interface. func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) { - rib, err := route.FetchRIB(syscall.AF_UNSPEC, syscall.NET_RT_IFMALIST, ifi.Index) + rib, err := routebsd.FetchRIB(syscall.AF_UNSPEC, syscall.NET_RT_IFMALIST, ifi.Index) if err != nil { return nil, err } - msgs, err := route.ParseRIB(syscall.NET_RT_IFMALIST, rib) + msgs, err := routebsd.ParseRIB(syscall.NET_RT_IFMALIST, rib) if err != nil { return nil, err } ifmat := make([]Addr, 0, len(msgs)) for _, m := range msgs { switch m := m.(type) { - case *route.InterfaceMulticastAddrMessage: + case *routebsd.InterfaceMulticastAddrMessage: if ifi.Index != m.Index { continue } var ip IP switch sa := m.Addrs[syscall.RTAX_IFA].(type) { - case *route.Inet4Addr: + case *routebsd.Inet4Addr: ip = IPv4(sa.IP[0], sa.IP[1], sa.IP[2], sa.IP[3]) - case *route.Inet6Addr: + case *routebsd.Inet6Addr: ip = make(IP, IPv6len) copy(ip, sa.IP[:]) } diff --git a/src/vendor/modules.txt b/src/vendor/modules.txt index d42f50b43ccdba..45bf5af236cad6 100644 --- a/src/vendor/modules.txt +++ b/src/vendor/modules.txt @@ -15,7 +15,6 @@ golang.org/x/net/http2/hpack golang.org/x/net/idna golang.org/x/net/lif golang.org/x/net/nettest -golang.org/x/net/route # golang.org/x/sys v0.28.0 ## explicit; go 1.18 golang.org/x/sys/cpu From dcebb675b3fa0fd8d3056323a9f7f857ce4a2105 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 18 Dec 2024 14:45:09 -0800 Subject: [PATCH 215/397] internal/routebsd: simplify for standard library Discard everything we don't need from x/net/route. Change-Id: If6a4ecb37e5e2349bc4df46c151990719a14f2c7 Reviewed-on: https://go-review.googlesource.com/c/go/+/637696 Auto-Submit: Ian Lance Taylor Reviewed-by: Ian Lance Taylor Reviewed-by: Damien Neil LUCI-TryBot-Result: Go LUCI Commit-Queue: Ian Lance Taylor --- src/internal/routebsd/address.go | 251 ++++-------------- src/internal/routebsd/address_darwin_test.go | 29 +- src/internal/routebsd/address_test.go | 14 +- src/internal/routebsd/binary.go | 52 +--- src/internal/routebsd/empty.s | 7 - src/internal/routebsd/interface.go | 23 +- src/internal/routebsd/interface_announce.go | 32 --- src/internal/routebsd/interface_classic.go | 6 +- src/internal/routebsd/interface_freebsd.go | 29 +- src/internal/routebsd/interface_multicast.go | 4 +- src/internal/routebsd/interface_openbsd.go | 31 +-- src/internal/routebsd/message.go | 29 +- src/internal/routebsd/message_darwin_test.go | 19 +- src/internal/routebsd/message_freebsd_test.go | 73 +---- src/internal/routebsd/message_test.go | 199 +------------- src/internal/routebsd/route.go | 145 +++------- src/internal/routebsd/route_classic.go | 75 ------ src/internal/routebsd/route_openbsd.go | 67 ----- src/internal/routebsd/route_test.go | 173 ++---------- src/internal/routebsd/sys.go | 2 +- src/internal/routebsd/sys_darwin.go | 71 +---- src/internal/routebsd/sys_dragonfly.go | 71 +---- src/internal/routebsd/sys_freebsd.go | 124 +-------- src/internal/routebsd/sys_netbsd.go | 63 +---- src/internal/routebsd/sys_openbsd.go | 66 +---- src/internal/routebsd/syscall.go | 12 - src/internal/routebsd/zsys_darwin.go | 22 -- src/internal/routebsd/zsys_dragonfly.go | 20 -- src/internal/routebsd/zsys_freebsd_386.go | 55 ---- src/internal/routebsd/zsys_freebsd_amd64.go | 52 ---- src/internal/routebsd/zsys_freebsd_arm.go | 52 ---- src/internal/routebsd/zsys_freebsd_arm64.go | 52 ---- src/internal/routebsd/zsys_freebsd_riscv64.go | 52 ---- src/internal/routebsd/zsys_netbsd.go | 17 -- src/internal/routebsd/zsys_openbsd.go | 12 - src/net/interface_bsd.go | 35 +-- src/net/interface_bsdvar.go | 6 +- src/net/interface_darwin.go | 26 +- src/net/interface_freebsd.go | 26 +- 39 files changed, 254 insertions(+), 1840 deletions(-) delete mode 100644 src/internal/routebsd/empty.s delete mode 100644 src/internal/routebsd/interface_announce.go delete mode 100644 src/internal/routebsd/route_classic.go delete mode 100644 src/internal/routebsd/route_openbsd.go delete mode 100644 src/internal/routebsd/syscall.go delete mode 100644 src/internal/routebsd/zsys_darwin.go delete mode 100644 src/internal/routebsd/zsys_dragonfly.go delete mode 100644 src/internal/routebsd/zsys_freebsd_386.go delete mode 100644 src/internal/routebsd/zsys_freebsd_amd64.go delete mode 100644 src/internal/routebsd/zsys_freebsd_arm.go delete mode 100644 src/internal/routebsd/zsys_freebsd_arm64.go delete mode 100644 src/internal/routebsd/zsys_freebsd_riscv64.go delete mode 100644 src/internal/routebsd/zsys_netbsd.go delete mode 100644 src/internal/routebsd/zsys_openbsd.go diff --git a/src/internal/routebsd/address.go b/src/internal/routebsd/address.go index 9479bb10e3a384..3368b22786eef7 100644 --- a/src/internal/routebsd/address.go +++ b/src/internal/routebsd/address.go @@ -7,6 +7,7 @@ package routebsd import ( + "net/netip" "runtime" "syscall" ) @@ -27,39 +28,6 @@ type LinkAddr struct { // Family implements the Family method of Addr interface. func (a *LinkAddr) Family() int { return syscall.AF_LINK } -func (a *LinkAddr) lenAndSpace() (int, int) { - l := 8 + len(a.Name) + len(a.Addr) - return l, roundup(l) -} - -func (a *LinkAddr) marshal(b []byte) (int, error) { - l, ll := a.lenAndSpace() - if len(b) < ll { - return 0, errShortBuffer - } - nlen, alen := len(a.Name), len(a.Addr) - if nlen > 255 || alen > 255 { - return 0, errInvalidAddr - } - b[0] = byte(l) - b[1] = syscall.AF_LINK - if a.Index > 0 { - nativeEndian.PutUint16(b[2:4], uint16(a.Index)) - } - data := b[8:] - if nlen > 0 { - b[5] = byte(nlen) - copy(data[:nlen], a.Name) - data = data[nlen:] - } - if alen > 0 { - b[6] = byte(alen) - copy(data[:alen], a.Addr) - data = data[alen:] - } - return ll, nil -} - func parseLinkAddr(b []byte) (Addr, error) { if len(b) < 8 { return nil, errInvalidAddr @@ -118,54 +86,17 @@ func parseKernelLinkAddr(_ int, b []byte) (int, Addr, error) { return l, &LinkAddr{Name: name, Addr: addr}, nil } -// An Inet4Addr represents an internet address for IPv4. -type Inet4Addr struct { - IP [4]byte // IP address -} - -// Family implements the Family method of Addr interface. -func (a *Inet4Addr) Family() int { return syscall.AF_INET } - -func (a *Inet4Addr) lenAndSpace() (int, int) { - return sizeofSockaddrInet, roundup(sizeofSockaddrInet) -} - -func (a *Inet4Addr) marshal(b []byte) (int, error) { - l, ll := a.lenAndSpace() - if len(b) < ll { - return 0, errShortBuffer - } - b[0] = byte(l) - b[1] = syscall.AF_INET - copy(b[4:8], a.IP[:]) - return ll, nil -} - -// An Inet6Addr represents an internet address for IPv6. -type Inet6Addr struct { - IP [16]byte // IP address - ZoneID int // zone identifier -} - -// Family implements the Family method of Addr interface. -func (a *Inet6Addr) Family() int { return syscall.AF_INET6 } - -func (a *Inet6Addr) lenAndSpace() (int, int) { - return sizeofSockaddrInet6, roundup(sizeofSockaddrInet6) +// An InetAddr represent an internet address using IPv4 or IPv6. +type InetAddr struct { + IP netip.Addr } -func (a *Inet6Addr) marshal(b []byte) (int, error) { - l, ll := a.lenAndSpace() - if len(b) < ll { - return 0, errShortBuffer - } - b[0] = byte(l) - b[1] = syscall.AF_INET6 - copy(b[8:24], a.IP[:]) - if a.ZoneID > 0 { - nativeEndian.PutUint32(b[24:28], uint32(a.ZoneID)) +func (a *InetAddr) Family() int { + if a.IP.Is4() { + return syscall.AF_INET + } else { + return syscall.AF_INET6 } - return ll, nil } // parseInetAddr parses b as an internet address for IPv4 or IPv6. @@ -180,12 +111,15 @@ func parseInetAddr(af int, b []byte) (Addr, error) { return nil, errInvalidAddr } sockAddrLen := int(b[0]) - a := &Inet4Addr{} + var ip [4]byte n := off4 + 4 if sockAddrLen < n { n = sockAddrLen } - copy(a.IP[:], b[off4:n]) + copy(ip[:], b[off4:n]) + a := &InetAddr{ + IP: netip.AddrFrom4(ip), + } return a, nil case syscall.AF_INET6: if len(b) < (off6+1) || len(b) < int(b[0]) || b[0] == 0 { @@ -196,22 +130,23 @@ func parseInetAddr(af int, b []byte) (Addr, error) { if sockAddrLen < n { n = sockAddrLen } - a := &Inet6Addr{} - if sockAddrLen == sizeofSockaddrInet6 { - a.ZoneID = int(nativeEndian.Uint32(b[24:28])) - } - copy(a.IP[:], b[off6:n]) - if a.IP[0] == 0xfe && a.IP[1]&0xc0 == 0x80 || a.IP[0] == 0xff && (a.IP[1]&0x0f == 0x01 || a.IP[1]&0x0f == 0x02) { + var ip [16]byte + copy(ip[:], b[off6:n]) + if ip[0] == 0xfe && ip[1]&0xc0 == 0x80 || ip[0] == 0xff && (ip[1]&0x0f == 0x01 || ip[1]&0x0f == 0x02) { // KAME based IPv6 protocol stack usually // embeds the interface index in the // interface-local or link-local address as // the kernel-internal form. - id := int(bigEndian.Uint16(a.IP[2:4])) + id := int(bigEndian.Uint16(ip[2:4])) if id != 0 { - a.ZoneID = id - a.IP[2], a.IP[3] = 0, 0 + ip[2], ip[3] = 0, 0 } } + // The kernel can provide an integer zone ID. + // We ignore it. + a := &InetAddr{ + IP: netip.AddrFrom16(ip), + } return a, nil default: return nil, errInvalidAddr @@ -260,130 +195,42 @@ func parseKernelInetAddr(af int, b []byte) (int, Addr, error) { off6 = 8 // offset of in6_addr ) switch { - case b[0] == sizeofSockaddrInet6: - a := &Inet6Addr{} - copy(a.IP[:], b[off6:off6+16]) + case b[0] == syscall.SizeofSockaddrInet6: + a := &InetAddr{ + IP: netip.AddrFrom16([16]byte(b[off6:off6+16])), + } return int(b[0]), a, nil case af == syscall.AF_INET6: - a := &Inet6Addr{} + var ab[16]byte if l-1 < off6 { - copy(a.IP[:], b[1:l]) + copy(ab[:], b[1:l]) } else { - copy(a.IP[:], b[l-off6:l]) + copy(ab[:], b[l-off6:l]) + } + a := &InetAddr{ + IP: netip.AddrFrom16(ab), } return int(b[0]), a, nil - case b[0] == sizeofSockaddrInet: - a := &Inet4Addr{} - copy(a.IP[:], b[off4:off4+4]) + case b[0] == syscall.SizeofSockaddrInet4: + a := &InetAddr{ + IP: netip.AddrFrom4([4]byte(b[off4:off4+4])), + } return int(b[0]), a, nil default: // an old fashion, AF_UNSPEC or unknown means AF_INET - a := &Inet4Addr{} + var ab [4]byte if l-1 < off4 { - copy(a.IP[:], b[1:l]) + copy(ab[:], b[1:l]) } else { - copy(a.IP[:], b[l-off4:l]) + copy(ab[:], b[l-off4:l]) } - return int(b[0]), a, nil - } -} - -// A DefaultAddr represents an address of various operating -// system-specific features. -type DefaultAddr struct { - af int - Raw []byte // raw format of address -} - -// Family implements the Family method of Addr interface. -func (a *DefaultAddr) Family() int { return a.af } - -func (a *DefaultAddr) lenAndSpace() (int, int) { - l := len(a.Raw) - return l, roundup(l) -} - -func (a *DefaultAddr) marshal(b []byte) (int, error) { - l, ll := a.lenAndSpace() - if len(b) < ll { - return 0, errShortBuffer - } - if l > 255 { - return 0, errInvalidAddr - } - b[1] = byte(l) - copy(b[:l], a.Raw) - return ll, nil -} - -func parseDefaultAddr(b []byte) (Addr, error) { - if len(b) < 2 || len(b) < int(b[0]) { - return nil, errInvalidAddr - } - a := &DefaultAddr{af: int(b[1]), Raw: b[:b[0]]} - return a, nil -} - -func addrsSpace(as []Addr) int { - var l int - for _, a := range as { - switch a := a.(type) { - case *LinkAddr: - _, ll := a.lenAndSpace() - l += ll - case *Inet4Addr: - _, ll := a.lenAndSpace() - l += ll - case *Inet6Addr: - _, ll := a.lenAndSpace() - l += ll - case *DefaultAddr: - _, ll := a.lenAndSpace() - l += ll - } - } - return l -} - -// marshalAddrs marshals as and returns a bitmap indicating which -// address is stored in b. -func marshalAddrs(b []byte, as []Addr) (uint, error) { - var attrs uint - for i, a := range as { - switch a := a.(type) { - case *LinkAddr: - l, err := a.marshal(b) - if err != nil { - return 0, err - } - b = b[l:] - attrs |= 1 << uint(i) - case *Inet4Addr: - l, err := a.marshal(b) - if err != nil { - return 0, err - } - b = b[l:] - attrs |= 1 << uint(i) - case *Inet6Addr: - l, err := a.marshal(b) - if err != nil { - return 0, err - } - b = b[l:] - attrs |= 1 << uint(i) - case *DefaultAddr: - l, err := a.marshal(b) - if err != nil { - return 0, err - } - b = b[l:] - attrs |= 1 << uint(i) + a := &InetAddr{ + IP: netip.AddrFrom4(ab), } + return int(b[0]), a, nil } - return attrs, nil } -func parseAddrs(attrs uint, fn func(int, []byte) (int, Addr, error), b []byte) ([]Addr, error) { +func parseAddrs(attrs uint, b []byte) ([]Addr, error) { var as [syscall.RTAX_MAX]Addr af := int(syscall.AF_UNSPEC) for i := uint(0); i < syscall.RTAX_MAX && len(b) >= roundup(0); i++ { @@ -420,7 +267,7 @@ func parseAddrs(attrs uint, fn func(int, []byte) (int, Addr, error), b []byte) ( } b = b[l:] default: - l, a, err := fn(af, b) + l, a, err := parseKernelInetAddr(af, b) if err != nil { return nil, err } @@ -433,11 +280,7 @@ func parseAddrs(attrs uint, fn func(int, []byte) (int, Addr, error), b []byte) ( } } } else { - a, err := parseDefaultAddr(b) - if err != nil { - return nil, err - } - as[i] = a + // Skip unknown addresses. l := roundup(int(b[0])) if len(b) < l { return nil, errMessageTooShort diff --git a/src/internal/routebsd/address_darwin_test.go b/src/internal/routebsd/address_darwin_test.go index 02a407a0c77a51..5f93e363a6fe90 100644 --- a/src/internal/routebsd/address_darwin_test.go +++ b/src/internal/routebsd/address_darwin_test.go @@ -5,6 +5,7 @@ package routebsd import ( + "net/netip" "reflect" "syscall" "testing" @@ -12,7 +13,6 @@ import ( type parseAddrsOnDarwinTest struct { attrs uint - fn func(int, []byte) (int, Addr, error) b []byte as []Addr } @@ -20,7 +20,6 @@ type parseAddrsOnDarwinTest struct { var parseAddrsOnDarwinLittleEndianTests = []parseAddrsOnDarwinTest{ { syscall.RTA_DST | syscall.RTA_GATEWAY | syscall.RTA_NETMASK, - parseKernelInetAddr, []byte{ 0x10, 0x2, 0x0, 0x0, 0xc0, 0xa8, 0x56, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, @@ -32,9 +31,9 @@ var parseAddrsOnDarwinLittleEndianTests = []parseAddrsOnDarwinTest{ 0x7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }, []Addr{ - &Inet4Addr{IP: [4]byte{192, 168, 86, 0}}, + &InetAddr{IP: netip.AddrFrom4([4]byte{192, 168, 86, 0})}, &LinkAddr{Index: 4}, - &Inet4Addr{IP: [4]byte{255, 255, 255, 255}}, + &InetAddr{IP: netip.AddrFrom4([4]byte{255, 255, 255, 255})}, nil, nil, nil, @@ -44,7 +43,6 @@ var parseAddrsOnDarwinLittleEndianTests = []parseAddrsOnDarwinTest{ }, { syscall.RTA_DST | syscall.RTA_GATEWAY | syscall.RTA_NETMASK, - parseKernelInetAddr, []byte{ 0x10, 0x02, 0x00, 0x00, 0x64, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -56,9 +54,9 @@ var parseAddrsOnDarwinLittleEndianTests = []parseAddrsOnDarwinTest{ 0x06, 0x02, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, }, []Addr{ - &Inet4Addr{IP: [4]byte{100, 113, 0, 0}}, + &InetAddr{IP: netip.AddrFrom4([4]byte{100, 113, 0, 0})}, &LinkAddr{Index: 33, Name: "utun4319"}, - &Inet4Addr{IP: [4]byte{255, 255, 0, 0}}, + &InetAddr{IP: netip.AddrFrom4([4]byte{255, 255, 0, 0})}, nil, nil, nil, @@ -70,7 +68,6 @@ var parseAddrsOnDarwinLittleEndianTests = []parseAddrsOnDarwinTest{ // gw fe80:0000:0000:0000:f22f:4bff:fe09:3bff { syscall.RTA_DST | syscall.RTA_GATEWAY | syscall.RTA_NETMASK, - parseKernelInetAddr, []byte{ 0x1c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0x84, 0x1b, 0x4e, 0x62, 0x81, 0x00, 0x00, @@ -86,9 +83,9 @@ var parseAddrsOnDarwinLittleEndianTests = []parseAddrsOnDarwinTest{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, }, []Addr{ - &Inet6Addr{IP: [16]byte{0xfd, 0x84, 0x1b, 0x4e, 0x62, 0x81}}, - &Inet6Addr{IP: [16]byte{0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x2f, 0x4b, 0xff, 0xfe, 0x09, 0x3b, 0xff}, ZoneID: 33}, - &Inet6Addr{IP: [16]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, + &InetAddr{IP: netip.AddrFrom16([16]byte{0xfd, 0x84, 0x1b, 0x4e, 0x62, 0x81})}, + &InetAddr{IP: netip.AddrFrom16([16]byte{0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x2f, 0x4b, 0xff, 0xfe, 0x09, 0x3b, 0xff})}, + &InetAddr{IP: netip.AddrFrom16([16]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff})}, nil, nil, nil, @@ -99,7 +96,6 @@ var parseAddrsOnDarwinLittleEndianTests = []parseAddrsOnDarwinTest{ // golang/go#70528, the kernel can produce addresses of length 0 { syscall.RTA_DST | syscall.RTA_GATEWAY | syscall.RTA_NETMASK, - parseKernelInetAddr, []byte{ 0x00, 0x1e, 0x00, 0x00, @@ -113,8 +109,8 @@ var parseAddrsOnDarwinLittleEndianTests = []parseAddrsOnDarwinTest{ }, []Addr{ nil, - &Inet6Addr{IP: [16]byte{0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x2f, 0x4b, 0xff, 0xfe, 0x09, 0x3b, 0xff}, ZoneID: 33}, - &Inet6Addr{IP: [16]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, + &InetAddr{IP: netip.AddrFrom16([16]byte{0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x2f, 0x4b, 0xff, 0xfe, 0x09, 0x3b, 0xff})}, + &InetAddr{IP: netip.AddrFrom16([16]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff})}, nil, nil, nil, @@ -125,7 +121,6 @@ var parseAddrsOnDarwinLittleEndianTests = []parseAddrsOnDarwinTest{ // Additional case: golang/go/issues/70528#issuecomment-2498692877 { syscall.RTA_DST | syscall.RTA_GATEWAY | syscall.RTA_NETMASK, - parseKernelInetAddr, []byte{ 0x84, 0x00, 0x05, 0x04, 0x01, 0x00, 0x00, 0x00, 0x03, 0x08, 0x00, 0x01, 0x15, 0x00, 0x00, 0x00, 0x1B, 0x01, 0x00, 0x00, 0xF5, 0x5A, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -138,7 +133,7 @@ var parseAddrsOnDarwinLittleEndianTests = []parseAddrsOnDarwinTest{ 0x00, 0x00, 0x00, 0x00, }, []Addr{ - &Inet4Addr{IP: [4]byte{0x0, 0x0, 0x0, 0x0}}, + &InetAddr{IP: netip.AddrFrom4([4]byte{0x0, 0x0, 0x0, 0x0})}, nil, nil, nil, @@ -157,7 +152,7 @@ func TestParseAddrsOnDarwin(t *testing.T) { } for i, tt := range tests { - as, err := parseAddrs(tt.attrs, tt.fn, tt.b) + as, err := parseAddrs(tt.attrs, tt.b) if err != nil { t.Error(i, err) continue diff --git a/src/internal/routebsd/address_test.go b/src/internal/routebsd/address_test.go index c230bb2f1cca3b..29de22b4130ec8 100644 --- a/src/internal/routebsd/address_test.go +++ b/src/internal/routebsd/address_test.go @@ -7,6 +7,7 @@ package routebsd import ( + "net/netip" "reflect" "syscall" "testing" @@ -14,7 +15,6 @@ import ( type parseAddrsTest struct { attrs uint - fn func(int, []byte) (int, Addr, error) b []byte as []Addr } @@ -22,7 +22,6 @@ type parseAddrsTest struct { var parseAddrsLittleEndianTests = []parseAddrsTest{ { syscall.RTA_DST | syscall.RTA_GATEWAY | syscall.RTA_NETMASK | syscall.RTA_BRD, - parseKernelInetAddr, []byte{ 0x38, 0x12, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, @@ -49,17 +48,16 @@ var parseAddrsLittleEndianTests = []parseAddrsTest{ []Addr{ &LinkAddr{Index: 0}, &LinkAddr{Index: 2, Name: "em1", Addr: []byte{0x00, 0x0c, 0x29, 0x66, 0x2c, 0xdc}}, - &Inet4Addr{IP: [4]byte{172, 16, 220, 180}}, + &InetAddr{IP: netip.AddrFrom4([4]byte{172, 16, 220, 180})}, nil, nil, nil, nil, - &Inet4Addr{IP: [4]byte{172, 16, 220, 255}}, + &InetAddr{IP: netip.AddrFrom4([4]byte{172, 16, 220, 255})}, }, }, { syscall.RTA_NETMASK | syscall.RTA_IFP | syscall.RTA_IFA, - parseKernelInetAddr, []byte{ 0x7, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, @@ -73,10 +71,10 @@ var parseAddrsLittleEndianTests = []parseAddrsTest{ []Addr{ nil, nil, - &Inet4Addr{IP: [4]byte{255, 255, 255, 0}}, + &InetAddr{IP: netip.AddrFrom4([4]byte{255, 255, 255, 0})}, nil, &LinkAddr{Index: 10, Name: "vlan5682"}, - &Inet4Addr{IP: [4]byte{169, 254, 0, 1}}, + &InetAddr{IP: netip.AddrFrom4([4]byte{169, 254, 0, 1})}, nil, nil, }, @@ -90,7 +88,7 @@ func TestParseAddrs(t *testing.T) { } for i, tt := range tests { - as, err := parseAddrs(tt.attrs, tt.fn, tt.b) + as, err := parseAddrs(tt.attrs, tt.b) if err != nil { t.Error(i, err) continue diff --git a/src/internal/routebsd/binary.go b/src/internal/routebsd/binary.go index 66b234c4f2c8a0..15f880472a9e07 100644 --- a/src/internal/routebsd/binary.go +++ b/src/internal/routebsd/binary.go @@ -6,6 +6,8 @@ package routebsd +import "internal/byteorder" + // This file contains duplicates of encoding/binary package. // // This package is supposed to be used by the net package of standard @@ -20,71 +22,33 @@ var ( type binaryByteOrder interface { Uint16([]byte) uint16 Uint32([]byte) uint32 - PutUint16([]byte, uint16) - PutUint32([]byte, uint32) Uint64([]byte) uint64 } type binaryLittleEndian struct{} func (binaryLittleEndian) Uint16(b []byte) uint16 { - _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 - return uint16(b[0]) | uint16(b[1])<<8 -} - -func (binaryLittleEndian) PutUint16(b []byte, v uint16) { - _ = b[1] // early bounds check to guarantee safety of writes below - b[0] = byte(v) - b[1] = byte(v >> 8) + return byteorder.LEUint16(b) } func (binaryLittleEndian) Uint32(b []byte) uint32 { - _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 - return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 -} - -func (binaryLittleEndian) PutUint32(b []byte, v uint32) { - _ = b[3] // early bounds check to guarantee safety of writes below - b[0] = byte(v) - b[1] = byte(v >> 8) - b[2] = byte(v >> 16) - b[3] = byte(v >> 24) + return byteorder.LEUint32(b) } func (binaryLittleEndian) Uint64(b []byte) uint64 { - _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | - uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 + return byteorder.LEUint64(b) } type binaryBigEndian struct{} func (binaryBigEndian) Uint16(b []byte) uint16 { - _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 - return uint16(b[1]) | uint16(b[0])<<8 -} - -func (binaryBigEndian) PutUint16(b []byte, v uint16) { - _ = b[1] // early bounds check to guarantee safety of writes below - b[0] = byte(v >> 8) - b[1] = byte(v) + return byteorder.BEUint16(b) } func (binaryBigEndian) Uint32(b []byte) uint32 { - _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 - return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 -} - -func (binaryBigEndian) PutUint32(b []byte, v uint32) { - _ = b[3] // early bounds check to guarantee safety of writes below - b[0] = byte(v >> 24) - b[1] = byte(v >> 16) - b[2] = byte(v >> 8) - b[3] = byte(v) + return byteorder.BEUint32(b) } func (binaryBigEndian) Uint64(b []byte) uint64 { - _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | - uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 + return byteorder.BEUint64(b) } diff --git a/src/internal/routebsd/empty.s b/src/internal/routebsd/empty.s deleted file mode 100644 index 49d79791e01bb6..00000000000000 --- a/src/internal/routebsd/empty.s +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright 2018 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. - -//go:build darwin && go1.12 - -// This exists solely so we can linkname in symbols from syscall. diff --git a/src/internal/routebsd/interface.go b/src/internal/routebsd/interface.go index a1523329b143ac..1ec415547f11c0 100644 --- a/src/internal/routebsd/interface.go +++ b/src/internal/routebsd/interface.go @@ -30,9 +30,6 @@ type InterfaceAddrMessage struct { raw []byte // raw message } -// Sys implements the Sys method of Message interface. -func (m *InterfaceAddrMessage) Sys() []Sys { return nil } - // An InterfaceMulticastAddrMessage represents an interface multicast // address message. type InterfaceMulticastAddrMessage struct { @@ -45,20 +42,8 @@ type InterfaceMulticastAddrMessage struct { raw []byte // raw message } -// Sys implements the Sys method of Message interface. -func (m *InterfaceMulticastAddrMessage) Sys() []Sys { return nil } - -// An InterfaceAnnounceMessage represents an interface announcement -// message. -type InterfaceAnnounceMessage struct { - Version int // message version - Type int // message type - Index int // interface index - Name string // interface name - What int // what type of announcement - - raw []byte // raw message -} +// Implement the Message interface. -// Sys implements the Sys method of Message interface. -func (m *InterfaceAnnounceMessage) Sys() []Sys { return nil } +func (InterfaceMessage) message() {} +func (InterfaceAddrMessage) message() {} +func (InterfaceMulticastAddrMessage) message() {} diff --git a/src/internal/routebsd/interface_announce.go b/src/internal/routebsd/interface_announce.go deleted file mode 100644 index 834f8d35185e9f..00000000000000 --- a/src/internal/routebsd/interface_announce.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2016 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. - -//go:build dragonfly || freebsd || netbsd - -package routebsd - -func (w *wireFormat) parseInterfaceAnnounceMessage(_ RIBType, b []byte) (Message, error) { - if len(b) < w.bodyOff { - return nil, errMessageTooShort - } - l := int(nativeEndian.Uint16(b[:2])) - if len(b) < l { - return nil, errInvalidMessage - } - m := &InterfaceAnnounceMessage{ - Version: int(b[2]), - Type: int(b[3]), - Index: int(nativeEndian.Uint16(b[4:6])), - What: int(nativeEndian.Uint16(b[22:24])), - raw: b[:l], - } - for i := 0; i < 16; i++ { - if b[6+i] != 0 { - continue - } - m.Name = string(b[6 : 6+i]) - break - } - return m, nil -} diff --git a/src/internal/routebsd/interface_classic.go b/src/internal/routebsd/interface_classic.go index 9d706a50dc29c8..7b26c7eb2ad789 100644 --- a/src/internal/routebsd/interface_classic.go +++ b/src/internal/routebsd/interface_classic.go @@ -11,7 +11,7 @@ import ( "syscall" ) -func (w *wireFormat) parseInterfaceMessage(_ RIBType, b []byte) (Message, error) { +func (w *wireFormat) parseInterfaceMessage(b []byte) (Message, error) { if len(b) < w.bodyOff { return nil, errMessageTooShort } @@ -41,7 +41,7 @@ func (w *wireFormat) parseInterfaceMessage(_ RIBType, b []byte) (Message, error) return m, nil } -func (w *wireFormat) parseInterfaceAddrMessage(_ RIBType, b []byte) (Message, error) { +func (w *wireFormat) parseInterfaceAddrMessage(b []byte) (Message, error) { if len(b) < w.bodyOff { return nil, errMessageTooShort } @@ -61,7 +61,7 @@ func (w *wireFormat) parseInterfaceAddrMessage(_ RIBType, b []byte) (Message, er m.Index = int(nativeEndian.Uint16(b[12:14])) } var err error - m.Addrs, err = parseAddrs(uint(nativeEndian.Uint32(b[4:8])), parseKernelInetAddr, b[w.bodyOff:]) + m.Addrs, err = parseAddrs(uint(nativeEndian.Uint32(b[4:8])), b[w.bodyOff:]) if err != nil { return nil, err } diff --git a/src/internal/routebsd/interface_freebsd.go b/src/internal/routebsd/interface_freebsd.go index 4a3ad8e30be051..7e105544b65f96 100644 --- a/src/internal/routebsd/interface_freebsd.go +++ b/src/internal/routebsd/interface_freebsd.go @@ -6,18 +6,9 @@ package routebsd import "syscall" -func (w *wireFormat) parseInterfaceMessage(typ RIBType, b []byte) (Message, error) { - var extOff, bodyOff int - if typ == syscall.NET_RT_IFLISTL { - if len(b) < 20 { - return nil, errMessageTooShort - } - extOff = int(nativeEndian.Uint16(b[18:20])) - bodyOff = int(nativeEndian.Uint16(b[16:18])) - } else { - extOff = w.extOff - bodyOff = w.bodyOff - } +func (w *wireFormat) parseInterfaceMessage(b []byte) (Message, error) { + extOff := w.extOff + bodyOff := w.bodyOff if len(b) < extOff || len(b) < bodyOff { return nil, errInvalidMessage } @@ -47,16 +38,8 @@ func (w *wireFormat) parseInterfaceMessage(typ RIBType, b []byte) (Message, erro return m, nil } -func (w *wireFormat) parseInterfaceAddrMessage(typ RIBType, b []byte) (Message, error) { - var bodyOff int - if typ == syscall.NET_RT_IFLISTL { - if len(b) < 24 { - return nil, errMessageTooShort - } - bodyOff = int(nativeEndian.Uint16(b[16:18])) - } else { - bodyOff = w.bodyOff - } +func (w *wireFormat) parseInterfaceAddrMessage(b []byte) (Message, error) { + bodyOff := w.bodyOff if len(b) < bodyOff { return nil, errInvalidMessage } @@ -72,7 +55,7 @@ func (w *wireFormat) parseInterfaceAddrMessage(typ RIBType, b []byte) (Message, raw: b[:l], } var err error - m.Addrs, err = parseAddrs(uint(nativeEndian.Uint32(b[4:8])), parseKernelInetAddr, b[bodyOff:]) + m.Addrs, err = parseAddrs(uint(nativeEndian.Uint32(b[4:8])), b[bodyOff:]) if err != nil { return nil, err } diff --git a/src/internal/routebsd/interface_multicast.go b/src/internal/routebsd/interface_multicast.go index c00199cf494201..8d2c7f56dc0074 100644 --- a/src/internal/routebsd/interface_multicast.go +++ b/src/internal/routebsd/interface_multicast.go @@ -6,7 +6,7 @@ package routebsd -func (w *wireFormat) parseInterfaceMulticastAddrMessage(_ RIBType, b []byte) (Message, error) { +func (w *wireFormat) parseInterfaceMulticastAddrMessage(b []byte) (Message, error) { if len(b) < w.bodyOff { return nil, errMessageTooShort } @@ -22,7 +22,7 @@ func (w *wireFormat) parseInterfaceMulticastAddrMessage(_ RIBType, b []byte) (Me raw: b[:l], } var err error - m.Addrs, err = parseAddrs(uint(nativeEndian.Uint32(b[4:8])), parseKernelInetAddr, b[w.bodyOff:]) + m.Addrs, err = parseAddrs(uint(nativeEndian.Uint32(b[4:8])), b[w.bodyOff:]) if err != nil { return nil, err } diff --git a/src/internal/routebsd/interface_openbsd.go b/src/internal/routebsd/interface_openbsd.go index 208ff78425a94a..8c6cd6f783456d 100644 --- a/src/internal/routebsd/interface_openbsd.go +++ b/src/internal/routebsd/interface_openbsd.go @@ -6,7 +6,7 @@ package routebsd import "syscall" -func (*wireFormat) parseInterfaceMessage(_ RIBType, b []byte) (Message, error) { +func (*wireFormat) parseInterfaceMessage(b []byte) (Message, error) { if len(b) < 32 { return nil, errMessageTooShort } @@ -39,7 +39,7 @@ func (*wireFormat) parseInterfaceMessage(_ RIBType, b []byte) (Message, error) { return m, nil } -func (*wireFormat) parseInterfaceAddrMessage(_ RIBType, b []byte) (Message, error) { +func (*wireFormat) parseInterfaceAddrMessage(b []byte) (Message, error) { if len(b) < 24 { return nil, errMessageTooShort } @@ -59,34 +59,9 @@ func (*wireFormat) parseInterfaceAddrMessage(_ RIBType, b []byte) (Message, erro raw: b[:l], } var err error - m.Addrs, err = parseAddrs(uint(nativeEndian.Uint32(b[12:16])), parseKernelInetAddr, b[bodyOff:]) + m.Addrs, err = parseAddrs(uint(nativeEndian.Uint32(b[12:16])), b[bodyOff:]) if err != nil { return nil, err } return m, nil } - -func (*wireFormat) parseInterfaceAnnounceMessage(_ RIBType, b []byte) (Message, error) { - if len(b) < 26 { - return nil, errMessageTooShort - } - l := int(nativeEndian.Uint16(b[:2])) - if len(b) < l { - return nil, errInvalidMessage - } - m := &InterfaceAnnounceMessage{ - Version: int(b[2]), - Type: int(b[3]), - Index: int(nativeEndian.Uint16(b[6:8])), - What: int(nativeEndian.Uint16(b[8:10])), - raw: b[:l], - } - for i := 0; i < 16; i++ { - if b[10+i] != 0 { - continue - } - m.Name = string(b[10 : 10+i]) - break - } - return m, nil -} diff --git a/src/internal/routebsd/message.go b/src/internal/routebsd/message.go index f8666b66486ada..f08dfc25dd06a9 100644 --- a/src/internal/routebsd/message.go +++ b/src/internal/routebsd/message.go @@ -8,32 +8,12 @@ package routebsd // A Message represents a routing message. type Message interface { - // Sys returns operating system-specific information. - Sys() []Sys + message() } -// A Sys reprensents operating system-specific information. -type Sys interface { - // SysType returns a type of operating system-specific - // information. - SysType() SysType -} - -// A SysType represents a type of operating system-specific -// information. -type SysType int - -const ( - SysMetrics SysType = iota - SysStats -) - -// ParseRIB parses b as a routing information base and returns a list +// parseRIB parses b as a routing information base and returns a list // of routing messages. -func ParseRIB(typ RIBType, b []byte) ([]Message, error) { - if !typ.parseable() { - return nil, errUnsupportedMessage - } +func parseRIB(b []byte) ([]Message, error) { var msgs []Message nmsgs, nskips := 0, 0 for len(b) > 4 { @@ -52,7 +32,7 @@ func ParseRIB(typ RIBType, b []byte) ([]Message, error) { if w, ok := wireFormats[int(b[3])]; !ok { nskips++ } else { - m, err := w.parse(typ, b[:l]) + m, err := w.parse(b[:l]) if err != nil { return nil, err } @@ -64,6 +44,7 @@ func ParseRIB(typ RIBType, b []byte) ([]Message, error) { } b = b[l:] } + // We failed to parse any of the messages - version mismatch? if nmsgs != len(msgs)+nskips { return nil, errMessageMismatch diff --git a/src/internal/routebsd/message_darwin_test.go b/src/internal/routebsd/message_darwin_test.go index a7fbdecf5d1e90..f224f0a73d4547 100644 --- a/src/internal/routebsd/message_darwin_test.go +++ b/src/internal/routebsd/message_darwin_test.go @@ -9,20 +9,11 @@ import ( "testing" ) -func TestFetchAndParseRIBOnDarwin(t *testing.T) { - for _, typ := range []RIBType{syscall.NET_RT_FLAGS, syscall.NET_RT_DUMP2, syscall.NET_RT_IFLIST2} { - var lastErr error - var ms []Message - for _, af := range []int{syscall.AF_UNSPEC, syscall.AF_INET, syscall.AF_INET6} { - rs, err := fetchAndParseRIB(af, typ) - if err != nil { - lastErr = err - continue - } - ms = append(ms, rs...) - } - if len(ms) == 0 && lastErr != nil { - t.Error(typ, lastErr) +func TestFetchRIBMessagesOnDarwin(t *testing.T) { + for _, typ := range []int{syscall.NET_RT_FLAGS, syscall.NET_RT_DUMP2, syscall.NET_RT_IFLIST2} { + ms, err := FetchRIBMessages(typ, 0) + if err != nil { + t.Error(typ, err) continue } ss, err := msgs(ms).validate() diff --git a/src/internal/routebsd/message_freebsd_test.go b/src/internal/routebsd/message_freebsd_test.go index f165e7c0e7fa57..f0065198c8f2ef 100644 --- a/src/internal/routebsd/message_freebsd_test.go +++ b/src/internal/routebsd/message_freebsd_test.go @@ -9,20 +9,11 @@ import ( "testing" ) -func TestFetchAndParseRIBOnFreeBSD(t *testing.T) { - for _, typ := range []RIBType{syscall.NET_RT_IFMALIST} { - var lastErr error - var ms []Message - for _, af := range []int{syscall.AF_UNSPEC, syscall.AF_INET, syscall.AF_INET6} { - rs, err := fetchAndParseRIB(af, typ) - if err != nil { - lastErr = err - continue - } - ms = append(ms, rs...) - } - if len(ms) == 0 && lastErr != nil { - t.Error(typ, lastErr) +func TestFetchRIBMessagesOnFreeBSD(t *testing.T) { + for _, typ := range []int{syscall.NET_RT_IFMALIST} { + ms, err := FetchRIBMessages(typ, 0) + if err != nil { + t.Error(typ, err) continue } ss, err := msgs(ms).validate() @@ -35,57 +26,3 @@ func TestFetchAndParseRIBOnFreeBSD(t *testing.T) { } } } - -func TestFetchAndParseRIBOnFreeBSD10AndAbove(t *testing.T) { - if _, err := FetchRIB(syscall.AF_UNSPEC, syscall.NET_RT_IFLISTL, 0); err != nil { - t.Skip("NET_RT_IFLISTL not supported") - } - if compatFreeBSD32 { - t.Skip("NET_RT_IFLIST vs. NET_RT_IFLISTL doesn't work for 386 emulation on amd64") - } - - var tests = [2]struct { - typ RIBType - b []byte - msgs []Message - ss []string - }{ - {typ: syscall.NET_RT_IFLIST}, - {typ: syscall.NET_RT_IFLISTL}, - } - for i := range tests { - var lastErr error - for _, af := range []int{syscall.AF_UNSPEC, syscall.AF_INET, syscall.AF_INET6} { - rs, err := fetchAndParseRIB(af, tests[i].typ) - if err != nil { - lastErr = err - continue - } - tests[i].msgs = append(tests[i].msgs, rs...) - } - if len(tests[i].msgs) == 0 && lastErr != nil { - t.Error(tests[i].typ, lastErr) - continue - } - tests[i].ss, lastErr = msgs(tests[i].msgs).validate() - if lastErr != nil { - t.Error(tests[i].typ, lastErr) - continue - } - for _, s := range tests[i].ss { - t.Log(s) - } - } - for i := len(tests) - 1; i > 0; i-- { - if len(tests[i].ss) != len(tests[i-1].ss) { - t.Errorf("got %v; want %v", tests[i].ss, tests[i-1].ss) - continue - } - for j, s1 := range tests[i].ss { - s0 := tests[i-1].ss[j] - if s1 != s0 { - t.Errorf("got %s; want %s", s1, s0) - } - } - } -} diff --git a/src/internal/routebsd/message_test.go b/src/internal/routebsd/message_test.go index 9d0d7284fcc001..958f2010628a06 100644 --- a/src/internal/routebsd/message_test.go +++ b/src/internal/routebsd/message_test.go @@ -7,26 +7,15 @@ package routebsd import ( - "os" "syscall" "testing" - "time" ) -func TestFetchAndParseRIB(t *testing.T) { - for _, typ := range []RIBType{syscall.NET_RT_DUMP, syscall.NET_RT_IFLIST} { - var lastErr error - var ms []Message - for _, af := range []int{syscall.AF_UNSPEC, syscall.AF_INET, syscall.AF_INET6} { - rs, err := fetchAndParseRIB(af, typ) - if err != nil { - lastErr = err - continue - } - ms = append(ms, rs...) - } - if len(ms) == 0 && lastErr != nil { - t.Error(typ, lastErr) +func TestFetchRIBMessages(t *testing.T) { + for _, typ := range []int{syscall.NET_RT_DUMP, syscall.NET_RT_IFLIST} { + ms, err := FetchRIBMessages(typ, 0) + if err != nil { + t.Error(typ, err) continue } ss, err := msgs(ms).validate() @@ -40,86 +29,6 @@ func TestFetchAndParseRIB(t *testing.T) { } } -var ( - rtmonSock int - rtmonErr error -) - -func init() { - // We need to keep rtmonSock alive to avoid treading on - // recycled socket descriptors. - rtmonSock, rtmonErr = syscall.Socket(syscall.AF_ROUTE, syscall.SOCK_RAW, syscall.AF_UNSPEC) -} - -// TestMonitorAndParseRIB leaks a worker goroutine and a socket -// descriptor but that's intentional. -func TestMonitorAndParseRIB(t *testing.T) { - if testing.Short() || os.Getuid() != 0 { - t.Skip("must be root") - } - - if rtmonErr != nil { - t.Fatal(rtmonErr) - } - - // We suppose that using an IPv4 link-local address and the - // dot1Q ID for Token Ring and FDDI doesn't harm anyone. - pv := &propVirtual{addr: "169.254.0.1", mask: "255.255.255.0"} - if err := pv.configure(1002); err != nil { - t.Skip(err) - } - if err := pv.setup(); err != nil { - t.Skip(err) - } - pv.teardown() - - go func() { - b := make([]byte, os.Getpagesize()) - for { - // There's no easy way to unblock this read - // call because the routing message exchange - // over routing socket is a connectionless - // message-oriented protocol, no control plane - // for signaling connectivity, and we cannot - // use the net package of standard library due - // to the lack of support for routing socket - // and circular dependency. - n, err := syscall.Read(rtmonSock, b) - if err != nil { - return - } - ms, err := ParseRIB(0, b[:n]) - if err != nil { - t.Error(err) - return - } - ss, err := msgs(ms).validate() - if err != nil { - t.Error(err) - return - } - for _, s := range ss { - t.Log(s) - } - } - }() - - for _, vid := range []int{1002, 1003, 1004, 1005} { - pv := &propVirtual{addr: "169.254.0.1", mask: "255.255.255.0"} - if err := pv.configure(vid); err != nil { - t.Fatal(err) - } - if err := pv.setup(); err != nil { - t.Fatal(err) - } - time.Sleep(200 * time.Millisecond) - if err := pv.teardown(); err != nil { - t.Fatal(err) - } - time.Sleep(200 * time.Millisecond) - } -} - func TestParseRIBWithFuzz(t *testing.T) { for _, fuzz := range []string{ "0\x00\x05\x050000000000000000" + @@ -137,102 +46,6 @@ func TestParseRIBWithFuzz(t *testing.T) { "\x00\x00\x00\x01\x00", "00000", } { - for typ := RIBType(0); typ < 256; typ++ { - ParseRIB(typ, []byte(fuzz)) - } - } -} - -func TestRouteMessage(t *testing.T) { - s, err := syscall.Socket(syscall.AF_ROUTE, syscall.SOCK_RAW, syscall.AF_UNSPEC) - if err != nil { - t.Fatal(err) - } - defer syscall.Close(s) - - var ms []RouteMessage - for _, af := range []int{syscall.AF_INET, syscall.AF_INET6} { - if _, err := fetchAndParseRIB(af, syscall.NET_RT_DUMP); err != nil { - t.Log(err) - continue - } - switch af { - case syscall.AF_INET: - ms = append(ms, []RouteMessage{ - { - Type: syscall.RTM_GET, - Addrs: []Addr{ - syscall.RTAX_DST: &Inet4Addr{IP: [4]byte{127, 0, 0, 1}}, - syscall.RTAX_GATEWAY: nil, - syscall.RTAX_NETMASK: nil, - syscall.RTAX_GENMASK: nil, - syscall.RTAX_IFP: &LinkAddr{}, - syscall.RTAX_IFA: &Inet4Addr{}, - syscall.RTAX_AUTHOR: nil, - syscall.RTAX_BRD: &Inet4Addr{}, - }, - }, - { - Type: syscall.RTM_GET, - Addrs: []Addr{ - syscall.RTAX_DST: &Inet4Addr{IP: [4]byte{127, 0, 0, 1}}, - }, - }, - }...) - case syscall.AF_INET6: - ms = append(ms, []RouteMessage{ - { - Type: syscall.RTM_GET, - Addrs: []Addr{ - syscall.RTAX_DST: &Inet6Addr{IP: [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}, - syscall.RTAX_GATEWAY: nil, - syscall.RTAX_NETMASK: nil, - syscall.RTAX_GENMASK: nil, - syscall.RTAX_IFP: &LinkAddr{}, - syscall.RTAX_IFA: &Inet6Addr{}, - syscall.RTAX_AUTHOR: nil, - syscall.RTAX_BRD: &Inet6Addr{}, - }, - }, - { - Type: syscall.RTM_GET, - Addrs: []Addr{ - syscall.RTAX_DST: &Inet6Addr{IP: [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}, - }, - }, - }...) - } - } - for i, m := range ms { - m.ID = uintptr(os.Getpid()) - m.Seq = i + 1 - wb, err := m.Marshal() - if err != nil { - t.Fatalf("%v: %v", m, err) - } - if _, err := syscall.Write(s, wb); err != nil { - t.Fatalf("%v: %v", m, err) - } - rb := make([]byte, os.Getpagesize()) - n, err := syscall.Read(s, rb) - if err != nil { - t.Fatalf("%v: %v", m, err) - } - rms, err := ParseRIB(0, rb[:n]) - if err != nil { - t.Fatalf("%v: %v", m, err) - } - for _, rm := range rms { - if rm, ok := rm.(*RouteMessage); ok && rm.Err != nil { - t.Errorf("%v: %v", m, rm.Err) - } - } - ss, err := msgs(rms).validate() - if err != nil { - t.Fatalf("%v: %v", m, err) - } - for _, s := range ss { - t.Log(s) - } + parseRIB([]byte(fuzz)) } } diff --git a/src/internal/routebsd/route.go b/src/internal/routebsd/route.go index d519c295fe71ff..5b6062e125869d 100644 --- a/src/internal/routebsd/route.go +++ b/src/internal/routebsd/route.go @@ -4,131 +4,56 @@ //go:build darwin || dragonfly || freebsd || netbsd || openbsd -// Package route provides basic functions for the manipulation of -// packet routing facilities on BSD variants. -// -// The package supports any version of Darwin, any version of -// DragonFly BSD, FreeBSD 7 and above, NetBSD 6 and above, and OpenBSD -// 5.6 and above. +// Package routebsd supports reading interface addresses on BSD systems. +// This is a very stripped down version of x/net/route, +// for use by the net package in the standard library. package routebsd import ( "errors" - "os" "syscall" ) var ( - errUnsupportedMessage = errors.New("unsupported message") - errMessageMismatch = errors.New("message mismatch") - errMessageTooShort = errors.New("message too short") - errInvalidMessage = errors.New("invalid message") - errInvalidAddr = errors.New("invalid address") - errShortBuffer = errors.New("short buffer") -) - -// A RouteMessage represents a message conveying an address prefix, a -// nexthop address and an output interface. -// -// Unlike other messages, this message can be used to query adjacency -// information for the given address prefix, to add a new route, and -// to delete or modify the existing route from the routing information -// base inside the kernel by writing and reading route messages on a -// routing socket. -// -// For the manipulation of routing information, the route message must -// contain appropriate fields that include: -// -// Version = -// Type = -// Flags = -// Index = -// ID = -// Seq = -// Addrs = -// -// The Type field specifies a type of manipulation, the Flags field -// specifies a class of target information and the Addrs field -// specifies target information like the following: -// -// route.RouteMessage{ -// Version: RTM_VERSION, -// Type: RTM_GET, -// Flags: RTF_UP | RTF_HOST, -// ID: uintptr(os.Getpid()), -// Seq: 1, -// Addrs: []route.Addrs{ -// RTAX_DST: &route.Inet4Addr{ ... }, -// RTAX_IFP: &route.LinkAddr{ ... }, -// RTAX_BRD: &route.Inet4Addr{ ... }, -// }, -// } -// -// The values for the above fields depend on the implementation of -// each operating system. -// -// The Err field on a response message contains an error value on the -// requested operation. If non-nil, the requested operation is failed. -type RouteMessage struct { - Version int // message version - Type int // message type - Flags int // route flags - Index int // interface index when attached - ID uintptr // sender's identifier; usually process ID - Seq int // sequence number - Err error // error on requested operation - Addrs []Addr // addresses - - extOff int // offset of header extension - raw []byte // raw message -} - -// Marshal returns the binary encoding of m. -func (m *RouteMessage) Marshal() ([]byte, error) { - return m.marshal() -} - -// A RIBType represents a type of routing information base. -type RIBType int - -const ( - RIBTypeRoute RIBType = syscall.NET_RT_DUMP - RIBTypeInterface RIBType = syscall.NET_RT_IFLIST + errMessageMismatch = errors.New("message mismatch") + errMessageTooShort = errors.New("message too short") + errInvalidMessage = errors.New("invalid message") + errInvalidAddr = errors.New("invalid address") ) -// FetchRIB fetches a routing information base from the operating +// fetchRIB fetches a routing information base from the operating // system. // -// The provided af must be an address family. -// -// The provided arg must be a RIBType-specific argument. -// When RIBType is related to routes, arg might be a set of route -// flags. When RIBType is related to network interfaces, arg might be -// an interface index or a set of interface flags. In most cases, zero -// means a wildcard. -func FetchRIB(af int, typ RIBType, arg int) ([]byte, error) { +// The arg is an interface index or 0 for all. +func fetchRIB(typ, arg int) ([]byte, error) { try := 0 for { try++ - mib := [6]int32{syscall.CTL_NET, syscall.AF_ROUTE, 0, int32(af), int32(typ), int32(arg)} - n := uintptr(0) - if err := sysctl(mib[:], nil, &n, nil, 0); err != nil { - return nil, os.NewSyscallError("sysctl", err) - } - if n == 0 { - return nil, nil + b, err := syscall.RouteRIB(typ, arg) + + // If the sysctl failed because the data got larger + // between the two sysctl calls, try a few times + // before failing (issue #45736). + const maxTries = 3 + if err == syscall.ENOMEM && try < maxTries { + continue } - b := make([]byte, n) - if err := sysctl(mib[:], &b[0], &n, nil, 0); err != nil { - // If the sysctl failed because the data got larger - // between the two sysctl calls, try a few times - // before failing. (golang.org/issue/45736). - const maxTries = 3 - if err == syscall.ENOMEM && try < maxTries { - continue - } - return nil, os.NewSyscallError("sysctl", err) - } - return b[:n], nil + + return b, err + } +} + +// FetchRIBMessages fetches a list of addressing messages for an interface. +// The typ argument is something like syscall.NET_RT_IFLIST. +// The argument is an interface index or 0 for all. +func FetchRIBMessages(typ, arg int) ([]Message, error) { + b, err := fetchRIB(typ, arg) + if err != nil { + return nil, err + } + ms, err := parseRIB(b) + if err != nil { + return nil, err } + return ms, nil } diff --git a/src/internal/routebsd/route_classic.go b/src/internal/routebsd/route_classic.go deleted file mode 100644 index 0d105d7bd43734..00000000000000 --- a/src/internal/routebsd/route_classic.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2016 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. - -//go:build darwin || dragonfly || freebsd || netbsd - -package routebsd - -import ( - "runtime" - "syscall" -) - -func (m *RouteMessage) marshal() ([]byte, error) { - w, ok := wireFormats[m.Type] - if !ok { - return nil, errUnsupportedMessage - } - l := w.bodyOff + addrsSpace(m.Addrs) - if runtime.GOOS == "darwin" || runtime.GOOS == "ios" { - // Fix stray pointer writes on macOS. - // See golang.org/issue/22456. - l += 1024 - } - b := make([]byte, l) - nativeEndian.PutUint16(b[:2], uint16(l)) - if m.Version == 0 { - b[2] = rtmVersion - } else { - b[2] = byte(m.Version) - } - b[3] = byte(m.Type) - nativeEndian.PutUint32(b[8:12], uint32(m.Flags)) - nativeEndian.PutUint16(b[4:6], uint16(m.Index)) - nativeEndian.PutUint32(b[16:20], uint32(m.ID)) - nativeEndian.PutUint32(b[20:24], uint32(m.Seq)) - attrs, err := marshalAddrs(b[w.bodyOff:], m.Addrs) - if err != nil { - return nil, err - } - if attrs > 0 { - nativeEndian.PutUint32(b[12:16], uint32(attrs)) - } - return b, nil -} - -func (w *wireFormat) parseRouteMessage(typ RIBType, b []byte) (Message, error) { - if len(b) < w.bodyOff { - return nil, errMessageTooShort - } - l := int(nativeEndian.Uint16(b[:2])) - if len(b) < l { - return nil, errInvalidMessage - } - m := &RouteMessage{ - Version: int(b[2]), - Type: int(b[3]), - Flags: int(nativeEndian.Uint32(b[8:12])), - Index: int(nativeEndian.Uint16(b[4:6])), - ID: uintptr(nativeEndian.Uint32(b[16:20])), - Seq: int(nativeEndian.Uint32(b[20:24])), - extOff: w.extOff, - raw: b[:l], - } - errno := syscall.Errno(nativeEndian.Uint32(b[28:32])) - if errno != 0 { - m.Err = errno - } - var err error - m.Addrs, err = parseAddrs(uint(nativeEndian.Uint32(b[12:16])), parseKernelInetAddr, b[w.bodyOff:]) - if err != nil { - return nil, err - } - return m, nil -} diff --git a/src/internal/routebsd/route_openbsd.go b/src/internal/routebsd/route_openbsd.go deleted file mode 100644 index e125b890067ac9..00000000000000 --- a/src/internal/routebsd/route_openbsd.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package routebsd - -import ( - "syscall" -) - -func (m *RouteMessage) marshal() ([]byte, error) { - l := sizeofRtMsghdr + addrsSpace(m.Addrs) - b := make([]byte, l) - nativeEndian.PutUint16(b[:2], uint16(l)) - if m.Version == 0 { - b[2] = syscall.RTM_VERSION - } else { - b[2] = byte(m.Version) - } - b[3] = byte(m.Type) - nativeEndian.PutUint16(b[4:6], uint16(sizeofRtMsghdr)) - nativeEndian.PutUint32(b[16:20], uint32(m.Flags)) - nativeEndian.PutUint16(b[6:8], uint16(m.Index)) - nativeEndian.PutUint32(b[24:28], uint32(m.ID)) - nativeEndian.PutUint32(b[28:32], uint32(m.Seq)) - attrs, err := marshalAddrs(b[sizeofRtMsghdr:], m.Addrs) - if err != nil { - return nil, err - } - if attrs > 0 { - nativeEndian.PutUint32(b[12:16], uint32(attrs)) - } - return b, nil -} - -func (*wireFormat) parseRouteMessage(_ RIBType, b []byte) (Message, error) { - if len(b) < sizeofRtMsghdr { - return nil, errMessageTooShort - } - l := int(nativeEndian.Uint16(b[:2])) - if len(b) < l { - return nil, errInvalidMessage - } - m := &RouteMessage{ - Version: int(b[2]), - Type: int(b[3]), - Flags: int(nativeEndian.Uint32(b[16:20])), - Index: int(nativeEndian.Uint16(b[6:8])), - ID: uintptr(nativeEndian.Uint32(b[24:28])), - Seq: int(nativeEndian.Uint32(b[28:32])), - raw: b[:l], - } - ll := int(nativeEndian.Uint16(b[4:6])) - if len(b) < ll { - return nil, errInvalidMessage - } - errno := syscall.Errno(nativeEndian.Uint32(b[32:36])) - if errno != 0 { - m.Err = errno - } - as, err := parseAddrs(uint(nativeEndian.Uint32(b[12:16])), parseKernelInetAddr, b[ll:]) - if err != nil { - return nil, err - } - m.Addrs = as - return m, nil -} diff --git a/src/internal/routebsd/route_test.go b/src/internal/routebsd/route_test.go index 2ac5fee9bdd64b..613175e388eceb 100644 --- a/src/internal/routebsd/route_test.go +++ b/src/internal/routebsd/route_test.go @@ -8,15 +8,10 @@ package routebsd import ( "fmt" - "os/exec" "runtime" "syscall" ) -func (m *RouteMessage) String() string { - return fmt.Sprintf("%s", addrAttrs(nativeEndian.Uint32(m.raw[12:16]))) -} - func (m *InterfaceMessage) String() string { var attrs addrAttrs if runtime.GOOS == "openbsd" { @@ -41,25 +36,6 @@ func (m *InterfaceMulticastAddrMessage) String() string { return fmt.Sprintf("%s", addrAttrs(nativeEndian.Uint32(m.raw[4:8]))) } -func (m *InterfaceAnnounceMessage) String() string { - what := "" - switch m.What { - case 0: - what = "arrival" - case 1: - what = "departure" - } - return fmt.Sprintf("(%d %s %s)", m.Index, m.Name, what) -} - -func (m *InterfaceMetrics) String() string { - return fmt.Sprintf("(type=%d mtu=%d)", m.Type, m.MTU) -} - -func (m *RouteMetrics) String() string { - return fmt.Sprintf("(pmtu=%d)", m.PathMTU) -} - type addrAttrs uint var addrAttrNames = [...]string{ @@ -102,15 +78,6 @@ func (ms msgs) validate() ([]string, error) { var ss []string for _, m := range ms { switch m := m.(type) { - case *RouteMessage: - if err := addrs(m.Addrs).match(addrAttrs(nativeEndian.Uint32(m.raw[12:16]))); err != nil { - return nil, err - } - sys := m.Sys() - if sys == nil { - return nil, fmt.Errorf("no sys for %s", m.String()) - } - ss = append(ss, m.String()+" "+syss(sys).String()+" "+addrs(m.Addrs).String()) case *InterfaceMessage: var attrs addrAttrs if runtime.GOOS == "openbsd" { @@ -121,11 +88,7 @@ func (ms msgs) validate() ([]string, error) { if err := addrs(m.Addrs).match(attrs); err != nil { return nil, err } - sys := m.Sys() - if sys == nil { - return nil, fmt.Errorf("no sys for %s", m.String()) - } - ss = append(ss, m.String()+" "+syss(sys).String()+" "+addrs(m.Addrs).String()) + ss = append(ss, m.String()+" "+addrs(m.Addrs).String()) case *InterfaceAddrMessage: var attrs addrAttrs if runtime.GOOS == "openbsd" { @@ -142,8 +105,6 @@ func (ms msgs) validate() ([]string, error) { return nil, err } ss = append(ss, m.String()+" "+addrs(m.Addrs).String()) - case *InterfaceAnnounceMessage: - ss = append(ss, m.String()) default: ss = append(ss, fmt.Sprintf("%+v", m)) } @@ -151,27 +112,6 @@ func (ms msgs) validate() ([]string, error) { return ss, nil } -type syss []Sys - -func (sys syss) String() string { - var s string - for _, sy := range sys { - switch sy := sy.(type) { - case *InterfaceMetrics: - if len(s) > 0 { - s += " " - } - s += sy.String() - case *RouteMetrics: - if len(s) > 0 { - s += " " - } - s += sy.String() - } - } - return s -} - type addrFamily int func (af addrFamily) String() string { @@ -239,16 +179,8 @@ func (a *LinkAddr) String() string { return fmt.Sprintf("(%v %d %s %s)", addrFamily(a.Family()), a.Index, name, lla) } -func (a *Inet4Addr) String() string { - return fmt.Sprintf("(%v %v)", addrFamily(a.Family()), ipAddr(a.IP[:])) -} - -func (a *Inet6Addr) String() string { - return fmt.Sprintf("(%v %v %d)", addrFamily(a.Family()), ipAddr(a.IP[:]), a.ZoneID) -} - -func (a *DefaultAddr) String() string { - return fmt.Sprintf("(%v %s)", addrFamily(a.Family()), ipAddr(a.Raw[2:]).String()) +func (a *InetAddr) String() string { + return fmt.Sprintf("(%v %v)", addrFamily(a.Family()), a.IP) } type addrs []Addr @@ -265,11 +197,7 @@ func (as addrs) String() string { switch a := a.(type) { case *LinkAddr: s += a.String() - case *Inet4Addr: - s += a.String() - case *Inet6Addr: - s += a.String() - case *DefaultAddr: + case *InetAddr: s += a.String() } } @@ -286,19 +214,20 @@ func (as addrs) match(attrs addrAttrs) error { if as[i] != nil { ts |= 1 << uint(i) } - switch as[i].(type) { - case *Inet4Addr: - if af == syscall.AF_UNSPEC { - af = syscall.AF_INET - } - if af != syscall.AF_INET { - return fmt.Errorf("got %v; want %v", addrs(as), addrFamily(af)) + switch addr := as[i].(type) { + case *InetAddr: + got := 0 + if addr.IP.Is4() { + got = syscall.AF_INET + } else if addr.IP.Is6() { + got = syscall.AF_INET6 } - case *Inet6Addr: if af == syscall.AF_UNSPEC { - af = syscall.AF_INET6 + if got != 0 { + af = got + } } - if af != syscall.AF_INET6 { + if got != 0 && af != got { return fmt.Errorf("got %v; want %v", addrs(as), addrFamily(af)) } } @@ -308,75 +237,3 @@ func (as addrs) match(attrs addrAttrs) error { } return nil } - -func fetchAndParseRIB(af int, typ RIBType) ([]Message, error) { - b, err := FetchRIB(af, typ, 0) - if err != nil { - return nil, fmt.Errorf("%v %d %v", addrFamily(af), typ, err) - } - ms, err := ParseRIB(typ, b) - if err != nil { - return nil, fmt.Errorf("%v %d %v", addrFamily(af), typ, err) - } - return ms, nil -} - -// propVirtual is a proprietary virtual network interface. -type propVirtual struct { - name string - addr, mask string - setupCmds []*exec.Cmd - teardownCmds []*exec.Cmd -} - -func (pv *propVirtual) setup() error { - for _, cmd := range pv.setupCmds { - if err := cmd.Run(); err != nil { - pv.teardown() - return err - } - } - return nil -} - -func (pv *propVirtual) teardown() error { - for _, cmd := range pv.teardownCmds { - if err := cmd.Run(); err != nil { - return err - } - } - return nil -} - -func (pv *propVirtual) configure(suffix int) error { - if runtime.GOOS == "openbsd" { - pv.name = fmt.Sprintf("vether%d", suffix) - } else { - pv.name = fmt.Sprintf("vlan%d", suffix) - } - xname, err := exec.LookPath("ifconfig") - if err != nil { - return err - } - pv.setupCmds = append(pv.setupCmds, &exec.Cmd{ - Path: xname, - Args: []string{"ifconfig", pv.name, "create"}, - }) - if runtime.GOOS == "netbsd" { - // NetBSD requires an underlying dot1Q-capable network - // interface. - pv.setupCmds = append(pv.setupCmds, &exec.Cmd{ - Path: xname, - Args: []string{"ifconfig", pv.name, "vlan", fmt.Sprintf("%d", suffix&0xfff), "vlanif", "wm0"}, - }) - } - pv.setupCmds = append(pv.setupCmds, &exec.Cmd{ - Path: xname, - Args: []string{"ifconfig", pv.name, "inet", pv.addr, "netmask", pv.mask}, - }) - pv.teardownCmds = append(pv.teardownCmds, &exec.Cmd{ - Path: xname, - Args: []string{"ifconfig", pv.name, "destroy"}, - }) - return nil -} diff --git a/src/internal/routebsd/sys.go b/src/internal/routebsd/sys.go index 69ef7b78716b1e..8805bca97e7cf2 100644 --- a/src/internal/routebsd/sys.go +++ b/src/internal/routebsd/sys.go @@ -41,5 +41,5 @@ func roundup(l int) int { type wireFormat struct { extOff int // offset of header extension bodyOff int // offset of message body - parse func(RIBType, []byte) (Message, error) + parse func([]byte) (Message, error) } diff --git a/src/internal/routebsd/sys_darwin.go b/src/internal/routebsd/sys_darwin.go index 2d8424a1c9b379..14864e2e327df2 100644 --- a/src/internal/routebsd/sys_darwin.go +++ b/src/internal/routebsd/sys_darwin.go @@ -6,77 +6,27 @@ package routebsd import "syscall" -func (typ RIBType) parseable() bool { - switch typ { - case syscall.NET_RT_STAT, syscall.NET_RT_TRASH: - return false - default: - return true - } -} - -// RouteMetrics represents route metrics. -type RouteMetrics struct { - PathMTU int // path maximum transmission unit -} - -// SysType implements the SysType method of Sys interface. -func (rmx *RouteMetrics) SysType() SysType { return SysMetrics } - -// Sys implements the Sys method of Message interface. -func (m *RouteMessage) Sys() []Sys { - return []Sys{ - &RouteMetrics{ - PathMTU: int(nativeEndian.Uint32(m.raw[m.extOff+4 : m.extOff+8])), - }, - } -} - -// InterfaceMetrics represents interface metrics. -type InterfaceMetrics struct { - Type int // interface type - MTU int // maximum transmission unit +// MTU returns the interface MTU. +func (m *InterfaceMessage) MTU() int { + return int(nativeEndian.Uint32(m.raw[m.extOff+8 : m.extOff+12])) } -// SysType implements the SysType method of Sys interface. -func (imx *InterfaceMetrics) SysType() SysType { return SysMetrics } - -// Sys implements the Sys method of Message interface. -func (m *InterfaceMessage) Sys() []Sys { - return []Sys{ - &InterfaceMetrics{ - Type: int(m.raw[m.extOff]), - MTU: int(nativeEndian.Uint32(m.raw[m.extOff+8 : m.extOff+12])), - }, - } -} +// sizeofIfMsghdr2 is copied from x/sys/unix. +const sizeofIfMsghdr2 = 0xa0 func probeRoutingStack() (int, map[int]*wireFormat) { - rtm := &wireFormat{extOff: 36, bodyOff: sizeofRtMsghdrDarwin15} - rtm.parse = rtm.parseRouteMessage - rtm2 := &wireFormat{extOff: 36, bodyOff: sizeofRtMsghdr2Darwin15} - rtm2.parse = rtm2.parseRouteMessage - ifm := &wireFormat{extOff: 16, bodyOff: sizeofIfMsghdrDarwin15} + ifm := &wireFormat{extOff: 16, bodyOff: syscall.SizeofIfMsghdr} ifm.parse = ifm.parseInterfaceMessage - ifm2 := &wireFormat{extOff: 32, bodyOff: sizeofIfMsghdr2Darwin15} + ifm2 := &wireFormat{extOff: 32, bodyOff: sizeofIfMsghdr2} ifm2.parse = ifm2.parseInterfaceMessage - ifam := &wireFormat{extOff: sizeofIfaMsghdrDarwin15, bodyOff: sizeofIfaMsghdrDarwin15} + ifam := &wireFormat{extOff: syscall.SizeofIfaMsghdr, bodyOff: syscall.SizeofIfaMsghdr} ifam.parse = ifam.parseInterfaceAddrMessage - ifmam := &wireFormat{extOff: sizeofIfmaMsghdrDarwin15, bodyOff: sizeofIfmaMsghdrDarwin15} + ifmam := &wireFormat{extOff: syscall.SizeofIfmaMsghdr, bodyOff: syscall.SizeofIfmaMsghdr} ifmam.parse = ifmam.parseInterfaceMulticastAddrMessage - ifmam2 := &wireFormat{extOff: sizeofIfmaMsghdr2Darwin15, bodyOff: sizeofIfmaMsghdr2Darwin15} + ifmam2 := &wireFormat{extOff: syscall.SizeofIfmaMsghdr2, bodyOff: syscall.SizeofIfmaMsghdr2} ifmam2.parse = ifmam2.parseInterfaceMulticastAddrMessage // Darwin kernels require 32-bit aligned access to routing facilities. return 4, map[int]*wireFormat{ - syscall.RTM_ADD: rtm, - syscall.RTM_DELETE: rtm, - syscall.RTM_CHANGE: rtm, - syscall.RTM_GET: rtm, - syscall.RTM_LOSING: rtm, - syscall.RTM_REDIRECT: rtm, - syscall.RTM_MISS: rtm, - syscall.RTM_LOCK: rtm, - syscall.RTM_RESOLVE: rtm, syscall.RTM_NEWADDR: ifam, syscall.RTM_DELADDR: ifam, syscall.RTM_IFINFO: ifm, @@ -84,6 +34,5 @@ func probeRoutingStack() (int, map[int]*wireFormat) { syscall.RTM_DELMADDR: ifmam, syscall.RTM_IFINFO2: ifm2, syscall.RTM_NEWMADDR2: ifmam2, - syscall.RTM_GET2: rtm2, } } diff --git a/src/internal/routebsd/sys_dragonfly.go b/src/internal/routebsd/sys_dragonfly.go index a3ee0ff73f3ee5..ce0e6fd4039245 100644 --- a/src/internal/routebsd/sys_dragonfly.go +++ b/src/internal/routebsd/sys_dragonfly.go @@ -9,80 +9,33 @@ import ( "unsafe" ) -func (typ RIBType) parseable() bool { return true } - -// RouteMetrics represents route metrics. -type RouteMetrics struct { - PathMTU int // path maximum transmission unit -} - -// SysType implements the SysType method of Sys interface. -func (rmx *RouteMetrics) SysType() SysType { return SysMetrics } - -// Sys implements the Sys method of Message interface. -func (m *RouteMessage) Sys() []Sys { - return []Sys{ - &RouteMetrics{ - PathMTU: int(nativeEndian.Uint64(m.raw[m.extOff+8 : m.extOff+16])), - }, - } -} - -// InterfaceMetrics represents interface metrics. -type InterfaceMetrics struct { - Type int // interface type - MTU int // maximum transmission unit -} - -// SysType implements the SysType method of Sys interface. -func (imx *InterfaceMetrics) SysType() SysType { return SysMetrics } - -// Sys implements the Sys method of Message interface. -func (m *InterfaceMessage) Sys() []Sys { - return []Sys{ - &InterfaceMetrics{ - Type: int(m.raw[m.extOff]), - MTU: int(nativeEndian.Uint32(m.raw[m.extOff+8 : m.extOff+12])), - }, - } +// MTU returns the interface MTU. +func (m *InterfaceMessage) MTU() int { + return int(nativeEndian.Uint32(m.raw[m.extOff+8 : m.extOff+12])) } func probeRoutingStack() (int, map[int]*wireFormat) { var p uintptr - rtm := &wireFormat{extOff: 40, bodyOff: sizeofRtMsghdrDragonFlyBSD4} - rtm.parse = rtm.parseRouteMessage - ifm := &wireFormat{extOff: 16, bodyOff: sizeofIfMsghdrDragonFlyBSD4} + ifm := &wireFormat{extOff: 16, bodyOff: syscall.SizeofIfMsghdr} ifm.parse = ifm.parseInterfaceMessage - ifam := &wireFormat{extOff: sizeofIfaMsghdrDragonFlyBSD4, bodyOff: sizeofIfaMsghdrDragonFlyBSD4} + ifam := &wireFormat{extOff: syscall.SizeofIfaMsghdr, bodyOff: syscall.SizeofIfaMsghdr} ifam.parse = ifam.parseInterfaceAddrMessage - ifmam := &wireFormat{extOff: sizeofIfmaMsghdrDragonFlyBSD4, bodyOff: sizeofIfmaMsghdrDragonFlyBSD4} + ifmam := &wireFormat{extOff: syscall.SizeofIfmaMsghdr, bodyOff: syscall.SizeofIfmaMsghdr} ifmam.parse = ifmam.parseInterfaceMulticastAddrMessage - ifanm := &wireFormat{extOff: sizeofIfAnnouncemsghdrDragonFlyBSD4, bodyOff: sizeofIfAnnouncemsghdrDragonFlyBSD4} - ifanm.parse = ifanm.parseInterfaceAnnounceMessage rel, _ := syscall.SysctlUint32("kern.osreldate") if rel >= 500705 { // https://github.com/DragonFlyBSD/DragonFlyBSD/commit/43a373152df2d405c9940983e584e6a25e76632d // but only the size of struct ifa_msghdr actually changed rtmVersion = 7 - ifam.bodyOff = sizeofIfaMsghdrDragonFlyBSD58 + ifam.bodyOff = 0x18 } return int(unsafe.Sizeof(p)), map[int]*wireFormat{ - syscall.RTM_ADD: rtm, - syscall.RTM_DELETE: rtm, - syscall.RTM_CHANGE: rtm, - syscall.RTM_GET: rtm, - syscall.RTM_LOSING: rtm, - syscall.RTM_REDIRECT: rtm, - syscall.RTM_MISS: rtm, - syscall.RTM_LOCK: rtm, - syscall.RTM_RESOLVE: rtm, - syscall.RTM_NEWADDR: ifam, - syscall.RTM_DELADDR: ifam, - syscall.RTM_IFINFO: ifm, - syscall.RTM_NEWMADDR: ifmam, - syscall.RTM_DELMADDR: ifmam, - syscall.RTM_IFANNOUNCE: ifanm, + syscall.RTM_NEWADDR: ifam, + syscall.RTM_DELADDR: ifam, + syscall.RTM_IFINFO: ifm, + syscall.RTM_NEWMADDR: ifmam, + syscall.RTM_DELMADDR: ifmam, } } diff --git a/src/internal/routebsd/sys_freebsd.go b/src/internal/routebsd/sys_freebsd.go index 6136e66385977b..5d5f49e42e01ea 100644 --- a/src/internal/routebsd/sys_freebsd.go +++ b/src/internal/routebsd/sys_freebsd.go @@ -9,52 +9,13 @@ import ( "unsafe" ) -func (typ RIBType) parseable() bool { return true } - -// RouteMetrics represents route metrics. -type RouteMetrics struct { - PathMTU int // path maximum transmission unit +// MTU returns the interface MTU. +func (m *InterfaceMessage) MTU() int { + return int(nativeEndian.Uint32(m.raw[m.extOff+8 : m.extOff+12])) } -// SysType implements the SysType method of Sys interface. -func (rmx *RouteMetrics) SysType() SysType { return SysMetrics } - -// Sys implements the Sys method of Message interface. -func (m *RouteMessage) Sys() []Sys { - if kernelAlign == 8 { - return []Sys{ - &RouteMetrics{ - PathMTU: int(nativeEndian.Uint64(m.raw[m.extOff+8 : m.extOff+16])), - }, - } - } - return []Sys{ - &RouteMetrics{ - PathMTU: int(nativeEndian.Uint32(m.raw[m.extOff+4 : m.extOff+8])), - }, - } -} - -// InterfaceMetrics represents interface metrics. -type InterfaceMetrics struct { - Type int // interface type - MTU int // maximum transmission unit -} - -// SysType implements the SysType method of Sys interface. -func (imx *InterfaceMetrics) SysType() SysType { return SysMetrics } - -// Sys implements the Sys method of Message interface. -func (m *InterfaceMessage) Sys() []Sys { - return []Sys{ - &InterfaceMetrics{ - Type: int(m.raw[m.extOff]), - MTU: int(nativeEndian.Uint32(m.raw[m.extOff+8 : m.extOff+12])), - }, - } -} - -var compatFreeBSD32 bool // 386 emulation on amd64 +// sizeofIfMsghdr is the size used on FreeBSD 11 for all platforms. +const sizeofIfMsghdr = 0xa8 func probeRoutingStack() (int, map[int]*wireFormat) { var p uintptr @@ -85,76 +46,17 @@ func probeRoutingStack() (int, map[int]*wireFormat) { break } } - if align != wordSize { - compatFreeBSD32 = true // 386 emulation on amd64 - } - var rtm, ifm, ifam, ifmam, ifanm *wireFormat - if compatFreeBSD32 { - rtm = &wireFormat{extOff: sizeofRtMsghdrFreeBSD10Emu - sizeofRtMetricsFreeBSD10Emu, bodyOff: sizeofRtMsghdrFreeBSD10Emu} - ifm = &wireFormat{extOff: 16} - ifam = &wireFormat{extOff: sizeofIfaMsghdrFreeBSD10Emu, bodyOff: sizeofIfaMsghdrFreeBSD10Emu} - ifmam = &wireFormat{extOff: sizeofIfmaMsghdrFreeBSD10Emu, bodyOff: sizeofIfmaMsghdrFreeBSD10Emu} - ifanm = &wireFormat{extOff: sizeofIfAnnouncemsghdrFreeBSD10Emu, bodyOff: sizeofIfAnnouncemsghdrFreeBSD10Emu} - } else { - rtm = &wireFormat{extOff: sizeofRtMsghdrFreeBSD10 - sizeofRtMetricsFreeBSD10, bodyOff: sizeofRtMsghdrFreeBSD10} - ifm = &wireFormat{extOff: 16} - ifam = &wireFormat{extOff: sizeofIfaMsghdrFreeBSD10, bodyOff: sizeofIfaMsghdrFreeBSD10} - ifmam = &wireFormat{extOff: sizeofIfmaMsghdrFreeBSD10, bodyOff: sizeofIfmaMsghdrFreeBSD10} - ifanm = &wireFormat{extOff: sizeofIfAnnouncemsghdrFreeBSD10, bodyOff: sizeofIfAnnouncemsghdrFreeBSD10} - } - rel, _ := syscall.SysctlUint32("kern.osreldate") - switch { - case rel < 800000: - if compatFreeBSD32 { - ifm.bodyOff = sizeofIfMsghdrFreeBSD7Emu - } else { - ifm.bodyOff = sizeofIfMsghdrFreeBSD7 - } - case 800000 <= rel && rel < 900000: - if compatFreeBSD32 { - ifm.bodyOff = sizeofIfMsghdrFreeBSD8Emu - } else { - ifm.bodyOff = sizeofIfMsghdrFreeBSD8 - } - case 900000 <= rel && rel < 1000000: - if compatFreeBSD32 { - ifm.bodyOff = sizeofIfMsghdrFreeBSD9Emu - } else { - ifm.bodyOff = sizeofIfMsghdrFreeBSD9 - } - case 1000000 <= rel && rel < 1100000: - if compatFreeBSD32 { - ifm.bodyOff = sizeofIfMsghdrFreeBSD10Emu - } else { - ifm.bodyOff = sizeofIfMsghdrFreeBSD10 - } - default: - if compatFreeBSD32 { - ifm.bodyOff = sizeofIfMsghdrFreeBSD11Emu - } else { - ifm.bodyOff = sizeofIfMsghdrFreeBSD11 - } - } - rtm.parse = rtm.parseRouteMessage + ifm := &wireFormat{extOff: 16, bodyOff: sizeofIfMsghdr} ifm.parse = ifm.parseInterfaceMessage + ifam := &wireFormat{extOff: syscall.SizeofIfaMsghdr, bodyOff: syscall.SizeofIfaMsghdr} ifam.parse = ifam.parseInterfaceAddrMessage + ifmam := &wireFormat{extOff: syscall.SizeofIfmaMsghdr, bodyOff: syscall.SizeofIfmaMsghdr} ifmam.parse = ifmam.parseInterfaceMulticastAddrMessage - ifanm.parse = ifanm.parseInterfaceAnnounceMessage return align, map[int]*wireFormat{ - syscall.RTM_ADD: rtm, - syscall.RTM_DELETE: rtm, - syscall.RTM_CHANGE: rtm, - syscall.RTM_GET: rtm, - syscall.RTM_LOSING: rtm, - syscall.RTM_REDIRECT: rtm, - syscall.RTM_MISS: rtm, - syscall.RTM_LOCK: rtm, - syscall.RTM_RESOLVE: rtm, - syscall.RTM_NEWADDR: ifam, - syscall.RTM_DELADDR: ifam, - syscall.RTM_IFINFO: ifm, - syscall.RTM_NEWMADDR: ifmam, - syscall.RTM_DELMADDR: ifmam, - syscall.RTM_IFANNOUNCE: ifanm, + syscall.RTM_NEWADDR: ifam, + syscall.RTM_DELADDR: ifam, + syscall.RTM_IFINFO: ifm, + syscall.RTM_NEWMADDR: ifmam, + syscall.RTM_DELMADDR: ifmam, } } diff --git a/src/internal/routebsd/sys_netbsd.go b/src/internal/routebsd/sys_netbsd.go index 3a33174454db4b..b181f727c25ca5 100644 --- a/src/internal/routebsd/sys_netbsd.go +++ b/src/internal/routebsd/sys_netbsd.go @@ -6,68 +6,21 @@ package routebsd import "syscall" -func (typ RIBType) parseable() bool { return true } - -// RouteMetrics represents route metrics. -type RouteMetrics struct { - PathMTU int // path maximum transmission unit -} - -// SysType implements the SysType method of Sys interface. -func (rmx *RouteMetrics) SysType() SysType { return SysMetrics } - -// Sys implements the Sys method of Message interface. -func (m *RouteMessage) Sys() []Sys { - return []Sys{ - &RouteMetrics{ - PathMTU: int(nativeEndian.Uint64(m.raw[m.extOff+8 : m.extOff+16])), - }, - } -} - -// RouteMetrics represents route metrics. -type InterfaceMetrics struct { - Type int // interface type - MTU int // maximum transmission unit -} - -// SysType implements the SysType method of Sys interface. -func (imx *InterfaceMetrics) SysType() SysType { return SysMetrics } - -// Sys implements the Sys method of Message interface. -func (m *InterfaceMessage) Sys() []Sys { - return []Sys{ - &InterfaceMetrics{ - Type: int(m.raw[m.extOff]), - MTU: int(nativeEndian.Uint32(m.raw[m.extOff+8 : m.extOff+12])), - }, - } +// MTU returns the interface MTU. +func (m *InterfaceMessage) MTU() int { + return int(nativeEndian.Uint32(m.raw[m.extOff+8 : m.extOff+12])) } func probeRoutingStack() (int, map[int]*wireFormat) { - rtm := &wireFormat{extOff: 40, bodyOff: sizeofRtMsghdrNetBSD7} - rtm.parse = rtm.parseRouteMessage - ifm := &wireFormat{extOff: 16, bodyOff: sizeofIfMsghdrNetBSD7} + ifm := &wireFormat{extOff: 16, bodyOff: syscall.SizeofIfMsghdr} ifm.parse = ifm.parseInterfaceMessage - ifam := &wireFormat{extOff: sizeofIfaMsghdrNetBSD7, bodyOff: sizeofIfaMsghdrNetBSD7} + ifam := &wireFormat{extOff: syscall.SizeofIfaMsghdr, bodyOff: syscall.SizeofIfaMsghdr} ifam.parse = ifam.parseInterfaceAddrMessage - ifanm := &wireFormat{extOff: sizeofIfAnnouncemsghdrNetBSD7, bodyOff: sizeofIfAnnouncemsghdrNetBSD7} - ifanm.parse = ifanm.parseInterfaceAnnounceMessage // NetBSD 6 and above kernels require 64-bit aligned access to // routing facilities. return 8, map[int]*wireFormat{ - syscall.RTM_ADD: rtm, - syscall.RTM_DELETE: rtm, - syscall.RTM_CHANGE: rtm, - syscall.RTM_GET: rtm, - syscall.RTM_LOSING: rtm, - syscall.RTM_REDIRECT: rtm, - syscall.RTM_MISS: rtm, - syscall.RTM_LOCK: rtm, - syscall.RTM_RESOLVE: rtm, - syscall.RTM_NEWADDR: ifam, - syscall.RTM_DELADDR: ifam, - syscall.RTM_IFANNOUNCE: ifanm, - syscall.RTM_IFINFO: ifm, + syscall.RTM_NEWADDR: ifam, + syscall.RTM_DELADDR: ifam, + syscall.RTM_IFINFO: ifm, } } diff --git a/src/internal/routebsd/sys_openbsd.go b/src/internal/routebsd/sys_openbsd.go index aaeb7284754adf..83256c8fabfa59 100644 --- a/src/internal/routebsd/sys_openbsd.go +++ b/src/internal/routebsd/sys_openbsd.go @@ -9,74 +9,20 @@ import ( "unsafe" ) -func (typ RIBType) parseable() bool { - switch typ { - case syscall.NET_RT_STATS, syscall.NET_RT_TABLE: - return false - default: - return true - } -} - -// RouteMetrics represents route metrics. -type RouteMetrics struct { - PathMTU int // path maximum transmission unit -} - -// SysType implements the SysType method of Sys interface. -func (rmx *RouteMetrics) SysType() SysType { return SysMetrics } - -// Sys implements the Sys method of Message interface. -func (m *RouteMessage) Sys() []Sys { - return []Sys{ - &RouteMetrics{ - PathMTU: int(nativeEndian.Uint32(m.raw[60:64])), - }, - } -} - -// InterfaceMetrics represents interface metrics. -type InterfaceMetrics struct { - Type int // interface type - MTU int // maximum transmission unit -} - -// SysType implements the SysType method of Sys interface. -func (imx *InterfaceMetrics) SysType() SysType { return SysMetrics } - -// Sys implements the Sys method of Message interface. -func (m *InterfaceMessage) Sys() []Sys { - return []Sys{ - &InterfaceMetrics{ - Type: int(m.raw[24]), - MTU: int(nativeEndian.Uint32(m.raw[28:32])), - }, - } +// MTU returns the interface MTU. +func (m *InterfaceMessage) MTU() int { + return int(nativeEndian.Uint32(m.raw[28:32])) } func probeRoutingStack() (int, map[int]*wireFormat) { var p uintptr - rtm := &wireFormat{extOff: -1, bodyOff: -1} - rtm.parse = rtm.parseRouteMessage ifm := &wireFormat{extOff: -1, bodyOff: -1} ifm.parse = ifm.parseInterfaceMessage ifam := &wireFormat{extOff: -1, bodyOff: -1} ifam.parse = ifam.parseInterfaceAddrMessage - ifanm := &wireFormat{extOff: -1, bodyOff: -1} - ifanm.parse = ifanm.parseInterfaceAnnounceMessage return int(unsafe.Sizeof(p)), map[int]*wireFormat{ - syscall.RTM_ADD: rtm, - syscall.RTM_DELETE: rtm, - syscall.RTM_CHANGE: rtm, - syscall.RTM_GET: rtm, - syscall.RTM_LOSING: rtm, - syscall.RTM_REDIRECT: rtm, - syscall.RTM_MISS: rtm, - syscall.RTM_RESOLVE: rtm, - syscall.RTM_NEWADDR: ifam, - syscall.RTM_DELADDR: ifam, - syscall.RTM_IFINFO: ifm, - syscall.RTM_IFANNOUNCE: ifanm, - syscall.RTM_DESYNC: rtm, + syscall.RTM_NEWADDR: ifam, + syscall.RTM_DELADDR: ifam, + syscall.RTM_IFINFO: ifm, } } diff --git a/src/internal/routebsd/syscall.go b/src/internal/routebsd/syscall.go deleted file mode 100644 index 559aa7dfdc613e..00000000000000 --- a/src/internal/routebsd/syscall.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2016 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. - -//go:build darwin || dragonfly || freebsd || netbsd || openbsd - -package routebsd - -import _ "unsafe" // for linkname - -//go:linkname sysctl syscall.sysctl -func sysctl(mib []int32, old *byte, oldlen *uintptr, new *byte, newlen uintptr) error diff --git a/src/internal/routebsd/zsys_darwin.go b/src/internal/routebsd/zsys_darwin.go deleted file mode 100644 index 3e6cbb0b0d6b08..00000000000000 --- a/src/internal/routebsd/zsys_darwin.go +++ /dev/null @@ -1,22 +0,0 @@ -// Code generated by cmd/cgo -godefs; DO NOT EDIT. -// cgo -godefs defs_darwin.go - -package routebsd - -const ( - sizeofIfMsghdrDarwin15 = 0x70 - sizeofIfaMsghdrDarwin15 = 0x14 - sizeofIfmaMsghdrDarwin15 = 0x10 - sizeofIfMsghdr2Darwin15 = 0xa0 - sizeofIfmaMsghdr2Darwin15 = 0x14 - sizeofIfDataDarwin15 = 0x60 - sizeofIfData64Darwin15 = 0x80 - - sizeofRtMsghdrDarwin15 = 0x5c - sizeofRtMsghdr2Darwin15 = 0x5c - sizeofRtMetricsDarwin15 = 0x38 - - sizeofSockaddrStorage = 0x80 - sizeofSockaddrInet = 0x10 - sizeofSockaddrInet6 = 0x1c -) diff --git a/src/internal/routebsd/zsys_dragonfly.go b/src/internal/routebsd/zsys_dragonfly.go deleted file mode 100644 index 41e74d53ae7e4c..00000000000000 --- a/src/internal/routebsd/zsys_dragonfly.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by cmd/cgo -godefs; DO NOT EDIT. -// cgo -godefs defs_dragonfly.go - -package routebsd - -const ( - sizeofIfMsghdrDragonFlyBSD4 = 0xb0 - sizeofIfaMsghdrDragonFlyBSD4 = 0x14 - sizeofIfmaMsghdrDragonFlyBSD4 = 0x10 - sizeofIfAnnouncemsghdrDragonFlyBSD4 = 0x18 - - sizeofIfaMsghdrDragonFlyBSD58 = 0x18 - - sizeofRtMsghdrDragonFlyBSD4 = 0x98 - sizeofRtMetricsDragonFlyBSD4 = 0x70 - - sizeofSockaddrStorage = 0x80 - sizeofSockaddrInet = 0x10 - sizeofSockaddrInet6 = 0x1c -) diff --git a/src/internal/routebsd/zsys_freebsd_386.go b/src/internal/routebsd/zsys_freebsd_386.go deleted file mode 100644 index 2a85855477dd2e..00000000000000 --- a/src/internal/routebsd/zsys_freebsd_386.go +++ /dev/null @@ -1,55 +0,0 @@ -// Code generated by cmd/cgo -godefs; DO NOT EDIT. -// cgo -godefs defs_freebsd.go - -package routebsd - -const ( - sizeofIfMsghdrlFreeBSD10 = 0x68 - sizeofIfaMsghdrFreeBSD10 = 0x14 - sizeofIfaMsghdrlFreeBSD10 = 0x6c - sizeofIfmaMsghdrFreeBSD10 = 0x10 - sizeofIfAnnouncemsghdrFreeBSD10 = 0x18 - - sizeofRtMsghdrFreeBSD10 = 0x5c - sizeofRtMetricsFreeBSD10 = 0x38 - - sizeofIfMsghdrFreeBSD7 = 0x60 - sizeofIfMsghdrFreeBSD8 = 0x60 - sizeofIfMsghdrFreeBSD9 = 0x60 - sizeofIfMsghdrFreeBSD10 = 0x64 - sizeofIfMsghdrFreeBSD11 = 0xa8 - - sizeofIfDataFreeBSD7 = 0x50 - sizeofIfDataFreeBSD8 = 0x50 - sizeofIfDataFreeBSD9 = 0x50 - sizeofIfDataFreeBSD10 = 0x54 - sizeofIfDataFreeBSD11 = 0x98 - - // MODIFIED BY HAND FOR 386 EMULATION ON AMD64 - // 386 EMULATION USES THE UNDERLYING RAW DATA LAYOUT - - sizeofIfMsghdrlFreeBSD10Emu = 0xb0 - sizeofIfaMsghdrFreeBSD10Emu = 0x14 - sizeofIfaMsghdrlFreeBSD10Emu = 0xb0 - sizeofIfmaMsghdrFreeBSD10Emu = 0x10 - sizeofIfAnnouncemsghdrFreeBSD10Emu = 0x18 - - sizeofRtMsghdrFreeBSD10Emu = 0x98 - sizeofRtMetricsFreeBSD10Emu = 0x70 - - sizeofIfMsghdrFreeBSD7Emu = 0xa8 - sizeofIfMsghdrFreeBSD8Emu = 0xa8 - sizeofIfMsghdrFreeBSD9Emu = 0xa8 - sizeofIfMsghdrFreeBSD10Emu = 0xa8 - sizeofIfMsghdrFreeBSD11Emu = 0xa8 - - sizeofIfDataFreeBSD7Emu = 0x98 - sizeofIfDataFreeBSD8Emu = 0x98 - sizeofIfDataFreeBSD9Emu = 0x98 - sizeofIfDataFreeBSD10Emu = 0x98 - sizeofIfDataFreeBSD11Emu = 0x98 - - sizeofSockaddrStorage = 0x80 - sizeofSockaddrInet = 0x10 - sizeofSockaddrInet6 = 0x1c -) diff --git a/src/internal/routebsd/zsys_freebsd_amd64.go b/src/internal/routebsd/zsys_freebsd_amd64.go deleted file mode 100644 index ea7b959f052238..00000000000000 --- a/src/internal/routebsd/zsys_freebsd_amd64.go +++ /dev/null @@ -1,52 +0,0 @@ -// Code generated by cmd/cgo -godefs; DO NOT EDIT. -// cgo -godefs defs_freebsd.go - -package routebsd - -const ( - sizeofIfMsghdrlFreeBSD10 = 0xb0 - sizeofIfaMsghdrFreeBSD10 = 0x14 - sizeofIfaMsghdrlFreeBSD10 = 0xb0 - sizeofIfmaMsghdrFreeBSD10 = 0x10 - sizeofIfAnnouncemsghdrFreeBSD10 = 0x18 - - sizeofRtMsghdrFreeBSD10 = 0x98 - sizeofRtMetricsFreeBSD10 = 0x70 - - sizeofIfMsghdrFreeBSD7 = 0xa8 - sizeofIfMsghdrFreeBSD8 = 0xa8 - sizeofIfMsghdrFreeBSD9 = 0xa8 - sizeofIfMsghdrFreeBSD10 = 0xa8 - sizeofIfMsghdrFreeBSD11 = 0xa8 - - sizeofIfDataFreeBSD7 = 0x98 - sizeofIfDataFreeBSD8 = 0x98 - sizeofIfDataFreeBSD9 = 0x98 - sizeofIfDataFreeBSD10 = 0x98 - sizeofIfDataFreeBSD11 = 0x98 - - sizeofIfMsghdrlFreeBSD10Emu = 0xb0 - sizeofIfaMsghdrFreeBSD10Emu = 0x14 - sizeofIfaMsghdrlFreeBSD10Emu = 0xb0 - sizeofIfmaMsghdrFreeBSD10Emu = 0x10 - sizeofIfAnnouncemsghdrFreeBSD10Emu = 0x18 - - sizeofRtMsghdrFreeBSD10Emu = 0x98 - sizeofRtMetricsFreeBSD10Emu = 0x70 - - sizeofIfMsghdrFreeBSD7Emu = 0xa8 - sizeofIfMsghdrFreeBSD8Emu = 0xa8 - sizeofIfMsghdrFreeBSD9Emu = 0xa8 - sizeofIfMsghdrFreeBSD10Emu = 0xa8 - sizeofIfMsghdrFreeBSD11Emu = 0xa8 - - sizeofIfDataFreeBSD7Emu = 0x98 - sizeofIfDataFreeBSD8Emu = 0x98 - sizeofIfDataFreeBSD9Emu = 0x98 - sizeofIfDataFreeBSD10Emu = 0x98 - sizeofIfDataFreeBSD11Emu = 0x98 - - sizeofSockaddrStorage = 0x80 - sizeofSockaddrInet = 0x10 - sizeofSockaddrInet6 = 0x1c -) diff --git a/src/internal/routebsd/zsys_freebsd_arm.go b/src/internal/routebsd/zsys_freebsd_arm.go deleted file mode 100644 index 1c3d653c869bbe..00000000000000 --- a/src/internal/routebsd/zsys_freebsd_arm.go +++ /dev/null @@ -1,52 +0,0 @@ -// Code generated by cmd/cgo -godefs; DO NOT EDIT. -// cgo -godefs defs_freebsd.go - -package routebsd - -const ( - sizeofIfMsghdrlFreeBSD10 = 0x68 - sizeofIfaMsghdrFreeBSD10 = 0x14 - sizeofIfaMsghdrlFreeBSD10 = 0x6c - sizeofIfmaMsghdrFreeBSD10 = 0x10 - sizeofIfAnnouncemsghdrFreeBSD10 = 0x18 - - sizeofRtMsghdrFreeBSD10 = 0x5c - sizeofRtMetricsFreeBSD10 = 0x38 - - sizeofIfMsghdrFreeBSD7 = 0x70 - sizeofIfMsghdrFreeBSD8 = 0x70 - sizeofIfMsghdrFreeBSD9 = 0x70 - sizeofIfMsghdrFreeBSD10 = 0x70 - sizeofIfMsghdrFreeBSD11 = 0xa8 - - sizeofIfDataFreeBSD7 = 0x60 - sizeofIfDataFreeBSD8 = 0x60 - sizeofIfDataFreeBSD9 = 0x60 - sizeofIfDataFreeBSD10 = 0x60 - sizeofIfDataFreeBSD11 = 0x98 - - sizeofIfMsghdrlFreeBSD10Emu = 0x68 - sizeofIfaMsghdrFreeBSD10Emu = 0x14 - sizeofIfaMsghdrlFreeBSD10Emu = 0x6c - sizeofIfmaMsghdrFreeBSD10Emu = 0x10 - sizeofIfAnnouncemsghdrFreeBSD10Emu = 0x18 - - sizeofRtMsghdrFreeBSD10Emu = 0x5c - sizeofRtMetricsFreeBSD10Emu = 0x38 - - sizeofIfMsghdrFreeBSD7Emu = 0x70 - sizeofIfMsghdrFreeBSD8Emu = 0x70 - sizeofIfMsghdrFreeBSD9Emu = 0x70 - sizeofIfMsghdrFreeBSD10Emu = 0x70 - sizeofIfMsghdrFreeBSD11Emu = 0xa8 - - sizeofIfDataFreeBSD7Emu = 0x60 - sizeofIfDataFreeBSD8Emu = 0x60 - sizeofIfDataFreeBSD9Emu = 0x60 - sizeofIfDataFreeBSD10Emu = 0x60 - sizeofIfDataFreeBSD11Emu = 0x98 - - sizeofSockaddrStorage = 0x80 - sizeofSockaddrInet = 0x10 - sizeofSockaddrInet6 = 0x1c -) diff --git a/src/internal/routebsd/zsys_freebsd_arm64.go b/src/internal/routebsd/zsys_freebsd_arm64.go deleted file mode 100644 index ea7b959f052238..00000000000000 --- a/src/internal/routebsd/zsys_freebsd_arm64.go +++ /dev/null @@ -1,52 +0,0 @@ -// Code generated by cmd/cgo -godefs; DO NOT EDIT. -// cgo -godefs defs_freebsd.go - -package routebsd - -const ( - sizeofIfMsghdrlFreeBSD10 = 0xb0 - sizeofIfaMsghdrFreeBSD10 = 0x14 - sizeofIfaMsghdrlFreeBSD10 = 0xb0 - sizeofIfmaMsghdrFreeBSD10 = 0x10 - sizeofIfAnnouncemsghdrFreeBSD10 = 0x18 - - sizeofRtMsghdrFreeBSD10 = 0x98 - sizeofRtMetricsFreeBSD10 = 0x70 - - sizeofIfMsghdrFreeBSD7 = 0xa8 - sizeofIfMsghdrFreeBSD8 = 0xa8 - sizeofIfMsghdrFreeBSD9 = 0xa8 - sizeofIfMsghdrFreeBSD10 = 0xa8 - sizeofIfMsghdrFreeBSD11 = 0xa8 - - sizeofIfDataFreeBSD7 = 0x98 - sizeofIfDataFreeBSD8 = 0x98 - sizeofIfDataFreeBSD9 = 0x98 - sizeofIfDataFreeBSD10 = 0x98 - sizeofIfDataFreeBSD11 = 0x98 - - sizeofIfMsghdrlFreeBSD10Emu = 0xb0 - sizeofIfaMsghdrFreeBSD10Emu = 0x14 - sizeofIfaMsghdrlFreeBSD10Emu = 0xb0 - sizeofIfmaMsghdrFreeBSD10Emu = 0x10 - sizeofIfAnnouncemsghdrFreeBSD10Emu = 0x18 - - sizeofRtMsghdrFreeBSD10Emu = 0x98 - sizeofRtMetricsFreeBSD10Emu = 0x70 - - sizeofIfMsghdrFreeBSD7Emu = 0xa8 - sizeofIfMsghdrFreeBSD8Emu = 0xa8 - sizeofIfMsghdrFreeBSD9Emu = 0xa8 - sizeofIfMsghdrFreeBSD10Emu = 0xa8 - sizeofIfMsghdrFreeBSD11Emu = 0xa8 - - sizeofIfDataFreeBSD7Emu = 0x98 - sizeofIfDataFreeBSD8Emu = 0x98 - sizeofIfDataFreeBSD9Emu = 0x98 - sizeofIfDataFreeBSD10Emu = 0x98 - sizeofIfDataFreeBSD11Emu = 0x98 - - sizeofSockaddrStorage = 0x80 - sizeofSockaddrInet = 0x10 - sizeofSockaddrInet6 = 0x1c -) diff --git a/src/internal/routebsd/zsys_freebsd_riscv64.go b/src/internal/routebsd/zsys_freebsd_riscv64.go deleted file mode 100644 index ea7b959f052238..00000000000000 --- a/src/internal/routebsd/zsys_freebsd_riscv64.go +++ /dev/null @@ -1,52 +0,0 @@ -// Code generated by cmd/cgo -godefs; DO NOT EDIT. -// cgo -godefs defs_freebsd.go - -package routebsd - -const ( - sizeofIfMsghdrlFreeBSD10 = 0xb0 - sizeofIfaMsghdrFreeBSD10 = 0x14 - sizeofIfaMsghdrlFreeBSD10 = 0xb0 - sizeofIfmaMsghdrFreeBSD10 = 0x10 - sizeofIfAnnouncemsghdrFreeBSD10 = 0x18 - - sizeofRtMsghdrFreeBSD10 = 0x98 - sizeofRtMetricsFreeBSD10 = 0x70 - - sizeofIfMsghdrFreeBSD7 = 0xa8 - sizeofIfMsghdrFreeBSD8 = 0xa8 - sizeofIfMsghdrFreeBSD9 = 0xa8 - sizeofIfMsghdrFreeBSD10 = 0xa8 - sizeofIfMsghdrFreeBSD11 = 0xa8 - - sizeofIfDataFreeBSD7 = 0x98 - sizeofIfDataFreeBSD8 = 0x98 - sizeofIfDataFreeBSD9 = 0x98 - sizeofIfDataFreeBSD10 = 0x98 - sizeofIfDataFreeBSD11 = 0x98 - - sizeofIfMsghdrlFreeBSD10Emu = 0xb0 - sizeofIfaMsghdrFreeBSD10Emu = 0x14 - sizeofIfaMsghdrlFreeBSD10Emu = 0xb0 - sizeofIfmaMsghdrFreeBSD10Emu = 0x10 - sizeofIfAnnouncemsghdrFreeBSD10Emu = 0x18 - - sizeofRtMsghdrFreeBSD10Emu = 0x98 - sizeofRtMetricsFreeBSD10Emu = 0x70 - - sizeofIfMsghdrFreeBSD7Emu = 0xa8 - sizeofIfMsghdrFreeBSD8Emu = 0xa8 - sizeofIfMsghdrFreeBSD9Emu = 0xa8 - sizeofIfMsghdrFreeBSD10Emu = 0xa8 - sizeofIfMsghdrFreeBSD11Emu = 0xa8 - - sizeofIfDataFreeBSD7Emu = 0x98 - sizeofIfDataFreeBSD8Emu = 0x98 - sizeofIfDataFreeBSD9Emu = 0x98 - sizeofIfDataFreeBSD10Emu = 0x98 - sizeofIfDataFreeBSD11Emu = 0x98 - - sizeofSockaddrStorage = 0x80 - sizeofSockaddrInet = 0x10 - sizeofSockaddrInet6 = 0x1c -) diff --git a/src/internal/routebsd/zsys_netbsd.go b/src/internal/routebsd/zsys_netbsd.go deleted file mode 100644 index f072c311dee870..00000000000000 --- a/src/internal/routebsd/zsys_netbsd.go +++ /dev/null @@ -1,17 +0,0 @@ -// Code generated by cmd/cgo -godefs; DO NOT EDIT. -// cgo -godefs defs_netbsd.go - -package routebsd - -const ( - sizeofIfMsghdrNetBSD7 = 0x98 - sizeofIfaMsghdrNetBSD7 = 0x18 - sizeofIfAnnouncemsghdrNetBSD7 = 0x18 - - sizeofRtMsghdrNetBSD7 = 0x78 - sizeofRtMetricsNetBSD7 = 0x50 - - sizeofSockaddrStorage = 0x80 - sizeofSockaddrInet = 0x10 - sizeofSockaddrInet6 = 0x1c -) diff --git a/src/internal/routebsd/zsys_openbsd.go b/src/internal/routebsd/zsys_openbsd.go deleted file mode 100644 index 2bb764125420dc..00000000000000 --- a/src/internal/routebsd/zsys_openbsd.go +++ /dev/null @@ -1,12 +0,0 @@ -// Code generated by cmd/cgo -godefs; DO NOT EDIT. -// cgo -godefs defs_openbsd.go - -package routebsd - -const ( - sizeofRtMsghdr = 0x60 - - sizeofSockaddrStorage = 0x100 - sizeofSockaddrInet = 0x10 - sizeofSockaddrInet6 = 0x1c -) diff --git a/src/net/interface_bsd.go b/src/net/interface_bsd.go index 687af00170cc74..0861610f168996 100644 --- a/src/net/interface_bsd.go +++ b/src/net/interface_bsd.go @@ -38,12 +38,7 @@ func interfaceTable(ifindex int) ([]Interface, error) { ift[n].HardwareAddr = make([]byte, len(sa.Addr)) copy(ift[n].HardwareAddr, sa.Addr) } - for _, sys := range m.Sys() { - if imx, ok := sys.(*routebsd.InterfaceMetrics); ok { - ift[n].MTU = imx.MTU - break - } - } + ift[n].MTU = m.MTU() n++ if ifindex == m.Index { return ift[:n], nil @@ -97,19 +92,27 @@ func interfaceAddrTable(ifi *Interface) ([]Addr, error) { } var mask IPMask switch sa := m.Addrs[syscall.RTAX_NETMASK].(type) { - case *routebsd.Inet4Addr: - mask = IPv4Mask(sa.IP[0], sa.IP[1], sa.IP[2], sa.IP[3]) - case *routebsd.Inet6Addr: - mask = make(IPMask, IPv6len) - copy(mask, sa.IP[:]) + case *routebsd.InetAddr: + if sa.IP.Is4() { + a := sa.IP.As4() + mask = IPv4Mask(a[0], a[1], a[2], a[3]) + } else if sa.IP.Is6() { + a := sa.IP.As16() + mask = make(IPMask, IPv6len) + copy(mask, a[:]) + } } var ip IP switch sa := m.Addrs[syscall.RTAX_IFA].(type) { - case *routebsd.Inet4Addr: - ip = IPv4(sa.IP[0], sa.IP[1], sa.IP[2], sa.IP[3]) - case *routebsd.Inet6Addr: - ip = make(IP, IPv6len) - copy(ip, sa.IP[:]) + case *routebsd.InetAddr: + if sa.IP.Is4() { + a := sa.IP.As4() + ip = IPv4(a[0], a[1], a[2], a[3]) + } else if sa.IP.Is6() { + a := sa.IP.As16() + ip = make(IP, IPv6len) + copy(ip, a[:]) + } } if ip != nil && mask != nil { // NetBSD may contain routebsd.LinkAddr ifat = append(ifat, &IPNet{IP: ip, Mask: mask}) diff --git a/src/net/interface_bsdvar.go b/src/net/interface_bsdvar.go index 3946921232778c..dc6c293a8e4b1a 100644 --- a/src/net/interface_bsdvar.go +++ b/src/net/interface_bsdvar.go @@ -12,11 +12,7 @@ import ( ) func interfaceMessages(ifindex int) ([]routebsd.Message, error) { - rib, err := routebsd.FetchRIB(syscall.AF_UNSPEC, syscall.NET_RT_IFLIST, ifindex) - if err != nil { - return nil, err - } - return routebsd.ParseRIB(syscall.NET_RT_IFLIST, rib) + return routebsd.FetchRIBMessages(syscall.NET_RT_IFLIST, ifindex) } // interfaceMulticastAddrTable returns addresses for a specific diff --git a/src/net/interface_darwin.go b/src/net/interface_darwin.go index 45f1363025f7ce..95c44e68e63a1e 100644 --- a/src/net/interface_darwin.go +++ b/src/net/interface_darwin.go @@ -10,21 +10,13 @@ import ( ) func interfaceMessages(ifindex int) ([]routebsd.Message, error) { - rib, err := routebsd.FetchRIB(syscall.AF_UNSPEC, syscall.NET_RT_IFLIST, ifindex) - if err != nil { - return nil, err - } - return routebsd.ParseRIB(syscall.NET_RT_IFLIST, rib) + return routebsd.FetchRIBMessages(syscall.NET_RT_IFLIST, ifindex) } // interfaceMulticastAddrTable returns addresses for a specific // interface. func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) { - rib, err := routebsd.FetchRIB(syscall.AF_UNSPEC, syscall.NET_RT_IFLIST2, ifi.Index) - if err != nil { - return nil, err - } - msgs, err := routebsd.ParseRIB(syscall.NET_RT_IFLIST2, rib) + msgs, err := routebsd.FetchRIBMessages(syscall.NET_RT_IFLIST2, ifi.Index) if err != nil { return nil, err } @@ -37,11 +29,15 @@ func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) { } var ip IP switch sa := m.Addrs[syscall.RTAX_IFA].(type) { - case *routebsd.Inet4Addr: - ip = IPv4(sa.IP[0], sa.IP[1], sa.IP[2], sa.IP[3]) - case *routebsd.Inet6Addr: - ip = make(IP, IPv6len) - copy(ip, sa.IP[:]) + case *routebsd.InetAddr: + if sa.IP.Is4() { + a := sa.IP.As4() + ip = IPv4(a[0], a[1], a[2], a[3]) + } else if sa.IP.Is6() { + a := sa.IP.As16() + ip = make(IP, IPv6len) + copy(ip, a[:]) + } } if ip != nil { ifmat = append(ifmat, &IPAddr{IP: ip}) diff --git a/src/net/interface_freebsd.go b/src/net/interface_freebsd.go index fda7a86a2f36b9..301faa47baef79 100644 --- a/src/net/interface_freebsd.go +++ b/src/net/interface_freebsd.go @@ -10,21 +10,13 @@ import ( ) func interfaceMessages(ifindex int) ([]routebsd.Message, error) { - rib, err := routebsd.FetchRIB(syscall.AF_UNSPEC, routebsd.RIBTypeInterface, ifindex) - if err != nil { - return nil, err - } - return routebsd.ParseRIB(routebsd.RIBTypeInterface, rib) + return routebsd.FetchRIBMessages(syscall.NET_RT_IFLIST, ifindex) } // interfaceMulticastAddrTable returns addresses for a specific // interface. func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) { - rib, err := routebsd.FetchRIB(syscall.AF_UNSPEC, syscall.NET_RT_IFMALIST, ifi.Index) - if err != nil { - return nil, err - } - msgs, err := routebsd.ParseRIB(syscall.NET_RT_IFMALIST, rib) + msgs, err := routebsd.FetchRIBMessages(syscall.NET_RT_IFMALIST, ifi.Index) if err != nil { return nil, err } @@ -37,11 +29,15 @@ func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) { } var ip IP switch sa := m.Addrs[syscall.RTAX_IFA].(type) { - case *routebsd.Inet4Addr: - ip = IPv4(sa.IP[0], sa.IP[1], sa.IP[2], sa.IP[3]) - case *routebsd.Inet6Addr: - ip = make(IP, IPv6len) - copy(ip, sa.IP[:]) + case *routebsd.InetAddr: + if sa.IP.Is4() { + a := sa.IP.As4() + ip = IPv4(a[0], a[1], a[2], a[3]) + } else if sa.IP.Is6() { + a := sa.IP.As16() + ip = make(IP, IPv6len) + copy(ip, a[:]) + } } if ip != nil { ifmat = append(ifmat, &IPAddr{IP: ip}) From 4160ebf28f69a738203571bba6abab6ec0913080 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 9 Jan 2025 13:04:51 -0800 Subject: [PATCH 216/397] net: permit Interface with no Name On darwin the utun interface sometimes has no name. Fixes #71064 Change-Id: Iec51641880515f8bd3f97bd892c26f68fd588fa3 Reviewed-on: https://go-review.googlesource.com/c/go/+/641855 LUCI-TryBot-Result: Go LUCI Auto-Submit: Ian Lance Taylor Reviewed-by: Ian Lance Taylor Commit-Queue: Ian Lance Taylor Reviewed-by: Cherry Mui Reviewed-by: Damien Neil --- src/internal/routebsd/interface_classic.go | 21 +++++++++++++-------- src/net/interface.go | 10 ++++++---- src/net/interface_test.go | 14 ++++++++------ 3 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/internal/routebsd/interface_classic.go b/src/internal/routebsd/interface_classic.go index 7b26c7eb2ad789..af9531c0df7ee7 100644 --- a/src/internal/routebsd/interface_classic.go +++ b/src/internal/routebsd/interface_classic.go @@ -20,9 +20,7 @@ func (w *wireFormat) parseInterfaceMessage(b []byte) (Message, error) { return nil, errInvalidMessage } attrs := uint(nativeEndian.Uint32(b[4:8])) - if attrs&syscall.RTA_IFP == 0 { - return nil, nil - } + m := &InterfaceMessage{ Version: int(b[2]), Type: int(b[3]), @@ -32,12 +30,19 @@ func (w *wireFormat) parseInterfaceMessage(b []byte) (Message, error) { extOff: w.extOff, raw: b[:l], } - a, err := parseLinkAddr(b[w.bodyOff:]) - if err != nil { - return nil, err + + // We used to require that RTA_IFP always be set. + // It turns out that on darwin messages about the + // utun interface may not include a name. Issue #71064. + if attrs&syscall.RTA_IFP != 0 { + a, err := parseLinkAddr(b[w.bodyOff:]) + if err != nil { + return nil, err + } + m.Addrs[syscall.RTAX_IFP] = a + m.Name = a.(*LinkAddr).Name } - m.Addrs[syscall.RTAX_IFP] = a - m.Name = a.(*LinkAddr).Name + return m, nil } diff --git a/src/net/interface.go b/src/net/interface.go index 74bb4f0e1c6122..b6057780c4a98f 100644 --- a/src/net/interface.go +++ b/src/net/interface.go @@ -42,7 +42,7 @@ var ( type Interface struct { Index int // positive integer that starts at one, zero is never used MTU int // maximum transmission unit - Name string // e.g., "en0", "lo0", "eth0.100" + Name string // e.g., "en0", "lo0", "eth0.100"; may be the empty string HardwareAddr HardwareAddr // IEEE MAC-48, EUI-48 and EUI-64 form Flags Flags // e.g., FlagUp, FlagLoopback, FlagMulticast } @@ -221,9 +221,11 @@ func (zc *ipv6ZoneCache) update(ift []Interface, force bool) (updated bool) { zc.toIndex = make(map[string]int, len(ift)) zc.toName = make(map[int]string, len(ift)) for _, ifi := range ift { - zc.toIndex[ifi.Name] = ifi.Index - if _, ok := zc.toName[ifi.Index]; !ok { - zc.toName[ifi.Index] = ifi.Name + if ifi.Name != "" { + zc.toIndex[ifi.Name] = ifi.Index + if _, ok := zc.toName[ifi.Index]; !ok { + zc.toName[ifi.Index] = ifi.Name + } } } return true diff --git a/src/net/interface_test.go b/src/net/interface_test.go index a97d675e7e0bd6..72befca0d89c95 100644 --- a/src/net/interface_test.go +++ b/src/net/interface_test.go @@ -68,12 +68,14 @@ func TestInterfaces(t *testing.T) { t.Errorf("got %v; want %v", ifxi, ifi) } } - ifxn, err := InterfaceByName(ifi.Name) - if err != nil { - t.Fatal(err) - } - if !reflect.DeepEqual(ifxn, &ifi) { - t.Errorf("got %v; want %v", ifxn, ifi) + if ifi.Name != "" { + ifxn, err := InterfaceByName(ifi.Name) + if err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(ifxn, &ifi) { + t.Errorf("got %v; want %v", ifxn, ifi) + } } t.Logf("%s: flags=%v index=%d mtu=%d hwaddr=%v", ifi.Name, ifi.Flags, ifi.Index, ifi.MTU, ifi.HardwareAddr) } From 530c829270bef744b3acae7891a0635874af3fd4 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 17 Jan 2025 09:59:50 -0800 Subject: [PATCH 217/397] syscall: use consistent message for ESTALE on Linux For some reason the ESTALE error message differed on Linux systems. On Linux strerror normally returns "Stale file handle" for ESTALE, except possibly in the en_GB locale. The mkerrors.sh script sets LC_ALL=C, so it should always produces "stale file handle". However, for some reason, several targets use "stale NFS file handle" instead. Clean this up so that we use the same string on all Linux systems. This is also consistent with golang.org/x/sys/unix. Fixes #71309 Change-Id: Ic2ffaf114c85112bc6d0831e43dd5fd2f4237bc2 Reviewed-on: https://go-review.googlesource.com/c/go/+/643335 Auto-Submit: Ian Lance Taylor Commit-Queue: Ian Lance Taylor Reviewed-by: Cherry Mui LUCI-TryBot-Result: Go LUCI Reviewed-by: Ian Lance Taylor Reviewed-by: Tobias Klauser --- src/syscall/zerrors_linux_386.go | 2 +- src/syscall/zerrors_linux_amd64.go | 2 +- src/syscall/zerrors_linux_arm.go | 2 +- src/syscall/zerrors_linux_mips64.go | 2 +- src/syscall/zerrors_linux_mips64le.go | 2 +- src/syscall/zerrors_linux_ppc64.go | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/syscall/zerrors_linux_386.go b/src/syscall/zerrors_linux_386.go index 9d4ecdeb698056..05b621a2cc51d7 100644 --- a/src/syscall/zerrors_linux_386.go +++ b/src/syscall/zerrors_linux_386.go @@ -1467,7 +1467,7 @@ var errors = [...]string{ 113: "no route to host", 114: "operation already in progress", 115: "operation now in progress", - 116: "stale NFS file handle", + 116: "stale file handle", 117: "structure needs cleaning", 118: "not a XENIX named type file", 119: "no XENIX semaphores available", diff --git a/src/syscall/zerrors_linux_amd64.go b/src/syscall/zerrors_linux_amd64.go index a8b67801e6936f..8bc322a707e8a2 100644 --- a/src/syscall/zerrors_linux_amd64.go +++ b/src/syscall/zerrors_linux_amd64.go @@ -1468,7 +1468,7 @@ var errors = [...]string{ 113: "no route to host", 114: "operation already in progress", 115: "operation now in progress", - 116: "stale NFS file handle", + 116: "stale file handle", 117: "structure needs cleaning", 118: "not a XENIX named type file", 119: "no XENIX semaphores available", diff --git a/src/syscall/zerrors_linux_arm.go b/src/syscall/zerrors_linux_arm.go index 285d26a5618e13..ccbea5f287d6be 100644 --- a/src/syscall/zerrors_linux_arm.go +++ b/src/syscall/zerrors_linux_arm.go @@ -1480,7 +1480,7 @@ var errors = [...]string{ 113: "no route to host", 114: "operation already in progress", 115: "operation now in progress", - 116: "stale NFS file handle", + 116: "stale file handle", 117: "structure needs cleaning", 118: "not a XENIX named type file", 119: "no XENIX semaphores available", diff --git a/src/syscall/zerrors_linux_mips64.go b/src/syscall/zerrors_linux_mips64.go index 6953c92484bc6a..7d505c7bb05618 100644 --- a/src/syscall/zerrors_linux_mips64.go +++ b/src/syscall/zerrors_linux_mips64.go @@ -1744,7 +1744,7 @@ var errors = [...]string{ 148: "no route to host", 149: "operation already in progress", 150: "operation now in progress", - 151: "stale NFS file handle", + 151: "stale file handle", 158: "operation canceled", 159: "no medium found", 160: "wrong medium type", diff --git a/src/syscall/zerrors_linux_mips64le.go b/src/syscall/zerrors_linux_mips64le.go index 6953c92484bc6a..7d505c7bb05618 100644 --- a/src/syscall/zerrors_linux_mips64le.go +++ b/src/syscall/zerrors_linux_mips64le.go @@ -1744,7 +1744,7 @@ var errors = [...]string{ 148: "no route to host", 149: "operation already in progress", 150: "operation now in progress", - 151: "stale NFS file handle", + 151: "stale file handle", 158: "operation canceled", 159: "no medium found", 160: "wrong medium type", diff --git a/src/syscall/zerrors_linux_ppc64.go b/src/syscall/zerrors_linux_ppc64.go index f0661a244556c6..fba5353b3e4b16 100644 --- a/src/syscall/zerrors_linux_ppc64.go +++ b/src/syscall/zerrors_linux_ppc64.go @@ -1800,7 +1800,7 @@ var errors = [...]string{ 113: "no route to host", 114: "operation already in progress", 115: "operation now in progress", - 116: "stale NFS file handle", + 116: "stale file handle", 117: "structure needs cleaning", 118: "not a XENIX named type file", 119: "no XENIX semaphores available", From 64eed8ef1d7e9ce832f2d207c6c37484c36d80a6 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 21 Nov 2024 15:53:05 -0800 Subject: [PATCH 218/397] go/parser: refactor parameter parsing (cleanup) Refactor parser.parseParameters to only parse ordinary parameters. Introduce a variant to parse type parameters. In the two places where we need ordinary and type parameters, call the function twice. Also, use a range loop in two places which is a bit easier to read. Change-Id: I0a62e1c508d6ccd16b7cb6e1b852ab1d32224ec2 Reviewed-on: https://go-review.googlesource.com/c/go/+/630816 Auto-Submit: Robert Griesemer TryBot-Bypass: Robert Griesemer Reviewed-by: Robert Findley Reviewed-by: Robert Griesemer Commit-Queue: Robert Griesemer --- src/go/parser/parser.go | 86 ++++++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 39 deletions(-) diff --git a/src/go/parser/parser.go b/src/go/parser/parser.go index 7260e963041871..533ee289beaa16 100644 --- a/src/go/parser/parser.go +++ b/src/go/parser/parser.go @@ -931,7 +931,7 @@ func (p *parser) parseParameterList(name0 *ast.Ident, typ0 ast.Expr, closing tok // distribute parameter types (len(list) > 0) if named == 0 { // all unnamed => found names are type names - for i := 0; i < len(list); i++ { + for i := range list { par := &list[i] if typ := par.name; typ != nil { par.typ = typ @@ -959,8 +959,8 @@ func (p *parser) parseParameterList(name0 *ast.Ident, typ0 ast.Expr, closing tok // some named or we're in a type parameter list => all must be named var errPos token.Pos // left-most error position (or invalid) var typ ast.Expr // current type (from right to left) - for i := len(list) - 1; i >= 0; i-- { - if par := &list[i]; par.typ != nil { + for i := range list { + if par := &list[len(list)-i-1]; par.typ != nil { typ = par.typ if par.name == nil { errPos = typ.Pos() @@ -1042,36 +1042,39 @@ func (p *parser) parseParameterList(name0 *ast.Ident, typ0 ast.Expr, closing tok return } -func (p *parser) parseParameters(acceptTParams bool) (tparams, params *ast.FieldList) { +func (p *parser) parseTypeParameters() *ast.FieldList { if p.trace { - defer un(trace(p, "Parameters")) + defer un(trace(p, "TypeParameters")) } - if acceptTParams && p.tok == token.LBRACK { - opening := p.pos - p.next() - // [T any](params) syntax - list := p.parseParameterList(nil, nil, token.RBRACK) - rbrack := p.expect(token.RBRACK) - tparams = &ast.FieldList{Opening: opening, List: list, Closing: rbrack} - // Type parameter lists must not be empty. - if tparams.NumFields() == 0 { - p.error(tparams.Closing, "empty type parameter list") - tparams = nil // avoid follow-on errors - } + lbrack := p.expect(token.LBRACK) + var list []*ast.Field + if p.tok != token.RBRACK { + list = p.parseParameterList(nil, nil, token.RBRACK) + } + rbrack := p.expect(token.RBRACK) + + if len(list) == 0 { + p.error(rbrack, "empty type parameter list") + return nil // avoid follow-on errors } - opening := p.expect(token.LPAREN) + return &ast.FieldList{Opening: lbrack, List: list, Closing: rbrack} +} - var fields []*ast.Field - if p.tok != token.RPAREN { - fields = p.parseParameterList(nil, nil, token.RPAREN) +func (p *parser) parseParameters() *ast.FieldList { + if p.trace { + defer un(trace(p, "Parameters")) } + lparen := p.expect(token.LPAREN) + var list []*ast.Field + if p.tok != token.RPAREN { + list = p.parseParameterList(nil, nil, token.RPAREN) + } rparen := p.expect(token.RPAREN) - params = &ast.FieldList{Opening: opening, List: fields, Closing: rparen} - return + return &ast.FieldList{Opening: lparen, List: list, Closing: rparen} } func (p *parser) parseResult() *ast.FieldList { @@ -1080,8 +1083,7 @@ func (p *parser) parseResult() *ast.FieldList { } if p.tok == token.LPAREN { - _, results := p.parseParameters(false) - return results + return p.parseParameters() } typ := p.tryIdentOrType() @@ -1100,10 +1102,14 @@ func (p *parser) parseFuncType() *ast.FuncType { } pos := p.expect(token.FUNC) - tparams, params := p.parseParameters(true) - if tparams != nil { - p.error(tparams.Pos(), "function type must have no type parameters") + // accept type parameters for more tolerant parsing but complain + if p.tok == token.LBRACK { + tparams := p.parseTypeParameters() + if tparams != nil { + p.error(tparams.Opening, "function type must have no type parameters") + } } + params := p.parseParameters() results := p.parseResult() return &ast.FuncType{Func: pos, Params: params, Results: results} @@ -1137,7 +1143,7 @@ func (p *parser) parseMethodSpec() *ast.Field { p.error(lbrack, "interface method must have no type parameters") // TODO(rfindley) refactor to share code with parseFuncType. - _, params := p.parseParameters(false) + params := p.parseParameters() results := p.parseResult() idents = []*ast.Ident{ident} typ = &ast.FuncType{ @@ -1167,7 +1173,7 @@ func (p *parser) parseMethodSpec() *ast.Field { case p.tok == token.LPAREN: // ordinary method // TODO(rfindley) refactor to share code with parseFuncType. - _, params := p.parseParameters(false) + params := p.parseParameters() results := p.parseResult() idents = []*ast.Ident{ident} typ = &ast.FuncType{Func: token.NoPos, Params: params, Results: results} @@ -2575,8 +2581,6 @@ func (p *parser) parseGenericType(spec *ast.TypeSpec, openPos token.Pos, name0 * list := p.parseParameterList(name0, typ0, token.RBRACK) closePos := p.expect(token.RBRACK) spec.TypeParams = &ast.FieldList{Opening: openPos, List: list, Closing: closePos} - // Let the type checker decide whether to accept type parameters on aliases: - // see go.dev/issue/46477. if p.tok == token.ASSIGN { // type alias spec.Assign = p.pos @@ -2771,18 +2775,22 @@ func (p *parser) parseFuncDecl() *ast.FuncDecl { var recv *ast.FieldList if p.tok == token.LPAREN { - _, recv = p.parseParameters(false) + recv = p.parseParameters() } ident := p.parseIdent() - tparams, params := p.parseParameters(true) - if recv != nil && tparams != nil { - // Method declarations do not have type parameters. We parse them for a - // better error message and improved error recovery. - p.error(tparams.Opening, "method must have no type parameters") - tparams = nil + var tparams *ast.FieldList + if p.tok == token.LBRACK { + tparams = p.parseTypeParameters() + if recv != nil && tparams != nil { + // Method declarations do not have type parameters. We parse them for a + // better error message and improved error recovery. + p.error(tparams.Opening, "method must have no type parameters") + tparams = nil + } } + params := p.parseParameters() results := p.parseResult() var body *ast.BlockStmt From d96fd2e758d79a60f2c3df46e9b15e9ad084a5cb Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 3 Feb 2025 13:45:27 -0800 Subject: [PATCH 219/397] cmd/go: update new test for removal of nocoverageredesign The new test was committed after the removal was tested. For #51430 For #65570 For #70244 Change-Id: I5f94c36a68ea96ba76d018dc06a5a233ad684aa5 Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest Reviewed-on: https://go-review.googlesource.com/c/go/+/646355 Reviewed-by: Ian Lance Taylor TryBot-Bypass: Ian Lance Taylor Reviewed-by: Robert Griesemer Auto-Submit: Ian Lance Taylor --- .../go/testdata/script/cover_coverprofile_nocoverpkg.txt | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/cmd/go/testdata/script/cover_coverprofile_nocoverpkg.txt b/src/cmd/go/testdata/script/cover_coverprofile_nocoverpkg.txt index 85b3136bf994f6..f077734045c9c7 100644 --- a/src/cmd/go/testdata/script/cover_coverprofile_nocoverpkg.txt +++ b/src/cmd/go/testdata/script/cover_coverprofile_nocoverpkg.txt @@ -13,13 +13,7 @@ go test -vet=off -count=1 -coverprofile=cov.p ./... # Generate a function profile. go tool cover -func=cov.p -# Prior to GOEXPERIMENT=coverageredesign we should see no output at all for -# pkg1 (since it has no tests). -[!GOEXPERIMENT:coverageredesign] ! stdout 'pkg1' - -# With GOEXPERIMENT=coverageredesign enabled we should see zero percent -# coverage for pkg1's DoSomething, not 100% (as in the bug). -[GOEXPERIMENT:coverageredesign] stdout 'cov/pkg1/file.go:3:\s+DoSomething\s+0.0%' +stdout 'cov/pkg1/file.go:3:\s+DoSomething\s+0.0%' -- go.mod -- module cov From ad7b46ee4ac1cee5095d64b01e8cf7fcda8bee5e Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Mon, 25 Nov 2024 13:08:34 -0800 Subject: [PATCH 220/397] go/parser, go/types, syntax, types2: report invalid uses of ... by parsers Check correct use of ...'s in parameter lists in parsers. This allows the type checkers to assume correct ASTs with respect to ... use. Adjust some error messages: if a ... is used in a result parameter list, the error is now more accurate. Eliminate a now unused error code. Change-Id: I66058e114e84805e24c59e570604b607ef5ff1fe Reviewed-on: https://go-review.googlesource.com/c/go/+/631135 Reviewed-by: Robert Griesemer Reviewed-by: Ian Lance Taylor TryBot-Bypass: Robert Griesemer Auto-Submit: Robert Griesemer --- src/cmd/compile/internal/syntax/parser.go | 36 ++++++--- src/cmd/compile/internal/types2/expr.go | 5 +- src/cmd/compile/internal/types2/signature.go | 2 +- src/cmd/compile/internal/types2/typexpr.go | 6 +- src/go/parser/parser.go | 76 +++++++++++-------- src/go/parser/short_test.go | 8 ++ src/go/types/expr.go | 5 +- src/go/types/signature.go | 2 +- src/go/types/typexpr.go | 6 +- src/internal/types/errors/code_string.go | 7 +- src/internal/types/errors/codes.go | 5 +- src/internal/types/testdata/check/issues0.go | 6 +- src/internal/types/testdata/examples/types.go | 2 +- 13 files changed, 96 insertions(+), 70 deletions(-) diff --git a/src/cmd/compile/internal/syntax/parser.go b/src/cmd/compile/internal/syntax/parser.go index 14a737c414988e..82786859435b97 100644 --- a/src/cmd/compile/internal/syntax/parser.go +++ b/src/cmd/compile/internal/syntax/parser.go @@ -650,7 +650,7 @@ func (p *parser) typeDecl(group *Group) Decl { // d.Name "[" pname ... // d.Name "[" pname ptype ... // d.Name "[" pname ptype "," ... - d.TParamList = p.paramList(pname, ptype, _Rbrack, true) // ptype may be nil + d.TParamList = p.paramList(pname, ptype, _Rbrack, true, false) // ptype may be nil d.Alias = p.gotAssign() d.Type = p.typeOrNil() } else { @@ -800,7 +800,7 @@ func (p *parser) funcDeclOrNil() *FuncDecl { var context string if p.got(_Lparen) { context = "method" - rcvr := p.paramList(nil, nil, _Rparen, false) + rcvr := p.paramList(nil, nil, _Rparen, false, false) switch len(rcvr) { case 0: p.error("method has no receiver") @@ -1469,12 +1469,12 @@ func (p *parser) funcType(context string) ([]*Field, *FuncType) { p.syntaxError("empty type parameter list") p.next() } else { - tparamList = p.paramList(nil, nil, _Rbrack, true) + tparamList = p.paramList(nil, nil, _Rbrack, true, false) } } p.want(_Lparen) - typ.ParamList = p.paramList(nil, nil, _Rparen, false) + typ.ParamList = p.paramList(nil, nil, _Rparen, false, true) typ.ResultList = p.funcResult() return tparamList, typ @@ -1582,7 +1582,7 @@ func (p *parser) funcResult() []*Field { } if p.got(_Lparen) { - return p.paramList(nil, nil, _Rparen, false) + return p.paramList(nil, nil, _Rparen, false, false) } pos := p.pos() @@ -1793,7 +1793,7 @@ func (p *parser) methodDecl() *Field { // A type argument list looks like a parameter list with only // types. Parse a parameter list and decide afterwards. - list := p.paramList(nil, nil, _Rbrack, false) + list := p.paramList(nil, nil, _Rbrack, false, false) if len(list) == 0 { // The type parameter list is not [] but we got nothing // due to other errors (reported by paramList). Treat @@ -1962,10 +1962,11 @@ func (p *parser) paramDeclOrNil(name *Name, follow token) *Field { p.next() t.Elem = p.typeOrNil() if t.Elem == nil { - t.Elem = p.badExpr() + f.Type = p.badExpr() p.syntaxError("... is missing type") + } else { + f.Type = t } - f.Type = t return f } @@ -1995,7 +1996,7 @@ func (p *parser) paramDeclOrNil(name *Name, follow token) *Field { // If name != nil, it is the first name after "(" or "[". // If typ != nil, name must be != nil, and (name, typ) is the first field in the list. // In the result list, either all fields have a name, or no field has a name. -func (p *parser) paramList(name *Name, typ Expr, close token, requireNames bool) (list []*Field) { +func (p *parser) paramList(name *Name, typ Expr, close token, requireNames, dddok bool) (list []*Field) { if trace { defer p.trace("paramList")() } @@ -2109,6 +2110,23 @@ func (p *parser) paramList(name *Name, typ Expr, close token, requireNames bool) } } + // check use of ... + first := true // only report first occurrence + for i, f := range list { + if t, _ := f.Type.(*DotsType); t != nil && (!dddok || i+1 < len(list)) { + if first { + first = false + if dddok { + p.errorAt(t.pos, "can only use ... with final parameter") + } else { + p.errorAt(t.pos, "invalid use of ...") + } + } + // use T instead of invalid ...T + f.Type = t.Elem + } + } + return } diff --git a/src/cmd/compile/internal/types2/expr.go b/src/cmd/compile/internal/types2/expr.go index 2bf42d1c6f1494..28a5d788724a90 100644 --- a/src/cmd/compile/internal/types2/expr.go +++ b/src/cmd/compile/internal/types2/expr.go @@ -1016,9 +1016,8 @@ func (check *Checker) exprInternal(T *target, x *operand, e syntax.Expr, hint Ty check.ident(x, e, nil, false) case *syntax.DotsType: - // dots are handled explicitly where they are legal - // (array composite literals and parameter lists) - check.error(e, BadDotDotDotSyntax, "invalid use of '...'") + // dots are handled explicitly where they are valid + check.error(e, InvalidSyntaxTree, "invalid use of ...") goto Error case *syntax.BasicLit: diff --git a/src/cmd/compile/internal/types2/signature.go b/src/cmd/compile/internal/types2/signature.go index de4f1eaa207fdc..622eb1383da000 100644 --- a/src/cmd/compile/internal/types2/signature.go +++ b/src/cmd/compile/internal/types2/signature.go @@ -344,7 +344,7 @@ func (check *Checker) collectParams(list []*syntax.Field, variadicOk bool) (name if variadicOk && i == len(list)-1 { variadic = true } else { - check.softErrorf(t, MisplacedDotDotDot, "can only use ... with final parameter in list") + check.error(t, InvalidSyntaxTree, "invalid use of ...") // ignore ... and continue } } diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go index e9b5ca9aa6c329..0964c53fe05815 100644 --- a/src/cmd/compile/internal/types2/typexpr.go +++ b/src/cmd/compile/internal/types2/typexpr.go @@ -321,10 +321,8 @@ func (check *Checker) typInternal(e0 syntax.Expr, def *TypeName) (T Type) { return typ case *syntax.DotsType: - // dots are handled explicitly where they are legal - // (array composite literals and parameter lists) - check.error(e, InvalidDotDotDot, "invalid use of '...'") - check.use(e.Elem) + // dots are handled explicitly where they are valid + check.error(e, InvalidSyntaxTree, "invalid use of ...") case *syntax.StructType: typ := new(Struct) diff --git a/src/go/parser/parser.go b/src/go/parser/parser.go index 533ee289beaa16..c2906c5bda8a38 100644 --- a/src/go/parser/parser.go +++ b/src/go/parser/parser.go @@ -872,7 +872,7 @@ func (p *parser) parseParamDecl(name *ast.Ident, typeSetsOK bool) (f field) { return } -func (p *parser) parseParameterList(name0 *ast.Ident, typ0 ast.Expr, closing token.Token) (params []*ast.Field) { +func (p *parser) parseParameterList(name0 *ast.Ident, typ0 ast.Expr, closing token.Token, dddok bool) (params []*ast.Field) { if p.trace { defer un(trace(p, "ParameterList")) } @@ -1006,6 +1006,26 @@ func (p *parser) parseParameterList(name0 *ast.Ident, typ0 ast.Expr, closing tok } } + // check use of ... + first := true // only report first occurrence + for i, _ := range list { + f := &list[i] + if t, _ := f.typ.(*ast.Ellipsis); t != nil && (!dddok || i+1 < len(list)) { + if first { + first = false + if dddok { + p.error(t.Ellipsis, "can only use ... with final parameter") + } else { + p.error(t.Ellipsis, "invalid use of ...") + } + } + // use T instead of invalid ...T + // TODO(gri) would like to use `f.typ = t.Elt` but that causes problems + // with the resolver in cases of reuse of the same identifier + f.typ = &ast.BadExpr{From: t.Pos(), To: t.End()} + } + } + // Convert list to []*ast.Field. // If list contains types only, each type gets its own ast.Field. if named == 0 { @@ -1050,7 +1070,7 @@ func (p *parser) parseTypeParameters() *ast.FieldList { lbrack := p.expect(token.LBRACK) var list []*ast.Field if p.tok != token.RBRACK { - list = p.parseParameterList(nil, nil, token.RBRACK) + list = p.parseParameterList(nil, nil, token.RBRACK, false) } rbrack := p.expect(token.RBRACK) @@ -1062,32 +1082,22 @@ func (p *parser) parseTypeParameters() *ast.FieldList { return &ast.FieldList{Opening: lbrack, List: list, Closing: rbrack} } -func (p *parser) parseParameters() *ast.FieldList { +func (p *parser) parseParameters(result bool) *ast.FieldList { if p.trace { defer un(trace(p, "Parameters")) } - lparen := p.expect(token.LPAREN) - var list []*ast.Field - if p.tok != token.RPAREN { - list = p.parseParameterList(nil, nil, token.RPAREN) - } - rparen := p.expect(token.RPAREN) - - return &ast.FieldList{Opening: lparen, List: list, Closing: rparen} -} - -func (p *parser) parseResult() *ast.FieldList { - if p.trace { - defer un(trace(p, "Result")) - } - - if p.tok == token.LPAREN { - return p.parseParameters() + if !result || p.tok == token.LPAREN { + lparen := p.expect(token.LPAREN) + var list []*ast.Field + if p.tok != token.RPAREN { + list = p.parseParameterList(nil, nil, token.RPAREN, !result) + } + rparen := p.expect(token.RPAREN) + return &ast.FieldList{Opening: lparen, List: list, Closing: rparen} } - typ := p.tryIdentOrType() - if typ != nil { + if typ := p.tryIdentOrType(); typ != nil { list := make([]*ast.Field, 1) list[0] = &ast.Field{Type: typ} return &ast.FieldList{List: list} @@ -1109,8 +1119,8 @@ func (p *parser) parseFuncType() *ast.FuncType { p.error(tparams.Opening, "function type must have no type parameters") } } - params := p.parseParameters() - results := p.parseResult() + params := p.parseParameters(false) + results := p.parseParameters(true) return &ast.FuncType{Func: pos, Params: params, Results: results} } @@ -1138,13 +1148,13 @@ func (p *parser) parseMethodSpec() *ast.Field { // // Interface methods do not have type parameters. We parse them for a // better error message and improved error recovery. - _ = p.parseParameterList(name0, nil, token.RBRACK) + _ = p.parseParameterList(name0, nil, token.RBRACK, false) _ = p.expect(token.RBRACK) p.error(lbrack, "interface method must have no type parameters") // TODO(rfindley) refactor to share code with parseFuncType. - params := p.parseParameters() - results := p.parseResult() + params := p.parseParameters(false) + results := p.parseParameters(true) idents = []*ast.Ident{ident} typ = &ast.FuncType{ Func: token.NoPos, @@ -1173,8 +1183,8 @@ func (p *parser) parseMethodSpec() *ast.Field { case p.tok == token.LPAREN: // ordinary method // TODO(rfindley) refactor to share code with parseFuncType. - params := p.parseParameters() - results := p.parseResult() + params := p.parseParameters(false) + results := p.parseParameters(true) idents = []*ast.Ident{ident} typ = &ast.FuncType{Func: token.NoPos, Params: params, Results: results} default: @@ -2578,7 +2588,7 @@ func (p *parser) parseGenericType(spec *ast.TypeSpec, openPos token.Pos, name0 * defer un(trace(p, "parseGenericType")) } - list := p.parseParameterList(name0, typ0, token.RBRACK) + list := p.parseParameterList(name0, typ0, token.RBRACK, false) closePos := p.expect(token.RBRACK) spec.TypeParams = &ast.FieldList{Opening: openPos, List: list, Closing: closePos} if p.tok == token.ASSIGN { @@ -2775,7 +2785,7 @@ func (p *parser) parseFuncDecl() *ast.FuncDecl { var recv *ast.FieldList if p.tok == token.LPAREN { - recv = p.parseParameters() + recv = p.parseParameters(false) } ident := p.parseIdent() @@ -2790,8 +2800,8 @@ func (p *parser) parseFuncDecl() *ast.FuncDecl { tparams = nil } } - params := p.parseParameters() - results := p.parseResult() + params := p.parseParameters(false) + results := p.parseParameters(true) var body *ast.BlockStmt switch p.tok { diff --git a/src/go/parser/short_test.go b/src/go/parser/short_test.go index 3a34e8c216bf96..9465fe0e478c55 100644 --- a/src/go/parser/short_test.go +++ b/src/go/parser/short_test.go @@ -190,6 +190,14 @@ var invalids = []string{ `package p; func f() { if true {} else ; /* ERROR "expected if statement or block" */ }`, `package p; func f() { if true {} else defer /* ERROR "expected if statement or block" */ f() }`, + // variadic parameter lists + `package p; func f(a, b ... /* ERROR "can only use ... with final parameter" */ int)`, + `package p; func f(a ... /* ERROR "can only use ... with final parameter" */ int, b int)`, + `package p; func f(... /* ERROR "can only use ... with final parameter" */ int, int)`, + `package p; func f() (... /* ERROR "invalid use of ..." */ int)`, + `package p; func f() (a, b ... /* ERROR "invalid use of ..." */ int)`, + `package p; func f[T ... /* ERROR "invalid use of ..." */ C]()() {}`, + // generic code `package p; type _[_ any] int; var _ = T[] /* ERROR "expected operand" */ {}`, `package p; var _ func[ /* ERROR "must have no type parameters" */ T any](T)`, diff --git a/src/go/types/expr.go b/src/go/types/expr.go index d4a08927015ac9..e2e8928a12391e 100644 --- a/src/go/types/expr.go +++ b/src/go/types/expr.go @@ -1006,9 +1006,8 @@ func (check *Checker) exprInternal(T *target, x *operand, e ast.Expr, hint Type) check.ident(x, e, nil, false) case *ast.Ellipsis: - // ellipses are handled explicitly where they are legal - // (array composite literals and parameter lists) - check.error(e, BadDotDotDotSyntax, "invalid use of '...'") + // ellipses are handled explicitly where they are valid + check.error(e, InvalidSyntaxTree, "invalid use of ...") goto Error case *ast.BasicLit: diff --git a/src/go/types/signature.go b/src/go/types/signature.go index ff405318ee4ca8..1738384febcc00 100644 --- a/src/go/types/signature.go +++ b/src/go/types/signature.go @@ -364,7 +364,7 @@ func (check *Checker) collectParams(list *ast.FieldList, variadicOk bool) (names if variadicOk && i == len(list.List)-1 && len(field.Names) <= 1 { variadic = true } else { - check.softErrorf(t, MisplacedDotDotDot, "can only use ... with final parameter in list") + check.softErrorf(t, InvalidSyntaxTree, "invalid use of ...") // ignore ... and continue } } diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index 7928ed8ef368de..549a84b3cc700c 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -322,10 +322,8 @@ func (check *Checker) typInternal(e0 ast.Expr, def *TypeName) (T Type) { // report error if we encountered [...] case *ast.Ellipsis: - // dots are handled explicitly where they are legal - // (array composite literals and parameter lists) - check.error(e, InvalidDotDotDot, "invalid use of '...'") - check.use(e.Elt) + // dots are handled explicitly where they are valid + check.error(e, InvalidSyntaxTree, "invalid use of ...") case *ast.StructType: typ := new(Struct) diff --git a/src/internal/types/errors/code_string.go b/src/internal/types/errors/code_string.go index 9ae675ef849d87..26d7b48ee78a63 100644 --- a/src/internal/types/errors/code_string.go +++ b/src/internal/types/errors/code_string.go @@ -86,7 +86,6 @@ func _() { _ = x[MissingFieldOrMethod-76] _ = x[BadDotDotDotSyntax-77] _ = x[NonVariadicDotDotDot-78] - _ = x[MisplacedDotDotDot-79] _ = x[InvalidDotDotDot-81] _ = x[UncalledBuiltin-82] _ = x[InvalidAppend-83] @@ -161,7 +160,7 @@ func _() { const ( _Code_name_0 = "InvalidSyntaxTree" _Code_name_1 = "TestBlankPkgNameMismatchedPkgNameInvalidPkgUseBadImportPathBrokenImportImportCRenamedUnusedImportInvalidInitCycleDuplicateDeclInvalidDeclCycleInvalidTypeCycleInvalidConstInitInvalidConstValInvalidConstTypeUntypedNilUseWrongAssignCountUnassignableOperandNoNewVarMultiValAssignOpInvalidIfaceAssignInvalidChanAssignIncompatibleAssignUnaddressableFieldAssignNotATypeInvalidArrayLenBlankIfaceMethodIncomparableMapKey" - _Code_name_2 = "InvalidPtrEmbedBadRecvInvalidRecvDuplicateFieldAndMethodDuplicateMethodInvalidBlankInvalidIotaMissingInitBodyInvalidInitSigInvalidInitDeclInvalidMainDeclTooManyValuesNotAnExprTruncatedFloatNumericOverflowUndefinedOpMismatchedTypesDivByZeroNonNumericIncDecUnaddressableOperandInvalidIndirectionNonIndexableOperandInvalidIndexSwappedSliceIndicesNonSliceableOperandInvalidSliceExprInvalidShiftCountInvalidShiftOperandInvalidReceiveInvalidSendDuplicateLitKeyMissingLitKeyInvalidLitIndexOversizeArrayLitMixedStructLitInvalidStructLitMissingLitFieldDuplicateLitFieldUnexportedLitFieldInvalidLitFieldUntypedLitInvalidLitAmbiguousSelectorUndeclaredImportedNameUnexportedNameUndeclaredNameMissingFieldOrMethodBadDotDotDotSyntaxNonVariadicDotDotDotMisplacedDotDotDot" + _Code_name_2 = "InvalidPtrEmbedBadRecvInvalidRecvDuplicateFieldAndMethodDuplicateMethodInvalidBlankInvalidIotaMissingInitBodyInvalidInitSigInvalidInitDeclInvalidMainDeclTooManyValuesNotAnExprTruncatedFloatNumericOverflowUndefinedOpMismatchedTypesDivByZeroNonNumericIncDecUnaddressableOperandInvalidIndirectionNonIndexableOperandInvalidIndexSwappedSliceIndicesNonSliceableOperandInvalidSliceExprInvalidShiftCountInvalidShiftOperandInvalidReceiveInvalidSendDuplicateLitKeyMissingLitKeyInvalidLitIndexOversizeArrayLitMixedStructLitInvalidStructLitMissingLitFieldDuplicateLitFieldUnexportedLitFieldInvalidLitFieldUntypedLitInvalidLitAmbiguousSelectorUndeclaredImportedNameUnexportedNameUndeclaredNameMissingFieldOrMethodBadDotDotDotSyntaxNonVariadicDotDotDot" _Code_name_3 = "InvalidDotDotDotUncalledBuiltinInvalidAppendInvalidCapInvalidCloseInvalidCopyInvalidComplexInvalidDeleteInvalidImagInvalidLenSwappedMakeArgsInvalidMakeInvalidRealInvalidAssertImpossibleAssertInvalidConversionInvalidUntypedConversionBadOffsetofSyntaxInvalidOffsetofUnusedExprUnusedVarMissingReturnWrongResultCountOutOfScopeResultInvalidCondInvalidPostDecl" _Code_name_4 = "InvalidIterVarInvalidRangeExprMisplacedBreakMisplacedContinueMisplacedFallthroughDuplicateCaseDuplicateDefaultBadTypeKeywordInvalidTypeSwitchInvalidExprSwitchInvalidSelectCaseUndeclaredLabelDuplicateLabelMisplacedLabelUnusedLabelJumpOverDeclJumpIntoBlockInvalidMethodExprWrongArgCountInvalidCallUnusedResultsInvalidDeferInvalidGoBadDeclRepeatedDeclInvalidUnsafeAddInvalidUnsafeSliceUnsupportedFeatureNotAGenericTypeWrongTypeArgCountCannotInferTypeArgsInvalidTypeArgInvalidInstanceCycleInvalidUnionMisplacedConstraintIfaceInvalidMethodTypeParamsMisplacedTypeParamInvalidUnsafeSliceDataInvalidUnsafeString" _Code_name_5 = "InvalidClearTypeTooLargeInvalidMinMaxOperandTooNew" @@ -169,7 +168,7 @@ const ( var ( _Code_index_1 = [...]uint16{0, 4, 16, 33, 46, 59, 71, 85, 97, 113, 126, 142, 158, 174, 189, 205, 218, 234, 253, 261, 277, 295, 312, 330, 354, 362, 377, 393, 411} - _Code_index_2 = [...]uint16{0, 15, 22, 33, 56, 71, 83, 94, 109, 123, 138, 153, 166, 175, 189, 204, 215, 230, 239, 255, 275, 293, 312, 324, 343, 362, 378, 395, 414, 428, 439, 454, 467, 482, 498, 512, 528, 543, 560, 578, 593, 603, 613, 630, 652, 666, 680, 700, 718, 738, 756} + _Code_index_2 = [...]uint16{0, 15, 22, 33, 56, 71, 83, 94, 109, 123, 138, 153, 166, 175, 189, 204, 215, 230, 239, 255, 275, 293, 312, 324, 343, 362, 378, 395, 414, 428, 439, 454, 467, 482, 498, 512, 528, 543, 560, 578, 593, 603, 613, 630, 652, 666, 680, 700, 718, 738} _Code_index_3 = [...]uint16{0, 16, 31, 44, 54, 66, 77, 91, 104, 115, 125, 140, 151, 162, 175, 191, 208, 232, 249, 264, 274, 283, 296, 312, 328, 339, 354} _Code_index_4 = [...]uint16{0, 14, 30, 44, 61, 81, 94, 110, 124, 141, 158, 175, 190, 204, 218, 229, 241, 254, 271, 284, 295, 308, 320, 329, 336, 348, 364, 382, 400, 415, 432, 451, 465, 485, 497, 521, 544, 562, 584, 603} _Code_index_5 = [...]uint8{0, 12, 24, 44, 50} @@ -182,7 +181,7 @@ func (i Code) String() string { case 1 <= i && i <= 28: i -= 1 return _Code_name_1[_Code_index_1[i]:_Code_index_1[i+1]] - case 30 <= i && i <= 79: + case 30 <= i && i <= 78: i -= 30 return _Code_name_2[_Code_index_2[i]:_Code_index_2[i+1]] case 81 <= i && i <= 106: diff --git a/src/internal/types/errors/codes.go b/src/internal/types/errors/codes.go index c0e6aa6c2daf52..f8c9eb920f5840 100644 --- a/src/internal/types/errors/codes.go +++ b/src/internal/types/errors/codes.go @@ -719,10 +719,7 @@ const ( // MisplacedDotDotDot occurs when a "..." is used somewhere other than the // final argument in a function declaration. - // - // Example: - // func f(...int, int) - MisplacedDotDotDot + _ // not used anymore (error reported by parser) _ // InvalidDotDotDotOperand was removed. diff --git a/src/internal/types/testdata/check/issues0.go b/src/internal/types/testdata/check/issues0.go index 44a709d66ea822..2b59a9c9b5c88a 100644 --- a/src/internal/types/testdata/check/issues0.go +++ b/src/internal/types/testdata/check/issues0.go @@ -326,9 +326,9 @@ func issue28281b(a, b int, c ...int) func issue28281c(a, b, c ... /* ERROR "can only use ... with final parameter" */ int) func issue28281d(... /* ERROR "can only use ... with final parameter" */ int, int) func issue28281e(a, b, c ... /* ERROR "can only use ... with final parameter" */ int, d int) -func issue28281f(... /* ERROR "can only use ... with final parameter" */ int, ... /* ERROR "can only use ... with final parameter" */ int, int) -func (... /* ERROR "invalid use of '...'" */ TT) f() -func issue28281g() (... /* ERROR "can only use ... with final parameter" */ TT) +func issue28281f(... /* ERROR "can only use ... with final parameter" */ int, ... int, int) +func (... /* ERROR "invalid use of ..." */ TT) f() +func issue28281g() (... /* ERROR "invalid use of ..." */ TT) // Issue #26234: Make various field/method lookup errors easier to read by matching cmd/compile's output func issue26234a(f *syn.Prog) { diff --git a/src/internal/types/testdata/examples/types.go b/src/internal/types/testdata/examples/types.go index 67f1534be39479..d6da2c5f6f9f9f 100644 --- a/src/internal/types/testdata/examples/types.go +++ b/src/internal/types/testdata/examples/types.go @@ -114,7 +114,7 @@ type I1[T any] interface{ } // There is no such thing as a variadic generic type. -type _[T ... /* ERROR "invalid use of '...'" */ any] struct{} +type _[T ... /* ERROR "invalid use of ..." */ any] struct{} // Generic interfaces may be embedded as one would expect. type I2 interface { From b07b20fbb591ac77158e1089299ce5acad71ffde Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 30 Jan 2025 15:21:55 -0800 Subject: [PATCH 221/397] spec: remove reference to Go 1.17 spec Also, delete go1.17_spec.html. Change-Id: I7c78029dcfbbe8dbabb4ca81052976c1c8f4ed9a Reviewed-on: https://go-review.googlesource.com/c/go/+/645717 Auto-Submit: Robert Griesemer Reviewed-by: Ian Lance Taylor Reviewed-by: Robert Griesemer TryBot-Bypass: Robert Griesemer --- doc/go1.17_spec.html | 6864 ------------------------------------------ doc/go_spec.html | 4 +- 2 files changed, 1 insertion(+), 6867 deletions(-) delete mode 100644 doc/go1.17_spec.html diff --git a/doc/go1.17_spec.html b/doc/go1.17_spec.html deleted file mode 100644 index dbff3598b5838b..00000000000000 --- a/doc/go1.17_spec.html +++ /dev/null @@ -1,6864 +0,0 @@ - - -

    Introduction

    - -

    -This is the reference manual for the Go programming language as it was for -language version 1.17, in October 2021, before the introduction of generics. -It is provided for historical interest. -The current reference manual can be found here. -For more information and other documents, see go.dev. -

    - -

    -Go is a general-purpose language designed with systems programming -in mind. It is strongly typed and garbage-collected and has explicit -support for concurrent programming. Programs are constructed from -packages, whose properties allow efficient management of -dependencies. -

    - -

    -The grammar is compact and simple to parse, allowing for easy analysis -by automatic tools such as integrated development environments. -

    - -

    Notation

    -

    -The syntax is specified using Extended Backus-Naur Form (EBNF): -

    - -
    -Production  = production_name "=" [ Expression ] "." .
    -Expression  = Alternative { "|" Alternative } .
    -Alternative = Term { Term } .
    -Term        = production_name | token [ "…" token ] | Group | Option | Repetition .
    -Group       = "(" Expression ")" .
    -Option      = "[" Expression "]" .
    -Repetition  = "{" Expression "}" .
    -
    - -

    -Productions are expressions constructed from terms and the following -operators, in increasing precedence: -

    -
    -|   alternation
    -()  grouping
    -[]  option (0 or 1 times)
    -{}  repetition (0 to n times)
    -
    - -

    -Lower-case production names are used to identify lexical tokens. -Non-terminals are in CamelCase. Lexical tokens are enclosed in -double quotes "" or back quotes ``. -

    - -

    -The form a … b represents the set of characters from -a through b as alternatives. The horizontal -ellipsis is also used elsewhere in the spec to informally denote various -enumerations or code snippets that are not further specified. The character -(as opposed to the three characters ...) is not a token of the Go -language. -

    - -

    Source code representation

    - -

    -Source code is Unicode text encoded in -UTF-8. The text is not -canonicalized, so a single accented code point is distinct from the -same character constructed from combining an accent and a letter; -those are treated as two code points. For simplicity, this document -will use the unqualified term character to refer to a Unicode code point -in the source text. -

    -

    -Each code point is distinct; for instance, upper and lower case letters -are different characters. -

    -

    -Implementation restriction: For compatibility with other tools, a -compiler may disallow the NUL character (U+0000) in the source text. -

    -

    -Implementation restriction: For compatibility with other tools, a -compiler may ignore a UTF-8-encoded byte order mark -(U+FEFF) if it is the first Unicode code point in the source text. -A byte order mark may be disallowed anywhere else in the source. -

    - -

    Characters

    - -

    -The following terms are used to denote specific Unicode character classes: -

    -
    -newline        = /* the Unicode code point U+000A */ .
    -unicode_char   = /* an arbitrary Unicode code point except newline */ .
    -unicode_letter = /* a Unicode code point classified as "Letter" */ .
    -unicode_digit  = /* a Unicode code point classified as "Number, decimal digit" */ .
    -
    - -

    -In The Unicode Standard 8.0, -Section 4.5 "General Category" defines a set of character categories. -Go treats all characters in any of the Letter categories Lu, Ll, Lt, Lm, or Lo -as Unicode letters, and those in the Number category Nd as Unicode digits. -

    - -

    Letters and digits

    - -

    -The underscore character _ (U+005F) is considered a letter. -

    -
    -letter        = unicode_letter | "_" .
    -decimal_digit = "0" … "9" .
    -binary_digit  = "0" | "1" .
    -octal_digit   = "0" … "7" .
    -hex_digit     = "0" … "9" | "A" … "F" | "a" … "f" .
    -
    - -

    Lexical elements

    - -

    Comments

    - -

    -Comments serve as program documentation. There are two forms: -

    - -
      -
    1. -Line comments start with the character sequence // -and stop at the end of the line. -
    2. -
    3. -General comments start with the character sequence /* -and stop with the first subsequent character sequence */. -
    4. -
    - -

    -A comment cannot start inside a rune or -string literal, or inside a comment. -A general comment containing no newlines acts like a space. -Any other comment acts like a newline. -

    - -

    Tokens

    - -

    -Tokens form the vocabulary of the Go language. -There are four classes: identifiers, keywords, operators -and punctuation, and literals. White space, formed from -spaces (U+0020), horizontal tabs (U+0009), -carriage returns (U+000D), and newlines (U+000A), -is ignored except as it separates tokens -that would otherwise combine into a single token. Also, a newline or end of file -may trigger the insertion of a semicolon. -While breaking the input into tokens, -the next token is the longest sequence of characters that form a -valid token. -

    - -

    Semicolons

    - -

    -The formal grammar uses semicolons ";" as terminators in -a number of productions. Go programs may omit most of these semicolons -using the following two rules: -

    - -
      -
    1. -When the input is broken into tokens, a semicolon is automatically inserted -into the token stream immediately after a line's final token if that token is - -
    2. - -
    3. -To allow complex statements to occupy a single line, a semicolon -may be omitted before a closing ")" or "}". -
    4. -
    - -

    -To reflect idiomatic use, code examples in this document elide semicolons -using these rules. -

    - - -

    Identifiers

    - -

    -Identifiers name program entities such as variables and types. -An identifier is a sequence of one or more letters and digits. -The first character in an identifier must be a letter. -

    -
    -identifier = letter { letter | unicode_digit } .
    -
    -
    -a
    -_x9
    -ThisVariableIsExported
    -αβ
    -
    - -

    -Some identifiers are predeclared. -

    - - -

    Keywords

    - -

    -The following keywords are reserved and may not be used as identifiers. -

    -
    -break        default      func         interface    select
    -case         defer        go           map          struct
    -chan         else         goto         package      switch
    -const        fallthrough  if           range        type
    -continue     for          import       return       var
    -
    - -

    Operators and punctuation

    - -

    -The following character sequences represent operators -(including assignment operators) and punctuation: -

    -
    -+    &     +=    &=     &&    ==    !=    (    )
    --    |     -=    |=     ||    <     <=    [    ]
    -*    ^     *=    ^=     <-    >     >=    {    }
    -/    <<    /=    <<=    ++    =     :=    ,    ;
    -%    >>    %=    >>=    --    !     ...   .    :
    -     &^          &^=
    -
    - -

    Integer literals

    - -

    -An integer literal is a sequence of digits representing an -integer constant. -An optional prefix sets a non-decimal base: 0b or 0B -for binary, 0, 0o, or 0O for octal, -and 0x or 0X for hexadecimal. -A single 0 is considered a decimal zero. -In hexadecimal literals, letters a through f -and A through F represent values 10 through 15. -

    - -

    -For readability, an underscore character _ may appear after -a base prefix or between successive digits; such underscores do not change -the literal's value. -

    -
    -int_lit        = decimal_lit | binary_lit | octal_lit | hex_lit .
    -decimal_lit    = "0" | ( "1" … "9" ) [ [ "_" ] decimal_digits ] .
    -binary_lit     = "0" ( "b" | "B" ) [ "_" ] binary_digits .
    -octal_lit      = "0" [ "o" | "O" ] [ "_" ] octal_digits .
    -hex_lit        = "0" ( "x" | "X" ) [ "_" ] hex_digits .
    -
    -decimal_digits = decimal_digit { [ "_" ] decimal_digit } .
    -binary_digits  = binary_digit { [ "_" ] binary_digit } .
    -octal_digits   = octal_digit { [ "_" ] octal_digit } .
    -hex_digits     = hex_digit { [ "_" ] hex_digit } .
    -
    - -
    -42
    -4_2
    -0600
    -0_600
    -0o600
    -0O600       // second character is capital letter 'O'
    -0xBadFace
    -0xBad_Face
    -0x_67_7a_2f_cc_40_c6
    -170141183460469231731687303715884105727
    -170_141183_460469_231731_687303_715884_105727
    -
    -_42         // an identifier, not an integer literal
    -42_         // invalid: _ must separate successive digits
    -4__2        // invalid: only one _ at a time
    -0_xBadFace  // invalid: _ must separate successive digits
    -
    - - -

    Floating-point literals

    - -

    -A floating-point literal is a decimal or hexadecimal representation of a -floating-point constant. -

    - -

    -A decimal floating-point literal consists of an integer part (decimal digits), -a decimal point, a fractional part (decimal digits), and an exponent part -(e or E followed by an optional sign and decimal digits). -One of the integer part or the fractional part may be elided; one of the decimal point -or the exponent part may be elided. -An exponent value exp scales the mantissa (integer and fractional part) by 10exp. -

    - -

    -A hexadecimal floating-point literal consists of a 0x or 0X -prefix, an integer part (hexadecimal digits), a radix point, a fractional part (hexadecimal digits), -and an exponent part (p or P followed by an optional sign and decimal digits). -One of the integer part or the fractional part may be elided; the radix point may be elided as well, -but the exponent part is required. (This syntax matches the one given in IEEE 754-2008 §5.12.3.) -An exponent value exp scales the mantissa (integer and fractional part) by 2exp. -

    - -

    -For readability, an underscore character _ may appear after -a base prefix or between successive digits; such underscores do not change -the literal value. -

    - -
    -float_lit         = decimal_float_lit | hex_float_lit .
    -
    -decimal_float_lit = decimal_digits "." [ decimal_digits ] [ decimal_exponent ] |
    -                    decimal_digits decimal_exponent |
    -                    "." decimal_digits [ decimal_exponent ] .
    -decimal_exponent  = ( "e" | "E" ) [ "+" | "-" ] decimal_digits .
    -
    -hex_float_lit     = "0" ( "x" | "X" ) hex_mantissa hex_exponent .
    -hex_mantissa      = [ "_" ] hex_digits "." [ hex_digits ] |
    -                    [ "_" ] hex_digits |
    -                    "." hex_digits .
    -hex_exponent      = ( "p" | "P" ) [ "+" | "-" ] decimal_digits .
    -
    - -
    -0.
    -72.40
    -072.40       // == 72.40
    -2.71828
    -1.e+0
    -6.67428e-11
    -1E6
    -.25
    -.12345E+5
    -1_5.         // == 15.0
    -0.15e+0_2    // == 15.0
    -
    -0x1p-2       // == 0.25
    -0x2.p10      // == 2048.0
    -0x1.Fp+0     // == 1.9375
    -0X.8p-0      // == 0.5
    -0X_1FFFP-16  // == 0.1249847412109375
    -0x15e-2      // == 0x15e - 2 (integer subtraction)
    -
    -0x.p1        // invalid: mantissa has no digits
    -1p-2         // invalid: p exponent requires hexadecimal mantissa
    -0x1.5e-2     // invalid: hexadecimal mantissa requires p exponent
    -1_.5         // invalid: _ must separate successive digits
    -1._5         // invalid: _ must separate successive digits
    -1.5_e1       // invalid: _ must separate successive digits
    -1.5e_1       // invalid: _ must separate successive digits
    -1.5e1_       // invalid: _ must separate successive digits
    -
    - - -

    Imaginary literals

    - -

    -An imaginary literal represents the imaginary part of a -complex constant. -It consists of an integer or -floating-point literal -followed by the lower-case letter i. -The value of an imaginary literal is the value of the respective -integer or floating-point literal multiplied by the imaginary unit i. -

    - -
    -imaginary_lit = (decimal_digits | int_lit | float_lit) "i" .
    -
    - -

    -For backward compatibility, an imaginary literal's integer part consisting -entirely of decimal digits (and possibly underscores) is considered a decimal -integer, even if it starts with a leading 0. -

    - -
    -0i
    -0123i         // == 123i for backward-compatibility
    -0o123i        // == 0o123 * 1i == 83i
    -0xabci        // == 0xabc * 1i == 2748i
    -0.i
    -2.71828i
    -1.e+0i
    -6.67428e-11i
    -1E6i
    -.25i
    -.12345E+5i
    -0x1p-2i       // == 0x1p-2 * 1i == 0.25i
    -
    - - -

    Rune literals

    - -

    -A rune literal represents a rune constant, -an integer value identifying a Unicode code point. -A rune literal is expressed as one or more characters enclosed in single quotes, -as in 'x' or '\n'. -Within the quotes, any character may appear except newline and unescaped single -quote. A single quoted character represents the Unicode value -of the character itself, -while multi-character sequences beginning with a backslash encode -values in various formats. -

    - -

    -The simplest form represents the single character within the quotes; -since Go source text is Unicode characters encoded in UTF-8, multiple -UTF-8-encoded bytes may represent a single integer value. For -instance, the literal 'a' holds a single byte representing -a literal a, Unicode U+0061, value 0x61, while -'ä' holds two bytes (0xc3 0xa4) representing -a literal a-dieresis, U+00E4, value 0xe4. -

    - -

    -Several backslash escapes allow arbitrary values to be encoded as -ASCII text. There are four ways to represent the integer value -as a numeric constant: \x followed by exactly two hexadecimal -digits; \u followed by exactly four hexadecimal digits; -\U followed by exactly eight hexadecimal digits, and a -plain backslash \ followed by exactly three octal digits. -In each case the value of the literal is the value represented by -the digits in the corresponding base. -

    - -

    -Although these representations all result in an integer, they have -different valid ranges. Octal escapes must represent a value between -0 and 255 inclusive. Hexadecimal escapes satisfy this condition -by construction. The escapes \u and \U -represent Unicode code points so within them some values are illegal, -in particular those above 0x10FFFF and surrogate halves. -

    - -

    -After a backslash, certain single-character escapes represent special values: -

    - -
    -\a   U+0007 alert or bell
    -\b   U+0008 backspace
    -\f   U+000C form feed
    -\n   U+000A line feed or newline
    -\r   U+000D carriage return
    -\t   U+0009 horizontal tab
    -\v   U+000B vertical tab
    -\\   U+005C backslash
    -\'   U+0027 single quote  (valid escape only within rune literals)
    -\"   U+0022 double quote  (valid escape only within string literals)
    -
    - -

    -All other sequences starting with a backslash are illegal inside rune literals. -

    -
    -rune_lit         = "'" ( unicode_value | byte_value ) "'" .
    -unicode_value    = unicode_char | little_u_value | big_u_value | escaped_char .
    -byte_value       = octal_byte_value | hex_byte_value .
    -octal_byte_value = `\` octal_digit octal_digit octal_digit .
    -hex_byte_value   = `\` "x" hex_digit hex_digit .
    -little_u_value   = `\` "u" hex_digit hex_digit hex_digit hex_digit .
    -big_u_value      = `\` "U" hex_digit hex_digit hex_digit hex_digit
    -                           hex_digit hex_digit hex_digit hex_digit .
    -escaped_char     = `\` ( "a" | "b" | "f" | "n" | "r" | "t" | "v" | `\` | "'" | `"` ) .
    -
    - -
    -'a'
    -'ä'
    -'本'
    -'\t'
    -'\000'
    -'\007'
    -'\377'
    -'\x07'
    -'\xff'
    -'\u12e4'
    -'\U00101234'
    -'\''         // rune literal containing single quote character
    -'aa'         // illegal: too many characters
    -'\xa'        // illegal: too few hexadecimal digits
    -'\0'         // illegal: too few octal digits
    -'\uDFFF'     // illegal: surrogate half
    -'\U00110000' // illegal: invalid Unicode code point
    -
    - - -

    String literals

    - -

    -A string literal represents a string constant -obtained from concatenating a sequence of characters. There are two forms: -raw string literals and interpreted string literals. -

    - -

    -Raw string literals are character sequences between back quotes, as in -`foo`. Within the quotes, any character may appear except -back quote. The value of a raw string literal is the -string composed of the uninterpreted (implicitly UTF-8-encoded) characters -between the quotes; -in particular, backslashes have no special meaning and the string may -contain newlines. -Carriage return characters ('\r') inside raw string literals -are discarded from the raw string value. -

    - -

    -Interpreted string literals are character sequences between double -quotes, as in "bar". -Within the quotes, any character may appear except newline and unescaped double quote. -The text between the quotes forms the -value of the literal, with backslash escapes interpreted as they -are in rune literals (except that \' is illegal and -\" is legal), with the same restrictions. -The three-digit octal (\nnn) -and two-digit hexadecimal (\xnn) escapes represent individual -bytes of the resulting string; all other escapes represent -the (possibly multi-byte) UTF-8 encoding of individual characters. -Thus inside a string literal \377 and \xFF represent -a single byte of value 0xFF=255, while ÿ, -\u00FF, \U000000FF and \xc3\xbf represent -the two bytes 0xc3 0xbf of the UTF-8 encoding of character -U+00FF. -

    - -
    -string_lit             = raw_string_lit | interpreted_string_lit .
    -raw_string_lit         = "`" { unicode_char | newline } "`" .
    -interpreted_string_lit = `"` { unicode_value | byte_value } `"` .
    -
    - -
    -`abc`                // same as "abc"
    -`\n
    -\n`                  // same as "\\n\n\\n"
    -"\n"
    -"\""                 // same as `"`
    -"Hello, world!\n"
    -"日本語"
    -"\u65e5本\U00008a9e"
    -"\xff\u00FF"
    -"\uD800"             // illegal: surrogate half
    -"\U00110000"         // illegal: invalid Unicode code point
    -
    - -

    -These examples all represent the same string: -

    - -
    -"日本語"                                 // UTF-8 input text
    -`日本語`                                 // UTF-8 input text as a raw literal
    -"\u65e5\u672c\u8a9e"                    // the explicit Unicode code points
    -"\U000065e5\U0000672c\U00008a9e"        // the explicit Unicode code points
    -"\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"  // the explicit UTF-8 bytes
    -
    - -

    -If the source code represents a character as two code points, such as -a combining form involving an accent and a letter, the result will be -an error if placed in a rune literal (it is not a single code -point), and will appear as two code points if placed in a string -literal. -

    - - -

    Constants

    - -

    There are boolean constants, -rune constants, -integer constants, -floating-point constants, complex constants, -and string constants. Rune, integer, floating-point, -and complex constants are -collectively called numeric constants. -

    - -

    -A constant value is represented by a -rune, -integer, -floating-point, -imaginary, -or -string literal, -an identifier denoting a constant, -a constant expression, -a conversion with a result that is a constant, or -the result value of some built-in functions such as -unsafe.Sizeof applied to any value, -cap or len applied to -some expressions, -real and imag applied to a complex constant -and complex applied to numeric constants. -The boolean truth values are represented by the predeclared constants -true and false. The predeclared identifier -iota denotes an integer constant. -

    - -

    -In general, complex constants are a form of -constant expression -and are discussed in that section. -

    - -

    -Numeric constants represent exact values of arbitrary precision and do not overflow. -Consequently, there are no constants denoting the IEEE 754 negative zero, infinity, -and not-a-number values. -

    - -

    -Constants may be typed or untyped. -Literal constants, true, false, iota, -and certain constant expressions -containing only untyped constant operands are untyped. -

    - -

    -A constant may be given a type explicitly by a constant declaration -or conversion, or implicitly when used in a -variable declaration or an -assignment or as an -operand in an expression. -It is an error if the constant value -cannot be represented as a value of the respective type. -

    - -

    -An untyped constant has a default type which is the type to which the -constant is implicitly converted in contexts where a typed value is required, -for instance, in a short variable declaration -such as i := 0 where there is no explicit type. -The default type of an untyped constant is bool, rune, -int, float64, complex128 or string -respectively, depending on whether it is a boolean, rune, integer, floating-point, -complex, or string constant. -

    - -

    -Implementation restriction: Although numeric constants have arbitrary -precision in the language, a compiler may implement them using an -internal representation with limited precision. That said, every -implementation must: -

    - -
      -
    • Represent integer constants with at least 256 bits.
    • - -
    • Represent floating-point constants, including the parts of - a complex constant, with a mantissa of at least 256 bits - and a signed binary exponent of at least 16 bits.
    • - -
    • Give an error if unable to represent an integer constant - precisely.
    • - -
    • Give an error if unable to represent a floating-point or - complex constant due to overflow.
    • - -
    • Round to the nearest representable constant if unable to - represent a floating-point or complex constant due to limits - on precision.
    • -
    - -

    -These requirements apply both to literal constants and to the result -of evaluating constant -expressions. -

    - - -

    Variables

    - -

    -A variable is a storage location for holding a value. -The set of permissible values is determined by the -variable's type. -

    - -

    -A variable declaration -or, for function parameters and results, the signature -of a function declaration -or function literal reserves -storage for a named variable. - -Calling the built-in function new -or taking the address of a composite literal -allocates storage for a variable at run time. -Such an anonymous variable is referred to via a (possibly implicit) -pointer indirection. -

    - -

    -Structured variables of array, slice, -and struct types have elements and fields that may -be addressed individually. Each such element -acts like a variable. -

    - -

    -The static type (or just type) of a variable is the -type given in its declaration, the type provided in the -new call or composite literal, or the type of -an element of a structured variable. -Variables of interface type also have a distinct dynamic type, -which is the concrete type of the value assigned to the variable at run time -(unless the value is the predeclared identifier nil, -which has no type). -The dynamic type may vary during execution but values stored in interface -variables are always assignable -to the static type of the variable. -

    - -
    -var x interface{}  // x is nil and has static type interface{}
    -var v *T           // v has value nil, static type *T
    -x = 42             // x has value 42 and dynamic type int
    -x = v              // x has value (*T)(nil) and dynamic type *T
    -
    - -

    -A variable's value is retrieved by referring to the variable in an -expression; it is the most recent value -assigned to the variable. -If a variable has not yet been assigned a value, its value is the -zero value for its type. -

    - - -

    Types

    - -

    -A type determines a set of values together with operations and methods specific -to those values. A type may be denoted by a type name, if it has one, -or specified using a type literal, which composes a type from existing types. -

    - -
    -Type      = TypeName | TypeLit | "(" Type ")" .
    -TypeName  = identifier | QualifiedIdent .
    -TypeLit   = ArrayType | StructType | PointerType | FunctionType | InterfaceType |
    -	    SliceType | MapType | ChannelType .
    -
    - -

    -The language predeclares certain type names. -Others are introduced with type declarations. -Composite types—array, struct, pointer, function, -interface, slice, map, and channel types—may be constructed using -type literals. -

    - -

    -Each type T has an underlying type: If T -is one of the predeclared boolean, numeric, or string types, or a type literal, -the corresponding underlying -type is T itself. Otherwise, T's underlying type -is the underlying type of the type to which T refers in its -type declaration. -

    - -
    -type (
    -	A1 = string
    -	A2 = A1
    -)
    -
    -type (
    -	B1 string
    -	B2 B1
    -	B3 []B1
    -	B4 B3
    -)
    -
    - -

    -The underlying type of string, A1, A2, B1, -and B2 is string. -The underlying type of []B1, B3, and B4 is []B1. -

    - -

    Method sets

    -

    -A type has a (possibly empty) method set associated with it. -The method set of an interface type is its interface. -The method set of any other type T consists of all -methods declared with receiver type T. -The method set of the corresponding pointer type *T -is the set of all methods declared with receiver *T or T -(that is, it also contains the method set of T). -Further rules apply to structs containing embedded fields, as described -in the section on struct types. -Any other type has an empty method set. -In a method set, each method must have a -unique -non-blank method name. -

    - -

    -The method set of a type determines the interfaces that the -type implements -and the methods that can be called -using a receiver of that type. -

    - -

    Boolean types

    - -

    -A boolean type represents the set of Boolean truth values -denoted by the predeclared constants true -and false. The predeclared boolean type is bool; -it is a defined type. -

    - -

    Numeric types

    - -

    -A numeric type represents sets of integer or floating-point values. -The predeclared architecture-independent numeric types are: -

    - -
    -uint8       the set of all unsigned  8-bit integers (0 to 255)
    -uint16      the set of all unsigned 16-bit integers (0 to 65535)
    -uint32      the set of all unsigned 32-bit integers (0 to 4294967295)
    -uint64      the set of all unsigned 64-bit integers (0 to 18446744073709551615)
    -
    -int8        the set of all signed  8-bit integers (-128 to 127)
    -int16       the set of all signed 16-bit integers (-32768 to 32767)
    -int32       the set of all signed 32-bit integers (-2147483648 to 2147483647)
    -int64       the set of all signed 64-bit integers (-9223372036854775808 to 9223372036854775807)
    -
    -float32     the set of all IEEE 754 32-bit floating-point numbers
    -float64     the set of all IEEE 754 64-bit floating-point numbers
    -
    -complex64   the set of all complex numbers with float32 real and imaginary parts
    -complex128  the set of all complex numbers with float64 real and imaginary parts
    -
    -byte        alias for uint8
    -rune        alias for int32
    -
    - -

    -The value of an n-bit integer is n bits wide and represented using -two's complement arithmetic. -

    - -

    -There is also a set of predeclared numeric types with implementation-specific sizes: -

    - -
    -uint     either 32 or 64 bits
    -int      same size as uint
    -uintptr  an unsigned integer large enough to store the uninterpreted bits of a pointer value
    -
    - -

    -To avoid portability issues all numeric types are defined -types and thus distinct except -byte, which is an alias for uint8, and -rune, which is an alias for int32. -Explicit conversions -are required when different numeric types are mixed in an expression -or assignment. For instance, int32 and int -are not the same type even though they may have the same size on a -particular architecture. -

    - -

    String types

    - -

    -A string type represents the set of string values. -A string value is a (possibly empty) sequence of bytes. -The number of bytes is called the length of the string and is never negative. -Strings are immutable: once created, -it is impossible to change the contents of a string. -The predeclared string type is string; -it is a defined type. -

    - -

    -The length of a string s can be discovered using -the built-in function len. -The length is a compile-time constant if the string is a constant. -A string's bytes can be accessed by integer indices -0 through len(s)-1. -It is illegal to take the address of such an element; if -s[i] is the i'th byte of a -string, &s[i] is invalid. -

    - - -

    Array types

    - -

    -An array is a numbered sequence of elements of a single -type, called the element type. -The number of elements is called the length of the array and is never negative. -

    - -
    -ArrayType   = "[" ArrayLength "]" ElementType .
    -ArrayLength = Expression .
    -ElementType = Type .
    -
    - -

    -The length is part of the array's type; it must evaluate to a -non-negative constant -representable by a value -of type int. -The length of array a can be discovered -using the built-in function len. -The elements can be addressed by integer indices -0 through len(a)-1. -Array types are always one-dimensional but may be composed to form -multi-dimensional types. -

    - -
    -[32]byte
    -[2*N] struct { x, y int32 }
    -[1000]*float64
    -[3][5]int
    -[2][2][2]float64  // same as [2]([2]([2]float64))
    -
    - -

    Slice types

    - -

    -A slice is a descriptor for a contiguous segment of an underlying array and -provides access to a numbered sequence of elements from that array. -A slice type denotes the set of all slices of arrays of its element type. -The number of elements is called the length of the slice and is never negative. -The value of an uninitialized slice is nil. -

    - -
    -SliceType = "[" "]" ElementType .
    -
    - -

    -The length of a slice s can be discovered by the built-in function -len; unlike with arrays it may change during -execution. The elements can be addressed by integer indices -0 through len(s)-1. The slice index of a -given element may be less than the index of the same element in the -underlying array. -

    -

    -A slice, once initialized, is always associated with an underlying -array that holds its elements. A slice therefore shares storage -with its array and with other slices of the same array; by contrast, -distinct arrays always represent distinct storage. -

    -

    -The array underlying a slice may extend past the end of the slice. -The capacity is a measure of that extent: it is the sum of -the length of the slice and the length of the array beyond the slice; -a slice of length up to that capacity can be created by -slicing a new one from the original slice. -The capacity of a slice a can be discovered using the -built-in function cap(a). -

    - -

    -A new, initialized slice value for a given element type T is -made using the built-in function -make, -which takes a slice type -and parameters specifying the length and optionally the capacity. -A slice created with make always allocates a new, hidden array -to which the returned slice value refers. That is, executing -

    - -
    -make([]T, length, capacity)
    -
    - -

    -produces the same slice as allocating an array and slicing -it, so these two expressions are equivalent: -

    - -
    -make([]int, 50, 100)
    -new([100]int)[0:50]
    -
    - -

    -Like arrays, slices are always one-dimensional but may be composed to construct -higher-dimensional objects. -With arrays of arrays, the inner arrays are, by construction, always the same length; -however with slices of slices (or arrays of slices), the inner lengths may vary dynamically. -Moreover, the inner slices must be initialized individually. -

    - -

    Struct types

    - -

    -A struct is a sequence of named elements, called fields, each of which has a -name and a type. Field names may be specified explicitly (IdentifierList) or -implicitly (EmbeddedField). -Within a struct, non-blank field names must -be unique. -

    - -
    -StructType    = "struct" "{" { FieldDecl ";" } "}" .
    -FieldDecl     = (IdentifierList Type | EmbeddedField) [ Tag ] .
    -EmbeddedField = [ "*" ] TypeName .
    -Tag           = string_lit .
    -
    - -
    -// An empty struct.
    -struct {}
    -
    -// A struct with 6 fields.
    -struct {
    -	x, y int
    -	u float32
    -	_ float32  // padding
    -	A *[]int
    -	F func()
    -}
    -
    - -

    -A field declared with a type but no explicit field name is called an embedded field. -An embedded field must be specified as -a type name T or as a pointer to a non-interface type name *T, -and T itself may not be -a pointer type. The unqualified type name acts as the field name. -

    - -
    -// A struct with four embedded fields of types T1, *T2, P.T3 and *P.T4
    -struct {
    -	T1        // field name is T1
    -	*T2       // field name is T2
    -	P.T3      // field name is T3
    -	*P.T4     // field name is T4
    -	x, y int  // field names are x and y
    -}
    -
    - -

    -The following declaration is illegal because field names must be unique -in a struct type: -

    - -
    -struct {
    -	T     // conflicts with embedded field *T and *P.T
    -	*T    // conflicts with embedded field T and *P.T
    -	*P.T  // conflicts with embedded field T and *T
    -}
    -
    - -

    -A field or method f of an -embedded field in a struct x is called promoted if -x.f is a legal selector that denotes -that field or method f. -

    - -

    -Promoted fields act like ordinary fields -of a struct except that they cannot be used as field names in -composite literals of the struct. -

    - -

    -Given a struct type S and a defined type -T, promoted methods are included in the method set of the struct as follows: -

    -
      -
    • - If S contains an embedded field T, - the method sets of S - and *S both include promoted methods with receiver - T. The method set of *S also - includes promoted methods with receiver *T. -
    • - -
    • - If S contains an embedded field *T, - the method sets of S and *S both - include promoted methods with receiver T or - *T. -
    • -
    - -

    -A field declaration may be followed by an optional string literal tag, -which becomes an attribute for all the fields in the corresponding -field declaration. An empty tag string is equivalent to an absent tag. -The tags are made visible through a reflection interface -and take part in type identity for structs -but are otherwise ignored. -

    - -
    -struct {
    -	x, y float64 ""  // an empty tag string is like an absent tag
    -	name string  "any string is permitted as a tag"
    -	_    [4]byte "ceci n'est pas un champ de structure"
    -}
    -
    -// A struct corresponding to a TimeStamp protocol buffer.
    -// The tag strings define the protocol buffer field numbers;
    -// they follow the convention outlined by the reflect package.
    -struct {
    -	microsec  uint64 `protobuf:"1"`
    -	serverIP6 uint64 `protobuf:"2"`
    -}
    -
    - -

    Pointer types

    - -

    -A pointer type denotes the set of all pointers to variables of a given -type, called the base type of the pointer. -The value of an uninitialized pointer is nil. -

    - -
    -PointerType = "*" BaseType .
    -BaseType    = Type .
    -
    - -
    -*Point
    -*[4]int
    -
    - -

    Function types

    - -

    -A function type denotes the set of all functions with the same parameter -and result types. The value of an uninitialized variable of function type -is nil. -

    - -
    -FunctionType   = "func" Signature .
    -Signature      = Parameters [ Result ] .
    -Result         = Parameters | Type .
    -Parameters     = "(" [ ParameterList [ "," ] ] ")" .
    -ParameterList  = ParameterDecl { "," ParameterDecl } .
    -ParameterDecl  = [ IdentifierList ] [ "..." ] Type .
    -
    - -

    -Within a list of parameters or results, the names (IdentifierList) -must either all be present or all be absent. If present, each name -stands for one item (parameter or result) of the specified type and -all non-blank names in the signature -must be unique. -If absent, each type stands for one item of that type. -Parameter and result -lists are always parenthesized except that if there is exactly -one unnamed result it may be written as an unparenthesized type. -

    - -

    -The final incoming parameter in a function signature may have -a type prefixed with .... -A function with such a parameter is called variadic and -may be invoked with zero or more arguments for that parameter. -

    - -
    -func()
    -func(x int) int
    -func(a, _ int, z float32) bool
    -func(a, b int, z float32) (bool)
    -func(prefix string, values ...int)
    -func(a, b int, z float64, opt ...interface{}) (success bool)
    -func(int, int, float64) (float64, *[]int)
    -func(n int) func(p *T)
    -
    - - -

    Interface types

    - -

    -An interface type specifies a method set called its interface. -A variable of interface type can store a value of any type with a method set -that is any superset of the interface. Such a type is said to -implement the interface. -The value of an uninitialized variable of interface type is nil. -

    - -
    -InterfaceType      = "interface" "{" { ( MethodSpec | InterfaceTypeName ) ";" } "}" .
    -MethodSpec         = MethodName Signature .
    -MethodName         = identifier .
    -InterfaceTypeName  = TypeName .
    -
    - -

    -An interface type may specify methods explicitly through method specifications, -or it may embed methods of other interfaces through interface type names. -

    - -
    -// A simple File interface.
    -interface {
    -	Read([]byte) (int, error)
    -	Write([]byte) (int, error)
    -	Close() error
    -}
    -
    - -

    -The name of each explicitly specified method must be unique -and not blank. -

    - -
    -interface {
    -	String() string
    -	String() string  // illegal: String not unique
    -	_(x int)         // illegal: method must have non-blank name
    -}
    -
    - -

    -More than one type may implement an interface. -For instance, if two types S1 and S2 -have the method set -

    - -
    -func (p T) Read(p []byte) (n int, err error)
    -func (p T) Write(p []byte) (n int, err error)
    -func (p T) Close() error
    -
    - -

    -(where T stands for either S1 or S2) -then the File interface is implemented by both S1 and -S2, regardless of what other methods -S1 and S2 may have or share. -

    - -

    -A type implements any interface comprising any subset of its methods -and may therefore implement several distinct interfaces. For -instance, all types implement the empty interface: -

    - -
    -interface{}
    -
    - -

    -Similarly, consider this interface specification, -which appears within a type declaration -to define an interface called Locker: -

    - -
    -type Locker interface {
    -	Lock()
    -	Unlock()
    -}
    -
    - -

    -If S1 and S2 also implement -

    - -
    -func (p T) Lock() { … }
    -func (p T) Unlock() { … }
    -
    - -

    -they implement the Locker interface as well -as the File interface. -

    - -

    -An interface T may use a (possibly qualified) interface type -name E in place of a method specification. This is called -embedding interface E in T. -The method set of T is the union -of the method sets of T’s explicitly declared methods and of -T’s embedded interfaces. -

    - -
    -type Reader interface {
    -	Read(p []byte) (n int, err error)
    -	Close() error
    -}
    -
    -type Writer interface {
    -	Write(p []byte) (n int, err error)
    -	Close() error
    -}
    -
    -// ReadWriter's methods are Read, Write, and Close.
    -type ReadWriter interface {
    -	Reader  // includes methods of Reader in ReadWriter's method set
    -	Writer  // includes methods of Writer in ReadWriter's method set
    -}
    -
    - -

    -A union of method sets contains the (exported and non-exported) -methods of each method set exactly once, and methods with the -same names must -have identical signatures. -

    - -
    -type ReadCloser interface {
    -	Reader   // includes methods of Reader in ReadCloser's method set
    -	Close()  // illegal: signatures of Reader.Close and Close are different
    -}
    -
    - -

    -An interface type T may not embed itself -or any interface type that embeds T, recursively. -

    - -
    -// illegal: Bad cannot embed itself
    -type Bad interface {
    -	Bad
    -}
    -
    -// illegal: Bad1 cannot embed itself using Bad2
    -type Bad1 interface {
    -	Bad2
    -}
    -type Bad2 interface {
    -	Bad1
    -}
    -
    - -

    Map types

    - -

    -A map is an unordered group of elements of one type, called the -element type, indexed by a set of unique keys of another type, -called the key type. -The value of an uninitialized map is nil. -

    - -
    -MapType     = "map" "[" KeyType "]" ElementType .
    -KeyType     = Type .
    -
    - -

    -The comparison operators -== and != must be fully defined -for operands of the key type; thus the key type must not be a function, map, or -slice. -If the key type is an interface type, these -comparison operators must be defined for the dynamic key values; -failure will cause a run-time panic. - -

    - -
    -map[string]int
    -map[*T]struct{ x, y float64 }
    -map[string]interface{}
    -
    - -

    -The number of map elements is called its length. -For a map m, it can be discovered using the -built-in function len -and may change during execution. Elements may be added during execution -using assignments and retrieved with -index expressions; they may be removed with the -delete built-in function. -

    -

    -A new, empty map value is made using the built-in -function make, -which takes the map type and an optional capacity hint as arguments: -

    - -
    -make(map[string]int)
    -make(map[string]int, 100)
    -
    - -

    -The initial capacity does not bound its size: -maps grow to accommodate the number of items -stored in them, with the exception of nil maps. -A nil map is equivalent to an empty map except that no elements -may be added. -

    - -

    Channel types

    - -

    -A channel provides a mechanism for -concurrently executing functions -to communicate by -sending and -receiving -values of a specified element type. -The value of an uninitialized channel is nil. -

    - -
    -ChannelType = ( "chan" | "chan" "<-" | "<-" "chan" ) ElementType .
    -
    - -

    -The optional <- operator specifies the channel direction, -send or receive. If no direction is given, the channel is -bidirectional. -A channel may be constrained only to send or only to receive by -assignment or -explicit conversion. -

    - -
    -chan T          // can be used to send and receive values of type T
    -chan<- float64  // can only be used to send float64s
    -<-chan int      // can only be used to receive ints
    -
    - -

    -The <- operator associates with the leftmost chan -possible: -

    - -
    -chan<- chan int    // same as chan<- (chan int)
    -chan<- <-chan int  // same as chan<- (<-chan int)
    -<-chan <-chan int  // same as <-chan (<-chan int)
    -chan (<-chan int)
    -
    - -

    -A new, initialized channel -value can be made using the built-in function -make, -which takes the channel type and an optional capacity as arguments: -

    - -
    -make(chan int, 100)
    -
    - -

    -The capacity, in number of elements, sets the size of the buffer in the channel. -If the capacity is zero or absent, the channel is unbuffered and communication -succeeds only when both a sender and receiver are ready. Otherwise, the channel -is buffered and communication succeeds without blocking if the buffer -is not full (sends) or not empty (receives). -A nil channel is never ready for communication. -

    - -

    -A channel may be closed with the built-in function -close. -The multi-valued assignment form of the -receive operator -reports whether a received value was sent before -the channel was closed. -

    - -

    -A single channel may be used in -send statements, -receive operations, -and calls to the built-in functions -cap and -len -by any number of goroutines without further synchronization. -Channels act as first-in-first-out queues. -For example, if one goroutine sends values on a channel -and a second goroutine receives them, the values are -received in the order sent. -

    - -

    Properties of types and values

    - -

    Type identity

    - -

    -Two types are either identical or different. -

    - -

    -A defined type is always different from any other type. -Otherwise, two types are identical if their underlying type literals are -structurally equivalent; that is, they have the same literal structure and corresponding -components have identical types. In detail: -

    - -
      -
    • Two array types are identical if they have identical element types and - the same array length.
    • - -
    • Two slice types are identical if they have identical element types.
    • - -
    • Two struct types are identical if they have the same sequence of fields, - and if corresponding fields have the same names, and identical types, - and identical tags. - Non-exported field names from different - packages are always different.
    • - -
    • Two pointer types are identical if they have identical base types.
    • - -
    • Two function types are identical if they have the same number of parameters - and result values, corresponding parameter and result types are - identical, and either both functions are variadic or neither is. - Parameter and result names are not required to match.
    • - -
    • Two interface types are identical if they have the same set of methods - with the same names and identical function types. - Non-exported method names from different - packages are always different. The order of the methods is irrelevant.
    • - -
    • Two map types are identical if they have identical key and element types.
    • - -
    • Two channel types are identical if they have identical element types and - the same direction.
    • -
    - -

    -Given the declarations -

    - -
    -type (
    -	A0 = []string
    -	A1 = A0
    -	A2 = struct{ a, b int }
    -	A3 = int
    -	A4 = func(A3, float64) *A0
    -	A5 = func(x int, _ float64) *[]string
    -)
    -
    -type (
    -	B0 A0
    -	B1 []string
    -	B2 struct{ a, b int }
    -	B3 struct{ a, c int }
    -	B4 func(int, float64) *B0
    -	B5 func(x int, y float64) *A1
    -)
    -
    -type	C0 = B0
    -
    - -

    -these types are identical: -

    - -
    -A0, A1, and []string
    -A2 and struct{ a, b int }
    -A3 and int
    -A4, func(int, float64) *[]string, and A5
    -
    -B0 and C0
    -[]int and []int
    -struct{ a, b *T5 } and struct{ a, b *T5 }
    -func(x int, y float64) *[]string, func(int, float64) (result *[]string), and A5
    -
    - -

    -B0 and B1 are different because they are new types -created by distinct type definitions; -func(int, float64) *B0 and func(x int, y float64) *[]string -are different because B0 is different from []string. -

    - - -

    Assignability

    - -

    -A value x is assignable to a variable of type T -("x is assignable to T") if one of the following conditions applies: -

    - -
      -
    • -x's type is identical to T. -
    • -
    • -x's type V and T have identical -underlying types and at least one of V -or T is not a defined type. -
    • -
    • -T is an interface type and -x implements T. -
    • -
    • -x is a bidirectional channel value, T is a channel type, -x's type V and T have identical element types, -and at least one of V or T is not a defined type. -
    • -
    • -x is the predeclared identifier nil and T -is a pointer, function, slice, map, channel, or interface type. -
    • -
    • -x is an untyped constant -representable -by a value of type T. -
    • -
    - - -

    Representability

    - -

    -A constant x is representable -by a value of type T if one of the following conditions applies: -

    - -
      -
    • -x is in the set of values determined by T. -
    • - -
    • -T is a floating-point type and x can be rounded to T's -precision without overflow. Rounding uses IEEE 754 round-to-even rules but with an IEEE -negative zero further simplified to an unsigned zero. Note that constant values never result -in an IEEE negative zero, NaN, or infinity. -
    • - -
    • -T is a complex type, and x's -components real(x) and imag(x) -are representable by values of T's component type (float32 or -float64). -
    • -
    - -
    -x                   T           x is representable by a value of T because
    -
    -'a'                 byte        97 is in the set of byte values
    -97                  rune        rune is an alias for int32, and 97 is in the set of 32-bit integers
    -"foo"               string      "foo" is in the set of string values
    -1024                int16       1024 is in the set of 16-bit integers
    -42.0                byte        42 is in the set of unsigned 8-bit integers
    -1e10                uint64      10000000000 is in the set of unsigned 64-bit integers
    -2.718281828459045   float32     2.718281828459045 rounds to 2.7182817 which is in the set of float32 values
    --1e-1000            float64     -1e-1000 rounds to IEEE -0.0 which is further simplified to 0.0
    -0i                  int         0 is an integer value
    -(42 + 0i)           float32     42.0 (with zero imaginary part) is in the set of float32 values
    -
    - -
    -x                   T           x is not representable by a value of T because
    -
    -0                   bool        0 is not in the set of boolean values
    -'a'                 string      'a' is a rune, it is not in the set of string values
    -1024                byte        1024 is not in the set of unsigned 8-bit integers
    --1                  uint16      -1 is not in the set of unsigned 16-bit integers
    -1.1                 int         1.1 is not an integer value
    -42i                 float32     (0 + 42i) is not in the set of float32 values
    -1e1000              float64     1e1000 overflows to IEEE +Inf after rounding
    -
    - - -

    Blocks

    - -

    -A block is a possibly empty sequence of declarations and statements -within matching brace brackets. -

    - -
    -Block = "{" StatementList "}" .
    -StatementList = { Statement ";" } .
    -
    - -

    -In addition to explicit blocks in the source code, there are implicit blocks: -

    - -
      -
    1. The universe block encompasses all Go source text.
    2. - -
    3. Each package has a package block containing all - Go source text for that package.
    4. - -
    5. Each file has a file block containing all Go source text - in that file.
    6. - -
    7. Each "if", - "for", and - "switch" - statement is considered to be in its own implicit block.
    8. - -
    9. Each clause in a "switch" - or "select" statement - acts as an implicit block.
    10. -
    - -

    -Blocks nest and influence scoping. -

    - - -

    Declarations and scope

    - -

    -A declaration binds a non-blank identifier to a -constant, -type, -variable, -function, -label, or -package. -Every identifier in a program must be declared. -No identifier may be declared twice in the same block, and -no identifier may be declared in both the file and package block. -

    - -

    -The blank identifier may be used like any other identifier -in a declaration, but it does not introduce a binding and thus is not declared. -In the package block, the identifier init may only be used for -init function declarations, -and like the blank identifier it does not introduce a new binding. -

    - -
    -Declaration   = ConstDecl | TypeDecl | VarDecl .
    -TopLevelDecl  = Declaration | FunctionDecl | MethodDecl .
    -
    - -

    -The scope of a declared identifier is the extent of source text in which -the identifier denotes the specified constant, type, variable, function, label, or package. -

    - -

    -Go is lexically scoped using blocks: -

    - -
      -
    1. The scope of a predeclared identifier is the universe block.
    2. - -
    3. The scope of an identifier denoting a constant, type, variable, - or function (but not method) declared at top level (outside any - function) is the package block.
    4. - -
    5. The scope of the package name of an imported package is the file block - of the file containing the import declaration.
    6. - -
    7. The scope of an identifier denoting a method receiver, function parameter, - or result variable is the function body.
    8. - -
    9. The scope of a constant or variable identifier declared - inside a function begins at the end of the ConstSpec or VarSpec - (ShortVarDecl for short variable declarations) - and ends at the end of the innermost containing block.
    10. - -
    11. The scope of a type identifier declared inside a function - begins at the identifier in the TypeSpec - and ends at the end of the innermost containing block.
    12. -
    - -

    -An identifier declared in a block may be redeclared in an inner block. -While the identifier of the inner declaration is in scope, it denotes -the entity declared by the inner declaration. -

    - -

    -The package clause is not a declaration; the package name -does not appear in any scope. Its purpose is to identify the files belonging -to the same package and to specify the default package name for import -declarations. -

    - - -

    Label scopes

    - -

    -Labels are declared by labeled statements and are -used in the "break", -"continue", and -"goto" statements. -It is illegal to define a label that is never used. -In contrast to other identifiers, labels are not block scoped and do -not conflict with identifiers that are not labels. The scope of a label -is the body of the function in which it is declared and excludes -the body of any nested function. -

    - - -

    Blank identifier

    - -

    -The blank identifier is represented by the underscore character _. -It serves as an anonymous placeholder instead of a regular (non-blank) -identifier and has special meaning in declarations, -as an operand, and in assignments. -

    - - -

    Predeclared identifiers

    - -

    -The following identifiers are implicitly declared in the -universe block: -

    -
    -Types:
    -	bool byte complex64 complex128 error float32 float64
    -	int int8 int16 int32 int64 rune string
    -	uint uint8 uint16 uint32 uint64 uintptr
    -
    -Constants:
    -	true false iota
    -
    -Zero value:
    -	nil
    -
    -Functions:
    -	append cap close complex copy delete imag len
    -	make new panic print println real recover
    -
    - - -

    Exported identifiers

    - -

    -An identifier may be exported to permit access to it from another package. -An identifier is exported if both: -

    -
      -
    1. the first character of the identifier's name is a Unicode upper case - letter (Unicode class "Lu"); and
    2. -
    3. the identifier is declared in the package block - or it is a field name or - method name.
    4. -
    -

    -All other identifiers are not exported. -

    - - -

    Uniqueness of identifiers

    - -

    -Given a set of identifiers, an identifier is called unique if it is -different from every other in the set. -Two identifiers are different if they are spelled differently, or if they -appear in different packages and are not -exported. Otherwise, they are the same. -

    - -

    Constant declarations

    - -

    -A constant declaration binds a list of identifiers (the names of -the constants) to the values of a list of constant expressions. -The number of identifiers must be equal -to the number of expressions, and the nth identifier on -the left is bound to the value of the nth expression on the -right. -

    - -
    -ConstDecl      = "const" ( ConstSpec | "(" { ConstSpec ";" } ")" ) .
    -ConstSpec      = IdentifierList [ [ Type ] "=" ExpressionList ] .
    -
    -IdentifierList = identifier { "," identifier } .
    -ExpressionList = Expression { "," Expression } .
    -
    - -

    -If the type is present, all constants take the type specified, and -the expressions must be assignable to that type. -If the type is omitted, the constants take the -individual types of the corresponding expressions. -If the expression values are untyped constants, -the declared constants remain untyped and the constant identifiers -denote the constant values. For instance, if the expression is a -floating-point literal, the constant identifier denotes a floating-point -constant, even if the literal's fractional part is zero. -

    - -
    -const Pi float64 = 3.14159265358979323846
    -const zero = 0.0         // untyped floating-point constant
    -const (
    -	size int64 = 1024
    -	eof        = -1  // untyped integer constant
    -)
    -const a, b, c = 3, 4, "foo"  // a = 3, b = 4, c = "foo", untyped integer and string constants
    -const u, v float32 = 0, 3    // u = 0.0, v = 3.0
    -
    - -

    -Within a parenthesized const declaration list the -expression list may be omitted from any but the first ConstSpec. -Such an empty list is equivalent to the textual substitution of the -first preceding non-empty expression list and its type if any. -Omitting the list of expressions is therefore equivalent to -repeating the previous list. The number of identifiers must be equal -to the number of expressions in the previous list. -Together with the iota constant generator -this mechanism permits light-weight declaration of sequential values: -

    - -
    -const (
    -	Sunday = iota
    -	Monday
    -	Tuesday
    -	Wednesday
    -	Thursday
    -	Friday
    -	Partyday
    -	numberOfDays  // this constant is not exported
    -)
    -
    - - -

    Iota

    - -

    -Within a constant declaration, the predeclared identifier -iota represents successive untyped integer -constants. Its value is the index of the respective ConstSpec -in that constant declaration, starting at zero. -It can be used to construct a set of related constants: -

    - -
    -const (
    -	c0 = iota  // c0 == 0
    -	c1 = iota  // c1 == 1
    -	c2 = iota  // c2 == 2
    -)
    -
    -const (
    -	a = 1 << iota  // a == 1  (iota == 0)
    -	b = 1 << iota  // b == 2  (iota == 1)
    -	c = 3          // c == 3  (iota == 2, unused)
    -	d = 1 << iota  // d == 8  (iota == 3)
    -)
    -
    -const (
    -	u         = iota * 42  // u == 0     (untyped integer constant)
    -	v float64 = iota * 42  // v == 42.0  (float64 constant)
    -	w         = iota * 42  // w == 84    (untyped integer constant)
    -)
    -
    -const x = iota  // x == 0
    -const y = iota  // y == 0
    -
    - -

    -By definition, multiple uses of iota in the same ConstSpec all have the same value: -

    - -
    -const (
    -	bit0, mask0 = 1 << iota, 1<<iota - 1  // bit0 == 1, mask0 == 0  (iota == 0)
    -	bit1, mask1                           // bit1 == 2, mask1 == 1  (iota == 1)
    -	_, _                                  //                        (iota == 2, unused)
    -	bit3, mask3                           // bit3 == 8, mask3 == 7  (iota == 3)
    -)
    -
    - -

    -This last example exploits the implicit repetition -of the last non-empty expression list. -

    - - -

    Type declarations

    - -

    -A type declaration binds an identifier, the type name, to a type. -Type declarations come in two forms: alias declarations and type definitions. -

    - -
    -TypeDecl = "type" ( TypeSpec | "(" { TypeSpec ";" } ")" ) .
    -TypeSpec = AliasDecl | TypeDef .
    -
    - -

    Alias declarations

    - -

    -An alias declaration binds an identifier to the given type. -

    - -
    -AliasDecl = identifier "=" Type .
    -
    - -

    -Within the scope of -the identifier, it serves as an alias for the type. -

    - -
    -type (
    -	nodeList = []*Node  // nodeList and []*Node are identical types
    -	Polar    = polar    // Polar and polar denote identical types
    -)
    -
    - - -

    Type definitions

    - -

    -A type definition creates a new, distinct type with the same -underlying type and operations as the given type, -and binds an identifier to it. -

    - -
    -TypeDef = identifier Type .
    -
    - -

    -The new type is called a defined type. -It is different from any other type, -including the type it is created from. -

    - -
    -type (
    -	Point struct{ x, y float64 }  // Point and struct{ x, y float64 } are different types
    -	polar Point                   // polar and Point denote different types
    -)
    -
    -type TreeNode struct {
    -	left, right *TreeNode
    -	value *Comparable
    -}
    -
    -type Block interface {
    -	BlockSize() int
    -	Encrypt(src, dst []byte)
    -	Decrypt(src, dst []byte)
    -}
    -
    - -

    -A defined type may have methods associated with it. -It does not inherit any methods bound to the given type, -but the method set -of an interface type or of elements of a composite type remains unchanged: -

    - -
    -// A Mutex is a data type with two methods, Lock and Unlock.
    -type Mutex struct         { /* Mutex fields */ }
    -func (m *Mutex) Lock()    { /* Lock implementation */ }
    -func (m *Mutex) Unlock()  { /* Unlock implementation */ }
    -
    -// NewMutex has the same composition as Mutex but its method set is empty.
    -type NewMutex Mutex
    -
    -// The method set of PtrMutex's underlying type *Mutex remains unchanged,
    -// but the method set of PtrMutex is empty.
    -type PtrMutex *Mutex
    -
    -// The method set of *PrintableMutex contains the methods
    -// Lock and Unlock bound to its embedded field Mutex.
    -type PrintableMutex struct {
    -	Mutex
    -}
    -
    -// MyBlock is an interface type that has the same method set as Block.
    -type MyBlock Block
    -
    - -

    -Type definitions may be used to define different boolean, numeric, -or string types and associate methods with them: -

    - -
    -type TimeZone int
    -
    -const (
    -	EST TimeZone = -(5 + iota)
    -	CST
    -	MST
    -	PST
    -)
    -
    -func (tz TimeZone) String() string {
    -	return fmt.Sprintf("GMT%+dh", tz)
    -}
    -
    - - -

    Variable declarations

    - -

    -A variable declaration creates one or more variables, -binds corresponding identifiers to them, and gives each a type and an initial value. -

    - -
    -VarDecl     = "var" ( VarSpec | "(" { VarSpec ";" } ")" ) .
    -VarSpec     = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList ) .
    -
    - -
    -var i int
    -var U, V, W float64
    -var k = 0
    -var x, y float32 = -1, -2
    -var (
    -	i       int
    -	u, v, s = 2.0, 3.0, "bar"
    -)
    -var re, im = complexSqrt(-1)
    -var _, found = entries[name]  // map lookup; only interested in "found"
    -
    - -

    -If a list of expressions is given, the variables are initialized -with the expressions following the rules for assignments. -Otherwise, each variable is initialized to its zero value. -

    - -

    -If a type is present, each variable is given that type. -Otherwise, each variable is given the type of the corresponding -initialization value in the assignment. -If that value is an untyped constant, it is first implicitly -converted to its default type; -if it is an untyped boolean value, it is first implicitly converted to type bool. -The predeclared value nil cannot be used to initialize a variable -with no explicit type. -

    - -
    -var d = math.Sin(0.5)  // d is float64
    -var i = 42             // i is int
    -var t, ok = x.(T)      // t is T, ok is bool
    -var n = nil            // illegal
    -
    - -

    -Implementation restriction: A compiler may make it illegal to declare a variable -inside a function body if the variable is -never used. -

    - -

    Short variable declarations

    - -

    -A short variable declaration uses the syntax: -

    - -
    -ShortVarDecl = IdentifierList ":=" ExpressionList .
    -
    - -

    -It is shorthand for a regular variable declaration -with initializer expressions but no types: -

    - -
    -"var" IdentifierList = ExpressionList .
    -
    - -
    -i, j := 0, 10
    -f := func() int { return 7 }
    -ch := make(chan int)
    -r, w, _ := os.Pipe()  // os.Pipe() returns a connected pair of Files and an error, if any
    -_, y, _ := coord(p)   // coord() returns three values; only interested in y coordinate
    -
    - -

    -Unlike regular variable declarations, a short variable declaration may redeclare -variables provided they were originally declared earlier in the same block -(or the parameter lists if the block is the function body) with the same type, -and at least one of the non-blank variables is new. -As a consequence, redeclaration can only appear in a multi-variable short declaration. -Redeclaration does not introduce a new variable; it just assigns a new value to the original. -

    - -
    -field1, offset := nextField(str, 0)
    -field2, offset := nextField(str, offset)  // redeclares offset
    -a, a := 1, 2                              // illegal: double declaration of a or no new variable if a was declared elsewhere
    -
    - -

    -Short variable declarations may appear only inside functions. -In some contexts such as the initializers for -"if", -"for", or -"switch" statements, -they can be used to declare local temporary variables. -

    - -

    Function declarations

    - -

    -A function declaration binds an identifier, the function name, -to a function. -

    - -
    -FunctionDecl = "func" FunctionName Signature [ FunctionBody ] .
    -FunctionName = identifier .
    -FunctionBody = Block .
    -
    - -

    -If the function's signature declares -result parameters, the function body's statement list must end in -a terminating statement. -

    - -
    -func IndexRune(s string, r rune) int {
    -	for i, c := range s {
    -		if c == r {
    -			return i
    -		}
    -	}
    -	// invalid: missing return statement
    -}
    -
    - -

    -A function declaration may omit the body. Such a declaration provides the -signature for a function implemented outside Go, such as an assembly routine. -

    - -
    -func min(x int, y int) int {
    -	if x < y {
    -		return x
    -	}
    -	return y
    -}
    -
    -func flushICache(begin, end uintptr)  // implemented externally
    -
    - -

    Method declarations

    - -

    -A method is a function with a receiver. -A method declaration binds an identifier, the method name, to a method, -and associates the method with the receiver's base type. -

    - -
    -MethodDecl = "func" Receiver MethodName Signature [ FunctionBody ] .
    -Receiver   = Parameters .
    -
    - -

    -The receiver is specified via an extra parameter section preceding the method -name. That parameter section must declare a single non-variadic parameter, the receiver. -Its type must be a defined type T or a -pointer to a defined type T. T is called the receiver -base type. A receiver base type cannot be a pointer or interface type and -it must be defined in the same package as the method. -The method is said to be bound to its receiver base type and the method name -is visible only within selectors for type T -or *T. -

    - -

    -A non-blank receiver identifier must be -unique in the method signature. -If the receiver's value is not referenced inside the body of the method, -its identifier may be omitted in the declaration. The same applies in -general to parameters of functions and methods. -

    - -

    -For a base type, the non-blank names of methods bound to it must be unique. -If the base type is a struct type, -the non-blank method and field names must be distinct. -

    - -

    -Given defined type Point, the declarations -

    - -
    -func (p *Point) Length() float64 {
    -	return math.Sqrt(p.x * p.x + p.y * p.y)
    -}
    -
    -func (p *Point) Scale(factor float64) {
    -	p.x *= factor
    -	p.y *= factor
    -}
    -
    - -

    -bind the methods Length and Scale, -with receiver type *Point, -to the base type Point. -

    - -

    -The type of a method is the type of a function with the receiver as first -argument. For instance, the method Scale has type -

    - -
    -func(p *Point, factor float64)
    -
    - -

    -However, a function declared this way is not a method. -

    - - -

    Expressions

    - -

    -An expression specifies the computation of a value by applying -operators and functions to operands. -

    - -

    Operands

    - -

    -Operands denote the elementary values in an expression. An operand may be a -literal, a (possibly qualified) -non-blank identifier denoting a -constant, -variable, or -function, -or a parenthesized expression. -

    - -

    -The blank identifier may appear as an -operand only on the left-hand side of an assignment. -

    - -
    -Operand     = Literal | OperandName | "(" Expression ")" .
    -Literal     = BasicLit | CompositeLit | FunctionLit .
    -BasicLit    = int_lit | float_lit | imaginary_lit | rune_lit | string_lit .
    -OperandName = identifier | QualifiedIdent .
    -
    - -

    Qualified identifiers

    - -

    -A qualified identifier is an identifier qualified with a package name prefix. -Both the package name and the identifier must not be -blank. -

    - -
    -QualifiedIdent = PackageName "." identifier .
    -
    - -

    -A qualified identifier accesses an identifier in a different package, which -must be imported. -The identifier must be exported and -declared in the package block of that package. -

    - -
    -math.Sin	// denotes the Sin function in package math
    -
    - -

    Composite literals

    - -

    -Composite literals construct values for structs, arrays, slices, and maps -and create a new value each time they are evaluated. -They consist of the type of the literal followed by a brace-bound list of elements. -Each element may optionally be preceded by a corresponding key. -

    - -
    -CompositeLit  = LiteralType LiteralValue .
    -LiteralType   = StructType | ArrayType | "[" "..." "]" ElementType |
    -                SliceType | MapType | TypeName .
    -LiteralValue  = "{" [ ElementList [ "," ] ] "}" .
    -ElementList   = KeyedElement { "," KeyedElement } .
    -KeyedElement  = [ Key ":" ] Element .
    -Key           = FieldName | Expression | LiteralValue .
    -FieldName     = identifier .
    -Element       = Expression | LiteralValue .
    -
    - -

    -The LiteralType's underlying type must be a struct, array, slice, or map type -(the grammar enforces this constraint except when the type is given -as a TypeName). -The types of the elements and keys must be assignable -to the respective field, element, and key types of the literal type; -there is no additional conversion. -The key is interpreted as a field name for struct literals, -an index for array and slice literals, and a key for map literals. -For map literals, all elements must have a key. It is an error -to specify multiple elements with the same field name or -constant key value. For non-constant map keys, see the section on -evaluation order. -

    - -

    -For struct literals the following rules apply: -

    -
      -
    • A key must be a field name declared in the struct type. -
    • -
    • An element list that does not contain any keys must - list an element for each struct field in the - order in which the fields are declared. -
    • -
    • If any element has a key, every element must have a key. -
    • -
    • An element list that contains keys does not need to - have an element for each struct field. Omitted fields - get the zero value for that field. -
    • -
    • A literal may omit the element list; such a literal evaluates - to the zero value for its type. -
    • -
    • It is an error to specify an element for a non-exported - field of a struct belonging to a different package. -
    • -
    - -

    -Given the declarations -

    -
    -type Point3D struct { x, y, z float64 }
    -type Line struct { p, q Point3D }
    -
    - -

    -one may write -

    - -
    -origin := Point3D{}                            // zero value for Point3D
    -line := Line{origin, Point3D{y: -4, z: 12.3}}  // zero value for line.q.x
    -
    - -

    -For array and slice literals the following rules apply: -

    -
      -
    • Each element has an associated integer index marking - its position in the array. -
    • -
    • An element with a key uses the key as its index. The - key must be a non-negative constant - representable by - a value of type int; and if it is typed - it must be of integer type. -
    • -
    • An element without a key uses the previous element's index plus one. - If the first element has no key, its index is zero. -
    • -
    - -

    -Taking the address of a composite literal -generates a pointer to a unique variable initialized -with the literal's value. -

    - -
    -var pointer *Point3D = &Point3D{y: 1000}
    -
    - -

    -Note that the zero value for a slice or map -type is not the same as an initialized but empty value of the same type. -Consequently, taking the address of an empty slice or map composite literal -does not have the same effect as allocating a new slice or map value with -new. -

    - -
    -p1 := &[]int{}    // p1 points to an initialized, empty slice with value []int{} and length 0
    -p2 := new([]int)  // p2 points to an uninitialized slice with value nil and length 0
    -
    - -

    -The length of an array literal is the length specified in the literal type. -If fewer elements than the length are provided in the literal, the missing -elements are set to the zero value for the array element type. -It is an error to provide elements with index values outside the index range -of the array. The notation ... specifies an array length equal -to the maximum element index plus one. -

    - -
    -buffer := [10]string{}             // len(buffer) == 10
    -intSet := [6]int{1, 2, 3, 5}       // len(intSet) == 6
    -days := [...]string{"Sat", "Sun"}  // len(days) == 2
    -
    - -

    -A slice literal describes the entire underlying array literal. -Thus the length and capacity of a slice literal are the maximum -element index plus one. A slice literal has the form -

    - -
    -[]T{x1, x2, … xn}
    -
    - -

    -and is shorthand for a slice operation applied to an array: -

    - -
    -tmp := [n]T{x1, x2, … xn}
    -tmp[0 : n]
    -
    - -

    -Within a composite literal of array, slice, or map type T, -elements or map keys that are themselves composite literals may elide the respective -literal type if it is identical to the element or key type of T. -Similarly, elements or keys that are addresses of composite literals may elide -the &T when the element or key type is *T. -

    - -
    -[...]Point{{1.5, -3.5}, {0, 0}}     // same as [...]Point{Point{1.5, -3.5}, Point{0, 0}}
    -[][]int{{1, 2, 3}, {4, 5}}          // same as [][]int{[]int{1, 2, 3}, []int{4, 5}}
    -[][]Point{{{0, 1}, {1, 2}}}         // same as [][]Point{[]Point{Point{0, 1}, Point{1, 2}}}
    -map[string]Point{"orig": {0, 0}}    // same as map[string]Point{"orig": Point{0, 0}}
    -map[Point]string{{0, 0}: "orig"}    // same as map[Point]string{Point{0, 0}: "orig"}
    -
    -type PPoint *Point
    -[2]*Point{{1.5, -3.5}, {}}          // same as [2]*Point{&Point{1.5, -3.5}, &Point{}}
    -[2]PPoint{{1.5, -3.5}, {}}          // same as [2]PPoint{PPoint(&Point{1.5, -3.5}), PPoint(&Point{})}
    -
    - -

    -A parsing ambiguity arises when a composite literal using the -TypeName form of the LiteralType appears as an operand between the -keyword and the opening brace of the block -of an "if", "for", or "switch" statement, and the composite literal -is not enclosed in parentheses, square brackets, or curly braces. -In this rare case, the opening brace of the literal is erroneously parsed -as the one introducing the block of statements. To resolve the ambiguity, -the composite literal must appear within parentheses. -

    - -
    -if x == (T{a,b,c}[i]) { … }
    -if (x == T{a,b,c}[i]) { … }
    -
    - -

    -Examples of valid array, slice, and map literals: -

    - -
    -// list of prime numbers
    -primes := []int{2, 3, 5, 7, 9, 2147483647}
    -
    -// vowels[ch] is true if ch is a vowel
    -vowels := [128]bool{'a': true, 'e': true, 'i': true, 'o': true, 'u': true, 'y': true}
    -
    -// the array [10]float32{-1, 0, 0, 0, -0.1, -0.1, 0, 0, 0, -1}
    -filter := [10]float32{-1, 4: -0.1, -0.1, 9: -1}
    -
    -// frequencies in Hz for equal-tempered scale (A4 = 440Hz)
    -noteFrequency := map[string]float32{
    -	"C0": 16.35, "D0": 18.35, "E0": 20.60, "F0": 21.83,
    -	"G0": 24.50, "A0": 27.50, "B0": 30.87,
    -}
    -
    - - -

    Function literals

    - -

    -A function literal represents an anonymous function. -

    - -
    -FunctionLit = "func" Signature FunctionBody .
    -
    - -
    -func(a, b int, z float64) bool { return a*b < int(z) }
    -
    - -

    -A function literal can be assigned to a variable or invoked directly. -

    - -
    -f := func(x, y int) int { return x + y }
    -func(ch chan int) { ch <- ACK }(replyChan)
    -
    - -

    -Function literals are closures: they may refer to variables -defined in a surrounding function. Those variables are then shared between -the surrounding function and the function literal, and they survive as long -as they are accessible. -

    - - -

    Primary expressions

    - -

    -Primary expressions are the operands for unary and binary expressions. -

    - -
    -PrimaryExpr =
    -	Operand |
    -	Conversion |
    -	MethodExpr |
    -	PrimaryExpr Selector |
    -	PrimaryExpr Index |
    -	PrimaryExpr Slice |
    -	PrimaryExpr TypeAssertion |
    -	PrimaryExpr Arguments .
    -
    -Selector       = "." identifier .
    -Index          = "[" Expression "]" .
    -Slice          = "[" [ Expression ] ":" [ Expression ] "]" |
    -                 "[" [ Expression ] ":" Expression ":" Expression "]" .
    -TypeAssertion  = "." "(" Type ")" .
    -Arguments      = "(" [ ( ExpressionList | Type [ "," ExpressionList ] ) [ "..." ] [ "," ] ] ")" .
    -
    - - -
    -x
    -2
    -(s + ".txt")
    -f(3.1415, true)
    -Point{1, 2}
    -m["foo"]
    -s[i : j + 1]
    -obj.color
    -f.p[i].x()
    -
    - - -

    Selectors

    - -

    -For a primary expression x -that is not a package name, the -selector expression -

    - -
    -x.f
    -
    - -

    -denotes the field or method f of the value x -(or sometimes *x; see below). -The identifier f is called the (field or method) selector; -it must not be the blank identifier. -The type of the selector expression is the type of f. -If x is a package name, see the section on -qualified identifiers. -

    - -

    -A selector f may denote a field or method f of -a type T, or it may refer -to a field or method f of a nested -embedded field of T. -The number of embedded fields traversed -to reach f is called its depth in T. -The depth of a field or method f -declared in T is zero. -The depth of a field or method f declared in -an embedded field A in T is the -depth of f in A plus one. -

    - -

    -The following rules apply to selectors: -

    - -
      -
    1. -For a value x of type T or *T -where T is not a pointer or interface type, -x.f denotes the field or method at the shallowest depth -in T where there -is such an f. -If there is not exactly one f -with shallowest depth, the selector expression is illegal. -
    2. - -
    3. -For a value x of type I where I -is an interface type, x.f denotes the actual method with name -f of the dynamic value of x. -If there is no method with name f in the -method set of I, the selector -expression is illegal. -
    4. - -
    5. -As an exception, if the type of x is a defined -pointer type and (*x).f is a valid selector expression denoting a field -(but not a method), x.f is shorthand for (*x).f. -
    6. - -
    7. -In all other cases, x.f is illegal. -
    8. - -
    9. -If x is of pointer type and has the value -nil and x.f denotes a struct field, -assigning to or evaluating x.f -causes a run-time panic. -
    10. - -
    11. -If x is of interface type and has the value -nil, calling or -evaluating the method x.f -causes a run-time panic. -
    12. -
    - -

    -For example, given the declarations: -

    - -
    -type T0 struct {
    -	x int
    -}
    -
    -func (*T0) M0()
    -
    -type T1 struct {
    -	y int
    -}
    -
    -func (T1) M1()
    -
    -type T2 struct {
    -	z int
    -	T1
    -	*T0
    -}
    -
    -func (*T2) M2()
    -
    -type Q *T2
    -
    -var t T2     // with t.T0 != nil
    -var p *T2    // with p != nil and (*p).T0 != nil
    -var q Q = p
    -
    - -

    -one may write: -

    - -
    -t.z          // t.z
    -t.y          // t.T1.y
    -t.x          // (*t.T0).x
    -
    -p.z          // (*p).z
    -p.y          // (*p).T1.y
    -p.x          // (*(*p).T0).x
    -
    -q.x          // (*(*q).T0).x        (*q).x is a valid field selector
    -
    -p.M0()       // ((*p).T0).M0()      M0 expects *T0 receiver
    -p.M1()       // ((*p).T1).M1()      M1 expects T1 receiver
    -p.M2()       // p.M2()              M2 expects *T2 receiver
    -t.M2()       // (&t).M2()           M2 expects *T2 receiver, see section on Calls
    -
    - -

    -but the following is invalid: -

    - -
    -q.M0()       // (*q).M0 is valid but not a field selector
    -
    - - -

    Method expressions

    - -

    -If M is in the method set of type T, -T.M is a function that is callable as a regular function -with the same arguments as M prefixed by an additional -argument that is the receiver of the method. -

    - -
    -MethodExpr    = ReceiverType "." MethodName .
    -ReceiverType  = Type .
    -
    - -

    -Consider a struct type T with two methods, -Mv, whose receiver is of type T, and -Mp, whose receiver is of type *T. -

    - -
    -type T struct {
    -	a int
    -}
    -func (tv  T) Mv(a int) int         { return 0 }  // value receiver
    -func (tp *T) Mp(f float32) float32 { return 1 }  // pointer receiver
    -
    -var t T
    -
    - -

    -The expression -

    - -
    -T.Mv
    -
    - -

    -yields a function equivalent to Mv but -with an explicit receiver as its first argument; it has signature -

    - -
    -func(tv T, a int) int
    -
    - -

    -That function may be called normally with an explicit receiver, so -these five invocations are equivalent: -

    - -
    -t.Mv(7)
    -T.Mv(t, 7)
    -(T).Mv(t, 7)
    -f1 := T.Mv; f1(t, 7)
    -f2 := (T).Mv; f2(t, 7)
    -
    - -

    -Similarly, the expression -

    - -
    -(*T).Mp
    -
    - -

    -yields a function value representing Mp with signature -

    - -
    -func(tp *T, f float32) float32
    -
    - -

    -For a method with a value receiver, one can derive a function -with an explicit pointer receiver, so -

    - -
    -(*T).Mv
    -
    - -

    -yields a function value representing Mv with signature -

    - -
    -func(tv *T, a int) int
    -
    - -

    -Such a function indirects through the receiver to create a value -to pass as the receiver to the underlying method; -the method does not overwrite the value whose address is passed in -the function call. -

    - -

    -The final case, a value-receiver function for a pointer-receiver method, -is illegal because pointer-receiver methods are not in the method set -of the value type. -

    - -

    -Function values derived from methods are called with function call syntax; -the receiver is provided as the first argument to the call. -That is, given f := T.Mv, f is invoked -as f(t, 7) not t.f(7). -To construct a function that binds the receiver, use a -function literal or -method value. -

    - -

    -It is legal to derive a function value from a method of an interface type. -The resulting function takes an explicit receiver of that interface type. -

    - -

    Method values

    - -

    -If the expression x has static type T and -M is in the method set of type T, -x.M is called a method value. -The method value x.M is a function value that is callable -with the same arguments as a method call of x.M. -The expression x is evaluated and saved during the evaluation of the -method value; the saved copy is then used as the receiver in any calls, -which may be executed later. -

    - -
    -type S struct { *T }
    -type T int
    -func (t T) M() { print(t) }
    -
    -t := new(T)
    -s := S{T: t}
    -f := t.M                    // receiver *t is evaluated and stored in f
    -g := s.M                    // receiver *(s.T) is evaluated and stored in g
    -*t = 42                     // does not affect stored receivers in f and g
    -
    - -

    -The type T may be an interface or non-interface type. -

    - -

    -As in the discussion of method expressions above, -consider a struct type T with two methods, -Mv, whose receiver is of type T, and -Mp, whose receiver is of type *T. -

    - -
    -type T struct {
    -	a int
    -}
    -func (tv  T) Mv(a int) int         { return 0 }  // value receiver
    -func (tp *T) Mp(f float32) float32 { return 1 }  // pointer receiver
    -
    -var t T
    -var pt *T
    -func makeT() T
    -
    - -

    -The expression -

    - -
    -t.Mv
    -
    - -

    -yields a function value of type -

    - -
    -func(int) int
    -
    - -

    -These two invocations are equivalent: -

    - -
    -t.Mv(7)
    -f := t.Mv; f(7)
    -
    - -

    -Similarly, the expression -

    - -
    -pt.Mp
    -
    - -

    -yields a function value of type -

    - -
    -func(float32) float32
    -
    - -

    -As with selectors, a reference to a non-interface method with a value receiver -using a pointer will automatically dereference that pointer: pt.Mv is equivalent to (*pt).Mv. -

    - -

    -As with method calls, a reference to a non-interface method with a pointer receiver -using an addressable value will automatically take the address of that value: t.Mp is equivalent to (&t).Mp. -

    - -
    -f := t.Mv; f(7)   // like t.Mv(7)
    -f := pt.Mp; f(7)  // like pt.Mp(7)
    -f := pt.Mv; f(7)  // like (*pt).Mv(7)
    -f := t.Mp; f(7)   // like (&t).Mp(7)
    -f := makeT().Mp   // invalid: result of makeT() is not addressable
    -
    - -

    -Although the examples above use non-interface types, it is also legal to create a method value -from a value of interface type. -

    - -
    -var i interface { M(int) } = myVal
    -f := i.M; f(7)  // like i.M(7)
    -
    - - -

    Index expressions

    - -

    -A primary expression of the form -

    - -
    -a[x]
    -
    - -

    -denotes the element of the array, pointer to array, slice, string or map a indexed by x. -The value x is called the index or map key, respectively. -The following rules apply: -

    - -

    -If a is not a map: -

    -
      -
    • the index x must be of integer type or an untyped constant
    • -
    • a constant index must be non-negative and - representable by a value of type int
    • -
    • a constant index that is untyped is given type int
    • -
    • the index x is in range if 0 <= x < len(a), - otherwise it is out of range
    • -
    - -

    -For a of array type A: -

    -
      -
    • a constant index must be in range
    • -
    • if x is out of range at run time, - a run-time panic occurs
    • -
    • a[x] is the array element at index x and the type of - a[x] is the element type of A
    • -
    - -

    -For a of pointer to array type: -

    -
      -
    • a[x] is shorthand for (*a)[x]
    • -
    - -

    -For a of slice type S: -

    -
      -
    • if x is out of range at run time, - a run-time panic occurs
    • -
    • a[x] is the slice element at index x and the type of - a[x] is the element type of S
    • -
    - -

    -For a of string type: -

    -
      -
    • a constant index must be in range - if the string a is also constant
    • -
    • if x is out of range at run time, - a run-time panic occurs
    • -
    • a[x] is the non-constant byte value at index x and the type of - a[x] is byte
    • -
    • a[x] may not be assigned to
    • -
    - -

    -For a of map type M: -

    -
      -
    • x's type must be - assignable - to the key type of M
    • -
    • if the map contains an entry with key x, - a[x] is the map element with key x - and the type of a[x] is the element type of M
    • -
    • if the map is nil or does not contain such an entry, - a[x] is the zero value - for the element type of M
    • -
    - -

    -Otherwise a[x] is illegal. -

    - -

    -An index expression on a map a of type map[K]V -used in an assignment or initialization of the special form -

    - -
    -v, ok = a[x]
    -v, ok := a[x]
    -var v, ok = a[x]
    -
    - -

    -yields an additional untyped boolean value. The value of ok is -true if the key x is present in the map, and -false otherwise. -

    - -

    -Assigning to an element of a nil map causes a -run-time panic. -

    - - -

    Slice expressions

    - -

    -Slice expressions construct a substring or slice from a string, array, pointer -to array, or slice. There are two variants: a simple form that specifies a low -and high bound, and a full form that also specifies a bound on the capacity. -

    - -

    Simple slice expressions

    - -

    -For a string, array, pointer to array, or slice a, the primary expression -

    - -
    -a[low : high]
    -
    - -

    -constructs a substring or slice. The indices low and -high select which elements of operand a appear -in the result. The result has indices starting at 0 and length equal to -high - low. -After slicing the array a -

    - -
    -a := [5]int{1, 2, 3, 4, 5}
    -s := a[1:4]
    -
    - -

    -the slice s has type []int, length 3, capacity 4, and elements -

    - -
    -s[0] == 2
    -s[1] == 3
    -s[2] == 4
    -
    - -

    -For convenience, any of the indices may be omitted. A missing low -index defaults to zero; a missing high index defaults to the length of the -sliced operand: -

    - -
    -a[2:]  // same as a[2 : len(a)]
    -a[:3]  // same as a[0 : 3]
    -a[:]   // same as a[0 : len(a)]
    -
    - -

    -If a is a pointer to an array, a[low : high] is shorthand for -(*a)[low : high]. -

    - -

    -For arrays or strings, the indices are in range if -0 <= low <= high <= len(a), -otherwise they are out of range. -For slices, the upper index bound is the slice capacity cap(a) rather than the length. -A constant index must be non-negative and -representable by a value of type -int; for arrays or constant strings, constant indices must also be in range. -If both indices are constant, they must satisfy low <= high. -If the indices are out of range at run time, a run-time panic occurs. -

    - -

    -Except for untyped strings, if the sliced operand is a string or slice, -the result of the slice operation is a non-constant value of the same type as the operand. -For untyped string operands the result is a non-constant value of type string. -If the sliced operand is an array, it must be addressable -and the result of the slice operation is a slice with the same element type as the array. -

    - -

    -If the sliced operand of a valid slice expression is a nil slice, the result -is a nil slice. Otherwise, if the result is a slice, it shares its underlying -array with the operand. -

    - -
    -var a [10]int
    -s1 := a[3:7]   // underlying array of s1 is array a; &s1[2] == &a[5]
    -s2 := s1[1:4]  // underlying array of s2 is underlying array of s1 which is array a; &s2[1] == &a[5]
    -s2[1] = 42     // s2[1] == s1[2] == a[5] == 42; they all refer to the same underlying array element
    -
    - - -

    Full slice expressions

    - -

    -For an array, pointer to array, or slice a (but not a string), the primary expression -

    - -
    -a[low : high : max]
    -
    - -

    -constructs a slice of the same type, and with the same length and elements as the simple slice -expression a[low : high]. Additionally, it controls the resulting slice's capacity -by setting it to max - low. Only the first index may be omitted; it defaults to 0. -After slicing the array a -

    - -
    -a := [5]int{1, 2, 3, 4, 5}
    -t := a[1:3:5]
    -
    - -

    -the slice t has type []int, length 2, capacity 4, and elements -

    - -
    -t[0] == 2
    -t[1] == 3
    -
    - -

    -As for simple slice expressions, if a is a pointer to an array, -a[low : high : max] is shorthand for (*a)[low : high : max]. -If the sliced operand is an array, it must be addressable. -

    - -

    -The indices are in range if 0 <= low <= high <= max <= cap(a), -otherwise they are out of range. -A constant index must be non-negative and -representable by a value of type -int; for arrays, constant indices must also be in range. -If multiple indices are constant, the constants that are present must be in range relative to each -other. -If the indices are out of range at run time, a run-time panic occurs. -

    - -

    Type assertions

    - -

    -For an expression x of interface type -and a type T, the primary expression -

    - -
    -x.(T)
    -
    - -

    -asserts that x is not nil -and that the value stored in x is of type T. -The notation x.(T) is called a type assertion. -

    -

    -More precisely, if T is not an interface type, x.(T) asserts -that the dynamic type of x is identical -to the type T. -In this case, T must implement the (interface) type of x; -otherwise the type assertion is invalid since it is not possible for x -to store a value of type T. -If T is an interface type, x.(T) asserts that the dynamic type -of x implements the interface T. -

    -

    -If the type assertion holds, the value of the expression is the value -stored in x and its type is T. If the type assertion is false, -a run-time panic occurs. -In other words, even though the dynamic type of x -is known only at run time, the type of x.(T) is -known to be T in a correct program. -

    - -
    -var x interface{} = 7          // x has dynamic type int and value 7
    -i := x.(int)                   // i has type int and value 7
    -
    -type I interface { m() }
    -
    -func f(y I) {
    -	s := y.(string)        // illegal: string does not implement I (missing method m)
    -	r := y.(io.Reader)     // r has type io.Reader and the dynamic type of y must implement both I and io.Reader
    -	…
    -}
    -
    - -

    -A type assertion used in an assignment or initialization of the special form -

    - -
    -v, ok = x.(T)
    -v, ok := x.(T)
    -var v, ok = x.(T)
    -var v, ok interface{} = x.(T) // dynamic types of v and ok are T and bool
    -
    - -

    -yields an additional untyped boolean value. The value of ok is true -if the assertion holds. Otherwise it is false and the value of v is -the zero value for type T. -No run-time panic occurs in this case. -

    - - -

    Calls

    - -

    -Given an expression f of function type -F, -

    - -
    -f(a1, a2, … an)
    -
    - -

    -calls f with arguments a1, a2, … an. -Except for one special case, arguments must be single-valued expressions -assignable to the parameter types of -F and are evaluated before the function is called. -The type of the expression is the result type -of F. -A method invocation is similar but the method itself -is specified as a selector upon a value of the receiver type for -the method. -

    - -
    -math.Atan2(x, y)  // function call
    -var pt *Point
    -pt.Scale(3.5)     // method call with receiver pt
    -
    - -

    -In a function call, the function value and arguments are evaluated in -the usual order. -After they are evaluated, the parameters of the call are passed by value to the function -and the called function begins execution. -The return parameters of the function are passed by value -back to the caller when the function returns. -

    - -

    -Calling a nil function value -causes a run-time panic. -

    - -

    -As a special case, if the return values of a function or method -g are equal in number and individually -assignable to the parameters of another function or method -f, then the call f(g(parameters_of_g)) -will invoke f after binding the return values of -g to the parameters of f in order. The call -of f must contain no parameters other than the call of g, -and g must have at least one return value. -If f has a final ... parameter, it is -assigned the return values of g that remain after -assignment of regular parameters. -

    - -
    -func Split(s string, pos int) (string, string) {
    -	return s[0:pos], s[pos:]
    -}
    -
    -func Join(s, t string) string {
    -	return s + t
    -}
    -
    -if Join(Split(value, len(value)/2)) != value {
    -	log.Panic("test fails")
    -}
    -
    - -

    -A method call x.m() is valid if the method set -of (the type of) x contains m and the -argument list can be assigned to the parameter list of m. -If x is addressable and &x's method -set contains m, x.m() is shorthand -for (&x).m(): -

    - -
    -var p Point
    -p.Scale(3.5)
    -
    - -

    -There is no distinct method type and there are no method literals. -

    - -

    Passing arguments to ... parameters

    - -

    -If f is variadic with a final -parameter p of type ...T, then within f -the type of p is equivalent to type []T. -If f is invoked with no actual arguments for p, -the value passed to p is nil. -Otherwise, the value passed is a new slice -of type []T with a new underlying array whose successive elements -are the actual arguments, which all must be assignable -to T. The length and capacity of the slice is therefore -the number of arguments bound to p and may differ for each -call site. -

    - -

    -Given the function and calls -

    -
    -func Greeting(prefix string, who ...string)
    -Greeting("nobody")
    -Greeting("hello:", "Joe", "Anna", "Eileen")
    -
    - -

    -within Greeting, who will have the value -nil in the first call, and -[]string{"Joe", "Anna", "Eileen"} in the second. -

    - -

    -If the final argument is assignable to a slice type []T and -is followed by ..., it is passed unchanged as the value -for a ...T parameter. In this case no new slice is created. -

    - -

    -Given the slice s and call -

    - -
    -s := []string{"James", "Jasmine"}
    -Greeting("goodbye:", s...)
    -
    - -

    -within Greeting, who will have the same value as s -with the same underlying array. -

    - - -

    Operators

    - -

    -Operators combine operands into expressions. -

    - -
    -Expression = UnaryExpr | Expression binary_op Expression .
    -UnaryExpr  = PrimaryExpr | unary_op UnaryExpr .
    -
    -binary_op  = "||" | "&&" | rel_op | add_op | mul_op .
    -rel_op     = "==" | "!=" | "<" | "<=" | ">" | ">=" .
    -add_op     = "+" | "-" | "|" | "^" .
    -mul_op     = "*" | "/" | "%" | "<<" | ">>" | "&" | "&^" .
    -
    -unary_op   = "+" | "-" | "!" | "^" | "*" | "&" | "<-" .
    -
    - -

    -Comparisons are discussed elsewhere. -For other binary operators, the operand types must be identical -unless the operation involves shifts or untyped constants. -For operations involving constants only, see the section on -constant expressions. -

    - -

    -Except for shift operations, if one operand is an untyped constant -and the other operand is not, the constant is implicitly converted -to the type of the other operand. -

    - -

    -The right operand in a shift expression must have integer type -or be an untyped constant representable by a -value of type uint. -If the left operand of a non-constant shift expression is an untyped constant, -it is first implicitly converted to the type it would assume if the shift expression were -replaced by its left operand alone. -

    - -
    -var a [1024]byte
    -var s uint = 33
    -
    -// The results of the following examples are given for 64-bit ints.
    -var i = 1<<s                   // 1 has type int
    -var j int32 = 1<<s             // 1 has type int32; j == 0
    -var k = uint64(1<<s)           // 1 has type uint64; k == 1<<33
    -var m int = 1.0<<s             // 1.0 has type int; m == 1<<33
    -var n = 1.0<<s == j            // 1.0 has type int32; n == true
    -var o = 1<<s == 2<<s           // 1 and 2 have type int; o == false
    -var p = 1<<s == 1<<33          // 1 has type int; p == true
    -var u = 1.0<<s                 // illegal: 1.0 has type float64, cannot shift
    -var u1 = 1.0<<s != 0           // illegal: 1.0 has type float64, cannot shift
    -var u2 = 1<<s != 1.0           // illegal: 1 has type float64, cannot shift
    -var v float32 = 1<<s           // illegal: 1 has type float32, cannot shift
    -var w int64 = 1.0<<33          // 1.0<<33 is a constant shift expression; w == 1<<33
    -var x = a[1.0<<s]              // panics: 1.0 has type int, but 1<<33 overflows array bounds
    -var b = make([]byte, 1.0<<s)   // 1.0 has type int; len(b) == 1<<33
    -
    -// The results of the following examples are given for 32-bit ints,
    -// which means the shifts will overflow.
    -var mm int = 1.0<<s            // 1.0 has type int; mm == 0
    -var oo = 1<<s == 2<<s          // 1 and 2 have type int; oo == true
    -var pp = 1<<s == 1<<33         // illegal: 1 has type int, but 1<<33 overflows int
    -var xx = a[1.0<<s]             // 1.0 has type int; xx == a[0]
    -var bb = make([]byte, 1.0<<s)  // 1.0 has type int; len(bb) == 0
    -
    - -

    Operator precedence

    -

    -Unary operators have the highest precedence. -As the ++ and -- operators form -statements, not expressions, they fall -outside the operator hierarchy. -As a consequence, statement *p++ is the same as (*p)++. -

    - -

    -There are five precedence levels for binary operators. -Multiplication operators bind strongest, followed by addition -operators, comparison operators, && (logical AND), -and finally || (logical OR): -

    - -
    -Precedence    Operator
    -    5             *  /  %  <<  >>  &  &^
    -    4             +  -  |  ^
    -    3             ==  !=  <  <=  >  >=
    -    2             &&
    -    1             ||
    -
    - -

    -Binary operators of the same precedence associate from left to right. -For instance, x / y * z is the same as (x / y) * z. -

    - -
    -+x
    -23 + 3*x[i]
    -x <= f()
    -^a >> b
    -f() || g()
    -x == y+1 && <-chanInt > 0
    -
    - - -

    Arithmetic operators

    -

    -Arithmetic operators apply to numeric values and yield a result of the same -type as the first operand. The four standard arithmetic operators (+, --, *, /) apply to integer, -floating-point, and complex types; + also applies to strings. -The bitwise logical and shift operators apply to integers only. -

    - -
    -+    sum                    integers, floats, complex values, strings
    --    difference             integers, floats, complex values
    -*    product                integers, floats, complex values
    -/    quotient               integers, floats, complex values
    -%    remainder              integers
    -
    -&    bitwise AND            integers
    -|    bitwise OR             integers
    -^    bitwise XOR            integers
    -&^   bit clear (AND NOT)    integers
    -
    -<<   left shift             integer << integer >= 0
    ->>   right shift            integer >> integer >= 0
    -
    - - -

    Integer operators

    - -

    -For two integer values x and y, the integer quotient -q = x / y and remainder r = x % y satisfy the following -relationships: -

    - -
    -x = q*y + r  and  |r| < |y|
    -
    - -

    -with x / y truncated towards zero -("truncated division"). -

    - -
    - x     y     x / y     x % y
    - 5     3       1         2
    --5     3      -1        -2
    - 5    -3      -1         2
    --5    -3       1        -2
    -
    - -

    -The one exception to this rule is that if the dividend x is -the most negative value for the int type of x, the quotient -q = x / -1 is equal to x (and r = 0) -due to two's-complement integer overflow: -

    - -
    -			 x, q
    -int8                     -128
    -int16                  -32768
    -int32             -2147483648
    -int64    -9223372036854775808
    -
    - -

    -If the divisor is a constant, it must not be zero. -If the divisor is zero at run time, a run-time panic occurs. -If the dividend is non-negative and the divisor is a constant power of 2, -the division may be replaced by a right shift, and computing the remainder may -be replaced by a bitwise AND operation: -

    - -
    - x     x / 4     x % 4     x >> 2     x & 3
    - 11      2         3         2          3
    --11     -2        -3        -3          1
    -
    - -

    -The shift operators shift the left operand by the shift count specified by the -right operand, which must be non-negative. If the shift count is negative at run time, -a run-time panic occurs. -The shift operators implement arithmetic shifts if the left operand is a signed -integer and logical shifts if it is an unsigned integer. -There is no upper limit on the shift count. Shifts behave -as if the left operand is shifted n times by 1 for a shift -count of n. -As a result, x << 1 is the same as x*2 -and x >> 1 is the same as -x/2 but truncated towards negative infinity. -

    - -

    -For integer operands, the unary operators -+, -, and ^ are defined as -follows: -

    - -
    -+x                          is 0 + x
    --x    negation              is 0 - x
    -^x    bitwise complement    is m ^ x  with m = "all bits set to 1" for unsigned x
    -                                      and  m = -1 for signed x
    -
    - - -

    Integer overflow

    - -

    -For unsigned integer values, the operations +, --, *, and << are -computed modulo 2n, where n is the bit width of -the unsigned integer's type. -Loosely speaking, these unsigned integer operations -discard high bits upon overflow, and programs may rely on "wrap around". -

    -

    -For signed integers, the operations +, --, *, /, and << may legally -overflow and the resulting value exists and is deterministically defined -by the signed integer representation, the operation, and its operands. -Overflow does not cause a run-time panic. -A compiler may not optimize code under the assumption that overflow does -not occur. For instance, it may not assume that x < x + 1 is always true. -

    - - -

    Floating-point operators

    - -

    -For floating-point and complex numbers, -+x is the same as x, -while -x is the negation of x. -The result of a floating-point or complex division by zero is not specified beyond the -IEEE 754 standard; whether a run-time panic -occurs is implementation-specific. -

    - -

    -An implementation may combine multiple floating-point operations into a single -fused operation, possibly across statements, and produce a result that differs -from the value obtained by executing and rounding the instructions individually. -An explicit floating-point type conversion rounds to -the precision of the target type, preventing fusion that would discard that rounding. -

    - -

    -For instance, some architectures provide a "fused multiply and add" (FMA) instruction -that computes x*y + z without rounding the intermediate result x*y. -These examples show when a Go implementation can use that instruction: -

    - -
    -// FMA allowed for computing r, because x*y is not explicitly rounded:
    -r  = x*y + z
    -r  = z;   r += x*y
    -t  = x*y; r = t + z
    -*p = x*y; r = *p + z
    -r  = x*y + float64(z)
    -
    -// FMA disallowed for computing r, because it would omit rounding of x*y:
    -r  = float64(x*y) + z
    -r  = z; r += float64(x*y)
    -t  = float64(x*y); r = t + z
    -
    - -

    String concatenation

    - -

    -Strings can be concatenated using the + operator -or the += assignment operator: -

    - -
    -s := "hi" + string(c)
    -s += " and good bye"
    -
    - -

    -String addition creates a new string by concatenating the operands. -

    - - -

    Comparison operators

    - -

    -Comparison operators compare two operands and yield an untyped boolean value. -

    - -
    -==    equal
    -!=    not equal
    -<     less
    -<=    less or equal
    ->     greater
    ->=    greater or equal
    -
    - -

    -In any comparison, the first operand -must be assignable -to the type of the second operand, or vice versa. -

    -

    -The equality operators == and != apply -to operands that are comparable. -The ordering operators <, <=, >, and >= -apply to operands that are ordered. -These terms and the result of the comparisons are defined as follows: -

    - -
      -
    • - Boolean values are comparable. - Two boolean values are equal if they are either both - true or both false. -
    • - -
    • - Integer values are comparable and ordered, in the usual way. -
    • - -
    • - Floating-point values are comparable and ordered, - as defined by the IEEE 754 standard. -
    • - -
    • - Complex values are comparable. - Two complex values u and v are - equal if both real(u) == real(v) and - imag(u) == imag(v). -
    • - -
    • - String values are comparable and ordered, lexically byte-wise. -
    • - -
    • - Pointer values are comparable. - Two pointer values are equal if they point to the same variable or if both have value nil. - Pointers to distinct zero-size variables may or may not be equal. -
    • - -
    • - Channel values are comparable. - Two channel values are equal if they were created by the same call to - make - or if both have value nil. -
    • - -
    • - Interface values are comparable. - Two interface values are equal if they have identical dynamic types - and equal dynamic values or if both have value nil. -
    • - -
    • - A value x of non-interface type X and - a value t of interface type T are comparable when values - of type X are comparable and - X implements T. - They are equal if t's dynamic type is identical to X - and t's dynamic value is equal to x. -
    • - -
    • - Struct values are comparable if all their fields are comparable. - Two struct values are equal if their corresponding - non-blank fields are equal. -
    • - -
    • - Array values are comparable if values of the array element type are comparable. - Two array values are equal if their corresponding elements are equal. -
    • -
    - -

    -A comparison of two interface values with identical dynamic types -causes a run-time panic if values -of that type are not comparable. This behavior applies not only to direct interface -value comparisons but also when comparing arrays of interface values -or structs with interface-valued fields. -

    - -

    -Slice, map, and function values are not comparable. -However, as a special case, a slice, map, or function value may -be compared to the predeclared identifier nil. -Comparison of pointer, channel, and interface values to nil -is also allowed and follows from the general rules above. -

    - -
    -const c = 3 < 4            // c is the untyped boolean constant true
    -
    -type MyBool bool
    -var x, y int
    -var (
    -	// The result of a comparison is an untyped boolean.
    -	// The usual assignment rules apply.
    -	b3        = x == y // b3 has type bool
    -	b4 bool   = x == y // b4 has type bool
    -	b5 MyBool = x == y // b5 has type MyBool
    -)
    -
    - -

    Logical operators

    - -

    -Logical operators apply to boolean values -and yield a result of the same type as the operands. -The right operand is evaluated conditionally. -

    - -
    -&&    conditional AND    p && q  is  "if p then q else false"
    -||    conditional OR     p || q  is  "if p then true else q"
    -!     NOT                !p      is  "not p"
    -
    - - -

    Address operators

    - -

    -For an operand x of type T, the address operation -&x generates a pointer of type *T to x. -The operand must be addressable, -that is, either a variable, pointer indirection, or slice indexing -operation; or a field selector of an addressable struct operand; -or an array indexing operation of an addressable array. -As an exception to the addressability requirement, x may also be a -(possibly parenthesized) -composite literal. -If the evaluation of x would cause a run-time panic, -then the evaluation of &x does too. -

    - -

    -For an operand x of pointer type *T, the pointer -indirection *x denotes the variable of type T pointed -to by x. -If x is nil, an attempt to evaluate *x -will cause a run-time panic. -

    - -
    -&x
    -&a[f(2)]
    -&Point{2, 3}
    -*p
    -*pf(x)
    -
    -var x *int = nil
    -*x   // causes a run-time panic
    -&*x  // causes a run-time panic
    -
    - - -

    Receive operator

    - -

    -For an operand ch of channel type, -the value of the receive operation <-ch is the value received -from the channel ch. The channel direction must permit receive operations, -and the type of the receive operation is the element type of the channel. -The expression blocks until a value is available. -Receiving from a nil channel blocks forever. -A receive operation on a closed channel can always proceed -immediately, yielding the element type's zero value -after any previously sent values have been received. -

    - -
    -v1 := <-ch
    -v2 = <-ch
    -f(<-ch)
    -<-strobe  // wait until clock pulse and discard received value
    -
    - -

    -A receive expression used in an assignment or initialization of the special form -

    - -
    -x, ok = <-ch
    -x, ok := <-ch
    -var x, ok = <-ch
    -var x, ok T = <-ch
    -
    - -

    -yields an additional untyped boolean result reporting whether the -communication succeeded. The value of ok is true -if the value received was delivered by a successful send operation to the -channel, or false if it is a zero value generated because the -channel is closed and empty. -

    - - -

    Conversions

    - -

    -A conversion changes the type of an expression -to the type specified by the conversion. -A conversion may appear literally in the source, or it may be implied -by the context in which an expression appears. -

    - -

    -An explicit conversion is an expression of the form T(x) -where T is a type and x is an expression -that can be converted to type T. -

    - -
    -Conversion = Type "(" Expression [ "," ] ")" .
    -
    - -

    -If the type starts with the operator * or <-, -or if the type starts with the keyword func -and has no result list, it must be parenthesized when -necessary to avoid ambiguity: -

    - -
    -*Point(p)        // same as *(Point(p))
    -(*Point)(p)      // p is converted to *Point
    -<-chan int(c)    // same as <-(chan int(c))
    -(<-chan int)(c)  // c is converted to <-chan int
    -func()(x)        // function signature func() x
    -(func())(x)      // x is converted to func()
    -(func() int)(x)  // x is converted to func() int
    -func() int(x)    // x is converted to func() int (unambiguous)
    -
    - -

    -A constant value x can be converted to -type T if x is representable -by a value of T. -As a special case, an integer constant x can be explicitly converted to a -string type using the -same rule -as for non-constant x. -

    - -

    -Converting a constant yields a typed constant as result. -

    - -
    -uint(iota)               // iota value of type uint
    -float32(2.718281828)     // 2.718281828 of type float32
    -complex128(1)            // 1.0 + 0.0i of type complex128
    -float32(0.49999999)      // 0.5 of type float32
    -float64(-1e-1000)        // 0.0 of type float64
    -string('x')              // "x" of type string
    -string(0x266c)           // "♬" of type string
    -MyString("foo" + "bar")  // "foobar" of type MyString
    -string([]byte{'a'})      // not a constant: []byte{'a'} is not a constant
    -(*int)(nil)              // not a constant: nil is not a constant, *int is not a boolean, numeric, or string type
    -int(1.2)                 // illegal: 1.2 cannot be represented as an int
    -string(65.0)             // illegal: 65.0 is not an integer constant
    -
    - -

    -A non-constant value x can be converted to type T -in any of these cases: -

    - -
      -
    • - x is assignable - to T. -
    • -
    • - ignoring struct tags (see below), - x's type and T have identical - underlying types. -
    • -
    • - ignoring struct tags (see below), - x's type and T are pointer types - that are not defined types, - and their pointer base types have identical underlying types. -
    • -
    • - x's type and T are both integer or floating - point types. -
    • -
    • - x's type and T are both complex types. -
    • -
    • - x is an integer or a slice of bytes or runes - and T is a string type. -
    • -
    • - x is a string and T is a slice of bytes or runes. -
    • -
    • - x is a slice, T is a pointer to an array, - and the slice and array types have identical element types. -
    • -
    - -

    -Struct tags are ignored when comparing struct types -for identity for the purpose of conversion: -

    - -
    -type Person struct {
    -	Name    string
    -	Address *struct {
    -		Street string
    -		City   string
    -	}
    -}
    -
    -var data *struct {
    -	Name    string `json:"name"`
    -	Address *struct {
    -		Street string `json:"street"`
    -		City   string `json:"city"`
    -	} `json:"address"`
    -}
    -
    -var person = (*Person)(data)  // ignoring tags, the underlying types are identical
    -
    - -

    -Specific rules apply to (non-constant) conversions between numeric types or -to and from a string type. -These conversions may change the representation of x -and incur a run-time cost. -All other conversions only change the type but not the representation -of x. -

    - -

    -There is no linguistic mechanism to convert between pointers and integers. -The package unsafe -implements this functionality under -restricted circumstances. -

    - -

    Conversions between numeric types

    - -

    -For the conversion of non-constant numeric values, the following rules apply: -

    - -
      -
    1. -When converting between integer types, if the value is a signed integer, it is -sign extended to implicit infinite precision; otherwise it is zero extended. -It is then truncated to fit in the result type's size. -For example, if v := uint16(0x10F0), then uint32(int8(v)) == 0xFFFFFFF0. -The conversion always yields a valid value; there is no indication of overflow. -
    2. -
    3. -When converting a floating-point number to an integer, the fraction is discarded -(truncation towards zero). -
    4. -
    5. -When converting an integer or floating-point number to a floating-point type, -or a complex number to another complex type, the result value is rounded -to the precision specified by the destination type. -For instance, the value of a variable x of type float32 -may be stored using additional precision beyond that of an IEEE 754 32-bit number, -but float32(x) represents the result of rounding x's value to -32-bit precision. Similarly, x + 0.1 may use more than 32 bits -of precision, but float32(x + 0.1) does not. -
    6. -
    - -

    -In all non-constant conversions involving floating-point or complex values, -if the result type cannot represent the value the conversion -succeeds but the result value is implementation-dependent. -

    - -

    Conversions to and from a string type

    - -
      -
    1. -Converting a signed or unsigned integer value to a string type yields a -string containing the UTF-8 representation of the integer. Values outside -the range of valid Unicode code points are converted to "\uFFFD". - -
      -string('a')       // "a"
      -string(-1)        // "\ufffd" == "\xef\xbf\xbd"
      -string(0xf8)      // "\u00f8" == "ø" == "\xc3\xb8"
      -type MyString string
      -MyString(0x65e5)  // "\u65e5" == "日" == "\xe6\x97\xa5"
      -
      -
    2. - -
    3. -Converting a slice of bytes to a string type yields -a string whose successive bytes are the elements of the slice. - -
      -string([]byte{'h', 'e', 'l', 'l', '\xc3', '\xb8'})   // "hellø"
      -string([]byte{})                                     // ""
      -string([]byte(nil))                                  // ""
      -
      -type MyBytes []byte
      -string(MyBytes{'h', 'e', 'l', 'l', '\xc3', '\xb8'})  // "hellø"
      -
      -
    4. - -
    5. -Converting a slice of runes to a string type yields -a string that is the concatenation of the individual rune values -converted to strings. - -
      -string([]rune{0x767d, 0x9d6c, 0x7fd4})   // "\u767d\u9d6c\u7fd4" == "白鵬翔"
      -string([]rune{})                         // ""
      -string([]rune(nil))                      // ""
      -
      -type MyRunes []rune
      -string(MyRunes{0x767d, 0x9d6c, 0x7fd4})  // "\u767d\u9d6c\u7fd4" == "白鵬翔"
      -
      -
    6. - -
    7. -Converting a value of a string type to a slice of bytes type -yields a slice whose successive elements are the bytes of the string. - -
      -[]byte("hellø")   // []byte{'h', 'e', 'l', 'l', '\xc3', '\xb8'}
      -[]byte("")        // []byte{}
      -
      -MyBytes("hellø")  // []byte{'h', 'e', 'l', 'l', '\xc3', '\xb8'}
      -
      -
    8. - -
    9. -Converting a value of a string type to a slice of runes type -yields a slice containing the individual Unicode code points of the string. - -
      -[]rune(MyString("白鵬翔"))  // []rune{0x767d, 0x9d6c, 0x7fd4}
      -[]rune("")                 // []rune{}
      -
      -MyRunes("白鵬翔")           // []rune{0x767d, 0x9d6c, 0x7fd4}
      -
      -
    10. -
    - -

    Conversions from slice to array pointer

    - -

    -Converting a slice to an array pointer yields a pointer to the underlying array of the slice. -If the length of the slice is less than the length of the array, -a run-time panic occurs. -

    - -
    -s := make([]byte, 2, 4)
    -s0 := (*[0]byte)(s)      // s0 != nil
    -s1 := (*[1]byte)(s[1:])  // &s1[0] == &s[1]
    -s2 := (*[2]byte)(s)      // &s2[0] == &s[0]
    -s4 := (*[4]byte)(s)      // panics: len([4]byte) > len(s)
    -
    -var t []string
    -t0 := (*[0]string)(t)    // t0 == nil
    -t1 := (*[1]string)(t)    // panics: len([1]string) > len(t)
    -
    -u := make([]byte, 0)
    -u0 := (*[0]byte)(u)      // u0 != nil
    -
    - -

    Constant expressions

    - -

    -Constant expressions may contain only constant -operands and are evaluated at compile time. -

    - -

    -Untyped boolean, numeric, and string constants may be used as operands -wherever it is legal to use an operand of boolean, numeric, or string type, -respectively. -

    - -

    -A constant comparison always yields -an untyped boolean constant. If the left operand of a constant -shift expression is an untyped constant, the -result is an integer constant; otherwise it is a constant of the same -type as the left operand, which must be of -integer type. -

    - -

    -Any other operation on untyped constants results in an untyped constant of the -same kind; that is, a boolean, integer, floating-point, complex, or string -constant. -If the untyped operands of a binary operation (other than a shift) are of -different kinds, the result is of the operand's kind that appears later in this -list: integer, rune, floating-point, complex. -For example, an untyped integer constant divided by an -untyped complex constant yields an untyped complex constant. -

    - -
    -const a = 2 + 3.0          // a == 5.0   (untyped floating-point constant)
    -const b = 15 / 4           // b == 3     (untyped integer constant)
    -const c = 15 / 4.0         // c == 3.75  (untyped floating-point constant)
    -const Θ float64 = 3/2      // Θ == 1.0   (type float64, 3/2 is integer division)
    -const Π float64 = 3/2.     // Π == 1.5   (type float64, 3/2. is float division)
    -const d = 1 << 3.0         // d == 8     (untyped integer constant)
    -const e = 1.0 << 3         // e == 8     (untyped integer constant)
    -const f = int32(1) << 33   // illegal    (constant 8589934592 overflows int32)
    -const g = float64(2) >> 1  // illegal    (float64(2) is a typed floating-point constant)
    -const h = "foo" > "bar"    // h == true  (untyped boolean constant)
    -const j = true             // j == true  (untyped boolean constant)
    -const k = 'w' + 1          // k == 'x'   (untyped rune constant)
    -const l = "hi"             // l == "hi"  (untyped string constant)
    -const m = string(k)        // m == "x"   (type string)
    -const Σ = 1 - 0.707i       //            (untyped complex constant)
    -const Δ = Σ + 2.0e-4       //            (untyped complex constant)
    -const Φ = iota*1i - 1/1i   //            (untyped complex constant)
    -
    - -

    -Applying the built-in function complex to untyped -integer, rune, or floating-point constants yields -an untyped complex constant. -

    - -
    -const ic = complex(0, c)   // ic == 3.75i  (untyped complex constant)
    -const iΘ = complex(0, Θ)   // iΘ == 1i     (type complex128)
    -
    - -

    -Constant expressions are always evaluated exactly; intermediate values and the -constants themselves may require precision significantly larger than supported -by any predeclared type in the language. The following are legal declarations: -

    - -
    -const Huge = 1 << 100         // Huge == 1267650600228229401496703205376  (untyped integer constant)
    -const Four int8 = Huge >> 98  // Four == 4                                (type int8)
    -
    - -

    -The divisor of a constant division or remainder operation must not be zero: -

    - -
    -3.14 / 0.0   // illegal: division by zero
    -
    - -

    -The values of typed constants must always be accurately -representable by values -of the constant type. The following constant expressions are illegal: -

    - -
    -uint(-1)     // -1 cannot be represented as a uint
    -int(3.14)    // 3.14 cannot be represented as an int
    -int64(Huge)  // 1267650600228229401496703205376 cannot be represented as an int64
    -Four * 300   // operand 300 cannot be represented as an int8 (type of Four)
    -Four * 100   // product 400 cannot be represented as an int8 (type of Four)
    -
    - -

    -The mask used by the unary bitwise complement operator ^ matches -the rule for non-constants: the mask is all 1s for unsigned constants -and -1 for signed and untyped constants. -

    - -
    -^1         // untyped integer constant, equal to -2
    -uint8(^1)  // illegal: same as uint8(-2), -2 cannot be represented as a uint8
    -^uint8(1)  // typed uint8 constant, same as 0xFF ^ uint8(1) = uint8(0xFE)
    -int8(^1)   // same as int8(-2)
    -^int8(1)   // same as -1 ^ int8(1) = -2
    -
    - -

    -Implementation restriction: A compiler may use rounding while -computing untyped floating-point or complex constant expressions; see -the implementation restriction in the section -on constants. This rounding may cause a -floating-point constant expression to be invalid in an integer -context, even if it would be integral when calculated using infinite -precision, and vice versa. -

    - - -

    Order of evaluation

    - -

    -At package level, initialization dependencies -determine the evaluation order of individual initialization expressions in -variable declarations. -Otherwise, when evaluating the operands of an -expression, assignment, or -return statement, -all function calls, method calls, and -communication operations are evaluated in lexical left-to-right -order. -

    - -

    -For example, in the (function-local) assignment -

    -
    -y[f()], ok = g(h(), i()+x[j()], <-c), k()
    -
    -

    -the function calls and communication happen in the order -f(), h(), i(), j(), -<-c, g(), and k(). -However, the order of those events compared to the evaluation -and indexing of x and the evaluation -of y is not specified. -

    - -
    -a := 1
    -f := func() int { a++; return a }
    -x := []int{a, f()}            // x may be [1, 2] or [2, 2]: evaluation order between a and f() is not specified
    -m := map[int]int{a: 1, a: 2}  // m may be {2: 1} or {2: 2}: evaluation order between the two map assignments is not specified
    -n := map[int]int{a: f()}      // n may be {2: 3} or {3: 3}: evaluation order between the key and the value is not specified
    -
    - -

    -At package level, initialization dependencies override the left-to-right rule -for individual initialization expressions, but not for operands within each -expression: -

    - -
    -var a, b, c = f() + v(), g(), sqr(u()) + v()
    -
    -func f() int        { return c }
    -func g() int        { return a }
    -func sqr(x int) int { return x*x }
    -
    -// functions u and v are independent of all other variables and functions
    -
    - -

    -The function calls happen in the order -u(), sqr(), v(), -f(), v(), and g(). -

    - -

    -Floating-point operations within a single expression are evaluated according to -the associativity of the operators. Explicit parentheses affect the evaluation -by overriding the default associativity. -In the expression x + (y + z) the addition y + z -is performed before adding x. -

    - -

    Statements

    - -

    -Statements control execution. -

    - -
    -Statement =
    -	Declaration | LabeledStmt | SimpleStmt |
    -	GoStmt | ReturnStmt | BreakStmt | ContinueStmt | GotoStmt |
    -	FallthroughStmt | Block | IfStmt | SwitchStmt | SelectStmt | ForStmt |
    -	DeferStmt .
    -
    -SimpleStmt = EmptyStmt | ExpressionStmt | SendStmt | IncDecStmt | Assignment | ShortVarDecl .
    -
    - -

    Terminating statements

    - -

    -A terminating statement interrupts the regular flow of control in -a block. The following statements are terminating: -

    - -
      -
    1. - A "return" or - "goto" statement. - -
      -
    2. - -
    3. - A call to the built-in function - panic. - -
      -
    4. - -
    5. - A block in which the statement list ends in a terminating statement. - -
      -
    6. - -
    7. - An "if" statement in which: -
        -
      • the "else" branch is present, and
      • -
      • both branches are terminating statements.
      • -
      -
    8. - -
    9. - A "for" statement in which: -
        -
      • there are no "break" statements referring to the "for" statement, and
      • -
      • the loop condition is absent, and
      • -
      • the "for" statement does not use a range clause.
      • -
      -
    10. - -
    11. - A "switch" statement in which: -
        -
      • there are no "break" statements referring to the "switch" statement,
      • -
      • there is a default case, and
      • -
      • the statement lists in each case, including the default, end in a terminating - statement, or a possibly labeled "fallthrough" - statement.
      • -
      -
    12. - -
    13. - A "select" statement in which: -
        -
      • there are no "break" statements referring to the "select" statement, and
      • -
      • the statement lists in each case, including the default if present, - end in a terminating statement.
      • -
      -
    14. - -
    15. - A labeled statement labeling - a terminating statement. -
    16. -
    - -

    -All other statements are not terminating. -

    - -

    -A statement list ends in a terminating statement if the list -is not empty and its final non-empty statement is terminating. -

    - - -

    Empty statements

    - -

    -The empty statement does nothing. -

    - -
    -EmptyStmt = .
    -
    - - -

    Labeled statements

    - -

    -A labeled statement may be the target of a goto, -break or continue statement. -

    - -
    -LabeledStmt = Label ":" Statement .
    -Label       = identifier .
    -
    - -
    -Error: log.Panic("error encountered")
    -
    - - -

    Expression statements

    - -

    -With the exception of specific built-in functions, -function and method calls and -receive operations -can appear in statement context. Such statements may be parenthesized. -

    - -
    -ExpressionStmt = Expression .
    -
    - -

    -The following built-in functions are not permitted in statement context: -

    - -
    -append cap complex imag len make new real
    -unsafe.Add unsafe.Alignof unsafe.Offsetof unsafe.Sizeof unsafe.Slice
    -
    - -
    -h(x+y)
    -f.Close()
    -<-ch
    -(<-ch)
    -len("foo")  // illegal if len is the built-in function
    -
    - - -

    Send statements

    - -

    -A send statement sends a value on a channel. -The channel expression must be of channel type, -the channel direction must permit send operations, -and the type of the value to be sent must be assignable -to the channel's element type. -

    - -
    -SendStmt = Channel "<-" Expression .
    -Channel  = Expression .
    -
    - -

    -Both the channel and the value expression are evaluated before communication -begins. Communication blocks until the send can proceed. -A send on an unbuffered channel can proceed if a receiver is ready. -A send on a buffered channel can proceed if there is room in the buffer. -A send on a closed channel proceeds by causing a run-time panic. -A send on a nil channel blocks forever. -

    - -
    -ch <- 3  // send value 3 to channel ch
    -
    - - -

    IncDec statements

    - -

    -The "++" and "--" statements increment or decrement their operands -by the untyped constant 1. -As with an assignment, the operand must be addressable -or a map index expression. -

    - -
    -IncDecStmt = Expression ( "++" | "--" ) .
    -
    - -

    -The following assignment statements are semantically -equivalent: -

    - -
    -IncDec statement    Assignment
    -x++                 x += 1
    -x--                 x -= 1
    -
    - - -

    Assignments

    - -
    -Assignment = ExpressionList assign_op ExpressionList .
    -
    -assign_op = [ add_op | mul_op ] "=" .
    -
    - -

    -Each left-hand side operand must be addressable, -a map index expression, or (for = assignments only) the -blank identifier. -Operands may be parenthesized. -

    - -
    -x = 1
    -*p = f()
    -a[i] = 23
    -(k) = <-ch  // same as: k = <-ch
    -
    - -

    -An assignment operation x op= -y where op is a binary arithmetic operator -is equivalent to x = x op -(y) but evaluates x -only once. The op= construct is a single token. -In assignment operations, both the left- and right-hand expression lists -must contain exactly one single-valued expression, and the left-hand -expression must not be the blank identifier. -

    - -
    -a[i] <<= 2
    -i &^= 1<<n
    -
    - -

    -A tuple assignment assigns the individual elements of a multi-valued -operation to a list of variables. There are two forms. In the -first, the right hand operand is a single multi-valued expression -such as a function call, a channel or -map operation, or a type assertion. -The number of operands on the left -hand side must match the number of values. For instance, if -f is a function returning two values, -

    - -
    -x, y = f()
    -
    - -

    -assigns the first value to x and the second to y. -In the second form, the number of operands on the left must equal the number -of expressions on the right, each of which must be single-valued, and the -nth expression on the right is assigned to the nth -operand on the left: -

    - -
    -one, two, three = '一', '二', '三'
    -
    - -

    -The blank identifier provides a way to -ignore right-hand side values in an assignment: -

    - -
    -_ = x       // evaluate x but ignore it
    -x, _ = f()  // evaluate f() but ignore second result value
    -
    - -

    -The assignment proceeds in two phases. -First, the operands of index expressions -and pointer indirections -(including implicit pointer indirections in selectors) -on the left and the expressions on the right are all -evaluated in the usual order. -Second, the assignments are carried out in left-to-right order. -

    - -
    -a, b = b, a  // exchange a and b
    -
    -x := []int{1, 2, 3}
    -i := 0
    -i, x[i] = 1, 2  // set i = 1, x[0] = 2
    -
    -i = 0
    -x[i], i = 2, 1  // set x[0] = 2, i = 1
    -
    -x[0], x[0] = 1, 2  // set x[0] = 1, then x[0] = 2 (so x[0] == 2 at end)
    -
    -x[1], x[3] = 4, 5  // set x[1] = 4, then panic setting x[3] = 5.
    -
    -type Point struct { x, y int }
    -var p *Point
    -x[2], p.x = 6, 7  // set x[2] = 6, then panic setting p.x = 7
    -
    -i = 2
    -x = []int{3, 5, 7}
    -for i, x[i] = range x {  // set i, x[2] = 0, x[0]
    -	break
    -}
    -// after this loop, i == 0 and x == []int{3, 5, 3}
    -
    - -

    -In assignments, each value must be assignable -to the type of the operand to which it is assigned, with the following special cases: -

    - -
      -
    1. - Any typed value may be assigned to the blank identifier. -
    2. - -
    3. - If an untyped constant - is assigned to a variable of interface type or the blank identifier, - the constant is first implicitly converted to its - default type. -
    4. - -
    5. - If an untyped boolean value is assigned to a variable of interface type or - the blank identifier, it is first implicitly converted to type bool. -
    6. -
    - -

    If statements

    - -

    -"If" statements specify the conditional execution of two branches -according to the value of a boolean expression. If the expression -evaluates to true, the "if" branch is executed, otherwise, if -present, the "else" branch is executed. -

    - -
    -IfStmt = "if" [ SimpleStmt ";" ] Expression Block [ "else" ( IfStmt | Block ) ] .
    -
    - -
    -if x > max {
    -	x = max
    -}
    -
    - -

    -The expression may be preceded by a simple statement, which -executes before the expression is evaluated. -

    - -
    -if x := f(); x < y {
    -	return x
    -} else if x > z {
    -	return z
    -} else {
    -	return y
    -}
    -
    - - -

    Switch statements

    - -

    -"Switch" statements provide multi-way execution. -An expression or type is compared to the "cases" -inside the "switch" to determine which branch -to execute. -

    - -
    -SwitchStmt = ExprSwitchStmt | TypeSwitchStmt .
    -
    - -

    -There are two forms: expression switches and type switches. -In an expression switch, the cases contain expressions that are compared -against the value of the switch expression. -In a type switch, the cases contain types that are compared against the -type of a specially annotated switch expression. -The switch expression is evaluated exactly once in a switch statement. -

    - -

    Expression switches

    - -

    -In an expression switch, -the switch expression is evaluated and -the case expressions, which need not be constants, -are evaluated left-to-right and top-to-bottom; the first one that equals the -switch expression -triggers execution of the statements of the associated case; -the other cases are skipped. -If no case matches and there is a "default" case, -its statements are executed. -There can be at most one default case and it may appear anywhere in the -"switch" statement. -A missing switch expression is equivalent to the boolean value -true. -

    - -
    -ExprSwitchStmt = "switch" [ SimpleStmt ";" ] [ Expression ] "{" { ExprCaseClause } "}" .
    -ExprCaseClause = ExprSwitchCase ":" StatementList .
    -ExprSwitchCase = "case" ExpressionList | "default" .
    -
    - -

    -If the switch expression evaluates to an untyped constant, it is first implicitly -converted to its default type. -The predeclared untyped value nil cannot be used as a switch expression. -The switch expression type must be comparable. -

    - -

    -If a case expression is untyped, it is first implicitly converted -to the type of the switch expression. -For each (possibly converted) case expression x and the value t -of the switch expression, x == t must be a valid comparison. -

    - -

    -In other words, the switch expression is treated as if it were used to declare and -initialize a temporary variable t without explicit type; it is that -value of t against which each case expression x is tested -for equality. -

    - -

    -In a case or default clause, the last non-empty statement -may be a (possibly labeled) -"fallthrough" statement to -indicate that control should flow from the end of this clause to -the first statement of the next clause. -Otherwise control flows to the end of the "switch" statement. -A "fallthrough" statement may appear as the last statement of all -but the last clause of an expression switch. -

    - -

    -The switch expression may be preceded by a simple statement, which -executes before the expression is evaluated. -

    - -
    -switch tag {
    -default: s3()
    -case 0, 1, 2, 3: s1()
    -case 4, 5, 6, 7: s2()
    -}
    -
    -switch x := f(); {  // missing switch expression means "true"
    -case x < 0: return -x
    -default: return x
    -}
    -
    -switch {
    -case x < y: f1()
    -case x < z: f2()
    -case x == 4: f3()
    -}
    -
    - -

    -Implementation restriction: A compiler may disallow multiple case -expressions evaluating to the same constant. -For instance, the current compilers disallow duplicate integer, -floating point, or string constants in case expressions. -

    - -

    Type switches

    - -

    -A type switch compares types rather than values. It is otherwise similar -to an expression switch. It is marked by a special switch expression that -has the form of a type assertion -using the keyword type rather than an actual type: -

    - -
    -switch x.(type) {
    -// cases
    -}
    -
    - -

    -Cases then match actual types T against the dynamic type of the -expression x. As with type assertions, x must be of -interface type, and each non-interface type -T listed in a case must implement the type of x. -The types listed in the cases of a type switch must all be -different. -

    - -
    -TypeSwitchStmt  = "switch" [ SimpleStmt ";" ] TypeSwitchGuard "{" { TypeCaseClause } "}" .
    -TypeSwitchGuard = [ identifier ":=" ] PrimaryExpr "." "(" "type" ")" .
    -TypeCaseClause  = TypeSwitchCase ":" StatementList .
    -TypeSwitchCase  = "case" TypeList | "default" .
    -TypeList        = Type { "," Type } .
    -
    - -

    -The TypeSwitchGuard may include a -short variable declaration. -When that form is used, the variable is declared at the end of the -TypeSwitchCase in the implicit block of each clause. -In clauses with a case listing exactly one type, the variable -has that type; otherwise, the variable has the type of the expression -in the TypeSwitchGuard. -

    - -

    -Instead of a type, a case may use the predeclared identifier -nil; -that case is selected when the expression in the TypeSwitchGuard -is a nil interface value. -There may be at most one nil case. -

    - -

    -Given an expression x of type interface{}, -the following type switch: -

    - -
    -switch i := x.(type) {
    -case nil:
    -	printString("x is nil")                // type of i is type of x (interface{})
    -case int:
    -	printInt(i)                            // type of i is int
    -case float64:
    -	printFloat64(i)                        // type of i is float64
    -case func(int) float64:
    -	printFunction(i)                       // type of i is func(int) float64
    -case bool, string:
    -	printString("type is bool or string")  // type of i is type of x (interface{})
    -default:
    -	printString("don't know the type")     // type of i is type of x (interface{})
    -}
    -
    - -

    -could be rewritten: -

    - -
    -v := x  // x is evaluated exactly once
    -if v == nil {
    -	i := v                                 // type of i is type of x (interface{})
    -	printString("x is nil")
    -} else if i, isInt := v.(int); isInt {
    -	printInt(i)                            // type of i is int
    -} else if i, isFloat64 := v.(float64); isFloat64 {
    -	printFloat64(i)                        // type of i is float64
    -} else if i, isFunc := v.(func(int) float64); isFunc {
    -	printFunction(i)                       // type of i is func(int) float64
    -} else {
    -	_, isBool := v.(bool)
    -	_, isString := v.(string)
    -	if isBool || isString {
    -		i := v                         // type of i is type of x (interface{})
    -		printString("type is bool or string")
    -	} else {
    -		i := v                         // type of i is type of x (interface{})
    -		printString("don't know the type")
    -	}
    -}
    -
    - -

    -The type switch guard may be preceded by a simple statement, which -executes before the guard is evaluated. -

    - -

    -The "fallthrough" statement is not permitted in a type switch. -

    - -

    For statements

    - -

    -A "for" statement specifies repeated execution of a block. There are three forms: -The iteration may be controlled by a single condition, a "for" clause, or a "range" clause. -

    - -
    -ForStmt = "for" [ Condition | ForClause | RangeClause ] Block .
    -Condition = Expression .
    -
    - -

    For statements with single condition

    - -

    -In its simplest form, a "for" statement specifies the repeated execution of -a block as long as a boolean condition evaluates to true. -The condition is evaluated before each iteration. -If the condition is absent, it is equivalent to the boolean value -true. -

    - -
    -for a < b {
    -	a *= 2
    -}
    -
    - -

    For statements with for clause

    - -

    -A "for" statement with a ForClause is also controlled by its condition, but -additionally it may specify an init -and a post statement, such as an assignment, -an increment or decrement statement. The init statement may be a -short variable declaration, but the post statement must not. -Variables declared by the init statement are re-used in each iteration. -

    - -
    -ForClause = [ InitStmt ] ";" [ Condition ] ";" [ PostStmt ] .
    -InitStmt = SimpleStmt .
    -PostStmt = SimpleStmt .
    -
    - -
    -for i := 0; i < 10; i++ {
    -	f(i)
    -}
    -
    - -

    -If non-empty, the init statement is executed once before evaluating the -condition for the first iteration; -the post statement is executed after each execution of the block (and -only if the block was executed). -Any element of the ForClause may be empty but the -semicolons are -required unless there is only a condition. -If the condition is absent, it is equivalent to the boolean value -true. -

    - -
    -for cond { S() }    is the same as    for ; cond ; { S() }
    -for      { S() }    is the same as    for true     { S() }
    -
    - -

    For statements with range clause

    - -

    -A "for" statement with a "range" clause -iterates through all entries of an array, slice, string or map, -or values received on a channel. For each entry it assigns iteration values -to corresponding iteration variables if present and then executes the block. -

    - -
    -RangeClause = [ ExpressionList "=" | IdentifierList ":=" ] "range" Expression .
    -
    - -

    -The expression on the right in the "range" clause is called the range expression, -which may be an array, pointer to an array, slice, string, map, or channel permitting -receive operations. -As with an assignment, if present the operands on the left must be -addressable or map index expressions; they -denote the iteration variables. If the range expression is a channel, at most -one iteration variable is permitted, otherwise there may be up to two. -If the last iteration variable is the blank identifier, -the range clause is equivalent to the same clause without that identifier. -

    - -

    -The range expression x is evaluated once before beginning the loop, -with one exception: if at most one iteration variable is present and -len(x) is constant, -the range expression is not evaluated. -

    - -

    -Function calls on the left are evaluated once per iteration. -For each iteration, iteration values are produced as follows -if the respective iteration variables are present: -

    - -
    -Range expression                          1st value          2nd value
    -
    -array or slice  a  [n]E, *[n]E, or []E    index    i  int    a[i]       E
    -string          s  string type            index    i  int    see below  rune
    -map             m  map[K]V                key      k  K      m[k]       V
    -channel         c  chan E, <-chan E       element  e  E
    -
    - -
      -
    1. -For an array, pointer to array, or slice value a, the index iteration -values are produced in increasing order, starting at element index 0. -If at most one iteration variable is present, the range loop produces -iteration values from 0 up to len(a)-1 and does not index into the array -or slice itself. For a nil slice, the number of iterations is 0. -
    2. - -
    3. -For a string value, the "range" clause iterates over the Unicode code points -in the string starting at byte index 0. On successive iterations, the index value will be the -index of the first byte of successive UTF-8-encoded code points in the string, -and the second value, of type rune, will be the value of -the corresponding code point. If the iteration encounters an invalid -UTF-8 sequence, the second value will be 0xFFFD, -the Unicode replacement character, and the next iteration will advance -a single byte in the string. -
    4. - -
    5. -The iteration order over maps is not specified -and is not guaranteed to be the same from one iteration to the next. -If a map entry that has not yet been reached is removed during iteration, -the corresponding iteration value will not be produced. If a map entry is -created during iteration, that entry may be produced during the iteration or -may be skipped. The choice may vary for each entry created and from one -iteration to the next. -If the map is nil, the number of iterations is 0. -
    6. - -
    7. -For channels, the iteration values produced are the successive values sent on -the channel until the channel is closed. If the channel -is nil, the range expression blocks forever. -
    8. -
    - -

    -The iteration values are assigned to the respective -iteration variables as in an assignment statement. -

    - -

    -The iteration variables may be declared by the "range" clause using a form of -short variable declaration -(:=). -In this case their types are set to the types of the respective iteration values -and their scope is the block of the "for" -statement; they are re-used in each iteration. -If the iteration variables are declared outside the "for" statement, -after execution their values will be those of the last iteration. -

    - -
    -var testdata *struct {
    -	a *[7]int
    -}
    -for i, _ := range testdata.a {
    -	// testdata.a is never evaluated; len(testdata.a) is constant
    -	// i ranges from 0 to 6
    -	f(i)
    -}
    -
    -var a [10]string
    -for i, s := range a {
    -	// type of i is int
    -	// type of s is string
    -	// s == a[i]
    -	g(i, s)
    -}
    -
    -var key string
    -var val interface{}  // element type of m is assignable to val
    -m := map[string]int{"mon":0, "tue":1, "wed":2, "thu":3, "fri":4, "sat":5, "sun":6}
    -for key, val = range m {
    -	h(key, val)
    -}
    -// key == last map key encountered in iteration
    -// val == map[key]
    -
    -var ch chan Work = producer()
    -for w := range ch {
    -	doWork(w)
    -}
    -
    -// empty a channel
    -for range ch {}
    -
    - - -

    Go statements

    - -

    -A "go" statement starts the execution of a function call -as an independent concurrent thread of control, or goroutine, -within the same address space. -

    - -
    -GoStmt = "go" Expression .
    -
    - -

    -The expression must be a function or method call; it cannot be parenthesized. -Calls of built-in functions are restricted as for -expression statements. -

    - -

    -The function value and parameters are -evaluated as usual -in the calling goroutine, but -unlike with a regular call, program execution does not wait -for the invoked function to complete. -Instead, the function begins executing independently -in a new goroutine. -When the function terminates, its goroutine also terminates. -If the function has any return values, they are discarded when the -function completes. -

    - -
    -go Server()
    -go func(ch chan<- bool) { for { sleep(10); ch <- true }} (c)
    -
    - - -

    Select statements

    - -

    -A "select" statement chooses which of a set of possible -send or -receive -operations will proceed. -It looks similar to a -"switch" statement but with the -cases all referring to communication operations. -

    - -
    -SelectStmt = "select" "{" { CommClause } "}" .
    -CommClause = CommCase ":" StatementList .
    -CommCase   = "case" ( SendStmt | RecvStmt ) | "default" .
    -RecvStmt   = [ ExpressionList "=" | IdentifierList ":=" ] RecvExpr .
    -RecvExpr   = Expression .
    -
    - -

    -A case with a RecvStmt may assign the result of a RecvExpr to one or -two variables, which may be declared using a -short variable declaration. -The RecvExpr must be a (possibly parenthesized) receive operation. -There can be at most one default case and it may appear anywhere -in the list of cases. -

    - -

    -Execution of a "select" statement proceeds in several steps: -

    - -
      -
    1. -For all the cases in the statement, the channel operands of receive operations -and the channel and right-hand-side expressions of send statements are -evaluated exactly once, in source order, upon entering the "select" statement. -The result is a set of channels to receive from or send to, -and the corresponding values to send. -Any side effects in that evaluation will occur irrespective of which (if any) -communication operation is selected to proceed. -Expressions on the left-hand side of a RecvStmt with a short variable declaration -or assignment are not yet evaluated. -
    2. - -
    3. -If one or more of the communications can proceed, -a single one that can proceed is chosen via a uniform pseudo-random selection. -Otherwise, if there is a default case, that case is chosen. -If there is no default case, the "select" statement blocks until -at least one of the communications can proceed. -
    4. - -
    5. -Unless the selected case is the default case, the respective communication -operation is executed. -
    6. - -
    7. -If the selected case is a RecvStmt with a short variable declaration or -an assignment, the left-hand side expressions are evaluated and the -received value (or values) are assigned. -
    8. - -
    9. -The statement list of the selected case is executed. -
    10. -
    - -

    -Since communication on nil channels can never proceed, -a select with only nil channels and no default case blocks forever. -

    - -
    -var a []int
    -var c, c1, c2, c3, c4 chan int
    -var i1, i2 int
    -select {
    -case i1 = <-c1:
    -	print("received ", i1, " from c1\n")
    -case c2 <- i2:
    -	print("sent ", i2, " to c2\n")
    -case i3, ok := (<-c3):  // same as: i3, ok := <-c3
    -	if ok {
    -		print("received ", i3, " from c3\n")
    -	} else {
    -		print("c3 is closed\n")
    -	}
    -case a[f()] = <-c4:
    -	// same as:
    -	// case t := <-c4
    -	//	a[f()] = t
    -default:
    -	print("no communication\n")
    -}
    -
    -for {  // send random sequence of bits to c
    -	select {
    -	case c <- 0:  // note: no statement, no fallthrough, no folding of cases
    -	case c <- 1:
    -	}
    -}
    -
    -select {}  // block forever
    -
    - - -

    Return statements

    - -

    -A "return" statement in a function F terminates the execution -of F, and optionally provides one or more result values. -Any functions deferred by F -are executed before F returns to its caller. -

    - -
    -ReturnStmt = "return" [ ExpressionList ] .
    -
    - -

    -In a function without a result type, a "return" statement must not -specify any result values. -

    -
    -func noResult() {
    -	return
    -}
    -
    - -

    -There are three ways to return values from a function with a result -type: -

    - -
      -
    1. The return value or values may be explicitly listed - in the "return" statement. Each expression must be single-valued - and assignable - to the corresponding element of the function's result type. -
      -func simpleF() int {
      -	return 2
      -}
      -
      -func complexF1() (re float64, im float64) {
      -	return -7.0, -4.0
      -}
      -
      -
    2. -
    3. The expression list in the "return" statement may be a single - call to a multi-valued function. The effect is as if each value - returned from that function were assigned to a temporary - variable with the type of the respective value, followed by a - "return" statement listing these variables, at which point the - rules of the previous case apply. -
      -func complexF2() (re float64, im float64) {
      -	return complexF1()
      -}
      -
      -
    4. -
    5. The expression list may be empty if the function's result - type specifies names for its result parameters. - The result parameters act as ordinary local variables - and the function may assign values to them as necessary. - The "return" statement returns the values of these variables. -
      -func complexF3() (re float64, im float64) {
      -	re = 7.0
      -	im = 4.0
      -	return
      -}
      -
      -func (devnull) Write(p []byte) (n int, _ error) {
      -	n = len(p)
      -	return
      -}
      -
      -
    6. -
    - -

    -Regardless of how they are declared, all the result values are initialized to -the zero values for their type upon entry to the -function. A "return" statement that specifies results sets the result parameters before -any deferred functions are executed. -

    - -

    -Implementation restriction: A compiler may disallow an empty expression list -in a "return" statement if a different entity (constant, type, or variable) -with the same name as a result parameter is in -scope at the place of the return. -

    - -
    -func f(n int) (res int, err error) {
    -	if _, err := f(n-1); err != nil {
    -		return  // invalid return statement: err is shadowed
    -	}
    -	return
    -}
    -
    - -

    Break statements

    - -

    -A "break" statement terminates execution of the innermost -"for", -"switch", or -"select" statement -within the same function. -

    - -
    -BreakStmt = "break" [ Label ] .
    -
    - -

    -If there is a label, it must be that of an enclosing -"for", "switch", or "select" statement, -and that is the one whose execution terminates. -

    - -
    -OuterLoop:
    -	for i = 0; i < n; i++ {
    -		for j = 0; j < m; j++ {
    -			switch a[i][j] {
    -			case nil:
    -				state = Error
    -				break OuterLoop
    -			case item:
    -				state = Found
    -				break OuterLoop
    -			}
    -		}
    -	}
    -
    - -

    Continue statements

    - -

    -A "continue" statement begins the next iteration of the -innermost "for" loop at its post statement. -The "for" loop must be within the same function. -

    - -
    -ContinueStmt = "continue" [ Label ] .
    -
    - -

    -If there is a label, it must be that of an enclosing -"for" statement, and that is the one whose execution -advances. -

    - -
    -RowLoop:
    -	for y, row := range rows {
    -		for x, data := range row {
    -			if data == endOfRow {
    -				continue RowLoop
    -			}
    -			row[x] = data + bias(x, y)
    -		}
    -	}
    -
    - -

    Goto statements

    - -

    -A "goto" statement transfers control to the statement with the corresponding label -within the same function. -

    - -
    -GotoStmt = "goto" Label .
    -
    - -
    -goto Error
    -
    - -

    -Executing the "goto" statement must not cause any variables to come into -scope that were not already in scope at the point of the goto. -For instance, this example: -

    - -
    -	goto L  // BAD
    -	v := 3
    -L:
    -
    - -

    -is erroneous because the jump to label L skips -the creation of v. -

    - -

    -A "goto" statement outside a block cannot jump to a label inside that block. -For instance, this example: -

    - -
    -if n%2 == 1 {
    -	goto L1
    -}
    -for n > 0 {
    -	f()
    -	n--
    -L1:
    -	f()
    -	n--
    -}
    -
    - -

    -is erroneous because the label L1 is inside -the "for" statement's block but the goto is not. -

    - -

    Fallthrough statements

    - -

    -A "fallthrough" statement transfers control to the first statement of the -next case clause in an expression "switch" statement. -It may be used only as the final non-empty statement in such a clause. -

    - -
    -FallthroughStmt = "fallthrough" .
    -
    - - -

    Defer statements

    - -

    -A "defer" statement invokes a function whose execution is deferred -to the moment the surrounding function returns, either because the -surrounding function executed a return statement, -reached the end of its function body, -or because the corresponding goroutine is panicking. -

    - -
    -DeferStmt = "defer" Expression .
    -
    - -

    -The expression must be a function or method call; it cannot be parenthesized. -Calls of built-in functions are restricted as for -expression statements. -

    - -

    -Each time a "defer" statement -executes, the function value and parameters to the call are -evaluated as usual -and saved anew but the actual function is not invoked. -Instead, deferred functions are invoked immediately before -the surrounding function returns, in the reverse order -they were deferred. That is, if the surrounding function -returns through an explicit return statement, -deferred functions are executed after any result parameters are set -by that return statement but before the function returns to its caller. -If a deferred function value evaluates -to nil, execution panics -when the function is invoked, not when the "defer" statement is executed. -

    - -

    -For instance, if the deferred function is -a function literal and the surrounding -function has named result parameters that -are in scope within the literal, the deferred function may access and modify -the result parameters before they are returned. -If the deferred function has any return values, they are discarded when -the function completes. -(See also the section on handling panics.) -

    - -
    -lock(l)
    -defer unlock(l)  // unlocking happens before surrounding function returns
    -
    -// prints 3 2 1 0 before surrounding function returns
    -for i := 0; i <= 3; i++ {
    -	defer fmt.Print(i)
    -}
    -
    -// f returns 42
    -func f() (result int) {
    -	defer func() {
    -		// result is accessed after it was set to 6 by the return statement
    -		result *= 7
    -	}()
    -	return 6
    -}
    -
    - -

    Built-in functions

    - -

    -Built-in functions are -predeclared. -They are called like any other function but some of them -accept a type instead of an expression as the first argument. -

    - -

    -The built-in functions do not have standard Go types, -so they can only appear in call expressions; -they cannot be used as function values. -

    - -

    Close

    - -

    -For a channel c, the built-in function close(c) -records that no more values will be sent on the channel. -It is an error if c is a receive-only channel. -Sending to or closing a closed channel causes a run-time panic. -Closing the nil channel also causes a run-time panic. -After calling close, and after any previously -sent values have been received, receive operations will return -the zero value for the channel's type without blocking. -The multi-valued receive operation -returns a received value along with an indication of whether the channel is closed. -

    - - -

    Length and capacity

    - -

    -The built-in functions len and cap take arguments -of various types and return a result of type int. -The implementation guarantees that the result always fits into an int. -

    - -
    -Call      Argument type    Result
    -
    -len(s)    string type      string length in bytes
    -          [n]T, *[n]T      array length (== n)
    -          []T              slice length
    -          map[K]T          map length (number of defined keys)
    -          chan T           number of elements queued in channel buffer
    -
    -cap(s)    [n]T, *[n]T      array length (== n)
    -          []T              slice capacity
    -          chan T           channel buffer capacity
    -
    - -

    -The capacity of a slice is the number of elements for which there is -space allocated in the underlying array. -At any time the following relationship holds: -

    - -
    -0 <= len(s) <= cap(s)
    -
    - -

    -The length of a nil slice, map or channel is 0. -The capacity of a nil slice or channel is 0. -

    - -

    -The expression len(s) is constant if -s is a string constant. The expressions len(s) and -cap(s) are constants if the type of s is an array -or pointer to an array and the expression s does not contain -channel receives or (non-constant) -function calls; in this case s is not evaluated. -Otherwise, invocations of len and cap are not -constant and s is evaluated. -

    - -
    -const (
    -	c1 = imag(2i)                    // imag(2i) = 2.0 is a constant
    -	c2 = len([10]float64{2})         // [10]float64{2} contains no function calls
    -	c3 = len([10]float64{c1})        // [10]float64{c1} contains no function calls
    -	c4 = len([10]float64{imag(2i)})  // imag(2i) is a constant and no function call is issued
    -	c5 = len([10]float64{imag(z)})   // invalid: imag(z) is a (non-constant) function call
    -)
    -var z complex128
    -
    - -

    Allocation

    - -

    -The built-in function new takes a type T, -allocates storage for a variable of that type -at run time, and returns a value of type *T -pointing to it. -The variable is initialized as described in the section on -initial values. -

    - -
    -new(T)
    -
    - -

    -For instance -

    - -
    -type S struct { a int; b float64 }
    -new(S)
    -
    - -

    -allocates storage for a variable of type S, -initializes it (a=0, b=0.0), -and returns a value of type *S containing the address -of the location. -

    - -

    Making slices, maps and channels

    - -

    -The built-in function make takes a type T, -which must be a slice, map or channel type, -optionally followed by a type-specific list of expressions. -It returns a value of type T (not *T). -The memory is initialized as described in the section on -initial values. -

    - -
    -Call             Type T     Result
    -
    -make(T, n)       slice      slice of type T with length n and capacity n
    -make(T, n, m)    slice      slice of type T with length n and capacity m
    -
    -make(T)          map        map of type T
    -make(T, n)       map        map of type T with initial space for approximately n elements
    -
    -make(T)          channel    unbuffered channel of type T
    -make(T, n)       channel    buffered channel of type T, buffer size n
    -
    - - -

    -Each of the size arguments n and m must be of integer type -or an untyped constant. -A constant size argument must be non-negative and representable -by a value of type int; if it is an untyped constant it is given type int. -If both n and m are provided and are constant, then -n must be no larger than m. -If n is negative or larger than m at run time, -a run-time panic occurs. -

    - -
    -s := make([]int, 10, 100)       // slice with len(s) == 10, cap(s) == 100
    -s := make([]int, 1e3)           // slice with len(s) == cap(s) == 1000
    -s := make([]int, 1<<63)         // illegal: len(s) is not representable by a value of type int
    -s := make([]int, 10, 0)         // illegal: len(s) > cap(s)
    -c := make(chan int, 10)         // channel with a buffer size of 10
    -m := make(map[string]int, 100)  // map with initial space for approximately 100 elements
    -
    - -

    -Calling make with a map type and size hint n will -create a map with initial space to hold n map elements. -The precise behavior is implementation-dependent. -

    - - -

    Appending to and copying slices

    - -

    -The built-in functions append and copy assist in -common slice operations. -For both functions, the result is independent of whether the memory referenced -by the arguments overlaps. -

    - -

    -The variadic function append -appends zero or more values x -to s of type S, which must be a slice type, and -returns the resulting slice, also of type S. -The values x are passed to a parameter of type ...T -where T is the element type of -S and the respective -parameter passing rules apply. -As a special case, append also accepts a first argument -assignable to type []byte with a second argument of -string type followed by .... This form appends the -bytes of the string. -

    - -
    -append(s S, x ...T) S  // T is the element type of S
    -
    - -

    -If the capacity of s is not large enough to fit the additional -values, append allocates a new, sufficiently large underlying -array that fits both the existing slice elements and the additional values. -Otherwise, append re-uses the underlying array. -

    - -
    -s0 := []int{0, 0}
    -s1 := append(s0, 2)                // append a single element     s1 == []int{0, 0, 2}
    -s2 := append(s1, 3, 5, 7)          // append multiple elements    s2 == []int{0, 0, 2, 3, 5, 7}
    -s3 := append(s2, s0...)            // append a slice              s3 == []int{0, 0, 2, 3, 5, 7, 0, 0}
    -s4 := append(s3[3:6], s3[2:]...)   // append overlapping slice    s4 == []int{3, 5, 7, 2, 3, 5, 7, 0, 0}
    -
    -var t []interface{}
    -t = append(t, 42, 3.1415, "foo")   //                             t == []interface{}{42, 3.1415, "foo"}
    -
    -var b []byte
    -b = append(b, "bar"...)            // append string contents      b == []byte{'b', 'a', 'r' }
    -
    - -

    -The function copy copies slice elements from -a source src to a destination dst and returns the -number of elements copied. -Both arguments must have identical element type T and must be -assignable to a slice of type []T. -The number of elements copied is the minimum of -len(src) and len(dst). -As a special case, copy also accepts a destination argument assignable -to type []byte with a source argument of a string type. -This form copies the bytes from the string into the byte slice. -

    - -
    -copy(dst, src []T) int
    -copy(dst []byte, src string) int
    -
    - -

    -Examples: -

    - -
    -var a = [...]int{0, 1, 2, 3, 4, 5, 6, 7}
    -var s = make([]int, 6)
    -var b = make([]byte, 5)
    -n1 := copy(s, a[0:])            // n1 == 6, s == []int{0, 1, 2, 3, 4, 5}
    -n2 := copy(s, s[2:])            // n2 == 4, s == []int{2, 3, 4, 5, 4, 5}
    -n3 := copy(b, "Hello, World!")  // n3 == 5, b == []byte("Hello")
    -
    - - -

    Deletion of map elements

    - -

    -The built-in function delete removes the element with key -k from a map m. The -type of k must be assignable -to the key type of m. -

    - -
    -delete(m, k)  // remove element m[k] from map m
    -
    - -

    -If the map m is nil or the element m[k] -does not exist, delete is a no-op. -

    - - -

    Manipulating complex numbers

    - -

    -Three functions assemble and disassemble complex numbers. -The built-in function complex constructs a complex -value from a floating-point real and imaginary part, while -real and imag -extract the real and imaginary parts of a complex value. -

    - -
    -complex(realPart, imaginaryPart floatT) complexT
    -real(complexT) floatT
    -imag(complexT) floatT
    -
    - -

    -The type of the arguments and return value correspond. -For complex, the two arguments must be of the same -floating-point type and the return type is the complex type -with the corresponding floating-point constituents: -complex64 for float32 arguments, and -complex128 for float64 arguments. -If one of the arguments evaluates to an untyped constant, it is first implicitly -converted to the type of the other argument. -If both arguments evaluate to untyped constants, they must be non-complex -numbers or their imaginary parts must be zero, and the return value of -the function is an untyped complex constant. -

    - -

    -For real and imag, the argument must be -of complex type, and the return type is the corresponding floating-point -type: float32 for a complex64 argument, and -float64 for a complex128 argument. -If the argument evaluates to an untyped constant, it must be a number, -and the return value of the function is an untyped floating-point constant. -

    - -

    -The real and imag functions together form the inverse of -complex, so for a value z of a complex type Z, -z == Z(complex(real(z), imag(z))). -

    - -

    -If the operands of these functions are all constants, the return -value is a constant. -

    - -
    -var a = complex(2, -2)             // complex128
    -const b = complex(1.0, -1.4)       // untyped complex constant 1 - 1.4i
    -x := float32(math.Cos(math.Pi/2))  // float32
    -var c64 = complex(5, -x)           // complex64
    -var s int = complex(1, 0)          // untyped complex constant 1 + 0i can be converted to int
    -_ = complex(1, 2<<s)               // illegal: 2 assumes floating-point type, cannot shift
    -var rl = real(c64)                 // float32
    -var im = imag(a)                   // float64
    -const c = imag(b)                  // untyped constant -1.4
    -_ = imag(3 << s)                   // illegal: 3 assumes complex type, cannot shift
    -
    - -

    Handling panics

    - -

    Two built-in functions, panic and recover, -assist in reporting and handling run-time panics -and program-defined error conditions. -

    - -
    -func panic(interface{})
    -func recover() interface{}
    -
    - -

    -While executing a function F, -an explicit call to panic or a run-time panic -terminates the execution of F. -Any functions deferred by F -are then executed as usual. -Next, any deferred functions run by F's caller are run, -and so on up to any deferred by the top-level function in the executing goroutine. -At that point, the program is terminated and the error -condition is reported, including the value of the argument to panic. -This termination sequence is called panicking. -

    - -
    -panic(42)
    -panic("unreachable")
    -panic(Error("cannot parse"))
    -
    - -

    -The recover function allows a program to manage behavior -of a panicking goroutine. -Suppose a function G defers a function D that calls -recover and a panic occurs in a function on the same goroutine in which G -is executing. -When the running of deferred functions reaches D, -the return value of D's call to recover will be the value passed to the call of panic. -If D returns normally, without starting a new -panic, the panicking sequence stops. In that case, -the state of functions called between G and the call to panic -is discarded, and normal execution resumes. -Any functions deferred by G before D are then run and G's -execution terminates by returning to its caller. -

    - -

    -The return value of recover is nil if any of the following conditions holds: -

    -
      -
    • -panic's argument was nil; -
    • -
    • -the goroutine is not panicking; -
    • -
    • -recover was not called directly by a deferred function. -
    • -
    - -

    -The protect function in the example below invokes -the function argument g and protects callers from -run-time panics raised by g. -

    - -
    -func protect(g func()) {
    -	defer func() {
    -		log.Println("done")  // Println executes normally even if there is a panic
    -		if x := recover(); x != nil {
    -			log.Printf("run time panic: %v", x)
    -		}
    -	}()
    -	log.Println("start")
    -	g()
    -}
    -
    - - -

    Bootstrapping

    - -

    -Current implementations provide several built-in functions useful during -bootstrapping. These functions are documented for completeness but are not -guaranteed to stay in the language. They do not return a result. -

    - -
    -Function   Behavior
    -
    -print      prints all arguments; formatting of arguments is implementation-specific
    -println    like print but prints spaces between arguments and a newline at the end
    -
    - -

    -Implementation restriction: print and println need not -accept arbitrary argument types, but printing of boolean, numeric, and string -types must be supported. -

    - -

    Packages

    - -

    -Go programs are constructed by linking together packages. -A package in turn is constructed from one or more source files -that together declare constants, types, variables and functions -belonging to the package and which are accessible in all files -of the same package. Those elements may be -exported and used in another package. -

    - -

    Source file organization

    - -

    -Each source file consists of a package clause defining the package -to which it belongs, followed by a possibly empty set of import -declarations that declare packages whose contents it wishes to use, -followed by a possibly empty set of declarations of functions, -types, variables, and constants. -

    - -
    -SourceFile       = PackageClause ";" { ImportDecl ";" } { TopLevelDecl ";" } .
    -
    - -

    Package clause

    - -

    -A package clause begins each source file and defines the package -to which the file belongs. -

    - -
    -PackageClause  = "package" PackageName .
    -PackageName    = identifier .
    -
    - -

    -The PackageName must not be the blank identifier. -

    - -
    -package math
    -
    - -

    -A set of files sharing the same PackageName form the implementation of a package. -An implementation may require that all source files for a package inhabit the same directory. -

    - -

    Import declarations

    - -

    -An import declaration states that the source file containing the declaration -depends on functionality of the imported package -(§Program initialization and execution) -and enables access to exported identifiers -of that package. -The import names an identifier (PackageName) to be used for access and an ImportPath -that specifies the package to be imported. -

    - -
    -ImportDecl       = "import" ( ImportSpec | "(" { ImportSpec ";" } ")" ) .
    -ImportSpec       = [ "." | PackageName ] ImportPath .
    -ImportPath       = string_lit .
    -
    - -

    -The PackageName is used in qualified identifiers -to access exported identifiers of the package within the importing source file. -It is declared in the file block. -If the PackageName is omitted, it defaults to the identifier specified in the -package clause of the imported package. -If an explicit period (.) appears instead of a name, all the -package's exported identifiers declared in that package's -package block will be declared in the importing source -file's file block and must be accessed without a qualifier. -

    - -

    -The interpretation of the ImportPath is implementation-dependent but -it is typically a substring of the full file name of the compiled -package and may be relative to a repository of installed packages. -

    - -

    -Implementation restriction: A compiler may restrict ImportPaths to -non-empty strings using only characters belonging to -Unicode's -L, M, N, P, and S general categories (the Graphic characters without -spaces) and may also exclude the characters -!"#$%&'()*,:;<=>?[\]^`{|} -and the Unicode replacement character U+FFFD. -

    - -

    -Assume we have compiled a package containing the package clause -package math, which exports function Sin, and -installed the compiled package in the file identified by -"lib/math". -This table illustrates how Sin is accessed in files -that import the package after the -various types of import declaration. -

    - -
    -Import declaration          Local name of Sin
    -
    -import   "lib/math"         math.Sin
    -import m "lib/math"         m.Sin
    -import . "lib/math"         Sin
    -
    - -

    -An import declaration declares a dependency relation between -the importing and imported package. -It is illegal for a package to import itself, directly or indirectly, -or to directly import a package without -referring to any of its exported identifiers. To import a package solely for -its side-effects (initialization), use the blank -identifier as explicit package name: -

    - -
    -import _ "lib/math"
    -
    - - -

    An example package

    - -

    -Here is a complete Go package that implements a concurrent prime sieve. -

    - -
    -package main
    -
    -import "fmt"
    -
    -// Send the sequence 2, 3, 4, … to channel 'ch'.
    -func generate(ch chan<- int) {
    -	for i := 2; ; i++ {
    -		ch <- i  // Send 'i' to channel 'ch'.
    -	}
    -}
    -
    -// Copy the values from channel 'src' to channel 'dst',
    -// removing those divisible by 'prime'.
    -func filter(src <-chan int, dst chan<- int, prime int) {
    -	for i := range src {  // Loop over values received from 'src'.
    -		if i%prime != 0 {
    -			dst <- i  // Send 'i' to channel 'dst'.
    -		}
    -	}
    -}
    -
    -// The prime sieve: Daisy-chain filter processes together.
    -func sieve() {
    -	ch := make(chan int)  // Create a new channel.
    -	go generate(ch)       // Start generate() as a subprocess.
    -	for {
    -		prime := <-ch
    -		fmt.Print(prime, "\n")
    -		ch1 := make(chan int)
    -		go filter(ch, ch1, prime)
    -		ch = ch1
    -	}
    -}
    -
    -func main() {
    -	sieve()
    -}
    -
    - -

    Program initialization and execution

    - -

    The zero value

    -

    -When storage is allocated for a variable, -either through a declaration or a call of new, or when -a new value is created, either through a composite literal or a call -of make, -and no explicit initialization is provided, the variable or value is -given a default value. Each element of such a variable or value is -set to the zero value for its type: false for booleans, -0 for numeric types, "" -for strings, and nil for pointers, functions, interfaces, slices, channels, and maps. -This initialization is done recursively, so for instance each element of an -array of structs will have its fields zeroed if no value is specified. -

    -

    -These two simple declarations are equivalent: -

    - -
    -var i int
    -var i int = 0
    -
    - -

    -After -

    - -
    -type T struct { i int; f float64; next *T }
    -t := new(T)
    -
    - -

    -the following holds: -

    - -
    -t.i == 0
    -t.f == 0.0
    -t.next == nil
    -
    - -

    -The same would also be true after -

    - -
    -var t T
    -
    - -

    Package initialization

    - -

    -Within a package, package-level variable initialization proceeds stepwise, -with each step selecting the variable earliest in declaration order -which has no dependencies on uninitialized variables. -

    - -

    -More precisely, a package-level variable is considered ready for -initialization if it is not yet initialized and either has -no initialization expression or -its initialization expression has no dependencies on uninitialized variables. -Initialization proceeds by repeatedly initializing the next package-level -variable that is earliest in declaration order and ready for initialization, -until there are no variables ready for initialization. -

    - -

    -If any variables are still uninitialized when this -process ends, those variables are part of one or more initialization cycles, -and the program is not valid. -

    - -

    -Multiple variables on the left-hand side of a variable declaration initialized -by single (multi-valued) expression on the right-hand side are initialized -together: If any of the variables on the left-hand side is initialized, all -those variables are initialized in the same step. -

    - -
    -var x = a
    -var a, b = f() // a and b are initialized together, before x is initialized
    -
    - -

    -For the purpose of package initialization, blank -variables are treated like any other variables in declarations. -

    - -

    -The declaration order of variables declared in multiple files is determined -by the order in which the files are presented to the compiler: Variables -declared in the first file are declared before any of the variables declared -in the second file, and so on. -

    - -

    -Dependency analysis does not rely on the actual values of the -variables, only on lexical references to them in the source, -analyzed transitively. For instance, if a variable x's -initialization expression refers to a function whose body refers to -variable y then x depends on y. -Specifically: -

    - -
      -
    • -A reference to a variable or function is an identifier denoting that -variable or function. -
    • - -
    • -A reference to a method m is a -method value or -method expression of the form -t.m, where the (static) type of t is -not an interface type, and the method m is in the -method set of t. -It is immaterial whether the resulting function value -t.m is invoked. -
    • - -
    • -A variable, function, or method x depends on a variable -y if x's initialization expression or body -(for functions and methods) contains a reference to y -or to a function or method that depends on y. -
    • -
    - -

    -For example, given the declarations -

    - -
    -var (
    -	a = c + b  // == 9
    -	b = f()    // == 4
    -	c = f()    // == 5
    -	d = 3      // == 5 after initialization has finished
    -)
    -
    -func f() int {
    -	d++
    -	return d
    -}
    -
    - -

    -the initialization order is d, b, c, a. -Note that the order of subexpressions in initialization expressions is irrelevant: -a = c + b and a = b + c result in the same initialization -order in this example. -

    - -

    -Dependency analysis is performed per package; only references referring -to variables, functions, and (non-interface) methods declared in the current -package are considered. If other, hidden, data dependencies exists between -variables, the initialization order between those variables is unspecified. -

    - -

    -For instance, given the declarations -

    - -
    -var x = I(T{}).ab()   // x has an undetected, hidden dependency on a and b
    -var _ = sideEffect()  // unrelated to x, a, or b
    -var a = b
    -var b = 42
    -
    -type I interface      { ab() []int }
    -type T struct{}
    -func (T) ab() []int   { return []int{a, b} }
    -
    - -

    -the variable a will be initialized after b but -whether x is initialized before b, between -b and a, or after a, and -thus also the moment at which sideEffect() is called (before -or after x is initialized) is not specified. -

    - -

    -Variables may also be initialized using functions named init -declared in the package block, with no arguments and no result parameters. -

    - -
    -func init() { … }
    -
    - -

    -Multiple such functions may be defined per package, even within a single -source file. In the package block, the init identifier can -be used only to declare init functions, yet the identifier -itself is not declared. Thus -init functions cannot be referred to from anywhere -in a program. -

    - -

    -A package with no imports is initialized by assigning initial values -to all its package-level variables followed by calling all init -functions in the order they appear in the source, possibly in multiple files, -as presented to the compiler. -If a package has imports, the imported packages are initialized -before initializing the package itself. If multiple packages import -a package, the imported package will be initialized only once. -The importing of packages, by construction, guarantees that there -can be no cyclic initialization dependencies. -

    - -

    -Package initialization—variable initialization and the invocation of -init functions—happens in a single goroutine, -sequentially, one package at a time. -An init function may launch other goroutines, which can run -concurrently with the initialization code. However, initialization -always sequences -the init functions: it will not invoke the next one -until the previous one has returned. -

    - -

    -To ensure reproducible initialization behavior, build systems are encouraged -to present multiple files belonging to the same package in lexical file name -order to a compiler. -

    - - -

    Program execution

    -

    -A complete program is created by linking a single, unimported package -called the main package with all the packages it imports, transitively. -The main package must -have package name main and -declare a function main that takes no -arguments and returns no value. -

    - -
    -func main() { … }
    -
    - -

    -Program execution begins by initializing the main package and then -invoking the function main. -When that function invocation returns, the program exits. -It does not wait for other (non-main) goroutines to complete. -

    - -

    Errors

    - -

    -The predeclared type error is defined as -

    - -
    -type error interface {
    -	Error() string
    -}
    -
    - -

    -It is the conventional interface for representing an error condition, -with the nil value representing no error. -For instance, a function to read data from a file might be defined: -

    - -
    -func Read(f *File, b []byte) (n int, err error)
    -
    - -

    Run-time panics

    - -

    -Execution errors such as attempting to index an array out -of bounds trigger a run-time panic equivalent to a call of -the built-in function panic -with a value of the implementation-defined interface type runtime.Error. -That type satisfies the predeclared interface type -error. -The exact error values that -represent distinct run-time error conditions are unspecified. -

    - -
    -package runtime
    -
    -type Error interface {
    -	error
    -	// and perhaps other methods
    -}
    -
    - -

    System considerations

    - -

    Package unsafe

    - -

    -The built-in package unsafe, known to the compiler -and accessible through the import path "unsafe", -provides facilities for low-level programming including operations -that violate the type system. A package using unsafe -must be vetted manually for type safety and may not be portable. -The package provides the following interface: -

    - -
    -package unsafe
    -
    -type ArbitraryType int  // shorthand for an arbitrary Go type; it is not a real type
    -type Pointer *ArbitraryType
    -
    -func Alignof(variable ArbitraryType) uintptr
    -func Offsetof(selector ArbitraryType) uintptr
    -func Sizeof(variable ArbitraryType) uintptr
    -
    -type IntegerType int  // shorthand for an integer type; it is not a real type
    -func Add(ptr Pointer, len IntegerType) Pointer
    -func Slice(ptr *ArbitraryType, len IntegerType) []ArbitraryType
    -
    - -

    -A Pointer is a pointer type but a Pointer -value may not be dereferenced. -Any pointer or value of underlying type uintptr can be converted to -a type of underlying type Pointer and vice versa. -The effect of converting between Pointer and uintptr is implementation-defined. -

    - -
    -var f float64
    -bits = *(*uint64)(unsafe.Pointer(&f))
    -
    -type ptr unsafe.Pointer
    -bits = *(*uint64)(ptr(&f))
    -
    -var p ptr = nil
    -
    - -

    -The functions Alignof and Sizeof take an expression x -of any type and return the alignment or size, respectively, of a hypothetical variable v -as if v was declared via var v = x. -

    -

    -The function Offsetof takes a (possibly parenthesized) selector -s.f, denoting a field f of the struct denoted by s -or *s, and returns the field offset in bytes relative to the struct's address. -If f is an embedded field, it must be reachable -without pointer indirections through fields of the struct. -For a struct s with field f: -

    - -
    -uintptr(unsafe.Pointer(&s)) + unsafe.Offsetof(s.f) == uintptr(unsafe.Pointer(&s.f))
    -
    - -

    -Computer architectures may require memory addresses to be aligned; -that is, for addresses of a variable to be a multiple of a factor, -the variable's type's alignment. The function Alignof -takes an expression denoting a variable of any type and returns the -alignment of the (type of the) variable in bytes. For a variable -x: -

    - -
    -uintptr(unsafe.Pointer(&x)) % unsafe.Alignof(x) == 0
    -
    - -

    -Calls to Alignof, Offsetof, and -Sizeof are compile-time constant expressions of type uintptr. -

    - -

    -The function Add adds len to ptr -and returns the updated pointer unsafe.Pointer(uintptr(ptr) + uintptr(len)). -The len argument must be of integer type or an untyped constant. -A constant len argument must be representable by a value of type int; -if it is an untyped constant it is given type int. -The rules for valid uses of Pointer still apply. -

    - -

    -The function Slice returns a slice whose underlying array starts at ptr -and whose length and capacity are len. -Slice(ptr, len) is equivalent to -

    - -
    -(*[len]ArbitraryType)(unsafe.Pointer(ptr))[:]
    -
    - -

    -except that, as a special case, if ptr -is nil and len is zero, -Slice returns nil. -

    - -

    -The len argument must be of integer type or an untyped constant. -A constant len argument must be non-negative and representable by a value of type int; -if it is an untyped constant it is given type int. -At run time, if len is negative, -or if ptr is nil and len is not zero, -a run-time panic occurs. -

    - -

    Size and alignment guarantees

    - -

    -For the numeric types, the following sizes are guaranteed: -

    - -
    -type                                 size in bytes
    -
    -byte, uint8, int8                     1
    -uint16, int16                         2
    -uint32, int32, float32                4
    -uint64, int64, float64, complex64     8
    -complex128                           16
    -
    - -

    -The following minimal alignment properties are guaranteed: -

    -
      -
    1. For a variable x of any type: unsafe.Alignof(x) is at least 1. -
    2. - -
    3. For a variable x of struct type: unsafe.Alignof(x) is the largest of - all the values unsafe.Alignof(x.f) for each field f of x, but at least 1. -
    4. - -
    5. For a variable x of array type: unsafe.Alignof(x) is the same as - the alignment of a variable of the array's element type. -
    6. -
    - -

    -A struct or array type has size zero if it contains no fields (or elements, respectively) that have a size greater than zero. Two distinct zero-size variables may have the same address in memory. -

    diff --git a/doc/go_spec.html b/doc/go_spec.html index db5fba45a53378..9865227c22d454 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -1,6 +1,6 @@ @@ -8,8 +8,6 @@

    Introduction

    This is the reference manual for the Go programming language. -The pre-Go1.18 version, without generics, can be found -here. For more information and other documents, see go.dev.

    From ef7f09149b4af54839e191841ddbfaff8640a484 Mon Sep 17 00:00:00 2001 From: Jakub Ciolek Date: Mon, 13 Jan 2025 21:35:04 +0100 Subject: [PATCH 222/397] cmd/compile: prefer hv2 <= 127 over hv2 < 128 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is shorter to encode on AMD64/x86. Shrinks a few functions and doesn't seem to cause any regressions. No size impact on other archs. Covers a bit more than CL 639935. compilecmp linux/amd64: unicode/utf8 unicode/utf8.RuneCountInString changed unicode/utf8.RuneCount changed unicode/utf8 [cmd/compile] unicode/utf8.RuneCount changed unicode/utf8.RuneCountInString changed runtime runtime.countrunes changed runtime.stringtoslicerune 413 -> 379 (-8.23%) runtime [cmd/compile] runtime.countrunes changed runtime.stringtoslicerune 413 -> 379 (-8.23%) bytes bytes.containsRune 143 -> 139 (-2.80%) bytes.IndexAny changed bytes.Runes 462 -> 455 (-1.52%) bytes.trimLeftUnicode changed bytes.trimRightUnicode 325 -> 316 (-2.77%) bytes.LastIndexAny 1261 -> 1256 (-0.40%) bytes.Count 524 -> 520 (-0.76%) strings strings.Map 1241 -> 1230 (-0.89%) strings.TrimFunc 261 -> 255 (-2.30%) strings.Count changed strings.IndexRune changed strings.TrimLeftFunc 249 -> 241 (-3.21%) strings.explode 462 -> 441 (-4.55%) strings.IndexAny changed strings.ToValidUTF8 changed strings.FieldsFunc 744 -> 741 (-0.40%) strings.EqualFold 638 -> 625 (-2.04%) strings.IndexFunc 185 -> 179 (-3.24%) strings.ContainsFunc 189 -> 185 (-2.12%) strings.indexFunc 213 -> 209 (-1.88%) go/build/constraint go/build/constraint.(*exprParser).lex changed go/build/constraint.isValidTag changed regexp/syntax regexp/syntax.isValidCaptureName 180 -> 174 (-3.33%) regexp/syntax.literalRegexp changed regexp/syntax.(*parser).parsePerlFlags changed regexp/syntax.parse changed time time.tzsetName 471 -> 455 (-3.40%) time.tzsetRule 2476 -> 2444 (-1.29%) time.tzsetNum 389 -> 365 (-6.17%) time.quote 1239 -> 1221 (-1.45%) time.tzsetOffset 1332 -> 1317 (-1.13%) io/fs io/fs.FileMode.String changed reflect reflect.Value.Seq2.func4 changed reflect.Value.Seq.func4 changed reflect.isValidFieldName 265 -> 261 (-1.51%) bytes [cmd/compile] bytes.Runes 462 -> 455 (-1.52%) bytes.trimLeftUnicode changed bytes.LastIndexAny 1261 -> 1256 (-0.40%) bytes.IndexAny changed bytes.trimRightUnicode 325 -> 316 (-2.77%) bytes.Count 524 -> 520 (-0.76%) bytes.containsRune 143 -> 139 (-2.80%) strings [cmd/compile] strings.indexFunc 213 -> 209 (-1.88%) strings.IndexAny changed strings.FieldsFunc 744 -> 741 (-0.40%) strings.IndexRune changed strings.Count changed strings.IndexFunc 185 -> 179 (-3.24%) strings.Map 1241 -> 1230 (-0.89%) strings.TrimFunc 261 -> 255 (-2.30%) strings.ToValidUTF8 changed strings.explode 462 -> 441 (-4.55%) strings.EqualFold 638 -> 625 (-2.04%) strings.ContainsFunc 189 -> 185 (-2.12%) strings.TrimLeftFunc 249 -> 241 (-3.21%) go/build/constraint [cmd/compile] go/build/constraint.(*exprParser).lex changed go/build/constraint.isValidTag changed regexp/syntax [cmd/compile] regexp/syntax.literalRegexp changed regexp/syntax.parse changed regexp/syntax.(*parser).parsePerlFlags changed regexp/syntax.isValidCaptureName 180 -> 174 (-3.33%) fmt fmt.(*ss).scanOne changed fmt.(*ss).scanUint changed fmt.(*ss).scanInt changed fmt.(*fmt).pad changed fmt.(*ss).getBase 447 -> 435 (-2.68%) fmt.(*fmt).fmtS 217 -> 211 (-2.76%) fmt.(*ss).consume changed fmt.(*fmt).fmtQ 494 -> 485 (-1.82%) fmt.(*fmt).truncateString changed fmt.(*ss).scanComplex changed fmt.(*ss).okVerb 410 -> 409 (-0.24%) fmt.(*ss).convertString 447 -> 436 (-2.46%) fmt.(*ss).peek changed fmt.FormatString 650 -> 625 (-3.85%) fmt.(*fmt).padString changed fmt.(*ss).convertFloat changed fmt.(*ss).scanBool changed fmt.indexRune changed time [cmd/compile] time.tzsetNum 389 -> 365 (-6.17%) time.tzsetOffset 1332 -> 1317 (-1.13%) time.tzsetName 471 -> 455 (-3.40%) time.tzsetRule 2476 -> 2444 (-1.29%) time.quote 1239 -> 1221 (-1.45%) net/url net/url.validOptionalPort 189 -> 186 (-1.59%) net/url.validUserinfo 229 -> 204 (-10.92%) net/url.parseAuthority 972 -> 948 (-2.47%) net/url.parseHost 1372 -> 1371 (-0.07%) net/url.splitHostPort 584 -> 581 (-0.51%) reflect [cmd/compile] reflect.isValidFieldName 265 -> 261 (-1.51%) reflect.Value.Seq2.func4 changed reflect.Value.Seq.func4 changed compress/gzip compress/gzip.(*Writer).writeString changed encoding/json encoding/json.isValidTag 313 -> 308 (-1.60%) testing testing.rewrite changed testing.(*B).ReportMetric changed mime mime.consumeValue 1012 -> 997 (-1.48%) mime.isToken 180 -> 172 (-4.44%) mime.checkMediaTypeDisposition changed mime.FormatMediaType 6375 -> 6343 (-0.50%) mime.consumeToken changed mime.needsEncoding 137 -> 135 (-1.46%) mime.WordEncoder.Encode 216 -> 210 (-2.78%) mime.consumeMediaParam 1620 -> 1605 (-0.93%) mime.hasNonWhitespace 142 -> 139 (-2.11%) mime.(*WordDecoder).DecodeHeader 2643 -> 2630 (-0.49%) mime.ParseMediaType 3037 -> 3035 (-0.07%) go/token go/token.IsIdentifier changed encoding/asn1 encoding/asn1.makeField changed text/tabwriter text/tabwriter.(*Writer).Write 3465 -> 3454 (-0.32%) text/tabwriter.(*Writer).updateWidth changed text/tabwriter.(*Writer).endEscape 335 -> 327 (-2.39%) internal/buildcfg internal/buildcfg.goriscv64 changed go/doc/comment go/doc/comment.wrap 5496 -> 5489 (-0.13%) go/doc/comment.(*Printer).Text 1033 -> 1030 (-0.29%) go/doc/comment.validImportPath 661 -> 648 (-1.97%) go/doc/comment.(*Heading).DefaultID changed go/doc/comment.(*textPrinter).text 1070 -> 1069 (-0.09%) archive/tar archive/tar.splitUSTARPath changed archive/tar.(*Writer).writeRawFile changed archive/tar.(*Reader).readHeader 2416 -> 2415 (-0.04%) archive/tar.isASCII 136 -> 133 (-2.21%) archive/tar.Header.allowedFormats.func1 changed archive/tar.toASCII 415 -> 393 (-5.30%) archive/tar.(*Writer).writePAXHeader.func1 645 -> 627 (-2.79%) crypto/x509/pkix crypto/x509/pkix.RDNSequence.String 1502 -> 1486 (-1.07%) go/constant go/constant.(*stringVal).String changed vendor/golang.org/x/net/idna vendor/golang.org/x/net/idna.decode changed vendor/golang.org/x/net/idna.encode 2000 -> 1968 (-1.60%) internal/trace/raw internal/trace/raw.readArgs 783 -> 781 (-0.26%) internal/trace/raw.NewTextReader 1158 -> 1157 (-0.09%) internal/trace/raw.readToken 542 -> 532 (-1.85%) cmd/internal/objabi cmd/internal/objabi.DecodeArg changed cmd/internal/quoted cmd/internal/quoted.Join changed cmd/internal/pkgpath cmd/internal/pkgpath.toSymbolV3 changed cmd/internal/pkgpath.toSymbolV2 changed testing/fstest testing/fstest.(*fsTester).checkGlob changed text/template text/template.JSEscapeString changed text/template.goodName changed io/fs [cmd/compile] io/fs.FileMode.String changed go/printer go/printer.sanitizeImportPath 470 -> 463 (-1.49%) go/printer.(*printer).isOneLineFieldList changed go/printer.identListSize 261 -> 254 (-2.68%) go/doc go/doc.assumedPackageName changed go/doc.firstSentence changed net net.parseCriteria.func1 changed net.hasUpperCase 181 -> 180 (-0.55%) net.parsePort changed net.lookupStaticHost changed html/template html/template.htmlNameFilter 251 -> 249 (-0.80%) vendor/golang.org/x/net/http/httpguts vendor/golang.org/x/net/http/httpguts.tokenEqual changed vendor/golang.org/x/net/http/httpguts.headerValueContainsToken 971 -> 965 (-0.62%) mime/multipart mime/multipart.(*Writer).SetBoundary 510 -> 505 (-0.98%) go/build go/build.splitQuoted 1157 -> 1148 (-0.78%) go/build.parseGoEmbed changed go/build.isValidImport 203 -> 197 (-2.96%) net/mail net/mail.(*addrParser).parseAddress changed net/mail.quoteString changed net/mail.(*Address).String changed crypto/x509 crypto/x509.(*Certificate).VerifyHostname 1020 -> 1018 (-0.20%) crypto/x509.toLowerCaseASCII 223 -> 215 (-3.59%) crypto/x509.matchHostnames changed crypto/x509.validHostname 506 -> 505 (-0.20%) crypto/x509.isIA5String 197 -> 186 (-5.58%) crypto/x509.parseNameConstraintsExtension.func1 changed crypto/x509.matchExactly changed crypto/x509.parseSANExtension.func1 1996 -> 1982 (-0.70%) crypto/x509.marshalSANs 3071 -> 3051 (-0.65%) crypto/x509.domainToReverseLabels 820 -> 805 (-1.83%) crypto/x509.buildCertExtensions.func2 changed crypto/x509.(*OID).unmarshalOIDText 1359 -> 1355 (-0.29%) crypto/x509.parseASN1String 1350 -> 1334 (-1.19%) cmd/cgo main.checkImportSymName changed main.splitQuoted 1157 -> 1148 (-0.78%) fmt [cmd/compile] fmt.(*fmt).fmtQ 494 -> 485 (-1.82%) fmt.(*ss).scanComplex changed fmt.(*fmt).truncateString changed fmt.(*fmt).pad changed fmt.(*ss).getBase 447 -> 435 (-2.68%) fmt.(*ss).convertFloat changed fmt.(*fmt).padString changed fmt.(*fmt).fmtS 217 -> 211 (-2.76%) fmt.(*ss).scanInt changed fmt.indexRune changed fmt.(*ss).okVerb 410 -> 409 (-0.24%) fmt.FormatString 650 -> 625 (-3.85%) fmt.(*ss).consume changed fmt.(*ss).scanUint changed fmt.(*ss).scanOne changed fmt.(*ss).peek changed fmt.(*ss).convertString 447 -> 436 (-2.46%) fmt.(*ss).scanBool changed internal/buildcfg [cmd/compile] internal/buildcfg.goriscv64 changed cmd/compile/internal/base cmd/compile/internal/base.lines.write 1451 -> 1450 (-0.07%) cmd/compile/internal/base.isnumber 165 -> 154 (-6.67%) go/token [cmd/compile] go/token.IsIdentifier changed net/url [cmd/compile] net/url.validOptionalPort 189 -> 186 (-1.59%) net/url.splitHostPort 584 -> 581 (-0.51%) net/url.parseAuthority 972 -> 948 (-2.47%) net/url.validUserinfo 229 -> 204 (-10.92%) net/url.parseHost 1372 -> 1371 (-0.07%) cmd/internal/objabi [cmd/compile] cmd/internal/objabi.DecodeArg changed text/tabwriter [cmd/compile] text/tabwriter.(*Writer).endEscape 335 -> 327 (-2.39%) text/tabwriter.(*Writer).updateWidth changed text/tabwriter.(*Writer).Write 3465 -> 3454 (-0.32%) go/doc/comment [cmd/compile] go/doc/comment.validImportPath 661 -> 648 (-1.97%) go/doc/comment.wrap 5496 -> 5489 (-0.13%) go/doc/comment.(*Printer).Text 1033 -> 1030 (-0.29%) go/doc/comment.(*textPrinter).text 1070 -> 1069 (-0.09%) go/doc/comment.(*Heading).DefaultID changed compress/gzip [cmd/compile] compress/gzip.(*Writer).writeString changed encoding/json [cmd/compile] encoding/json.isValidTag 313 -> 308 (-1.60%) cmd/doc main.match 549 -> 542 (-1.28%) go/types go/types.validatedImportPath changed go/types.(*Checker).lookupError 3109 -> 3082 (-0.87%) go/types.stripAnnotations 233 -> 229 (-1.72%) go/types.tail 153 -> 148 (-3.27%) go/types.isValidName 345 -> 330 (-4.35%) cmd/compile/internal/syntax cmd/compile/internal/syntax.(*scanner).lineComment 655 -> 634 (-3.21%) cmd/compile/internal/syntax.(*scanner).fullComment 527 -> 517 (-1.90%) crypto/tls crypto/tls.validDNSName changed go/constant [cmd/compile] go/constant.(*stringVal).String changed cmd/go/internal/str cmd/go/internal/str.ToFold 293 -> 278 (-5.12%) cmd/go/internal/str.QuoteGlob changed go/doc [cmd/compile] go/doc.firstSentence changed go/doc.assumedPackageName changed cmd/compile/internal/base [cmd/compile] cmd/compile/internal/base.lines.write 1451 -> 1450 (-0.07%) cmd/compile/internal/base.isnumber 165 -> 154 (-6.67%) cmd/compile/internal/syntax [cmd/compile] cmd/compile/internal/syntax.(*scanner).fullComment 527 -> 517 (-1.90%) cmd/compile/internal/syntax.(*scanner).lineComment changed cmd/vendor/golang.org/x/mod/module cmd/vendor/golang.org/x/mod/module.unescapeString 500 -> 487 (-2.60%) cmd/vendor/golang.org/x/mod/module.escapeString 538 -> 519 (-3.53%) cmd/vendor/golang.org/x/mod/module.checkPath changed cmd/vendor/golang.org/x/mod/module.checkElem changed cmd/vendor/golang.org/x/mod/module.CheckPath changed cmd/vendor/golang.org/x/mod/sumdb/note cmd/vendor/golang.org/x/mod/sumdb/note.isValidName 246 -> 244 (-0.81%) cmd/go/internal/base cmd/go/internal/base.validToolName 150 -> 142 (-5.33%) cmd/go/internal/base.ToolPath 488 -> 474 (-2.87%) cmd/go/internal/imports cmd/go/internal/imports.matchTag changed go/build [cmd/compile] go/build.isValidImport 203 -> 197 (-2.96%) go/build.splitQuoted 1157 -> 1148 (-0.78%) go/build.parseGoEmbed changed cmd/vendor/golang.org/x/mod/modfile cmd/vendor/golang.org/x/mod/modfile.Position.add 421 -> 412 (-2.14%) cmd/vendor/golang.org/x/mod/modfile.MustQuote 380 -> 372 (-2.11%) cmd/vendor/golang.org/x/mod/zip cmd/vendor/golang.org/x/mod/zip.strToFold changed cmd/link/internal/benchmark cmd/link/internal/benchmark.makeBenchString 476 -> 453 (-4.83%) cmd/internal/script cmd/internal/script.wrapLine 773 -> 766 (-0.91%) cmd/compile/internal/ir cmd/compile/internal/ir.splitPkg changed cmd/compile/internal/ir.splitType changed cmd/compile/internal/ir.LookupMethodSelector changed cmd/go/internal/modindex cmd/go/internal/modindex.parseGoEmbed changed cmd/go/internal/modindex.splitQuoted 1157 -> 1148 (-0.78%) cmd/pack main.setOp 325 -> 308 (-5.23%) cmd/vendor/golang.org/x/term cmd/vendor/golang.org/x/term.(*Terminal).handleKey changed cmd/compile/internal/types2 cmd/compile/internal/types2.validatedImportPath changed cmd/compile/internal/types2.tail 153 -> 148 (-3.27%) cmd/compile/internal/types2.(*Checker).lookupError 3717 -> 3690 (-0.73%) cmd/compile/internal/types2.isValidName 345 -> 330 (-4.35%) cmd/compile/internal/types2.stripAnnotations 233 -> 229 (-1.72%) net/http net/http.NewRequestWithContext 2251 -> 2245 (-0.27%) net/http.isValidWildcardName 357 -> 351 (-1.68%) net/http.ParseCookie 1100 -> 1099 (-0.09%) net/http.ParseSetCookie changed net/http.readCookies changed net/http.(*http2Framer).readMetaFrame.func1 changed net/http.isCookieNameValid changed net/http.(*Cookie).String changed net/http.(*Cookie).Valid changed net/http.validMethod changed net/http.parsePattern 4343 -> 4330 (-0.30%) net/http.http2validWireHeaderFieldName changed net/http.http2encodeHeaders changed net/http.(*Transport).roundTrip changed cmd/compile/internal/types2 [cmd/compile] cmd/compile/internal/types2.validatedImportPath changed cmd/compile/internal/types2.stripAnnotations 233 -> 229 (-1.72%) cmd/compile/internal/types2.tail 153 -> 148 (-3.27%) cmd/compile/internal/types2.(*Checker).lookupError 3717 -> 3690 (-0.73%) cmd/compile/internal/types2.isValidName 345 -> 330 (-4.35%) cmd/compile/internal/ir [cmd/compile] cmd/compile/internal/ir.LookupMethodSelector changed cmd/compile/internal/ir.splitType changed cmd/compile/internal/ir.splitPkg changed cmd/compile/internal/typecheck cmd/compile/internal/typecheck.stringtoruneslit changed net/http/cookiejar net/http/cookiejar.encode 1944 -> 1936 (-0.41%) expvar expvar.appendJSONQuote changed cmd/go/internal/web cmd/go/internal/web.(*Response).formatErrorDetail 1552 -> 1529 (-1.48%) cmd/vendor/golang.org/x/text/internal/language cmd/vendor/golang.org/x/text/internal/language.Parse 1102 -> 1099 (-0.27%) cmd/vendor/golang.org/x/tools/go/analysis cmd/vendor/golang.org/x/tools/go/analysis.validIdent 351 -> 346 (-1.42%) cmd/compile/internal/typecheck [cmd/compile] cmd/compile/internal/typecheck.stringtoruneslit changed cmd/vendor/github.com/google/pprof/internal/report cmd/vendor/github.com/google/pprof/internal/report.rightPad 377 -> 365 (-3.18%) cmd/vendor/github.com/google/pprof/internal/report.indentation 169 -> 165 (-2.37%) cmd/vendor/github.com/google/pprof/internal/report.makeWebListLine changed cmd/vendor/golang.org/x/tools/go/analysis/passes/buildtag cmd/vendor/golang.org/x/tools/go/analysis/passes/buildtag.(*checker).plusBuildLine changed cmd/vendor/golang.org/x/tools/go/analysis/passes/directive cmd/vendor/golang.org/x/tools/go/analysis/passes/directive.(*checker).comment changed cmd/vendor/rsc.io/markdown cmd/vendor/rsc.io/markdown.(*CodeBlock).PrintHTML changed cmd/vendor/rsc.io/markdown.(*Code).printMarkdown changed cmd/vendor/rsc.io/markdown.newATXHeading changed cmd/vendor/rsc.io/markdown.longestSequence 249 -> 237 (-4.82%) cmd/vendor/rsc.io/markdown.newFence changed cmd/link/internal/ld cmd/link/internal/ld.methodref.isExported changed cmd/go/internal/modload cmd/go/internal/modload.ShortMessage changed cmd/go/internal/work cmd/go/internal/work.encodeArg changed cmd/compile/internal/walk cmd/compile/internal/walk.rangeAssign2 changed cmd/compile/internal/walk.arrayRangeClear changed cmd/compile/internal/walk.rangeAssign changed cmd/compile/internal/walk.mapClear changed cmd/compile/internal/walk.arrayClear changed cmd/compile/internal/walk.isMapClear changed cmd/compile/internal/walk.walkRange 15218 -> 15538 (+2.10%) cmd/compile/internal/walk.mapRangeClear changed cmd/compile/internal/walk.mapRangeClear.func1 changed cmd/compile/internal/walk.rangeConvert changed cmd/compile/internal/noder cmd/compile/internal/noder.checkImportPath changed cmd/compile/internal/noder.pragmaFields changed cmd/compile/internal/noder.parseGoEmbed 1309 -> 1300 (-0.69%) cmd/compile/internal/walk [cmd/compile] cmd/compile/internal/walk.mapRangeClear changed cmd/compile/internal/walk.rangeAssign2 changed cmd/compile/internal/walk.arrayClear changed cmd/compile/internal/walk.arrayRangeClear changed cmd/compile/internal/walk.walkRange 14789 -> 15109 (+2.16%) cmd/compile/internal/walk.mapRangeClear.func1 changed cmd/compile/internal/walk.rangeConvert changed cmd/compile/internal/walk.mapClear changed cmd/compile/internal/walk.isMapClear changed cmd/compile/internal/walk.rangeAssign changed cmd/compile/internal/noder [cmd/compile] cmd/compile/internal/noder.pragmaFields changed cmd/compile/internal/noder.parseGoEmbed 1309 -> 1300 (-0.69%) cmd/compile/internal/noder.checkImportPath changed file before after Δ % runtime.s 577251 577217 -34 -0.006% runtime [cmd/compile].s 642419 642385 -34 -0.005% bytes.s 36806 36777 -29 -0.079% strings.s 44176 44100 -76 -0.172% regexp/syntax.s 81719 81713 -6 -0.007% time.s 94341 94236 -105 -0.111% reflect.s 180291 180287 -4 -0.002% bytes [cmd/compile].s 38181 38152 -29 -0.076% strings [cmd/compile].s 44192 44116 -76 -0.172% regexp/syntax [cmd/compile].s 81719 81713 -6 -0.007% fmt.s 75019 74955 -64 -0.085% time [cmd/compile].s 94341 94236 -105 -0.111% net/url.s 37111 37055 -56 -0.151% reflect [cmd/compile].s 180340 180336 -4 -0.002% encoding/json.s 110294 110289 -5 -0.005% mime.s 47009 46913 -96 -0.204% text/tabwriter.s 9538 9519 -19 -0.199% go/doc/comment.s 49401 49377 -24 -0.049% archive/tar.s 71994 71950 -44 -0.061% crypto/x509/pkix.s 8493 8477 -16 -0.188% vendor/golang.org/x/net/idna.s 21271 21239 -32 -0.150% internal/trace/raw.s 15413 15400 -13 -0.084% go/printer.s 93669 93655 -14 -0.015% net.s 299569 299568 -1 -0.000% html/template.s 97069 97067 -2 -0.002% vendor/golang.org/x/net/http/httpguts.s 3187 3181 -6 -0.188% mime/multipart.s 31070 31065 -5 -0.016% go/build.s 75077 75062 -15 -0.020% crypto/x509.s 177195 177104 -91 -0.051% cmd/cgo.s 215638 215629 -9 -0.004% fmt [cmd/compile].s 86358 86294 -64 -0.074% cmd/compile/internal/base.s 44380 44368 -12 -0.027% net/url [cmd/compile].s 37222 37166 -56 -0.150% text/tabwriter [cmd/compile].s 9649 9630 -19 -0.197% go/doc/comment [cmd/compile].s 49512 49488 -24 -0.048% encoding/json [cmd/compile].s 110712 110707 -5 -0.005% cmd/doc.s 54581 54574 -7 -0.013% go/types.s 558219 558168 -51 -0.009% cmd/compile/internal/syntax.s 181755 181724 -31 -0.017% cmd/go/internal/str.s 3166 3151 -15 -0.474% cmd/compile/internal/base [cmd/compile].s 44589 44577 -12 -0.027% cmd/compile/internal/syntax [cmd/compile].s 196105 196095 -10 -0.005% cmd/vendor/golang.org/x/mod/module.s 19140 19108 -32 -0.167% cmd/vendor/golang.org/x/mod/sumdb/note.s 12831 12829 -2 -0.016% cmd/go/internal/base.s 20413 20391 -22 -0.108% go/build [cmd/compile].s 75188 75173 -15 -0.020% cmd/vendor/golang.org/x/mod/modfile.s 116513 116496 -17 -0.015% cmd/link/internal/benchmark.s 4068 4045 -23 -0.565% cmd/internal/script.s 83442 83435 -7 -0.008% cmd/go/internal/modindex.s 83527 83518 -9 -0.011% cmd/pack.s 9128 9111 -17 -0.186% cmd/compile/internal/types2.s 540279 540228 -51 -0.009% net/http.s 620639 620613 -26 -0.004% cmd/compile/internal/types2 [cmd/compile].s 577279 577228 -51 -0.009% net/http/cookiejar.s 28569 28561 -8 -0.028% cmd/go/internal/web.s 16316 16293 -23 -0.141% cmd/vendor/golang.org/x/text/internal/language.s 57819 57816 -3 -0.005% cmd/vendor/golang.org/x/tools/go/analysis.s 5528 5523 -5 -0.090% cmd/vendor/github.com/google/pprof/internal/report.s 83881 83865 -16 -0.019% cmd/vendor/rsc.io/markdown.s 117312 117300 -12 -0.010% cmd/compile/internal/walk.s 329328 329648 +320 +0.097% cmd/compile/internal/noder.s 262295 262286 -9 -0.003% cmd/compile/internal/walk [cmd/compile].s 350300 350620 +320 +0.091% cmd/compile/internal/noder [cmd/compile].s 298464 298455 -9 -0.003% total 36179015 36177972 -1043 -0.003% Change-Id: I191371db975761c24e53bb83bef0c42fa8ba3485 Reviewed-on: https://go-review.googlesource.com/c/go/+/641758 Reviewed-by: Keith Randall Reviewed-by: Keith Randall Reviewed-by: Cherry Mui LUCI-TryBot-Result: Go LUCI --- src/cmd/compile/internal/walk/range.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/walk/range.go b/src/cmd/compile/internal/walk/range.go index a51b218ae57d20..ede9f2182d494f 100644 --- a/src/cmd/compile/internal/walk/range.go +++ b/src/cmd/compile/internal/walk/range.go @@ -342,7 +342,10 @@ func walkRange(nrange *ir.RangeStmt) ir.Node { // if hv2 < utf8.RuneSelf nif := ir.NewIfStmt(base.Pos, nil, nil, nil) - nif.Cond = ir.NewBinaryExpr(base.Pos, ir.OLT, hv2, ir.NewInt(base.Pos, utf8.RuneSelf)) + + // On x86, hv2 <= 127 is shorter to encode than hv2 < 128 + // Doesn't hurt other archs. + nif.Cond = ir.NewBinaryExpr(base.Pos, ir.OLE, hv2, ir.NewInt(base.Pos, utf8.RuneSelf-1)) // hv1++ nif.Body = []ir.Node{ir.NewAssignStmt(base.Pos, hv1, ir.NewBinaryExpr(base.Pos, ir.OADD, hv1, ir.NewInt(base.Pos, 1)))} From 3981b446ddba60108572606a74bc27bff1936d9e Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Fri, 22 Nov 2024 15:24:54 -0800 Subject: [PATCH 223/397] cmd/internal/sys: allow unaligned loads on big-endian ppc64 According to https://go.dev/wiki/MinimumRequirements, we've required power8 since Go 1.9. Before that, we supported power5 which couldn't do unaligned loads. But power8 should be able to (it does for ppc64le). In fact, I think we already support unaligned loads in some cases, for instance cmd/compile/internal/ssa/config.go lists big-endian ppc64 as having unaligned loads. Change-Id: I4a75f09d4b5199a889e0e8db0b3b7a1fa23145f3 Reviewed-on: https://go-review.googlesource.com/c/go/+/631318 LUCI-TryBot-Result: Go LUCI Reviewed-by: Keith Randall Reviewed-by: Jayanth Krishnamurthy Reviewed-by: Keith Randall Reviewed-by: Cherry Mui --- src/cmd/internal/sys/arch.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/internal/sys/arch.go b/src/cmd/internal/sys/arch.go index 2e35284137833a..ee7089b544f57a 100644 --- a/src/cmd/internal/sys/arch.go +++ b/src/cmd/internal/sys/arch.go @@ -208,7 +208,7 @@ var ArchPPC64 = &Arch{ RegSize: 8, MinLC: 4, Alignment: 1, - CanMergeLoads: false, + CanMergeLoads: true, HasLR: true, // PIC code on ppc64le requires 32 bytes of stack, and it's // easier to just use that much stack always. From bdc2d856a872f42705b3a7045c3420031efa4af7 Mon Sep 17 00:00:00 2001 From: Jakub Ciolek Date: Tue, 14 Jan 2025 21:29:50 +0100 Subject: [PATCH 224/397] cmd/compile: use isGenericIntConst() in prove Use the existing Value method to make it a bit shorter. Change-Id: I47c4328b5241ab48b3490a04a3d93d4428f7b88c Reviewed-on: https://go-review.googlesource.com/c/go/+/642735 LUCI-TryBot-Result: Go LUCI Reviewed-by: Cherry Mui Reviewed-by: Keith Randall Reviewed-by: Keith Randall --- src/cmd/compile/internal/ssa/prove.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/compile/internal/ssa/prove.go b/src/cmd/compile/internal/ssa/prove.go index c3948dc9b1d370..8d0bb73d4c0c08 100644 --- a/src/cmd/compile/internal/ssa/prove.go +++ b/src/cmd/compile/internal/ssa/prove.go @@ -1362,11 +1362,11 @@ func prove(f *Func) { start, end = end, start } - if !(start.Op == OpConst8 || start.Op == OpConst16 || start.Op == OpConst32 || start.Op == OpConst64) { + if !start.isGenericIntConst() { // if start is not a constant we would be winning nothing from inverting the loop continue } - if end.Op == OpConst8 || end.Op == OpConst16 || end.Op == OpConst32 || end.Op == OpConst64 { + if end.isGenericIntConst() { // TODO: if both start and end are constants we should rewrite such that the comparison // is against zero and nxt is ++ or -- operation // That means: From 46fd6b4e37f043b57a2d426a633f61ffd4c40931 Mon Sep 17 00:00:00 2001 From: Jakub Ciolek Date: Sun, 5 Jan 2025 11:31:11 +0100 Subject: [PATCH 225/397] cmd/compile: remove reduntant Zero rule These two rules produce the same output but have opposite s%16 conditions. Consolidate them into a single rule. Change-Id: I6daa0e7f7af4a4e59a3125b66b85f59e888586c5 Reviewed-on: https://go-review.googlesource.com/c/go/+/640475 LUCI-TryBot-Result: Go LUCI Reviewed-by: Keith Randall Reviewed-by: Keith Randall Reviewed-by: Cherry Mui --- src/cmd/compile/internal/ssa/_gen/AMD64.rules | 6 +---- src/cmd/compile/internal/ssa/rewriteAMD64.go | 25 ++----------------- 2 files changed, 3 insertions(+), 28 deletions(-) diff --git a/src/cmd/compile/internal/ssa/_gen/AMD64.rules b/src/cmd/compile/internal/ssa/_gen/AMD64.rules index 716f4f1c32d153..1a32c26ae24b26 100644 --- a/src/cmd/compile/internal/ssa/_gen/AMD64.rules +++ b/src/cmd/compile/internal/ssa/_gen/AMD64.rules @@ -404,11 +404,7 @@ (MOVQstoreconst [makeValAndOff(0,0)] destptr mem)) // Adjust zeros to be a multiple of 16 bytes. -(Zero [s] destptr mem) && s%16 != 0 && s > 16 && s%16 > 8 && config.useSSE => - (Zero [s-s%16] (OffPtr destptr [s%16]) - (MOVOstoreconst [makeValAndOff(0,0)] destptr mem)) - -(Zero [s] destptr mem) && s%16 != 0 && s > 16 && s%16 <= 8 && config.useSSE => +(Zero [s] destptr mem) && s%16 != 0 && s > 16 && config.useSSE => (Zero [s-s%16] (OffPtr destptr [s%16]) (MOVOstoreconst [makeValAndOff(0,0)] destptr mem)) diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go index d62f38f0e2f594..7dc0a7bdc2a1a1 100644 --- a/src/cmd/compile/internal/ssa/rewriteAMD64.go +++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go @@ -30270,34 +30270,13 @@ func rewriteValueAMD64_OpZero(v *Value) bool { return true } // match: (Zero [s] destptr mem) - // cond: s%16 != 0 && s > 16 && s%16 > 8 && config.useSSE + // cond: s%16 != 0 && s > 16 && config.useSSE // result: (Zero [s-s%16] (OffPtr destptr [s%16]) (MOVOstoreconst [makeValAndOff(0,0)] destptr mem)) for { s := auxIntToInt64(v.AuxInt) destptr := v_0 mem := v_1 - if !(s%16 != 0 && s > 16 && s%16 > 8 && config.useSSE) { - break - } - v.reset(OpZero) - v.AuxInt = int64ToAuxInt(s - s%16) - v0 := b.NewValue0(v.Pos, OpOffPtr, destptr.Type) - v0.AuxInt = int64ToAuxInt(s % 16) - v0.AddArg(destptr) - v1 := b.NewValue0(v.Pos, OpAMD64MOVOstoreconst, types.TypeMem) - v1.AuxInt = valAndOffToAuxInt(makeValAndOff(0, 0)) - v1.AddArg2(destptr, mem) - v.AddArg2(v0, v1) - return true - } - // match: (Zero [s] destptr mem) - // cond: s%16 != 0 && s > 16 && s%16 <= 8 && config.useSSE - // result: (Zero [s-s%16] (OffPtr destptr [s%16]) (MOVOstoreconst [makeValAndOff(0,0)] destptr mem)) - for { - s := auxIntToInt64(v.AuxInt) - destptr := v_0 - mem := v_1 - if !(s%16 != 0 && s > 16 && s%16 <= 8 && config.useSSE) { + if !(s%16 != 0 && s > 16 && config.useSSE) { break } v.reset(OpZero) From 7472b4c324970895b1d44f39c284d72c40d4b621 Mon Sep 17 00:00:00 2001 From: David Chase Date: Wed, 8 Jan 2025 17:01:05 -0500 Subject: [PATCH 226/397] cmd/compile: include liveness info in GOSSAFUNC output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For this function ``` func test(a, b int, c string, s []int, r [3]int, f ifn) { in(a) in(b) sl(s) ar(r) fu(f) } ``` this output ``` HASH live at entry to test: f s HASH /Users/drchase/work/src/live/main.go 00000 (15) TEXT main.test(SB), ABIInternal 00001 (15) FUNCDATA $0, gclocals·vYpXgR4/KsH5nhFsqkHG1Q==(SB) 00002 (15) FUNCDATA $1, gclocals·Soq6RzO4SX8YA1O9euewoQ==(SB) 00003 (15) FUNCDATA $5, main.test.arginfo1(SB) 00004 (15) FUNCDATA $6, main.test.argliveinfo(SB) b1 00005 (15) PCDATA $3, $1 v32 00006 (21) MOVD R6, main.s+72(RSP) v27 00007 (21) MOVD R5, main.s+64(RSP) v30 00008 (21) MOVD R4, main.s+56(RSP) v7 00009 (21) MOVD R1, main.b+32(RSP) v34 00010 (21) MOVD R7, main.f+80(RSP) v34 00011 (21) PCDATA $3, $2 v15 00012 (+16) PCDATA $1, $0 HASH live at call to in: f s v15 00013 (+16) CALL main.in(SB) v3 00014 (+17) MOVD main.b+32(RSP), R0 HASH live at call to in: f s v17 00015 (+17) CALL main.in(SB) v8 00016 (+18) MOVD main.s+56(RSP), R0 v21 00017 (18) MOVD main.s+64(RSP), R1 v33 00018 (18) MOVD main.s+72(RSP), R2 v19 00019 (+18) PCDATA $1, $1 HASH live at call to sl: f v19 00020 (+18) CALL main.sl(SB) v29 00021 (+19) LDP main.r(RSP), (R1, R2) v9 00022 (19) STP (R1, R2), 8(RSP) v12 00023 (19) MOVD main.r+16(RSP), R1 v31 00024 (19) MOVD R1, 24(RSP) HASH live at call to ar: f v22 00025 (+19) CALL main.ar(SB) v35 00026 (+20) MOVD main.f+80(RSP), R0 v24 00027 (+20) PCDATA $1, $2 HASH live at call to fu: v24 00028 (+20) CALL main.fu(SB) b1 00029 (21) RET 00030 (?) END ``` Where "HASH" is the git commit comment character I don't know how to escape and this was easier than fighting with git. Change-Id: I0691a3f7988db111d11d69388ace83641a841e57 Reviewed-on: https://go-review.googlesource.com/c/go/+/641360 LUCI-TryBot-Result: Go LUCI Reviewed-by: Cuong Manh Le Reviewed-by: Michael Knyszek --- .../compile/internal/liveness/mergelocals.go | 2 +- src/cmd/compile/internal/liveness/plive.go | 76 ++++++++++++------- src/cmd/compile/internal/ssagen/ssa.go | 27 ++++++- 3 files changed, 75 insertions(+), 30 deletions(-) diff --git a/src/cmd/compile/internal/liveness/mergelocals.go b/src/cmd/compile/internal/liveness/mergelocals.go index cbe49aa6550838..6967ee016ee710 100644 --- a/src/cmd/compile/internal/liveness/mergelocals.go +++ b/src/cmd/compile/internal/liveness/mergelocals.go @@ -56,7 +56,7 @@ type candRegion struct { type cstate struct { fn *ir.Func f *ssa.Func - lv *liveness + lv *Liveness cands []*ir.Name nameToSlot map[*ir.Name]int32 regions []candRegion diff --git a/src/cmd/compile/internal/liveness/plive.go b/src/cmd/compile/internal/liveness/plive.go index a20d856aa2a77e..ac0c2dff0a96c2 100644 --- a/src/cmd/compile/internal/liveness/plive.go +++ b/src/cmd/compile/internal/liveness/plive.go @@ -102,8 +102,8 @@ type blockEffects struct { liveout bitvec.BitVec } -// A collection of global state used by liveness analysis. -type liveness struct { +// A collection of global state used by Liveness analysis. +type Liveness struct { fn *ir.Func f *ssa.Func vars []*ir.Name @@ -235,7 +235,7 @@ func getvariables(fn *ir.Func) ([]*ir.Name, map[*ir.Name]int32) { return vars, idx } -func (lv *liveness) initcache() { +func (lv *Liveness) initcache() { if lv.cache.initialized { base.Fatalf("liveness cache initialized twice") return @@ -281,7 +281,7 @@ const ( // valueEffects returns the index of a variable in lv.vars and the // liveness effects v has on that variable. // If v does not affect any tracked variables, it returns -1, 0. -func (lv *liveness) valueEffects(v *ssa.Value) (int32, liveEffect) { +func (lv *Liveness) valueEffects(v *ssa.Value) (int32, liveEffect) { n, e := affectedVar(v) if e == 0 || n == nil { // cheapest checks first return -1, 0 @@ -392,8 +392,8 @@ type livenessFuncCache struct { // Constructs a new liveness structure used to hold the global state of the // liveness computation. The cfg argument is a slice of *BasicBlocks and the // vars argument is a slice of *Nodes. -func newliveness(fn *ir.Func, f *ssa.Func, vars []*ir.Name, idx map[*ir.Name]int32, stkptrsize int64) *liveness { - lv := &liveness{ +func newliveness(fn *ir.Func, f *ssa.Func, vars []*ir.Name, idx map[*ir.Name]int32, stkptrsize int64) *Liveness { + lv := &Liveness{ fn: fn, f: f, vars: vars, @@ -447,14 +447,14 @@ func newliveness(fn *ir.Func, f *ssa.Func, vars []*ir.Name, idx map[*ir.Name]int return lv } -func (lv *liveness) blockEffects(b *ssa.Block) *blockEffects { +func (lv *Liveness) blockEffects(b *ssa.Block) *blockEffects { return &lv.be[b.ID] } // Generates live pointer value maps for arguments and local variables. The // this argument and the in arguments are always assumed live. The vars // argument is a slice of *Nodes. -func (lv *liveness) pointerMap(liveout bitvec.BitVec, vars []*ir.Name, args, locals bitvec.BitVec) { +func (lv *Liveness) pointerMap(liveout bitvec.BitVec, vars []*ir.Name, args, locals bitvec.BitVec) { var slotsSeen map[int64]*ir.Name checkForDuplicateSlots := base.Debug.MergeLocals != 0 if checkForDuplicateSlots { @@ -504,7 +504,7 @@ func IsUnsafe(f *ssa.Func) bool { } // markUnsafePoints finds unsafe points and computes lv.unsafePoints. -func (lv *liveness) markUnsafePoints() { +func (lv *Liveness) markUnsafePoints() { if IsUnsafe(lv.f) { // No complex analysis necessary. lv.allUnsafe = true @@ -647,7 +647,7 @@ func (lv *liveness) markUnsafePoints() { // This does not necessarily mean the instruction is a safe-point. In // particular, call Values can have a stack map in case the callee // grows the stack, but not themselves be a safe-point. -func (lv *liveness) hasStackMap(v *ssa.Value) bool { +func (lv *Liveness) hasStackMap(v *ssa.Value) bool { if !v.Op.IsCall() { return false } @@ -663,7 +663,7 @@ func (lv *liveness) hasStackMap(v *ssa.Value) bool { // Initializes the sets for solving the live variables. Visits all the // instructions in each basic block to summarizes the information at each basic // block -func (lv *liveness) prologue() { +func (lv *Liveness) prologue() { lv.initcache() for _, b := range lv.f.Blocks { @@ -685,7 +685,7 @@ func (lv *liveness) prologue() { } // Solve the liveness dataflow equations. -func (lv *liveness) solve() { +func (lv *Liveness) solve() { // These temporary bitvectors exist to avoid successive allocations and // frees within the loop. nvars := int32(len(lv.vars)) @@ -745,7 +745,7 @@ func (lv *liveness) solve() { // Visits all instructions in a basic block and computes a bit vector of live // variables at each safe point locations. -func (lv *liveness) epilogue() { +func (lv *Liveness) epilogue() { nvars := int32(len(lv.vars)) liveout := bitvec.New(nvars) livedefer := bitvec.New(nvars) // always-live variables @@ -914,7 +914,7 @@ func (lv *liveness) epilogue() { // is actually a net loss: we save about 50k of argument bitmaps but the new // PCDATA tables cost about 100k. So for now we keep using a single index for // both bitmap lists. -func (lv *liveness) compact(b *ssa.Block) { +func (lv *Liveness) compact(b *ssa.Block) { pos := 0 if b == lv.f.Entry { // Handle entry stack map. @@ -939,7 +939,7 @@ func (lv *liveness) compact(b *ssa.Block) { lv.livevars = lv.livevars[:0] } -func (lv *liveness) enableClobber() { +func (lv *Liveness) enableClobber() { // The clobberdead experiment inserts code to clobber pointer slots in all // the dead variables (locals and args) at every synchronous safepoint. if !base.Flag.ClobberDead { @@ -994,7 +994,7 @@ func (lv *liveness) enableClobber() { // Inserts code to clobber pointer slots in all the dead variables (locals and args) // at every synchronous safepoint in b. -func (lv *liveness) clobber(b *ssa.Block) { +func (lv *Liveness) clobber(b *ssa.Block) { // Copy block's values to a temporary. oldSched := append([]*ssa.Value{}, b.Values...) b.Values = b.Values[:0] @@ -1029,7 +1029,7 @@ func (lv *liveness) clobber(b *ssa.Block) { // clobber generates code to clobber pointer slots in all dead variables // (those not marked in live). Clobbering instructions are added to the end // of b.Values. -func clobber(lv *liveness, b *ssa.Block, live bitvec.BitVec) { +func clobber(lv *Liveness, b *ssa.Block, live bitvec.BitVec) { for i, n := range lv.vars { if !live.Get(int32(i)) && !n.Addrtaken() && !n.OpenDeferSlot() && !n.IsOutputParamHeapAddr() { // Don't clobber stack objects (address-taken). They are @@ -1102,7 +1102,7 @@ func clobberPtr(b *ssa.Block, v *ir.Name, offset int64) { b.NewValue0IA(src.NoXPos, ssa.OpClobber, types.TypeVoid, offset, v) } -func (lv *liveness) showlive(v *ssa.Value, live bitvec.BitVec) { +func (lv *Liveness) showlive(v *ssa.Value, live bitvec.BitVec) { if base.Flag.Live == 0 || ir.FuncName(lv.fn) == "init" || strings.HasPrefix(ir.FuncName(lv.fn), ".") { return } @@ -1119,6 +1119,24 @@ func (lv *liveness) showlive(v *ssa.Value, live bitvec.BitVec) { return } + pos, s := lv.format(v, live) + + base.WarnfAt(pos, "%s", s) +} + +func (lv *Liveness) Format(v *ssa.Value) string { + if v == nil { + _, s := lv.format(nil, lv.stackMaps[0]) + return s + } + if idx := lv.livenessMap.Get(v); idx.StackMapValid() { + _, s := lv.format(v, lv.stackMaps[idx]) + return s + } + return "" +} + +func (lv *Liveness) format(v *ssa.Value, live bitvec.BitVec) (src.XPos, string) { pos := lv.fn.Nname.Pos() if v != nil { pos = v.Pos @@ -1149,11 +1167,10 @@ func (lv *liveness) showlive(v *ssa.Value, live bitvec.BitVec) { for _, v := range names { s += " " + v } - - base.WarnfAt(pos, "%s", s) + return pos, s } -func (lv *liveness) printbvec(printed bool, name string, live bitvec.BitVec) bool { +func (lv *Liveness) printbvec(printed bool, name string, live bitvec.BitVec) bool { if live.IsEmpty() { return printed } @@ -1177,7 +1194,7 @@ func (lv *liveness) printbvec(printed bool, name string, live bitvec.BitVec) boo } // printeffect is like printbvec, but for valueEffects. -func (lv *liveness) printeffect(printed bool, name string, pos int32, x bool) bool { +func (lv *Liveness) printeffect(printed bool, name string, pos int32, x bool) bool { if !x { return printed } @@ -1197,7 +1214,7 @@ func (lv *liveness) printeffect(printed bool, name string, pos int32, x bool) bo // Prints the computed liveness information and inputs, for debugging. // This format synthesizes the information used during the multiple passes // into a single presentation. -func (lv *liveness) printDebug() { +func (lv *Liveness) printDebug() { fmt.Printf("liveness: %s\n", ir.FuncName(lv.fn)) for i, b := range lv.f.Blocks { @@ -1309,7 +1326,7 @@ func (lv *liveness) printDebug() { // first word dumped is the total number of bitmaps. The second word is the // length of the bitmaps. All bitmaps are assumed to be of equal length. The // remaining bytes are the raw bitmaps. -func (lv *liveness) emit() (argsSym, liveSym *obj.LSym) { +func (lv *Liveness) emit() (argsSym, liveSym *obj.LSym) { // Size args bitmaps to be just large enough to hold the largest pointer. // First, find the largest Xoffset node we care about. // (Nodes without pointers aren't in lv.vars; see ShouldTrack.) @@ -1370,7 +1387,7 @@ func (lv *liveness) emit() (argsSym, liveSym *obj.LSym) { // structure read by the garbage collector. // Returns a map from GC safe points to their corresponding stack map index, // and a map that contains all input parameters that may be partially live. -func Compute(curfn *ir.Func, f *ssa.Func, stkptrsize int64, pp *objw.Progs) (Map, map[*ir.Name]bool) { +func Compute(curfn *ir.Func, f *ssa.Func, stkptrsize int64, pp *objw.Progs, retLiveness bool) (Map, map[*ir.Name]bool, *Liveness) { // Construct the global liveness state. vars, idx := getvariables(curfn) lv := newliveness(curfn, f, vars, idx, stkptrsize) @@ -1432,10 +1449,15 @@ func Compute(curfn *ir.Func, f *ssa.Func, stkptrsize int64, pp *objw.Progs) (Map p.To.Sym = x } - return lv.livenessMap, lv.partLiveArgs + retLv := lv + if !retLiveness { + retLv = nil + } + + return lv.livenessMap, lv.partLiveArgs, retLv } -func (lv *liveness) emitStackObjects() *obj.LSym { +func (lv *Liveness) emitStackObjects() *obj.LSym { var vars []*ir.Name for _, n := range lv.fn.Dcl { if shouldTrack(n) && n.Addrtaken() && n.Esc() != ir.EscHeap { diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index edd1ffb0c915e8..6e8a8b9cc86fb2 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -6335,7 +6335,10 @@ func genssa(f *ssa.Func, pp *objw.Progs) { e := f.Frontend().(*ssafn) - s.livenessMap, s.partLiveArgs = liveness.Compute(e.curfn, f, e.stkptrsize, pp) + gatherPrintInfo := f.PrintOrHtmlSSA || ssa.GenssaDump[f.Name] + + var lv *liveness.Liveness + s.livenessMap, s.partLiveArgs, lv = liveness.Compute(e.curfn, f, e.stkptrsize, pp, gatherPrintInfo) emitArgInfo(e, f, pp) argLiveBlockMap, argLiveValueMap := liveness.ArgLiveness(e.curfn, f, pp) @@ -6358,7 +6361,6 @@ func genssa(f *ssa.Func, pp *objw.Progs) { var progToValue map[*obj.Prog]*ssa.Value var progToBlock map[*obj.Prog]*ssa.Block var valueToProgAfter []*obj.Prog // The first Prog following computation of a value v; v is visible at this point. - gatherPrintInfo := f.PrintOrHtmlSSA || ssa.GenssaDump[f.Name] if gatherPrintInfo { progToValue = make(map[*obj.Prog]*ssa.Value, f.NumValues()) progToBlock = make(map[*obj.Prog]*ssa.Block, f.NumBlocks()) @@ -6766,6 +6768,14 @@ func genssa(f *ssa.Func, pp *objw.Progs) { buf.WriteString("") buf.WriteString("
    ") filename := "" + + liveness := lv.Format(nil) + if liveness != "" { + buf.WriteString("
    ") + buf.WriteString(html.EscapeString("# " + liveness)) + buf.WriteString("
    ") + } + for p := s.pp.Text; p != nil; p = p.Link { // Don't spam every line with the file name, which is often huge. // Only print changes, and "unknown" is not a change. @@ -6778,6 +6788,19 @@ func genssa(f *ssa.Func, pp *objw.Progs) { buf.WriteString("
    ") if v, ok := progToValue[p]; ok { + + // Prefix calls with their liveness, if any + if p.As != obj.APCDATA { + if liveness := lv.Format(v); liveness != "" { + // Steal this line, and restart a line + buf.WriteString("
    ") + buf.WriteString(html.EscapeString("# " + liveness)) + buf.WriteString("
    ") + // restarting a line + buf.WriteString("
    ") + } + } + buf.WriteString(v.HTML()) } else if b, ok := progToBlock[p]; ok { buf.WriteString("" + b.HTML() + "") From 5cb5437b6daee8971be0bd393535e263333ef311 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 4 Feb 2025 11:56:38 -0800 Subject: [PATCH 227/397] cmd/go/internal/vcsweb/vcstest: skip bzr test if deps not found The linux-arm64 trybots are consistently failing with vcstest_test.go:155: 2025/01/30 21:50:41 hello.txt: > handle bzr > env BZR_EMAIL='Russ Cox ' > env EMAIL='Russ Cox ' > bzr init-repo . [stderr] brz: ERROR: Couldn't import breezy and dependencies. Please check the directory containing breezy is on your PYTHONPATH. Error: PyErr { type: , value: ModuleNotFoundError("No module named 'breezy'"), traceback: None } vcstest_test.go:161: hello.txt:6: bzr init-repo .: exit status 1 This seems to be a problem with the builder. For now, skip the test if we see that error message, just as we already skip the test if the bzr executable is not found. For #71504 Change-Id: If8b6d4dea02dc16198ba6067595dff3340a81299 Reviewed-on: https://go-review.googlesource.com/c/go/+/646635 Reviewed-by: Dmitri Shuralyov Auto-Submit: Ian Lance Taylor Reviewed-by: Carlos Amedee Reviewed-by: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Reviewed-by: Dmitri Shuralyov --- src/cmd/go/internal/vcweb/vcstest/vcstest_test.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/cmd/go/internal/vcweb/vcstest/vcstest_test.go b/src/cmd/go/internal/vcweb/vcstest/vcstest_test.go index 4a6d60039ed0b2..df707d529efff5 100644 --- a/src/cmd/go/internal/vcweb/vcstest/vcstest_test.go +++ b/src/cmd/go/internal/vcweb/vcstest/vcstest_test.go @@ -158,6 +158,13 @@ func TestScripts(t *testing.T) { if notInstalled := (vcweb.ServerNotInstalledError{}); errors.As(err, ¬Installed) || errors.Is(err, exec.ErrNotFound) { t.Skip(err) } + + // For issue #71504 ignore an error about + // bzr not being able to find dependencies. + if strings.Contains(buf.String(), "brz: ERROR: Couldn't import breezy and dependencies.") { + t.Skip("skipping test due to bzr installation problem") + } + t.Error(err) } }) From 0825475599d40c786c19c3449e22d2db66754456 Mon Sep 17 00:00:00 2001 From: Youlin Feng Date: Mon, 18 Nov 2024 17:34:20 +0800 Subject: [PATCH 228/397] cmd/compile: do not treat OpLocalAddr as load in DSE Fixes #70409 Fixes #47107 Change-Id: I82a66c46f6b76c68e156b5d937273b0316975d44 Reviewed-on: https://go-review.googlesource.com/c/go/+/629016 LUCI-TryBot-Result: Go LUCI Reviewed-by: Keith Randall Reviewed-by: Keith Randall Reviewed-by: David Chase --- src/cmd/compile/internal/ssa/deadstore.go | 3 +-- test/codegen/issue70409.go | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 test/codegen/issue70409.go diff --git a/src/cmd/compile/internal/ssa/deadstore.go b/src/cmd/compile/internal/ssa/deadstore.go index 9f61ef29b9d527..29cf1e91e0f1a6 100644 --- a/src/cmd/compile/internal/ssa/deadstore.go +++ b/src/cmd/compile/internal/ssa/deadstore.go @@ -52,9 +52,8 @@ func dse(f *Func) { if v.Op == OpLocalAddr { if _, ok := localAddrs[v.Aux]; !ok { localAddrs[v.Aux] = v - } else { - continue } + continue } if v.Op == OpInlMark { // Not really a use of the memory. See #67957. diff --git a/test/codegen/issue70409.go b/test/codegen/issue70409.go new file mode 100644 index 00000000000000..bfb4560582e4f0 --- /dev/null +++ b/test/codegen/issue70409.go @@ -0,0 +1,20 @@ +// asmcheck -gcflags=-d=ssa/check/on + +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package codegen + +// amd64:-"MOVQ" +func foo(v uint64) (b [8]byte) { + b[0] = byte(v) + b[1] = byte(v >> 8) + b[2] = byte(v >> 16) + b[3] = byte(v >> 24) + b[4] = byte(v >> 32) + b[5] = byte(v >> 40) + b[6] = byte(v >> 48) + b[7] = byte(v >> 56) + return b +} From 5c2b5e02c422ab3936645e2faa4489bf32fa8a57 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sun, 22 Dec 2024 20:20:17 -0800 Subject: [PATCH 229/397] os: separate Process.handle into a separate memory allocation This is a step toward using AddCleanup rather than SetFinalizer to close process handles. For #70907 Change-Id: I7fb37461dd67b27135eab46fbdae94f0058ace85 Reviewed-on: https://go-review.googlesource.com/c/go/+/638575 Auto-Submit: Ian Lance Taylor Reviewed-by: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Reviewed-by: Robert Griesemer --- src/os/exec.go | 94 ++++++++++++++++++++++++++++++++--------- src/os/exec_linux.go | 4 +- src/os/exec_nohandle.go | 4 +- src/os/exec_windows.go | 4 +- 4 files changed, 82 insertions(+), 24 deletions(-) diff --git a/src/os/exec.go b/src/os/exec.go index 1220761df5ee09..e00a4769546c7c 100644 --- a/src/os/exec.go +++ b/src/os/exec.go @@ -90,16 +90,66 @@ type Process struct { // Used only in modePID. sigMu sync.RWMutex // avoid race between wait and signal - // handle is the OS handle for process actions, used only in - // modeHandle. - // - // handle must be accessed only via the handleTransientAcquire method - // (or during closeHandle), not directly! handle is immutable. + // handle, if not nil, is a pointer to a struct + // that holds the OS-specific process handle. + // This pointer is set when Process is created, + // and never changed afterward. + // This is a pointer to a separate memory allocation + // so that we can use runtime.AddCleanup. + handle *processHandle +} + +// processHandle holds an operating system handle to a process. +// This is only used on systems that support that concept, +// currently Linux and Windows. +// This maintains a reference count to the handle, +// and closes the handle when the reference drops to zero. +type processHandle struct { + // The actual handle. This field should not be used directly. + // Instead, use the acquire and release methods. // - // On Windows, it is a handle from OpenProcess. - // On Linux, it is a pidfd. - // It is unused on other GOOSes. + // On Windows this is a handle returned by OpenProcess. + // On Linux this is a pidfd. handle uintptr + + // Number of active references. When this drops to zero + // the handle is closed. + refs atomic.Int32 +} + +// acquire adds a reference and returns the handle. +// The bool result reports whether acquire succeeded; +// it fails if the handle is already closed. +// Every successful call to acquire should be paired with a call to release. +func (ph *processHandle) acquire() (uintptr, bool) { + for { + refs := ph.refs.Load() + if refs < 0 { + panic("internal error: negative process handle reference count") + } + if refs == 0 { + return 0, false + } + if ph.refs.CompareAndSwap(refs, refs+1) { + return ph.handle, true + } + } +} + +// release releases a reference to the handle. +func (ph *processHandle) release() { + for { + refs := ph.refs.Load() + if refs <= 0 { + panic("internal error: too many releases of process handle") + } + if ph.refs.CompareAndSwap(refs, refs-1) { + if refs == 1 { + ph.closeHandle() + } + return + } + } } func newPIDProcess(pid int) *Process { @@ -112,10 +162,18 @@ func newPIDProcess(pid int) *Process { } func newHandleProcess(pid int, handle uintptr) *Process { + ph := &processHandle{ + handle: handle, + } + + // Start the reference count as 1, + // meaning the reference from the returned Process. + ph.refs.Store(1) + p := &Process{ Pid: pid, mode: modeHandle, - handle: handle, + handle: ph, } p.state.Store(1) // 1 persistent reference runtime.SetFinalizer(p, (*Process).Release) @@ -125,9 +183,7 @@ func newHandleProcess(pid int, handle uintptr) *Process { func newDoneProcess(pid int) *Process { p := &Process{ Pid: pid, - mode: modeHandle, - // N.B Since we set statusDone, handle will never actually be - // used, so its value doesn't matter. + mode: modePID, } p.state.Store(uint64(statusDone)) // No persistent reference, as there is no handle. runtime.SetFinalizer(p, (*Process).Release) @@ -148,7 +204,11 @@ func (p *Process) handleTransientAcquire() (uintptr, processStatus) { if !p.state.CompareAndSwap(refs, new) { continue } - return p.handle, statusOK + h, ok := p.handle.acquire() + if !ok { + panic("inconsistent reference counts") + } + return h, statusOK } } @@ -179,9 +239,7 @@ func (p *Process) handleTransientRelease() { if !p.state.CompareAndSwap(state, new) { continue } - if new&^processStatusMask == 0 { - p.closeHandle() - } + p.handle.release() return } } @@ -216,9 +274,7 @@ func (p *Process) handlePersistentRelease(reason processStatus) processStatus { if !p.state.CompareAndSwap(refs, new) { continue } - if new&^processStatusMask == 0 { - p.closeHandle() - } + p.handle.release() return status } } diff --git a/src/os/exec_linux.go b/src/os/exec_linux.go index b47c6cb191986e..aaa022cb96d028 100644 --- a/src/os/exec_linux.go +++ b/src/os/exec_linux.go @@ -8,6 +8,6 @@ import ( "syscall" ) -func (p *Process) closeHandle() { - syscall.Close(int(p.handle)) +func (ph *processHandle) closeHandle() { + syscall.Close(int(ph.handle)) } diff --git a/src/os/exec_nohandle.go b/src/os/exec_nohandle.go index d06f4091c3eb77..0f70d21ccd8607 100644 --- a/src/os/exec_nohandle.go +++ b/src/os/exec_nohandle.go @@ -6,4 +6,6 @@ package os -func (p *Process) closeHandle() {} +func (ph *processHandle) closeHandle() { + panic("internal error: unexpected call to closeHandle") +} diff --git a/src/os/exec_windows.go b/src/os/exec_windows.go index ab2dae1d718548..43445d6804e465 100644 --- a/src/os/exec_windows.go +++ b/src/os/exec_windows.go @@ -88,8 +88,8 @@ func (p *Process) release() error { return nil } -func (p *Process) closeHandle() { - syscall.CloseHandle(syscall.Handle(p.handle)) +func (ph *processHandle) closeHandle() { + syscall.CloseHandle(syscall.Handle(ph.handle)) } func findProcess(pid int) (p *Process, err error) { From b485e5bceb8cf417c28debe82f9c42b91f66132e Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sun, 22 Dec 2024 20:26:23 -0800 Subject: [PATCH 230/397] os: remove Process.mode field It's now redundant with checking whether the handle field is nil. For #70907 Change-Id: I877f2a7c63d15ab5f8e3d2c9aa24776c2e3e2056 Reviewed-on: https://go-review.googlesource.com/c/go/+/638576 Reviewed-by: Robert Griesemer Reviewed-by: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Auto-Submit: Ian Lance Taylor Commit-Queue: Ian Lance Taylor --- src/os/exec.go | 49 +++++++++++------------------------------- src/os/exec_unix.go | 19 ++++++---------- src/os/exec_windows.go | 2 +- 3 files changed, 19 insertions(+), 51 deletions(-) diff --git a/src/os/exec.go b/src/os/exec.go index e00a4769546c7c..a531cdab080114 100644 --- a/src/os/exec.go +++ b/src/os/exec.go @@ -17,26 +17,6 @@ import ( // ErrProcessDone indicates a [Process] has finished. var ErrProcessDone = errors.New("os: process already finished") -type processMode uint8 - -const ( - // modePID means that Process operations such use the raw PID from the - // Pid field. handle is not used. - // - // This may be due to the host not supporting handles, or because - // Process was created as a literal, leaving handle unset. - // - // This must be the zero value so Process literals get modePID. - modePID processMode = iota - - // modeHandle means that Process operations use handle, which is - // initialized with an OS process handle. - // - // Note that Release and Wait will deactivate and eventually close the - // handle, so acquire may fail, indicating the reason. - modeHandle -) - type processStatus uint64 const ( @@ -58,15 +38,13 @@ const ( type Process struct { Pid int - mode processMode - // State contains the atomic process state. // - // In modePID, this consists only of the processStatus fields, which - // indicate if the process is done/released. + // If handle is nil, this consists only of the processStatus fields, + // which indicate if the process is done/released. // - // In modeHandle, the lower bits also contain a reference count for the - // handle field. + // In handle is not nil, the lower bits also contain a reference + // count for the handle field. // // The Process itself initially holds 1 persistent reference. Any // operation that uses the handle with a system call temporarily holds @@ -87,7 +65,7 @@ type Process struct { // errors returned by concurrent calls. state atomic.Uint64 - // Used only in modePID. + // Used only when handle is nil sigMu sync.RWMutex // avoid race between wait and signal // handle, if not nil, is a pointer to a struct @@ -154,8 +132,7 @@ func (ph *processHandle) release() { func newPIDProcess(pid int) *Process { p := &Process{ - Pid: pid, - mode: modePID, + Pid: pid, } runtime.SetFinalizer(p, (*Process).Release) return p @@ -172,7 +149,6 @@ func newHandleProcess(pid int, handle uintptr) *Process { p := &Process{ Pid: pid, - mode: modeHandle, handle: ph, } p.state.Store(1) // 1 persistent reference @@ -182,8 +158,7 @@ func newHandleProcess(pid int, handle uintptr) *Process { func newDoneProcess(pid int) *Process { p := &Process{ - Pid: pid, - mode: modePID, + Pid: pid, } p.state.Store(uint64(statusDone)) // No persistent reference, as there is no handle. runtime.SetFinalizer(p, (*Process).Release) @@ -191,7 +166,7 @@ func newDoneProcess(pid int) *Process { } func (p *Process) handleTransientAcquire() (uintptr, processStatus) { - if p.mode != modeHandle { + if p.handle == nil { panic("handleTransientAcquire called in invalid mode") } @@ -213,7 +188,7 @@ func (p *Process) handleTransientAcquire() (uintptr, processStatus) { } func (p *Process) handleTransientRelease() { - if p.mode != modeHandle { + if p.handle == nil { panic("handleTransientRelease called in invalid mode") } @@ -250,7 +225,7 @@ func (p *Process) handleTransientRelease() { // Returns the status prior to this call. If this is not statusOK, then the // reference was not dropped or status changed. func (p *Process) handlePersistentRelease(reason processStatus) processStatus { - if p.mode != modeHandle { + if p.handle == nil { panic("handlePersistentRelease called in invalid mode") } @@ -280,7 +255,7 @@ func (p *Process) handlePersistentRelease(reason processStatus) processStatus { } func (p *Process) pidStatus() processStatus { - if p.mode != modePID { + if p.handle != nil { panic("pidStatus called in invalid mode") } @@ -288,7 +263,7 @@ func (p *Process) pidStatus() processStatus { } func (p *Process) pidDeactivate(reason processStatus) { - if p.mode != modePID { + if p.handle != nil { panic("pidDeactivate called in invalid mode") } diff --git a/src/os/exec_unix.go b/src/os/exec_unix.go index 34467ac7a039ad..e58801b184cd2f 100644 --- a/src/os/exec_unix.go +++ b/src/os/exec_unix.go @@ -21,15 +21,12 @@ const ( func (p *Process) wait() (ps *ProcessState, err error) { // Which type of Process do we have? - switch p.mode { - case modeHandle: + if p.handle != nil { // pidfd return p.pidfdWait() - case modePID: + } else { // Regular PID return p.pidWait() - default: - panic("unreachable") } } @@ -85,15 +82,12 @@ func (p *Process) signal(sig Signal) error { } // Which type of Process do we have? - switch p.mode { - case modeHandle: + if p.handle != nil { // pidfd return p.pidfdSendSignal(s) - case modePID: + } else { // Regular PID return p.pidSignal(s) - default: - panic("unreachable") } } @@ -131,15 +125,14 @@ func (p *Process) release() error { // solely on statusReleased to determine that the Process is released. p.Pid = pidReleased - switch p.mode { - case modeHandle: + if p.handle != nil { // Drop the Process' reference and mark handle unusable for // future calls. // // Ignore the return value: we don't care if this was a no-op // racing with Wait, or a double Release. p.handlePersistentRelease(statusReleased) - case modePID: + } else { // Just mark the PID unusable. p.pidDeactivate(statusReleased) } diff --git a/src/os/exec_windows.go b/src/os/exec_windows.go index 43445d6804e465..969eeb7c217db2 100644 --- a/src/os/exec_windows.go +++ b/src/os/exec_windows.go @@ -12,7 +12,7 @@ import ( "time" ) -// Note that Process.mode is always modeHandle because Windows always requires +// Note that Process.handle is never nil because Windows always requires // a handle. A manually-created Process literal is not valid. func (p *Process) wait() (ps *ProcessState, err error) { From 0e35fb2f99ce4c249c0a42ad93a597835ae742b5 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 4 Feb 2025 14:23:14 -0800 Subject: [PATCH 231/397] net: ignore unnamed interfaces on DragonFly On DragonFly it seems that we can see an unnamed interface, but be unable to retrieve it. Skip unnamed interface cases. For #71064 Change-Id: Ie9af74bd656d403ddc19cc5f14062cd8e0fa2571 Reviewed-on: https://go-review.googlesource.com/c/go/+/646675 LUCI-TryBot-Result: Go LUCI Reviewed-by: Damien Neil Auto-Submit: Ian Lance Taylor Commit-Queue: Ian Lance Taylor TryBot-Result: Gopher Robot Reviewed-by: Ian Lance Taylor Run-TryBot: Ian Lance Taylor --- src/internal/routebsd/interface_classic.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/internal/routebsd/interface_classic.go b/src/internal/routebsd/interface_classic.go index af9531c0df7ee7..2599e5dd591358 100644 --- a/src/internal/routebsd/interface_classic.go +++ b/src/internal/routebsd/interface_classic.go @@ -41,6 +41,12 @@ func (w *wireFormat) parseInterfaceMessage(b []byte) (Message, error) { } m.Addrs[syscall.RTAX_IFP] = a m.Name = a.(*LinkAddr).Name + } else { + // DragonFly seems to have unnamed interfaces + // that we can't look up again. Just skip them. + if runtime.GOOS == "dragonfly" { + return nil, nil + } } return m, nil From a1ea78c470d3136b7aed42a4d8b94497563f98ea Mon Sep 17 00:00:00 2001 From: apocelipes Date: Wed, 5 Feb 2025 00:37:18 +0000 Subject: [PATCH 232/397] net: use strings.SplitSeq and bytes.SplitSeq Replace `for _, s := range {strings, bytes}.Split(v, sep)` with `for s := range {strings, bytes}.SplitSeq(v, sep)`, to simplify the code and reduce some memory allocations. Change-Id: Idead4de1e3928fc75cc5ba8caeff85542f1243d5 GitHub-Last-Rev: 5fb196a073e7583b23b1ebb446d6c067580ed63a GitHub-Pull-Request: golang/go#71554 Reviewed-on: https://go-review.googlesource.com/c/go/+/646216 Reviewed-by: Damien Neil Reviewed-by: Ian Lance Taylor Auto-Submit: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI --- src/net/http/fs.go | 2 +- src/net/http/httptest/recorder.go | 2 +- src/net/http/httputil/reverseproxy.go | 2 +- src/net/http/httputil/reverseproxy_test.go | 2 +- src/net/http/main_test.go | 2 +- src/net/http/server.go | 2 +- src/net/main_test.go | 2 +- src/net/net_windows_test.go | 12 ++++-------- 8 files changed, 11 insertions(+), 15 deletions(-) diff --git a/src/net/http/fs.go b/src/net/http/fs.go index e990f196d6d904..48ba05a664dbaf 100644 --- a/src/net/http/fs.go +++ b/src/net/http/fs.go @@ -1014,7 +1014,7 @@ func parseRange(s string, size int64) ([]httpRange, error) { } var ranges []httpRange noOverlap := false - for _, ra := range strings.Split(s[len(b):], ",") { + for ra := range strings.SplitSeq(s[len(b):], ",") { ra = textproto.TrimString(ra) if ra == "" { continue diff --git a/src/net/http/httptest/recorder.go b/src/net/http/httptest/recorder.go index dd51901b0d3b94..17aa70f06760a2 100644 --- a/src/net/http/httptest/recorder.go +++ b/src/net/http/httptest/recorder.go @@ -207,7 +207,7 @@ func (rw *ResponseRecorder) Result() *http.Response { if trailers, ok := rw.snapHeader["Trailer"]; ok { res.Trailer = make(http.Header, len(trailers)) for _, k := range trailers { - for _, k := range strings.Split(k, ",") { + for k := range strings.SplitSeq(k, ",") { k = http.CanonicalHeaderKey(textproto.TrimString(k)) if !httpguts.ValidTrailerHeader(k) { // Ignore since forbidden by RFC 7230, section 4.1.2. diff --git a/src/net/http/httputil/reverseproxy.go b/src/net/http/httputil/reverseproxy.go index d64d2fc3a18ee3..15e968470815d4 100644 --- a/src/net/http/httputil/reverseproxy.go +++ b/src/net/http/httputil/reverseproxy.go @@ -577,7 +577,7 @@ func shouldPanicOnCopyError(req *http.Request) bool { func removeHopByHopHeaders(h http.Header) { // RFC 7230, section 6.1: Remove headers listed in the "Connection" header. for _, f := range h["Connection"] { - for _, sf := range strings.Split(f, ",") { + for sf := range strings.SplitSeq(f, ",") { if sf = textproto.TrimString(sf); sf != "" { h.Del(sf) } diff --git a/src/net/http/httputil/reverseproxy_test.go b/src/net/http/httputil/reverseproxy_test.go index 2f9a5eec5cce4c..c618f6f19e3706 100644 --- a/src/net/http/httputil/reverseproxy_test.go +++ b/src/net/http/httputil/reverseproxy_test.go @@ -197,7 +197,7 @@ func TestReverseProxyStripHeadersPresentInConnection(t *testing.T) { c := r.Header["Connection"] var cf []string for _, f := range c { - for _, sf := range strings.Split(f, ",") { + for sf := range strings.SplitSeq(f, ",") { if sf = strings.TrimSpace(sf); sf != "" { cf = append(cf, sf) } diff --git a/src/net/http/main_test.go b/src/net/http/main_test.go index 4c1832071704e2..0c58a94f20fc24 100644 --- a/src/net/http/main_test.go +++ b/src/net/http/main_test.go @@ -31,7 +31,7 @@ func TestMain(m *testing.M) { func interestingGoroutines() (gs []string) { buf := make([]byte, 2<<20) buf = buf[:runtime.Stack(buf, true)] - for _, g := range strings.Split(string(buf), "\n\n") { + for g := range strings.SplitSeq(string(buf), "\n\n") { _, stack, _ := strings.Cut(g, "\n") stack = strings.TrimSpace(stack) if stack == "" || diff --git a/src/net/http/server.go b/src/net/http/server.go index 1e8e1437d26832..cbdc9dd0e3af60 100644 --- a/src/net/http/server.go +++ b/src/net/http/server.go @@ -1590,7 +1590,7 @@ func foreachHeaderElement(v string, fn func(string)) { fn(v) return } - for _, f := range strings.Split(v, ",") { + for f := range strings.SplitSeq(v, ",") { if f = textproto.TrimString(f); f != "" { fn(f) } diff --git a/src/net/main_test.go b/src/net/main_test.go index e5767f7c7c12f6..66735962f10373 100644 --- a/src/net/main_test.go +++ b/src/net/main_test.go @@ -185,7 +185,7 @@ func runningGoroutines() []string { var gss []string b := make([]byte, 2<<20) b = b[:runtime.Stack(b, true)] - for _, s := range strings.Split(string(b), "\n\n") { + for s := range strings.SplitSeq(string(b), "\n\n") { _, stack, _ := strings.Cut(s, "\n") stack = strings.TrimSpace(stack) if !strings.Contains(stack, "created by net") { diff --git a/src/net/net_windows_test.go b/src/net/net_windows_test.go index 50554c05c5eb2a..480e89dfd74945 100644 --- a/src/net/net_windows_test.go +++ b/src/net/net_windows_test.go @@ -240,8 +240,7 @@ func netshInterfaceIPShowInterface(ipver string, ifaces map[string]bool) error { //Metric : 10 //... var name string - lines := bytes.Split(out, []byte{'\r', '\n'}) - for _, line := range lines { + for line := range bytes.SplitSeq(out, []byte{'\r', '\n'}) { if bytes.HasPrefix(line, []byte("Interface ")) && bytes.HasSuffix(line, []byte(" Parameters")) { f := line[len("Interface "):] f = f[:len(f)-len(" Parameters")] @@ -330,8 +329,7 @@ func netshInterfaceIPv4ShowAddress(name string, netshOutput []byte) []string { addrs := make([]string, 0) var addr, subnetprefix string var processingOurInterface bool - lines := bytes.Split(netshOutput, []byte{'\r', '\n'}) - for _, line := range lines { + for line := range bytes.SplitSeq(netshOutput, []byte{'\r', '\n'}) { if !processingOurInterface { if !bytes.HasPrefix(line, []byte("Configuration for interface")) { continue @@ -398,8 +396,7 @@ func netshInterfaceIPv6ShowAddress(name string, netshOutput []byte) []string { // TODO: need to test ipv6 netmask too, but netsh does not outputs it var addr string addrs := make([]string, 0) - lines := bytes.Split(netshOutput, []byte{'\r', '\n'}) - for _, line := range lines { + for line := range bytes.SplitSeq(netshOutput, []byte{'\r', '\n'}) { if addr != "" { if len(line) == 0 { addr = "" @@ -584,8 +581,7 @@ func TestInterfaceHardwareAddrWithGetmac(t *testing.T) { want[cname] = addr group = make(map[string]string) } - lines := bytes.Split(out, []byte{'\r', '\n'}) - for _, line := range lines { + for line := range bytes.SplitSeq(out, []byte{'\r', '\n'}) { if len(line) == 0 { processGroup() continue From be2b809e5b888ed0ee636f1e07340640ffd88842 Mon Sep 17 00:00:00 2001 From: Amirhossein Akhlaghpour Date: Mon, 3 Feb 2025 05:56:31 +0000 Subject: [PATCH 233/397] os: fix race condition in readdir by atomically initializing dirinfo This change ensures that dirinfo in the File struct is initialized atomically, avoiding redundant allocations when multiple goroutines access it concurrently. Instead of creating separate buffers, we now use CompareAndSwap to guarantee thread-safe initialization and reduce unnecessary memory usage. Although this is not a strict race condition, the update enhances efficiency by eliminating duplicate allocations and ensuring safer concurrent access. Fixes #71496. Change-Id: If08699a94afa05611cdf67e82a5957a8d8f9d5c8 GitHub-Last-Rev: 1e1f6191439cf3ad32f3ba54bba5a0185dd55b14 GitHub-Pull-Request: golang/go#71501 Reviewed-on: https://go-review.googlesource.com/c/go/+/645720 Auto-Submit: Ian Lance Taylor Reviewed-by: Dmitri Shuralyov LUCI-TryBot-Result: Go LUCI Reviewed-by: Ian Lance Taylor --- src/os/dir_plan9.go | 17 ++++++++++++----- src/os/dir_unix.go | 16 ++++++++++++---- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/os/dir_plan9.go b/src/os/dir_plan9.go index ab5c1efce5b075..9d28bd7dda4a89 100644 --- a/src/os/dir_plan9.go +++ b/src/os/dir_plan9.go @@ -11,12 +11,19 @@ import ( ) func (file *File) readdir(n int, mode readdirMode) (names []string, dirents []DirEntry, infos []FileInfo, err error) { - // If this file has no dirinfo, create one. - d := file.dirinfo.Load() - if d == nil { - d = new(dirInfo) - file.dirinfo.Store(d) + var d *dirInfo + for { + d = file.dirinfo.Load() + if d != nil { + break + } + newD := new(dirInfo) + if file.dirinfo.CompareAndSwap(nil, newD) { + d = newD + break + } } + d.mu.Lock() defer d.mu.Unlock() diff --git a/src/os/dir_unix.go b/src/os/dir_unix.go index eadc1660c212ea..6a0135b70b073b 100644 --- a/src/os/dir_unix.go +++ b/src/os/dir_unix.go @@ -46,11 +46,19 @@ func (d *dirInfo) close() { func (f *File) readdir(n int, mode readdirMode) (names []string, dirents []DirEntry, infos []FileInfo, err error) { // If this file has no dirInfo, create one. - d := f.dirinfo.Load() - if d == nil { - d = new(dirInfo) - f.dirinfo.Store(d) + var d *dirInfo + for { + d = f.dirinfo.Load() + if d != nil { + break + } + newD := new(dirInfo) + if f.dirinfo.CompareAndSwap(nil, newD) { + d = newD + break + } } + d.mu.Lock() defer d.mu.Unlock() if d.buf == nil { From 842e4b5207003db692d72a1aeba4f164bbeb1c13 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 4 Feb 2025 10:33:38 -0800 Subject: [PATCH 234/397] net/rpc: move frozen notice to the start of the package doc For #71559 Change-Id: I68b9518a26cab75789d596839267abab7997bc2c Reviewed-on: https://go-review.googlesource.com/c/go/+/646575 Reviewed-by: Ian Lance Taylor Reviewed-by: Rob Pike Auto-Submit: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Reviewed-by: Dmitri Shuralyov Commit-Queue: Ian Lance Taylor --- src/net/rpc/server.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/net/rpc/server.go b/src/net/rpc/server.go index 1771726a932eda..4233a426fefb1f 100644 --- a/src/net/rpc/server.go +++ b/src/net/rpc/server.go @@ -4,7 +4,11 @@ /* Package rpc provides access to the exported methods of an object across a -network or other I/O connection. A server registers an object, making it visible +network or other I/O connection. + +The net/rpc package is frozen and is not accepting new features. + +A server registers an object, making it visible as a service with the name of the type of the object. After registration, exported methods of the object will be accessible remotely. A server may register multiple objects (services) of different types but it is an error to register multiple @@ -121,8 +125,6 @@ or A server implementation will often provide a simple, type-safe wrapper for the client. - -The net/rpc package is frozen and is not accepting new features. */ package rpc From 664aebab7da0da5859857c60b401ec85e3a408dd Mon Sep 17 00:00:00 2001 From: Mark Ryan Date: Mon, 2 Dec 2024 15:47:25 +0100 Subject: [PATCH 235/397] cmd/go: add rva23u64 as a valid value for GORISCV64 The RVA23 profile was ratified on the 21st of October 2024. https://riscv.org/announcements/2024/10/risc-v-announces-ratification-of-the-rva23-profile-standard/ Now that it's ratified we can add rva23u64 as a valid value for the GORISCV64 environment variable. This will allow the compiler and assembler to generate instructions made mandatory by the new profile without a runtime check. Examples of such instructions include those introduced by the Vector and Zicond extensions. Setting GORISCV64=rva23u64 defines the riscv64.rva20u64, riscv64.rva22u64 and riscv64.rva23u64 build tags, sets the internal variable buildcfg.GORISCV64 to 23 and defines the macros GORISCV64_rva23u64, hasV, hasZba, hasZbb, hasZbs, hasZfa, and hasZicond for use in assembly language code. Updates #61476 Change-Id: I7641c23084fa52891c9a18df58f4013cb6597d88 Reviewed-on: https://go-review.googlesource.com/c/go/+/633417 Reviewed-by: Carlos Amedee Reviewed-by: Jorropo Reviewed-by: Joel Sing Reviewed-by: Dmitri Shuralyov LUCI-TryBot-Result: Go LUCI Reviewed-by: Meng Zhuo --- src/cmd/go/alldocs.go | 7 ++++--- src/cmd/go/internal/help/helpdoc.go | 7 ++++--- src/cmd/go/testdata/script/tooltags.txt | 7 ++++++- src/cmd/internal/testdir/testdir_test.go | 2 +- src/internal/buildcfg/cfg.go | 7 ++++++- src/internal/buildcfg/cfg_test.go | 4 ++++ src/runtime/asm_riscv64.h | 9 +++++++++ 7 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index b9cf7202c22337..e28f68df6a0b52 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -2100,8 +2100,8 @@ // (or ppc64le.power8, ppc64le.power9, and ppc64le.power10) // feature build tags. // - For GOARCH=riscv64, -// GORISCV64=rva20u64 and rva22u64 correspond to the riscv64.rva20u64 -// and riscv64.rva22u64 build tags. +// GORISCV64=rva20u64, rva22u64 and rva23u64 correspond to the riscv64.rva20u64, +// riscv64.rva22u64 and riscv64.rva23u64 build tags. // - For GOARCH=wasm, GOWASM=satconv and signext // correspond to the wasm.satconv and wasm.signext feature build tags. // @@ -2473,8 +2473,9 @@ // Valid values are power8 (default), power9, power10. // GORISCV64 // For GOARCH=riscv64, the RISC-V user-mode application profile for which -// to compile. Valid values are rva20u64 (default), rva22u64. +// to compile. Valid values are rva20u64 (default), rva22u64, rva23u64. // See https://github.com/riscv/riscv-profiles/blob/main/src/profiles.adoc +// and https://github.com/riscv/riscv-profiles/blob/main/src/rva23-profile.adoc // GOWASM // For GOARCH=wasm, comma-separated list of experimental WebAssembly features to use. // Valid values are satconv, signext. diff --git a/src/cmd/go/internal/help/helpdoc.go b/src/cmd/go/internal/help/helpdoc.go index d2f0fd173beef9..e96849521525d6 100644 --- a/src/cmd/go/internal/help/helpdoc.go +++ b/src/cmd/go/internal/help/helpdoc.go @@ -646,8 +646,9 @@ Architecture-specific environment variables: Valid values are power8 (default), power9, power10. GORISCV64 For GOARCH=riscv64, the RISC-V user-mode application profile for which - to compile. Valid values are rva20u64 (default), rva22u64. + to compile. Valid values are rva20u64 (default), rva22u64, rva23u64. See https://github.com/riscv/riscv-profiles/blob/main/src/profiles.adoc + and https://github.com/riscv/riscv-profiles/blob/main/src/rva23-profile.adoc GOWASM For GOARCH=wasm, comma-separated list of experimental WebAssembly features to use. Valid values are satconv, signext. @@ -951,8 +952,8 @@ The defined architecture feature build tags are: (or ppc64le.power8, ppc64le.power9, and ppc64le.power10) feature build tags. - For GOARCH=riscv64, - GORISCV64=rva20u64 and rva22u64 correspond to the riscv64.rva20u64 - and riscv64.rva22u64 build tags. + GORISCV64=rva20u64, rva22u64 and rva23u64 correspond to the riscv64.rva20u64, + riscv64.rva22u64 and riscv64.rva23u64 build tags. - For GOARCH=wasm, GOWASM=satconv and signext correspond to the wasm.satconv and wasm.signext feature build tags. diff --git a/src/cmd/go/testdata/script/tooltags.txt b/src/cmd/go/testdata/script/tooltags.txt index 1f6f54563ca97a..a69b7a5c37b746 100644 --- a/src/cmd/go/testdata/script/tooltags.txt +++ b/src/cmd/go/testdata/script/tooltags.txt @@ -50,10 +50,15 @@ env GORISCV64=rva22u64 go list -f '{{context.ToolTags}}' stdout 'riscv64.rva20u64 riscv64.rva22u64' +env GOARCH=riscv64 +env GORISCV64=rva23u64 +go list -f '{{context.ToolTags}}' +stdout 'riscv64.rva20u64 riscv64.rva22u64 riscv64.rva23u64' + env GOARCH=riscv64 env GORISCV64=rva22 ! go list -f '{{context.ToolTags}}' -stderr 'go: invalid GORISCV64: must be rva20u64, rva22u64' +stderr 'go: invalid GORISCV64: must be rva20u64, rva22u64, rva23u64' env GOARCH=riscv64 env GORISCV64= diff --git a/src/cmd/internal/testdir/testdir_test.go b/src/cmd/internal/testdir/testdir_test.go index 7469a6491aa4bb..29bd1f7cf81cb8 100644 --- a/src/cmd/internal/testdir/testdir_test.go +++ b/src/cmd/internal/testdir/testdir_test.go @@ -1489,7 +1489,7 @@ var ( "ppc64x": {}, // A pseudo-arch representing both ppc64 and ppc64le "s390x": {}, "wasm": {}, - "riscv64": {"GORISCV64", "rva20u64", "rva22u64"}, + "riscv64": {"GORISCV64", "rva20u64", "rva22u64", "rva23u64"}, } ) diff --git a/src/internal/buildcfg/cfg.go b/src/internal/buildcfg/cfg.go index fca09bf8d3384a..5ae4c0c7adc8fe 100644 --- a/src/internal/buildcfg/cfg.go +++ b/src/internal/buildcfg/cfg.go @@ -307,8 +307,10 @@ func goriscv64() int { return 20 case "rva22u64": return 22 + case "rva23u64": + return 23 } - Error = fmt.Errorf("invalid GORISCV64: must be rva20u64, rva22u64") + Error = fmt.Errorf("invalid GORISCV64: must be rva20u64, rva22u64, rva23u64") v := DefaultGORISCV64[len("rva"):] i := strings.IndexFunc(v, func(r rune) bool { return r < '0' || r > '9' @@ -441,6 +443,9 @@ func gogoarchTags() []string { if GORISCV64 >= 22 { list = append(list, GOARCH+"."+"rva22u64") } + if GORISCV64 >= 23 { + list = append(list, GOARCH+"."+"rva23u64") + } return list case "wasm": var list []string diff --git a/src/internal/buildcfg/cfg_test.go b/src/internal/buildcfg/cfg_test.go index 757270b7788f27..2bbd478280241e 100644 --- a/src/internal/buildcfg/cfg_test.go +++ b/src/internal/buildcfg/cfg_test.go @@ -32,6 +32,10 @@ func TestConfigFlags(t *testing.T) { if goriscv64() != 22 { t.Errorf("Wrong parsing of RISCV64=rva22u64") } + os.Setenv("GORISCV64", "rva23u64") + if goriscv64() != 23 { + t.Errorf("Wrong parsing of RISCV64=rva23u64") + } Error = nil os.Setenv("GORISCV64", "rva22") if _ = goriscv64(); Error == nil { diff --git a/src/runtime/asm_riscv64.h b/src/runtime/asm_riscv64.h index d4deb093a66164..2414b9f067675a 100644 --- a/src/runtime/asm_riscv64.h +++ b/src/runtime/asm_riscv64.h @@ -10,3 +10,12 @@ #define hasZbb #define hasZbs #endif + +#ifdef GORISCV64_rva23u64 +#define hasV +#define hasZba +#define hasZbb +#define hasZbs +#define hasZfa +#define hasZicond +#endif From bcfa00cbd259a8653547b227f8207ab43bf7d5c8 Mon Sep 17 00:00:00 2001 From: Mark Ryan Date: Fri, 25 Aug 2023 11:22:02 +0200 Subject: [PATCH 236/397] cpu/internal: provide runtime detection of RISC-V extensions on Linux Add a RISCV64 variable to cpu/internal that indicates both the presence of RISC-V extensions and performance information about the underlying RISC-V cores. The variable is only populated with non false values on Linux. The detection code relies on the riscv_hwprobe syscall introduced in Linux 6.4. The patch can detect RVV 1.0 and whether the CPU supports fast misaligned accesses. It can only detect RVV 1.0 on a 6.5 kernel or later (without backports). Updates #61416 Change-Id: I2d8289345c885b699afff441d417cae38f6bdc54 Reviewed-on: https://go-review.googlesource.com/c/go/+/522995 Reviewed-by: Joel Sing Reviewed-by: Meng Zhuo LUCI-TryBot-Result: Go LUCI Reviewed-by: Michael Knyszek Reviewed-by: David Chase --- src/internal/cpu/cpu.go | 12 ++++ src/internal/cpu/cpu_riscv64.go | 11 ++++ src/internal/cpu/cpu_riscv64_linux.go | 91 +++++++++++++++++++++++++++ src/internal/cpu/cpu_riscv64_other.go | 11 ++++ src/runtime/os_linux_riscv64.go | 30 +++++++++ 5 files changed, 155 insertions(+) create mode 100644 src/internal/cpu/cpu_riscv64_linux.go create mode 100644 src/internal/cpu/cpu_riscv64_other.go diff --git a/src/internal/cpu/cpu.go b/src/internal/cpu/cpu.go index cd3db105238eec..81b8f7022e8e59 100644 --- a/src/internal/cpu/cpu.go +++ b/src/internal/cpu/cpu.go @@ -136,6 +136,17 @@ var S390X struct { _ CacheLinePad } +// RISCV64 contains the supported CPU features and performance characteristics for riscv64 +// platforms. The booleans in RISCV64, with the exception of HasFastMisaligned, indicate +// the presence of RISC-V extensions. +// The struct is padded to avoid false sharing. +var RISCV64 struct { + _ CacheLinePad + HasFastMisaligned bool // Fast misaligned accesses + HasV bool // Vector extension compatible with RVV 1.0 + _ CacheLinePad +} + // CPU feature variables are accessed by assembly code in various packages. //go:linkname X86 //go:linkname ARM @@ -144,6 +155,7 @@ var S390X struct { //go:linkname MIPS64X //go:linkname PPC64 //go:linkname S390X +//go:linkname RISCV64 // Initialize examines the processor and sets the relevant variables above. // This is called by the runtime package early in program initialization, diff --git a/src/internal/cpu/cpu_riscv64.go b/src/internal/cpu/cpu_riscv64.go index 2173fe88860904..e6e532c7e7e18f 100644 --- a/src/internal/cpu/cpu_riscv64.go +++ b/src/internal/cpu/cpu_riscv64.go @@ -6,5 +6,16 @@ package cpu const CacheLinePadSize = 64 +// RISC-V doesn't have a 'cpuid' equivalent. On Linux we rely on the riscv_hwprobe syscall. + func doinit() { + options = []option{ + {Name: "fastmisaligned", Feature: &RISCV64.HasFastMisaligned}, + {Name: "v", Feature: &RISCV64.HasV}, + } + osInit() +} + +func isSet(hwc uint, value uint) bool { + return hwc&value != 0 } diff --git a/src/internal/cpu/cpu_riscv64_linux.go b/src/internal/cpu/cpu_riscv64_linux.go new file mode 100644 index 00000000000000..a076d3e33ce2a4 --- /dev/null +++ b/src/internal/cpu/cpu_riscv64_linux.go @@ -0,0 +1,91 @@ +// Copyright 2024 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. + +//go:build riscv64 && linux + +package cpu + +import _ "unsafe" + +// RISC-V extension discovery code for Linux. +// +// A note on detection of the Vector extension using HWCAP. +// +// Support for the Vector extension version 1.0 was added to the Linux kernel in release 6.5. +// Support for the riscv_hwprobe syscall was added in 6.4. It follows that if the riscv_hwprobe +// syscall is not available then neither is the Vector extension (which needs kernel support). +// The riscv_hwprobe syscall should then be all we need to detect the Vector extension. +// However, some RISC-V board manufacturers ship boards with an older kernel on top of which +// they have back-ported various versions of the Vector extension patches but not the riscv_hwprobe +// patches. These kernels advertise support for the Vector extension using HWCAP. Falling +// back to HWCAP to detect the Vector extension, if riscv_hwprobe is not available, or simply not +// bothering with riscv_hwprobe at all and just using HWCAP may then seem like an attractive option. +// +// Unfortunately, simply checking the 'V' bit in AT_HWCAP will not work as this bit is used by +// RISC-V board and cloud instance providers to mean different things. The Lichee Pi 4A board +// and the Scaleway RV1 cloud instances use the 'V' bit to advertise their support for the unratified +// 0.7.1 version of the Vector Specification. The Banana Pi BPI-F3 and the CanMV-K230 board use +// it to advertise support for 1.0 of the Vector extension. Versions 0.7.1 and 1.0 of the Vector +// extension are binary incompatible. HWCAP can then not be used in isolation to populate the +// HasV field as this field indicates that the underlying CPU is compatible with RVV 1.0. +// Go will only support the ratified versions >= 1.0 and so any vector code it might generate +// would crash on a Scaleway RV1 instance or a Lichee Pi 4a, if allowed to run. +// +// There is a way at runtime to distinguish between versions 0.7.1 and 1.0 of the Vector +// specification by issuing a RVV 1.0 vsetvli instruction and checking the vill bit of the vtype +// register. This check would allow us to safely detect version 1.0 of the Vector extension +// with HWCAP, if riscv_hwprobe were not available. However, the check cannot +// be added until the assembler supports the Vector instructions. +// +// Note the riscv_hwprobe syscall does not suffer from these ambiguities by design as all of the +// extensions it advertises support for are explicitly versioned. It's also worth noting that +// the riscv_hwprobe syscall is the only way to detect multi-letter RISC-V extensions, e.g., Zvbb. +// These cannot be detected using HWCAP and so riscv_hwprobe must be used to detect the majority +// of RISC-V extensions. +// +// Please see https://docs.kernel.org/arch/riscv/hwprobe.html for more information. + +const ( + // Copied from golang.org/x/sys/unix/ztypes_linux_riscv64.go. + riscv_HWPROBE_KEY_IMA_EXT_0 = 0x4 + riscv_HWPROBE_IMA_V = 0x4 + riscv_HWPROBE_KEY_CPUPERF_0 = 0x5 + riscv_HWPROBE_MISALIGNED_FAST = 0x3 + riscv_HWPROBE_MISALIGNED_MASK = 0x7 +) + +// riscvHWProbePairs is copied from golang.org/x/sys/unix/ztypes_linux_riscv64.go. +type riscvHWProbePairs struct { + key int64 + value uint64 +} + +//go:linkname riscvHWProbe +func riscvHWProbe(pairs []riscvHWProbePairs, flags uint) bool + +func osInit() { + // A slice of key/value pair structures is passed to the RISCVHWProbe syscall. The key + // field should be initialised with one of the key constants defined above, e.g., + // RISCV_HWPROBE_KEY_IMA_EXT_0. The syscall will set the value field to the appropriate value. + // If the kernel does not recognise a key it will set the key field to -1 and the value field to 0. + + pairs := []riscvHWProbePairs{ + {riscv_HWPROBE_KEY_IMA_EXT_0, 0}, + {riscv_HWPROBE_KEY_CPUPERF_0, 0}, + } + + // This call only indicates that extensions are supported if they are implemented on all cores. + if !riscvHWProbe(pairs, 0) { + return + } + + if pairs[0].key != -1 { + v := uint(pairs[0].value) + RISCV64.HasV = isSet(v, riscv_HWPROBE_IMA_V) + } + if pairs[1].key != -1 { + v := pairs[1].value & riscv_HWPROBE_MISALIGNED_MASK + RISCV64.HasFastMisaligned = v == riscv_HWPROBE_MISALIGNED_FAST + } +} diff --git a/src/internal/cpu/cpu_riscv64_other.go b/src/internal/cpu/cpu_riscv64_other.go new file mode 100644 index 00000000000000..1307d822b3257f --- /dev/null +++ b/src/internal/cpu/cpu_riscv64_other.go @@ -0,0 +1,11 @@ +// Copyright 2024 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. + +//go:build riscv64 && !linux + +package cpu + +func osInit() { + // Other operating systems do not support the riscv_hwprobe syscall. +} diff --git a/src/runtime/os_linux_riscv64.go b/src/runtime/os_linux_riscv64.go index 9be88a5ad24468..c4a4d4e50d4506 100644 --- a/src/runtime/os_linux_riscv64.go +++ b/src/runtime/os_linux_riscv64.go @@ -4,4 +4,34 @@ package runtime +import ( + "internal/runtime/syscall" + "unsafe" +) + func osArchInit() {} + +type riscvHWProbePairs = struct { + key int64 + value uint64 +} + +// TODO: Consider whether to use the VDSO entry for riscv_hwprobe. +// There is a VDSO entry for riscv_hwprobe that should allow us to avoid the syscall +// entirely as it can handle the case where the caller only requests extensions that are +// supported on all cores, which is what we're doing here. However, as we're only calling +// this syscall once, it may not be worth the added effort to implement the VDSO call. + +//go:linkname internal_cpu_riscvHWProbe internal/cpu.riscvHWProbe +func internal_cpu_riscvHWProbe(pairs []riscvHWProbePairs, flags uint) bool { + // sys_RISCV_HWPROBE is copied from golang.org/x/sys/unix/zsysnum_linux_riscv64.go. + const sys_RISCV_HWPROBE uintptr = 258 + + if len(pairs) == 0 { + return false + } + // Passing in a cpuCount of 0 and a cpu of nil ensures that only extensions supported by all the + // cores are returned, which is the behaviour we want in internal/cpu. + _, _, e1 := syscall.Syscall6(sys_RISCV_HWPROBE, uintptr(unsafe.Pointer(&pairs[0])), uintptr(len(pairs)), uintptr(0), uintptr(unsafe.Pointer(nil)), uintptr(flags), 0) + return e1 == 0 +} From b7c9cdd53cb39934f74b1cdbe08ad1f9e4a12e78 Mon Sep 17 00:00:00 2001 From: Jakub Ciolek Date: Tue, 14 Jan 2025 22:13:29 +0100 Subject: [PATCH 237/397] cmd/compile: establish limits of bool to uint8 conversions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Improves bound check elimination for: func arrayLargeEnough(b bool, a [2]int64) int64 { c := byte(0) if b { c = 1 } // this bound check gets elided return a[c] } We also detect never true branches like: func cCanOnlyBe0or1(b bool) byte { var c byte if b { c = 1 } // this statement can never be true so we can elide it if c == 2 { c = 3 } return c } Hits a few times: crypto/internal/sysrand crypto/internal/sysrand.Read 357 -> 349 (-2.24%) testing testing.(*F).Fuzz.func1.1 837 -> 828 (-1.08%) image/png image/png.(*Encoder).Encode 1735 -> 1733 (-0.12%) vendor/golang.org/x/crypto/cryptobyte vendor/golang.org/x/crypto/cryptobyte.(*Builder).callContinuation 187 -> 185 (-1.07%) crypto/internal/sysrand [cmd/compile] crypto/internal/sysrand.Read 357 -> 349 (-2.24%) go/parser go/parser.(*parser).parseType 463 -> 457 (-1.30%) go/parser.(*parser).embeddedElem 633 -> 626 (-1.11%) go/parser.(*parser).parseFuncDecl 917 -> 914 (-0.33%) go/parser.(*parser).parseDotsType 393 -> 391 (-0.51%) go/parser.(*parser).error 1061 -> 1054 (-0.66%) go/parser.(*parser).parseTypeName 537 -> 532 (-0.93%) go/parser.(*parser).parseParamDecl 1478 -> 1451 (-1.83%) go/parser.(*parser).parseFuncTypeOrLit 498 -> 495 (-0.60%) go/parser.(*parser).parseValue 375 -> 371 (-1.07%) go/parser.(*parser).parseElementList 594 -> 593 (-0.17%) go/parser.(*parser).parseResult 593 -> 583 (-1.69%) go/parser.(*parser).parseElement 506 -> 504 (-0.40%) go/parser.(*parser).parseImportSpec 1110 -> 1108 (-0.18%) go/parser.(*parser).parseStructType 741 -> 735 (-0.81%) go/parser.(*parser).parseTypeSpec 1054 -> 1048 (-0.57%) go/parser.(*parser).parseIdentList 625 -> 623 (-0.32%) go/parser.(*parser).parseOperand 1221 -> 1199 (-1.80%) go/parser.(*parser).parseIndexOrSliceOrInstance 2713 -> 2694 (-0.70%) go/parser.(*parser).parseSwitchStmt 1458 -> 1447 (-0.75%) go/parser.(*parser).parseArrayFieldOrTypeInstance 1865 -> 1861 (-0.21%) go/parser.(*parser).parseExpr 307 -> 305 (-0.65%) go/parser.(*parser).parseSelector 427 -> 425 (-0.47%) go/parser.(*parser).parseTypeInstance 1433 -> 1420 (-0.91%) go/parser.(*parser).parseCaseClause 629 -> 626 (-0.48%) go/parser.(*parser).parseParameterList 4212 -> 4189 (-0.55%) go/parser.(*parser).parsePointerType 393 -> 391 (-0.51%) go/parser.(*parser).parseFuncType 465 -> 463 (-0.43%) go/parser.(*parser).parseTypeAssertion 559 -> 557 (-0.36%) go/parser.(*parser).parseSimpleStmt 2443 -> 2388 (-2.25%) go/parser.(*parser).parseCallOrConversion 1093 -> 1087 (-0.55%) go/parser.(*parser).parseForStmt 2168 -> 2159 (-0.42%) go/parser.(*parser).embeddedTerm 657 -> 649 (-1.22%) go/parser.(*parser).parseCommClause 1509 -> 1501 (-0.53%) cmd/internal/objfile cmd/internal/objfile.(*goobjFile).symbols 5299 -> 5274 (-0.47%) net net.initConfVal 378 -> 374 (-1.06%) net.(*conf).hostLookupOrder 269 -> 267 (-0.74%) net.(*conf).addrLookupOrder 261 -> 255 (-2.30%) cmd/internal/obj/loong64 cmd/internal/obj/loong64.(*ctxt0).oplook 1829 -> 1813 (-0.87%) cmd/internal/obj/mips cmd/internal/obj/mips.(*ctxt0).oplook 1428 -> 1400 (-1.96%) go/types go/types.(*typeWriter).signature 605 -> 601 (-0.66%) go/types.(*Checker).instantiateSignature 1469 -> 1467 (-0.14%) go/parser [cmd/compile] go/parser.(*parser).parseSwitchStmt 1458 -> 1447 (-0.75%) go/parser.(*parser).parseDotsType 393 -> 391 (-0.51%) go/parser.(*parser).embeddedElem 633 -> 626 (-1.11%) go/parser.(*parser).parseTypeAssertion 559 -> 557 (-0.36%) go/parser.(*parser).parseCommClause 1509 -> 1501 (-0.53%) go/parser.(*parser).parseCaseClause 629 -> 626 (-0.48%) go/parser.(*parser).parseImportSpec 1110 -> 1108 (-0.18%) go/parser.(*parser).parseTypeSpec 1054 -> 1048 (-0.57%) go/parser.(*parser).parseElementList 594 -> 593 (-0.17%) go/parser.(*parser).parseParamDecl 1478 -> 1451 (-1.83%) go/parser.(*parser).parseType 463 -> 457 (-1.30%) go/parser.(*parser).parseSimpleStmt 2443 -> 2388 (-2.25%) go/parser.(*parser).parseIdentList 625 -> 623 (-0.32%) go/parser.(*parser).parseTypeInstance 1433 -> 1420 (-0.91%) go/parser.(*parser).parseResult 593 -> 583 (-1.69%) go/parser.(*parser).parseValue 375 -> 371 (-1.07%) go/parser.(*parser).parseFuncDecl 917 -> 914 (-0.33%) go/parser.(*parser).error 1061 -> 1054 (-0.66%) go/parser.(*parser).parseElement 506 -> 504 (-0.40%) go/parser.(*parser).parseFuncType 465 -> 463 (-0.43%) go/parser.(*parser).parsePointerType 393 -> 391 (-0.51%) go/parser.(*parser).parseTypeName 537 -> 532 (-0.93%) go/parser.(*parser).parseExpr 307 -> 305 (-0.65%) go/parser.(*parser).parseFuncTypeOrLit 498 -> 495 (-0.60%) go/parser.(*parser).parseStructType 741 -> 735 (-0.81%) go/parser.(*parser).parseOperand 1221 -> 1199 (-1.80%) go/parser.(*parser).parseIndexOrSliceOrInstance 2713 -> 2694 (-0.70%) go/parser.(*parser).parseForStmt 2168 -> 2159 (-0.42%) go/parser.(*parser).parseParameterList 4212 -> 4189 (-0.55%) go/parser.(*parser).parseArrayFieldOrTypeInstance 1865 -> 1861 (-0.21%) go/parser.(*parser).parseSelector 427 -> 425 (-0.47%) go/parser.(*parser).parseCallOrConversion 1093 -> 1087 (-0.55%) go/parser.(*parser).embeddedTerm 657 -> 649 (-1.22%) crypto/tls crypto/tls.(*Conn).clientHandshake 3430 -> 3421 (-0.26%) cmd/internal/obj/mips [cmd/compile] cmd/internal/obj/mips.(*ctxt0).oplook 1428 -> 1400 (-1.96%) cmd/internal/obj/loong64 [cmd/compile] cmd/internal/obj/loong64.(*ctxt0).oplook 1829 -> 1813 (-0.87%) cmd/compile/internal/types2 cmd/compile/internal/types2.(*typeWriter).signature 605 -> 601 (-0.66%) cmd/compile/internal/types2.(*Checker).infer 10646 -> 10614 (-0.30%) cmd/compile/internal/types2.(*Checker).instantiateSignature 1567 -> 1561 (-0.38%) cmd/compile/internal/types2 [cmd/compile] cmd/compile/internal/types2.(*Checker).instantiateSignature 1567 -> 1561 (-0.38%) cmd/compile/internal/types2.(*typeWriter).signature 605 -> 601 (-0.66%) cmd/compile/internal/types2.(*Checker).infer 10718 -> 10654 (-0.60%) cmd/vendor/golang.org/x/arch/s390x/s390xasm cmd/vendor/golang.org/x/arch/s390x/s390xasm.GoSyntax 36778 -> 36682 (-0.26%) net/http net/http.(*Client).do 4202 -> 4170 (-0.76%) net/http.(*http2clientStream).writeRequest 3692 -> 3686 (-0.16%) cmd/vendor/github.com/ianlancetaylor/demangle cmd/vendor/github.com/ianlancetaylor/demangle.(*rustState).genericArgs 466 -> 463 (-0.64%) cmd/compile/internal/devirtualize cmd/compile/internal/devirtualize.ProfileGuided.func1 1364 -> 1357 (-0.51%) cmd/compile/internal/inline/interleaved cmd/compile/internal/inline/interleaved.DevirtualizeAndInlinePackage.func2 533 -> 526 (-1.31%) cmd/compile/internal/devirtualize [cmd/compile] cmd/compile/internal/devirtualize.ProfileGuided.func1 1343 -> 1332 (-0.82%) cmd/compile/internal/inline/interleaved [cmd/compile] cmd/compile/internal/inline/interleaved.DevirtualizeAndInlinePackage.func2 533 -> 526 (-1.31%) cmd/link/internal/ld cmd/link/internal/ld.mustLinkExternal 2739 -> 2674 (-2.37%) cmd/compile/internal/ssa cmd/compile/internal/ssa.(*poset).Ordered 391 -> 389 (-0.51%) cmd/compile/internal/ssa.(*poset).Equal 318 -> 313 (-1.57%) cmd/compile/internal/ssa.(*poset).Undo 1842 -> 1832 (-0.54%) cmd/compile/internal/ssa.(*expandState).decomposeAsNecessary 4587 -> 4555 (-0.70%) cmd/compile/internal/ssa.(*poset).OrderedOrEqual 390 -> 389 (-0.26%) cmd/compile/internal/ssa.(*poset).NonEqual 613 -> 606 (-1.14%) cmd/compile/internal/ssa [cmd/compile] cmd/compile/internal/ssa.(*poset).OrderedOrEqual 368 -> 365 (-0.82%) cmd/compile/internal/ssa.(*poset).Equal 318 -> 313 (-1.57%) cmd/compile/internal/ssa.(*expandState).decomposeAsNecessary 4952 -> 4938 (-0.28%) cmd/compile/internal/ssa.(*poset).NonEqual 613 -> 606 (-1.14%) cmd/compile/internal/ssa.(*poset).SetEqual 2533 -> 2505 (-1.11%) cmd/compile/internal/ssa.(*poset).SetNonEqual 785 -> 777 (-1.02%) cmd/compile/internal/ssa.(*poset).Ordered 370 -> 366 (-1.08%) cmd/compile/internal/gc [cmd/compile] cmd/compile/internal/gc.Main.DevirtualizeAndInlinePackage.func2 492 -> 489 (-0.61%) file before after Δ % crypto/internal/sysrand.s 1553 1545 -8 -0.515% internal/zstd.s 49179 49190 +11 +0.022% testing.s 115197 115188 -9 -0.008% image/png.s 36109 36107 -2 -0.006% vendor/golang.org/x/crypto/cryptobyte.s 30980 30978 -2 -0.006% crypto/internal/sysrand [cmd/compile].s 1553 1545 -8 -0.515% go/parser.s 112638 112354 -284 -0.252% cmd/internal/objfile.s 49994 49969 -25 -0.050% net.s 299558 299546 -12 -0.004% cmd/internal/obj/loong64.s 71651 71635 -16 -0.022% cmd/internal/obj/mips.s 59681 59653 -28 -0.047% go/types.s 558839 558833 -6 -0.001% cmd/compile/internal/types.s 71305 71306 +1 +0.001% go/parser [cmd/compile].s 112749 112465 -284 -0.252% crypto/tls.s 388859 388850 -9 -0.002% cmd/internal/obj/mips [cmd/compile].s 59792 59764 -28 -0.047% cmd/internal/obj/loong64 [cmd/compile].s 71762 71746 -16 -0.022% cmd/compile/internal/types2.s 540608 540566 -42 -0.008% cmd/compile/internal/types2 [cmd/compile].s 577428 577354 -74 -0.013% cmd/vendor/golang.org/x/arch/s390x/s390xasm.s 267664 267568 -96 -0.036% net/http.s 620704 620666 -38 -0.006% cmd/vendor/github.com/ianlancetaylor/demangle.s 299991 299988 -3 -0.001% cmd/compile/internal/devirtualize.s 21452 21445 -7 -0.033% cmd/compile/internal/inline/interleaved.s 8358 8351 -7 -0.084% cmd/compile/internal/devirtualize [cmd/compile].s 20994 20983 -11 -0.052% cmd/compile/internal/inline/interleaved [cmd/compile].s 8328 8321 -7 -0.084% cmd/link/internal/ld.s 641802 641737 -65 -0.010% cmd/compile/internal/ssa.s 3552939 3552957 +18 +0.001% cmd/compile/internal/ssa [cmd/compile].s 3752191 3752197 +6 +0.000% cmd/compile/internal/ssagen.s 405780 405786 +6 +0.001% cmd/compile/internal/ssagen [cmd/compile].s 434472 434496 +24 +0.006% cmd/compile/internal/gc [cmd/compile].s 38499 38496 -3 -0.008% total 36185267 36184243 -1024 -0.003% Change-Id: I867222b0f907b29d32b2676e55c6b5789ec56511 Reviewed-on: https://go-review.googlesource.com/c/go/+/642716 Reviewed-by: Keith Randall LUCI-TryBot-Result: Go LUCI Reviewed-by: Cherry Mui Reviewed-by: Keith Randall --- src/cmd/compile/internal/ssa/prove.go | 4 ++++ test/prove.go | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/cmd/compile/internal/ssa/prove.go b/src/cmd/compile/internal/ssa/prove.go index 8d0bb73d4c0c08..9d2ee5ceedf9d7 100644 --- a/src/cmd/compile/internal/ssa/prove.go +++ b/src/cmd/compile/internal/ssa/prove.go @@ -1653,6 +1653,10 @@ func initLimit(v *Value) limit { case OpCtz8, OpBitLen8: lim = lim.unsignedMax(8) + // bool to uint8 conversion + case OpCvtBoolToUint8: + lim = lim.unsignedMax(1) + // length operations case OpStringLen, OpSliceLen, OpSliceCap: lim = lim.signedMin(0) diff --git a/test/prove.go b/test/prove.go index edfd8908a2d8cf..908b05c7fa5328 100644 --- a/test/prove.go +++ b/test/prove.go @@ -1712,6 +1712,24 @@ func clampedIdx2(x []int, i int) int { return x[max(min(i, len(x)-1), 0)] // TODO: can't get rid of this bounds check yet } +func cvtBoolToUint8Disprove(b bool) byte { + var c byte + if b { + c = 1 + } + if c == 2 { // ERROR "Disproved Eq8" + c = 3 + } + return c +} +func cvtBoolToUint8BCE(b bool, a [2]int64) int64 { + c := byte(0) + if b { + c = 1 + } + return a[c] // ERROR "Proved IsInBounds$" +} + //go:noinline func useInt(a int) { } From f6ea0621d2e7e7386d7f58241fb34bc78e39ebcc Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 4 Feb 2025 15:11:42 -0800 Subject: [PATCH 238/397] internal/routebsd: fix parsing network address of length zero This applies CL 646555 from the net repository to this copy. For #70528 Change-Id: Ib7e23accfa3f278392e7bdca6f8544b8f1395e7e Reviewed-on: https://go-review.googlesource.com/c/go/+/646676 Reviewed-by: Damien Neil Auto-Submit: Ian Lance Taylor TryBot-Bypass: Ian Lance Taylor Reviewed-by: Ian Lance Taylor --- src/internal/routebsd/address.go | 74 +++++++++++--------- src/internal/routebsd/address_darwin_test.go | 2 +- 2 files changed, 40 insertions(+), 36 deletions(-) diff --git a/src/internal/routebsd/address.go b/src/internal/routebsd/address.go index 3368b22786eef7..75fafb1a15deb7 100644 --- a/src/internal/routebsd/address.go +++ b/src/internal/routebsd/address.go @@ -102,44 +102,52 @@ func (a *InetAddr) Family() int { // parseInetAddr parses b as an internet address for IPv4 or IPv6. func parseInetAddr(af int, b []byte) (Addr, error) { const ( - off4 = 4 // offset of in_addr - off6 = 8 // offset of in6_addr + off4 = 4 // offset of in_addr + off6 = 8 // offset of in6_addr + ipv4Len = 4 // length of IPv4 address in bytes + ipv6Len = 16 // length of IPv6 address in bytes ) switch af { case syscall.AF_INET: - if len(b) < (off4+1) || len(b) < int(b[0]) || b[0] == 0 { + if len(b) < (off4+1) || len(b) < int(b[0]) { return nil, errInvalidAddr } sockAddrLen := int(b[0]) - var ip [4]byte - n := off4 + 4 - if sockAddrLen < n { - n = sockAddrLen + var ip [ipv4Len]byte + if sockAddrLen != 0 { + // Calculate how many bytes of the address to copy: + // either full IPv4 length or the available length. + n := off4 + ipv4Len + if sockAddrLen < n { + n = sockAddrLen + } + copy(ip[:], b[off4:n]) } - copy(ip[:], b[off4:n]) a := &InetAddr{ IP: netip.AddrFrom4(ip), } return a, nil case syscall.AF_INET6: - if len(b) < (off6+1) || len(b) < int(b[0]) || b[0] == 0 { + if len(b) < (off6+1) || len(b) < int(b[0]) { return nil, errInvalidAddr } + var ip [ipv6Len]byte sockAddrLen := int(b[0]) - n := off6 + 16 - if sockAddrLen < n { - n = sockAddrLen - } - var ip [16]byte - copy(ip[:], b[off6:n]) - if ip[0] == 0xfe && ip[1]&0xc0 == 0x80 || ip[0] == 0xff && (ip[1]&0x0f == 0x01 || ip[1]&0x0f == 0x02) { - // KAME based IPv6 protocol stack usually - // embeds the interface index in the - // interface-local or link-local address as - // the kernel-internal form. - id := int(bigEndian.Uint16(ip[2:4])) - if id != 0 { - ip[2], ip[3] = 0, 0 + if sockaddrLen != 0 { + n := off6 + ipv6Len + if sockAddrLen < n { + n = sockAddrLen + } + copy(ip[:], b[off6:n]) + if ip[0] == 0xfe && ip[1]&0xc0 == 0x80 || ip[0] == 0xff && (ip[1]&0x0f == 0x01 || ip[1]&0x0f == 0x02) { + // KAME based IPv6 protocol stack usually + // embeds the interface index in the + // interface-local or link-local address as + // the kernel-internal form. + id := int(bigEndian.Uint16(ip[2:4])) + if id != 0 { + ip[2], ip[3] = 0, 0 + } } } // The kernel can provide an integer zone ID. @@ -197,11 +205,11 @@ func parseKernelInetAddr(af int, b []byte) (int, Addr, error) { switch { case b[0] == syscall.SizeofSockaddrInet6: a := &InetAddr{ - IP: netip.AddrFrom16([16]byte(b[off6:off6+16])), + IP: netip.AddrFrom16([16]byte(b[off6 : off6+16])), } return int(b[0]), a, nil case af == syscall.AF_INET6: - var ab[16]byte + var ab [16]byte if l-1 < off6 { copy(ab[:], b[1:l]) } else { @@ -213,7 +221,7 @@ func parseKernelInetAddr(af int, b []byte) (int, Addr, error) { return int(b[0]), a, nil case b[0] == syscall.SizeofSockaddrInet4: a := &InetAddr{ - IP: netip.AddrFrom4([4]byte(b[off4:off4+4])), + IP: netip.AddrFrom4([4]byte(b[off4 : off4+4])), } return int(b[0]), a, nil default: // an old fashion, AF_UNSPEC or unknown means AF_INET @@ -251,16 +259,12 @@ func parseAddrs(attrs uint, b []byte) ([]Addr, error) { } b = b[l:] case syscall.AF_INET, syscall.AF_INET6: - // #70528: if the sockaddrlen is 0, no address to parse inside, - // skip over the record. - if b[0] > 0 { - af = int(b[1]) - a, err := parseInetAddr(af, b) - if err != nil { - return nil, err - } - as[i] = a + af = int(b[1]) + a, err := parseInetAddr(af, b) + if err != nil { + return nil, err } + as[i] = a l := roundup(int(b[0])) if len(b) < l { return nil, errMessageTooShort diff --git a/src/internal/routebsd/address_darwin_test.go b/src/internal/routebsd/address_darwin_test.go index 5f93e363a6fe90..feffb1919aad34 100644 --- a/src/internal/routebsd/address_darwin_test.go +++ b/src/internal/routebsd/address_darwin_test.go @@ -108,7 +108,7 @@ var parseAddrsOnDarwinLittleEndianTests = []parseAddrsOnDarwinTest{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, }, []Addr{ - nil, + &InetAddr{IP: netip.AddrFrom16([16]byte{})}, &InetAddr{IP: netip.AddrFrom16([16]byte{0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x2f, 0x4b, 0xff, 0xfe, 0x09, 0x3b, 0xff})}, &InetAddr{IP: netip.AddrFrom16([16]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff})}, nil, From a7cbea833276454597c583751629a3e11cfa9232 Mon Sep 17 00:00:00 2001 From: Dmitri Shuralyov Date: Tue, 4 Feb 2025 19:54:25 -0500 Subject: [PATCH 239/397] cmd/go: skip bzr tests if 'bzr help' has non-zero exit code It appears to be quite easy to end up with a broken 'bzr' installation. For example, if bzr was installed via a system-wide package manager and intends to work with a system-wide Python installation, it may break if another 'python3' binary is added to PATH. If something as simple as 'bzr help' fails to exit with zero code, consider it broken and skip tests that require a working bzr binary just like if the 'bzr' binary isn't present in PATH at all. This makes these tests more robust and capable of producing useful signal in more environments. Separately from this, we'll want to restore a working bzr installation on the linux-arm64 builders, but at least there's still one on linux-amd64 builders. For #71563. Fixes #71504. Change-Id: Ia147196f12b90a0731ebbfab63b5de308212ed65 Cq-Include-Trybots: luci.golang.try:gotip-linux-arm64-longtest,gotip-linux-amd64-longtest Reviewed-on: https://go-review.googlesource.com/c/go/+/646715 Auto-Submit: Dmitri Shuralyov Reviewed-by: Ian Lance Taylor Reviewed-by: Dmitri Shuralyov LUCI-TryBot-Result: Go LUCI --- src/cmd/go/internal/vcweb/script.go | 51 +++++++++++++++++++ .../go/internal/vcweb/vcstest/vcstest_test.go | 12 ++--- src/cmd/go/scriptconds_test.go | 12 +++++ src/cmd/go/testdata/script/README | 2 + .../testdata/script/version_buildvcs_bzr.txt | 2 +- src/cmd/go/testdata/vcstest/bzr/hello.txt | 1 + 6 files changed, 73 insertions(+), 7 deletions(-) diff --git a/src/cmd/go/internal/vcweb/script.go b/src/cmd/go/internal/vcweb/script.go index 1ba9c0aff4f36a..3342ab200c6faa 100644 --- a/src/cmd/go/internal/vcweb/script.go +++ b/src/cmd/go/internal/vcweb/script.go @@ -32,6 +32,17 @@ import ( func newScriptEngine() *script.Engine { conds := script.DefaultConds() + add := func(name string, cond script.Cond) { + if _, ok := conds[name]; ok { + panic(fmt.Sprintf("condition %q is already registered", name)) + } + conds[name] = cond + } + lazyBool := func(summary string, f func() bool) script.Cond { + return script.OnceCondition(summary, func() (bool, error) { return f(), nil }) + } + add("bzr", lazyBool("the 'bzr' executable exists and provides the standard CLI", hasWorkingBzr)) + interrupt := func(cmd *exec.Cmd) error { return cmd.Process.Signal(os.Interrupt) } gracePeriod := 30 * time.Second // arbitrary @@ -43,6 +54,7 @@ func newScriptEngine() *script.Engine { cmds["hg"] = script.Program("hg", interrupt, gracePeriod) cmds["handle"] = scriptHandle() cmds["modzip"] = scriptModzip() + cmds["skip"] = scriptSkip() cmds["svnadmin"] = script.Program("svnadmin", interrupt, gracePeriod) cmds["svn"] = script.Program("svn", interrupt, gracePeriod) cmds["unquote"] = scriptUnquote() @@ -321,6 +333,34 @@ func scriptModzip() script.Cmd { }) } +func scriptSkip() script.Cmd { + return script.Command( + script.CmdUsage{ + Summary: "skip the current test", + Args: "[msg]", + }, + func(_ *script.State, args ...string) (script.WaitFunc, error) { + if len(args) > 1 { + return nil, script.ErrUsage + } + if len(args) == 0 { + return nil, SkipError{""} + } + return nil, SkipError{args[0]} + }) +} + +type SkipError struct { + Msg string +} + +func (s SkipError) Error() string { + if s.Msg == "" { + return "skip" + } + return s.Msg +} + func scriptUnquote() script.Cmd { return script.Command( script.CmdUsage{ @@ -343,3 +383,14 @@ func scriptUnquote() script.Cmd { return wait, nil }) } + +func hasWorkingBzr() bool { + bzr, err := exec.LookPath("bzr") + if err != nil { + return false + } + // Check that 'bzr help' exits with code 0. + // See go.dev/issue/71504 for an example where 'bzr' exists in PATH but doesn't work. + err = exec.Command(bzr, "help").Run() + return err == nil +} diff --git a/src/cmd/go/internal/vcweb/vcstest/vcstest_test.go b/src/cmd/go/internal/vcweb/vcstest/vcstest_test.go index df707d529efff5..67234ac20d4628 100644 --- a/src/cmd/go/internal/vcweb/vcstest/vcstest_test.go +++ b/src/cmd/go/internal/vcweb/vcstest/vcstest_test.go @@ -158,13 +158,13 @@ func TestScripts(t *testing.T) { if notInstalled := (vcweb.ServerNotInstalledError{}); errors.As(err, ¬Installed) || errors.Is(err, exec.ErrNotFound) { t.Skip(err) } - - // For issue #71504 ignore an error about - // bzr not being able to find dependencies. - if strings.Contains(buf.String(), "brz: ERROR: Couldn't import breezy and dependencies.") { - t.Skip("skipping test due to bzr installation problem") + if skip := (vcweb.SkipError{}); errors.As(err, &skip) { + if skip.Msg == "" { + t.Skip("SKIP") + } else { + t.Skipf("SKIP: %v", skip.Msg) + } } - t.Error(err) } }) diff --git a/src/cmd/go/scriptconds_test.go b/src/cmd/go/scriptconds_test.go index 262214f6a96c76..af9691ad2a4aca 100644 --- a/src/cmd/go/scriptconds_test.go +++ b/src/cmd/go/scriptconds_test.go @@ -37,6 +37,7 @@ func scriptConditions(t *testing.T) map[string]script.Cond { } add("abscc", script.Condition("default $CC path is absolute and exists", defaultCCIsAbsolute)) + add("bzr", lazyBool("the 'bzr' executable exists and provides the standard CLI", hasWorkingBzr)) add("case-sensitive", script.OnceCondition("$WORK filesystem is case-sensitive", isCaseSensitive)) add("cc", script.PrefixCondition("go env CC = (ignoring the go/env file)", ccIs)) add("git", lazyBool("the 'git' executable exists and provides the standard CLI", hasWorkingGit)) @@ -151,3 +152,14 @@ func hasWorkingGit() bool { _, err := exec.LookPath("git") return err == nil } + +func hasWorkingBzr() bool { + bzr, err := exec.LookPath("bzr") + if err != nil { + return false + } + // Check that 'bzr help' exits with code 0. + // See go.dev/issue/71504 for an example where 'bzr' exists in PATH but doesn't work. + err = exec.Command(bzr, "help").Run() + return err == nil +} diff --git a/src/cmd/go/testdata/script/README b/src/cmd/go/testdata/script/README index 8c95945ebe0761..7724bc10ec46f0 100644 --- a/src/cmd/go/testdata/script/README +++ b/src/cmd/go/testdata/script/README @@ -377,6 +377,8 @@ The available conditions are: GOOS/GOARCH supports -asan [buildmode:*] go supports -buildmode= +[bzr] + the 'bzr' executable exists and provides the standard CLI [case-sensitive] $WORK filesystem is case-sensitive [cc:*] diff --git a/src/cmd/go/testdata/script/version_buildvcs_bzr.txt b/src/cmd/go/testdata/script/version_buildvcs_bzr.txt index fc80f45677799e..59796d1ffa8c2d 100644 --- a/src/cmd/go/testdata/script/version_buildvcs_bzr.txt +++ b/src/cmd/go/testdata/script/version_buildvcs_bzr.txt @@ -2,8 +2,8 @@ # controlled with -buildvcs. This test focuses on Bazaar specifics. # The Git test covers common functionality. -[!exec:bzr] skip [short] skip +[!bzr] skip 'requires a working bzr client' env GOBIN=$WORK/gopath/bin env oldpath=$PATH env HOME=$WORK diff --git a/src/cmd/go/testdata/vcstest/bzr/hello.txt b/src/cmd/go/testdata/vcstest/bzr/hello.txt index 59315852f73652..68465ec553bd55 100644 --- a/src/cmd/go/testdata/vcstest/bzr/hello.txt +++ b/src/cmd/go/testdata/vcstest/bzr/hello.txt @@ -1,3 +1,4 @@ +[!bzr] skip 'requires a working bzr client' handle bzr env BZR_EMAIL='Russ Cox ' From 721f5ca4edc8073b777bd71df6801b237d72c332 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Tue, 4 Feb 2025 17:04:26 +0100 Subject: [PATCH 240/397] runtime: adjust comments for auxv getAuxv github.com/cilium/ebpf no longer accesses getAuxv using linkname but now uses the golang.org/x/sys/unix.Auxv wrapper introduced in go.dev/cl/644295. Also adjust the list of users to include x/sys/unix. Updates #67839 Updates #67401 Change-Id: Ieee266360b22cc0bc4be8f740e0302afd7dbd14f Reviewed-on: https://go-review.googlesource.com/c/go/+/646535 Reviewed-by: Ian Lance Taylor Auto-Submit: Tobias Klauser LUCI-TryBot-Result: Go LUCI Reviewed-by: Dmitri Shuralyov --- src/runtime/runtime.go | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/runtime/runtime.go b/src/runtime/runtime.go index e8e614815d236b..3afb6558b03f50 100644 --- a/src/runtime/runtime.go +++ b/src/runtime/runtime.go @@ -290,23 +290,15 @@ func setCrashFD(fd uintptr) uintptr { } // auxv is populated on relevant platforms but defined here for all platforms -// so x/sys/cpu can assume the getAuxv symbol exists without keeping its list -// of auxv-using GOOS build tags in sync. +// so x/sys/cpu and x/sys/unix can assume the getAuxv symbol exists without +// keeping its list of auxv-using GOOS build tags in sync. // // It contains an even number of elements, (tag, value) pairs. var auxv []uintptr -// golang.org/x/sys/cpu uses getAuxv via linkname. +// golang.org/x/sys/cpu and golang.org/x/sys/unix use getAuxv via linkname. // Do not remove or change the type signature. -// (See go.dev/issue/57336.) -// -// getAuxv should be an internal detail, -// but widely used packages access it using linkname. -// Notable members of the hall of shame include: -// - github.com/cilium/ebpf -// -// Do not remove or change the type signature. -// See go.dev/issue/67401. +// See go.dev/issue/57336 and go.dev/issue/67401. // //go:linkname getAuxv func getAuxv() []uintptr { return auxv } From ee6e0a5ed6a11f79f40ca58ca5337ec5bad16ebb Mon Sep 17 00:00:00 2001 From: Dmitri Shuralyov Date: Wed, 5 Feb 2025 13:52:56 -0500 Subject: [PATCH 241/397] internal/routebsd: fix typo in sockAddrLen identifer name For #70528. Change-Id: I0db75cb998aeb299676384fe59bf241db18ebc5c Reviewed-on: https://go-review.googlesource.com/c/go/+/646975 Reviewed-by: Cherry Mui Reviewed-by: Dmitri Shuralyov Auto-Submit: Dmitri Shuralyov LUCI-TryBot-Result: Go LUCI --- src/internal/routebsd/address.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/internal/routebsd/address.go b/src/internal/routebsd/address.go index 75fafb1a15deb7..aa1bc21d3f00ae 100644 --- a/src/internal/routebsd/address.go +++ b/src/internal/routebsd/address.go @@ -133,7 +133,7 @@ func parseInetAddr(af int, b []byte) (Addr, error) { } var ip [ipv6Len]byte sockAddrLen := int(b[0]) - if sockaddrLen != 0 { + if sockAddrLen != 0 { n := off6 + ipv6Len if sockAddrLen < n { n = sockAddrLen From b45c7d546669c37bbfdb1dedffa1b3e12acfc18c Mon Sep 17 00:00:00 2001 From: Dmitri Shuralyov Date: Mon, 3 Feb 2025 22:50:29 -0500 Subject: [PATCH 242/397] internal/trace: skip TestTraceCgoCallback on freebsd-amd64-race builders For #71556. Change-Id: I754f113bfdad244d0e978cf559bf45f2f4d7bf06 Reviewed-on: https://go-review.googlesource.com/c/go/+/646396 Reviewed-by: Michael Knyszek Auto-Submit: Dmitri Shuralyov TryBot-Bypass: Dmitri Shuralyov Reviewed-by: Dmitri Shuralyov --- src/internal/trace/trace_test.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/internal/trace/trace_test.go b/src/internal/trace/trace_test.go index facac47eef0604..4ff87c1ede6ac6 100644 --- a/src/internal/trace/trace_test.go +++ b/src/internal/trace/trace_test.go @@ -573,6 +573,11 @@ func testTraceProg(t *testing.T, progName string, extra func(t *testing.T, trace onBuilder := testenv.Builder() != "" onOldBuilder := !strings.Contains(testenv.Builder(), "gotip") && !strings.Contains(testenv.Builder(), "go1") + if progName == "cgo-callback.go" && onBuilder && !onOldBuilder && + runtime.GOOS == "freebsd" && runtime.GOARCH == "amd64" && race.Enabled { + t.Skip("test fails on freebsd-amd64-race in LUCI; see go.dev/issue/71556") + } + testPath := filepath.Join("./testdata/testprog", progName) testName := progName runTest := func(t *testing.T, stress bool, extraGODEBUG string) { From 220fe7987138a4b6c63de4b750fda58852237560 Mon Sep 17 00:00:00 2001 From: Michael Matloob Date: Wed, 5 Feb 2025 15:27:29 -0500 Subject: [PATCH 243/397] cmd/go: add '-skip' to list of cacheable test flags -run is cacheable, so -skip should be cacheable too. Fixes #70692 Change-Id: I16880189b0d3a963f8f08008fc7fedcdc6f11630 Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest,gotip-windows-amd64-longtest Reviewed-on: https://go-review.googlesource.com/c/go/+/646997 LUCI-TryBot-Result: Go LUCI Reviewed-by: Sam Thanawalla --- src/cmd/go/alldocs.go | 2 +- src/cmd/go/internal/test/test.go | 3 ++- src/cmd/go/testdata/script/test_cache_inputs.txt | 5 +++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index e28f68df6a0b52..7289b5f4b1e16f 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -1890,7 +1890,7 @@ // The rule for a match in the cache is that the run involves the same // test binary and the flags on the command line come entirely from a // restricted set of 'cacheable' test flags, defined as -benchtime, -cpu, -// -list, -parallel, -run, -short, -timeout, -failfast, -fullpath and -v. +// -list, -parallel, -run, -short, -skip, -timeout, -failfast, -fullpath and -v. // If a run of go test has any test or non-test flags outside this set, // the result is not cached. To disable test caching, use any test flag // or argument other than the cacheable flags. The idiomatic way to disable diff --git a/src/cmd/go/internal/test/test.go b/src/cmd/go/internal/test/test.go index e3cd50d59c88fb..28ab6a09355020 100644 --- a/src/cmd/go/internal/test/test.go +++ b/src/cmd/go/internal/test/test.go @@ -127,7 +127,7 @@ elapsed time in the summary line. The rule for a match in the cache is that the run involves the same test binary and the flags on the command line come entirely from a restricted set of 'cacheable' test flags, defined as -benchtime, -cpu, --list, -parallel, -run, -short, -timeout, -failfast, -fullpath and -v. +-list, -parallel, -run, -short, -skip, -timeout, -failfast, -fullpath and -v. If a run of go test has any test or non-test flags outside this set, the result is not cached. To disable test caching, use any test flag or argument other than the cacheable flags. The idiomatic way to disable @@ -1781,6 +1781,7 @@ func (c *runCache) tryCacheWithID(b *work.Builder, a *work.Action, id string) bo "-test.parallel", "-test.run", "-test.short", + "-test.skip", "-test.timeout", "-test.failfast", "-test.v", diff --git a/src/cmd/go/testdata/script/test_cache_inputs.txt b/src/cmd/go/testdata/script/test_cache_inputs.txt index 68a700b1160763..796a5880eb6146 100644 --- a/src/cmd/go/testdata/script/test_cache_inputs.txt +++ b/src/cmd/go/testdata/script/test_cache_inputs.txt @@ -128,6 +128,11 @@ go test testcache -run=TestOSArgs -fullpath go test testcache -run=TestOSArgs -fullpath stdout '\(cached\)' +# golang.org/issue/70692: that includes the `-skip` flag +go test testcache -run=TestOdd -skip=TestOddFile +! stdout '\(cached\)' +go test testcache -run=TestOdd -skip=TestOddFile +stdout '\(cached\)' # Executables within GOROOT and GOPATH should affect caching, # even if the test does not stat them explicitly. From 51bf2cf7cfa999777697a9548d59d22c3716fbde Mon Sep 17 00:00:00 2001 From: Roland Shoemaker Date: Wed, 29 Jan 2025 08:03:59 -0800 Subject: [PATCH 244/397] Revert "cmd/go/internal/work: allow @ character in some -Wl, linker flags on darwin" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts CL 638075 (commit e3cd55e9d293d519e622e788e902f372dc30338a). This change introduced a security issue as @ flags are first resolved as files by the darwin linker, before their meaning as flags, allowing the flag filtering logic to be entirely bypassed. Thanks to Juho Forsén for reporting this issue. Fixes #71476 Fixes CVE-2025-22867 Change-Id: I3a4b4a6fc534de105d930b8ed5b9900bc94b0c4e Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/1900 Reviewed-by: Russ Cox Reviewed-by: Damien Neil Reviewed-on: https://go-review.googlesource.com/c/go/+/646996 Reviewed-by: Carlos Amedee LUCI-TryBot-Result: Go LUCI --- src/cmd/go/internal/work/security.go | 22 +----------- src/cmd/go/internal/work/security_test.go | 44 ----------------------- 2 files changed, 1 insertion(+), 65 deletions(-) diff --git a/src/cmd/go/internal/work/security.go b/src/cmd/go/internal/work/security.go index 33341a4f4dde09..50bfd0ab705383 100644 --- a/src/cmd/go/internal/work/security.go +++ b/src/cmd/go/internal/work/security.go @@ -227,21 +227,6 @@ var validLinkerFlags = []*lazyregexp.Regexp{ re(`\./.*\.(a|o|obj|dll|dylib|so|tbd)`), } -var validLinkerFlagsOnDarwin = []*lazyregexp.Regexp{ - // The GNU linker interprets `@file` as "read command-line options from - // file". Thus, we forbid values starting with `@` on linker flags. - // However, this causes a problem when targeting Darwin. - // `@executable_path`, `@loader_path`, and `@rpath` are special values - // used in Mach-O to change the library search path and can be used in - // conjunction with the `-install_name` and `-rpath` linker flags. - // Since the GNU linker does not support Mach-O, targeting Darwin - // implies not using the GNU linker. Therefore, we allow @ in the linker - // flags if and only if cfg.Goos == "darwin" || cfg.Goos == "ios". - re(`-Wl,-dylib_install_name,@rpath(/[^,]*)?`), - re(`-Wl,-install_name,@rpath(/[^,]*)?`), - re(`-Wl,-rpath,@(executable_path|loader_path)(/[^,]*)?`), -} - var validLinkerFlagsWithNextArg = []string{ "-arch", "-F", @@ -264,13 +249,8 @@ func checkCompilerFlags(name, source string, list []string) error { } func checkLinkerFlags(name, source string, list []string) error { - validLinkerFlagsForPlatform := validLinkerFlags - if cfg.Goos == "darwin" || cfg.Goos == "ios" { - validLinkerFlagsForPlatform = append(validLinkerFlags, validLinkerFlagsOnDarwin...) - } - checkOverrides := true - return checkFlags(name, source, list, invalidLinkerFlags, validLinkerFlagsForPlatform, validLinkerFlagsWithNextArg, checkOverrides) + return checkFlags(name, source, list, invalidLinkerFlags, validLinkerFlags, validLinkerFlagsWithNextArg, checkOverrides) } // checkCompilerFlagsForInternalLink returns an error if 'list' diff --git a/src/cmd/go/internal/work/security_test.go b/src/cmd/go/internal/work/security_test.go index 52e54e25e4a293..35af62176472b4 100644 --- a/src/cmd/go/internal/work/security_test.go +++ b/src/cmd/go/internal/work/security_test.go @@ -8,8 +8,6 @@ import ( "os" "strings" "testing" - - "cmd/go/internal/cfg" ) var goodCompilerFlags = [][]string{ @@ -247,8 +245,6 @@ var badLinkerFlags = [][]string{ {"-Wl,--hash-style=foo"}, {"-x", "--c"}, {"-x", "@obj"}, - {"-Wl,-dylib_install_name,@foo"}, - {"-Wl,-install_name,@foo"}, {"-Wl,-rpath,@foo"}, {"-Wl,-R,foo,bar"}, {"-Wl,-R,@foo"}, @@ -265,21 +261,6 @@ var badLinkerFlags = [][]string{ {"./-Wl,--push-state,-R.c"}, } -var goodLinkerFlagsOnDarwin = [][]string{ - {"-Wl,-dylib_install_name,@rpath"}, - {"-Wl,-dylib_install_name,@rpath/"}, - {"-Wl,-dylib_install_name,@rpath/foo"}, - {"-Wl,-install_name,@rpath"}, - {"-Wl,-install_name,@rpath/"}, - {"-Wl,-install_name,@rpath/foo"}, - {"-Wl,-rpath,@executable_path"}, - {"-Wl,-rpath,@executable_path/"}, - {"-Wl,-rpath,@executable_path/foo"}, - {"-Wl,-rpath,@loader_path"}, - {"-Wl,-rpath,@loader_path/"}, - {"-Wl,-rpath,@loader_path/foo"}, -} - func TestCheckLinkerFlags(t *testing.T) { for _, f := range goodLinkerFlags { if err := checkLinkerFlags("test", "test", f); err != nil { @@ -291,31 +272,6 @@ func TestCheckLinkerFlags(t *testing.T) { t.Errorf("missing error for %q", f) } } - - goos := cfg.Goos - - cfg.Goos = "darwin" - for _, f := range goodLinkerFlagsOnDarwin { - if err := checkLinkerFlags("test", "test", f); err != nil { - t.Errorf("unexpected error for %q: %v", f, err) - } - } - - cfg.Goos = "ios" - for _, f := range goodLinkerFlagsOnDarwin { - if err := checkLinkerFlags("test", "test", f); err != nil { - t.Errorf("unexpected error for %q: %v", f, err) - } - } - - cfg.Goos = "linux" - for _, f := range goodLinkerFlagsOnDarwin { - if err := checkLinkerFlags("test", "test", f); err == nil { - t.Errorf("missing error for %q", f) - } - } - - cfg.Goos = goos } func TestCheckFlagAllowDisallow(t *testing.T) { From 4cc7705e56be24d5719b59cb369ce4d40643983c Mon Sep 17 00:00:00 2001 From: apocelipes Date: Wed, 5 Feb 2025 12:19:12 +0000 Subject: [PATCH 245/397] testing: use strings.SplitSeq and bytes.SplitSeq To simplify the code. This is a follow-up for the CL 646216. Change-Id: Ib09d1074a783482fb293527e9f1abeb3c02137c3 GitHub-Last-Rev: 2e7a6ad40cc22ea855e4d703ff39db9cc2c8a58e GitHub-Pull-Request: golang/go#71568 Reviewed-on: https://go-review.googlesource.com/c/go/+/646755 Reviewed-by: Jorropo LUCI-TryBot-Result: Go LUCI Reviewed-by: Salah (Globlost) Reviewed-by: Damien Neil Auto-Submit: Damien Neil Reviewed-by: Alan Donovan --- src/testing/slogtest/example_test.go | 2 +- src/testing/testing.go | 2 +- src/testing/testing_test.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/testing/slogtest/example_test.go b/src/testing/slogtest/example_test.go index 0517a4b8574d8c..88fd2427b2e6d7 100644 --- a/src/testing/slogtest/example_test.go +++ b/src/testing/slogtest/example_test.go @@ -23,7 +23,7 @@ func Example_parsing() { results := func() []map[string]any { var ms []map[string]any - for _, line := range bytes.Split(buf.Bytes(), []byte{'\n'}) { + for line := range bytes.SplitSeq(buf.Bytes(), []byte{'\n'}) { if len(line) == 0 { continue } diff --git a/src/testing/testing.go b/src/testing/testing.go index 2bfa4b6db07992..aefcb84fc8de20 100644 --- a/src/testing/testing.go +++ b/src/testing/testing.go @@ -2501,7 +2501,7 @@ func (m *M) stopAlarm() { } func parseCpuList() { - for _, val := range strings.Split(*cpuListStr, ",") { + for val := range strings.SplitSeq(*cpuListStr, ",") { val = strings.TrimSpace(val) if val == "" { continue diff --git a/src/testing/testing_test.go b/src/testing/testing_test.go index 797728c7a89b0a..addf6cad91d667 100644 --- a/src/testing/testing_test.go +++ b/src/testing/testing_test.go @@ -894,7 +894,7 @@ func TestRunningTestsInCleanup(t *testing.T) { func parseRunningTests(out []byte) (runningTests []string, ok bool) { inRunningTests := false - for _, line := range strings.Split(string(out), "\n") { + for line := range strings.SplitSeq(string(out), "\n") { if inRunningTests { // Package testing adds one tab, the panic printer adds another. if trimmed, ok := strings.CutPrefix(line, "\t\t"); ok { From a8e532b0f234b3bbf7a1cdcd4213d154e82ba08e Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 5 Feb 2025 17:22:43 -0800 Subject: [PATCH 246/397] runtime/cgo: clarify that C code must not retain pointer For #71566 Change-Id: I6dc365dd799d7b506b4a55895f1736d3dfd4684b Reviewed-on: https://go-review.googlesource.com/c/go/+/647095 Reviewed-by: Alan Donovan Reviewed-by: Ian Lance Taylor Auto-Submit: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Commit-Queue: Ian Lance Taylor --- src/runtime/cgo/handle.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/runtime/cgo/handle.go b/src/runtime/cgo/handle.go index 59b65da2b6d763..7d6dd9146c30d3 100644 --- a/src/runtime/cgo/handle.go +++ b/src/runtime/cgo/handle.go @@ -61,10 +61,16 @@ import ( // } // // Some C functions accept a void* argument that points to an arbitrary -// data value supplied by the caller. It is not safe to coerce a [cgo.Handle] +// data value supplied by the caller. It is not safe to coerce a Handle // (an integer) to a Go [unsafe.Pointer], but instead we can pass the address // of the cgo.Handle to the void* parameter, as in this variant of the -// previous example: +// previous example. +// +// Note that, as described in the [cmd/cgo] documentation, +// the C code must not keep a copy of the Go pointer that it receives, +// unless the memory is explicitly pinned using [runtime.Pinner]. +// This example is OK because the C function myprint does not keep +// a copy of the pointer. // // package main // From cd595be6d669af171bc28bdc939cc36785717718 Mon Sep 17 00:00:00 2001 From: Jakub Ciolek Date: Sat, 11 Jan 2025 19:26:57 +0100 Subject: [PATCH 247/397] cmd/compile: prefer an add when shifting left by 1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ADD(Q|L) has generally twice the throughput. Came up in CL 626998. Throughput by arch: Zen 4: SHLL (R64, 1): 0.5 ADD (R64, R64): 0.25 Intel Alder Lake: SHLL (R64, 1): 0.5 ADD (R64, R64): 0.2 Intel Haswell: SHLL (R64, 1): 0.5 ADD (R64, R64): 0.25 Also include a minor opt for: (x + x) << c -> x << (c + 1) Before this, the code: func addShift(x int64) int64 { return (x + x) << 1 } emitted two instructions: ADDQ AX, AX SHLQ $1, AX but we can do it in a single shift: SHLQ $2, AX Add a codegen test for clearing the last bit. compilecmp linux/amd64: math math.sqrt 243 -> 242 (-0.41%) math [cmd/compile] math.sqrt 243 -> 242 (-0.41%) runtime runtime.selectgo 5455 -> 5445 (-0.18%) runtime.sysargs 665 -> 662 (-0.45%) runtime.isPinned 145 -> 141 (-2.76%) runtime.atoi64 198 -> 194 (-2.02%) runtime.setPinned 714 -> 709 (-0.70%) runtime [cmd/compile] runtime.sysargs 665 -> 662 (-0.45%) runtime.setPinned 714 -> 709 (-0.70%) runtime.atoi64 198 -> 194 (-2.02%) runtime.isPinned 145 -> 141 (-2.76%) strconv strconv.computeBounds 109 -> 107 (-1.83%) strconv.FormatInt 201 -> 197 (-1.99%) strconv.ryuFtoaShortest 1298 -> 1266 (-2.47%) strconv.small 144 -> 134 (-6.94%) strconv.AppendInt 357 -> 344 (-3.64%) strconv.ryuDigits32 490 -> 488 (-0.41%) strconv.AppendUint 342 -> 340 (-0.58%) strconv [cmd/compile] strconv.FormatInt 201 -> 197 (-1.99%) strconv.ryuFtoaShortest 1298 -> 1266 (-2.47%) strconv.ryuDigits32 490 -> 488 (-0.41%) strconv.AppendUint 342 -> 340 (-0.58%) strconv.computeBounds 109 -> 107 (-1.83%) strconv.small 144 -> 134 (-6.94%) strconv.AppendInt 357 -> 344 (-3.64%) image image.Rectangle.Inset 101 -> 97 (-3.96%) regexp/syntax regexp/syntax.inCharClass.func1 111 -> 110 (-0.90%) regexp/syntax.(*compiler).quest 586 -> 573 (-2.22%) regexp/syntax.ranges.Less 153 -> 150 (-1.96%) regexp/syntax.(*compiler).loop 583 -> 568 (-2.57%) time time.Time.Before 179 -> 161 (-10.06%) time.Time.Compare 189 -> 166 (-12.17%) time.Time.Sub 444 -> 425 (-4.28%) time.Time.UnixMicro 106 -> 95 (-10.38%) time.div 592 -> 587 (-0.84%) time.Time.UnixNano 85 -> 78 (-8.24%) time.(*Time).UnixMilli 141 -> 140 (-0.71%) time.Time.UnixMilli 106 -> 95 (-10.38%) time.(*Time).UnixMicro 141 -> 140 (-0.71%) time.Time.After 179 -> 161 (-10.06%) time.Time.Equal 170 -> 150 (-11.76%) time.Time.AppendBinary 766 -> 757 (-1.17%) time.Time.IsZero 74 -> 66 (-10.81%) time.(*Time).UnixNano 124 -> 113 (-8.87%) time.(*Time).IsZero 113 -> 108 (-4.42%) regexp regexp.(*Regexp).FindAllStringSubmatch.func1 590 -> 569 (-3.56%) regexp.QuoteMeta 485 -> 469 (-3.30%) regexp/syntax [cmd/compile] regexp/syntax.inCharClass.func1 111 -> 110 (-0.90%) regexp/syntax.(*compiler).loop 583 -> 568 (-2.57%) regexp/syntax.(*compiler).quest 586 -> 573 (-2.22%) regexp/syntax.ranges.Less 153 -> 150 (-1.96%) encoding/base64 encoding/base64.decodedLen 92 -> 90 (-2.17%) encoding/base64.(*Encoding).DecodedLen 99 -> 97 (-2.02%) time [cmd/compile] time.(*Time).IsZero 113 -> 108 (-4.42%) time.Time.IsZero 74 -> 66 (-10.81%) time.(*Time).UnixNano 124 -> 113 (-8.87%) time.Time.UnixMilli 106 -> 95 (-10.38%) time.Time.Equal 170 -> 150 (-11.76%) time.Time.UnixMicro 106 -> 95 (-10.38%) time.(*Time).UnixMicro 141 -> 140 (-0.71%) time.Time.Before 179 -> 161 (-10.06%) time.Time.UnixNano 85 -> 78 (-8.24%) time.Time.AppendBinary 766 -> 757 (-1.17%) time.div 592 -> 587 (-0.84%) time.Time.After 179 -> 161 (-10.06%) time.Time.Compare 189 -> 166 (-12.17%) time.(*Time).UnixMilli 141 -> 140 (-0.71%) time.Time.Sub 444 -> 425 (-4.28%) index/suffixarray index/suffixarray.sais_8_32 1677 -> 1645 (-1.91%) index/suffixarray.sais_32 1677 -> 1645 (-1.91%) index/suffixarray.sais_64 1677 -> 1654 (-1.37%) index/suffixarray.sais_8_64 1677 -> 1654 (-1.37%) index/suffixarray.writeInt 249 -> 247 (-0.80%) os os.Expand 1070 -> 1051 (-1.78%) os.Chtimes 787 -> 774 (-1.65%) regexp [cmd/compile] regexp.(*Regexp).FindAllStringSubmatch.func1 590 -> 569 (-3.56%) regexp.QuoteMeta 485 -> 469 (-3.30%) encoding/base64 [cmd/compile] encoding/base64.decodedLen 92 -> 90 (-2.17%) encoding/base64.(*Encoding).DecodedLen 99 -> 97 (-2.02%) encoding/hex encoding/hex.Encode 138 -> 136 (-1.45%) encoding/hex.(*decoder).Read 830 -> 824 (-0.72%) crypto/des crypto/des.initFeistelBox 235 -> 229 (-2.55%) crypto/des.cryptBlock 549 -> 538 (-2.00%) os [cmd/compile] os.Chtimes 787 -> 774 (-1.65%) os.Expand 1070 -> 1051 (-1.78%) math/big math/big.newFloat 238 -> 223 (-6.30%) math/big.nat.mul 2138 -> 2122 (-0.75%) math/big.karatsubaSqr 1372 -> 1369 (-0.22%) math/big.(*Float).sqrtInverse 895 -> 878 (-1.90%) math/big.basicSqr 1032 -> 1017 (-1.45%) cmd/vendor/golang.org/x/sys/unix cmd/vendor/golang.org/x/sys/unix.TimeToTimespec 72 -> 66 (-8.33%) encoding/json encoding/json.Indent 404 -> 403 (-0.25%) encoding/json.MarshalIndent 303 -> 297 (-1.98%) testing testing.(*T).Deadline 84 -> 82 (-2.38%) testing.(*M).Run 3545 -> 3525 (-0.56%) archive/zip archive/zip.headerFileInfo.ModTime 229 -> 223 (-2.62%) encoding/gob encoding/gob.(*encoderState).encodeInt 474 -> 469 (-1.05%) crypto/elliptic crypto/elliptic.Marshal 728 -> 714 (-1.92%) debug/buildinfo debug/buildinfo.readString 325 -> 315 (-3.08%) image/png image/png.(*decoder).readImagePass 10866 -> 10834 (-0.29%) archive/tar archive/tar.Header.allowedFormats.func3 1768 -> 1736 (-1.81%) archive/tar.formatPAXTime 389 -> 358 (-7.97%) archive/tar.(*Writer).writeGNUHeader 741 -> 727 (-1.89%) archive/tar.readGNUSparseMap0x1 709 -> 695 (-1.97%) archive/tar.(*Writer).templateV7Plus 915 -> 909 (-0.66%) crypto/internal/cryptotest crypto/internal/cryptotest.TestHash.func4 890 -> 879 (-1.24%) crypto/internal/cryptotest.TestStream.func6.1 646 -> 645 (-0.15%) crypto/internal/cryptotest.testCipher.func3 1300 -> 1289 (-0.85%) internal/pkgbits internal/pkgbits.(*Encoder).Int64 113 -> 103 (-8.85%) internal/pkgbits.(*Encoder).rawVarint 74 -> 72 (-2.70%) testing/quick testing/quick.(*Config).getRand 316 -> 315 (-0.32%) log/slog log/slog.TimeValue 489 -> 479 (-2.04%) runtime/pprof runtime/pprof.(*profileBuilder).build 2341 -> 2322 (-0.81%) internal/coverage/cfile internal/coverage/cfile.(*emitState).openMetaFile 824 -> 822 (-0.24%) internal/coverage/cfile.(*emitState).openCounterFile 904 -> 892 (-1.33%) cmd/internal/objabi cmd/internal/objabi.expandArgs 1177 -> 1169 (-0.68%) crypto/ecdsa crypto/ecdsa.pointFromAffine 1162 -> 1144 (-1.55%) net net.minNonzeroTime 313 -> 308 (-1.60%) net.cgoLookupAddrPTR 812 -> 797 (-1.85%) net.(*IPNet).String 851 -> 827 (-2.82%) net.IP.AppendText 488 -> 471 (-3.48%) net.IPMask.String 281 -> 270 (-3.91%) net.partialDeadline 374 -> 366 (-2.14%) net.hexString 249 -> 240 (-3.61%) net.IP.String 454 -> 453 (-0.22%) internal/fuzz internal/fuzz.newPcgRand 240 -> 234 (-2.50%) crypto/x509 crypto/x509.(*Certificate).isValid 2642 -> 2611 (-1.17%) cmd/internal/obj/s390x cmd/internal/obj/s390x.buildop 33676 -> 33644 (-0.10%) encoding/hex [cmd/compile] encoding/hex.(*decoder).Read 830 -> 824 (-0.72%) encoding/hex.Encode 138 -> 136 (-1.45%) cmd/internal/objabi [cmd/compile] cmd/internal/objabi.expandArgs 1177 -> 1169 (-0.68%) math/big [cmd/compile] math/big.(*Float).sqrtInverse 895 -> 878 (-1.90%) math/big.nat.mul 2138 -> 2122 (-0.75%) math/big.karatsubaSqr 1372 -> 1369 (-0.22%) math/big.basicSqr 1032 -> 1017 (-1.45%) math/big.newFloat 238 -> 223 (-6.30%) encoding/json [cmd/compile] encoding/json.MarshalIndent 303 -> 297 (-1.98%) encoding/json.Indent 404 -> 403 (-0.25%) cmd/covdata main.(*metaMerge).emitCounters 985 -> 973 (-1.22%) runtime/pprof [cmd/compile] runtime/pprof.(*profileBuilder).build 2341 -> 2322 (-0.81%) cmd/compile/internal/syntax cmd/compile/internal/syntax.(*source).fill 722 -> 703 (-2.63%) cmd/dist main.runInstall 19081 -> 19049 (-0.17%) crypto/tls crypto/tls.extractPadding 176 -> 175 (-0.57%) slices.Clone[[]crypto/tls.SignatureScheme,crypto/tls.SignatureScheme] 253 -> 247 (-2.37%) slices.Clone[[]uint16,uint16] 253 -> 247 (-2.37%) slices.Clone[[]crypto/tls.CurveID,crypto/tls.CurveID] 253 -> 247 (-2.37%) crypto/tls.(*Config).cipherSuites 335 -> 326 (-2.69%) slices.DeleteFunc[go.shape.[]crypto/tls.CurveID,go.shape.uint16] 437 -> 434 (-0.69%) crypto/tls.dial 1349 -> 1339 (-0.74%) slices.DeleteFunc[go.shape.[]uint16,go.shape.uint16] 437 -> 434 (-0.69%) internal/pkgbits [cmd/compile] internal/pkgbits.(*Encoder).Int64 113 -> 103 (-8.85%) internal/pkgbits.(*Encoder).rawVarint 74 -> 72 (-2.70%) cmd/compile/internal/syntax [cmd/compile] cmd/compile/internal/syntax.(*source).fill 722 -> 703 (-2.63%) cmd/internal/obj/s390x [cmd/compile] cmd/internal/obj/s390x.buildop 33676 -> 33644 (-0.10%) cmd/go/internal/trace cmd/go/internal/trace.Flow 910 -> 886 (-2.64%) cmd/go/internal/trace.(*Span).Done 311 -> 304 (-2.25%) cmd/go/internal/trace.StartSpan 620 -> 615 (-0.81%) cmd/internal/script cmd/internal/script.(*Engine).Execute.func2 534 -> 528 (-1.12%) cmd/link/internal/loader cmd/link/internal/loader.(*Loader).SetSymSect 344 -> 338 (-1.74%) net/http net/http.(*Transport).queueForIdleConn 1797 -> 1766 (-1.73%) net/http.(*Transport).getConn 2149 -> 2131 (-0.84%) net/http.(*http2ClientConn).tooIdleLocked 207 -> 197 (-4.83%) net/http.(*http2responseWriter).SetWriteDeadline.func1 520 -> 508 (-2.31%) net/http.(*Cookie).Valid 837 -> 818 (-2.27%) net/http.(*http2responseWriter).SetReadDeadline 373 -> 357 (-4.29%) net/http.checkIfRange 701 -> 690 (-1.57%) net/http.(*http2SettingsFrame).Value 325 -> 298 (-8.31%) net/http.(*http2SettingsFrame).HasDuplicates 777 -> 767 (-1.29%) net/http.(*Server).Serve 1746 -> 1739 (-0.40%) net/http.http2traceGotConn 569 -> 556 (-2.28%) net/http/pprof net/http/pprof.collectProfile 242 -> 239 (-1.24%) cmd/compile/internal/coverage cmd/compile/internal/coverage.metaHashAndLen 439 -> 438 (-0.23%) cmd/vendor/golang.org/x/telemetry/internal/upload cmd/vendor/golang.org/x/telemetry/internal/upload.(*uploader).findWork 4570 -> 4540 (-0.66%) cmd/vendor/golang.org/x/telemetry/internal/upload.(*uploader).reports 3604 -> 3572 (-0.89%) cmd/compile/internal/coverage [cmd/compile] cmd/compile/internal/coverage.metaHashAndLen 439 -> 438 (-0.23%) cmd/vendor/golang.org/x/text/language cmd/vendor/golang.org/x/text/language.regionGroupDist 287 -> 284 (-1.05%) cmd/go/internal/vcweb cmd/go/internal/vcweb.(*Server).overview.func1 1045 -> 1041 (-0.38%) cmd/go/internal/vcs cmd/go/internal/vcs.expand 761 -> 741 (-2.63%) cmd/compile/internal/inline/inlheur slices.stableCmpFunc[go.shape.struct 2300 -> 2284 (-0.70%) cmd/compile/internal/inline/inlheur [cmd/compile] slices.stableCmpFunc[go.shape.struct 2300 -> 2284 (-0.70%) cmd/go/internal/modfetch/codehost cmd/go/internal/modfetch/codehost.bzrParseStat 2217 -> 2213 (-0.18%) cmd/link/internal/ld cmd/link/internal/ld.decodetypeStructFieldCount 157 -> 152 (-3.18%) cmd/link/internal/ld.(*Link).address 12559 -> 12495 (-0.51%) cmd/link/internal/ld.(*dodataState).allocateDataSections 18345 -> 18205 (-0.76%) cmd/link/internal/ld.elfshreloc 618 -> 616 (-0.32%) cmd/link/internal/ld.(*deadcodePass).decodetypeMethods 794 -> 779 (-1.89%) cmd/link/internal/ld.(*dodataState).assignDsymsToSection 668 -> 663 (-0.75%) cmd/link/internal/ld.relocSectFn 285 -> 284 (-0.35%) cmd/link/internal/ld.decodetypeIfaceMethodCount 146 -> 144 (-1.37%) cmd/link/internal/ld.decodetypeArrayLen 157 -> 152 (-3.18%) cmd/link/internal/arm64 cmd/link/internal/arm64.gensymlate.func1 895 -> 888 (-0.78%) cmd/go/internal/modload cmd/go/internal/modload.queryProxy.func3 1029 -> 1012 (-1.65%) cmd/go/internal/load cmd/go/internal/load.(*Package).setBuildInfo 8453 -> 8447 (-0.07%) cmd/go/internal/clean cmd/go/internal/clean.runClean 2120 -> 2104 (-0.75%) cmd/compile/internal/ssa cmd/compile/internal/ssa.(*poset).aliasnodes 2010 -> 1978 (-1.59%) cmd/compile/internal/ssa.rewriteValueARM64_OpARM64MOVHstoreidx2 730 -> 719 (-1.51%) cmd/compile/internal/ssa.(*debugState).buildLocationLists 3326 -> 3294 (-0.96%) cmd/compile/internal/ssa.rewriteValueAMD64_OpAMD64ADDLconst 3069 -> 2941 (-4.17%) cmd/compile/internal/ssa.(*debugState).processValue 9756 -> 9724 (-0.33%) cmd/compile/internal/ssa.rewriteValueAMD64_OpAMD64ADDQconst 3069 -> 2941 (-4.17%) cmd/compile/internal/ssa.(*poset).mergeroot 1079 -> 1054 (-2.32%) cmd/compile/internal/ssa [cmd/compile] cmd/compile/internal/ssa.rewriteValueARM64_OpARM64MOVHstoreidx2 730 -> 719 (-1.51%) cmd/compile/internal/ssa.(*poset).aliasnodes 2010 -> 1978 (-1.59%) cmd/compile/internal/ssa.(*poset).mergeroot 1079 -> 1054 (-2.32%) cmd/compile/internal/ssa.rewriteValueAMD64_OpAMD64ADDQconst 3069 -> 2941 (-4.17%) cmd/compile/internal/ssa.rewriteValueAMD64_OpAMD64ADDLconst 3069 -> 2941 (-4.17%) file before after Δ % math/bits.s 2352 2354 +2 +0.085% math/bits [cmd/compile].s 2352 2354 +2 +0.085% math.s 35675 35674 -1 -0.003% math [cmd/compile].s 35675 35674 -1 -0.003% runtime.s 577251 577245 -6 -0.001% runtime [cmd/compile].s 642419 642438 +19 +0.003% sort.s 37434 37435 +1 +0.003% strconv.s 48391 48343 -48 -0.099% sort [cmd/compile].s 37434 37435 +1 +0.003% bufio.s 21386 21418 +32 +0.150% strconv [cmd/compile].s 48391 48343 -48 -0.099% image.s 34978 35022 +44 +0.126% regexp/syntax.s 81719 81781 +62 +0.076% time.s 94341 94184 -157 -0.166% regexp.s 60411 60399 -12 -0.020% bufio [cmd/compile].s 21512 21544 +32 +0.149% encoding/binary.s 34062 34087 +25 +0.073% regexp/syntax [cmd/compile].s 81719 81781 +62 +0.076% encoding/base64.s 11907 11903 -4 -0.034% time [cmd/compile].s 94341 94184 -157 -0.166% index/suffixarray.s 41633 41527 -106 -0.255% os.s 101770 101738 -32 -0.031% regexp [cmd/compile].s 60411 60399 -12 -0.020% encoding/binary [cmd/compile].s 37173 37198 +25 +0.067% encoding/base64 [cmd/compile].s 11907 11903 -4 -0.034% os/exec.s 23900 23907 +7 +0.029% encoding/hex.s 6038 6030 -8 -0.132% crypto/des.s 5073 5056 -17 -0.335% os [cmd/compile].s 102030 101998 -32 -0.031% vendor/golang.org/x/net/http2/hpack.s 22027 22033 +6 +0.027% math/big.s 164808 164753 -55 -0.033% cmd/vendor/golang.org/x/sys/unix.s 121450 121444 -6 -0.005% encoding/json.s 110294 110287 -7 -0.006% testing.s 115303 115281 -22 -0.019% archive/zip.s 65329 65325 -4 -0.006% os/user.s 10078 10080 +2 +0.020% encoding/gob.s 143788 143783 -5 -0.003% crypto/elliptic.s 30686 30704 +18 +0.059% go/doc/comment.s 49401 49433 +32 +0.065% debug/buildinfo.s 9095 9085 -10 -0.110% image/png.s 36113 36081 -32 -0.089% archive/tar.s 71994 71897 -97 -0.135% crypto/internal/cryptotest.s 60872 60849 -23 -0.038% internal/pkgbits.s 20441 20429 -12 -0.059% testing/quick.s 8236 8235 -1 -0.012% log/slog.s 77568 77558 -10 -0.013% internal/trace/internal/oldtrace.s 52885 52896 +11 +0.021% runtime/pprof.s 123978 123969 -9 -0.007% internal/coverage/cfile.s 25198 25184 -14 -0.056% cmd/internal/objabi.s 19954 19946 -8 -0.040% crypto/ecdsa.s 29159 29141 -18 -0.062% log/slog/internal/benchmarks.s 6694 6695 +1 +0.015% net.s 299569 299503 -66 -0.022% os/exec [cmd/compile].s 23888 23895 +7 +0.029% internal/trace.s 179226 179240 +14 +0.008% internal/fuzz.s 86190 86191 +1 +0.001% crypto/x509.s 177195 177164 -31 -0.017% cmd/internal/obj/s390x.s 121642 121610 -32 -0.026% cmd/internal/obj/ppc64.s 140118 140122 +4 +0.003% encoding/hex [cmd/compile].s 6149 6141 -8 -0.130% cmd/internal/objabi [cmd/compile].s 19954 19946 -8 -0.040% cmd/internal/obj/arm64.s 158523 158555 +32 +0.020% go/doc/comment [cmd/compile].s 49512 49544 +32 +0.065% math/big [cmd/compile].s 166394 166339 -55 -0.033% encoding/json [cmd/compile].s 110712 110705 -7 -0.006% cmd/covdata.s 39699 39687 -12 -0.030% runtime/pprof [cmd/compile].s 125209 125200 -9 -0.007% cmd/compile/internal/syntax.s 181755 181736 -19 -0.010% cmd/dist.s 177893 177861 -32 -0.018% crypto/tls.s 389157 389113 -44 -0.011% internal/pkgbits [cmd/compile].s 41644 41632 -12 -0.029% cmd/compile/internal/syntax [cmd/compile].s 196105 196086 -19 -0.010% cmd/compile/internal/types.s 71315 71345 +30 +0.042% cmd/internal/obj/s390x [cmd/compile].s 121733 121701 -32 -0.026% cmd/go/internal/trace.s 4796 4760 -36 -0.751% cmd/internal/obj/arm64 [cmd/compile].s 168120 168147 +27 +0.016% cmd/internal/obj/ppc64 [cmd/compile].s 140219 140223 +4 +0.003% cmd/internal/script.s 83442 83436 -6 -0.007% cmd/link/internal/loader.s 93299 93294 -5 -0.005% net/http.s 620639 620472 -167 -0.027% net/http/pprof.s 35016 35013 -3 -0.009% cmd/compile/internal/coverage.s 6668 6667 -1 -0.015% cmd/vendor/golang.org/x/telemetry/internal/upload.s 34210 34148 -62 -0.181% cmd/compile/internal/coverage [cmd/compile].s 6664 6663 -1 -0.015% cmd/vendor/golang.org/x/text/language.s 48077 48074 -3 -0.006% cmd/go/internal/vcweb.s 45193 45189 -4 -0.009% cmd/go/internal/vcs.s 44749 44729 -20 -0.045% cmd/compile/internal/inline/inlheur.s 83758 83742 -16 -0.019% cmd/compile/internal/inline/inlheur [cmd/compile].s 84773 84757 -16 -0.019% cmd/go/internal/modfetch/codehost.s 89098 89094 -4 -0.004% cmd/trace.s 257550 257564 +14 +0.005% cmd/link/internal/ld.s 641945 641706 -239 -0.037% cmd/link/internal/arm64.s 34805 34798 -7 -0.020% cmd/go/internal/modload.s 328971 328954 -17 -0.005% cmd/go/internal/load.s 178877 178871 -6 -0.003% cmd/go/internal/clean.s 11006 10990 -16 -0.145% cmd/compile/internal/ssa.s 3552843 3553347 +504 +0.014% cmd/compile/internal/ssa [cmd/compile].s 3752511 3753123 +612 +0.016% total 36179015 36178687 -328 -0.001% Change-Id: I251c2898ccf3c9931d162d87dabbd49cf4ec73a5 Reviewed-on: https://go-review.googlesource.com/c/go/+/641757 Reviewed-by: Keith Randall Auto-Submit: Keith Randall Reviewed-by: Keith Randall Reviewed-by: Cherry Mui LUCI-TryBot-Result: Go LUCI --- src/cmd/compile/internal/ssa/_gen/AMD64.rules | 26 +- src/cmd/compile/internal/ssa/rewriteAMD64.go | 315 +++++++++++++----- test/codegen/arithmetic.go | 9 + test/codegen/bits.go | 10 + test/codegen/shift.go | 30 ++ 5 files changed, 300 insertions(+), 90 deletions(-) diff --git a/src/cmd/compile/internal/ssa/_gen/AMD64.rules b/src/cmd/compile/internal/ssa/_gen/AMD64.rules index 1a32c26ae24b26..ba7f181f5e4909 100644 --- a/src/cmd/compile/internal/ssa/_gen/AMD64.rules +++ b/src/cmd/compile/internal/ssa/_gen/AMD64.rules @@ -664,9 +664,11 @@ // Handle bit-testing in the form (a>>b)&1 != 0 by building the above rules // and further combining shifts. (BT(Q|L)const [c] (SHRQconst [d] x)) && (c+d)<64 => (BTQconst [c+d] x) +(BT(Q|L)const [c] (ADDQ x x)) && c>1 => (BT(Q|L)const [c-1] x) (BT(Q|L)const [c] (SHLQconst [d] x)) && c>d => (BT(Q|L)const [c-d] x) (BT(Q|L)const [0] s:(SHRQ x y)) => (BTQ y x) (BTLconst [c] (SHRLconst [d] x)) && (c+d)<32 => (BTLconst [c+d] x) +(BTLconst [c] (ADDL x x)) && c>1 => (BTLconst [c-1] x) (BTLconst [c] (SHLLconst [d] x)) && c>d => (BTLconst [c-d] x) (BTLconst [0] s:(SHR(L|XL) x y)) => (BTL y x) @@ -702,11 +704,11 @@ // We thus special-case them, by detecting the shift patterns. // Special case resetting first/last bit -(SHL(L|Q)const [1] (SHR(L|Q)const [1] x)) +(ADD(L|Q) (SHR(L|Q)const [1] x) (SHR(L|Q)const [1] x)) => (AND(L|Q)const [-2] x) -(SHRLconst [1] (SHLLconst [1] x)) +(SHRLconst [1] (ADDL x x)) => (ANDLconst [0x7fffffff] x) -(SHRQconst [1] (SHLQconst [1] x)) +(SHRQconst [1] (ADDQ x x)) => (BTRQconst [63] x) // Special case testing first/last bit (with double-shift generated by generic.rules) @@ -933,17 +935,19 @@ (MUL(Q|L)const [c] x) && c%5 == 0 && isPowerOfTwo(c/5) => (SHL(Q|L)const [int8(log32(c/5))] (LEA(Q|L)4 x x)) (MUL(Q|L)const [c] x) && c%9 == 0 && isPowerOfTwo(c/9) => (SHL(Q|L)const [int8(log32(c/9))] (LEA(Q|L)8 x x)) +// Prefer addition when shifting left by one +(SHL(Q|L)const [1] x) => (ADD(Q|L) x x) + // combine add/shift into LEAQ/LEAL (ADD(L|Q) x (SHL(L|Q)const [3] y)) => (LEA(L|Q)8 x y) (ADD(L|Q) x (SHL(L|Q)const [2] y)) => (LEA(L|Q)4 x y) -(ADD(L|Q) x (SHL(L|Q)const [1] y)) => (LEA(L|Q)2 x y) (ADD(L|Q) x (ADD(L|Q) y y)) => (LEA(L|Q)2 x y) (ADD(L|Q) x (ADD(L|Q) x y)) => (LEA(L|Q)2 y x) // combine ADDQ/ADDQconst into LEAQ1/LEAL1 (ADD(Q|L)const [c] (ADD(Q|L) x y)) => (LEA(Q|L)1 [c] x y) (ADD(Q|L) (ADD(Q|L)const [c] x) y) => (LEA(Q|L)1 [c] x y) -(ADD(Q|L)const [c] (SHL(Q|L)const [1] x)) => (LEA(Q|L)1 [c] x x) +(ADD(Q|L)const [c] (ADD(Q|L) x x)) => (LEA(Q|L)1 [c] x x) // fold ADDQ/ADDL into LEAQ/LEAL (ADD(Q|L)const [c] (LEA(Q|L) [d] {s} x)) && is32Bit(int64(c)+int64(d)) => (LEA(Q|L) [c+d] {s} x) @@ -965,12 +969,18 @@ (LEA(Q|L)8 [c] {s} x (ADD(Q|L)const [d] y)) && is32Bit(int64(c)+8*int64(d)) && y.Op != OpSB => (LEA(Q|L)8 [c+8*d] {s} x y) // fold shifts into LEAQx/LEALx -(LEA(Q|L)1 [c] {s} x (SHL(Q|L)const [1] y)) => (LEA(Q|L)2 [c] {s} x y) +(LEA(Q|L)1 [c] {s} x (ADD(Q|L) y y)) => (LEA(Q|L)2 [c] {s} x y) (LEA(Q|L)1 [c] {s} x (SHL(Q|L)const [2] y)) => (LEA(Q|L)4 [c] {s} x y) (LEA(Q|L)1 [c] {s} x (SHL(Q|L)const [3] y)) => (LEA(Q|L)8 [c] {s} x y) -(LEA(Q|L)2 [c] {s} x (SHL(Q|L)const [1] y)) => (LEA(Q|L)4 [c] {s} x y) +(LEA(Q|L)2 [c] {s} x (ADD(Q|L) y y)) => (LEA(Q|L)4 [c] {s} x y) (LEA(Q|L)2 [c] {s} x (SHL(Q|L)const [2] y)) => (LEA(Q|L)8 [c] {s} x y) -(LEA(Q|L)4 [c] {s} x (SHL(Q|L)const [1] y)) => (LEA(Q|L)8 [c] {s} x y) +(LEA(Q|L)4 [c] {s} x (ADD(Q|L) y y)) => (LEA(Q|L)8 [c] {s} x y) + +// (x + x) << 1 -> x << 2 +(LEA(Q|L)2 [0] {s} (ADD(Q|L) x x) x) && s == nil => (SHL(Q|L)const [2] x) + +// (x + x) << 2 -> x << 3 and similar +(SHL(Q|L)const [c] (ADD(Q|L) x x)) => (SHL(Q|L)const [c+1] x) // reverse ordering of compare instruction (SETL (InvertFlags x)) => (SETG x) diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go index 7dc0a7bdc2a1a1..28041ea76d1953 100644 --- a/src/cmd/compile/internal/ssa/rewriteAMD64.go +++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go @@ -1261,6 +1261,21 @@ func rewriteValueAMD64_OpAMD64ADCQconst(v *Value) bool { func rewriteValueAMD64_OpAMD64ADDL(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] + // match: (ADDL (SHRLconst [1] x) (SHRLconst [1] x)) + // result: (ANDLconst [-2] x) + for { + if v_0.Op != OpAMD64SHRLconst || auxIntToInt8(v_0.AuxInt) != 1 { + break + } + x := v_0.Args[0] + if v_1.Op != OpAMD64SHRLconst || auxIntToInt8(v_1.AuxInt) != 1 || x != v_1.Args[0] { + break + } + v.reset(OpAMD64ANDLconst) + v.AuxInt = int32ToAuxInt(-2) + v.AddArg(x) + return true + } // match: (ADDL x (MOVLconst [c])) // result: (ADDLconst [c] x) for { @@ -1307,21 +1322,6 @@ func rewriteValueAMD64_OpAMD64ADDL(v *Value) bool { } break } - // match: (ADDL x (SHLLconst [1] y)) - // result: (LEAL2 x y) - for { - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - x := v_0 - if v_1.Op != OpAMD64SHLLconst || auxIntToInt8(v_1.AuxInt) != 1 { - continue - } - y := v_1.Args[0] - v.reset(OpAMD64LEAL2) - v.AddArg2(x, y) - return true - } - break - } // match: (ADDL x (ADDL y y)) // result: (LEAL2 x y) for { @@ -1461,14 +1461,17 @@ func rewriteValueAMD64_OpAMD64ADDLconst(v *Value) bool { v.AddArg2(x, y) return true } - // match: (ADDLconst [c] (SHLLconst [1] x)) + // match: (ADDLconst [c] (ADDL x x)) // result: (LEAL1 [c] x x) for { c := auxIntToInt32(v.AuxInt) - if v_0.Op != OpAMD64SHLLconst || auxIntToInt8(v_0.AuxInt) != 1 { + if v_0.Op != OpAMD64ADDL { + break + } + x := v_0.Args[1] + if x != v_0.Args[0] { break } - x := v_0.Args[0] v.reset(OpAMD64LEAL1) v.AuxInt = int32ToAuxInt(c) v.AddArg2(x, x) @@ -1806,6 +1809,21 @@ func rewriteValueAMD64_OpAMD64ADDLmodify(v *Value) bool { func rewriteValueAMD64_OpAMD64ADDQ(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] + // match: (ADDQ (SHRQconst [1] x) (SHRQconst [1] x)) + // result: (ANDQconst [-2] x) + for { + if v_0.Op != OpAMD64SHRQconst || auxIntToInt8(v_0.AuxInt) != 1 { + break + } + x := v_0.Args[0] + if v_1.Op != OpAMD64SHRQconst || auxIntToInt8(v_1.AuxInt) != 1 || x != v_1.Args[0] { + break + } + v.reset(OpAMD64ANDQconst) + v.AuxInt = int32ToAuxInt(-2) + v.AddArg(x) + return true + } // match: (ADDQ x (MOVQconst [c])) // cond: is32Bit(c) && !t.IsPtr() // result: (ADDQconst [int32(c)] x) @@ -1873,21 +1891,6 @@ func rewriteValueAMD64_OpAMD64ADDQ(v *Value) bool { } break } - // match: (ADDQ x (SHLQconst [1] y)) - // result: (LEAQ2 x y) - for { - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - x := v_0 - if v_1.Op != OpAMD64SHLQconst || auxIntToInt8(v_1.AuxInt) != 1 { - continue - } - y := v_1.Args[0] - v.reset(OpAMD64LEAQ2) - v.AddArg2(x, y) - return true - } - break - } // match: (ADDQ x (ADDQ y y)) // result: (LEAQ2 x y) for { @@ -2052,14 +2055,17 @@ func rewriteValueAMD64_OpAMD64ADDQconst(v *Value) bool { v.AddArg2(x, y) return true } - // match: (ADDQconst [c] (SHLQconst [1] x)) + // match: (ADDQconst [c] (ADDQ x x)) // result: (LEAQ1 [c] x x) for { c := auxIntToInt32(v.AuxInt) - if v_0.Op != OpAMD64SHLQconst || auxIntToInt8(v_0.AuxInt) != 1 { + if v_0.Op != OpAMD64ADDQ { + break + } + x := v_0.Args[1] + if x != v_0.Args[0] { break } - x := v_0.Args[0] v.reset(OpAMD64LEAQ1) v.AuxInt = int32ToAuxInt(c) v.AddArg2(x, x) @@ -3637,6 +3643,23 @@ func rewriteValueAMD64_OpAMD64BTLconst(v *Value) bool { v.AddArg(x) return true } + // match: (BTLconst [c] (ADDQ x x)) + // cond: c>1 + // result: (BTLconst [c-1] x) + for { + c := auxIntToInt8(v.AuxInt) + if v_0.Op != OpAMD64ADDQ { + break + } + x := v_0.Args[1] + if x != v_0.Args[0] || !(c > 1) { + break + } + v.reset(OpAMD64BTLconst) + v.AuxInt = int8ToAuxInt(c - 1) + v.AddArg(x) + return true + } // match: (BTLconst [c] (SHLQconst [d] x)) // cond: c>d // result: (BTLconst [c-d] x) @@ -3689,6 +3712,23 @@ func rewriteValueAMD64_OpAMD64BTLconst(v *Value) bool { v.AddArg(x) return true } + // match: (BTLconst [c] (ADDL x x)) + // cond: c>1 + // result: (BTLconst [c-1] x) + for { + c := auxIntToInt8(v.AuxInt) + if v_0.Op != OpAMD64ADDL { + break + } + x := v_0.Args[1] + if x != v_0.Args[0] || !(c > 1) { + break + } + v.reset(OpAMD64BTLconst) + v.AuxInt = int8ToAuxInt(c - 1) + v.AddArg(x) + return true + } // match: (BTLconst [c] (SHLLconst [d] x)) // cond: c>d // result: (BTLconst [c-d] x) @@ -3761,6 +3801,23 @@ func rewriteValueAMD64_OpAMD64BTQconst(v *Value) bool { v.AddArg(x) return true } + // match: (BTQconst [c] (ADDQ x x)) + // cond: c>1 + // result: (BTQconst [c-1] x) + for { + c := auxIntToInt8(v.AuxInt) + if v_0.Op != OpAMD64ADDQ { + break + } + x := v_0.Args[1] + if x != v_0.Args[0] || !(c > 1) { + break + } + v.reset(OpAMD64BTQconst) + v.AuxInt = int8ToAuxInt(c - 1) + v.AddArg(x) + return true + } // match: (BTQconst [c] (SHLQconst [d] x)) // cond: c>d // result: (BTQconst [c-d] x) @@ -8287,17 +8344,20 @@ func rewriteValueAMD64_OpAMD64LEAL1(v *Value) bool { } break } - // match: (LEAL1 [c] {s} x (SHLLconst [1] y)) + // match: (LEAL1 [c] {s} x (ADDL y y)) // result: (LEAL2 [c] {s} x y) for { c := auxIntToInt32(v.AuxInt) s := auxToSym(v.Aux) for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { x := v_0 - if v_1.Op != OpAMD64SHLLconst || auxIntToInt8(v_1.AuxInt) != 1 { + if v_1.Op != OpAMD64ADDL { + continue + } + y := v_1.Args[1] + if y != v_1.Args[0] { continue } - y := v_1.Args[0] v.reset(OpAMD64LEAL2) v.AuxInt = int32ToAuxInt(c) v.Aux = symToAux(s) @@ -8391,16 +8451,19 @@ func rewriteValueAMD64_OpAMD64LEAL2(v *Value) bool { v.AddArg2(x, y) return true } - // match: (LEAL2 [c] {s} x (SHLLconst [1] y)) + // match: (LEAL2 [c] {s} x (ADDL y y)) // result: (LEAL4 [c] {s} x y) for { c := auxIntToInt32(v.AuxInt) s := auxToSym(v.Aux) x := v_0 - if v_1.Op != OpAMD64SHLLconst || auxIntToInt8(v_1.AuxInt) != 1 { + if v_1.Op != OpAMD64ADDL { + break + } + y := v_1.Args[1] + if y != v_1.Args[0] { break } - y := v_1.Args[0] v.reset(OpAMD64LEAL4) v.AuxInt = int32ToAuxInt(c) v.Aux = symToAux(s) @@ -8423,6 +8486,26 @@ func rewriteValueAMD64_OpAMD64LEAL2(v *Value) bool { v.AddArg2(x, y) return true } + // match: (LEAL2 [0] {s} (ADDL x x) x) + // cond: s == nil + // result: (SHLLconst [2] x) + for { + if auxIntToInt32(v.AuxInt) != 0 { + break + } + s := auxToSym(v.Aux) + if v_0.Op != OpAMD64ADDL { + break + } + x := v_0.Args[1] + if x != v_0.Args[0] || x != v_1 || !(s == nil) { + break + } + v.reset(OpAMD64SHLLconst) + v.AuxInt = int8ToAuxInt(2) + v.AddArg(x) + return true + } return false } func rewriteValueAMD64_OpAMD64LEAL4(v *Value) bool { @@ -8470,16 +8553,19 @@ func rewriteValueAMD64_OpAMD64LEAL4(v *Value) bool { v.AddArg2(x, y) return true } - // match: (LEAL4 [c] {s} x (SHLLconst [1] y)) + // match: (LEAL4 [c] {s} x (ADDL y y)) // result: (LEAL8 [c] {s} x y) for { c := auxIntToInt32(v.AuxInt) s := auxToSym(v.Aux) x := v_0 - if v_1.Op != OpAMD64SHLLconst || auxIntToInt8(v_1.AuxInt) != 1 { + if v_1.Op != OpAMD64ADDL { + break + } + y := v_1.Args[1] + if y != v_1.Args[0] { break } - y := v_1.Args[0] v.reset(OpAMD64LEAL8) v.AuxInt = int32ToAuxInt(c) v.Aux = symToAux(s) @@ -8721,17 +8807,20 @@ func rewriteValueAMD64_OpAMD64LEAQ1(v *Value) bool { } break } - // match: (LEAQ1 [c] {s} x (SHLQconst [1] y)) + // match: (LEAQ1 [c] {s} x (ADDQ y y)) // result: (LEAQ2 [c] {s} x y) for { c := auxIntToInt32(v.AuxInt) s := auxToSym(v.Aux) for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { x := v_0 - if v_1.Op != OpAMD64SHLQconst || auxIntToInt8(v_1.AuxInt) != 1 { + if v_1.Op != OpAMD64ADDQ { + continue + } + y := v_1.Args[1] + if y != v_1.Args[0] { continue } - y := v_1.Args[0] v.reset(OpAMD64LEAQ2) v.AuxInt = int32ToAuxInt(c) v.Aux = symToAux(s) @@ -8924,16 +9013,19 @@ func rewriteValueAMD64_OpAMD64LEAQ2(v *Value) bool { v.AddArg2(x, y) return true } - // match: (LEAQ2 [c] {s} x (SHLQconst [1] y)) + // match: (LEAQ2 [c] {s} x (ADDQ y y)) // result: (LEAQ4 [c] {s} x y) for { c := auxIntToInt32(v.AuxInt) s := auxToSym(v.Aux) x := v_0 - if v_1.Op != OpAMD64SHLQconst || auxIntToInt8(v_1.AuxInt) != 1 { + if v_1.Op != OpAMD64ADDQ { + break + } + y := v_1.Args[1] + if y != v_1.Args[0] { break } - y := v_1.Args[0] v.reset(OpAMD64LEAQ4) v.AuxInt = int32ToAuxInt(c) v.Aux = symToAux(s) @@ -8956,6 +9048,26 @@ func rewriteValueAMD64_OpAMD64LEAQ2(v *Value) bool { v.AddArg2(x, y) return true } + // match: (LEAQ2 [0] {s} (ADDQ x x) x) + // cond: s == nil + // result: (SHLQconst [2] x) + for { + if auxIntToInt32(v.AuxInt) != 0 { + break + } + s := auxToSym(v.Aux) + if v_0.Op != OpAMD64ADDQ { + break + } + x := v_0.Args[1] + if x != v_0.Args[0] || x != v_1 || !(s == nil) { + break + } + v.reset(OpAMD64SHLQconst) + v.AuxInt = int8ToAuxInt(2) + v.AddArg(x) + return true + } // match: (LEAQ2 [off1] {sym1} (LEAQ [off2] {sym2} x) y) // cond: is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && x.Op != OpSB // result: (LEAQ2 [off1+off2] {mergeSym(sym1,sym2)} x y) @@ -9087,16 +9199,19 @@ func rewriteValueAMD64_OpAMD64LEAQ4(v *Value) bool { v.AddArg2(x, y) return true } - // match: (LEAQ4 [c] {s} x (SHLQconst [1] y)) + // match: (LEAQ4 [c] {s} x (ADDQ y y)) // result: (LEAQ8 [c] {s} x y) for { c := auxIntToInt32(v.AuxInt) s := auxToSym(v.Aux) x := v_0 - if v_1.Op != OpAMD64SHLQconst || auxIntToInt8(v_1.AuxInt) != 1 { + if v_1.Op != OpAMD64ADDQ { + break + } + y := v_1.Args[1] + if y != v_1.Args[0] { break } - y := v_1.Args[0] v.reset(OpAMD64LEAQ8) v.AuxInt = int32ToAuxInt(c) v.Aux = symToAux(s) @@ -20736,26 +20851,41 @@ func rewriteValueAMD64_OpAMD64SHLL(v *Value) bool { } func rewriteValueAMD64_OpAMD64SHLLconst(v *Value) bool { v_0 := v.Args[0] - // match: (SHLLconst [1] (SHRLconst [1] x)) - // result: (ANDLconst [-2] x) + // match: (SHLLconst x [0]) + // result: x for { - if auxIntToInt8(v.AuxInt) != 1 || v_0.Op != OpAMD64SHRLconst || auxIntToInt8(v_0.AuxInt) != 1 { + if auxIntToInt8(v.AuxInt) != 0 { break } - x := v_0.Args[0] - v.reset(OpAMD64ANDLconst) - v.AuxInt = int32ToAuxInt(-2) - v.AddArg(x) + x := v_0 + v.copyOf(x) return true } - // match: (SHLLconst x [0]) - // result: x + // match: (SHLLconst [1] x) + // result: (ADDL x x) for { - if auxIntToInt8(v.AuxInt) != 0 { + if auxIntToInt8(v.AuxInt) != 1 { break } x := v_0 - v.copyOf(x) + v.reset(OpAMD64ADDL) + v.AddArg2(x, x) + return true + } + // match: (SHLLconst [c] (ADDL x x)) + // result: (SHLLconst [c+1] x) + for { + c := auxIntToInt8(v.AuxInt) + if v_0.Op != OpAMD64ADDL { + break + } + x := v_0.Args[1] + if x != v_0.Args[0] { + break + } + v.reset(OpAMD64SHLLconst) + v.AuxInt = int8ToAuxInt(c + 1) + v.AddArg(x) return true } // match: (SHLLconst [d] (MOVLconst [c])) @@ -20992,26 +21122,41 @@ func rewriteValueAMD64_OpAMD64SHLQ(v *Value) bool { } func rewriteValueAMD64_OpAMD64SHLQconst(v *Value) bool { v_0 := v.Args[0] - // match: (SHLQconst [1] (SHRQconst [1] x)) - // result: (ANDQconst [-2] x) + // match: (SHLQconst x [0]) + // result: x for { - if auxIntToInt8(v.AuxInt) != 1 || v_0.Op != OpAMD64SHRQconst || auxIntToInt8(v_0.AuxInt) != 1 { + if auxIntToInt8(v.AuxInt) != 0 { break } - x := v_0.Args[0] - v.reset(OpAMD64ANDQconst) - v.AuxInt = int32ToAuxInt(-2) - v.AddArg(x) + x := v_0 + v.copyOf(x) return true } - // match: (SHLQconst x [0]) - // result: x + // match: (SHLQconst [1] x) + // result: (ADDQ x x) for { - if auxIntToInt8(v.AuxInt) != 0 { + if auxIntToInt8(v.AuxInt) != 1 { break } x := v_0 - v.copyOf(x) + v.reset(OpAMD64ADDQ) + v.AddArg2(x, x) + return true + } + // match: (SHLQconst [c] (ADDQ x x)) + // result: (SHLQconst [c+1] x) + for { + c := auxIntToInt8(v.AuxInt) + if v_0.Op != OpAMD64ADDQ { + break + } + x := v_0.Args[1] + if x != v_0.Args[0] { + break + } + v.reset(OpAMD64SHLQconst) + v.AuxInt = int8ToAuxInt(c + 1) + v.AddArg(x) return true } // match: (SHLQconst [d] (MOVQconst [c])) @@ -21419,13 +21564,16 @@ func rewriteValueAMD64_OpAMD64SHRL(v *Value) bool { } func rewriteValueAMD64_OpAMD64SHRLconst(v *Value) bool { v_0 := v.Args[0] - // match: (SHRLconst [1] (SHLLconst [1] x)) + // match: (SHRLconst [1] (ADDL x x)) // result: (ANDLconst [0x7fffffff] x) for { - if auxIntToInt8(v.AuxInt) != 1 || v_0.Op != OpAMD64SHLLconst || auxIntToInt8(v_0.AuxInt) != 1 { + if auxIntToInt8(v.AuxInt) != 1 || v_0.Op != OpAMD64ADDL { + break + } + x := v_0.Args[1] + if x != v_0.Args[0] { break } - x := v_0.Args[0] v.reset(OpAMD64ANDLconst) v.AuxInt = int32ToAuxInt(0x7fffffff) v.AddArg(x) @@ -21663,13 +21811,16 @@ func rewriteValueAMD64_OpAMD64SHRQ(v *Value) bool { } func rewriteValueAMD64_OpAMD64SHRQconst(v *Value) bool { v_0 := v.Args[0] - // match: (SHRQconst [1] (SHLQconst [1] x)) + // match: (SHRQconst [1] (ADDQ x x)) // result: (BTRQconst [63] x) for { - if auxIntToInt8(v.AuxInt) != 1 || v_0.Op != OpAMD64SHLQconst || auxIntToInt8(v_0.AuxInt) != 1 { + if auxIntToInt8(v.AuxInt) != 1 || v_0.Op != OpAMD64ADDQ { + break + } + x := v_0.Args[1] + if x != v_0.Args[0] { break } - x := v_0.Args[0] v.reset(OpAMD64BTRQconst) v.AuxInt = int8ToAuxInt(63) v.AddArg(x) diff --git a/test/codegen/arithmetic.go b/test/codegen/arithmetic.go index 4b47f6c13d86de..063055053ec95e 100644 --- a/test/codegen/arithmetic.go +++ b/test/codegen/arithmetic.go @@ -185,6 +185,15 @@ func Pow2Muls(n1, n2 int) (int, int) { return a, b } +func Mul_2(n1 int32, n2 int64) (int32, int64) { + // amd64:"ADDL", -"SHLL" + a := n1 * 2 + // amd64:"ADDQ", -"SHLQ" + b := n2 * 2 + + return a, b +} + func Mul_96(n int) int { // amd64:`SHLQ\t[$]5`,`LEAQ\t\(.*\)\(.*\*2\),`,-`IMULQ` // 386:`SHLL\t[$]5`,`LEAL\t\(.*\)\(.*\*2\),`,-`IMULL` diff --git a/test/codegen/bits.go b/test/codegen/bits.go index 354dbf407a4bac..c20e4d67333f63 100644 --- a/test/codegen/bits.go +++ b/test/codegen/bits.go @@ -120,6 +120,16 @@ func bitoff64(a, b uint64) (n uint64) { return n } +func clearLastBit(x int64, y int32) (int64, int32) { + // amd64:"ANDQ\t[$]-2" + a := (x >> 1) << 1 + + // amd64:"ANDL\t[$]-2" + b := (y >> 1) << 1 + + return a, b +} + func bitcompl64(a, b uint64) (n uint64) { // amd64:"BTCQ" n += b ^ (1 << (a & 63)) diff --git a/test/codegen/shift.go b/test/codegen/shift.go index 2d8cf868571b7d..52efefb0ed828c 100644 --- a/test/codegen/shift.go +++ b/test/codegen/shift.go @@ -58,6 +58,16 @@ func rshConst64x64Overflow8(v int8) int64 { return int64(v) >> 8 } +func lshConst32x1(v int32) int32 { + // amd64:"ADDL", -"SHLL" + return v << 1 +} + +func lshConst64x1(v int64) int64 { + // amd64:"ADDQ", -"SHLQ" + return v << 1 +} + func lshConst32x64(v int32) int32 { // ppc64x:"SLW" // riscv64:"SLLI",-"AND",-"SLTIU", -"MOVW" @@ -94,6 +104,26 @@ func rshConst64x32(v int64) int64 { return v >> uint32(33) } +func lshConst32x1Add(x int32) int32 { + // amd64:"SHLL\t[$]2" + return (x + x) << 1 +} + +func lshConst64x1Add(x int64) int64 { + // amd64:"SHLQ\t[$]2" + return (x + x) << 1 +} + +func lshConst32x2Add(x int32) int32 { + // amd64:"SHLL\t[$]3" + return (x + x) << 2 +} + +func lshConst64x2Add(x int64) int64 { + // amd64:"SHLQ\t[$]3" + return (x + x) << 2 +} + // ------------------ // // masked shifts // // ------------------ // From 65004c7bf4a1193af7742a6de9bc515c4b07bb75 Mon Sep 17 00:00:00 2001 From: qmuntal Date: Mon, 3 Feb 2025 21:05:51 +0100 Subject: [PATCH 248/397] cmd/go: report gcc ld error message when linking fails The output of the gcc ld command is useful to understand why a package that uses cgo can't use internal linking. We should log it. Change-Id: Id524065fc5348be57387f2b67d1e00861f9adf15 Reviewed-on: https://go-review.googlesource.com/c/go/+/646315 LUCI-TryBot-Result: Go LUCI Reviewed-by: Cherry Mui Reviewed-by: Ian Lance Taylor --- src/cmd/go/internal/work/exec.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go index c79d6f73ef4a9d..8e5d48103339b5 100644 --- a/src/cmd/go/internal/work/exec.go +++ b/src/cmd/go/internal/work/exec.go @@ -2208,7 +2208,7 @@ func (b *Builder) gccld(a *Action, objdir, outfile string, flags []string, objs } cmdargs := []any{cmd, "-o", outfile, objs, flags} - _, err := sh.runOut(base.Cwd(), b.cCompilerEnv(), cmdargs...) + out, err := sh.runOut(base.Cwd(), b.cCompilerEnv(), cmdargs...) // Note that failure is an expected outcome here, so we report output only // in debug mode and don't report the error. @@ -2217,7 +2217,7 @@ func (b *Builder) gccld(a *Action, objdir, outfile string, flags []string, objs if err != nil { saw = "failed" } - sh.ShowCmd("", "%s # test for internal linking errors (%s)", joinUnambiguously(str.StringList(cmdargs...)), saw) + sh.ShowCmd("", "%s # test for internal linking errors (%s)\n%s", joinUnambiguously(str.StringList(cmdargs...)), saw, out) } return err From 0da7fafac4eabec799df40278f68ba86b574afea Mon Sep 17 00:00:00 2001 From: Jesse Rittner Date: Sat, 25 Jan 2025 16:21:53 -0500 Subject: [PATCH 249/397] net: fix ListenMulitcastUDP to work properly when interface has no IPv4 The existing implementation would either fail or bind to the wrong interface when the requested interface had no IPv4 address, such as when the Ethernet cable was unplugged. Now on Linux, it will always bind to the requested interface. On other operating systems, it will consistently fail if the requested interface has no IPv4 address. Fixes #70132 Change-Id: I22ec7f9d4adaa4b5afb21fc448050fb4219cacee Reviewed-on: https://go-review.googlesource.com/c/go/+/644375 Reviewed-by: Damien Neil Reviewed-by: Ian Lance Taylor Commit-Queue: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Auto-Submit: Ian Lance Taylor --- src/net/sockopt_posix.go | 30 ----------- ...ckoptip_bsdvar.go => sockoptip4_bsdvar.go} | 0 ...sockoptip_linux.go => sockoptip4_linux.go} | 10 ++++ src/net/sockoptip4_posix_nonlinux.go | 52 +++++++++++++++++++ ...optip_windows.go => sockoptip4_windows.go} | 0 ...sockoptip_posix.go => sockoptip6_posix.go} | 10 ---- 6 files changed, 62 insertions(+), 40 deletions(-) rename src/net/{sockoptip_bsdvar.go => sockoptip4_bsdvar.go} (100%) rename src/net/{sockoptip_linux.go => sockoptip4_linux.go} (68%) create mode 100644 src/net/sockoptip4_posix_nonlinux.go rename src/net/{sockoptip_windows.go => sockoptip4_windows.go} (100%) rename src/net/{sockoptip_posix.go => sockoptip6_posix.go} (74%) diff --git a/src/net/sockopt_posix.go b/src/net/sockopt_posix.go index a380c7719b484c..2452f06b0a6e32 100644 --- a/src/net/sockopt_posix.go +++ b/src/net/sockopt_posix.go @@ -7,7 +7,6 @@ package net import ( - "internal/bytealg" "runtime" "syscall" ) @@ -43,35 +42,6 @@ func interfaceToIPv4Addr(ifi *Interface) (IP, error) { return nil, errNoSuchInterface } -func setIPv4MreqToInterface(mreq *syscall.IPMreq, ifi *Interface) error { - if ifi == nil { - return nil - } - ifat, err := ifi.Addrs() - if err != nil { - return err - } - for _, ifa := range ifat { - switch v := ifa.(type) { - case *IPAddr: - if a := v.IP.To4(); a != nil { - copy(mreq.Interface[:], a) - goto done - } - case *IPNet: - if a := v.IP.To4(); a != nil { - copy(mreq.Interface[:], a) - goto done - } - } - } -done: - if bytealg.Equal(mreq.Multiaddr[:], IPv4zero.To4()) { - return errNoSuchMulticastInterface - } - return nil -} - func setReadBuffer(fd *netFD, bytes int) error { err := fd.pfd.SetsockoptInt(syscall.SOL_SOCKET, syscall.SO_RCVBUF, bytes) runtime.KeepAlive(fd) diff --git a/src/net/sockoptip_bsdvar.go b/src/net/sockoptip4_bsdvar.go similarity index 100% rename from src/net/sockoptip_bsdvar.go rename to src/net/sockoptip4_bsdvar.go diff --git a/src/net/sockoptip_linux.go b/src/net/sockoptip4_linux.go similarity index 68% rename from src/net/sockoptip_linux.go rename to src/net/sockoptip4_linux.go index bd7d8344258e24..8b953ebdc6b438 100644 --- a/src/net/sockoptip_linux.go +++ b/src/net/sockoptip4_linux.go @@ -9,6 +9,16 @@ import ( "syscall" ) +func joinIPv4Group(fd *netFD, ifi *Interface, ip IP) error { + mreq := &syscall.IPMreqn{Multiaddr: [4]byte{ip[0], ip[1], ip[2], ip[3]}} + if ifi != nil { + mreq.Ifindex = int32(ifi.Index) + } + err := fd.pfd.SetsockoptIPMreqn(syscall.IPPROTO_IP, syscall.IP_ADD_MEMBERSHIP, mreq) + runtime.KeepAlive(fd) + return wrapSyscallError("setsockopt", err) +} + func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error { var v int32 if ifi != nil { diff --git a/src/net/sockoptip4_posix_nonlinux.go b/src/net/sockoptip4_posix_nonlinux.go new file mode 100644 index 00000000000000..85e8c6dcfe4116 --- /dev/null +++ b/src/net/sockoptip4_posix_nonlinux.go @@ -0,0 +1,52 @@ +// Copyright 2011 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. + +//go:build (unix && !linux) || windows + +package net + +import ( + "internal/bytealg" + "runtime" + "syscall" +) + +func joinIPv4Group(fd *netFD, ifi *Interface, ip IP) error { + mreq := &syscall.IPMreq{Multiaddr: [4]byte{ip[0], ip[1], ip[2], ip[3]}} + if err := setIPv4MreqToInterface(mreq, ifi); err != nil { + return err + } + err := fd.pfd.SetsockoptIPMreq(syscall.IPPROTO_IP, syscall.IP_ADD_MEMBERSHIP, mreq) + runtime.KeepAlive(fd) + return wrapSyscallError("setsockopt", err) +} + +func setIPv4MreqToInterface(mreq *syscall.IPMreq, ifi *Interface) error { + if ifi == nil { + return nil + } + ifat, err := ifi.Addrs() + if err != nil { + return err + } + for _, ifa := range ifat { + switch v := ifa.(type) { + case *IPAddr: + if a := v.IP.To4(); a != nil { + copy(mreq.Interface[:], a) + goto done + } + case *IPNet: + if a := v.IP.To4(); a != nil { + copy(mreq.Interface[:], a) + goto done + } + } + } +done: + if bytealg.Equal(mreq.Interface[:], IPv4zero.To4()) { + return errNoSuchMulticastInterface + } + return nil +} diff --git a/src/net/sockoptip_windows.go b/src/net/sockoptip4_windows.go similarity index 100% rename from src/net/sockoptip_windows.go rename to src/net/sockoptip4_windows.go diff --git a/src/net/sockoptip_posix.go b/src/net/sockoptip6_posix.go similarity index 74% rename from src/net/sockoptip_posix.go rename to src/net/sockoptip6_posix.go index 572ea455c09586..5bbc609f7b1a4b 100644 --- a/src/net/sockoptip_posix.go +++ b/src/net/sockoptip6_posix.go @@ -11,16 +11,6 @@ import ( "syscall" ) -func joinIPv4Group(fd *netFD, ifi *Interface, ip IP) error { - mreq := &syscall.IPMreq{Multiaddr: [4]byte{ip[0], ip[1], ip[2], ip[3]}} - if err := setIPv4MreqToInterface(mreq, ifi); err != nil { - return err - } - err := fd.pfd.SetsockoptIPMreq(syscall.IPPROTO_IP, syscall.IP_ADD_MEMBERSHIP, mreq) - runtime.KeepAlive(fd) - return wrapSyscallError("setsockopt", err) -} - func setIPv6MulticastInterface(fd *netFD, ifi *Interface) error { var v int if ifi != nil { From 9b4a462a7d85753738723402e298039c3424e584 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 25 Dec 2024 16:01:58 -0800 Subject: [PATCH 250/397] cmd/cgo: use strings.Builder to build long strings Change-Id: I33ba7c8a7b731647cdff3ffe7c4274f76f8923ee Reviewed-on: https://go-review.googlesource.com/c/go/+/638736 Reviewed-by: Cherry Mui LUCI-TryBot-Result: Go LUCI Commit-Queue: Ian Lance Taylor Reviewed-by: Ian Lance Taylor Auto-Submit: Ian Lance Taylor Reviewed-by: Jorropo --- src/cmd/cgo/out.go | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index 36a0267713eea8..9e65dcbef7295c 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -942,7 +942,9 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) { // just have to agree. The gcc struct will be compiled // with __attribute__((packed)) so all padding must be // accounted for explicitly. - ctype := "struct {\n" + var ctype strings.Builder + const start = "struct {\n" + ctype.WriteString(start) gotype := new(bytes.Buffer) fmt.Fprintf(gotype, "struct {\n") off := int64(0) @@ -952,11 +954,11 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) { t := p.cgoType(typ) if off%t.Align != 0 { pad := t.Align - off%t.Align - ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad) + fmt.Fprintf(&ctype, "\t\tchar __pad%d[%d];\n", npad, pad) off += pad npad++ } - ctype += fmt.Sprintf("\t\t%s %s;\n", t.C, name) + fmt.Fprintf(&ctype, "\t\t%s %s;\n", t.C, name) fmt.Fprintf(gotype, "\t\t%s ", name) noSourceConf.Fprint(gotype, fset, typ) fmt.Fprintf(gotype, "\n") @@ -974,10 +976,10 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) { func(i int, aname string, atype ast.Expr) { argField(atype, "r%d", i) }) - if ctype == "struct {\n" { - ctype += "\t\tchar unused;\n" // avoid empty struct + if ctype.Len() == len(start) { + ctype.WriteString("\t\tchar unused;\n") // avoid empty struct } - ctype += "\t}" + ctype.WriteString("\t}") fmt.Fprintf(gotype, "\t}") // Get the return type of the wrapper function @@ -1007,19 +1009,20 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) { if goos == "windows" { gccExport = "__declspec(dllexport) " } - s := fmt.Sprintf("%s%s %s(", gccExport, gccResult, exp.ExpName) + var s strings.Builder + fmt.Fprintf(&s, "%s%s %s(", gccExport, gccResult, exp.ExpName) if fn.Recv != nil { - s += p.cgoType(fn.Recv.List[0].Type).C.String() - s += " recv" + s.WriteString(p.cgoType(fn.Recv.List[0].Type).C.String()) + s.WriteString(" recv") } forFieldList(fntype.Params, func(i int, aname string, atype ast.Expr) { if i > 0 || fn.Recv != nil { - s += ", " + s.WriteString(", ") } - s += fmt.Sprintf("%s %s", p.cgoType(atype).C, exportParamName(aname, i)) + fmt.Fprintf(&s, "%s %s", p.cgoType(atype).C, exportParamName(aname, i)) }) - s += ")" + s.WriteByte(')') if len(exp.Doc) > 0 { fmt.Fprintf(fgcch, "\n%s", exp.Doc) @@ -1027,11 +1030,11 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) { fmt.Fprint(fgcch, "\n") } } - fmt.Fprintf(fgcch, "extern %s;\n", s) + fmt.Fprintf(fgcch, "extern %s;\n", s.String()) fmt.Fprintf(fgcc, "extern void _cgoexp%s_%s(void *);\n", cPrefix, exp.ExpName) fmt.Fprintf(fgcc, "\nCGO_NO_SANITIZE_THREAD") - fmt.Fprintf(fgcc, "\n%s\n", s) + fmt.Fprintf(fgcc, "\n%s\n", s.String()) fmt.Fprintf(fgcc, "{\n") fmt.Fprintf(fgcc, "\tsize_t _cgo_ctxt = _cgo_wait_runtime_init_done();\n") // The results part of the argument structure must be @@ -1043,7 +1046,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) { // string.h for memset, and is also robust to C++ // types with constructors. Both GCC and LLVM optimize // this into just zeroing _cgo_a. - fmt.Fprintf(fgcc, "\ttypedef %s %v _cgo_argtype;\n", ctype, p.packedAttribute()) + fmt.Fprintf(fgcc, "\ttypedef %s %v _cgo_argtype;\n", ctype.String(), p.packedAttribute()) fmt.Fprintf(fgcc, "\tstatic _cgo_argtype _cgo_zero;\n") fmt.Fprintf(fgcc, "\t_cgo_argtype _cgo_a = _cgo_zero;\n") if gccResult != "void" && (len(fntype.Results.List) > 1 || len(fntype.Results.List[0].Names) > 1) { From 478ad013f90fe1dbb199d22f41b93c920ae0d5e9 Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Fri, 31 Jan 2025 15:03:15 -0800 Subject: [PATCH 251/397] runtime: don't duplicate reraised panic values in printpanics Change the output printed when crashing with a reraised panic value to not duplicate that value. Changes output of panicking with "PANIC", recovering, and reraising from: panic: PANIC [recovered] panic: PANIC to: panic: PANIC [recovered, reraised] Fixes #71517 Change-Id: Id59938c4ea0df555b851ffc650fe6f94c0845499 Reviewed-on: https://go-review.googlesource.com/c/go/+/645916 Reviewed-by: Michael Knyszek LUCI-TryBot-Result: Go LUCI --- doc/next/4-runtime.md | 17 +++++++++ src/runtime/crash_test.go | 31 +++++++++++++++ src/runtime/panic.go | 14 ++++++- src/runtime/runtime2.go | 1 + src/runtime/testdata/testprog/crash.go | 52 ++++++++++++++++++++++++++ 5 files changed, 114 insertions(+), 1 deletion(-) diff --git a/doc/next/4-runtime.md b/doc/next/4-runtime.md index 1f8e445e0b10de..28483eb519d342 100644 --- a/doc/next/4-runtime.md +++ b/doc/next/4-runtime.md @@ -1 +1,18 @@ ## Runtime {#runtime} + + + +The message printed when a program exits due to an unhandled panic +that was recovered and re-raised no longer repeats the text of +the panic value. + +Previously, a program which panicked with `panic("PANIC")`, +recovered the panic, and then re-panicked with the original +value would print: + + panic: PANIC [recovered] + panic: PANIC + +This program will now print: + + panic: PANIC [recovered, reraised] diff --git a/src/runtime/crash_test.go b/src/runtime/crash_test.go index 236c32ea34f7de..c390218355c57f 100644 --- a/src/runtime/crash_test.go +++ b/src/runtime/crash_test.go @@ -356,6 +356,37 @@ panic: third panic } +func TestReraisedPanic(t *testing.T) { + output := runTestProg(t, "testprog", "ReraisedPanic") + want := `panic: message [recovered, reraised] +` + if !strings.HasPrefix(output, want) { + t.Fatalf("output does not start with %q:\n%s", want, output) + } +} + +func TestReraisedMiddlePanic(t *testing.T) { + output := runTestProg(t, "testprog", "ReraisedMiddlePanic") + want := `panic: inner [recovered] + panic: middle [recovered, reraised] + panic: outer +` + if !strings.HasPrefix(output, want) { + t.Fatalf("output does not start with %q:\n%s", want, output) + } +} + +func TestReraisedPanicSandwich(t *testing.T) { + output := runTestProg(t, "testprog", "ReraisedPanicSandwich") + want := `panic: outer [recovered] + panic: inner [recovered] + panic: outer +` + if !strings.HasPrefix(output, want) { + t.Fatalf("output does not start with %q:\n%s", want, output) + } +} + func TestGoexitCrash(t *testing.T) { // External linking brings in cgo, causing deadlock detection not working. testenv.MustInternalLink(t, false) diff --git a/src/runtime/panic.go b/src/runtime/panic.go index 3ffb3966d026c8..2dd3c3c2dbfe0d 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -649,6 +649,13 @@ func preprintpanics(p *_panic) { } }() for p != nil { + if p.link != nil && *efaceOf(&p.link.arg) == *efaceOf(&p.arg) { + // This panic contains the same value as the next one in the chain. + // Mark it as reraised. We will skip printing it twice in a row. + p.link.reraised = true + p = p.link + continue + } switch v := p.arg.(type) { case error: p.arg = v.Error() @@ -664,6 +671,9 @@ func preprintpanics(p *_panic) { func printpanics(p *_panic) { if p.link != nil { printpanics(p.link) + if p.link.reraised { + return + } if !p.link.goexit { print("\t") } @@ -673,7 +683,9 @@ func printpanics(p *_panic) { } print("panic: ") printpanicval(p.arg) - if p.recovered { + if p.reraised { + print(" [recovered, reraised]") + } else if p.recovered { print(" [recovered]") } print("\n") diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go index e837c28af8715d..7280643f483566 100644 --- a/src/runtime/runtime2.go +++ b/src/runtime/runtime2.go @@ -1016,6 +1016,7 @@ type _panic struct { slotsPtr unsafe.Pointer recovered bool // whether this panic has been recovered + reraised bool // whether this panic was reraised goexit bool deferreturn bool } diff --git a/src/runtime/testdata/testprog/crash.go b/src/runtime/testdata/testprog/crash.go index bdc395f652edca..56dd701ffb373c 100644 --- a/src/runtime/testdata/testprog/crash.go +++ b/src/runtime/testdata/testprog/crash.go @@ -19,6 +19,9 @@ func init() { register("StringPanic", StringPanic) register("NilPanic", NilPanic) register("CircularPanic", CircularPanic) + register("ReraisedPanic", ReraisedPanic) + register("ReraisedMiddlePanic", ReraisedMiddlePanic) + register("ReraisedPanicSandwich", ReraisedPanicSandwich) } func test(name string) { @@ -137,3 +140,52 @@ func (e exampleCircleEndError) Error() string { func CircularPanic() { panic(exampleCircleStartError{}) } + +func ReraisedPanic() { + defer func() { + panic(recover()) + }() + panic("message") +} + +func ReraisedMiddlePanic() { + defer func() { + recover() + panic("outer") + }() + func() { + defer func() { + panic(recover()) + }() + func() { + defer func() { + recover() + panic("middle") + }() + panic("inner") + }() + }() +} + +// Panic sandwich: +// +// panic("outer") => +// recovered, panic("inner") => +// panic(recovered outer panic value) +// +// Exercises the edge case where we reraise a panic value, +// but with another panic in the middle. +func ReraisedPanicSandwich() { + var outer any + defer func() { + recover() + panic(outer) + }() + func() { + defer func() { + outer = recover() + panic("inner") + }() + panic("outer") + }() +} From 8163ea1458763aa38fa9197e479bd30cb0145429 Mon Sep 17 00:00:00 2001 From: thepudds Date: Thu, 6 Feb 2025 08:07:38 -0500 Subject: [PATCH 252/397] weak: prevent unsafe conversions using weak pointers Prevent conversions between Pointer types, like we do for sync/atomic.Pointer. Fixes #71583 Change-Id: I20e83106d8a27996f221e6cd9d52637b0442cea4 Reviewed-on: https://go-review.googlesource.com/c/go/+/647195 LUCI-TryBot-Result: Go LUCI Auto-Submit: Michael Knyszek Reviewed-by: Michael Knyszek Reviewed-by: Cherry Mui --- src/weak/pointer.go | 5 ++++- src/weak/pointer_test.go | 10 ++++++++++ test/weak.go | 24 ++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 test/weak.go diff --git a/src/weak/pointer.go b/src/weak/pointer.go index 39c512e76d6fe4..e9d7420880a7f9 100644 --- a/src/weak/pointer.go +++ b/src/weak/pointer.go @@ -56,6 +56,9 @@ import ( // referenced object. Typically, this batching only happens for tiny // (on the order of 16 bytes or less) and pointer-free objects. type Pointer[T any] struct { + // Mention T in the type definition to prevent conversions + // between Pointer types, like we do for sync/atomic.Pointer. + _ [0]*T u unsafe.Pointer } @@ -69,7 +72,7 @@ func Make[T any](ptr *T) Pointer[T] { u = runtime_registerWeakPointer(unsafe.Pointer(ptr)) } runtime.KeepAlive(ptr) - return Pointer[T]{u} + return Pointer[T]{u: u} } // Value returns the original pointer used to create the weak pointer. diff --git a/src/weak/pointer_test.go b/src/weak/pointer_test.go index e0ef30377e9e81..70c743381cacf8 100644 --- a/src/weak/pointer_test.go +++ b/src/weak/pointer_test.go @@ -6,10 +6,12 @@ package weak_test import ( "context" + "internal/goarch" "runtime" "sync" "testing" "time" + "unsafe" "weak" ) @@ -155,6 +157,14 @@ func TestPointerFinalizer(t *testing.T) { } } +func TestPointerSize(t *testing.T) { + var p weak.Pointer[T] + size := unsafe.Sizeof(p) + if size != goarch.PtrSize { + t.Errorf("weak.Pointer[T] size = %d, want %d", size, goarch.PtrSize) + } +} + // Regression test for issue 69210. // // Weak-to-strong conversions must shade the new strong pointer, otherwise diff --git a/test/weak.go b/test/weak.go new file mode 100644 index 00000000000000..ca3ec797fc2366 --- /dev/null +++ b/test/weak.go @@ -0,0 +1,24 @@ +// errorcheck + +// Copyright 2025 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. + +// Test weak pointers. + +package p + +import ( + "runtime" + "weak" +) + +// Adapted from example in https://github.com/golang/go/issues/67552#issuecomment-2639661220 +func conversion() { + p := "hello" + a := weak.Make(&p) + b := (weak.Pointer[*byte])(a) // ERROR "cannot convert a \(variable of struct type weak\.Pointer\[string\]\) to type weak.Pointer\[\*byte\]" + c := b.Value() + println(**c) + runtime.KeepAlive(p) +} From 372f2d802201583b0af2db2fa023d355812db2b1 Mon Sep 17 00:00:00 2001 From: Luka Krmpotic Date: Thu, 6 Feb 2025 21:33:18 +0000 Subject: [PATCH 253/397] unicode/utf8: remove init from utf8_test TestConstants and init test the same thing, remove init, it does not exist in utf16_test.go either. Fixes #71579 Change-Id: Ie0afd640bebde822733b6eac0bf98a17872f4e5f GitHub-Last-Rev: d7224c18376e00038261279abdfa954abc3a8303 GitHub-Pull-Request: golang/go#71582 Reviewed-on: https://go-review.googlesource.com/c/go/+/647335 Commit-Queue: Ian Lance Taylor Reviewed-by: Keith Randall Reviewed-by: Keith Randall Reviewed-by: qiu laidongfeng2 <2645477756@qq.com> Auto-Submit: Ian Lance Taylor Reviewed-by: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI --- src/unicode/utf8/utf8_test.go | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/unicode/utf8/utf8_test.go b/src/unicode/utf8/utf8_test.go index 69362d2cf1af6c..865167731f990b 100644 --- a/src/unicode/utf8/utf8_test.go +++ b/src/unicode/utf8/utf8_test.go @@ -12,16 +12,6 @@ import ( . "unicode/utf8" ) -// Validate the constants redefined from unicode. -func init() { - if MaxRune != unicode.MaxRune { - panic("utf8.MaxRune is wrong") - } - if RuneError != unicode.ReplacementChar { - panic("utf8.RuneError is wrong") - } -} - // Validate the constants redefined from unicode. func TestConstants(t *testing.T) { if MaxRune != unicode.MaxRune { From 88108cc563418ab962e41bdcc54a1d2010c2efcf Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 6 Feb 2025 15:01:17 -0800 Subject: [PATCH 254/397] cmd/go: adjust testsuite to add reraised panic message A couple of tests generate different output due to CL 645916 for issue #71517. Fixes #71593 Fixes #71594 Change-Id: Ifaeff4e9de8d881202bd9e6394c9b9cff8959596 Reviewed-on: https://go-review.googlesource.com/c/go/+/647495 LUCI-TryBot-Result: Go LUCI Commit-Queue: Ian Lance Taylor Reviewed-by: Ian Lance Taylor Auto-Submit: Ian Lance Taylor Reviewed-by: Damien Neil --- src/cmd/go/testdata/script/test_cleanup_failnow.txt | 6 +++--- src/cmd/go/testdata/script/test_fuzz_return.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cmd/go/testdata/script/test_cleanup_failnow.txt b/src/cmd/go/testdata/script/test_cleanup_failnow.txt index 0aba8c7c00f8b9..80182cd9e3fae9 100644 --- a/src/cmd/go/testdata/script/test_cleanup_failnow.txt +++ b/src/cmd/go/testdata/script/test_cleanup_failnow.txt @@ -14,8 +14,8 @@ env GOGC=off ! go test -v cleanup_failnow/panic_nocleanup_test.go ! stdout 'no tests to run' -stdout '(?s)panic: die \[recovered\].*panic: die' -! stdout '(?s)panic: die \[recovered\].*panic: die.*panic: die' +stdout '(?s)panic: die \[recovered, reraised\]' +! stdout '(?s)panic: die \[recovered, reraised\].*panic: die' ! go test -v cleanup_failnow/panic_withcleanup_test.go ! stdout 'no tests to run' @@ -43,4 +43,4 @@ func TestCleanupWithFailNow(t *testing.T) { panic("die") }) }) -} \ No newline at end of file +} diff --git a/src/cmd/go/testdata/script/test_fuzz_return.txt b/src/cmd/go/testdata/script/test_fuzz_return.txt index 2f7b85bcc011b0..d86783e9cb9bb1 100644 --- a/src/cmd/go/testdata/script/test_fuzz_return.txt +++ b/src/cmd/go/testdata/script/test_fuzz_return.txt @@ -3,7 +3,7 @@ # Disable vet, as its "tests" analyzer would report the same problem statically. ! go test -vet=off . -stdout '^panic: testing: fuzz target must not return a value \[recovered\]$' +stdout '^panic: testing: fuzz target must not return a value \[recovered, reraised\]$' -- go.mod -- module test From 5c9b13d90f4c751c61ccb4560f79a1189cab2279 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 7 Jan 2025 10:47:01 -0800 Subject: [PATCH 255/397] crypto/internal/fips140/drbg: add package comment For #69536 Change-Id: I70d2ed10555fed244f08c898899399e3032e17b7 Reviewed-on: https://go-review.googlesource.com/c/go/+/640597 Reviewed-by: Robert Griesemer Reviewed-by: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Auto-Submit: Ian Lance Taylor Commit-Queue: Ian Lance Taylor Auto-Submit: Ian Lance Taylor --- src/crypto/internal/fips140/drbg/rand.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/crypto/internal/fips140/drbg/rand.go b/src/crypto/internal/fips140/drbg/rand.go index e7ab19a4cfe0a6..c1a3ea0ae658ff 100644 --- a/src/crypto/internal/fips140/drbg/rand.go +++ b/src/crypto/internal/fips140/drbg/rand.go @@ -2,6 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// Package drbg provides cryptographically secure random bytes +// usable by FIPS code. In FIPS mode it uses an SP 800-90A Rev. 1 +// Deterministic Random Bit Generator (DRBG). Otherwise, +// it uses the operating system's random number generator. package drbg import ( From 7c6b047ea14dcc6aa948f901956511c4e8691abf Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 9 Jan 2025 14:42:16 -0800 Subject: [PATCH 256/397] encoding/base64: use internal/byteorder This permits us to remove the dependency on reflect. Change-Id: I60b1e9fd713f340bfd5eec2edfa58fc724a8e2d8 Reviewed-on: https://go-review.googlesource.com/c/go/+/641936 Reviewed-by: Ian Lance Taylor Reviewed-by: Robert Griesemer Auto-Submit: Ian Lance Taylor TryBot-Bypass: Ian Lance Taylor Auto-Submit: Ian Lance Taylor --- src/encoding/base64/base64.go | 6 +++--- src/go/build/deps_test.go | 11 ++++++----- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/encoding/base64/base64.go b/src/encoding/base64/base64.go index f94bea132cbde3..57aa1a697fc7bd 100644 --- a/src/encoding/base64/base64.go +++ b/src/encoding/base64/base64.go @@ -6,7 +6,7 @@ package base64 import ( - "encoding/binary" + "internal/byteorder" "io" "slices" "strconv" @@ -538,7 +538,7 @@ func (enc *Encoding) Decode(dst, src []byte) (n int, err error) { enc.decodeMap[src2[6]], enc.decodeMap[src2[7]], ); ok { - binary.BigEndian.PutUint64(dst[n:], dn) + byteorder.BEPutUint64(dst[n:], dn) n += 6 si += 8 } else { @@ -559,7 +559,7 @@ func (enc *Encoding) Decode(dst, src []byte) (n int, err error) { enc.decodeMap[src2[2]], enc.decodeMap[src2[3]], ); ok { - binary.BigEndian.PutUint32(dst[n:], dn) + byteorder.BEPutUint32(dst[n:], dn) n += 3 si += 4 } else { diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index e96578f8d38462..31ec9512c13e16 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -244,17 +244,17 @@ var depsRules = ` # encodings # core ones do not use fmt. io, strconv, slices - < encoding; + < encoding, encoding/base32, encoding/base64; encoding, reflect - < encoding/binary - < encoding/base32, encoding/base64; + < encoding/binary; FMT, encoding < flag; fmt !< encoding/base32, encoding/base64; - FMT, encoding/base32, encoding/base64, internal/saferio + FMT, encoding, encoding/base32, encoding/base64, encoding/binary, + internal/saferio < encoding/ascii85, encoding/csv, encoding/gob, encoding/hex, encoding/json, encoding/pem, encoding/xml, mime; @@ -662,7 +662,8 @@ var depsRules = ` log/slog, testing < testing/slogtest; - FMT, crypto/sha256, encoding/json, go/ast, go/parser, go/token, + FMT, crypto/sha256, encoding/binary, encoding/json, + go/ast, go/parser, go/token, internal/godebug, math/rand, encoding/hex < internal/fuzz; From 290ec2d92bca6472fdabce51fc331b3bcaa7129d Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sun, 26 Jan 2025 21:52:58 -0800 Subject: [PATCH 257/397] bufio: don't do empty Write at start of WriteTo The empty Write will cause the wrong thing to happen when using io.Copy to copy to a package-based stream. Fixes #71424 Change-Id: I046a27539447182692ac76a8bdd422327345dd8d Reviewed-on: https://go-review.googlesource.com/c/go/+/644535 Reviewed-by: Keith Randall Reviewed-by: Michael Knyszek LUCI-TryBot-Result: Go LUCI Reviewed-by: Keith Randall Auto-Submit: Ian Lance Taylor Reviewed-by: Mauri de Souza Meneguzzo Reviewed-by: Damien Neil --- src/bufio/bufio.go | 8 ++-- src/bufio/bufio_test.go | 2 +- src/bufio/net_test.go | 96 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 102 insertions(+), 4 deletions(-) create mode 100644 src/bufio/net_test.go diff --git a/src/bufio/bufio.go b/src/bufio/bufio.go index d589701e19a85c..5244ce2e0ca943 100644 --- a/src/bufio/bufio.go +++ b/src/bufio/bufio.go @@ -519,9 +519,11 @@ func (b *Reader) WriteTo(w io.Writer) (n int64, err error) { b.lastByte = -1 b.lastRuneSize = -1 - n, err = b.writeBuf(w) - if err != nil { - return + if b.r < b.w { + n, err = b.writeBuf(w) + if err != nil { + return + } } if r, ok := b.rd.(io.WriterTo); ok { diff --git a/src/bufio/bufio_test.go b/src/bufio/bufio_test.go index 63dd2ea4322cea..742e1954256903 100644 --- a/src/bufio/bufio_test.go +++ b/src/bufio/bufio_test.go @@ -1149,7 +1149,7 @@ func (w errorWriterToTest) Write(p []byte) (int, error) { var errorWriterToTests = []errorWriterToTest{ {1, 0, nil, io.ErrClosedPipe, io.ErrClosedPipe}, {0, 1, io.ErrClosedPipe, nil, io.ErrClosedPipe}, - {0, 0, io.ErrUnexpectedEOF, io.ErrClosedPipe, io.ErrClosedPipe}, + {0, 0, io.ErrUnexpectedEOF, io.ErrClosedPipe, io.ErrUnexpectedEOF}, {0, 1, io.EOF, nil, nil}, } diff --git a/src/bufio/net_test.go b/src/bufio/net_test.go new file mode 100644 index 00000000000000..9c609fbccaeedb --- /dev/null +++ b/src/bufio/net_test.go @@ -0,0 +1,96 @@ +// Copyright 2025 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. + +//go:build unix + +package bufio_test + +import ( + "bufio" + "io" + "net" + "path/filepath" + "strings" + "sync" + "testing" +) + +// TestCopyUnixpacket tests that we can use bufio when copying +// across a unixpacket socket. This used to fail due to an unnecessary +// empty Write call that was interpreted as an EOF. +func TestCopyUnixpacket(t *testing.T) { + tmpDir := t.TempDir() + socket := filepath.Join(tmpDir, "unixsock") + + // Start a unixpacket server. + addr := &net.UnixAddr{ + Name: socket, + Net: "unixpacket", + } + server, err := net.ListenUnix("unixpacket", addr) + if err != nil { + t.Fatal(err) + } + + // Start a goroutine for the server to accept one connection + // and read all the data sent on the connection, + // reporting the number of bytes read on ch. + ch := make(chan int, 1) + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + + tot := 0 + defer func() { + ch <- tot + }() + + serverConn, err := server.Accept() + if err != nil { + t.Error(err) + return + } + + buf := make([]byte, 1024) + for { + n, err := serverConn.Read(buf) + tot += n + if err == io.EOF { + return + } + if err != nil { + t.Error(err) + return + } + } + }() + + clientConn, err := net.DialUnix("unixpacket", nil, addr) + if err != nil { + // Leaves the server goroutine hanging. Oh well. + t.Fatal(err) + } + + defer wg.Wait() + defer clientConn.Close() + + const data = "data" + r := bufio.NewReader(strings.NewReader(data)) + n, err := io.Copy(clientConn, r) + if err != nil { + t.Fatal(err) + } + + if n != int64(len(data)) { + t.Errorf("io.Copy returned %d, want %d", n, len(data)) + } + + clientConn.Close() + tot := <-ch + + if tot != len(data) { + t.Errorf("server read %d, want %d", tot, len(data)) + } +} From 637c235b510a885622cdbb914ad9e0d4bbce9a14 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 27 Jan 2025 10:21:57 -0800 Subject: [PATCH 258/397] lib/time: build with Ubuntu backward compatibility options Change-Id: I7e241eb602e45eea3c730793c14d8a5f666f9181 Reviewed-on: https://go-review.googlesource.com/c/go/+/644077 LUCI-TryBot-Result: Go LUCI Reviewed-by: Michael Knyszek Reviewed-by: Damien Neil Auto-Submit: Ian Lance Taylor --- lib/time/update.bash | 7 ++++++- lib/time/zoneinfo.zip | Bin 406409 -> 405501 bytes 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/time/update.bash b/lib/time/update.bash index 67cb016e79392f..940596fb11221f 100755 --- a/lib/time/update.bash +++ b/lib/time/update.bash @@ -40,7 +40,12 @@ curl -sS -L -O https://www.iana.org/time-zones/repository/releases/tzdata$DATA.t tar xzf tzcode$CODE.tar.gz tar xzf tzdata$DATA.tar.gz -if ! make CFLAGS=-DSTD_INSPIRED AWK=awk TZDIR=zoneinfo posix_only >make.out 2>&1; then +# The PACKRATLIST and PACKRATDATA options are copied from Ubuntu: +# https://git.launchpad.net/ubuntu/+source/tzdata/tree/debian/rules?h=debian/sid +# +# You can see the description of these make variables in the tzdata Makefile: +# https://github.com/eggert/tz/blob/main/Makefile +if ! make CFLAGS=-DSTD_INSPIRED AWK=awk TZDIR=zoneinfo PACKRATDATA=backzone PACKRATLIST=zone.tab posix_only >make.out 2>&1; then cat make.out exit 2 fi diff --git a/lib/time/zoneinfo.zip b/lib/time/zoneinfo.zip index 6ba9ff6fd6afc9736c41c5ec2c3bfd1aa12a0f1b..f8099b1b494fc920c1bc181cf783431e6105f36a 100644 GIT binary patch delta 15932 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 delta 8853 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 Q$6Y_kUXnJ@Pf14q1Ef_X-T(jq From caf29da4ccf0ca64b422835dfa48fa6e06f87f24 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sun, 22 Dec 2024 21:00:58 -0800 Subject: [PATCH 259/397] os: don't store reference count in Process.state We only need a reference count in processHandle. For #70907 Fixes #71564 Change-Id: I209ded869203dea10f12b070190774fb5f1d3d71 Reviewed-on: https://go-review.googlesource.com/c/go/+/638577 Commit-Queue: Ian Lance Taylor Reviewed-by: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Reviewed-by: Michael Knyszek Auto-Submit: Ian Lance Taylor --- src/os/exec.go | 94 ++++++++++++-------------------------------------- 1 file changed, 22 insertions(+), 72 deletions(-) diff --git a/src/os/exec.go b/src/os/exec.go index a531cdab080114..f3cede299673aa 100644 --- a/src/os/exec.go +++ b/src/os/exec.go @@ -38,31 +38,10 @@ const ( type Process struct { Pid int - // State contains the atomic process state. + // state contains the atomic process state. // - // If handle is nil, this consists only of the processStatus fields, + // This consists of the processStatus fields, // which indicate if the process is done/released. - // - // In handle is not nil, the lower bits also contain a reference - // count for the handle field. - // - // The Process itself initially holds 1 persistent reference. Any - // operation that uses the handle with a system call temporarily holds - // an additional transient reference. This prevents the handle from - // being closed prematurely, which could result in the OS allocating a - // different handle with the same value, leading to Process' methods - // operating on the wrong process. - // - // Release and Wait both drop the Process' persistent reference, but - // other concurrent references may delay actually closing the handle - // because they hold a transient reference. - // - // Regardless, we want new method calls to immediately treat the handle - // as unavailable after Release or Wait to avoid extending this delay. - // This is achieved by setting either processStatus flag when the - // Process' persistent reference is dropped. The only difference in the - // flags is the reason the handle is unavailable, which affects the - // errors returned by concurrent calls. state atomic.Uint64 // Used only when handle is nil @@ -151,7 +130,6 @@ func newHandleProcess(pid int, handle uintptr) *Process { Pid: pid, handle: ph, } - p.state.Store(1) // 1 persistent reference runtime.SetFinalizer(p, (*Process).Release) return p } @@ -170,53 +148,31 @@ func (p *Process) handleTransientAcquire() (uintptr, processStatus) { panic("handleTransientAcquire called in invalid mode") } - for { - refs := p.state.Load() - if refs&processStatusMask != 0 { - return 0, processStatus(refs & processStatusMask) - } - new := refs + 1 - if !p.state.CompareAndSwap(refs, new) { - continue - } - h, ok := p.handle.acquire() - if !ok { - panic("inconsistent reference counts") - } + state := p.state.Load() + if state&processStatusMask != 0 { + return 0, processStatus(state & processStatusMask) + } + h, ok := p.handle.acquire() + if ok { return h, statusOK } + + // This case means that the handle has been closed. + // We always set the status to non-zero before closing the handle. + // If we get here the status must have been set non-zero after + // we just checked it above. + state = p.state.Load() + if state&processStatusMask == 0 { + panic("inconsistent process status") + } + return 0, processStatus(state & processStatusMask) } func (p *Process) handleTransientRelease() { if p.handle == nil { panic("handleTransientRelease called in invalid mode") } - - for { - state := p.state.Load() - refs := state &^ processStatusMask - status := processStatus(state & processStatusMask) - if refs == 0 { - // This should never happen because - // handleTransientRelease is always paired with - // handleTransientAcquire. - panic("release of handle with refcount 0") - } - if refs == 1 && status == statusOK { - // Process holds a persistent reference and always sets - // a status when releasing that reference - // (handlePersistentRelease). Thus something has gone - // wrong if this is the last release but a status has - // not always been set. - panic("final release of handle without processStatus") - } - new := state - 1 - if !p.state.CompareAndSwap(state, new) { - continue - } - p.handle.release() - return - } + p.handle.release() } // Drop the Process' persistent reference on the handle, deactivating future @@ -230,8 +186,8 @@ func (p *Process) handlePersistentRelease(reason processStatus) processStatus { } for { - refs := p.state.Load() - status := processStatus(refs & processStatusMask) + state := p.state.Load() + status := processStatus(state & processStatusMask) if status != statusOK { // Both Release and successful Wait will drop the // Process' persistent reference on the handle. We @@ -240,13 +196,7 @@ func (p *Process) handlePersistentRelease(reason processStatus) processStatus { // reference is dropped exactly once. return status } - if refs == 0 { - // This should never happen because dropping the - // persistent reference always sets a status. - panic("release of handle with refcount 0") - } - new := (refs - 1) | uint64(reason) - if !p.state.CompareAndSwap(refs, new) { + if !p.state.CompareAndSwap(state, uint64(reason)) { continue } p.handle.release() From e7c9667defe1aed61818d63ace6ebb7a27b9c13e Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sun, 22 Dec 2024 21:15:30 -0800 Subject: [PATCH 260/397] os: simplify process status Since it no longer holds a reference count, just use values. For #70907 Change-Id: I19a42583988d4f8a9133b1c837356ca0179d688c Reviewed-on: https://go-review.googlesource.com/c/go/+/638578 LUCI-TryBot-Result: Go LUCI Auto-Submit: Ian Lance Taylor Reviewed-by: Cherry Mui Reviewed-by: Michael Knyszek Reviewed-by: Robert Griesemer --- src/os/exec.go | 34 ++++++++++++++++------------------ src/os/export_linux_test.go | 2 +- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/src/os/exec.go b/src/os/exec.go index f3cede299673aa..3f83139da5b2ff 100644 --- a/src/os/exec.go +++ b/src/os/exec.go @@ -17,21 +17,19 @@ import ( // ErrProcessDone indicates a [Process] has finished. var ErrProcessDone = errors.New("os: process already finished") -type processStatus uint64 +type processStatus uint32 const ( - // PID/handle OK to use. - statusOK processStatus = 0 + // statusOK means that the Process is ready to use. + statusOK processStatus = iota // statusDone indicates that the PID/handle should not be used because // the process is done (has been successfully Wait'd on). - statusDone processStatus = 1 << 62 + statusDone // statusReleased indicates that the PID/handle should not be used // because the process is released. - statusReleased processStatus = 1 << 63 - - processStatusMask = 0x3 << 62 + statusReleased ) // Process stores the information about a process created by [StartProcess]. @@ -42,7 +40,7 @@ type Process struct { // // This consists of the processStatus fields, // which indicate if the process is done/released. - state atomic.Uint64 + state atomic.Uint32 // Used only when handle is nil sigMu sync.RWMutex // avoid race between wait and signal @@ -138,7 +136,7 @@ func newDoneProcess(pid int) *Process { p := &Process{ Pid: pid, } - p.state.Store(uint64(statusDone)) // No persistent reference, as there is no handle. + p.state.Store(uint32(statusDone)) // No persistent reference, as there is no handle. runtime.SetFinalizer(p, (*Process).Release) return p } @@ -148,9 +146,9 @@ func (p *Process) handleTransientAcquire() (uintptr, processStatus) { panic("handleTransientAcquire called in invalid mode") } - state := p.state.Load() - if state&processStatusMask != 0 { - return 0, processStatus(state & processStatusMask) + status := processStatus(p.state.Load()) + if status != statusOK { + return 0, status } h, ok := p.handle.acquire() if ok { @@ -161,11 +159,11 @@ func (p *Process) handleTransientAcquire() (uintptr, processStatus) { // We always set the status to non-zero before closing the handle. // If we get here the status must have been set non-zero after // we just checked it above. - state = p.state.Load() - if state&processStatusMask == 0 { + status = processStatus(p.state.Load()) + if status == statusOK { panic("inconsistent process status") } - return 0, processStatus(state & processStatusMask) + return 0, status } func (p *Process) handleTransientRelease() { @@ -187,7 +185,7 @@ func (p *Process) handlePersistentRelease(reason processStatus) processStatus { for { state := p.state.Load() - status := processStatus(state & processStatusMask) + status := processStatus(state) if status != statusOK { // Both Release and successful Wait will drop the // Process' persistent reference on the handle. We @@ -196,7 +194,7 @@ func (p *Process) handlePersistentRelease(reason processStatus) processStatus { // reference is dropped exactly once. return status } - if !p.state.CompareAndSwap(state, uint64(reason)) { + if !p.state.CompareAndSwap(state, uint32(reason)) { continue } p.handle.release() @@ -225,7 +223,7 @@ func (p *Process) pidDeactivate(reason processStatus) { // racing Release and Wait, Wait may successfully wait on the process, // returning the wait status, while future calls error with "process // released" rather than "process done". - p.state.CompareAndSwap(0, uint64(reason)) + p.state.CompareAndSwap(0, uint32(reason)) } // ProcAttr holds the attributes that will be applied to a new process diff --git a/src/os/export_linux_test.go b/src/os/export_linux_test.go index 12434cb42671ef..4ace32bb5b2c0b 100644 --- a/src/os/export_linux_test.go +++ b/src/os/export_linux_test.go @@ -14,5 +14,5 @@ var ( const StatusDone = statusDone func (p *Process) Status() processStatus { - return processStatus(p.state.Load() & processStatusMask) + return processStatus(p.state.Load()) } From 76c18e2ed2e62f34a9afed5e6fa681837cc16b77 Mon Sep 17 00:00:00 2001 From: qmuntal Date: Tue, 4 Feb 2025 11:16:40 +0100 Subject: [PATCH 261/397] cmd/link: add -e (no limit on errors) flag The compiler and assembler have a -e flag that disables the limit on the number of errors before the build fails. This flag is useful for debugging, the linker should have it too. Change-Id: I892cfd6ee1519e9e86261af7d05e1af2ded21684 Reviewed-on: https://go-review.googlesource.com/c/go/+/646435 Reviewed-by: Cherry Mui Reviewed-by: Carlos Amedee LUCI-TryBot-Result: Go LUCI --- src/cmd/link/doc.go | 2 ++ src/cmd/link/internal/ld/main.go | 1 + src/cmd/link/internal/ld/util.go | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/cmd/link/doc.go b/src/cmd/link/doc.go index 7b548f960fd86d..840f4b04edd1f4 100644 --- a/src/cmd/link/doc.go +++ b/src/cmd/link/doc.go @@ -72,6 +72,8 @@ Flags: system tools now assume the presence of the header. -dumpdep Dump symbol dependency graph. + -e + No limit on number of errors reported. -extar ar Set the external archive program (default "ar"). Used only for -buildmode=c-archive. diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go index 7614b6d194facf..377dcd6c856fa6 100644 --- a/src/cmd/link/internal/ld/main.go +++ b/src/cmd/link/internal/ld/main.go @@ -108,6 +108,7 @@ var ( flagEntrySymbol = flag.String("E", "", "set `entry` symbol name") flagPruneWeakMap = flag.Bool("pruneweakmap", true, "prune weak mapinit refs") flagRandLayout = flag.Int64("randlayout", 0, "randomize function layout") + flagAllErrors = flag.Bool("e", false, "no limit on number of errors reported") cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`") memprofile = flag.String("memprofile", "", "write memory profile to `file`") memprofilerate = flag.Int64("memprofilerate", 0, "set runtime.MemProfileRate to `rate`") diff --git a/src/cmd/link/internal/ld/util.go b/src/cmd/link/internal/ld/util.go index 948bfa020e83f2..556c77d7326258 100644 --- a/src/cmd/link/internal/ld/util.go +++ b/src/cmd/link/internal/ld/util.go @@ -48,7 +48,7 @@ func afterErrorAction() { if *flagH { panic("error") } - if nerrors > 20 { + if nerrors > 20 && !*flagAllErrors { Exitf("too many errors") } } From 85b5d11246a2c768646f49f3c6750a139ecd1b21 Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Fri, 3 Jan 2025 19:06:07 +1100 Subject: [PATCH 262/397] crypto/subtle: add additional benchmarks for XORBytes Provide alignment benchmarks for XORBytes, as well as including 8192 byte blocks in the existing benchmarks. This allows us to better evaluate performance with unaligned inputs. Change-Id: Iad497c594c0425389ae02ca848aede5cb0ac3afd Reviewed-on: https://go-review.googlesource.com/c/go/+/639316 Reviewed-by: Cherry Mui LUCI-TryBot-Result: Go LUCI Reviewed-by: Filippo Valsorda Reviewed-by: Roland Shoemaker --- src/crypto/subtle/xor_test.go | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/crypto/subtle/xor_test.go b/src/crypto/subtle/xor_test.go index 2e2169db0aac62..855e54d82bb26f 100644 --- a/src/crypto/subtle/xor_test.go +++ b/src/crypto/subtle/xor_test.go @@ -92,7 +92,7 @@ func BenchmarkXORBytes(b *testing.B) { dst := make([]byte, 1<<15) data0 := make([]byte, 1<<15) data1 := make([]byte, 1<<15) - sizes := []int64{1 << 3, 1 << 7, 1 << 11, 1 << 15} + sizes := []int64{1 << 3, 1 << 7, 1 << 11, 1 << 13, 1 << 15} for _, size := range sizes { b.Run(fmt.Sprintf("%dBytes", size), func(b *testing.B) { s0 := data0[:size] @@ -105,6 +105,26 @@ func BenchmarkXORBytes(b *testing.B) { } } +func BenchmarkXORBytesAlignment(b *testing.B) { + dst := make([]byte, 8+1<<11) + data0 := make([]byte, 8+1<<11) + data1 := make([]byte, 8+1<<11) + sizes := []int64{1 << 3, 1 << 7, 1 << 11} + for _, size := range sizes { + for offset := int64(0); offset < 8; offset++ { + b.Run(fmt.Sprintf("%dBytes%dOffset", size, offset), func(b *testing.B) { + d := dst[offset : offset+size] + s0 := data0[offset : offset+size] + s1 := data1[offset : offset+size] + b.SetBytes(int64(size)) + for i := 0; i < b.N; i++ { + XORBytes(d, s0, s1) + } + }) + } + } +} + func mustPanic(t *testing.T, expected string, f func()) { t.Helper() defer func() { From b8fb95becda267e8369a3a2bfd30037c91504fba Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Fri, 3 Jan 2025 19:06:13 +1100 Subject: [PATCH 263/397] crypto/internal/fips140/subtle: combine xor_.go files There is not much point in having per architecture files that all contain the same content. Instead, merge the various xor_.go files into a single xor_asm.go file that has appropriate build tags. Change-Id: I555d44b2fd83f260a4855d83cacb9e101d689bc0 Reviewed-on: https://go-review.googlesource.com/c/go/+/639856 Reviewed-by: Roland Shoemaker Reviewed-by: Cherry Mui LUCI-TryBot-Result: Go LUCI Reviewed-by: Filippo Valsorda --- src/crypto/internal/fips140/subtle/xor_arm64.go | 10 ---------- .../fips140/subtle/{xor_amd64.go => xor_asm.go} | 2 +- src/crypto/internal/fips140/subtle/xor_loong64.go | 10 ---------- src/crypto/internal/fips140/subtle/xor_ppc64x.go | 10 ---------- 4 files changed, 1 insertion(+), 31 deletions(-) delete mode 100644 src/crypto/internal/fips140/subtle/xor_arm64.go rename src/crypto/internal/fips140/subtle/{xor_amd64.go => xor_asm.go} (76%) delete mode 100644 src/crypto/internal/fips140/subtle/xor_loong64.go delete mode 100644 src/crypto/internal/fips140/subtle/xor_ppc64x.go diff --git a/src/crypto/internal/fips140/subtle/xor_arm64.go b/src/crypto/internal/fips140/subtle/xor_arm64.go deleted file mode 100644 index 65bab4c6574cde..00000000000000 --- a/src/crypto/internal/fips140/subtle/xor_arm64.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2020 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. - -//go:build !purego - -package subtle - -//go:noescape -func xorBytes(dst, a, b *byte, n int) diff --git a/src/crypto/internal/fips140/subtle/xor_amd64.go b/src/crypto/internal/fips140/subtle/xor_asm.go similarity index 76% rename from src/crypto/internal/fips140/subtle/xor_amd64.go rename to src/crypto/internal/fips140/subtle/xor_asm.go index 3bb2f08b7c909e..16343db6588cb7 100644 --- a/src/crypto/internal/fips140/subtle/xor_amd64.go +++ b/src/crypto/internal/fips140/subtle/xor_asm.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build !purego +//go:build (amd64 || arm64 || loong64 || ppc64 || ppc64le) && !purego package subtle diff --git a/src/crypto/internal/fips140/subtle/xor_loong64.go b/src/crypto/internal/fips140/subtle/xor_loong64.go deleted file mode 100644 index e49f0fc9e3fa02..00000000000000 --- a/src/crypto/internal/fips140/subtle/xor_loong64.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2024 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. - -//go:build !purego - -package subtle - -//go:noescape -func xorBytes(dst, a, b *byte, n int) diff --git a/src/crypto/internal/fips140/subtle/xor_ppc64x.go b/src/crypto/internal/fips140/subtle/xor_ppc64x.go deleted file mode 100644 index 760463c7e5014c..00000000000000 --- a/src/crypto/internal/fips140/subtle/xor_ppc64x.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2018 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. - -//go:build (ppc64 || ppc64le) && !purego - -package subtle - -//go:noescape -func xorBytes(dst, a, b *byte, n int) From 7a2f757c521d9af201c6d3463a0e203c4104d5aa Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Sun, 24 Nov 2024 14:38:33 +1100 Subject: [PATCH 264/397] cmd/internal/obj/riscv: update references to RISC-V specification Update references to version 20240411 of the RISC-V specifications. Reorder and regroup instructions to maintain ordering. Also be consistent with formatting. The instruction encodings table was seemingly missed in CL 616115. Change-Id: I47b7c8538383ff3b0503ba59db570c3d4f0d5653 Reviewed-on: https://go-review.googlesource.com/c/go/+/631935 Reviewed-by: Cherry Mui LUCI-TryBot-Result: Go LUCI Reviewed-by: Ian Lance Taylor Reviewed-by: Meng Zhuo Reviewed-by: Pengcheng Wang --- src/cmd/asm/internal/asm/testdata/riscv64.s | 4 + src/cmd/internal/obj/riscv/cpu.go | 118 ++++++++++---------- src/cmd/internal/obj/riscv/obj.go | 54 ++++----- 3 files changed, 94 insertions(+), 82 deletions(-) diff --git a/src/cmd/asm/internal/asm/testdata/riscv64.s b/src/cmd/asm/internal/asm/testdata/riscv64.s index 37c0c1d858f34c..9ab4e066bee481 100644 --- a/src/cmd/asm/internal/asm/testdata/riscv64.s +++ b/src/cmd/asm/internal/asm/testdata/riscv64.s @@ -363,6 +363,10 @@ start: SLLIUW $63, X17, X18 // 1b99f80b SLLIUW $1, X18, X19 // 9b191908 + // + // "B" Extension for Bit Manipulation, Version 1.0.0 + // + // 28.4.2: Basic Bit Manipulation (Zbb) ANDN X19, X20, X21 // b37a3a41 or 93caf9ffb37a5a01 ANDN X19, X20 // 337a3a41 or 93cff9ff337afa01 diff --git a/src/cmd/internal/obj/riscv/cpu.go b/src/cmd/internal/obj/riscv/cpu.go index 1501a5027ec99b..69a85166968648 100644 --- a/src/cmd/internal/obj/riscv/cpu.go +++ b/src/cmd/internal/obj/riscv/cpu.go @@ -571,6 +571,10 @@ const ( // 22.5 Quad-Precision Floating-Point Classify Instruction AFCLASSQ + // + // "B" Extension for Bit Manipulation, Version 1.0.0 + // + // 28.4.1: Address Generation Instructions (Zba) AADDUW ASH1ADD @@ -620,15 +624,15 @@ const ( ABSETI // - // RISC-V Vector ISA-extension (1.0) (Unprivileged 20240411) + // "V" Standard Extension for Vector Operations, Version 1.0 // - // 31.6. Configuration-Setting Instructions + // 31.6: Configuration-Setting Instructions AVSETVLI AVSETIVLI AVSETVL - // 31.7.4. Vector Unit-Stride Instructions + // 31.7.4: Vector Unit-Stride Instructions AVLE8V AVLE16V AVLE32V @@ -640,7 +644,7 @@ const ( AVLMV AVSMV - // 31.7.5. Vector Strided Instructions + // 31.7.5: Vector Strided Instructions AVLSE8V AVLSE16V AVLSE32V @@ -650,7 +654,7 @@ const ( AVSSE32V AVSSE64V - // 31.7.6. Vector Indexed Instructions + // 31.7.6: Vector Indexed Instructions AVLUXEI8V AVLUXEI16V AVLUXEI32V @@ -668,13 +672,13 @@ const ( AVSOXEI32V AVSOXEI64V - // 31.7.7. Unit-stride Fault-Only-First Loads + // 31.7.7: Unit-stride Fault-Only-First Loads AVLE8FFV AVLE16FFV AVLE32FFV AVLE64FFV - // 31.7.9. Vector Load/Store Whole Register Instructions + // 31.7.9: Vector Load/Store Whole Register Instructions AVL1RE8V AVL1RE16V AVL1RE32V @@ -696,7 +700,7 @@ const ( AVS4RV AVS8RV - // 31.11.1. Vector Single-Width Integer Add and Subtract + // 31.11.1: Vector Single-Width Integer Add and Subtract AVADDVV AVADDVX AVADDVI @@ -705,7 +709,7 @@ const ( AVRSUBVX AVRSUBVI - // 31.11.2. Vector Widening Integer Add/Subtract + // 31.11.2: Vector Widening Integer Add/Subtract AVWADDUVV AVWADDUVX AVWSUBUVV @@ -723,7 +727,7 @@ const ( AVWSUBWV AVWSUBWX - // 31.11.3. Vector Integer Extension + // 31.11.3: Vector Integer Extension AVZEXTVF2 AVSEXTVF2 AVZEXTVF4 @@ -731,7 +735,7 @@ const ( AVZEXTVF8 AVSEXTVF8 - // 31.11.4. Vector Integer Add-with-Carry / Subtract-with-Borrow Instructions + // 31.11.4: Vector Integer Add-with-Carry / Subtract-with-Borrow Instructions AVADCVVM AVADCVXM AVADCVIM @@ -748,7 +752,7 @@ const ( AVMSBCVV AVMSBCVX - // 31.11.5. Vector Bitwise Logical Instructions + // 31.11.5: Vector Bitwise Logical Instructions AVANDVV AVANDVX AVANDVI @@ -759,7 +763,7 @@ const ( AVXORVX AVXORVI - // 31.11.6. Vector Single-Width Shift Instructions + // 31.11.6: Vector Single-Width Shift Instructions AVSLLVV AVSLLVX AVSLLVI @@ -770,7 +774,7 @@ const ( AVSRAVX AVSRAVI - // 31.11.7. Vector Narrowing Integer Right Shift Instructions + // 31.11.7: Vector Narrowing Integer Right Shift Instructions AVNSRLWV AVNSRLWX AVNSRLWI @@ -778,7 +782,7 @@ const ( AVNSRAWX AVNSRAWI - // 31.11.8. Vector Integer Compare Instructions + // 31.11.8: Vector Integer Compare Instructions AVMSEQVV AVMSEQVX AVMSEQVI @@ -800,7 +804,7 @@ const ( AVMSGTVX AVMSGTVI - // 31.11.9. Vector Integer Min/Max Instructions + // 31.11.9: Vector Integer Min/Max Instructions AVMINUVV AVMINUVX AVMINVV @@ -810,7 +814,7 @@ const ( AVMAXVV AVMAXVX - // 31.11.10. Vector Single-Width Integer Multiply Instructions + // 31.11.10: Vector Single-Width Integer Multiply Instructions AVMULVV AVMULVX AVMULHVV @@ -820,7 +824,7 @@ const ( AVMULHSUVV AVMULHSUVX - // 31.11.11. Vector Integer Divide Instructions + // 31.11.11: Vector Integer Divide Instructions AVDIVUVV AVDIVUVX AVDIVVV @@ -830,7 +834,7 @@ const ( AVREMVV AVREMVX - // 31.11.12. Vector Widening Integer Multiply Instructions + // 31.11.12: Vector Widening Integer Multiply Instructions AVWMULVV AVWMULVX AVWMULUVV @@ -838,7 +842,7 @@ const ( AVWMULSUVV AVWMULSUVX - // 31.11.13. Vector Single-Width Integer Multiply-Add Instructions + // 31.11.13: Vector Single-Width Integer Multiply-Add Instructions AVMACCVV AVMACCVX AVNMSACVV @@ -848,7 +852,7 @@ const ( AVNMSUBVV AVNMSUBVX - // 31.11.14. Vector Widening Integer Multiply-Add Instructions + // 31.11.14: Vector Widening Integer Multiply-Add Instructions AVWMACCUVV AVWMACCUVX AVWMACCVV @@ -857,17 +861,17 @@ const ( AVWMACCSUVX AVWMACCUSVX - // 31.11.15. Vector Integer Merge Instructions + // 31.11.15: Vector Integer Merge Instructions AVMERGEVVM AVMERGEVXM AVMERGEVIM - // 31.11.16. Vector Integer Move Instructions + // 31.11.16: Vector Integer Move Instructions AVMVVV AVMVVX AVMVVI - // 31.12.1. Vector Single-Width Saturating Add and Subtract + // 31.12.1: Vector Single-Width Saturating Add and Subtract AVSADDUVV AVSADDUVX AVSADDUVI @@ -879,7 +883,7 @@ const ( AVSSUBVV AVSSUBVX - // 31.12.2. Vector Single-Width Averaging Add and Subtract + // 31.12.2: Vector Single-Width Averaging Add and Subtract AVAADDUVV AVAADDUVX AVAADDVV @@ -889,11 +893,11 @@ const ( AVASUBVV AVASUBVX - // 31.12.3. Vector Single-Width Fractional Multiply with Rounding and Saturation + // 31.12.3: Vector Single-Width Fractional Multiply with Rounding and Saturation AVSMULVV AVSMULVX - // 31.12.4. Vector Single-Width Scaling Shift Instructions + // 31.12.4: Vector Single-Width Scaling Shift Instructions AVSSRLVV AVSSRLVX AVSSRLVI @@ -901,7 +905,7 @@ const ( AVSSRAVX AVSSRAVI - // 31.12.5. Vector Narrowing Fixed-Point Clip Instructions + // 31.12.5: Vector Narrowing Fixed-Point Clip Instructions AVNCLIPUWV AVNCLIPUWX AVNCLIPUWI @@ -909,14 +913,14 @@ const ( AVNCLIPWX AVNCLIPWI - // 31.13.2. Vector Single-Width Floating-Point Add/Subtract Instructions + // 31.13.2: Vector Single-Width Floating-Point Add/Subtract Instructions AVFADDVV AVFADDVF AVFSUBVV AVFSUBVF AVFRSUBVF - // 31.13.3. Vector Widening Floating-Point Add/Subtract Instructions + // 31.13.3: Vector Widening Floating-Point Add/Subtract Instructions AVFWADDVV AVFWADDVF AVFWSUBVV @@ -926,18 +930,18 @@ const ( AVFWSUBWV AVFWSUBWF - // 31.13.4. Vector Single-Width Floating-Point Multiply/Divide Instructions + // 31.13.4: Vector Single-Width Floating-Point Multiply/Divide Instructions AVFMULVV AVFMULVF AVFDIVVV AVFDIVVF AVFRDIVVF - // 31.13.5. Vector Widening Floating-Point Multiply + // 31.13.5: Vector Widening Floating-Point Multiply AVFWMULVV AVFWMULVF - // 31.13.6. Vector Single-Width Floating-Point Fused Multiply-Add Instructions + // 31.13.6: Vector Single-Width Floating-Point Fused Multiply-Add Instructions AVFMACCVV AVFMACCVF AVFNMACCVV @@ -955,7 +959,7 @@ const ( AVFNMSUBVV AVFNMSUBVF - // 31.13.7. Vector Widening Floating-Point Fused Multiply-Add Instructions + // 31.13.7: Vector Widening Floating-Point Fused Multiply-Add Instructions AVFWMACCVV AVFWMACCVF AVFWNMACCVV @@ -965,22 +969,22 @@ const ( AVFWNMSACVV AVFWNMSACVF - // 31.13.8. Vector Floating-Point Square-Root Instruction + // 31.13.8: Vector Floating-Point Square-Root Instruction AVFSQRTV - // 31.13.9. Vector Floating-Point Reciprocal Square-Root Estimate Instruction + // 31.13.9: Vector Floating-Point Reciprocal Square-Root Estimate Instruction AVFRSQRT7V - // 31.13.10. Vector Floating-Point Reciprocal Estimate Instruction + // 31.13.10: Vector Floating-Point Reciprocal Estimate Instruction AVFREC7V - // 31.13.11. Vector Floating-Point MIN/MAX Instructions + // 31.13.11: Vector Floating-Point MIN/MAX Instructions AVFMINVV AVFMINVF AVFMAXVV AVFMAXVF - // 31.13.12. Vector Floating-Point Sign-Injection Instructions + // 31.13.12: Vector Floating-Point Sign-Injection Instructions AVFSGNJVV AVFSGNJVF AVFSGNJNVV @@ -988,7 +992,7 @@ const ( AVFSGNJXVV AVFSGNJXVF - // 31.13.13. Vector Floating-Point Compare Instructions + // 31.13.13: Vector Floating-Point Compare Instructions AVMFEQVV AVMFEQVF AVMFNEVV @@ -1000,16 +1004,16 @@ const ( AVMFGTVF AVMFGEVF - // 31.13.14. Vector Floating-Point Classify Instruction + // 31.13.14: Vector Floating-Point Classify Instruction AVFCLASSV - // 31.13.15. Vector Floating-Point Merge Instruction + // 31.13.15: Vector Floating-Point Merge Instruction AVFMERGEVFM - // 31.13.16. Vector Floating-Point Move Instruction + // 31.13.16: Vector Floating-Point Move Instruction AVFMVVF - // 31.13.17. Single-Width Floating-Point/Integer Type-Convert Instructions + // 31.13.17: Single-Width Floating-Point/Integer Type-Convert Instructions AVFCVTXUFV AVFCVTXFV AVFCVTRTZXUFV @@ -1017,7 +1021,7 @@ const ( AVFCVTFXUV AVFCVTFXV - // 31.13.18. Widening Floating-Point/Integer Type-Convert Instructions + // 31.13.18: Widening Floating-Point/Integer Type-Convert Instructions AVFWCVTXUFV AVFWCVTXFV AVFWCVTRTZXUFV @@ -1026,7 +1030,7 @@ const ( AVFWCVTFXV AVFWCVTFFV - // 31.13.19. Narrowing Floating-Point/Integer Type-Convert Instructions + // 31.13.19: Narrowing Floating-Point/Integer Type-Convert Instructions AVFNCVTXUFW AVFNCVTXFW AVFNCVTRTZXUFW @@ -1036,7 +1040,7 @@ const ( AVFNCVTFFW AVFNCVTRODFFW - // 31.14.1. Vector Single-Width Integer Reduction Instructions + // 31.14.1: Vector Single-Width Integer Reduction Instructions AVREDSUMVS AVREDMAXUVS AVREDMAXVS @@ -1046,21 +1050,21 @@ const ( AVREDORVS AVREDXORVS - // 31.14.2. Vector Widening Integer Reduction Instructions + // 31.14.2: Vector Widening Integer Reduction Instructions AVWREDSUMUVS AVWREDSUMVS - // 31.14.3. Vector Single-Width Floating-Point Reduction Instructions + // 31.14.3: Vector Single-Width Floating-Point Reduction Instructions AVFREDOSUMVS AVFREDUSUMVS AVFREDMAXVS AVFREDMINVS - // 31.14.4. Vector Widening Floating-Point Reduction Instructions + // 31.14.4: Vector Widening Floating-Point Reduction Instructions AVFWREDOSUMVS AVFWREDUSUMVS - // 31.15. Vector Mask Instructions + // 31.15: Vector Mask Instructions AVMANDMM AVMNANDMM AVMANDNMM @@ -1077,15 +1081,15 @@ const ( AVIOTAM AVIDV - // 31.16.1. Integer Scalar Move Instructions + // 31.16.1: Integer Scalar Move Instructions AVMVXS AVMVSX - // 31.16.2. Floating-Point Scalar Move Instructions + // 31.16.2: Floating-Point Scalar Move Instructions AVFMVFS AVFMVSF - // 31.16.3. Vector Slide Instructions + // 31.16.3: Vector Slide Instructions AVSLIDEUPVX AVSLIDEUPVI AVSLIDEDOWNVX @@ -1095,16 +1099,16 @@ const ( AVSLIDE1DOWNVX AVFSLIDE1DOWNVF - // 31.16.4. Vector Register Gather Instructions + // 31.16.4: Vector Register Gather Instructions AVRGATHERVV AVRGATHEREI16VV AVRGATHERVX AVRGATHERVI - // 31.16.5. Vector Compress Instruction + // 31.16.5: Vector Compress Instruction AVCOMPRESSVM - // 31.16.6. Whole Vector Register Move + // 31.16.6: Whole Vector Register Move AVMV1RV AVMV2RV AVMV4RV diff --git a/src/cmd/internal/obj/riscv/obj.go b/src/cmd/internal/obj/riscv/obj.go index 5f01c43e7bf4c3..381dc085608644 100644 --- a/src/cmd/internal/obj/riscv/obj.go +++ b/src/cmd/internal/obj/riscv/obj.go @@ -1540,7 +1540,9 @@ type instructionData struct { // their encoding type. Entries are masked with obj.AMask to keep // indices small. var instructions = [ALAST & obj.AMask]instructionData{ + // // Unprivileged ISA + // // 2.4: Integer Computational Instructions AADDI & obj.AMask: {enc: iIIEncoding, ternary: true}, @@ -1589,7 +1591,7 @@ var instructions = [ALAST & obj.AMask]instructionData{ // 2.7: Memory Ordering AFENCE & obj.AMask: {enc: iIIEncoding}, - // 5.2: Integer Computational Instructions (RV64I) + // 4.2: Integer Computational Instructions (RV64I) AADDIW & obj.AMask: {enc: iIIEncoding, ternary: true}, ASLLIW & obj.AMask: {enc: iIIEncoding, ternary: true}, ASRLIW & obj.AMask: {enc: iIIEncoding, ternary: true}, @@ -1600,14 +1602,14 @@ var instructions = [ALAST & obj.AMask]instructionData{ ASUBW & obj.AMask: {enc: rIIIEncoding, ternary: true}, ASRAW & obj.AMask: {enc: rIIIEncoding, immForm: ASRAIW, ternary: true}, - // 5.3: Load and Store Instructions (RV64I) + // 4.3: Load and Store Instructions (RV64I) ALD & obj.AMask: {enc: iIIEncoding}, ASD & obj.AMask: {enc: sIEncoding}, // 7.1: CSR Instructions ACSRRS & obj.AMask: {enc: iIIEncoding}, - // 7.1: Multiplication Operations + // 13.1: Multiplication Operations AMUL & obj.AMask: {enc: rIIIEncoding, ternary: true}, AMULH & obj.AMask: {enc: rIIIEncoding, ternary: true}, AMULHU & obj.AMask: {enc: rIIIEncoding, ternary: true}, @@ -1622,13 +1624,13 @@ var instructions = [ALAST & obj.AMask]instructionData{ AREMW & obj.AMask: {enc: rIIIEncoding, ternary: true}, AREMUW & obj.AMask: {enc: rIIIEncoding, ternary: true}, - // 8.2: Load-Reserved/Store-Conditional + // 14.2: Load-Reserved/Store-Conditional Instructions (Zalrsc) ALRW & obj.AMask: {enc: rIIIEncoding}, ALRD & obj.AMask: {enc: rIIIEncoding}, ASCW & obj.AMask: {enc: rIIIEncoding}, ASCD & obj.AMask: {enc: rIIIEncoding}, - // 8.3: Atomic Memory Operations + // 14.4: Atomic Memory Operations (Zaamo) AAMOSWAPW & obj.AMask: {enc: rIIIEncoding}, AAMOSWAPD & obj.AMask: {enc: rIIIEncoding}, AAMOADDW & obj.AMask: {enc: rIIIEncoding}, @@ -1648,11 +1650,11 @@ var instructions = [ALAST & obj.AMask]instructionData{ AAMOMINUW & obj.AMask: {enc: rIIIEncoding}, AAMOMINUD & obj.AMask: {enc: rIIIEncoding}, - // 11.5: Single-Precision Load and Store Instructions + // 20.5: Single-Precision Load and Store Instructions AFLW & obj.AMask: {enc: iFEncoding}, AFSW & obj.AMask: {enc: sFEncoding}, - // 11.6: Single-Precision Floating-Point Computational Instructions + // 20.6: Single-Precision Floating-Point Computational Instructions AFADDS & obj.AMask: {enc: rFFFEncoding}, AFSUBS & obj.AMask: {enc: rFFFEncoding}, AFMULS & obj.AMask: {enc: rFFFEncoding}, @@ -1665,7 +1667,7 @@ var instructions = [ALAST & obj.AMask]instructionData{ AFNMSUBS & obj.AMask: {enc: rFFFFEncoding}, AFNMADDS & obj.AMask: {enc: rFFFFEncoding}, - // 11.7: Single-Precision Floating-Point Conversion and Move Instructions + // 20.7: Single-Precision Floating-Point Conversion and Move Instructions AFCVTWS & obj.AMask: {enc: rFIEncoding}, AFCVTLS & obj.AMask: {enc: rFIEncoding}, AFCVTSW & obj.AMask: {enc: rIFEncoding}, @@ -1680,19 +1682,19 @@ var instructions = [ALAST & obj.AMask]instructionData{ AFMVXW & obj.AMask: {enc: rFIEncoding}, AFMVWX & obj.AMask: {enc: rIFEncoding}, - // 11.8: Single-Precision Floating-Point Compare Instructions + // 20.8: Single-Precision Floating-Point Compare Instructions AFEQS & obj.AMask: {enc: rFFIEncoding}, AFLTS & obj.AMask: {enc: rFFIEncoding}, AFLES & obj.AMask: {enc: rFFIEncoding}, - // 11.9: Single-Precision Floating-Point Classify Instruction + // 20.9: Single-Precision Floating-Point Classify Instruction AFCLASSS & obj.AMask: {enc: rFIEncoding}, // 12.3: Double-Precision Load and Store Instructions AFLD & obj.AMask: {enc: iFEncoding}, AFSD & obj.AMask: {enc: sFEncoding}, - // 12.4: Double-Precision Floating-Point Computational Instructions + // 21.4: Double-Precision Floating-Point Computational Instructions AFADDD & obj.AMask: {enc: rFFFEncoding}, AFSUBD & obj.AMask: {enc: rFFFEncoding}, AFMULD & obj.AMask: {enc: rFFFEncoding}, @@ -1705,7 +1707,7 @@ var instructions = [ALAST & obj.AMask]instructionData{ AFNMSUBD & obj.AMask: {enc: rFFFFEncoding}, AFNMADDD & obj.AMask: {enc: rFFFFEncoding}, - // 12.5: Double-Precision Floating-Point Conversion and Move Instructions + // 21.5: Double-Precision Floating-Point Conversion and Move Instructions AFCVTWD & obj.AMask: {enc: rFIEncoding}, AFCVTLD & obj.AMask: {enc: rFIEncoding}, AFCVTDW & obj.AMask: {enc: rIFEncoding}, @@ -1722,25 +1724,19 @@ var instructions = [ALAST & obj.AMask]instructionData{ AFMVXD & obj.AMask: {enc: rFIEncoding}, AFMVDX & obj.AMask: {enc: rIFEncoding}, - // 12.6: Double-Precision Floating-Point Compare Instructions + // 21.6: Double-Precision Floating-Point Compare Instructions AFEQD & obj.AMask: {enc: rFFIEncoding}, AFLTD & obj.AMask: {enc: rFFIEncoding}, AFLED & obj.AMask: {enc: rFFIEncoding}, - // 12.7: Double-Precision Floating-Point Classify Instruction + // 21.7: Double-Precision Floating-Point Classify Instruction AFCLASSD & obj.AMask: {enc: rFIEncoding}, - // Privileged ISA - - // 3.2.1: Environment Call and Breakpoint - AECALL & obj.AMask: {enc: iIIEncoding}, - AEBREAK & obj.AMask: {enc: iIIEncoding}, - // - // RISC-V Bit-Manipulation ISA-extensions (1.0) + // "B" Extension for Bit Manipulation, Version 1.0.0 // - // 1.1: Address Generation Instructions (Zba) + // 28.4.1: Address Generation Instructions (Zba) AADDUW & obj.AMask: {enc: rIIIEncoding, ternary: true}, ASH1ADD & obj.AMask: {enc: rIIIEncoding, ternary: true}, ASH1ADDUW & obj.AMask: {enc: rIIIEncoding, ternary: true}, @@ -1750,7 +1746,7 @@ var instructions = [ALAST & obj.AMask]instructionData{ ASH3ADDUW & obj.AMask: {enc: rIIIEncoding, ternary: true}, ASLLIUW & obj.AMask: {enc: iIIEncoding, ternary: true}, - // 1.2: Basic Bit Manipulation (Zbb) + // 28.4.2: Basic Bit Manipulation (Zbb) AANDN & obj.AMask: {enc: rIIIEncoding, ternary: true}, ACLZ & obj.AMask: {enc: rIIEncoding}, ACLZW & obj.AMask: {enc: rIIEncoding}, @@ -1768,7 +1764,7 @@ var instructions = [ALAST & obj.AMask]instructionData{ AXNOR & obj.AMask: {enc: rIIIEncoding, ternary: true}, AZEXTH & obj.AMask: {enc: rIIEncoding}, - // 1.3: Bitwise Rotation (Zbb) + // 28.4.3: Bitwise Rotation (Zbb) AROL & obj.AMask: {enc: rIIIEncoding, ternary: true}, AROLW & obj.AMask: {enc: rIIIEncoding, ternary: true}, AROR & obj.AMask: {enc: rIIIEncoding, immForm: ARORI, ternary: true}, @@ -1778,7 +1774,7 @@ var instructions = [ALAST & obj.AMask]instructionData{ AORCB & obj.AMask: {enc: iIIEncoding}, AREV8 & obj.AMask: {enc: iIIEncoding}, - // 1.5: Single-bit Instructions (Zbs) + // 28.4.4: Single-bit Instructions (Zbs) ABCLR & obj.AMask: {enc: rIIIEncoding, immForm: ABCLRI, ternary: true}, ABCLRI & obj.AMask: {enc: iIIEncoding, ternary: true}, ABEXT & obj.AMask: {enc: rIIIEncoding, immForm: ABEXTI, ternary: true}, @@ -1788,6 +1784,14 @@ var instructions = [ALAST & obj.AMask]instructionData{ ABSET & obj.AMask: {enc: rIIIEncoding, immForm: ABSETI, ternary: true}, ABSETI & obj.AMask: {enc: iIIEncoding, ternary: true}, + // + // Privileged ISA + // + + // 3.3.1: Environment Call and Breakpoint + AECALL & obj.AMask: {enc: iIIEncoding}, + AEBREAK & obj.AMask: {enc: iIIEncoding}, + // Escape hatch AWORD & obj.AMask: {enc: rawEncoding}, From 09fdcdc97d6dcf90aaac3177a6ce2088613547be Mon Sep 17 00:00:00 2001 From: qmuntal Date: Thu, 6 Feb 2025 09:07:08 +0100 Subject: [PATCH 265/397] {all,clean,make,race,run}.bat: remove %GOBUILDEXIT% and %GOBUILDFAIL% %GOBUILDEXIT% is used to avoid closing the terminal window when the build or the tests fail on a dev machine. It is only set in CI to get a non-zero exit code in case of failure. %GOBUILDFAIL% is used to pass the exit code from a child batch file to the parent batch file. It is set to 1 in the child batch file if the build or the tests fail. These two variables add complexity to the batch files and impose some limitations on how they are implemented. For example, the child files can't use setlocal, as it would make the parent file unable to read the %GOBUILDFAIL% variable. This CL removes these two variables and replaces them with unconditional calls to "exit /b 1" in case of failure, which is more idiomatic and composable. The trick is that the "/b" parameter makes the exit only apply to the current batch file, not the entire shell session (unless the bat file is the root, in which case the parameter is ignored), so the parent batch file can continue executing, potentially checking the errorlevel of the child batch file (which we always set to 1). Change-Id: Ib053fb181ab14d58679551e03485700de77878d7 Reviewed-on: https://go-review.googlesource.com/c/go/+/647115 Auto-Submit: Damien Neil LUCI-TryBot-Result: Go LUCI Reviewed-by: Cherry Mui Reviewed-by: Damien Neil --- src/all.bat | 12 ++++++------ src/clean.bat | 9 ++------- src/make.bat | 5 +---- src/race.bat | 17 +++++------------ src/run.bat | 10 +++------- 5 files changed, 17 insertions(+), 36 deletions(-) diff --git a/src/all.bat b/src/all.bat index d5abec141f31aa..016987f86ecb35 100644 --- a/src/all.bat +++ b/src/all.bat @@ -8,15 +8,15 @@ setlocal if exist make.bat goto ok echo all.bat must be run from go\src -:: cannot exit: would kill parent command interpreter -goto end +exit /b 1 :ok call .\make.bat --no-banner --no-local -if %GOBUILDFAIL%==1 goto end +if errorlevel 1 goto fail call .\run.bat --no-rebuild --no-local -if %GOBUILDFAIL%==1 goto end +if errorlevel 1 goto fail "%GOTOOLDIR%/dist" banner +goto :eof -:end -if x%GOBUILDEXIT%==x1 exit %GOBUILDFAIL% +:fail +exit /b 1 diff --git a/src/clean.bat b/src/clean.bat index 6688b41e5e2c9d..ceba3a56cf44e8 100644 --- a/src/clean.bat +++ b/src/clean.bat @@ -6,8 +6,6 @@ setlocal -set GOBUILDFAIL=0 - go tool dist env -w -p >env.bat if errorlevel 1 goto fail call .\env.bat @@ -23,10 +21,7 @@ goto fail "%GOBIN%\go" tool dist clean "%GOBIN%\go" clean -i cmd -goto end +goto :eof :fail -set GOBUILDFAIL=1 - -:end -if x%GOBUILDEXIT%==x1 exit %GOBUILDFAIL% +exit /b 1 diff --git a/src/make.bat b/src/make.bat index 3b5a4663dce342..3a72a59470e565 100644 --- a/src/make.bat +++ b/src/make.bat @@ -47,8 +47,6 @@ if x%4==x--no-local goto nolocal setlocal :nolocal -set GOBUILDFAIL=0 - if exist make.bat goto ok echo Must run make.bat from Go src directory. goto fail @@ -180,5 +178,4 @@ echo ERROR: Cannot find %GOROOT_BOOTSTRAP%\bin\go.exe echo Set GOROOT_BOOTSTRAP to a working Go tree ^>= Go %bootgo%. :fail -set GOBUILDFAIL=1 -if x%GOBUILDEXIT%==x1 exit %GOBUILDFAIL% +exit /b 1 diff --git a/src/race.bat b/src/race.bat index d395e19f9741dd..64510b60129e9d 100644 --- a/src/race.bat +++ b/src/race.bat @@ -11,8 +11,7 @@ setlocal if exist make.bat goto ok echo race.bat must be run from go\src -:: cannot exit: would kill parent command interpreter -goto end +exit /b 1 :ok set GOROOT=%CD%\.. @@ -29,7 +28,7 @@ goto fail :continue call .\make.bat --no-banner --no-local -if %GOBUILDFAIL%==1 goto end +if errorlevel 1 goto fail echo # go install -race std go install -race std if errorlevel 1 goto fail @@ -37,15 +36,9 @@ if errorlevel 1 goto fail go tool dist test -race if errorlevel 1 goto fail -goto succ +echo All tests passed. +goto :eof :fail -set GOBUILDFAIL=1 echo Fail. -goto end - -:succ -echo All tests passed. - -:end -if x%GOBUILDEXIT%==x1 exit %GOBUILDFAIL% +exit /b 1 diff --git a/src/run.bat b/src/run.bat index 35c8ead8cb2247..8815a1109f1ab4 100644 --- a/src/run.bat +++ b/src/run.bat @@ -16,8 +16,6 @@ if x%2==x--no-local goto nolocal setlocal :nolocal -set GOBUILDFAIL=0 - set GOENV=off ..\bin\go tool dist env > env.bat if errorlevel 1 goto fail @@ -29,14 +27,12 @@ set GOPATH=c:\nonexist-gopath if x%1==x--no-rebuild goto norebuild ..\bin\go tool dist test --rebuild if errorlevel 1 goto fail -goto end +goto :eof :norebuild ..\bin\go tool dist test if errorlevel 1 goto fail -goto end +goto :eof :fail -set GOBUILDFAIL=1 - -:end +exit /b 1 From 6563a23560569488704754409667ebeca2648f68 Mon Sep 17 00:00:00 2001 From: qmuntal Date: Thu, 6 Feb 2025 09:19:20 +0100 Subject: [PATCH 266/397] run.bat: pass through all arguments to "go tool dist test" nolocal is no longer needed after CL 647115. If we remove it, then we can pass through all arguments to the Go command, which is useful for running tests with additional flags, like -json or -v. Change-Id: I5c48d9b90720c039bf2ec3d9213e7ce5cea33818 Reviewed-on: https://go-review.googlesource.com/c/go/+/647116 Reviewed-by: Damien Neil Auto-Submit: Damien Neil LUCI-TryBot-Result: Go LUCI Reviewed-by: Cherry Mui --- src/all.bat | 2 +- src/run.bat | 14 +------------- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/src/all.bat b/src/all.bat index 016987f86ecb35..0c4d5de70c6cc0 100644 --- a/src/all.bat +++ b/src/all.bat @@ -13,7 +13,7 @@ exit /b 1 call .\make.bat --no-banner --no-local if errorlevel 1 goto fail -call .\run.bat --no-rebuild --no-local +call .\run.bat --no-rebuild if errorlevel 1 goto fail "%GOTOOLDIR%/dist" banner goto :eof diff --git a/src/run.bat b/src/run.bat index 8815a1109f1ab4..6a0ffe3af905ac 100644 --- a/src/run.bat +++ b/src/run.bat @@ -9,12 +9,7 @@ echo Must run run.bat from Go src directory after installing cmd/go. goto fail :ok -:: Keep environment variables within this script -:: unless invoked with --no-local. -if x%1==x--no-local goto nolocal -if x%2==x--no-local goto nolocal setlocal -:nolocal set GOENV=off ..\bin\go tool dist env > env.bat @@ -23,14 +18,7 @@ call .\env.bat del env.bat set GOPATH=c:\nonexist-gopath - -if x%1==x--no-rebuild goto norebuild -..\bin\go tool dist test --rebuild -if errorlevel 1 goto fail -goto :eof - -:norebuild -..\bin\go tool dist test +..\bin\go tool dist test --rebuild %* if errorlevel 1 goto fail goto :eof From 9125e214a1d3341836d41ec3f297f42b9b141db1 Mon Sep 17 00:00:00 2001 From: Alexander Yastrebov Date: Fri, 7 Feb 2025 11:29:34 +0000 Subject: [PATCH 267/397] crypto/internal/fips140/edwards25519/field: speed up Element.Bytes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Write bytes in 64-bit chunks made from adjacent limbs. goos: linux goarch: amd64 pkg: crypto/internal/fips140/edwards25519/field cpu: Intel(R) Core(TM) i5-8350U CPU @ 1.70GHz │ HEAD~1 │ HEAD │ │ sec/op │ sec/op vs base │ Bytes-8 76.14n ± 3% 13.61n ± 3% -82.13% (p=0.000 n=10) │ HEAD~1 │ HEAD │ │ B/op │ B/op vs base │ Bytes-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ ¹ all samples are equal │ HEAD~1 │ HEAD │ │ allocs/op │ allocs/op vs base │ Bytes-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ ¹ all samples are equal Change-Id: Iaecc32da7fd8df96ff048e1e855a990f44dc9db5 GitHub-Last-Rev: d0e1583a4faf8cc3471af03437107cc0e5770d57 GitHub-Pull-Request: golang/go#71603 Reviewed-on: https://go-review.googlesource.com/c/go/+/647595 Reviewed-by: Filippo Valsorda Reviewed-by: Roland Shoemaker LUCI-TryBot-Result: Go LUCI Reviewed-by: Cherry Mui Auto-Submit: Filippo Valsorda --- .../internal/fips140/edwards25519/field/fe.go | 28 +++++++++++-------- .../edwards25519/field/fe_bench_test.go | 8 ++++++ 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/crypto/internal/fips140/edwards25519/field/fe.go b/src/crypto/internal/fips140/edwards25519/field/fe.go index 2d76ba72740b80..21bedefa0ca7d3 100644 --- a/src/crypto/internal/fips140/edwards25519/field/fe.go +++ b/src/crypto/internal/fips140/edwards25519/field/fe.go @@ -233,18 +233,22 @@ func (v *Element) bytes(out *[32]byte) []byte { t := *v t.reduce() - var buf [8]byte - for i, l := range [5]uint64{t.l0, t.l1, t.l2, t.l3, t.l4} { - bitsOffset := i * 51 - byteorder.LEPutUint64(buf[:], l<= len(out) { - break - } - out[off] |= bb - } - } + // Pack five 51-bit limbs into four 64-bit words: + // + // 255 204 153 102 51 0 + // ├──l4──┼──l3──┼──l2──┼──l1──┼──l0──┤ + // ├───u3───┼───u2───┼───u1───┼───u0───┤ + // 256 192 128 64 0 + + u0 := t.l1<<51 | t.l0 + u1 := t.l2<<(102-64) | t.l1>>(64-51) + u2 := t.l3<<(153-128) | t.l2>>(128-102) + u3 := t.l4<<(204-192) | t.l3>>(192-153) + + byteorder.LEPutUint64(out[0*8:], u0) + byteorder.LEPutUint64(out[1*8:], u1) + byteorder.LEPutUint64(out[2*8:], u2) + byteorder.LEPutUint64(out[3*8:], u3) return out[:] } diff --git a/src/crypto/internal/fips140/edwards25519/field/fe_bench_test.go b/src/crypto/internal/fips140/edwards25519/field/fe_bench_test.go index 84fdf05a8e474a..fb80ca88fe255d 100644 --- a/src/crypto/internal/fips140/edwards25519/field/fe_bench_test.go +++ b/src/crypto/internal/fips140/edwards25519/field/fe_bench_test.go @@ -47,3 +47,11 @@ func BenchmarkMult32(b *testing.B) { x.Mult32(x, 0xaa42aa42) } } + +func BenchmarkBytes(b *testing.B) { + x := new(Element).One() + b.ResetTimer() + for i := 0; i < b.N; i++ { + x.Bytes() + } +} From d9d87edc56e72808b004a80e8c6846bde690d6c1 Mon Sep 17 00:00:00 2001 From: Quim Muntal Date: Thu, 6 Feb 2025 13:16:34 -0800 Subject: [PATCH 268/397] Revert "cmd/go: report gcc ld error message when linking fails" This reverts CL 646315. Reason for revert: broke cgo_undef test Change-Id: Ic992a1666a446736c605a8caefa77f791dceb64c Reviewed-on: https://go-review.googlesource.com/c/go/+/647415 Reviewed-by: Cherry Mui Reviewed-by: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI --- src/cmd/go/internal/work/exec.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go index 8e5d48103339b5..c79d6f73ef4a9d 100644 --- a/src/cmd/go/internal/work/exec.go +++ b/src/cmd/go/internal/work/exec.go @@ -2208,7 +2208,7 @@ func (b *Builder) gccld(a *Action, objdir, outfile string, flags []string, objs } cmdargs := []any{cmd, "-o", outfile, objs, flags} - out, err := sh.runOut(base.Cwd(), b.cCompilerEnv(), cmdargs...) + _, err := sh.runOut(base.Cwd(), b.cCompilerEnv(), cmdargs...) // Note that failure is an expected outcome here, so we report output only // in debug mode and don't report the error. @@ -2217,7 +2217,7 @@ func (b *Builder) gccld(a *Action, objdir, outfile string, flags []string, objs if err != nil { saw = "failed" } - sh.ShowCmd("", "%s # test for internal linking errors (%s)\n%s", joinUnambiguously(str.StringList(cmdargs...)), saw, out) + sh.ShowCmd("", "%s # test for internal linking errors (%s)", joinUnambiguously(str.StringList(cmdargs...)), saw) } return err From f99a214d96c14c5c4287a39f99342ae895194cc0 Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Thu, 14 Nov 2024 16:00:43 -0500 Subject: [PATCH 269/397] crypto/internal/fips140test: add EDDSA ACVP tests This commit adds ACVP test coverage for EDDSA (Ed25519, and HashEd25519/Ed25519ph) for the keyGen, keyVer, sigGen, and sigVer capabilities. Updates #69642 Change-Id: I5122d86180bd4d2f7d94570a6dc939808aa24fc4 Reviewed-on: https://go-review.googlesource.com/c/go/+/621135 Reviewed-by: Roland Shoemaker LUCI-TryBot-Result: Go LUCI Reviewed-by: Filippo Valsorda Auto-Submit: Filippo Valsorda Reviewed-by: Cherry Mui --- .../fips140test/acvp_capabilities.json | 7 +- .../fips140test/acvp_test.config.json | 4 +- src/crypto/internal/fips140test/acvp_test.go | 129 ++++++++++++++++++ 3 files changed, 138 insertions(+), 2 deletions(-) diff --git a/src/crypto/internal/fips140test/acvp_capabilities.json b/src/crypto/internal/fips140test/acvp_capabilities.json index 8a4a97758cce39..368c7809deb980 100644 --- a/src/crypto/internal/fips140test/acvp_capabilities.json +++ b/src/crypto/internal/fips140test/acvp_capabilities.json @@ -37,5 +37,10 @@ {"algorithm":"hmacDRBG","revision":"1.0","predResistanceEnabled":[false],"reseedImplemented":false,"capabilities":[{"mode":"SHA3-224","derFuncEnabled":false,"entropyInputLen":[192],"nonceLen":[96],"persoStringLen":[192],"additionalInputLen":[0],"returnedBitsLen":224}]}, {"algorithm":"hmacDRBG","revision":"1.0","predResistanceEnabled":[false],"reseedImplemented":false,"capabilities":[{"mode":"SHA3-256","derFuncEnabled":false,"entropyInputLen":[256],"nonceLen":[128],"persoStringLen":[256],"additionalInputLen":[0],"returnedBitsLen":256}]}, {"algorithm":"hmacDRBG","revision":"1.0","predResistanceEnabled":[false],"reseedImplemented":false,"capabilities":[{"mode":"SHA3-384","derFuncEnabled":false,"entropyInputLen":[256],"nonceLen":[128],"persoStringLen":[256],"additionalInputLen":[0],"returnedBitsLen":384}]}, - {"algorithm":"hmacDRBG","revision":"1.0","predResistanceEnabled":[false],"reseedImplemented":false,"capabilities":[{"mode":"SHA3-512","derFuncEnabled":false,"entropyInputLen":[256],"nonceLen":[128],"persoStringLen":[256],"additionalInputLen":[0],"returnedBitsLen":512}]} + {"algorithm":"hmacDRBG","revision":"1.0","predResistanceEnabled":[false],"reseedImplemented":false,"capabilities":[{"mode":"SHA3-512","derFuncEnabled":false,"entropyInputLen":[256],"nonceLen":[128],"persoStringLen":[256],"additionalInputLen":[0],"returnedBitsLen":512}]}, + + {"algorithm":"EDDSA","mode":"keyGen","revision":"1.0","curve":["ED-25519"]}, + {"algorithm":"EDDSA","mode":"keyVer","revision":"1.0","curve":["ED-25519"]}, + {"algorithm":"EDDSA","mode":"sigGen","revision":"1.0","pure":true,"preHash":true,"contextLength":[{"min":0,"max":255,"increment":1}],"curve":["ED-25519"]}, + {"algorithm":"EDDSA","mode":"sigVer","revision":"1.0","pure":true,"preHash":true,"curve":["ED-25519"]} ] diff --git a/src/crypto/internal/fips140test/acvp_test.config.json b/src/crypto/internal/fips140test/acvp_test.config.json index dc4d714f19c620..2afd457f46ce90 100644 --- a/src/crypto/internal/fips140test/acvp_test.config.json +++ b/src/crypto/internal/fips140test/acvp_test.config.json @@ -27,5 +27,7 @@ {"Wrapper": "go", "In": "vectors/ML-KEM.bz2", "Out": "expected/ML-KEM.bz2"}, - {"Wrapper": "go", "In": "vectors/hmacDRBG.bz2", "Out": "expected/hmacDRBG.bz2"} + {"Wrapper": "go", "In": "vectors/hmacDRBG.bz2", "Out": "expected/hmacDRBG.bz2"}, + + {"Wrapper": "go", "In": "vectors/EDDSA.bz2", "Out": "expected/EDDSA.bz2"} ] \ No newline at end of file diff --git a/src/crypto/internal/fips140test/acvp_test.go b/src/crypto/internal/fips140test/acvp_test.go index 8dedb9a79159b5..b160f60d17cccc 100644 --- a/src/crypto/internal/fips140test/acvp_test.go +++ b/src/crypto/internal/fips140test/acvp_test.go @@ -24,6 +24,8 @@ import ( "crypto/internal/cryptotest" "crypto/internal/fips140" "crypto/internal/fips140/ecdsa" + "crypto/internal/fips140/ed25519" + "crypto/internal/fips140/edwards25519" "crypto/internal/fips140/hmac" "crypto/internal/fips140/mlkem" "crypto/internal/fips140/pbkdf2" @@ -81,6 +83,8 @@ var ( // https://pages.nist.gov/ACVP/draft-celi-acvp-ml-kem.html#section-7.3 // HMAC DRBG algorithm capabilities: // https://pages.nist.gov/ACVP/draft-vassilev-acvp-drbg.html#section-7.2 + // EDDSA algorithm capabilities: + // https://pages.nist.gov/ACVP/draft-celi-acvp-eddsa.html#section-7 //go:embed acvp_capabilities.json capabilitiesJson []byte @@ -142,6 +146,11 @@ var ( "hmacDRBG/SHA3-256": cmdHmacDrbgAft(func() fips140.Hash { return sha3.New256() }), "hmacDRBG/SHA3-384": cmdHmacDrbgAft(func() fips140.Hash { return sha3.New384() }), "hmacDRBG/SHA3-512": cmdHmacDrbgAft(func() fips140.Hash { return sha3.New512() }), + + "EDDSA/keyGen": cmdEddsaKeyGenAft(), + "EDDSA/keyVer": cmdEddsaKeyVerAft(), + "EDDSA/sigGen": cmdEddsaSigGenAftBft(), + "EDDSA/sigVer": cmdEddsaSigVerAft(), } ) @@ -397,6 +406,126 @@ func cmdPbkdf() command { } } +func cmdEddsaKeyGenAft() command { + return command{ + requiredArgs: 1, // Curve name + handler: func(args [][]byte) ([][]byte, error) { + if string(args[0]) != "ED-25519" { + return nil, fmt.Errorf("unsupported EDDSA curve: %q", args[0]) + } + + sk, err := ed25519.GenerateKey() + if err != nil { + return nil, fmt.Errorf("generating EDDSA keypair: %w", err) + } + + // EDDSA/keyGen/AFT responses are d & q, described[0] as: + // d The encoded private key point + // q The encoded public key point + // + // Contrary to the description of a "point", d is the private key + // seed bytes per FIPS.186-5[1] A.2.3. + // + // [0]: https://pages.nist.gov/ACVP/draft-celi-acvp-eddsa.html#section-9.1 + // [1]: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-5.pdf + return [][]byte{sk.Seed(), sk.PublicKey()}, nil + }, + } +} + +func cmdEddsaKeyVerAft() command { + return command{ + requiredArgs: 2, // Curve name, Q + handler: func(args [][]byte) ([][]byte, error) { + if string(args[0]) != "ED-25519" { + return nil, fmt.Errorf("unsupported EDDSA curve: %q", args[0]) + } + + // Verify the point is on the curve. The higher-level ed25519 API does + // this at signature verification time so we have to use the lower-level + // edwards25519 package to do it here in absence of a signature to verify. + if _, err := new(edwards25519.Point).SetBytes(args[1]); err != nil { + return [][]byte{{0}}, nil + } + + return [][]byte{{1}}, nil + }, + } +} + +func cmdEddsaSigGenAftBft() command { + return command{ + requiredArgs: 5, // Curve name, private key seed, message, prehash, context + handler: func(args [][]byte) ([][]byte, error) { + if string(args[0]) != "ED-25519" { + return nil, fmt.Errorf("unsupported EDDSA curve: %q", args[0]) + } + + sk, err := ed25519.NewPrivateKeyFromSeed(args[1]) + if err != nil { + return nil, fmt.Errorf("error creating private key: %w", err) + } + msg := args[2] + prehash := args[3] + context := string(args[4]) + + var sig []byte + if prehash[0] == 1 { + h := sha512.New() + h.Write(msg) + msg = h.Sum(nil) + + // With ed25519 the context is only specified for sigGen tests when using prehashing. + // See https://pages.nist.gov/ACVP/draft-celi-acvp-eddsa.html#section-8.6 + sig, err = ed25519.SignPH(sk, msg, context) + if err != nil { + return nil, fmt.Errorf("error signing message: %w", err) + } + } else { + sig = ed25519.Sign(sk, msg) + } + + return [][]byte{sig}, nil + }, + } +} + +func cmdEddsaSigVerAft() command { + return command{ + requiredArgs: 5, // Curve name, message, public key, signature, prehash + handler: func(args [][]byte) ([][]byte, error) { + if string(args[0]) != "ED-25519" { + return nil, fmt.Errorf("unsupported EDDSA curve: %q", args[0]) + } + + msg := args[1] + pk, err := ed25519.NewPublicKey(args[2]) + if err != nil { + return nil, fmt.Errorf("invalid public key: %w", err) + } + sig := args[3] + prehash := args[4] + + if prehash[0] == 1 { + h := sha512.New() + h.Write(msg) + msg = h.Sum(nil) + // Context is only specified for sigGen, not sigVer. + // See https://pages.nist.gov/ACVP/draft-celi-acvp-eddsa.html#section-8.6 + err = ed25519.VerifyPH(pk, msg, sig, "") + } else { + err = ed25519.Verify(pk, msg, sig) + } + + if err != nil { + return [][]byte{{0}}, nil + } + + return [][]byte{{1}}, nil + }, + } +} + func lookupHash(name string) (func() fips140.Hash, error) { var h func() fips140.Hash From 78132a1f5731fcca5d2ee4535cebc15741946d1e Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Thu, 14 Nov 2024 15:54:54 -0500 Subject: [PATCH 270/397] crypto/internal/fips140test: add ECDSA ACVP tests This commit adds ACVP test coverage for the non-deterministic ECDSA vectors (keyGen, keyVer, sigGen, sigVer) based on the NIST spec: https://pages.nist.gov/ACVP/draft-fussell-acvp-ecdsa.html Updates #69642 Change-Id: Iec8b18a247b0a652d13f9167a78de2cb74f4dfd0 Reviewed-on: https://go-review.googlesource.com/c/go/+/620935 Reviewed-by: Roland Shoemaker Reviewed-by: Filippo Valsorda Auto-Submit: Filippo Valsorda TryBot-Bypass: Filippo Valsorda Reviewed-by: Cherry Mui --- .../fips140test/acvp_capabilities.json | 7 +- .../fips140test/acvp_test.config.json | 4 +- src/crypto/internal/fips140test/acvp_test.go | 231 ++++++++++++++++++ 3 files changed, 240 insertions(+), 2 deletions(-) diff --git a/src/crypto/internal/fips140test/acvp_capabilities.json b/src/crypto/internal/fips140test/acvp_capabilities.json index 368c7809deb980..47ae58e9e07017 100644 --- a/src/crypto/internal/fips140test/acvp_capabilities.json +++ b/src/crypto/internal/fips140test/acvp_capabilities.json @@ -42,5 +42,10 @@ {"algorithm":"EDDSA","mode":"keyGen","revision":"1.0","curve":["ED-25519"]}, {"algorithm":"EDDSA","mode":"keyVer","revision":"1.0","curve":["ED-25519"]}, {"algorithm":"EDDSA","mode":"sigGen","revision":"1.0","pure":true,"preHash":true,"contextLength":[{"min":0,"max":255,"increment":1}],"curve":["ED-25519"]}, - {"algorithm":"EDDSA","mode":"sigVer","revision":"1.0","pure":true,"preHash":true,"curve":["ED-25519"]} + {"algorithm":"EDDSA","mode":"sigVer","revision":"1.0","pure":true,"preHash":true,"curve":["ED-25519"]}, + + {"algorithm":"ECDSA","mode":"keyGen","revision":"FIPS186-5","curve":["P-224","P-256","P-384","P-521"],"secretGenerationMode":["testing candidates"]}, + {"algorithm":"ECDSA","mode":"keyVer","revision":"FIPS186-5","curve":["P-224","P-256","P-384","P-521"]}, + {"algorithm":"ECDSA","mode":"sigGen","revision":"FIPS186-5","capabilities":[{"curve":["P-224","P-256","P-384","P-521"],"hashAlg":["SHA2-224","SHA2-256","SHA2-384","SHA2-512","SHA2-512/224","SHA2-512/256","SHA3-224","SHA3-256","SHA3-384","SHA3-512"]}]}, + {"algorithm":"ECDSA","mode":"sigVer","revision":"FIPS186-5","capabilities":[{"curve":["P-224","P-256","P-384","P-521"],"hashAlg":["SHA2-224","SHA2-256","SHA2-384","SHA2-512","SHA2-512/224","SHA2-512/256","SHA3-224","SHA3-256","SHA3-384","SHA3-512"]}]} ] diff --git a/src/crypto/internal/fips140test/acvp_test.config.json b/src/crypto/internal/fips140test/acvp_test.config.json index 2afd457f46ce90..4c1879380c2c91 100644 --- a/src/crypto/internal/fips140test/acvp_test.config.json +++ b/src/crypto/internal/fips140test/acvp_test.config.json @@ -29,5 +29,7 @@ {"Wrapper": "go", "In": "vectors/hmacDRBG.bz2", "Out": "expected/hmacDRBG.bz2"}, - {"Wrapper": "go", "In": "vectors/EDDSA.bz2", "Out": "expected/EDDSA.bz2"} + {"Wrapper": "go", "In": "vectors/EDDSA.bz2", "Out": "expected/EDDSA.bz2"}, + + {"Wrapper": "go", "In": "vectors/ECDSA.bz2", "Out": "expected/ECDSA.bz2"} ] \ No newline at end of file diff --git a/src/crypto/internal/fips140test/acvp_test.go b/src/crypto/internal/fips140test/acvp_test.go index b160f60d17cccc..ae0009c938e4b0 100644 --- a/src/crypto/internal/fips140test/acvp_test.go +++ b/src/crypto/internal/fips140test/acvp_test.go @@ -21,6 +21,7 @@ package fipstest import ( "bufio" "bytes" + "crypto/elliptic" "crypto/internal/cryptotest" "crypto/internal/fips140" "crypto/internal/fips140/ecdsa" @@ -32,12 +33,14 @@ import ( "crypto/internal/fips140/sha256" "crypto/internal/fips140/sha3" "crypto/internal/fips140/sha512" + "crypto/rand" _ "embed" "encoding/binary" "errors" "fmt" "internal/testenv" "io" + "math/big" "os" "path/filepath" "strings" @@ -85,6 +88,8 @@ var ( // https://pages.nist.gov/ACVP/draft-vassilev-acvp-drbg.html#section-7.2 // EDDSA algorithm capabilities: // https://pages.nist.gov/ACVP/draft-celi-acvp-eddsa.html#section-7 + // ECDSA algorithm capabilities: + // https://pages.nist.gov/ACVP/draft-fussell-acvp-ecdsa.html#section-7 //go:embed acvp_capabilities.json capabilitiesJson []byte @@ -151,6 +156,11 @@ var ( "EDDSA/keyVer": cmdEddsaKeyVerAft(), "EDDSA/sigGen": cmdEddsaSigGenAftBft(), "EDDSA/sigVer": cmdEddsaSigVerAft(), + + "ECDSA/keyGen": cmdEcdsaKeyGenAft(), + "ECDSA/keyVer": cmdEcdsaKeyVerAft(), + "ECDSA/sigGen": cmdEcdsaSigGenAft(), + "ECDSA/sigVer": cmdEcdsaSigVerAft(), } ) @@ -526,6 +536,208 @@ func cmdEddsaSigVerAft() command { } } +func cmdEcdsaKeyGenAft() command { + return command{ + requiredArgs: 1, // Curve name + handler: func(args [][]byte) ([][]byte, error) { + curve, err := lookupCurve(string(args[0])) + if err != nil { + return nil, err + } + + var sk *ecdsa.PrivateKey + switch curve.Params() { + case elliptic.P224().Params(): + sk, err = ecdsa.GenerateKey(ecdsa.P224(), rand.Reader) + case elliptic.P256().Params(): + sk, err = ecdsa.GenerateKey(ecdsa.P256(), rand.Reader) + case elliptic.P384().Params(): + sk, err = ecdsa.GenerateKey(ecdsa.P384(), rand.Reader) + case elliptic.P521().Params(): + sk, err = ecdsa.GenerateKey(ecdsa.P521(), rand.Reader) + default: + return nil, fmt.Errorf("unsupported curve: %v", curve) + } + + if err != nil { + return nil, err + } + + pubBytes := sk.PublicKey().Bytes() + byteLen := (curve.Params().BitSize + 7) / 8 + + return [][]byte{ + sk.Bytes(), + pubBytes[1 : 1+byteLen], + pubBytes[1+byteLen:], + }, nil + }, + } +} + +func cmdEcdsaKeyVerAft() command { + return command{ + requiredArgs: 3, // Curve name, X, Y + handler: func(args [][]byte) ([][]byte, error) { + curve, err := lookupCurve(string(args[0])) + if err != nil { + return nil, err + } + + x := new(big.Int).SetBytes(args[1]) + y := new(big.Int).SetBytes(args[2]) + + if curve.IsOnCurve(x, y) { + return [][]byte{{1}}, nil + } + + return [][]byte{{0}}, nil + }, + } +} + +// pointFromAffine is used to convert the PublicKey to a nistec SetBytes input. +// Duplicated from crypto/ecdsa.go's pointFromAffine. +func pointFromAffine(curve elliptic.Curve, x, y *big.Int) ([]byte, error) { + bitSize := curve.Params().BitSize + // Reject values that would not get correctly encoded. + if x.Sign() < 0 || y.Sign() < 0 { + return nil, errors.New("negative coordinate") + } + if x.BitLen() > bitSize || y.BitLen() > bitSize { + return nil, errors.New("overflowing coordinate") + } + // Encode the coordinates and let SetBytes reject invalid points. + byteLen := (bitSize + 7) / 8 + buf := make([]byte, 1+2*byteLen) + buf[0] = 4 // uncompressed point + x.FillBytes(buf[1 : 1+byteLen]) + y.FillBytes(buf[1+byteLen : 1+2*byteLen]) + return buf, nil +} + +func signEcdsa[P ecdsa.Point[P], H fips140.Hash](c *ecdsa.Curve[P], h func() H, q []byte, sk []byte, digest []byte) (*ecdsa.Signature, error) { + priv, err := ecdsa.NewPrivateKey(c, sk, q) + if err != nil { + return nil, fmt.Errorf("invalid private key: %w", err) + } + + sig, err := ecdsa.Sign(c, h, priv, rand.Reader, digest) + if err != nil { + return nil, fmt.Errorf("signing failed: %w", err) + } + + return sig, nil +} + +func cmdEcdsaSigGenAft() command { + return command{ + requiredArgs: 4, // Curve name, private key, hash name, message + handler: func(args [][]byte) ([][]byte, error) { + curve, err := lookupCurve(string(args[0])) + if err != nil { + return nil, err + } + + sk := args[1] + + newH, err := lookupHash(string(args[2])) + if err != nil { + return nil, err + } + + msg := args[3] + hashFunc := newH() + hashFunc.Write(msg) + digest := hashFunc.Sum(nil) + + d := new(big.Int).SetBytes(sk) + x, y := curve.ScalarBaseMult(d.Bytes()) + q, err := pointFromAffine(curve, x, y) + if err != nil { + return nil, err + } + + var sig *ecdsa.Signature + switch curve.Params() { + case elliptic.P224().Params(): + sig, err = signEcdsa(ecdsa.P224(), newH, q, sk, digest) + case elliptic.P256().Params(): + sig, err = signEcdsa(ecdsa.P256(), newH, q, sk, digest) + case elliptic.P384().Params(): + sig, err = signEcdsa(ecdsa.P384(), newH, q, sk, digest) + case elliptic.P521().Params(): + sig, err = signEcdsa(ecdsa.P521(), newH, q, sk, digest) + default: + return nil, fmt.Errorf("unsupported curve: %v", curve) + } + if err != nil { + return nil, err + } + + return [][]byte{sig.R, sig.S}, nil + }, + } +} + +func cmdEcdsaSigVerAft() command { + return command{ + requiredArgs: 7, // Curve name, hash name, message, X, Y, R, S + handler: func(args [][]byte) ([][]byte, error) { + curve, err := lookupCurve(string(args[0])) + if err != nil { + return nil, err + } + + newH, err := lookupHash(string(args[1])) + if err != nil { + return nil, err + } + + msg := args[2] + hashFunc := newH() + hashFunc.Write(msg) + digest := hashFunc.Sum(nil) + + x, y := args[3], args[4] + q, err := pointFromAffine(curve, new(big.Int).SetBytes(x), new(big.Int).SetBytes(y)) + if err != nil { + return nil, fmt.Errorf("invalid x/y coordinates: %v", err) + } + + signature := &ecdsa.Signature{R: args[5], S: args[6]} + + switch curve.Params() { + case elliptic.P224().Params(): + err = verifyEcdsa(ecdsa.P224(), q, digest, signature) + case elliptic.P256().Params(): + err = verifyEcdsa(ecdsa.P256(), q, digest, signature) + case elliptic.P384().Params(): + err = verifyEcdsa(ecdsa.P384(), q, digest, signature) + case elliptic.P521().Params(): + err = verifyEcdsa(ecdsa.P521(), q, digest, signature) + default: + return nil, fmt.Errorf("unsupported curve: %v", curve) + } + + if err == nil { + return [][]byte{{1}}, nil + } + + return [][]byte{{0}}, nil + }, + } +} + +func verifyEcdsa[P ecdsa.Point[P]](c *ecdsa.Curve[P], q []byte, digest []byte, sig *ecdsa.Signature) error { + pub, err := ecdsa.NewPublicKey(c, q) + if err != nil { + return fmt.Errorf("invalid public key: %w", err) + } + + return ecdsa.Verify(c, pub, digest, sig) +} + func lookupHash(name string) (func() fips140.Hash, error) { var h func() fips140.Hash @@ -714,6 +926,25 @@ func cmdHmacDrbgAft(h func() fips140.Hash) command { } } +func lookupCurve(name string) (elliptic.Curve, error) { + var c elliptic.Curve + + switch name { + case "P-224": + c = elliptic.P224() + case "P-256": + c = elliptic.P256() + case "P-384": + c = elliptic.P384() + case "P-521": + c = elliptic.P521() + default: + return nil, fmt.Errorf("unknown curve name: %q", name) + } + + return c, nil +} + func TestACVP(t *testing.T) { testenv.SkipIfShortAndSlow(t) From 273db12ceeef8ec74f437ec097474eeda587485d Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Wed, 11 Dec 2024 16:31:22 -0500 Subject: [PATCH 271/397] crypto/internal/fips140test: add DetECDSA ACVP tests Adds ACVP test coverage for deterministic ECDSA based on the NIST spec: https://pages.nist.gov/ACVP/draft-fussell-acvp-ecdsa.html Notably there is no corresponding acvp_test.config.json update in this commit because ACVP DetECDSA only specifies sigGen mode. The ACVP ECDSA sigGen tests are not amenable to testing against static data because the test vectors don't provide a key pair to use for the signature, just the message. The module wrapper has to generate its own keypair and return the public key components with the signature. DetECDSA produces deterministic signatures only when signing the same message with the same key. Change-Id: I9921f52e943c96b32e02e79cb5556ba0fabeae17 Reviewed-on: https://go-review.googlesource.com/c/go/+/635341 Auto-Submit: Filippo Valsorda Reviewed-by: Cherry Mui LUCI-TryBot-Result: Go LUCI Reviewed-by: Roland Shoemaker Reviewed-by: Filippo Valsorda --- .../fips140test/acvp_capabilities.json | 3 +- src/crypto/internal/fips140test/acvp_test.go | 40 +++++++++++++------ 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/src/crypto/internal/fips140test/acvp_capabilities.json b/src/crypto/internal/fips140test/acvp_capabilities.json index 47ae58e9e07017..ff94d3b6ba01ad 100644 --- a/src/crypto/internal/fips140test/acvp_capabilities.json +++ b/src/crypto/internal/fips140test/acvp_capabilities.json @@ -47,5 +47,6 @@ {"algorithm":"ECDSA","mode":"keyGen","revision":"FIPS186-5","curve":["P-224","P-256","P-384","P-521"],"secretGenerationMode":["testing candidates"]}, {"algorithm":"ECDSA","mode":"keyVer","revision":"FIPS186-5","curve":["P-224","P-256","P-384","P-521"]}, {"algorithm":"ECDSA","mode":"sigGen","revision":"FIPS186-5","capabilities":[{"curve":["P-224","P-256","P-384","P-521"],"hashAlg":["SHA2-224","SHA2-256","SHA2-384","SHA2-512","SHA2-512/224","SHA2-512/256","SHA3-224","SHA3-256","SHA3-384","SHA3-512"]}]}, - {"algorithm":"ECDSA","mode":"sigVer","revision":"FIPS186-5","capabilities":[{"curve":["P-224","P-256","P-384","P-521"],"hashAlg":["SHA2-224","SHA2-256","SHA2-384","SHA2-512","SHA2-512/224","SHA2-512/256","SHA3-224","SHA3-256","SHA3-384","SHA3-512"]}]} + {"algorithm":"ECDSA","mode":"sigVer","revision":"FIPS186-5","capabilities":[{"curve":["P-224","P-256","P-384","P-521"],"hashAlg":["SHA2-224","SHA2-256","SHA2-384","SHA2-512","SHA2-512/224","SHA2-512/256","SHA3-224","SHA3-256","SHA3-384","SHA3-512"]}]}, + {"algorithm":"DetECDSA","mode":"sigGen","revision":"FIPS186-5","capabilities":[{"curve":["P-224","P-256","P-384","P-521"],"hashAlg":["SHA2-224","SHA2-256","SHA2-384","SHA2-512","SHA2-512/224","SHA2-512/256","SHA3-224","SHA3-256","SHA3-384","SHA3-512"]}]} ] diff --git a/src/crypto/internal/fips140test/acvp_test.go b/src/crypto/internal/fips140test/acvp_test.go index ae0009c938e4b0..1ee13c3f1d9b90 100644 --- a/src/crypto/internal/fips140test/acvp_test.go +++ b/src/crypto/internal/fips140test/acvp_test.go @@ -75,6 +75,13 @@ type command struct { handler commandHandler } +type ecdsaSigType int + +const ( + ecdsaSigTypeNormal ecdsaSigType = iota + ecdsaSigTypeDeterministic +) + var ( // SHA2 algorithm capabilities: // https://pages.nist.gov/ACVP/draft-celi-acvp-sha.html#section-7.2 @@ -88,7 +95,7 @@ var ( // https://pages.nist.gov/ACVP/draft-vassilev-acvp-drbg.html#section-7.2 // EDDSA algorithm capabilities: // https://pages.nist.gov/ACVP/draft-celi-acvp-eddsa.html#section-7 - // ECDSA algorithm capabilities: + // ECDSA and DetECDSA algorithm capabilities: // https://pages.nist.gov/ACVP/draft-fussell-acvp-ecdsa.html#section-7 //go:embed acvp_capabilities.json capabilitiesJson []byte @@ -157,10 +164,11 @@ var ( "EDDSA/sigGen": cmdEddsaSigGenAftBft(), "EDDSA/sigVer": cmdEddsaSigVerAft(), - "ECDSA/keyGen": cmdEcdsaKeyGenAft(), - "ECDSA/keyVer": cmdEcdsaKeyVerAft(), - "ECDSA/sigGen": cmdEcdsaSigGenAft(), - "ECDSA/sigVer": cmdEcdsaSigVerAft(), + "ECDSA/keyGen": cmdEcdsaKeyGenAft(), + "ECDSA/keyVer": cmdEcdsaKeyVerAft(), + "ECDSA/sigGen": cmdEcdsaSigGenAft(ecdsaSigTypeNormal), + "ECDSA/sigVer": cmdEcdsaSigVerAft(), + "DetECDSA/sigGen": cmdEcdsaSigGenAft(ecdsaSigTypeDeterministic), } ) @@ -616,13 +624,21 @@ func pointFromAffine(curve elliptic.Curve, x, y *big.Int) ([]byte, error) { return buf, nil } -func signEcdsa[P ecdsa.Point[P], H fips140.Hash](c *ecdsa.Curve[P], h func() H, q []byte, sk []byte, digest []byte) (*ecdsa.Signature, error) { +func signEcdsa[P ecdsa.Point[P], H fips140.Hash](c *ecdsa.Curve[P], h func() H, sigType ecdsaSigType, q []byte, sk []byte, digest []byte) (*ecdsa.Signature, error) { priv, err := ecdsa.NewPrivateKey(c, sk, q) if err != nil { return nil, fmt.Errorf("invalid private key: %w", err) } - sig, err := ecdsa.Sign(c, h, priv, rand.Reader, digest) + var sig *ecdsa.Signature + switch sigType { + case ecdsaSigTypeNormal: + sig, err = ecdsa.Sign(c, h, priv, rand.Reader, digest) + case ecdsaSigTypeDeterministic: + sig, err = ecdsa.SignDeterministic(c, h, priv, digest) + default: + return nil, fmt.Errorf("unsupported signature type: %v", sigType) + } if err != nil { return nil, fmt.Errorf("signing failed: %w", err) } @@ -630,7 +646,7 @@ func signEcdsa[P ecdsa.Point[P], H fips140.Hash](c *ecdsa.Curve[P], h func() H, return sig, nil } -func cmdEcdsaSigGenAft() command { +func cmdEcdsaSigGenAft(sigType ecdsaSigType) command { return command{ requiredArgs: 4, // Curve name, private key, hash name, message handler: func(args [][]byte) ([][]byte, error) { @@ -661,13 +677,13 @@ func cmdEcdsaSigGenAft() command { var sig *ecdsa.Signature switch curve.Params() { case elliptic.P224().Params(): - sig, err = signEcdsa(ecdsa.P224(), newH, q, sk, digest) + sig, err = signEcdsa(ecdsa.P224(), newH, sigType, q, sk, digest) case elliptic.P256().Params(): - sig, err = signEcdsa(ecdsa.P256(), newH, q, sk, digest) + sig, err = signEcdsa(ecdsa.P256(), newH, sigType, q, sk, digest) case elliptic.P384().Params(): - sig, err = signEcdsa(ecdsa.P384(), newH, q, sk, digest) + sig, err = signEcdsa(ecdsa.P384(), newH, sigType, q, sk, digest) case elliptic.P521().Params(): - sig, err = signEcdsa(ecdsa.P521(), newH, q, sk, digest) + sig, err = signEcdsa(ecdsa.P521(), newH, sigType, q, sk, digest) default: return nil, fmt.Errorf("unsupported curve: %v", curve) } From 302bf3631493417b365d693788357973a379a03d Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Wed, 11 Dec 2024 14:48:00 -0500 Subject: [PATCH 272/397] crypto/internal/fips140test: add AES ACVP tests Adds ACVP AES test coverage for: * AES CBC * AES CTR * AES GCM (both internal & external iv gen) For AES key sizes of 128, 192, and 256 bits, based on the NIST spec: https://pages.nist.gov/ACVP/draft-celi-acvp-symmetric.html ECB mode is excluded based on upcoming policy changes forbidding its use. Internal IV gen is excluded from the go-acvp static test data since it's non-deterministic based on the DRBG. Updates #69642 Change-Id: I34f471725e2f1a2f5d32ab9877bde153abf2db0f Reviewed-on: https://go-review.googlesource.com/c/go/+/627655 Reviewed-by: Cherry Mui LUCI-TryBot-Result: Go LUCI Auto-Submit: Filippo Valsorda Reviewed-by: Filippo Valsorda Reviewed-by: Roland Shoemaker --- .../fips140test/acvp_capabilities.json | 7 +- .../fips140test/acvp_test.config.json | 6 +- src/crypto/internal/fips140test/acvp_test.go | 193 ++++++++++++++++++ 3 files changed, 204 insertions(+), 2 deletions(-) diff --git a/src/crypto/internal/fips140test/acvp_capabilities.json b/src/crypto/internal/fips140test/acvp_capabilities.json index ff94d3b6ba01ad..68d8e3bd2a6a25 100644 --- a/src/crypto/internal/fips140test/acvp_capabilities.json +++ b/src/crypto/internal/fips140test/acvp_capabilities.json @@ -48,5 +48,10 @@ {"algorithm":"ECDSA","mode":"keyVer","revision":"FIPS186-5","curve":["P-224","P-256","P-384","P-521"]}, {"algorithm":"ECDSA","mode":"sigGen","revision":"FIPS186-5","capabilities":[{"curve":["P-224","P-256","P-384","P-521"],"hashAlg":["SHA2-224","SHA2-256","SHA2-384","SHA2-512","SHA2-512/224","SHA2-512/256","SHA3-224","SHA3-256","SHA3-384","SHA3-512"]}]}, {"algorithm":"ECDSA","mode":"sigVer","revision":"FIPS186-5","capabilities":[{"curve":["P-224","P-256","P-384","P-521"],"hashAlg":["SHA2-224","SHA2-256","SHA2-384","SHA2-512","SHA2-512/224","SHA2-512/256","SHA3-224","SHA3-256","SHA3-384","SHA3-512"]}]}, - {"algorithm":"DetECDSA","mode":"sigGen","revision":"FIPS186-5","capabilities":[{"curve":["P-224","P-256","P-384","P-521"],"hashAlg":["SHA2-224","SHA2-256","SHA2-384","SHA2-512","SHA2-512/224","SHA2-512/256","SHA3-224","SHA3-256","SHA3-384","SHA3-512"]}]} + {"algorithm":"DetECDSA","mode":"sigGen","revision":"FIPS186-5","capabilities":[{"curve":["P-224","P-256","P-384","P-521"],"hashAlg":["SHA2-224","SHA2-256","SHA2-384","SHA2-512","SHA2-512/224","SHA2-512/256","SHA3-224","SHA3-256","SHA3-384","SHA3-512"]}]}, + + {"algorithm":"ACVP-AES-CBC","direction":["encrypt","decrypt"],"keyLen":[128,192,256],"revision":"1.0"}, + {"algorithm":"ACVP-AES-CTR","direction":["encrypt","decrypt"],"keyLen":[128,192,256],"payloadLen":[{"min":8,"max":128,"increment":8}],"incrementalCounter":true,"overflowCounter":true,"performCounterTests":true,"revision":"1.0"}, + {"algorithm":"ACVP-AES-GCM","direction":["encrypt","decrypt"],"keyLen":[128,192,256],"payloadLen":[{"min":0,"max":65536,"increment":8}],"aadLen":[{"min":0,"max":65536,"increment":8}],"tagLen":[96,104,112,120,128],"ivLen":[96],"ivGen":"external","revision":"1.0"}, + {"algorithm":"ACVP-AES-GCM","direction":["encrypt","decrypt"],"keyLen":[128,192,256],"payloadLen":[{"min":0,"max":65536,"increment":8}],"aadLen":[{"min":0,"max":65536,"increment":8}],"tagLen":[128],"ivLen":[96],"ivGen":"internal","ivGenMode":"8.2.2","revision":"1.0"} ] diff --git a/src/crypto/internal/fips140test/acvp_test.config.json b/src/crypto/internal/fips140test/acvp_test.config.json index 4c1879380c2c91..d994f5b7c552b0 100644 --- a/src/crypto/internal/fips140test/acvp_test.config.json +++ b/src/crypto/internal/fips140test/acvp_test.config.json @@ -31,5 +31,9 @@ {"Wrapper": "go", "In": "vectors/EDDSA.bz2", "Out": "expected/EDDSA.bz2"}, - {"Wrapper": "go", "In": "vectors/ECDSA.bz2", "Out": "expected/ECDSA.bz2"} + {"Wrapper": "go", "In": "vectors/ECDSA.bz2", "Out": "expected/ECDSA.bz2"}, + + {"Wrapper": "go", "In": "vectors/ACVP-AES-CBC.bz2", "Out": "expected/ACVP-AES-CBC.bz2"}, + {"Wrapper": "go", "In": "vectors/ACVP-AES-CTR.bz2", "Out": "expected/ACVP-AES-CTR.bz2"}, + {"Wrapper": "go", "In": "vectors/ACVP-AES-GCM.bz2", "Out": "expected/ACVP-AES-GCM.bz2"} ] \ No newline at end of file diff --git a/src/crypto/internal/fips140test/acvp_test.go b/src/crypto/internal/fips140test/acvp_test.go index 1ee13c3f1d9b90..2637ccc3e40add 100644 --- a/src/crypto/internal/fips140test/acvp_test.go +++ b/src/crypto/internal/fips140test/acvp_test.go @@ -24,6 +24,8 @@ import ( "crypto/elliptic" "crypto/internal/cryptotest" "crypto/internal/fips140" + "crypto/internal/fips140/aes" + "crypto/internal/fips140/aes/gcm" "crypto/internal/fips140/ecdsa" "crypto/internal/fips140/ed25519" "crypto/internal/fips140/edwards25519" @@ -82,6 +84,13 @@ const ( ecdsaSigTypeDeterministic ) +type aesDirection int + +const ( + aesEncrypt aesDirection = iota + aesDecrypt +) + var ( // SHA2 algorithm capabilities: // https://pages.nist.gov/ACVP/draft-celi-acvp-sha.html#section-7.2 @@ -97,6 +106,8 @@ var ( // https://pages.nist.gov/ACVP/draft-celi-acvp-eddsa.html#section-7 // ECDSA and DetECDSA algorithm capabilities: // https://pages.nist.gov/ACVP/draft-fussell-acvp-ecdsa.html#section-7 + // AES algorithm capabilities: + // https://pages.nist.gov/ACVP/draft-celi-acvp-symmetric.html#section-7.3 //go:embed acvp_capabilities.json capabilitiesJson []byte @@ -169,6 +180,15 @@ var ( "ECDSA/sigGen": cmdEcdsaSigGenAft(ecdsaSigTypeNormal), "ECDSA/sigVer": cmdEcdsaSigVerAft(), "DetECDSA/sigGen": cmdEcdsaSigGenAft(ecdsaSigTypeDeterministic), + + "AES-CBC/encrypt": cmdAesCbc(aesEncrypt), + "AES-CBC/decrypt": cmdAesCbc(aesDecrypt), + "AES-CTR/encrypt": cmdAesCtr(aesEncrypt), + "AES-CTR/decrypt": cmdAesCtr(aesDecrypt), + "AES-GCM/seal": cmdAesGcmSeal(false), + "AES-GCM/open": cmdAesGcmOpen(false), + "AES-GCM-randnonce/seal": cmdAesGcmSeal(true), + "AES-GCM-randnonce/open": cmdAesGcmOpen(true), } ) @@ -961,6 +981,179 @@ func lookupCurve(name string) (elliptic.Curve, error) { return c, nil } +func cmdAesCbc(direction aesDirection) command { + return command{ + requiredArgs: 4, // Key, ciphertext or plaintext, IV, num iterations + handler: func(args [][]byte) ([][]byte, error) { + if direction != aesEncrypt && direction != aesDecrypt { + panic("invalid AES direction") + } + + key := args[0] + input := args[1] + iv := args[2] + numIterations := binary.LittleEndian.Uint32(args[3]) + + blockCipher, err := aes.New(key) + if err != nil { + return nil, fmt.Errorf("creating AES block cipher with key len %d: %w", len(key), err) + } + + if len(input)%blockCipher.BlockSize() != 0 || len(input) == 0 { + return nil, fmt.Errorf("invalid ciphertext/plaintext size %d: not a multiple of block size %d", + len(input), blockCipher.BlockSize()) + } + + if blockCipher.BlockSize() != len(iv) { + return nil, fmt.Errorf("invalid IV size: expected %d, got %d", blockCipher.BlockSize(), len(iv)) + } + + result := make([]byte, len(input)) + prevResult := make([]byte, len(input)) + prevInput := make([]byte, len(input)) + + for i := uint32(0); i < numIterations; i++ { + copy(prevResult, result) + + if i > 0 { + if direction == aesEncrypt { + copy(iv, result) + } else { + copy(iv, prevInput) + } + } + + if direction == aesEncrypt { + cbcEnc := aes.NewCBCEncrypter(blockCipher, [16]byte(iv)) + cbcEnc.CryptBlocks(result, input) + } else { + cbcDec := aes.NewCBCDecrypter(blockCipher, [16]byte(iv)) + cbcDec.CryptBlocks(result, input) + } + + if direction == aesDecrypt { + copy(prevInput, input) + } + + if i == 0 { + copy(input, iv) + } else { + copy(input, prevResult) + } + } + + return [][]byte{result, prevResult}, nil + }, + } +} + +func cmdAesCtr(direction aesDirection) command { + return command{ + requiredArgs: 4, // Key, ciphertext or plaintext, initial counter, num iterations (constant 1) + handler: func(args [][]byte) ([][]byte, error) { + if direction != aesEncrypt && direction != aesDecrypt { + panic("invalid AES direction") + } + + key := args[0] + input := args[1] + iv := args[2] + numIterations := binary.LittleEndian.Uint32(args[3]) + if numIterations != 1 { + return nil, fmt.Errorf("invalid num iterations: expected 1, got %d", numIterations) + } + + if len(iv) != aes.BlockSize { + return nil, fmt.Errorf("invalid IV size: expected %d, got %d", aes.BlockSize, len(iv)) + } + + blockCipher, err := aes.New(key) + if err != nil { + return nil, fmt.Errorf("creating AES block cipher with key len %d: %w", len(key), err) + } + + result := make([]byte, len(input)) + stream := aes.NewCTR(blockCipher, iv) + stream.XORKeyStream(result, input) + + return [][]byte{result}, nil + }, + } +} + +func cmdAesGcmSeal(randNonce bool) command { + return command{ + requiredArgs: 5, // tag len, key, plaintext, nonce (empty for randNonce), additional data + handler: func(args [][]byte) ([][]byte, error) { + tagLen := binary.LittleEndian.Uint32(args[0]) + key := args[1] + plaintext := args[2] + nonce := args[3] + additionalData := args[4] + + blockCipher, err := aes.New(key) + if err != nil { + return nil, fmt.Errorf("creating AES block cipher with key len %d: %w", len(key), err) + } + + aesGCM, err := gcm.New(blockCipher, 12, int(tagLen)) + if err != nil { + return nil, fmt.Errorf("creating AES-GCM with tag len %d: %w", tagLen, err) + } + + var ct []byte + if !randNonce { + ct = aesGCM.Seal(nil, nonce, plaintext, additionalData) + } else { + var internalNonce [12]byte + ct = make([]byte, len(plaintext)+16) + gcm.SealWithRandomNonce(aesGCM, internalNonce[:], ct, plaintext, additionalData) + // acvptool expects the internally generated nonce to be appended to the end of the ciphertext. + ct = append(ct, internalNonce[:]...) + } + + return [][]byte{ct}, nil + }, + } +} + +func cmdAesGcmOpen(randNonce bool) command { + return command{ + requiredArgs: 5, // tag len, key, ciphertext, nonce (empty for randNonce), additional data + handler: func(args [][]byte) ([][]byte, error) { + + tagLen := binary.LittleEndian.Uint32(args[0]) + key := args[1] + ciphertext := args[2] + nonce := args[3] + additionalData := args[4] + + blockCipher, err := aes.New(key) + if err != nil { + return nil, fmt.Errorf("creating AES block cipher with key len %d: %w", len(key), err) + } + + aesGCM, err := gcm.New(blockCipher, 12, int(tagLen)) + if err != nil { + return nil, fmt.Errorf("creating AES-GCM with tag len %d: %w", tagLen, err) + } + + if randNonce { + // for randNonce tests acvptool appends the nonce to the end of the ciphertext. + nonce = ciphertext[len(ciphertext)-12:] + ciphertext = ciphertext[:len(ciphertext)-12] + } + + pt, err := aesGCM.Open(nil, nonce, ciphertext, additionalData) + if err != nil { + return [][]byte{{0}, nil}, nil + } + + return [][]byte{{1}, pt}, nil + }, + } +} + func TestACVP(t *testing.T) { testenv.SkipIfShortAndSlow(t) From 580a383103f2bc67955a146a2d45b7c0c98dae8a Mon Sep 17 00:00:00 2001 From: qmuntal Date: Thu, 6 Feb 2025 10:55:59 +0100 Subject: [PATCH 273/397] {all,clean,make,race,run}.bat: use || instead of "if errorlevel 1" "if errorlevel 1" is and old construct that returns true if the errorlevel is greater than or equal to 1. There are better alternatives since Windows NT. For example, the || operator runs the RHS operand if the preceding command failed, determined by checking that the errorlevel is different from 0. This approach is more robust -it also works with negative errorlevels- and is less verbose. Change-Id: I2070d654d8f9dd41a6cd586ba5ad5f4fea0638ed Reviewed-on: https://go-review.googlesource.com/c/go/+/647136 Reviewed-by: Cherry Mui LUCI-TryBot-Result: Go LUCI Reviewed-by: Damien Neil --- src/all.bat | 6 ++---- src/clean.bat | 3 +-- src/make.bat | 9 +++------ src/race.bat | 16 +++++----------- src/run.bat | 6 ++---- 5 files changed, 13 insertions(+), 27 deletions(-) diff --git a/src/all.bat b/src/all.bat index 0c4d5de70c6cc0..483151b8931dff 100644 --- a/src/all.bat +++ b/src/all.bat @@ -11,10 +11,8 @@ echo all.bat must be run from go\src exit /b 1 :ok -call .\make.bat --no-banner --no-local -if errorlevel 1 goto fail -call .\run.bat --no-rebuild -if errorlevel 1 goto fail +call .\make.bat --no-banner --no-local || goto fail +call .\run.bat --no-rebuild || goto fail "%GOTOOLDIR%/dist" banner goto :eof diff --git a/src/clean.bat b/src/clean.bat index ceba3a56cf44e8..51fa857b7c7ac7 100644 --- a/src/clean.bat +++ b/src/clean.bat @@ -6,8 +6,7 @@ setlocal -go tool dist env -w -p >env.bat -if errorlevel 1 goto fail +go tool dist env -w -p >env.bat || goto fail call .\env.bat del env.bat echo. diff --git a/src/make.bat b/src/make.bat index 3a72a59470e565..57e4e5f80cc9af 100644 --- a/src/make.bat +++ b/src/make.bat @@ -101,11 +101,9 @@ echo Building Go cmd/dist using %GOROOT_BOOTSTRAP%. (%GOROOT_BOOTSTRAP_VERSION%) if x%vflag==x-v echo cmd/dist set GOROOT=%GOROOT_BOOTSTRAP% set GOBIN= -"%GOROOT_BOOTSTRAP%\bin\go.exe" build -o cmd\dist\dist.exe .\cmd\dist +"%GOROOT_BOOTSTRAP%\bin\go.exe" build -o cmd\dist\dist.exe .\cmd\dist || goto fail endlocal -if errorlevel 1 goto fail -.\cmd\dist\dist.exe env -w -p >env.bat -if errorlevel 1 goto fail +.\cmd\dist\dist.exe env -w -p >env.bat || goto fail call .\env.bat del env.bat if x%vflag==x-v echo. @@ -148,8 +146,7 @@ if x%4==x--distpack set bootstrapflags=%bootstrapflags% -distpack :: Run dist bootstrap to complete make.bash. :: Bootstrap installs a proper cmd/dist, built with the new toolchain. :: Throw ours, built with the bootstrap toolchain, away after bootstrap. -.\cmd\dist\dist.exe bootstrap -a %vflag% %bootstrapflags% -if errorlevel 1 goto fail +.\cmd\dist\dist.exe bootstrap -a %vflag% %bootstrapflags% || goto fail del .\cmd\dist\dist.exe goto :eof diff --git a/src/race.bat b/src/race.bat index 64510b60129e9d..2f6ba914758ef8 100644 --- a/src/race.bat +++ b/src/race.bat @@ -15,10 +15,8 @@ exit /b 1 :ok set GOROOT=%CD%\.. -call .\make.bat --dist-tool >NUL -if errorlevel 1 goto fail -.\cmd\dist\dist.exe env -w -p >env.bat -if errorlevel 1 goto fail +call .\make.bat --dist-tool >NUL || goto fail +.\cmd\dist\dist.exe env -w -p >env.bat || goto fail call .\env.bat del env.bat @@ -27,15 +25,11 @@ echo Race detector is only supported on windows/amd64. goto fail :continue -call .\make.bat --no-banner --no-local -if errorlevel 1 goto fail +call .\make.bat --no-banner --no-local || goto fail echo # go install -race std -go install -race std -if errorlevel 1 goto fail +go install -race std || goto fail +go tool dist test -race || goto fail -go tool dist test -race - -if errorlevel 1 goto fail echo All tests passed. goto :eof diff --git a/src/run.bat b/src/run.bat index 6a0ffe3af905ac..3e7b1a1b0c25b0 100644 --- a/src/run.bat +++ b/src/run.bat @@ -12,14 +12,12 @@ goto fail setlocal set GOENV=off -..\bin\go tool dist env > env.bat -if errorlevel 1 goto fail +..\bin\go tool dist env > env.bat || goto fail call .\env.bat del env.bat set GOPATH=c:\nonexist-gopath -..\bin\go tool dist test --rebuild %* -if errorlevel 1 goto fail +..\bin\go tool dist test --rebuild %* || goto fail goto :eof :fail From 1bfbefa1593638dc9ff78e4d2959c865cb1c66a6 Mon Sep 17 00:00:00 2001 From: qmuntal Date: Thu, 6 Feb 2025 11:13:19 +0100 Subject: [PATCH 274/397] make.bat: pass through all arguments to "dist bootstrap" nolocal is (almost) no longer needed after CL 647115. If we remove it, then we can pass through all arguments to the Go command, which is useful for running tests with additional flags, like -json or -v. This CL also updates all.bat to use "go tool dist" instead of "%GOTOOLDIR%/dist", as %GOTOOLDIR% is no longer set after making make.bat uncoditionally set nolocal. Change-Id: I97dc687faa5686d023f7d7d2b96637295995fe67 Reviewed-on: https://go-review.googlesource.com/c/go/+/647117 Reviewed-by: Damien Neil Reviewed-by: Cherry Mui Auto-Submit: Damien Neil LUCI-TryBot-Result: Go LUCI --- src/all.bat | 4 ++-- src/make.bat | 39 +-------------------------------------- src/race.bat | 2 +- 3 files changed, 4 insertions(+), 41 deletions(-) diff --git a/src/all.bat b/src/all.bat index 483151b8931dff..cb4536284e1a58 100644 --- a/src/all.bat +++ b/src/all.bat @@ -11,9 +11,9 @@ echo all.bat must be run from go\src exit /b 1 :ok -call .\make.bat --no-banner --no-local || goto fail +call .\make.bat --no-banner || goto fail call .\run.bat --no-rebuild || goto fail -"%GOTOOLDIR%/dist" banner +..\bin\go tool dist banner goto :eof :fail diff --git a/src/make.bat b/src/make.bat index 57e4e5f80cc9af..0d5dd2761a7155 100644 --- a/src/make.bat +++ b/src/make.bat @@ -34,18 +34,7 @@ @echo off -:: Keep environment variables within this script -:: unless invoked with --no-local. -if x%1==x-no-local goto nolocal -if x%2==x-no-local goto nolocal -if x%3==x-no-local goto nolocal -if x%4==x-no-local goto nolocal -if x%1==x--no-local goto nolocal -if x%2==x--no-local goto nolocal -if x%3==x--no-local goto nolocal -if x%4==x--no-local goto nolocal setlocal -:nolocal if exist make.bat goto ok echo Must run make.bat from Go src directory. @@ -117,36 +106,10 @@ if x%2==x--dist-tool goto copydist if x%3==x--dist-tool goto copydist if x%4==x--dist-tool goto copydist -set bootstrapflags= -if x%1==x-no-clean set bootstrapflags=-no-clean -if x%2==x-no-clean set bootstrapflags=-no-clean -if x%3==x-no-clean set bootstrapflags=-no-clean -if x%4==x-no-clean set bootstrapflags=-no-clean -if x%1==x--no-clean set bootstrapflags=-no-clean -if x%2==x--no-clean set bootstrapflags=-no-clean -if x%3==x--no-clean set bootstrapflags=-no-clean -if x%4==x--no-clean set bootstrapflags=-no-clean -if x%1==x-no-banner set bootstrapflags=%bootstrapflags% -no-banner -if x%2==x-no-banner set bootstrapflags=%bootstrapflags% -no-banner -if x%3==x-no-banner set bootstrapflags=%bootstrapflags% -no-banner -if x%4==x-no-banner set bootstrapflags=%bootstrapflags% -no-banner -if x%1==x--no-banner set bootstrapflags=%bootstrapflags% -no-banner -if x%2==x--no-banner set bootstrapflags=%bootstrapflags% -no-banner -if x%3==x--no-banner set bootstrapflags=%bootstrapflags% -no-banner -if x%4==x--no-banner set bootstrapflags=%bootstrapflags% -no-banner -if x%1==x-distpack set bootstrapflags=%bootstrapflags% -distpack -if x%2==x-distpack set bootstrapflags=%bootstrapflags% -distpack -if x%3==x-distpack set bootstrapflags=%bootstrapflags% -distpack -if x%4==x-distpack set bootstrapflags=%bootstrapflags% -distpack -if x%1==x--distpack set bootstrapflags=%bootstrapflags% -distpack -if x%2==x--distpack set bootstrapflags=%bootstrapflags% -distpack -if x%3==x--distpack set bootstrapflags=%bootstrapflags% -distpack -if x%4==x--distpack set bootstrapflags=%bootstrapflags% -distpack - :: Run dist bootstrap to complete make.bash. :: Bootstrap installs a proper cmd/dist, built with the new toolchain. :: Throw ours, built with the bootstrap toolchain, away after bootstrap. -.\cmd\dist\dist.exe bootstrap -a %vflag% %bootstrapflags% || goto fail +.\cmd\dist\dist.exe bootstrap -a %* || goto fail del .\cmd\dist\dist.exe goto :eof diff --git a/src/race.bat b/src/race.bat index 2f6ba914758ef8..7f1e0a1987230f 100644 --- a/src/race.bat +++ b/src/race.bat @@ -25,7 +25,7 @@ echo Race detector is only supported on windows/amd64. goto fail :continue -call .\make.bat --no-banner --no-local || goto fail +call .\make.bat --no-banner || goto fail echo # go install -race std go install -race std || goto fail go tool dist test -race || goto fail From cb47156e90cac6b1030d747f1ccd433c00494dfc Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Thu, 30 Jan 2025 10:55:36 -0800 Subject: [PATCH 275/397] testing/synctest: add an example of testing networked code For #67434 Change-Id: If7dcd3bf7bb69e1730856405d55cffc72ce0e132 Reviewed-on: https://go-review.googlesource.com/c/go/+/645675 Reviewed-by: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Auto-Submit: Damien Neil --- src/testing/synctest/http_example_test.go | 101 ++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 src/testing/synctest/http_example_test.go diff --git a/src/testing/synctest/http_example_test.go b/src/testing/synctest/http_example_test.go new file mode 100644 index 00000000000000..ec503a9fa26aeb --- /dev/null +++ b/src/testing/synctest/http_example_test.go @@ -0,0 +1,101 @@ +// Copyright 2025 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. + +//go:build goexperiment.synctest + +package synctest_test + +import ( + "bufio" + "bytes" + "context" + "fmt" + "io" + "net" + "net/http" + "strings" + "testing/synctest" + "time" +) + +// This example demonstrates testing [http.Transport]'s 100 Continue handling. +// +// An HTTP client sending a request can include an "Expect: 100-continue" header +// to tell the server that the client has additional data to send. +// The server may then respond with an 100 Continue information response +// to request the data, or some other status to tell the client the data is not needed. +// For example, a client uploading a large file might use this feature to confirm +// that the server is willing to accept the file before sending it. +// +// This test confirms that when sending an "Expect: 100-continue" header +// the HTTP client does not send a request's content before the server requests it, +// and that it does send the content after receiving a 100 Continue response. +func Example_httpTransport100Continue() { + synctest.Run(func() { + // Create an in-process fake network connection. + // We cannot use a loopback network connection for this test, + // because goroutines blocked on network I/O prevent a synctest + // bubble from becoming idle. + srvConn, cliConn := net.Pipe() + defer cliConn.Close() + defer srvConn.Close() + + tr := &http.Transport{ + // Use the fake network connection created above. + DialContext: func(ctx context.Context, network, address string) (net.Conn, error) { + return cliConn, nil + }, + // Enable "Expect: 100-continue" handling. + ExpectContinueTimeout: 5 * time.Second, + } + + // Send a request with the "Expect: 100-continue" header set. + // Send it in a new goroutine, since it won't complete until the end of the test. + body := "request body" + go func() { + req, err := http.NewRequest("PUT", "http://test.tld/", strings.NewReader(body)) + if err != nil { + panic(err) + } + req.Header.Set("Expect", "100-continue") + resp, err := tr.RoundTrip(req) + if err != nil { + fmt.Printf("RoundTrip: unexpected error %v\n", err) + } else { + resp.Body.Close() + } + }() + + // Read the request headers sent by the client. + req, err := http.ReadRequest(bufio.NewReader(srvConn)) + if err != nil { + fmt.Printf("ReadRequest: %v\n", err) + return + } + + // Start a new goroutine copying the body sent by the client into a buffer. + // Wait for all goroutines in the bubble to block and verify that we haven't + // read anything from the client yet. + var gotBody bytes.Buffer + go io.Copy(&gotBody, req.Body) + synctest.Wait() + fmt.Printf("before sending 100 Continue, read body: %q\n", gotBody.String()) + + // Write a "100 Continue" response to the client and verify that + // it sends the request body. + srvConn.Write([]byte("HTTP/1.1 100 Continue\r\n\r\n")) + synctest.Wait() + fmt.Printf("after sending 100 Continue, read body: %q\n", gotBody.String()) + + // Finish up by sending the "200 OK" response to conclude the request. + srvConn.Write([]byte("HTTP/1.1 200 OK\r\n\r\n")) + + // We started several goroutines during the test. + // The synctest.Run call will wait for all of them to exit before returning. + }) + + // Output: + // before sending 100 Continue, read body: "" + // after sending 100 Continue, read body: "request body" +} From d7f6f6fd54bb888606d882cd73df9dcac229b80a Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 6 Feb 2025 18:04:00 -0800 Subject: [PATCH 276/397] bufio: skip network test if unixpacket socket not supported Change-Id: I03434fdc4916fc8d195de2617edc28ec4b66a172 Reviewed-on: https://go-review.googlesource.com/c/go/+/647535 Auto-Submit: Ian Lance Taylor Reviewed-by: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Reviewed-by: Damien Neil --- src/bufio/net_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bufio/net_test.go b/src/bufio/net_test.go index 9c609fbccaeedb..d3b47e4cb99a39 100644 --- a/src/bufio/net_test.go +++ b/src/bufio/net_test.go @@ -30,7 +30,7 @@ func TestCopyUnixpacket(t *testing.T) { } server, err := net.ListenUnix("unixpacket", addr) if err != nil { - t.Fatal(err) + t.Skipf("skipping test because opening a unixpacket socket failed: %v", err) } // Start a goroutine for the server to accept one connection From ca1cfea3710a5873132d0c5f6e3710804714efd4 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Thu, 9 Jan 2025 18:17:49 +0000 Subject: [PATCH 277/397] internal/trace: refactor how experimental batches are exposed This change modifies how per-generation experimental batches are exposed. Rather than expose them on the ExperimentalEvent, it exposes it as part of the Sync event, so it's clear to the caller when the information becomes relevant and when it should be parsed. This change also adds a field to each ExperimentalEvent indicating which experiment the event is a part of. Because this information needs to appear *before* a generation is observed, we now ensure there is a sync event both before and after each generation. This means the final sync event is now a special case; previously we would only emit a sync event after each generation. This change is based on feedback from Austin Clements on the experimental events functionality. For #62627. Change-Id: I48b0fe12b22abb7ac8820a9e73447bfed8419856 Reviewed-on: https://go-review.googlesource.com/c/go/+/644215 Auto-Submit: Michael Knyszek Reviewed-by: Michael Pratt LUCI-TryBot-Result: Go LUCI --- src/internal/trace/base.go | 5 +- src/internal/trace/event.go | 60 ++++++++++------ src/internal/trace/event/go122/event.go | 8 +++ src/internal/trace/event_test.go | 2 +- src/internal/trace/gc.go | 10 +-- src/internal/trace/generation.go | 25 ++++--- .../trace/internal/oldtrace/parser.go | 8 +++ src/internal/trace/reader.go | 69 ++++++++++++------- src/internal/trace/testtrace/validation.go | 29 ++++---- src/runtime/crash_test.go | 7 +- 10 files changed, 141 insertions(+), 82 deletions(-) diff --git a/src/internal/trace/base.go b/src/internal/trace/base.go index 4f4ce486305434..5d707bd6cc376b 100644 --- a/src/internal/trace/base.go +++ b/src/internal/trace/base.go @@ -58,9 +58,8 @@ type evTable struct { extraStringIDs map[string]extraStringID nextExtra extraStringID - // expData contains extra unparsed data that is accessible - // only to ExperimentEvent via an EventExperimental event. - expData map[event.Experiment]*ExperimentalData + // expBatches contains extra unparsed data relevant to a specific experiment. + expBatches map[event.Experiment][]ExperimentalBatch } // addExtraString adds an extra string to the evTable and returns diff --git a/src/internal/trace/event.go b/src/internal/trace/event.go index a5c5aec2f8a8ba..c86c3c0c99c0b1 100644 --- a/src/internal/trace/event.go +++ b/src/internal/trace/event.go @@ -313,26 +313,15 @@ type ExperimentalEvent struct { // Name is the name of the event. Name string + // Experiment is the name of the experiment this event is a part of. + Experiment string + // ArgNames is the names of the event's arguments in order. // This may refer to a globally shared slice. Copy before mutating. ArgNames []string // Args contains the event's arguments. Args []uint64 - - // Data is additional unparsed data that is associated with the experimental event. - // Data is likely to be shared across many ExperimentalEvents, so callers that parse - // Data are encouraged to cache the parse result and look it up by the value of Data. - Data *ExperimentalData -} - -// ExperimentalData represents some raw and unparsed sidecar data present in the trace that is -// associated with certain kinds of experimental events. For example, this data may contain -// tables needed to interpret ExperimentalEvent arguments, or the ExperimentEvent could just be -// a placeholder for a differently encoded event that's actually present in the experimental data. -type ExperimentalData struct { - // Batches contain the actual experimental data, along with metadata about each batch. - Batches []ExperimentalBatch } // ExperimentalBatch represents a packet of unparsed data along with metadata about that packet. @@ -658,6 +647,35 @@ func (e Event) StateTransition() StateTransition { return s } +// Sync returns details that are relevant for the following events, up to but excluding the +// next EventSync event. +func (e Event) Sync() Sync { + if e.Kind() != EventSync { + panic("Sync called on non-Sync event") + } + var expBatches map[string][]ExperimentalBatch + if e.table != nil { + expBatches = make(map[string][]ExperimentalBatch) + for exp, batches := range e.table.expBatches { + expBatches[go122.Experiments()[exp]] = batches + } + } + return Sync{ + N: int(e.base.args[0]), + ExperimentalBatches: expBatches, + } +} + +// Sync contains details potentially relevant to all the following events, up to but excluding +// the next EventSync event. +type Sync struct { + // N indicates that this is the Nth sync event in the trace. + N int + + // ExperimentalBatches contain all the unparsed batches of data for a given experiment. + ExperimentalBatches map[string][]ExperimentalBatch +} + // Experimental returns a view of the raw event for an experimental event. // // Panics if Kind != EventExperimental. @@ -668,10 +686,10 @@ func (e Event) Experimental() ExperimentalEvent { spec := go122.Specs()[e.base.typ] argNames := spec.Args[1:] // Skip timestamp; already handled. return ExperimentalEvent{ - Name: spec.Name, - ArgNames: argNames, - Args: e.base.args[:len(argNames)], - Data: e.table.expData[spec.Experiment], + Name: spec.Name, + Experiment: go122.Experiments()[spec.Experiment], + ArgNames: argNames, + Args: e.base.args[:len(argNames)], } } @@ -848,8 +866,8 @@ func (e Event) validateTableIDs() error { return nil } -func syncEvent(table *evTable, ts Time) Event { - return Event{ +func syncEvent(table *evTable, ts Time, n int) Event { + ev := Event{ table: table, ctx: schedCtx{ G: NoGoroutine, @@ -861,4 +879,6 @@ func syncEvent(table *evTable, ts Time) Event { time: ts, }, } + ev.base.args[0] = uint64(n) + return ev } diff --git a/src/internal/trace/event/go122/event.go b/src/internal/trace/event/go122/event.go index f6075e3ed51413..f22b23ddbb44fa 100644 --- a/src/internal/trace/event/go122/event.go +++ b/src/internal/trace/event/go122/event.go @@ -86,6 +86,14 @@ const ( AllocFree event.Experiment = 1 + iota ) +func Experiments() []string { + return experiments[:] +} + +var experiments = [...]string{ + AllocFree: "AllocFree", +} + // Experimental events. const ( _ event.Type = 127 + iota diff --git a/src/internal/trace/event_test.go b/src/internal/trace/event_test.go index c81a45185dc475..d39d6b75bd7613 100644 --- a/src/internal/trace/event_test.go +++ b/src/internal/trace/event_test.go @@ -8,7 +8,7 @@ import "testing" func TestPanicEvent(t *testing.T) { // Use a sync event for this because it doesn't have any extra metadata. - ev := syncEvent(nil, 0) + ev := syncEvent(nil, 0, 0) mustPanic(t, func() { _ = ev.Range() diff --git a/src/internal/trace/gc.go b/src/internal/trace/gc.go index bf271ed73baf20..46890e784df24c 100644 --- a/src/internal/trace/gc.go +++ b/src/internal/trace/gc.go @@ -75,7 +75,7 @@ func MutatorUtilizationV2(events []Event, flags UtilFlags) [][]MutatorUtil { states := make(map[GoID]GoState) bgMark := make(map[GoID]bool) procs := []procsCount{} - seenSync := false + nSync := 0 // Helpers. handleSTW := func(r Range) bool { @@ -97,7 +97,7 @@ func MutatorUtilizationV2(events []Event, flags UtilFlags) [][]MutatorUtil { // Process the event. switch ev.Kind() { case EventSync: - seenSync = true + nSync = ev.Sync().N case EventMetric: m := ev.Metric() if m.Name != "/sched/gomaxprocs:threads" { @@ -135,9 +135,9 @@ func MutatorUtilizationV2(events []Event, flags UtilFlags) [][]MutatorUtil { switch ev.Kind() { case EventRangeActive: - if seenSync { - // If we've seen a sync, then we can be sure we're not finding out about - // something late; we have complete information after that point, and these + if nSync > 1 { + // If we've seen a full generation, then we can be sure we're not finding out + // about something late; we have complete information after that point, and these // active events will just be redundant. break } diff --git a/src/internal/trace/generation.go b/src/internal/trace/generation.go index 98bbf4398569f9..42c2526a202968 100644 --- a/src/internal/trace/generation.go +++ b/src/internal/trace/generation.go @@ -27,6 +27,7 @@ type generation struct { batches map[ThreadID][]batch batchMs []ThreadID cpuSamples []cpuSample + minTs timestamp *evTable } @@ -100,6 +101,9 @@ func readGeneration(r *bufio.Reader, spill *spilledBatch) (*generation, *spilled // problem as soon as we see it. return nil, nil, fmt.Errorf("generations out of order") } + if g.minTs == 0 || b.time < g.minTs { + g.minTs = b.time + } if err := processBatch(g, b); err != nil { return nil, nil, err } @@ -163,10 +167,10 @@ func processBatch(g *generation, b batch) error { } g.freq = freq case b.exp != event.NoExperiment: - if g.expData == nil { - g.expData = make(map[event.Experiment]*ExperimentalData) + if g.expBatches == nil { + g.expBatches = make(map[event.Experiment][]ExperimentalBatch) } - if err := addExperimentalData(g.expData, b); err != nil { + if err := addExperimentalBatch(g.expBatches, b); err != nil { return err } default: @@ -435,18 +439,13 @@ func parseFreq(b batch) (frequency, error) { return frequency(1.0 / (float64(f) / 1e9)), nil } -// addExperimentalData takes an experimental batch and adds it to the ExperimentalData -// for the experiment its a part of. -func addExperimentalData(expData map[event.Experiment]*ExperimentalData, b batch) error { +// addExperimentalBatch takes an experimental batch and adds it to the list of experimental +// batches for the experiment its a part of. +func addExperimentalBatch(expBatches map[event.Experiment][]ExperimentalBatch, b batch) error { if b.exp == event.NoExperiment { - return fmt.Errorf("internal error: addExperimentalData called on non-experimental batch") - } - ed, ok := expData[b.exp] - if !ok { - ed = new(ExperimentalData) - expData[b.exp] = ed + return fmt.Errorf("internal error: addExperimentalBatch called on non-experimental batch") } - ed.Batches = append(ed.Batches, ExperimentalBatch{ + expBatches[b.exp] = append(expBatches[b.exp], ExperimentalBatch{ Thread: b.m, Data: b.data, }) diff --git a/src/internal/trace/internal/oldtrace/parser.go b/src/internal/trace/internal/oldtrace/parser.go index 0365eeff70b0c8..5b12df7e2b9093 100644 --- a/src/internal/trace/internal/oldtrace/parser.go +++ b/src/internal/trace/internal/oldtrace/parser.go @@ -343,6 +343,14 @@ func (l *Events) Pop() (*Event, bool) { return ptr, true } +func (l *Events) Peek() (*Event, bool) { + if l.off == l.n { + return nil, false + } + a, b := l.index(l.off) + return &l.buckets[a][b], true +} + func (l *Events) All() func(yield func(ev *Event) bool) { return func(yield func(ev *Event) bool) { for i := 0; i < l.Len(); i++ { diff --git a/src/internal/trace/reader.go b/src/internal/trace/reader.go index 81157292fb3f08..149a88b7b42e5e 100644 --- a/src/internal/trace/reader.go +++ b/src/internal/trace/reader.go @@ -17,16 +17,21 @@ import ( ) // Reader reads a byte stream, validates it, and produces trace events. +// +// Provided the trace is non-empty the Reader always produces a Sync +// event as the first event, and a Sync event as the last event. +// (There may also be any number of Sync events in the middle, too.) type Reader struct { - r *bufio.Reader - lastTs Time - gen *generation - spill *spilledBatch - spillErr error // error from reading spill - frontier []*batchCursor - cpuSamples []cpuSample - order ordering - emittedSync bool + r *bufio.Reader + lastTs Time + gen *generation + spill *spilledBatch + spillErr error // error from reading spill + frontier []*batchCursor + cpuSamples []cpuSample + order ordering + syncs int + done bool go121Events *oldTraceConverter } @@ -56,8 +61,6 @@ func NewReader(r io.Reader) (*Reader, error) { gStates: make(map[GoID]*gState), activeTasks: make(map[TaskID]taskState), }, - // Don't emit a sync event when we first go to emit events. - emittedSync: true, }, nil default: return nil, fmt.Errorf("unknown or unsupported version go 1.%d", v) @@ -66,13 +69,30 @@ func NewReader(r io.Reader) (*Reader, error) { // ReadEvent reads a single event from the stream. // -// If the stream has been exhausted, it returns an invalid -// event and io.EOF. +// If the stream has been exhausted, it returns an invalid event and io.EOF. func (r *Reader) ReadEvent() (e Event, err error) { + // Return only io.EOF if we're done. + if r.done { + return Event{}, io.EOF + } + + // Handle old execution traces. if r.go121Events != nil { + if r.syncs == 0 { + // Always emit a sync event first, if we have any events at all. + ev, ok := r.go121Events.events.Peek() + if ok { + r.syncs++ + return syncEvent(r.go121Events.evt, Time(ev.Ts-1), r.syncs), nil + } + } ev, err := r.go121Events.next() - if err != nil { - // XXX do we have to emit an EventSync when the trace is done? + if err == io.EOF { + // Always emit a sync event at the end. + r.done = true + r.syncs++ + return syncEvent(nil, r.go121Events.lastTs+1, r.syncs), nil + } else if err != nil { return Event{}, err } return ev, nil @@ -115,10 +135,6 @@ func (r *Reader) ReadEvent() (e Event, err error) { // Check if we need to refresh the generation. if len(r.frontier) == 0 && len(r.cpuSamples) == 0 { - if !r.emittedSync { - r.emittedSync = true - return syncEvent(r.gen.evTable, r.lastTs), nil - } if r.spillErr != nil { return Event{}, r.spillErr } @@ -127,8 +143,10 @@ func (r *Reader) ReadEvent() (e Event, err error) { // and there's nothing left in the frontier, and // there's no spilled batch, indicating that there's // no further generation, it means we're done. - // Return io.EOF. - return Event{}, io.EOF + // Emit the final sync event. + r.done = true + r.syncs++ + return syncEvent(nil, r.lastTs, r.syncs), nil } // Read the next generation. var err error @@ -155,9 +173,12 @@ func (r *Reader) ReadEvent() (e Event, err error) { } r.frontier = heapInsert(r.frontier, bc) } - - // Reset emittedSync. - r.emittedSync = false + r.syncs++ + if r.lastTs == 0 { + r.lastTs = r.gen.freq.mul(r.gen.minTs) + } + // Always emit a sync event at the beginning of the generation. + return syncEvent(r.gen.evTable, r.lastTs, r.syncs), nil } tryAdvance := func(i int) (bool, error) { bc := r.frontier[i] diff --git a/src/internal/trace/testtrace/validation.go b/src/internal/trace/testtrace/validation.go index 59ff19e6106e9b..3d12f75c499ff6 100644 --- a/src/internal/trace/testtrace/validation.go +++ b/src/internal/trace/testtrace/validation.go @@ -14,14 +14,14 @@ import ( // Validator is a type used for validating a stream of trace.Events. type Validator struct { - lastTs trace.Time - gs map[trace.GoID]*goState - ps map[trace.ProcID]*procState - ms map[trace.ThreadID]*schedContext - ranges map[trace.ResourceID][]string - tasks map[trace.TaskID]string - seenSync bool - Go121 bool + lastTs trace.Time + gs map[trace.GoID]*goState + ps map[trace.ProcID]*procState + ms map[trace.ThreadID]*schedContext + ranges map[trace.ResourceID][]string + tasks map[trace.TaskID]string + nSync int + Go121 bool } type schedContext struct { @@ -60,7 +60,7 @@ func (v *Validator) Event(ev trace.Event) error { // Validate timestamp order. if v.lastTs != 0 { if ev.Time() <= v.lastTs { - e.Errorf("timestamp out-of-order for %+v", ev) + e.Errorf("timestamp out-of-order (want > %v) for %+v", v.lastTs, ev) } else { v.lastTs = ev.Time() } @@ -73,8 +73,11 @@ func (v *Validator) Event(ev trace.Event) error { switch ev.Kind() { case trace.EventSync: - // Just record that we've seen a Sync at some point. - v.seenSync = true + s := ev.Sync() + if s.N != v.nSync+1 { + e.Errorf("sync count is not sequential: expected %d, got %d", v.nSync+1, s.N) + } + v.nSync = s.N case trace.EventMetric: m := ev.Metric() if !strings.Contains(m.Name, ":") { @@ -140,7 +143,7 @@ func (v *Validator) Event(ev trace.Event) error { if new == trace.GoUndetermined { e.Errorf("transition to undetermined state for goroutine %d", id) } - if v.seenSync && old == trace.GoUndetermined { + if v.nSync > 1 && old == trace.GoUndetermined { e.Errorf("undetermined goroutine %d after first global sync", id) } if new == trace.GoNotExist && v.hasAnyRange(trace.MakeResourceID(id)) { @@ -193,7 +196,7 @@ func (v *Validator) Event(ev trace.Event) error { if new == trace.ProcUndetermined { e.Errorf("transition to undetermined state for proc %d", id) } - if v.seenSync && old == trace.ProcUndetermined { + if v.nSync > 1 && old == trace.ProcUndetermined { e.Errorf("undetermined proc %d after first global sync", id) } if new == trace.ProcNotExist && v.hasAnyRange(trace.MakeResourceID(id)) { diff --git a/src/runtime/crash_test.go b/src/runtime/crash_test.go index c390218355c57f..fcf5ef85ce7dbd 100644 --- a/src/runtime/crash_test.go +++ b/src/runtime/crash_test.go @@ -990,7 +990,8 @@ func TestCrashWhileTracing(t *testing.T) { if err != nil { t.Fatalf("could not create trace.NewReader: %v", err) } - var seen, seenSync bool + var seen bool + nSync := 0 i := 1 loop: for ; ; i++ { @@ -1005,7 +1006,7 @@ loop: } switch ev.Kind() { case traceparse.EventSync: - seenSync = true + nSync = ev.Sync().N case traceparse.EventLog: v := ev.Log() if v.Category == "xyzzy-cat" && v.Message == "xyzzy-msg" { @@ -1019,7 +1020,7 @@ loop: if err := cmd.Wait(); err == nil { t.Error("the process should have panicked") } - if !seenSync { + if nSync <= 1 { t.Errorf("expected at least one full generation to have been emitted before the trace was considered broken") } if !seen { From a4ef655edee839d74567afa507e462a779439922 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Fri, 24 Jan 2025 18:10:31 +0000 Subject: [PATCH 278/397] internal/trace: move SchedReqs out of events package It's only used by order.go; there's no reason for it to be in a shared package. Change-Id: If99df075089e6f6e37a78b12e64a1b81a556331c Reviewed-on: https://go-review.googlesource.com/c/go/+/644216 Auto-Submit: Michael Knyszek LUCI-TryBot-Result: Go LUCI Reviewed-by: Michael Pratt --- src/internal/trace/event/requirements.go | 26 ------- src/internal/trace/order.go | 87 +++++++++++++++--------- 2 files changed, 54 insertions(+), 59 deletions(-) delete mode 100644 src/internal/trace/event/requirements.go diff --git a/src/internal/trace/event/requirements.go b/src/internal/trace/event/requirements.go deleted file mode 100644 index c5adf2e0c239d1..00000000000000 --- a/src/internal/trace/event/requirements.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package event - -// SchedReqs is a set of constraints on what the scheduling -// context must look like. -type SchedReqs struct { - Thread Constraint - Proc Constraint - Goroutine Constraint -} - -// Constraint represents a various presence requirements. -type Constraint uint8 - -const ( - MustNotHave Constraint = iota - MayHave - MustHave -) - -// UserGoReqs is a common requirement among events that are running -// or are close to running user code. -var UserGoReqs = SchedReqs{Thread: MustHave, Proc: MustHave, Goroutine: MustHave} diff --git a/src/internal/trace/order.go b/src/internal/trace/order.go index 8a1261330175ac..131e05ce249f61 100644 --- a/src/internal/trace/order.go +++ b/src/internal/trace/order.go @@ -246,7 +246,7 @@ func (o *ordering) advanceProcStart(ev *baseEvent, evt *evTable, m ThreadID, gen // We can advance this P. Check some invariants. // // We might have a goroutine if a goroutine is exiting a syscall. - reqs := event.SchedReqs{Thread: event.MustHave, Proc: event.MustNotHave, Goroutine: event.MayHave} + reqs := schedReqs{M: mustHave, P: mustNotHave, G: mayHave} if err := validateCtx(curCtx, reqs); err != nil { return curCtx, false, err } @@ -275,7 +275,7 @@ func (o *ordering) advanceProcStop(ev *baseEvent, evt *evTable, m ThreadID, gen if state.status != go122.ProcRunning && state.status != go122.ProcSyscall { return curCtx, false, fmt.Errorf("%s event for proc that's not %s or %s", go122.EventString(ev.typ), go122.ProcRunning, go122.ProcSyscall) } - reqs := event.SchedReqs{Thread: event.MustHave, Proc: event.MustHave, Goroutine: event.MayHave} + reqs := schedReqs{M: mustHave, P: mustHave, G: mayHave} if err := validateCtx(curCtx, reqs); err != nil { return curCtx, false, err } @@ -297,7 +297,7 @@ func (o *ordering) advanceProcSteal(ev *baseEvent, evt *evTable, m ThreadID, gen return curCtx, false, nil } // We can advance this P. Check some invariants. - reqs := event.SchedReqs{Thread: event.MustHave, Proc: event.MayHave, Goroutine: event.MayHave} + reqs := schedReqs{M: mustHave, P: mayHave, G: mayHave} if err := validateCtx(curCtx, reqs); err != nil { return curCtx, false, err } @@ -437,7 +437,7 @@ func (o *ordering) advanceGoStatus(ev *baseEvent, evt *evTable, m ThreadID, gen func (o *ordering) advanceGoCreate(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) { // Goroutines must be created on a running P, but may or may not be created // by a running goroutine. - reqs := event.SchedReqs{Thread: event.MustHave, Proc: event.MustHave, Goroutine: event.MayHave} + reqs := schedReqs{M: mustHave, P: mustHave, G: mayHave} if err := validateCtx(curCtx, reqs); err != nil { return curCtx, false, err } @@ -463,7 +463,7 @@ func (o *ordering) advanceGoStopExec(ev *baseEvent, evt *evTable, m ThreadID, ge // These are goroutine events that all require an active running // goroutine on some thread. They must *always* be advance-able, // since running goroutines are bound to their M. - if err := validateCtx(curCtx, event.UserGoReqs); err != nil { + if err := validateCtx(curCtx, userGoReqs); err != nil { return curCtx, false, err } state, ok := o.gStates[curCtx.G] @@ -505,7 +505,7 @@ func (o *ordering) advanceGoStart(ev *baseEvent, evt *evTable, m ThreadID, gen u return curCtx, false, nil } // We can advance this goroutine. Check some invariants. - reqs := event.SchedReqs{Thread: event.MustHave, Proc: event.MustHave, Goroutine: event.MustNotHave} + reqs := schedReqs{M: mustHave, P: mustHave, G: mustNotHave} if err := validateCtx(curCtx, reqs); err != nil { return curCtx, false, err } @@ -546,7 +546,7 @@ func (o *ordering) advanceGoSwitch(ev *baseEvent, evt *evTable, m ThreadID, gen // only advance it if the sequence numbers line up. // // The current goroutine on the thread must be actively running. - if err := validateCtx(curCtx, event.UserGoReqs); err != nil { + if err := validateCtx(curCtx, userGoReqs); err != nil { return curCtx, false, err } curGState, ok := o.gStates[curCtx.G] @@ -601,7 +601,7 @@ func (o *ordering) advanceGoSwitch(ev *baseEvent, evt *evTable, m ThreadID, gen func (o *ordering) advanceGoSyscallBegin(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) { // Entering a syscall requires an active running goroutine with a // proc on some thread. It is always advancable. - if err := validateCtx(curCtx, event.UserGoReqs); err != nil { + if err := validateCtx(curCtx, userGoReqs); err != nil { return curCtx, false, err } state, ok := o.gStates[curCtx.G] @@ -642,7 +642,7 @@ func (o *ordering) advanceGoSyscallEnd(ev *baseEvent, evt *evTable, m ThreadID, // This event is always advance-able because it happens on the same // thread that EvGoSyscallStart happened, and the goroutine can't leave // that thread until its done. - if err := validateCtx(curCtx, event.UserGoReqs); err != nil { + if err := validateCtx(curCtx, userGoReqs); err != nil { return curCtx, false, err } state, ok := o.gStates[curCtx.G] @@ -689,7 +689,7 @@ func (o *ordering) advanceGoSyscallEndBlocked(ev *baseEvent, evt *evTable, m Thr } // As mentioned above, we may have a P here if we ProcStart // before this event. - if err := validateCtx(curCtx, event.SchedReqs{Thread: event.MustHave, Proc: event.MayHave, Goroutine: event.MustHave}); err != nil { + if err := validateCtx(curCtx, schedReqs{M: mustHave, P: mayHave, G: mustHave}); err != nil { return curCtx, false, err } state, ok := o.gStates[curCtx.G] @@ -710,7 +710,7 @@ func (o *ordering) advanceGoCreateSyscall(ev *baseEvent, evt *evTable, m ThreadI // This event indicates that a goroutine is effectively // being created out of a cgo callback. Such a goroutine // is 'created' in the syscall state. - if err := validateCtx(curCtx, event.SchedReqs{Thread: event.MustHave, Proc: event.MayHave, Goroutine: event.MustNotHave}); err != nil { + if err := validateCtx(curCtx, schedReqs{M: mustHave, P: mayHave, G: mustNotHave}); err != nil { return curCtx, false, err } // This goroutine is effectively being created. Add a state for it. @@ -743,7 +743,7 @@ func (o *ordering) advanceGoDestroySyscall(ev *baseEvent, evt *evTable, m Thread // Note: we might have a P here. The P might not be released // eagerly by the runtime, and it might get stolen back later // (or never again, if the program is going to exit). - if err := validateCtx(curCtx, event.SchedReqs{Thread: event.MustHave, Proc: event.MayHave, Goroutine: event.MustHave}); err != nil { + if err := validateCtx(curCtx, schedReqs{M: mustHave, P: mayHave, G: mustHave}); err != nil { return curCtx, false, err } // Check to make sure the goroutine exists in the right state. @@ -812,7 +812,7 @@ func (o *ordering) advanceUserTaskBegin(ev *baseEvent, evt *evTable, m ThreadID, return curCtx, false, fmt.Errorf("invalid string ID %v for %v event", nameID, ev.typ) } o.activeTasks[id] = taskState{name: name, parentID: parentID} - if err := validateCtx(curCtx, event.UserGoReqs); err != nil { + if err := validateCtx(curCtx, userGoReqs); err != nil { return curCtx, false, err } o.queue.push(Event{table: evt, ctx: curCtx, base: *ev}) @@ -833,7 +833,7 @@ func (o *ordering) advanceUserTaskEnd(ev *baseEvent, evt *evTable, m ThreadID, g ev.extra(version.Go122)[0] = uint64(NoTask) ev.extra(version.Go122)[1] = uint64(evt.addExtraString("")) } - if err := validateCtx(curCtx, event.UserGoReqs); err != nil { + if err := validateCtx(curCtx, userGoReqs); err != nil { return curCtx, false, err } o.queue.push(Event{table: evt, ctx: curCtx, base: *ev}) @@ -841,7 +841,7 @@ func (o *ordering) advanceUserTaskEnd(ev *baseEvent, evt *evTable, m ThreadID, g } func (o *ordering) advanceUserRegionBegin(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) { - if err := validateCtx(curCtx, event.UserGoReqs); err != nil { + if err := validateCtx(curCtx, userGoReqs); err != nil { return curCtx, false, err } tid := TaskID(ev.args[0]) @@ -862,7 +862,7 @@ func (o *ordering) advanceUserRegionBegin(ev *baseEvent, evt *evTable, m ThreadI } func (o *ordering) advanceUserRegionEnd(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) { - if err := validateCtx(curCtx, event.UserGoReqs); err != nil { + if err := validateCtx(curCtx, userGoReqs); err != nil { return curCtx, false, err } tid := TaskID(ev.args[0]) @@ -908,7 +908,7 @@ func (o *ordering) advanceGCActive(ev *baseEvent, evt *evTable, m ThreadID, gen return curCtx, false, fmt.Errorf("encountered GCActive while GC was not in progress") } o.gcSeq = seq - if err := validateCtx(curCtx, event.UserGoReqs); err != nil { + if err := validateCtx(curCtx, userGoReqs); err != nil { return curCtx, false, err } o.queue.push(Event{table: evt, ctx: curCtx, base: *ev}) @@ -932,7 +932,7 @@ func (o *ordering) advanceGCBegin(ev *baseEvent, evt *evTable, m ThreadID, gen u } o.gcSeq = seq o.gcState = gcRunning - if err := validateCtx(curCtx, event.UserGoReqs); err != nil { + if err := validateCtx(curCtx, userGoReqs); err != nil { return curCtx, false, err } o.queue.push(Event{table: evt, ctx: curCtx, base: *ev}) @@ -953,7 +953,7 @@ func (o *ordering) advanceGCEnd(ev *baseEvent, evt *evTable, m ThreadID, gen uin } o.gcSeq = seq o.gcState = gcNotRunning - if err := validateCtx(curCtx, event.UserGoReqs); err != nil { + if err := validateCtx(curCtx, userGoReqs); err != nil { return curCtx, false, err } o.queue.push(Event{table: evt, ctx: curCtx, base: *ev}) @@ -962,7 +962,7 @@ func (o *ordering) advanceGCEnd(ev *baseEvent, evt *evTable, m ThreadID, gen uin func (o *ordering) advanceAnnotation(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) { // Handle simple instantaneous events that require a G. - if err := validateCtx(curCtx, event.UserGoReqs); err != nil { + if err := validateCtx(curCtx, userGoReqs); err != nil { return curCtx, false, err } o.queue.push(Event{table: evt, ctx: curCtx, base: *ev}) @@ -971,7 +971,7 @@ func (o *ordering) advanceAnnotation(ev *baseEvent, evt *evTable, m ThreadID, ge func (o *ordering) advanceHeapMetric(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) { // Handle allocation metrics, which don't require a G. - if err := validateCtx(curCtx, event.SchedReqs{Thread: event.MustHave, Proc: event.MustHave, Goroutine: event.MayHave}); err != nil { + if err := validateCtx(curCtx, schedReqs{M: mustHave, P: mustHave, G: mayHave}); err != nil { return curCtx, false, err } o.queue.push(Event{table: evt, ctx: curCtx, base: *ev}) @@ -980,7 +980,7 @@ func (o *ordering) advanceHeapMetric(ev *baseEvent, evt *evTable, m ThreadID, ge func (o *ordering) advanceGCSweepBegin(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) { // Handle sweep, which is bound to a P and doesn't require a G. - if err := validateCtx(curCtx, event.SchedReqs{Thread: event.MustHave, Proc: event.MustHave, Goroutine: event.MayHave}); err != nil { + if err := validateCtx(curCtx, schedReqs{M: mustHave, P: mustHave, G: mayHave}); err != nil { return curCtx, false, err } if err := o.pStates[curCtx.P].beginRange(makeRangeType(ev.typ, 0)); err != nil { @@ -1008,7 +1008,7 @@ func (o *ordering) advanceGCSweepActive(ev *baseEvent, evt *evTable, m ThreadID, } func (o *ordering) advanceGCSweepEnd(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) { - if err := validateCtx(curCtx, event.SchedReqs{Thread: event.MustHave, Proc: event.MustHave, Goroutine: event.MayHave}); err != nil { + if err := validateCtx(curCtx, schedReqs{M: mustHave, P: mustHave, G: mayHave}); err != nil { return curCtx, false, err } _, err := o.pStates[curCtx.P].endRange(ev.typ) @@ -1021,7 +1021,7 @@ func (o *ordering) advanceGCSweepEnd(ev *baseEvent, evt *evTable, m ThreadID, ge func (o *ordering) advanceGoRangeBegin(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) { // Handle special goroutine-bound event ranges. - if err := validateCtx(curCtx, event.UserGoReqs); err != nil { + if err := validateCtx(curCtx, userGoReqs); err != nil { return curCtx, false, err } desc := stringID(0) @@ -1056,7 +1056,7 @@ func (o *ordering) advanceGoRangeActive(ev *baseEvent, evt *evTable, m ThreadID, } func (o *ordering) advanceGoRangeEnd(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) { - if err := validateCtx(curCtx, event.UserGoReqs); err != nil { + if err := validateCtx(curCtx, userGoReqs); err != nil { return curCtx, false, err } gState, ok := o.gStates[curCtx.G] @@ -1078,7 +1078,7 @@ func (o *ordering) advanceGoRangeEnd(ev *baseEvent, evt *evTable, m ThreadID, ge func (o *ordering) advanceAllocFree(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) { // Handle simple instantaneous events that may or may not have a P. - if err := validateCtx(curCtx, event.SchedReqs{Thread: event.MustHave, Proc: event.MayHave, Goroutine: event.MayHave}); err != nil { + if err := validateCtx(curCtx, schedReqs{M: mustHave, P: mayHave, G: mayHave}); err != nil { return curCtx, false, err } o.queue.push(Event{table: evt, ctx: curCtx, base: *ev}) @@ -1099,25 +1099,25 @@ type schedCtx struct { // validateCtx ensures that ctx conforms to some reqs, returning an error if // it doesn't. -func validateCtx(ctx schedCtx, reqs event.SchedReqs) error { +func validateCtx(ctx schedCtx, reqs schedReqs) error { // Check thread requirements. - if reqs.Thread == event.MustHave && ctx.M == NoThread { + if reqs.M == mustHave && ctx.M == NoThread { return fmt.Errorf("expected a thread but didn't have one") - } else if reqs.Thread == event.MustNotHave && ctx.M != NoThread { + } else if reqs.M == mustNotHave && ctx.M != NoThread { return fmt.Errorf("expected no thread but had one") } // Check proc requirements. - if reqs.Proc == event.MustHave && ctx.P == NoProc { + if reqs.P == mustHave && ctx.P == NoProc { return fmt.Errorf("expected a proc but didn't have one") - } else if reqs.Proc == event.MustNotHave && ctx.P != NoProc { + } else if reqs.P == mustNotHave && ctx.P != NoProc { return fmt.Errorf("expected no proc but had one") } // Check goroutine requirements. - if reqs.Goroutine == event.MustHave && ctx.G == NoGoroutine { + if reqs.G == mustHave && ctx.G == NoGoroutine { return fmt.Errorf("expected a goroutine but didn't have one") - } else if reqs.Goroutine == event.MustNotHave && ctx.G != NoGoroutine { + } else if reqs.G == mustNotHave && ctx.G != NoGoroutine { return fmt.Errorf("expected no goroutine but had one") } return nil @@ -1393,3 +1393,24 @@ func makeEvent(table *evTable, ctx schedCtx, typ event.Type, time Time, args ... copy(ev.base.args[:], args) return ev } + +// schedReqs is a set of constraints on what the scheduling +// context must look like. +type schedReqs struct { + M constraint + P constraint + G constraint +} + +// constraint represents a various presence requirements. +type constraint uint8 + +const ( + mustNotHave constraint = iota + mayHave + mustHave +) + +// userGoReqs is a common requirement among events that are running +// or are close to running user code. +var userGoReqs = schedReqs{M: mustHave, P: mustHave, G: mustHave} From 8028731648eb8c5f7693a69f748d990a3228a6e0 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Fri, 24 Jan 2025 20:17:20 +0000 Subject: [PATCH 279/397] internal/trace: rename "oldtrace" to trace v1 This is part of a refactoring to better distinguish trace wire format versions. Even though details may change between Go versions and they might be backwards-incompatible, the trace format still broadly has two wire formats: v1 and v2. A follow-up change will rename go122 to v2 to make this more consistent. Change-Id: If4fe1c82d8aeabc8baa05f525e08a9e7d469a5c7 Reviewed-on: https://go-review.googlesource.com/c/go/+/644217 Auto-Submit: Michael Knyszek LUCI-TryBot-Result: Go LUCI Reviewed-by: Michael Pratt --- src/go/build/deps_test.go | 4 +- src/internal/trace/event/go122/event.go | 116 +++++++-------- .../internal/{oldtrace => tracev1}/order.go | 2 +- .../internal/{oldtrace => tracev1}/parser.go | 4 +- .../{oldtrace => tracev1}/parser_test.go | 2 +- .../testdata/fmt_1_21_pprof_good | Bin .../testdata/http_1_19_good | Bin .../testdata/http_1_21_good | Bin .../testdata/stress_1_11_good | Bin .../testdata/stress_1_19_good | Bin .../testdata/stress_1_21_good | Bin .../testdata/stress_start_stop_1_11_good | Bin .../testdata/stress_start_stop_1_19_good | Bin .../testdata/stress_start_stop_1_21_good | Bin .../testdata/user_task_region_1_11_good | Bin .../testdata/user_task_region_1_19_good | Bin .../testdata/user_task_region_1_21_good | Bin src/internal/trace/reader.go | 22 +-- .../trace/{oldtrace.go => tracev1.go} | 132 +++++++++--------- .../{oldtrace_test.go => tracev1_test.go} | 6 +- 20 files changed, 144 insertions(+), 144 deletions(-) rename src/internal/trace/internal/{oldtrace => tracev1}/order.go (99%) rename src/internal/trace/internal/{oldtrace => tracev1}/parser.go (99%) rename src/internal/trace/internal/{oldtrace => tracev1}/parser_test.go (99%) rename src/internal/trace/internal/{oldtrace => tracev1}/testdata/fmt_1_21_pprof_good (100%) rename src/internal/trace/internal/{oldtrace => tracev1}/testdata/http_1_19_good (100%) rename src/internal/trace/internal/{oldtrace => tracev1}/testdata/http_1_21_good (100%) rename src/internal/trace/internal/{oldtrace => tracev1}/testdata/stress_1_11_good (100%) rename src/internal/trace/internal/{oldtrace => tracev1}/testdata/stress_1_19_good (100%) rename src/internal/trace/internal/{oldtrace => tracev1}/testdata/stress_1_21_good (100%) rename src/internal/trace/internal/{oldtrace => tracev1}/testdata/stress_start_stop_1_11_good (100%) rename src/internal/trace/internal/{oldtrace => tracev1}/testdata/stress_start_stop_1_19_good (100%) rename src/internal/trace/internal/{oldtrace => tracev1}/testdata/stress_start_stop_1_21_good (100%) rename src/internal/trace/internal/{oldtrace => tracev1}/testdata/user_task_region_1_11_good (100%) rename src/internal/trace/internal/{oldtrace => tracev1}/testdata/user_task_region_1_19_good (100%) rename src/internal/trace/internal/{oldtrace => tracev1}/testdata/user_task_region_1_21_good (100%) rename src/internal/trace/{oldtrace.go => tracev1.go} (85%) rename src/internal/trace/{oldtrace_test.go => tracev1_test.go} (93%) diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index 31ec9512c13e16..e992681da4d4b4 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -711,9 +711,9 @@ var depsRules = ` < internal/trace/raw; FMT, internal/trace/event, internal/trace/version, io, sort, encoding/binary - < internal/trace/internal/oldtrace; + < internal/trace/internal/tracev1; - FMT, encoding/binary, internal/trace/version, internal/trace/internal/oldtrace, container/heap, math/rand + FMT, encoding/binary, internal/trace/version, internal/trace/internal/tracev1, container/heap, math/rand < internal/trace; regexp, internal/trace, internal/trace/raw, internal/txtar diff --git a/src/internal/trace/event/go122/event.go b/src/internal/trace/event/go122/event.go index f22b23ddbb44fa..5eadf0e571f28a 100644 --- a/src/internal/trace/event/go122/event.go +++ b/src/internal/trace/event/go122/event.go @@ -130,246 +130,246 @@ func Specs() []event.Spec { var specs = [...]event.Spec{ // "Structural" Events. - EvEventBatch: event.Spec{ + EvEventBatch: { Name: "EventBatch", Args: []string{"gen", "m", "time", "size"}, }, - EvStacks: event.Spec{ + EvStacks: { Name: "Stacks", }, - EvStack: event.Spec{ + EvStack: { Name: "Stack", Args: []string{"id", "nframes"}, IsStack: true, }, - EvStrings: event.Spec{ + EvStrings: { Name: "Strings", }, - EvString: event.Spec{ + EvString: { Name: "String", Args: []string{"id"}, HasData: true, }, - EvCPUSamples: event.Spec{ + EvCPUSamples: { Name: "CPUSamples", }, - EvCPUSample: event.Spec{ + EvCPUSample: { Name: "CPUSample", Args: []string{"time", "m", "p", "g", "stack"}, // N.B. There's clearly a timestamp here, but these Events // are special in that they don't appear in the regular // M streams. }, - EvFrequency: event.Spec{ + EvFrequency: { Name: "Frequency", Args: []string{"freq"}, }, - EvExperimentalBatch: event.Spec{ + EvExperimentalBatch: { Name: "ExperimentalBatch", Args: []string{"exp", "gen", "m", "time"}, HasData: true, // Easier to represent for raw readers. }, // "Timed" Events. - EvProcsChange: event.Spec{ + EvProcsChange: { Name: "ProcsChange", Args: []string{"dt", "procs_value", "stack"}, IsTimedEvent: true, StackIDs: []int{2}, }, - EvProcStart: event.Spec{ + EvProcStart: { Name: "ProcStart", Args: []string{"dt", "p", "p_seq"}, IsTimedEvent: true, }, - EvProcStop: event.Spec{ + EvProcStop: { Name: "ProcStop", Args: []string{"dt"}, IsTimedEvent: true, }, - EvProcSteal: event.Spec{ + EvProcSteal: { Name: "ProcSteal", Args: []string{"dt", "p", "p_seq", "m"}, IsTimedEvent: true, }, - EvProcStatus: event.Spec{ + EvProcStatus: { Name: "ProcStatus", Args: []string{"dt", "p", "pstatus"}, IsTimedEvent: true, }, - EvGoCreate: event.Spec{ + EvGoCreate: { Name: "GoCreate", Args: []string{"dt", "new_g", "new_stack", "stack"}, IsTimedEvent: true, StackIDs: []int{3, 2}, }, - EvGoCreateSyscall: event.Spec{ + EvGoCreateSyscall: { Name: "GoCreateSyscall", Args: []string{"dt", "new_g"}, IsTimedEvent: true, }, - EvGoStart: event.Spec{ + EvGoStart: { Name: "GoStart", Args: []string{"dt", "g", "g_seq"}, IsTimedEvent: true, }, - EvGoDestroy: event.Spec{ + EvGoDestroy: { Name: "GoDestroy", Args: []string{"dt"}, IsTimedEvent: true, }, - EvGoDestroySyscall: event.Spec{ + EvGoDestroySyscall: { Name: "GoDestroySyscall", Args: []string{"dt"}, IsTimedEvent: true, }, - EvGoStop: event.Spec{ + EvGoStop: { Name: "GoStop", Args: []string{"dt", "reason_string", "stack"}, IsTimedEvent: true, StackIDs: []int{2}, StringIDs: []int{1}, }, - EvGoBlock: event.Spec{ + EvGoBlock: { Name: "GoBlock", Args: []string{"dt", "reason_string", "stack"}, IsTimedEvent: true, StackIDs: []int{2}, StringIDs: []int{1}, }, - EvGoUnblock: event.Spec{ + EvGoUnblock: { Name: "GoUnblock", Args: []string{"dt", "g", "g_seq", "stack"}, IsTimedEvent: true, StackIDs: []int{3}, }, - EvGoSyscallBegin: event.Spec{ + EvGoSyscallBegin: { Name: "GoSyscallBegin", Args: []string{"dt", "p_seq", "stack"}, IsTimedEvent: true, StackIDs: []int{2}, }, - EvGoSyscallEnd: event.Spec{ + EvGoSyscallEnd: { Name: "GoSyscallEnd", Args: []string{"dt"}, StartEv: EvGoSyscallBegin, IsTimedEvent: true, }, - EvGoSyscallEndBlocked: event.Spec{ + EvGoSyscallEndBlocked: { Name: "GoSyscallEndBlocked", Args: []string{"dt"}, StartEv: EvGoSyscallBegin, IsTimedEvent: true, }, - EvGoStatus: event.Spec{ + EvGoStatus: { Name: "GoStatus", Args: []string{"dt", "g", "m", "gstatus"}, IsTimedEvent: true, }, - EvSTWBegin: event.Spec{ + EvSTWBegin: { Name: "STWBegin", Args: []string{"dt", "kind_string", "stack"}, IsTimedEvent: true, StackIDs: []int{2}, StringIDs: []int{1}, }, - EvSTWEnd: event.Spec{ + EvSTWEnd: { Name: "STWEnd", Args: []string{"dt"}, StartEv: EvSTWBegin, IsTimedEvent: true, }, - EvGCActive: event.Spec{ + EvGCActive: { Name: "GCActive", Args: []string{"dt", "gc_seq"}, IsTimedEvent: true, StartEv: EvGCBegin, }, - EvGCBegin: event.Spec{ + EvGCBegin: { Name: "GCBegin", Args: []string{"dt", "gc_seq", "stack"}, IsTimedEvent: true, StackIDs: []int{2}, }, - EvGCEnd: event.Spec{ + EvGCEnd: { Name: "GCEnd", Args: []string{"dt", "gc_seq"}, StartEv: EvGCBegin, IsTimedEvent: true, }, - EvGCSweepActive: event.Spec{ + EvGCSweepActive: { Name: "GCSweepActive", Args: []string{"dt", "p"}, StartEv: EvGCSweepBegin, IsTimedEvent: true, }, - EvGCSweepBegin: event.Spec{ + EvGCSweepBegin: { Name: "GCSweepBegin", Args: []string{"dt", "stack"}, IsTimedEvent: true, StackIDs: []int{1}, }, - EvGCSweepEnd: event.Spec{ + EvGCSweepEnd: { Name: "GCSweepEnd", Args: []string{"dt", "swept_value", "reclaimed_value"}, StartEv: EvGCSweepBegin, IsTimedEvent: true, }, - EvGCMarkAssistActive: event.Spec{ + EvGCMarkAssistActive: { Name: "GCMarkAssistActive", Args: []string{"dt", "g"}, StartEv: EvGCMarkAssistBegin, IsTimedEvent: true, }, - EvGCMarkAssistBegin: event.Spec{ + EvGCMarkAssistBegin: { Name: "GCMarkAssistBegin", Args: []string{"dt", "stack"}, IsTimedEvent: true, StackIDs: []int{1}, }, - EvGCMarkAssistEnd: event.Spec{ + EvGCMarkAssistEnd: { Name: "GCMarkAssistEnd", Args: []string{"dt"}, StartEv: EvGCMarkAssistBegin, IsTimedEvent: true, }, - EvHeapAlloc: event.Spec{ + EvHeapAlloc: { Name: "HeapAlloc", Args: []string{"dt", "heapalloc_value"}, IsTimedEvent: true, }, - EvHeapGoal: event.Spec{ + EvHeapGoal: { Name: "HeapGoal", Args: []string{"dt", "heapgoal_value"}, IsTimedEvent: true, }, - EvGoLabel: event.Spec{ + EvGoLabel: { Name: "GoLabel", Args: []string{"dt", "label_string"}, IsTimedEvent: true, StringIDs: []int{1}, }, - EvUserTaskBegin: event.Spec{ + EvUserTaskBegin: { Name: "UserTaskBegin", Args: []string{"dt", "task", "parent_task", "name_string", "stack"}, IsTimedEvent: true, StackIDs: []int{4}, StringIDs: []int{3}, }, - EvUserTaskEnd: event.Spec{ + EvUserTaskEnd: { Name: "UserTaskEnd", Args: []string{"dt", "task", "stack"}, IsTimedEvent: true, StackIDs: []int{2}, }, - EvUserRegionBegin: event.Spec{ + EvUserRegionBegin: { Name: "UserRegionBegin", Args: []string{"dt", "task", "name_string", "stack"}, IsTimedEvent: true, StackIDs: []int{3}, StringIDs: []int{2}, }, - EvUserRegionEnd: event.Spec{ + EvUserRegionEnd: { Name: "UserRegionEnd", Args: []string{"dt", "task", "name_string", "stack"}, StartEv: EvUserRegionBegin, @@ -377,30 +377,30 @@ var specs = [...]event.Spec{ StackIDs: []int{3}, StringIDs: []int{2}, }, - EvUserLog: event.Spec{ + EvUserLog: { Name: "UserLog", Args: []string{"dt", "task", "key_string", "value_string", "stack"}, IsTimedEvent: true, StackIDs: []int{4}, StringIDs: []int{2, 3}, }, - EvGoSwitch: event.Spec{ + EvGoSwitch: { Name: "GoSwitch", Args: []string{"dt", "g", "g_seq"}, IsTimedEvent: true, }, - EvGoSwitchDestroy: event.Spec{ + EvGoSwitchDestroy: { Name: "GoSwitchDestroy", Args: []string{"dt", "g", "g_seq"}, IsTimedEvent: true, }, - EvGoCreateBlocked: event.Spec{ + EvGoCreateBlocked: { Name: "GoCreateBlocked", Args: []string{"dt", "new_g", "new_stack", "stack"}, IsTimedEvent: true, StackIDs: []int{3, 2}, }, - EvGoStatusStack: event.Spec{ + EvGoStatusStack: { Name: "GoStatusStack", Args: []string{"dt", "g", "m", "gstatus", "stack"}, IsTimedEvent: true, @@ -409,55 +409,55 @@ var specs = [...]event.Spec{ // Experimental events. - EvSpan: event.Spec{ + EvSpan: { Name: "Span", Args: []string{"dt", "id", "npages_value", "kindclass"}, IsTimedEvent: true, Experiment: AllocFree, }, - EvSpanAlloc: event.Spec{ + EvSpanAlloc: { Name: "SpanAlloc", Args: []string{"dt", "id", "npages_value", "kindclass"}, IsTimedEvent: true, Experiment: AllocFree, }, - EvSpanFree: event.Spec{ + EvSpanFree: { Name: "SpanFree", Args: []string{"dt", "id"}, IsTimedEvent: true, Experiment: AllocFree, }, - EvHeapObject: event.Spec{ + EvHeapObject: { Name: "HeapObject", Args: []string{"dt", "id", "type"}, IsTimedEvent: true, Experiment: AllocFree, }, - EvHeapObjectAlloc: event.Spec{ + EvHeapObjectAlloc: { Name: "HeapObjectAlloc", Args: []string{"dt", "id", "type"}, IsTimedEvent: true, Experiment: AllocFree, }, - EvHeapObjectFree: event.Spec{ + EvHeapObjectFree: { Name: "HeapObjectFree", Args: []string{"dt", "id"}, IsTimedEvent: true, Experiment: AllocFree, }, - EvGoroutineStack: event.Spec{ + EvGoroutineStack: { Name: "GoroutineStack", Args: []string{"dt", "id", "order"}, IsTimedEvent: true, Experiment: AllocFree, }, - EvGoroutineStackAlloc: event.Spec{ + EvGoroutineStackAlloc: { Name: "GoroutineStackAlloc", Args: []string{"dt", "id", "order"}, IsTimedEvent: true, Experiment: AllocFree, }, - EvGoroutineStackFree: event.Spec{ + EvGoroutineStackFree: { Name: "GoroutineStackFree", Args: []string{"dt", "id"}, IsTimedEvent: true, diff --git a/src/internal/trace/internal/oldtrace/order.go b/src/internal/trace/internal/tracev1/order.go similarity index 99% rename from src/internal/trace/internal/oldtrace/order.go rename to src/internal/trace/internal/tracev1/order.go index b9d63e2f0c22f0..683d7f03b47f2b 100644 --- a/src/internal/trace/internal/oldtrace/order.go +++ b/src/internal/trace/internal/tracev1/order.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package oldtrace +package tracev1 import "errors" diff --git a/src/internal/trace/internal/oldtrace/parser.go b/src/internal/trace/internal/tracev1/parser.go similarity index 99% rename from src/internal/trace/internal/oldtrace/parser.go rename to src/internal/trace/internal/tracev1/parser.go index 5b12df7e2b9093..b95f86e43d202f 100644 --- a/src/internal/trace/internal/oldtrace/parser.go +++ b/src/internal/trace/internal/tracev1/parser.go @@ -2,14 +2,14 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package oldtrace implements a parser for Go execution traces from versions +// Package tracev1 implements a parser for Go execution traces from versions // 1.11–1.21. // // The package started as a copy of Go 1.19's internal/trace, but has been // optimized to be faster while using less memory and fewer allocations. It has // been further modified for the specific purpose of converting traces to the // new 1.22+ format. -package oldtrace +package tracev1 import ( "bytes" diff --git a/src/internal/trace/internal/oldtrace/parser_test.go b/src/internal/trace/internal/tracev1/parser_test.go similarity index 99% rename from src/internal/trace/internal/oldtrace/parser_test.go rename to src/internal/trace/internal/tracev1/parser_test.go index 6fe31e2e7e1fe1..af6d8db2340eab 100644 --- a/src/internal/trace/internal/oldtrace/parser_test.go +++ b/src/internal/trace/internal/tracev1/parser_test.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package oldtrace +package tracev1 import ( "bytes" diff --git a/src/internal/trace/internal/oldtrace/testdata/fmt_1_21_pprof_good b/src/internal/trace/internal/tracev1/testdata/fmt_1_21_pprof_good similarity index 100% rename from src/internal/trace/internal/oldtrace/testdata/fmt_1_21_pprof_good rename to src/internal/trace/internal/tracev1/testdata/fmt_1_21_pprof_good diff --git a/src/internal/trace/internal/oldtrace/testdata/http_1_19_good b/src/internal/trace/internal/tracev1/testdata/http_1_19_good similarity index 100% rename from src/internal/trace/internal/oldtrace/testdata/http_1_19_good rename to src/internal/trace/internal/tracev1/testdata/http_1_19_good diff --git a/src/internal/trace/internal/oldtrace/testdata/http_1_21_good b/src/internal/trace/internal/tracev1/testdata/http_1_21_good similarity index 100% rename from src/internal/trace/internal/oldtrace/testdata/http_1_21_good rename to src/internal/trace/internal/tracev1/testdata/http_1_21_good diff --git a/src/internal/trace/internal/oldtrace/testdata/stress_1_11_good b/src/internal/trace/internal/tracev1/testdata/stress_1_11_good similarity index 100% rename from src/internal/trace/internal/oldtrace/testdata/stress_1_11_good rename to src/internal/trace/internal/tracev1/testdata/stress_1_11_good diff --git a/src/internal/trace/internal/oldtrace/testdata/stress_1_19_good b/src/internal/trace/internal/tracev1/testdata/stress_1_19_good similarity index 100% rename from src/internal/trace/internal/oldtrace/testdata/stress_1_19_good rename to src/internal/trace/internal/tracev1/testdata/stress_1_19_good diff --git a/src/internal/trace/internal/oldtrace/testdata/stress_1_21_good b/src/internal/trace/internal/tracev1/testdata/stress_1_21_good similarity index 100% rename from src/internal/trace/internal/oldtrace/testdata/stress_1_21_good rename to src/internal/trace/internal/tracev1/testdata/stress_1_21_good diff --git a/src/internal/trace/internal/oldtrace/testdata/stress_start_stop_1_11_good b/src/internal/trace/internal/tracev1/testdata/stress_start_stop_1_11_good similarity index 100% rename from src/internal/trace/internal/oldtrace/testdata/stress_start_stop_1_11_good rename to src/internal/trace/internal/tracev1/testdata/stress_start_stop_1_11_good diff --git a/src/internal/trace/internal/oldtrace/testdata/stress_start_stop_1_19_good b/src/internal/trace/internal/tracev1/testdata/stress_start_stop_1_19_good similarity index 100% rename from src/internal/trace/internal/oldtrace/testdata/stress_start_stop_1_19_good rename to src/internal/trace/internal/tracev1/testdata/stress_start_stop_1_19_good diff --git a/src/internal/trace/internal/oldtrace/testdata/stress_start_stop_1_21_good b/src/internal/trace/internal/tracev1/testdata/stress_start_stop_1_21_good similarity index 100% rename from src/internal/trace/internal/oldtrace/testdata/stress_start_stop_1_21_good rename to src/internal/trace/internal/tracev1/testdata/stress_start_stop_1_21_good diff --git a/src/internal/trace/internal/oldtrace/testdata/user_task_region_1_11_good b/src/internal/trace/internal/tracev1/testdata/user_task_region_1_11_good similarity index 100% rename from src/internal/trace/internal/oldtrace/testdata/user_task_region_1_11_good rename to src/internal/trace/internal/tracev1/testdata/user_task_region_1_11_good diff --git a/src/internal/trace/internal/oldtrace/testdata/user_task_region_1_19_good b/src/internal/trace/internal/tracev1/testdata/user_task_region_1_19_good similarity index 100% rename from src/internal/trace/internal/oldtrace/testdata/user_task_region_1_19_good rename to src/internal/trace/internal/tracev1/testdata/user_task_region_1_19_good diff --git a/src/internal/trace/internal/oldtrace/testdata/user_task_region_1_21_good b/src/internal/trace/internal/tracev1/testdata/user_task_region_1_21_good similarity index 100% rename from src/internal/trace/internal/oldtrace/testdata/user_task_region_1_21_good rename to src/internal/trace/internal/tracev1/testdata/user_task_region_1_21_good diff --git a/src/internal/trace/reader.go b/src/internal/trace/reader.go index 149a88b7b42e5e..6fc39e28acdfb0 100644 --- a/src/internal/trace/reader.go +++ b/src/internal/trace/reader.go @@ -12,7 +12,7 @@ import ( "strings" "internal/trace/event/go122" - "internal/trace/internal/oldtrace" + "internal/trace/internal/tracev1" "internal/trace/version" ) @@ -33,7 +33,7 @@ type Reader struct { syncs int done bool - go121Events *oldTraceConverter + v1Events *traceV1Converter } // NewReader creates a new trace reader. @@ -45,12 +45,12 @@ func NewReader(r io.Reader) (*Reader, error) { } switch v { case version.Go111, version.Go119, version.Go121: - tr, err := oldtrace.Parse(br, v) + tr, err := tracev1.Parse(br, v) if err != nil { return nil, err } return &Reader{ - go121Events: convertOldFormat(tr), + v1Events: convertV1Trace(tr), }, nil case version.Go122, version.Go123: return &Reader{ @@ -76,29 +76,29 @@ func (r *Reader) ReadEvent() (e Event, err error) { return Event{}, io.EOF } - // Handle old execution traces. - if r.go121Events != nil { + // Handle v1 execution traces. + if r.v1Events != nil { if r.syncs == 0 { // Always emit a sync event first, if we have any events at all. - ev, ok := r.go121Events.events.Peek() + ev, ok := r.v1Events.events.Peek() if ok { r.syncs++ - return syncEvent(r.go121Events.evt, Time(ev.Ts-1), r.syncs), nil + return syncEvent(r.v1Events.evt, Time(ev.Ts-1), r.syncs), nil } } - ev, err := r.go121Events.next() + ev, err := r.v1Events.next() if err == io.EOF { // Always emit a sync event at the end. r.done = true r.syncs++ - return syncEvent(nil, r.go121Events.lastTs+1, r.syncs), nil + return syncEvent(nil, r.v1Events.lastTs+1, r.syncs), nil } else if err != nil { return Event{}, err } return ev, nil } - // Go 1.22+ trace parsing algorithm. + // Trace v2 parsing algorithm. // // (1) Read in all the batches for the next generation from the stream. // (a) Use the size field in the header to quickly find all batches. diff --git a/src/internal/trace/oldtrace.go b/src/internal/trace/tracev1.go similarity index 85% rename from src/internal/trace/oldtrace.go rename to src/internal/trace/tracev1.go index c49f8c7474d49a..91752efa99d22a 100644 --- a/src/internal/trace/oldtrace.go +++ b/src/internal/trace/tracev1.go @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// This file implements conversion from old (Go 1.11–Go 1.21) traces to the Go -// 1.22 format. +// This file implements conversion from v1 (Go 1.11–Go 1.21) traces to the v2 +// format (Go 1.22+). // -// Most events have direct equivalents in 1.22, at worst requiring arguments to +// Most events have direct equivalents in v2, at worst requiring arguments to // be reordered. Some events, such as GoWaiting need to look ahead for follow-up // events to determine the correct translation. GoSyscall, which is an // instantaneous event, gets turned into a 1 ns long pair of @@ -13,11 +13,11 @@ // emit a GoSyscallStart+GoSyscallEndBlocked pair with the correct duration // (i.e. starting at the original GoSyscall). // -// The resulting trace treats the old trace as a single, large generation, +// The resulting trace treats the trace v1 as a single, large generation, // sharing a single evTable for all events. // // We use a new (compared to what was used for 'go tool trace' in earlier -// versions of Go) parser for old traces that is optimized for speed, low memory +// versions of Go) parser for v1 traces that is optimized for speed, low memory // usage, and minimal GC pressure. It allocates events in batches so that even // though we have to load the entire trace into memory, the conversion process // shouldn't result in a doubling of memory usage, even if all converted events @@ -32,16 +32,16 @@ import ( "fmt" "internal/trace/event" "internal/trace/event/go122" - "internal/trace/internal/oldtrace" + "internal/trace/internal/tracev1" "io" ) -type oldTraceConverter struct { - trace oldtrace.Trace +type traceV1Converter struct { + trace tracev1.Trace evt *evTable preInit bool createdPreInit map[GoID]struct{} - events oldtrace.Events + events tracev1.Events extra []Event extraArr [3]Event tasks map[TaskID]taskState @@ -91,7 +91,7 @@ const ( sLast ) -func (it *oldTraceConverter) init(pr oldtrace.Trace) error { +func (it *traceV1Converter) init(pr tracev1.Trace) error { it.trace = pr it.preInit = true it.createdPreInit = make(map[GoID]struct{}) @@ -105,7 +105,7 @@ func (it *oldTraceConverter) init(pr oldtrace.Trace) error { evt := it.evt - // Convert from oldtracer's Strings map to our dataTable. + // Convert from trace v1's Strings map to our dataTable. var max uint64 for id, s := range pr.Strings { evt.strings.insert(stringID(id), s) @@ -115,7 +115,7 @@ func (it *oldTraceConverter) init(pr oldtrace.Trace) error { } pr.Strings = nil - // Add all strings used for UserLog. In the old trace format, these were + // Add all strings used for UserLog. In the trace v1 format, these were // stored inline and didn't have IDs. We generate IDs for them. if max+uint64(len(pr.InlineStrings)) < max { return errors.New("trace contains too many strings") @@ -187,7 +187,7 @@ func (it *oldTraceConverter) init(pr oldtrace.Trace) error { } // OPT(dh): if we could share the frame type between this package and - // oldtrace we wouldn't have to copy the map. + // tracev1 we wouldn't have to copy the map. for pc, f := range pr.PCs { evt.pcs[pc] = frame{ pc: pc, @@ -204,7 +204,7 @@ func (it *oldTraceConverter) init(pr oldtrace.Trace) error { // next returns the next event, io.EOF if there are no more events, or a // descriptive error for invalid events. -func (it *oldTraceConverter) next() (Event, error) { +func (it *traceV1Converter) next() (Event, error) { if len(it.extra) > 0 { ev := it.extra[0] it.extra = it.extra[1:] @@ -245,20 +245,20 @@ func (it *oldTraceConverter) next() (Event, error) { var errSkip = errors.New("skip event") -// convertEvent converts an event from the old trace format to zero or more +// convertEvent converts an event from the trace v1 format to zero or more // events in the new format. Most events translate 1 to 1. Some events don't // result in an event right away, in which case convertEvent returns errSkip. // Some events result in more than one new event; in this case, convertEvent // returns the first event and stores additional events in it.extra. When -// encountering events that oldtrace shouldn't be able to emit, ocnvertEvent +// encountering events that tracev1 shouldn't be able to emit, ocnvertEvent // returns a descriptive error. -func (it *oldTraceConverter) convertEvent(ev *oldtrace.Event) (OUT Event, ERR error) { +func (it *traceV1Converter) convertEvent(ev *tracev1.Event) (OUT Event, ERR error) { var mappedType event.Type var mappedArgs timedEventArgs copy(mappedArgs[:], ev.Args[:]) switch ev.Type { - case oldtrace.EvGomaxprocs: + case tracev1.EvGomaxprocs: mappedType = go122.EvProcsChange if it.preInit { // The first EvGomaxprocs signals the end of trace initialization. At this point we've seen @@ -286,7 +286,7 @@ func (it *oldTraceConverter) convertEvent(ev *oldtrace.Event) (OUT Event, ERR er it.createdPreInit = nil return Event{}, errSkip } - case oldtrace.EvProcStart: + case tracev1.EvProcStart: it.procMs[ProcID(ev.P)] = ThreadID(ev.Args[0]) if _, ok := it.seenProcs[ProcID(ev.P)]; ok { mappedType = go122.EvProcStart @@ -296,7 +296,7 @@ func (it *oldTraceConverter) convertEvent(ev *oldtrace.Event) (OUT Event, ERR er mappedType = go122.EvProcStatus mappedArgs = timedEventArgs{uint64(ev.P), uint64(go122.ProcRunning)} } - case oldtrace.EvProcStop: + case tracev1.EvProcStop: if _, ok := it.seenProcs[ProcID(ev.P)]; ok { mappedType = go122.EvProcStop mappedArgs = timedEventArgs{uint64(ev.P)} @@ -305,29 +305,29 @@ func (it *oldTraceConverter) convertEvent(ev *oldtrace.Event) (OUT Event, ERR er mappedType = go122.EvProcStatus mappedArgs = timedEventArgs{uint64(ev.P), uint64(go122.ProcIdle)} } - case oldtrace.EvGCStart: + case tracev1.EvGCStart: mappedType = go122.EvGCBegin - case oldtrace.EvGCDone: + case tracev1.EvGCDone: mappedType = go122.EvGCEnd - case oldtrace.EvSTWStart: + case tracev1.EvSTWStart: sid := it.builtinToStringID[sSTWUnknown+it.trace.STWReason(ev.Args[0])] it.lastStwReason = sid mappedType = go122.EvSTWBegin mappedArgs = timedEventArgs{uint64(sid)} - case oldtrace.EvSTWDone: + case tracev1.EvSTWDone: mappedType = go122.EvSTWEnd mappedArgs = timedEventArgs{it.lastStwReason} - case oldtrace.EvGCSweepStart: + case tracev1.EvGCSweepStart: mappedType = go122.EvGCSweepBegin - case oldtrace.EvGCSweepDone: + case tracev1.EvGCSweepDone: mappedType = go122.EvGCSweepEnd - case oldtrace.EvGoCreate: + case tracev1.EvGoCreate: if it.preInit { it.createdPreInit[GoID(ev.Args[0])] = struct{}{} return Event{}, errSkip } mappedType = go122.EvGoCreate - case oldtrace.EvGoStart: + case tracev1.EvGoStart: if it.preInit { mappedType = go122.EvGoStatus mappedArgs = timedEventArgs{ev.Args[0], ^uint64(0), uint64(go122.GoRunning)} @@ -335,7 +335,7 @@ func (it *oldTraceConverter) convertEvent(ev *oldtrace.Event) (OUT Event, ERR er } else { mappedType = go122.EvGoStart } - case oldtrace.EvGoStartLabel: + case tracev1.EvGoStartLabel: it.extra = []Event{{ ctx: schedCtx{ G: GoID(ev.G), @@ -362,58 +362,58 @@ func (it *oldTraceConverter) convertEvent(ev *oldtrace.Event) (OUT Event, ERR er args: mappedArgs, }, }, nil - case oldtrace.EvGoEnd: + case tracev1.EvGoEnd: mappedType = go122.EvGoDestroy - case oldtrace.EvGoStop: + case tracev1.EvGoStop: mappedType = go122.EvGoBlock mappedArgs = timedEventArgs{uint64(it.builtinToStringID[sForever]), uint64(ev.StkID)} - case oldtrace.EvGoSched: + case tracev1.EvGoSched: mappedType = go122.EvGoStop mappedArgs = timedEventArgs{uint64(it.builtinToStringID[sGosched]), uint64(ev.StkID)} - case oldtrace.EvGoPreempt: + case tracev1.EvGoPreempt: mappedType = go122.EvGoStop mappedArgs = timedEventArgs{uint64(it.builtinToStringID[sPreempted]), uint64(ev.StkID)} - case oldtrace.EvGoSleep: + case tracev1.EvGoSleep: mappedType = go122.EvGoBlock mappedArgs = timedEventArgs{uint64(it.builtinToStringID[sSleep]), uint64(ev.StkID)} - case oldtrace.EvGoBlock: + case tracev1.EvGoBlock: mappedType = go122.EvGoBlock mappedArgs = timedEventArgs{uint64(it.builtinToStringID[sEmpty]), uint64(ev.StkID)} - case oldtrace.EvGoUnblock: + case tracev1.EvGoUnblock: mappedType = go122.EvGoUnblock - case oldtrace.EvGoBlockSend: + case tracev1.EvGoBlockSend: mappedType = go122.EvGoBlock mappedArgs = timedEventArgs{uint64(it.builtinToStringID[sChanSend]), uint64(ev.StkID)} - case oldtrace.EvGoBlockRecv: + case tracev1.EvGoBlockRecv: mappedType = go122.EvGoBlock mappedArgs = timedEventArgs{uint64(it.builtinToStringID[sChanRecv]), uint64(ev.StkID)} - case oldtrace.EvGoBlockSelect: + case tracev1.EvGoBlockSelect: mappedType = go122.EvGoBlock mappedArgs = timedEventArgs{uint64(it.builtinToStringID[sSelect]), uint64(ev.StkID)} - case oldtrace.EvGoBlockSync: + case tracev1.EvGoBlockSync: mappedType = go122.EvGoBlock mappedArgs = timedEventArgs{uint64(it.builtinToStringID[sSync]), uint64(ev.StkID)} - case oldtrace.EvGoBlockCond: + case tracev1.EvGoBlockCond: mappedType = go122.EvGoBlock mappedArgs = timedEventArgs{uint64(it.builtinToStringID[sSyncCond]), uint64(ev.StkID)} - case oldtrace.EvGoBlockNet: + case tracev1.EvGoBlockNet: mappedType = go122.EvGoBlock mappedArgs = timedEventArgs{uint64(it.builtinToStringID[sNetwork]), uint64(ev.StkID)} - case oldtrace.EvGoBlockGC: + case tracev1.EvGoBlockGC: mappedType = go122.EvGoBlock mappedArgs = timedEventArgs{uint64(it.builtinToStringID[sMarkAssistWait]), uint64(ev.StkID)} - case oldtrace.EvGoSysCall: + case tracev1.EvGoSysCall: // Look for the next event for the same G to determine if the syscall // blocked. blocked := false - it.events.All()(func(nev *oldtrace.Event) bool { + it.events.All()(func(nev *tracev1.Event) bool { if nev.G != ev.G { return true } // After an EvGoSysCall, the next event on the same G will either be // EvGoSysBlock to denote a blocking syscall, or some other event // (or the end of the trace) if the syscall didn't block. - if nev.Type == oldtrace.EvGoSysBlock { + if nev.Type == tracev1.EvGoSysBlock { blocked = true } return false @@ -453,30 +453,30 @@ func (it *oldTraceConverter) convertEvent(ev *oldtrace.Event) (OUT Event, ERR er return out1, nil } - case oldtrace.EvGoSysExit: + case tracev1.EvGoSysExit: mappedType = go122.EvGoSyscallEndBlocked - case oldtrace.EvGoSysBlock: + case tracev1.EvGoSysBlock: return Event{}, errSkip - case oldtrace.EvGoWaiting: + case tracev1.EvGoWaiting: mappedType = go122.EvGoStatus mappedArgs = timedEventArgs{ev.Args[0], ^uint64(0), uint64(go122.GoWaiting)} delete(it.createdPreInit, GoID(ev.Args[0])) - case oldtrace.EvGoInSyscall: + case tracev1.EvGoInSyscall: mappedType = go122.EvGoStatus // In the new tracer, GoStatus with GoSyscall knows what thread the - // syscall is on. In the old tracer, EvGoInSyscall doesn't contain that + // syscall is on. In trace v1, EvGoInSyscall doesn't contain that // information and all we can do here is specify NoThread. mappedArgs = timedEventArgs{ev.Args[0], ^uint64(0), uint64(go122.GoSyscall)} delete(it.createdPreInit, GoID(ev.Args[0])) - case oldtrace.EvHeapAlloc: + case tracev1.EvHeapAlloc: mappedType = go122.EvHeapAlloc - case oldtrace.EvHeapGoal: + case tracev1.EvHeapGoal: mappedType = go122.EvHeapGoal - case oldtrace.EvGCMarkAssistStart: + case tracev1.EvGCMarkAssistStart: mappedType = go122.EvGCMarkAssistBegin - case oldtrace.EvGCMarkAssistDone: + case tracev1.EvGCMarkAssistDone: mappedType = go122.EvGCMarkAssistEnd - case oldtrace.EvUserTaskCreate: + case tracev1.EvUserTaskCreate: mappedType = go122.EvUserTaskBegin parent := ev.Args[1] if parent == 0 { @@ -485,7 +485,7 @@ func (it *oldTraceConverter) convertEvent(ev *oldtrace.Event) (OUT Event, ERR er mappedArgs = timedEventArgs{ev.Args[0], parent, ev.Args[2], uint64(ev.StkID)} name, _ := it.evt.strings.get(stringID(ev.Args[2])) it.tasks[TaskID(ev.Args[0])] = taskState{name: name, parentID: TaskID(ev.Args[1])} - case oldtrace.EvUserTaskEnd: + case tracev1.EvUserTaskEnd: mappedType = go122.EvUserTaskEnd // Event.Task expects the parent and name to be smuggled in extra args // and as extra strings. @@ -501,7 +501,7 @@ func (it *oldTraceConverter) convertEvent(ev *oldtrace.Event) (OUT Event, ERR er } else { mappedArgs = timedEventArgs{ev.Args[0], ev.Args[1], uint64(NoTask), uint64(it.evt.addExtraString(""))} } - case oldtrace.EvUserRegion: + case tracev1.EvUserRegion: switch ev.Args[1] { case 0: // start mappedType = go122.EvUserRegionBegin @@ -509,10 +509,10 @@ func (it *oldTraceConverter) convertEvent(ev *oldtrace.Event) (OUT Event, ERR er mappedType = go122.EvUserRegionEnd } mappedArgs = timedEventArgs{ev.Args[0], ev.Args[2], uint64(ev.StkID)} - case oldtrace.EvUserLog: + case tracev1.EvUserLog: mappedType = go122.EvUserLog mappedArgs = timedEventArgs{ev.Args[0], ev.Args[1], it.inlineToStringID[ev.Args[3]], uint64(ev.StkID)} - case oldtrace.EvCPUSample: + case tracev1.EvCPUSample: mappedType = go122.EvCPUSample // When emitted by the Go 1.22 tracer, CPU samples have 5 arguments: // timestamp, M, P, G, stack. However, after they get turned into Event, @@ -524,19 +524,19 @@ func (it *oldTraceConverter) convertEvent(ev *oldtrace.Event) (OUT Event, ERR er return Event{}, fmt.Errorf("unexpected event type %v", ev.Type) } - if oldtrace.EventDescriptions[ev.Type].Stack { + if tracev1.EventDescriptions[ev.Type].Stack { if stackIDs := go122.Specs()[mappedType].StackIDs; len(stackIDs) > 0 { mappedArgs[stackIDs[0]-1] = uint64(ev.StkID) } } m := NoThread - if ev.P != -1 && ev.Type != oldtrace.EvCPUSample { + if ev.P != -1 && ev.Type != tracev1.EvCPUSample { if t, ok := it.procMs[ProcID(ev.P)]; ok { m = ThreadID(t) } } - if ev.Type == oldtrace.EvProcStop { + if ev.Type == tracev1.EvProcStop { delete(it.procMs, ProcID(ev.P)) } g := GoID(ev.G) @@ -559,10 +559,10 @@ func (it *oldTraceConverter) convertEvent(ev *oldtrace.Event) (OUT Event, ERR er return out, nil } -// convertOldFormat takes a fully loaded trace in the old trace format and +// convertV1Trace takes a fully loaded trace in the v1 trace format and // returns an iterator over events in the new format. -func convertOldFormat(pr oldtrace.Trace) *oldTraceConverter { - it := &oldTraceConverter{} +func convertV1Trace(pr tracev1.Trace) *traceV1Converter { + it := &traceV1Converter{} it.init(pr) return it } diff --git a/src/internal/trace/oldtrace_test.go b/src/internal/trace/tracev1_test.go similarity index 93% rename from src/internal/trace/oldtrace_test.go rename to src/internal/trace/tracev1_test.go index f812d5ef840700..0f8e24d2c4ec17 100644 --- a/src/internal/trace/oldtrace_test.go +++ b/src/internal/trace/tracev1_test.go @@ -13,15 +13,15 @@ import ( "testing" ) -func TestOldtrace(t *testing.T) { - traces, err := filepath.Glob("./internal/oldtrace/testdata/*_good") +func TestTraceV1(t *testing.T) { + traces, err := filepath.Glob("./internal/tracev1/testdata/*_good") if err != nil { t.Fatalf("failed to glob for tests: %s", err) } var testedUserRegions bool for _, p := range traces { p := p - testName, err := filepath.Rel("./internal/oldtrace/testdata", p) + testName, err := filepath.Rel("./internal/tracev1/testdata", p) if err != nil { t.Fatalf("failed to relativize testdata path: %s", err) } From bdbc5ca1bd0547d91441c4785854c82dbd852443 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sun, 22 Dec 2024 21:23:55 -0800 Subject: [PATCH 280/397] os: use AddCleanup, not SetFinalizer, for Process There is no reason to use a cleanup/finalizer for a Process that doesn't use a handle, because Release doesn't change anything visible about the process. For #70907 Change-Id: I3b92809175523ceee2e07d601cc2a8e8b86321e0 Reviewed-on: https://go-review.googlesource.com/c/go/+/638579 Reviewed-by: Carlos Amedee LUCI-TryBot-Result: Go LUCI Auto-Submit: Ian Lance Taylor Reviewed-by: Michael Knyszek --- src/os/exec.go | 14 +++++++++++--- src/os/exec_plan9.go | 3 --- src/os/exec_unix.go | 4 +--- src/os/exec_windows.go | 2 -- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/os/exec.go b/src/os/exec.go index 3f83139da5b2ff..212689b0faf0d0 100644 --- a/src/os/exec.go +++ b/src/os/exec.go @@ -52,6 +52,9 @@ type Process struct { // This is a pointer to a separate memory allocation // so that we can use runtime.AddCleanup. handle *processHandle + + // cleanup is used to clean up the process handle. + cleanup runtime.Cleanup } // processHandle holds an operating system handle to a process. @@ -111,7 +114,6 @@ func newPIDProcess(pid int) *Process { p := &Process{ Pid: pid, } - runtime.SetFinalizer(p, (*Process).Release) return p } @@ -128,7 +130,9 @@ func newHandleProcess(pid int, handle uintptr) *Process { Pid: pid, handle: ph, } - runtime.SetFinalizer(p, (*Process).Release) + + p.cleanup = runtime.AddCleanup(p, (*processHandle).release, ph) + return p } @@ -137,7 +141,6 @@ func newDoneProcess(pid int) *Process { Pid: pid, } p.state.Store(uint32(statusDone)) // No persistent reference, as there is no handle. - runtime.SetFinalizer(p, (*Process).Release) return p } @@ -197,7 +200,12 @@ func (p *Process) handlePersistentRelease(reason processStatus) processStatus { if !p.state.CompareAndSwap(state, uint32(reason)) { continue } + + // No need for more cleanup. + p.cleanup.Stop() + p.handle.release() + return status } } diff --git a/src/os/exec_plan9.go b/src/os/exec_plan9.go index bc7a9cdcbc5f74..6e32a1ae17db35 100644 --- a/src/os/exec_plan9.go +++ b/src/os/exec_plan9.go @@ -6,7 +6,6 @@ package os import ( "internal/itoa" - "runtime" "syscall" "time" ) @@ -95,8 +94,6 @@ func (p *Process) release() error { // Just mark the PID unusable. p.pidDeactivate(statusReleased) - // no need for a finalizer anymore - runtime.SetFinalizer(p, nil) return nil } diff --git a/src/os/exec_unix.go b/src/os/exec_unix.go index e58801b184cd2f..3b2552eb510d0b 100644 --- a/src/os/exec_unix.go +++ b/src/os/exec_unix.go @@ -8,7 +8,6 @@ package os import ( "errors" - "runtime" "syscall" "time" ) @@ -136,8 +135,7 @@ func (p *Process) release() error { // Just mark the PID unusable. p.pidDeactivate(statusReleased) } - // no need for a finalizer anymore - runtime.SetFinalizer(p, nil) + return nil } diff --git a/src/os/exec_windows.go b/src/os/exec_windows.go index 969eeb7c217db2..0eebe76da32e40 100644 --- a/src/os/exec_windows.go +++ b/src/os/exec_windows.go @@ -83,8 +83,6 @@ func (p *Process) release() error { return syscall.EINVAL } - // no need for a finalizer anymore - runtime.SetFinalizer(p, nil) return nil } From 646d285d7d0f5a8b18195e3fdfce7470219175c3 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 23 Dec 2024 11:27:13 -0800 Subject: [PATCH 281/397] os: simplify Process.Release Consolidate release/deactivation into a single doRelease method. It needs to check GOOS for backward compatibility, but it's simpler to keep all the logic in one place. Change-Id: I242eb084d44d2682f862a8fbf55c410fb8c53358 Reviewed-on: https://go-review.googlesource.com/c/go/+/638580 LUCI-TryBot-Result: Go LUCI Auto-Submit: Ian Lance Taylor Reviewed-by: Michael Knyszek Reviewed-by: Cherry Mui --- src/os/exec.go | 115 +++++++++++++++++------------------------ src/os/exec_plan9.go | 11 +--- src/os/exec_unix.go | 25 +-------- src/os/exec_windows.go | 19 ++----- src/os/pidfd_linux.go | 8 +-- 5 files changed, 61 insertions(+), 117 deletions(-) diff --git a/src/os/exec.go b/src/os/exec.go index 212689b0faf0d0..6206ae28cd3fea 100644 --- a/src/os/exec.go +++ b/src/os/exec.go @@ -176,40 +176,6 @@ func (p *Process) handleTransientRelease() { p.handle.release() } -// Drop the Process' persistent reference on the handle, deactivating future -// Wait/Signal calls with the passed reason. -// -// Returns the status prior to this call. If this is not statusOK, then the -// reference was not dropped or status changed. -func (p *Process) handlePersistentRelease(reason processStatus) processStatus { - if p.handle == nil { - panic("handlePersistentRelease called in invalid mode") - } - - for { - state := p.state.Load() - status := processStatus(state) - if status != statusOK { - // Both Release and successful Wait will drop the - // Process' persistent reference on the handle. We - // can't allow concurrent calls to drop the reference - // twice, so we use the status as a guard to ensure the - // reference is dropped exactly once. - return status - } - if !p.state.CompareAndSwap(state, uint32(reason)) { - continue - } - - // No need for more cleanup. - p.cleanup.Stop() - - p.handle.release() - - return status - } -} - func (p *Process) pidStatus() processStatus { if p.handle != nil { panic("pidStatus called in invalid mode") @@ -218,22 +184,6 @@ func (p *Process) pidStatus() processStatus { return processStatus(p.state.Load()) } -func (p *Process) pidDeactivate(reason processStatus) { - if p.handle != nil { - panic("pidDeactivate called in invalid mode") - } - - // Both Release and successful Wait will deactivate the PID. Only one - // of those should win, so nothing left to do here if the compare - // fails. - // - // N.B. This means that results can be inconsistent. e.g., with a - // racing Release and Wait, Wait may successfully wait on the process, - // returning the wait status, while future calls error with "process - // released" rather than "process done". - p.state.CompareAndSwap(0, uint32(reason)) -} - // ProcAttr holds the attributes that will be applied to a new process // started by StartProcess. type ProcAttr struct { @@ -310,23 +260,54 @@ func StartProcess(name string, argv []string, attr *ProcAttr) (*Process, error) // rendering it unusable in the future. // Release only needs to be called if [Process.Wait] is not. func (p *Process) Release() error { - // Note to future authors: the Release API is cursed. - // - // On Unix and Plan 9, Release sets p.Pid = -1. This is the only part of the - // Process API that is not thread-safe, but it can't be changed now. - // - // On Windows, Release does _not_ modify p.Pid. - // - // On Windows, Wait calls Release after successfully waiting to - // proactively clean up resources. - // - // On Unix and Plan 9, Wait also proactively cleans up resources, but - // can not call Release, as Wait does not set p.Pid = -1. - // - // On Unix and Plan 9, calling Release a second time has no effect. - // - // On Windows, calling Release a second time returns EINVAL. - return p.release() + // Unfortunately, for historical reasons, on systems other + // than Windows, Release sets the Pid field to -1. + // This causes the race detector to report a problem + // on concurrent calls to Release, but we can't change it now. + if runtime.GOOS != "windows" { + p.Pid = -1 + } + + oldStatus := p.doRelease(statusReleased) + + // For backward compatibility, on Windows only, + // we return EINVAL on a second call to Release. + if runtime.GOOS == "windows" { + if oldStatus == statusReleased { + return syscall.EINVAL + } + } + + return nil +} + +// doRelease releases a [Process], setting the status to newStatus. +// If the previous status is not statusOK, this does nothing. +// It returns the previous status. +func (p *Process) doRelease(newStatus processStatus) processStatus { + for { + state := p.state.Load() + oldStatus := processStatus(state) + if oldStatus != statusOK { + return oldStatus + } + + if !p.state.CompareAndSwap(state, uint32(newStatus)) { + continue + } + + // We have successfully released the Process. + // If it has a handle, release the reference we + // created in newHandleProcess. + if p.handle != nil { + // No need for more cleanup. + p.cleanup.Stop() + + p.handle.release() + } + + return statusOK + } } // Kill causes the [Process] to exit immediately. Kill does not wait until diff --git a/src/os/exec_plan9.go b/src/os/exec_plan9.go index 6e32a1ae17db35..357b925b360813 100644 --- a/src/os/exec_plan9.go +++ b/src/os/exec_plan9.go @@ -80,7 +80,7 @@ func (p *Process) wait() (ps *ProcessState, err error) { return nil, NewSyscallError("wait", err) } - p.pidDeactivate(statusDone) + p.doRelease(statusDone) ps = &ProcessState{ pid: waitmsg.Pid, status: &waitmsg, @@ -88,15 +88,6 @@ func (p *Process) wait() (ps *ProcessState, err error) { return ps, nil } -func (p *Process) release() error { - p.Pid = -1 - - // Just mark the PID unusable. - p.pidDeactivate(statusReleased) - - return nil -} - func findProcess(pid int) (p *Process, err error) { // NOOP for Plan 9. return newPIDProcess(pid), nil diff --git a/src/os/exec_unix.go b/src/os/exec_unix.go index 3b2552eb510d0b..f9be8dc06878ac 100644 --- a/src/os/exec_unix.go +++ b/src/os/exec_unix.go @@ -49,7 +49,7 @@ func (p *Process) pidWait() (*ProcessState, error) { if ready { // Mark the process done now, before the call to Wait4, // so that Process.pidSignal will not send a signal. - p.pidDeactivate(statusDone) + p.doRelease(statusDone) // Acquire a write lock on sigMu to wait for any // active call to the signal method to complete. p.sigMu.Lock() @@ -66,7 +66,7 @@ func (p *Process) pidWait() (*ProcessState, error) { if err != nil { return nil, NewSyscallError("wait", err) } - p.pidDeactivate(statusDone) + p.doRelease(statusDone) return &ProcessState{ pid: pid1, status: status, @@ -118,27 +118,6 @@ func convertESRCH(err error) error { return err } -func (p *Process) release() error { - // We clear the Pid field only for API compatibility. On Unix, Release - // has always set Pid to -1. Internally, the implementation relies - // solely on statusReleased to determine that the Process is released. - p.Pid = pidReleased - - if p.handle != nil { - // Drop the Process' reference and mark handle unusable for - // future calls. - // - // Ignore the return value: we don't care if this was a no-op - // racing with Wait, or a double Release. - p.handlePersistentRelease(statusReleased) - } else { - // Just mark the PID unusable. - p.pidDeactivate(statusReleased) - } - - return nil -} - func findProcess(pid int) (p *Process, err error) { h, err := pidfdFind(pid) if err == ErrProcessDone { diff --git a/src/os/exec_windows.go b/src/os/exec_windows.go index 0eebe76da32e40..68c7064d2dd0e5 100644 --- a/src/os/exec_windows.go +++ b/src/os/exec_windows.go @@ -44,7 +44,11 @@ func (p *Process) wait() (ps *ProcessState, err error) { if e != nil { return nil, NewSyscallError("GetProcessTimes", e) } - defer p.Release() + + // For compatibility we use statusReleased here rather + // than statusDone. + p.doRelease(statusReleased) + return &ProcessState{p.Pid, syscall.WaitStatus{ExitCode: ec}, &u}, nil } @@ -73,19 +77,6 @@ func (p *Process) signal(sig Signal) error { return syscall.Errno(syscall.EWINDOWS) } -func (p *Process) release() error { - // Drop the Process' reference and mark handle unusable for - // future calls. - // - // The API on Windows expects EINVAL if Release is called multiple - // times. - if old := p.handlePersistentRelease(statusReleased); old == statusReleased { - return syscall.EINVAL - } - - return nil -} - func (ph *processHandle) closeHandle() { syscall.CloseHandle(syscall.Handle(ph.handle)) } diff --git a/src/os/pidfd_linux.go b/src/os/pidfd_linux.go index fe4a743cf8a8e8..7a6f4cfad0b177 100644 --- a/src/os/pidfd_linux.go +++ b/src/os/pidfd_linux.go @@ -108,9 +108,11 @@ func (p *Process) pidfdWait() (*ProcessState, error) { if err != nil { return nil, NewSyscallError("waitid", err) } - // Release the Process' handle reference, in addition to the reference - // we took above. - p.handlePersistentRelease(statusDone) + + // Update the Process status to statusDone. + // This also releases a reference to the handle. + p.doRelease(statusDone) + return &ProcessState{ pid: int(info.Pid), status: info.WaitStatus(), From ff627d28dbc5fc3ef156c36f74b5dd026b41d21b Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 23 Dec 2024 11:44:42 -0800 Subject: [PATCH 282/397] os: improve comments for process support, minor code cleanup Change-Id: I97ecbc6fc0c73c6d8469144f86a7ad8c2655a658 Reviewed-on: https://go-review.googlesource.com/c/go/+/638581 Reviewed-by: Robert Griesemer LUCI-TryBot-Result: Go LUCI Auto-Submit: Ian Lance Taylor Reviewed-by: Cherry Mui --- src/os/exec.go | 14 ++++++++++++++ src/os/pidfd_linux.go | 6 ++++++ 2 files changed, 20 insertions(+) diff --git a/src/os/exec.go b/src/os/exec.go index 6206ae28cd3fea..43b33fe9442864 100644 --- a/src/os/exec.go +++ b/src/os/exec.go @@ -17,6 +17,7 @@ import ( // ErrProcessDone indicates a [Process] has finished. var ErrProcessDone = errors.New("os: process already finished") +// processStatus describes the status of a [Process]. type processStatus uint32 const ( @@ -110,6 +111,7 @@ func (ph *processHandle) release() { } } +// newPIDProcess returns a [Process] for the given PID. func newPIDProcess(pid int) *Process { p := &Process{ Pid: pid, @@ -117,6 +119,7 @@ func newPIDProcess(pid int) *Process { return p } +// newHandleProcess returns a [Process] with the given PID and handle. func newHandleProcess(pid int, handle uintptr) *Process { ph := &processHandle{ handle: handle, @@ -136,6 +139,9 @@ func newHandleProcess(pid int, handle uintptr) *Process { return p } +// newDoneProcess returns a [Process] for the given PID +// that is already marked as done. This is used on Unix systems +// if the process is known to not exist. func newDoneProcess(pid int) *Process { p := &Process{ Pid: pid, @@ -144,6 +150,8 @@ func newDoneProcess(pid int) *Process { return p } +// handleTransientAcquire returns the process handle or, +// if the process is not ready, the current status. func (p *Process) handleTransientAcquire() (uintptr, processStatus) { if p.handle == nil { panic("handleTransientAcquire called in invalid mode") @@ -169,6 +177,7 @@ func (p *Process) handleTransientAcquire() (uintptr, processStatus) { return 0, status } +// handleTransientRelease releases a handle returned by handleTransientAcquire. func (p *Process) handleTransientRelease() { if p.handle == nil { panic("handleTransientRelease called in invalid mode") @@ -176,6 +185,7 @@ func (p *Process) handleTransientRelease() { p.handle.release() } +// pidStatus returns the current process status. func (p *Process) pidStatus() processStatus { if p.handle != nil { panic("pidStatus called in invalid mode") @@ -301,6 +311,10 @@ func (p *Process) doRelease(newStatus processStatus) processStatus { // created in newHandleProcess. if p.handle != nil { // No need for more cleanup. + // We must stop the cleanup before calling release; + // otherwise the cleanup might run concurrently + // with the release, which would cause the reference + // counts to be invalid, causing a panic. p.cleanup.Stop() p.handle.release() diff --git a/src/os/pidfd_linux.go b/src/os/pidfd_linux.go index 7a6f4cfad0b177..5d89c9d39d60b7 100644 --- a/src/os/pidfd_linux.go +++ b/src/os/pidfd_linux.go @@ -66,6 +66,7 @@ func getPidfd(sysAttr *syscall.SysProcAttr, needDup bool) (uintptr, bool) { return uintptr(h), true } +// pidfdFind returns the process handle for pid. func pidfdFind(pid int) (uintptr, error) { if !pidfdWorks() { return 0, syscall.ENOSYS @@ -78,6 +79,8 @@ func pidfdFind(pid int) (uintptr, error) { return h, nil } +// pidfdWait waits for the process to complete, +// and updates the process status to done. func (p *Process) pidfdWait() (*ProcessState, error) { // When pidfd is used, there is no wait/kill race (described in CL 23967) // because the PID recycle issue doesn't exist (IOW, pidfd, unlike PID, @@ -120,6 +123,7 @@ func (p *Process) pidfdWait() (*ProcessState, error) { }, nil } +// pidfdSendSignal sends a signal to the process. func (p *Process) pidfdSendSignal(s syscall.Signal) error { handle, status := p.handleTransientAcquire() switch status { @@ -133,10 +137,12 @@ func (p *Process) pidfdSendSignal(s syscall.Signal) error { return convertESRCH(unix.PidFDSendSignal(handle, s)) } +// pidfdWorks returns whether we can use pidfd on this system. func pidfdWorks() bool { return checkPidfdOnce() == nil } +// checkPidfdOnce is used to only check whether pidfd works once. var checkPidfdOnce = sync.OnceValue(checkPidfd) // checkPidfd checks whether all required pidfd-related syscalls work. This From a4fcfaa1676f40a1dc5879cdabe98471c6054daf Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 6 Feb 2025 13:51:51 -0800 Subject: [PATCH 283/397] go/types, types2: better error messages for channel sends and receives Use the same code pattern for sends and receives and factor it out into a new helper method Checker.chanElem. Provide the exact error cause rather than simply referring to the core type. For #70128. Change-Id: I4a0b597a487b78c057eebe06c4ac28f9bf1f7719 Reviewed-on: https://go-review.googlesource.com/c/go/+/647455 Auto-Submit: Robert Griesemer Reviewed-by: Robert Findley Reviewed-by: Robert Griesemer LUCI-TryBot-Result: Go LUCI --- src/cmd/compile/internal/types2/expr.go | 79 +++++++++++++----- src/cmd/compile/internal/types2/stmt.go | 16 +--- src/go/types/expr.go | 80 ++++++++++++++----- src/go/types/stmt.go | 16 +--- .../types/testdata/fixedbugs/issue43671.go | 8 +- .../types/testdata/fixedbugs/issue47115.go | 8 +- 6 files changed, 134 insertions(+), 73 deletions(-) diff --git a/src/cmd/compile/internal/types2/expr.go b/src/cmd/compile/internal/types2/expr.go index 28a5d788724a90..a73e073ac3eeb1 100644 --- a/src/cmd/compile/internal/types2/expr.go +++ b/src/cmd/compile/internal/types2/expr.go @@ -148,26 +148,13 @@ func (check *Checker) unary(x *operand, e *syntax.Operation) { return case syntax.Recv: - u := coreType(x.typ) - if u == nil { - check.errorf(x, InvalidReceive, invalidOp+"cannot receive from %s (no core type)", x) - x.mode = invalid + if elem := check.chanElem(x, x, true); elem != nil { + x.mode = commaok + x.typ = elem + check.hasCallOrRecv = true return } - ch, _ := u.(*Chan) - if ch == nil { - check.errorf(x, InvalidReceive, invalidOp+"cannot receive from non-channel %s", x) - x.mode = invalid - return - } - if ch.dir == SendOnly { - check.errorf(x, InvalidReceive, invalidOp+"cannot receive from send-only channel %s", x) - x.mode = invalid - return - } - x.mode = commaok - x.typ = ch.elem - check.hasCallOrRecv = true + x.mode = invalid return case syntax.Tilde: @@ -205,6 +192,62 @@ func (check *Checker) unary(x *operand, e *syntax.Operation) { // x.typ remains unchanged } +// chanElem returns the channel element type of x for a receive from x (recv == true) +// or send to x (recv == false) operation. If the operation is not valid, chanElem +// reports an error and returns nil. +func (check *Checker) chanElem(pos poser, x *operand, recv bool) Type { + var elem Type + var cause string + typeset(x.typ, func(t, u Type) bool { + if u == nil { + // Type set contains no explicit terms. + // It is either empty or contains all types (any) + cause = "no specific channel type" + return false + } + ch, _ := u.(*Chan) + if ch == nil { + cause = check.sprintf("non-channel %s", t) + return false + } + if recv && ch.dir == SendOnly { + cause = check.sprintf("send-only channel %s", t) + return false + } + if !recv && ch.dir == RecvOnly { + cause = check.sprintf("receive-only channel %s", t) + return false + } + if elem != nil && !Identical(elem, ch.elem) { + cause = check.sprintf("channels with different element types %s and %s", elem, ch.elem) + return false + } + elem = ch.elem + return true + }) + + if cause == "" { + return elem + } + + if recv { + if isTypeParam(x.typ) { + check.errorf(pos, InvalidReceive, invalidOp+"cannot receive from %s: type set contains %s", x, cause) + } else { + // In this case, only the non-channel and send-only channel error are possible. + check.errorf(pos, InvalidReceive, invalidOp+"cannot receive from %s %s", cause, x) + } + } else { + if isTypeParam(x.typ) { + check.errorf(pos, InvalidSend, invalidOp+"cannot send to %s: type set contains %s", x, cause) + } else { + // In this case, only the non-channel and receive-only channel error are possible. + check.errorf(pos, InvalidSend, invalidOp+"cannot send to %s %s", cause, x) + } + } + return nil +} + func isShift(op syntax.Operator) bool { return op == syntax.Shl || op == syntax.Shr } diff --git a/src/cmd/compile/internal/types2/stmt.go b/src/cmd/compile/internal/types2/stmt.go index c46ea7a091afd2..60955da4fc7a20 100644 --- a/src/cmd/compile/internal/types2/stmt.go +++ b/src/cmd/compile/internal/types2/stmt.go @@ -465,21 +465,9 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) { if ch.mode == invalid || val.mode == invalid { return } - u := coreType(ch.typ) - if u == nil { - check.errorf(s, InvalidSend, invalidOp+"cannot send to %s: no core type", &ch) - return - } - uch, _ := u.(*Chan) - if uch == nil { - check.errorf(s, InvalidSend, invalidOp+"cannot send to non-channel %s", &ch) - return - } - if uch.dir == RecvOnly { - check.errorf(s, InvalidSend, invalidOp+"cannot send to receive-only channel %s", &ch) - return + if elem := check.chanElem(s, &ch, false); elem != nil { + check.assignment(&val, elem, "send") } - check.assignment(&val, uch.elem, "send") case *syntax.AssignStmt: if s.Rhs == nil { diff --git a/src/go/types/expr.go b/src/go/types/expr.go index e2e8928a12391e..aaafe95eba0afb 100644 --- a/src/go/types/expr.go +++ b/src/go/types/expr.go @@ -147,27 +147,13 @@ func (check *Checker) unary(x *operand, e *ast.UnaryExpr) { return case token.ARROW: - u := coreType(x.typ) - if u == nil { - check.errorf(x, InvalidReceive, invalidOp+"cannot receive from %s (no core type)", x) - x.mode = invalid + if elem := check.chanElem(x, x, true); elem != nil { + x.mode = commaok + x.typ = elem + check.hasCallOrRecv = true return } - ch, _ := u.(*Chan) - if ch == nil { - check.errorf(x, InvalidReceive, invalidOp+"cannot receive from non-channel %s", x) - x.mode = invalid - return - } - if ch.dir == SendOnly { - check.errorf(x, InvalidReceive, invalidOp+"cannot receive from send-only channel %s", x) - x.mode = invalid - return - } - - x.mode = commaok - x.typ = ch.elem - check.hasCallOrRecv = true + x.mode = invalid return case token.TILDE: @@ -205,6 +191,62 @@ func (check *Checker) unary(x *operand, e *ast.UnaryExpr) { // x.typ remains unchanged } +// chanElem returns the channel element type of x for a receive from x (recv == true) +// or send to x (recv == false) operation. If the operation is not valid, chanElem +// reports an error and returns nil. +func (check *Checker) chanElem(pos positioner, x *operand, recv bool) Type { + var elem Type + var cause string + typeset(x.typ, func(t, u Type) bool { + if u == nil { + // Type set contains no explicit terms. + // It is either empty or contains all types (any) + cause = "no specific channel type" + return false + } + ch, _ := u.(*Chan) + if ch == nil { + cause = check.sprintf("non-channel %s", t) + return false + } + if recv && ch.dir == SendOnly { + cause = check.sprintf("send-only channel %s", t) + return false + } + if !recv && ch.dir == RecvOnly { + cause = check.sprintf("receive-only channel %s", t) + return false + } + if elem != nil && !Identical(elem, ch.elem) { + cause = check.sprintf("channels with different element types %s and %s", elem, ch.elem) + return false + } + elem = ch.elem + return true + }) + + if cause == "" { + return elem + } + + if recv { + if isTypeParam(x.typ) { + check.errorf(pos, InvalidReceive, invalidOp+"cannot receive from %s: type set contains %s", x, cause) + } else { + // In this case, only the non-channel and send-only channel error are possible. + check.errorf(pos, InvalidReceive, invalidOp+"cannot receive from %s %s", cause, x) + } + } else { + if isTypeParam(x.typ) { + check.errorf(pos, InvalidSend, invalidOp+"cannot send to %s: type set contains %s", x, cause) + } else { + // In this case, only the non-channel and receive-only channel error are possible. + check.errorf(pos, InvalidSend, invalidOp+"cannot send to %s %s", cause, x) + } + } + return nil +} + func isShift(op token.Token) bool { return op == token.SHL || op == token.SHR } diff --git a/src/go/types/stmt.go b/src/go/types/stmt.go index de3d01e8dd2b43..d6a9fdd2de315f 100644 --- a/src/go/types/stmt.go +++ b/src/go/types/stmt.go @@ -466,21 +466,9 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) { if ch.mode == invalid || val.mode == invalid { return } - u := coreType(ch.typ) - if u == nil { - check.errorf(inNode(s, s.Arrow), InvalidSend, invalidOp+"cannot send to %s: no core type", &ch) - return - } - uch, _ := u.(*Chan) - if uch == nil { - check.errorf(inNode(s, s.Arrow), InvalidSend, invalidOp+"cannot send to non-channel %s", &ch) - return - } - if uch.dir == RecvOnly { - check.errorf(inNode(s, s.Arrow), InvalidSend, invalidOp+"cannot send to receive-only channel %s", &ch) - return + if elem := check.chanElem(inNode(s, s.Arrow), &ch, false); elem != nil { + check.assignment(&val, elem, "send") } - check.assignment(&val, uch.elem, "send") case *ast.IncDecStmt: var op token.Token diff --git a/src/internal/types/testdata/fixedbugs/issue43671.go b/src/internal/types/testdata/fixedbugs/issue43671.go index be4c9ee5dd1f51..19da7e0ccca207 100644 --- a/src/internal/types/testdata/fixedbugs/issue43671.go +++ b/src/internal/types/testdata/fixedbugs/issue43671.go @@ -12,11 +12,11 @@ type C4 interface{ chan int | chan<- int } type C5[T any] interface{ ~chan T | <-chan T } func _[T any](ch T) { - <-ch // ERRORx `cannot receive from ch .* \(no core type\)` + <-ch // ERRORx `cannot receive from ch .*: type set contains no specific channel type` } func _[T C0](ch T) { - <-ch // ERROR "cannot receive from non-channel ch" + <-ch // ERRORx `cannot receive from ch .*: type set contains non-channel int` } func _[T C1](ch T) { @@ -28,11 +28,11 @@ func _[T C2](ch T) { } func _[T C3](ch T) { - <-ch // ERRORx `cannot receive from ch .* \(no core type\)` + <-ch // ERRORx `cannot receive from ch .*: type set contains channels with different element types int and float32` } func _[T C4](ch T) { - <-ch // ERROR "cannot receive from send-only channel" + <-ch // ERRORx `cannot receive from ch .*: type set contains send-only channel chan<- int` } func _[T C5[X], X any](ch T, x X) { diff --git a/src/internal/types/testdata/fixedbugs/issue47115.go b/src/internal/types/testdata/fixedbugs/issue47115.go index 2d2be34104216e..1de85b3791a2d0 100644 --- a/src/internal/types/testdata/fixedbugs/issue47115.go +++ b/src/internal/types/testdata/fixedbugs/issue47115.go @@ -12,11 +12,11 @@ type C4 interface{ chan int | chan<- int } type C5[T any] interface{ ~chan T | chan<- T } func _[T any](ch T) { - ch <- /* ERRORx `cannot send to ch .* no core type` */ 0 + ch <- /* ERRORx `cannot send to ch .*: type set contains no specific channel type` */ 0 } func _[T C0](ch T) { - ch <- /* ERROR "cannot send to non-channel" */ 0 + ch <- /* ERRORx `cannot send to ch .*: type set contains non-channel int` */ 0 } func _[T C1](ch T) { @@ -24,11 +24,11 @@ func _[T C1](ch T) { } func _[T C2](ch T) { - ch <-/* ERROR "cannot send to receive-only channel" */ 0 + ch <- /* ERRORx `cannot send to ch .*: type set contains receive-only channel <-chan int` */ 0 } func _[T C3](ch T) { - ch <- /* ERRORx `cannot send to ch .* no core type` */ 0 + ch <- /* ERRORx `cannot send to ch .*: type set contains channels with different element types` */ 0 } func _[T C4](ch T) { From 215de81513286c010951624243c2923f7dc79675 Mon Sep 17 00:00:00 2001 From: Meng Zhuo Date: Thu, 12 Sep 2024 19:46:20 +0800 Subject: [PATCH 284/397] cmd/compile: don't merge symbols on riscv64 when dynamic linking Each plugin is compiled as a separate shared object, with its own symbol table. When dynamic linking plugin symbols are resolved within the plugin's scope, not globally merged to avoid conflicts. Change-Id: I9e6986085855c17fbd6c39b937cb6129d216f5e9 Reviewed-on: https://go-review.googlesource.com/c/go/+/435015 LUCI-TryBot-Result: Go LUCI Reviewed-by: Joel Sing Reviewed-by: Michael Pratt Reviewed-by: Cherry Mui --- .../compile/internal/ssa/_gen/RISCV64.rules | 82 +++------- .../compile/internal/ssa/rewriteRISCV64.go | 154 +++++++++++------- 2 files changed, 115 insertions(+), 121 deletions(-) diff --git a/src/cmd/compile/internal/ssa/_gen/RISCV64.rules b/src/cmd/compile/internal/ssa/_gen/RISCV64.rules index 9ae96043810cfd..a69df619a576c6 100644 --- a/src/cmd/compile/internal/ssa/_gen/RISCV64.rules +++ b/src/cmd/compile/internal/ssa/_gen/RISCV64.rules @@ -270,65 +270,29 @@ // We need to fold MOVaddr into the LD/MOVDstore ops so that the live variable analysis // knows what variables are being read/written by the ops. -(MOVBUload [off1] {sym1} (MOVaddr [off2] {sym2} base) mem) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) => - (MOVBUload [off1+off2] {mergeSym(sym1,sym2)} base mem) -(MOVBload [off1] {sym1} (MOVaddr [off2] {sym2} base) mem) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) => - (MOVBload [off1+off2] {mergeSym(sym1,sym2)} base mem) -(MOVHUload [off1] {sym1} (MOVaddr [off2] {sym2} base) mem) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) => - (MOVHUload [off1+off2] {mergeSym(sym1,sym2)} base mem) -(MOVHload [off1] {sym1} (MOVaddr [off2] {sym2} base) mem) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) => - (MOVHload [off1+off2] {mergeSym(sym1,sym2)} base mem) -(MOVWUload [off1] {sym1} (MOVaddr [off2] {sym2} base) mem) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) => - (MOVWUload [off1+off2] {mergeSym(sym1,sym2)} base mem) -(MOVWload [off1] {sym1} (MOVaddr [off2] {sym2} base) mem) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) => - (MOVWload [off1+off2] {mergeSym(sym1,sym2)} base mem) -(MOVDload [off1] {sym1} (MOVaddr [off2] {sym2} base) mem) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) => - (MOVDload [off1+off2] {mergeSym(sym1,sym2)} base mem) - -(MOVBstore [off1] {sym1} (MOVaddr [off2] {sym2} base) val mem) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) => - (MOVBstore [off1+off2] {mergeSym(sym1,sym2)} base val mem) -(MOVHstore [off1] {sym1} (MOVaddr [off2] {sym2} base) val mem) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) => - (MOVHstore [off1+off2] {mergeSym(sym1,sym2)} base val mem) -(MOVWstore [off1] {sym1} (MOVaddr [off2] {sym2} base) val mem) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) => - (MOVWstore [off1+off2] {mergeSym(sym1,sym2)} base val mem) -(MOVDstore [off1] {sym1} (MOVaddr [off2] {sym2} base) val mem) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) => - (MOVDstore [off1+off2] {mergeSym(sym1,sym2)} base val mem) -(MOVBstorezero [off1] {sym1} (MOVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) => - (MOVBstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem) -(MOVHstorezero [off1] {sym1} (MOVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) => - (MOVHstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem) -(MOVWstorezero [off1] {sym1} (MOVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) => - (MOVWstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem) -(MOVDstorezero [off1] {sym1} (MOVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) => - (MOVDstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem) - -(MOVBUload [off1] {sym} (ADDI [off2] base) mem) && is32Bit(int64(off1)+off2) => - (MOVBUload [off1+int32(off2)] {sym} base mem) -(MOVBload [off1] {sym} (ADDI [off2] base) mem) && is32Bit(int64(off1)+off2) => - (MOVBload [off1+int32(off2)] {sym} base mem) -(MOVHUload [off1] {sym} (ADDI [off2] base) mem) && is32Bit(int64(off1)+off2) => - (MOVHUload [off1+int32(off2)] {sym} base mem) -(MOVHload [off1] {sym} (ADDI [off2] base) mem) && is32Bit(int64(off1)+off2) => - (MOVHload [off1+int32(off2)] {sym} base mem) -(MOVWUload [off1] {sym} (ADDI [off2] base) mem) && is32Bit(int64(off1)+off2) => - (MOVWUload [off1+int32(off2)] {sym} base mem) -(MOVWload [off1] {sym} (ADDI [off2] base) mem) && is32Bit(int64(off1)+off2) => - (MOVWload [off1+int32(off2)] {sym} base mem) -(MOVDload [off1] {sym} (ADDI [off2] base) mem) && is32Bit(int64(off1)+off2) => - (MOVDload [off1+int32(off2)] {sym} base mem) - -(MOVBstore [off1] {sym} (ADDI [off2] base) val mem) && is32Bit(int64(off1)+off2) => - (MOVBstore [off1+int32(off2)] {sym} base val mem) -(MOVHstore [off1] {sym} (ADDI [off2] base) val mem) && is32Bit(int64(off1)+off2) => - (MOVHstore [off1+int32(off2)] {sym} base val mem) -(MOVWstore [off1] {sym} (ADDI [off2] base) val mem) && is32Bit(int64(off1)+off2) => - (MOVWstore [off1+int32(off2)] {sym} base val mem) -(MOVDstore [off1] {sym} (ADDI [off2] base) val mem) && is32Bit(int64(off1)+off2) => - (MOVDstore [off1+int32(off2)] {sym} base val mem) -(MOVBstorezero [off1] {sym} (ADDI [off2] ptr) mem) && is32Bit(int64(off1)+off2) => (MOVBstorezero [off1+int32(off2)] {sym} ptr mem) -(MOVHstorezero [off1] {sym} (ADDI [off2] ptr) mem) && is32Bit(int64(off1)+off2) => (MOVHstorezero [off1+int32(off2)] {sym} ptr mem) -(MOVWstorezero [off1] {sym} (ADDI [off2] ptr) mem) && is32Bit(int64(off1)+off2) => (MOVWstorezero [off1+int32(off2)] {sym} ptr mem) -(MOVDstorezero [off1] {sym} (ADDI [off2] ptr) mem) && is32Bit(int64(off1)+off2) => (MOVDstorezero [off1+int32(off2)] {sym} ptr mem) +(MOV(B|BU|H|HU|W|WU|D)load [off1] {sym1} (MOVaddr [off2] {sym2} base) mem) && + is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && + (base.Op != OpSB || !config.ctxt.Flag_dynlink) => + (MOV(B|BU|H|HU|W|WU|D)load [off1+off2] {mergeSym(sym1,sym2)} base mem) + +(MOV(B|H|W|D)store [off1] {sym1} (MOVaddr [off2] {sym2} base) val mem) && + is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && + (base.Op != OpSB || !config.ctxt.Flag_dynlink) => + (MOV(B|H|W|D)store [off1+off2] {mergeSym(sym1,sym2)} base val mem) + +(MOV(B|H|W|D)storezero [off1] {sym1} (MOVaddr [off2] {sym2} base) mem) && + canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) && + (base.Op != OpSB || !config.ctxt.Flag_dynlink) => + (MOV(B|H|W|D)storezero [off1+off2] {mergeSym(sym1,sym2)} base mem) + +(MOV(B|BU|H|HU|W|WU|D)load [off1] {sym} (ADDI [off2] base) mem) && is32Bit(int64(off1)+off2) => + (MOV(B|BU|H|HU|W|WU|D)load [off1+int32(off2)] {sym} base mem) + +(MOV(B|H|W|D)store [off1] {sym} (ADDI [off2] base) val mem) && is32Bit(int64(off1)+off2) => + (MOV(B|H|W|D)store [off1+int32(off2)] {sym} base val mem) + +(MOV(B|H|W|D)storezero [off1] {sym} (ADDI [off2] base) mem) && is32Bit(int64(off1)+off2) => + (MOV(B|H|W|D)storezero [off1+int32(off2)] {sym} base mem) // Similarly, fold ADDI into MOVaddr to avoid confusing live variable analysis // with OffPtr -> ADDI. diff --git a/src/cmd/compile/internal/ssa/rewriteRISCV64.go b/src/cmd/compile/internal/ssa/rewriteRISCV64.go index aa44ab311e92af..3a044b5c9d2602 100644 --- a/src/cmd/compile/internal/ssa/rewriteRISCV64.go +++ b/src/cmd/compile/internal/ssa/rewriteRISCV64.go @@ -4008,8 +4008,10 @@ func rewriteValueRISCV64_OpRISCV64FSUBS(v *Value) bool { func rewriteValueRISCV64_OpRISCV64MOVBUload(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] + b := v.Block + config := b.Func.Config // match: (MOVBUload [off1] {sym1} (MOVaddr [off2] {sym2} base) mem) - // cond: is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) + // cond: is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_dynlink) // result: (MOVBUload [off1+off2] {mergeSym(sym1,sym2)} base mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -4021,7 +4023,7 @@ func rewriteValueRISCV64_OpRISCV64MOVBUload(v *Value) bool { sym2 := auxToSym(v_0.Aux) base := v_0.Args[0] mem := v_1 - if !(is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2)) { + if !(is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_dynlink)) { break } v.reset(OpRISCV64MOVBUload) @@ -4315,8 +4317,10 @@ func rewriteValueRISCV64_OpRISCV64MOVBUreg(v *Value) bool { func rewriteValueRISCV64_OpRISCV64MOVBload(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] + b := v.Block + config := b.Func.Config // match: (MOVBload [off1] {sym1} (MOVaddr [off2] {sym2} base) mem) - // cond: is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) + // cond: is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_dynlink) // result: (MOVBload [off1+off2] {mergeSym(sym1,sym2)} base mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -4328,7 +4332,7 @@ func rewriteValueRISCV64_OpRISCV64MOVBload(v *Value) bool { sym2 := auxToSym(v_0.Aux) base := v_0.Args[0] mem := v_1 - if !(is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2)) { + if !(is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_dynlink)) { break } v.reset(OpRISCV64MOVBload) @@ -4441,8 +4445,10 @@ func rewriteValueRISCV64_OpRISCV64MOVBstore(v *Value) bool { v_2 := v.Args[2] v_1 := v.Args[1] v_0 := v.Args[0] + b := v.Block + config := b.Func.Config // match: (MOVBstore [off1] {sym1} (MOVaddr [off2] {sym2} base) val mem) - // cond: is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) + // cond: is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_dynlink) // result: (MOVBstore [off1+off2] {mergeSym(sym1,sym2)} base val mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -4455,7 +4461,7 @@ func rewriteValueRISCV64_OpRISCV64MOVBstore(v *Value) bool { base := v_0.Args[0] val := v_1 mem := v_2 - if !(is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2)) { + if !(is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_dynlink)) { break } v.reset(OpRISCV64MOVBstore) @@ -4609,9 +4615,11 @@ func rewriteValueRISCV64_OpRISCV64MOVBstore(v *Value) bool { func rewriteValueRISCV64_OpRISCV64MOVBstorezero(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] - // match: (MOVBstorezero [off1] {sym1} (MOVaddr [off2] {sym2} ptr) mem) - // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) - // result: (MOVBstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem) + b := v.Block + config := b.Func.Config + // match: (MOVBstorezero [off1] {sym1} (MOVaddr [off2] {sym2} base) mem) + // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) && (base.Op != OpSB || !config.ctxt.Flag_dynlink) + // result: (MOVBstorezero [off1+off2] {mergeSym(sym1,sym2)} base mem) for { off1 := auxIntToInt32(v.AuxInt) sym1 := auxToSym(v.Aux) @@ -4620,20 +4628,20 @@ func rewriteValueRISCV64_OpRISCV64MOVBstorezero(v *Value) bool { } off2 := auxIntToInt32(v_0.AuxInt) sym2 := auxToSym(v_0.Aux) - ptr := v_0.Args[0] + base := v_0.Args[0] mem := v_1 - if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))) { + if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) && (base.Op != OpSB || !config.ctxt.Flag_dynlink)) { break } v.reset(OpRISCV64MOVBstorezero) v.AuxInt = int32ToAuxInt(off1 + off2) v.Aux = symToAux(mergeSym(sym1, sym2)) - v.AddArg2(ptr, mem) + v.AddArg2(base, mem) return true } - // match: (MOVBstorezero [off1] {sym} (ADDI [off2] ptr) mem) + // match: (MOVBstorezero [off1] {sym} (ADDI [off2] base) mem) // cond: is32Bit(int64(off1)+off2) - // result: (MOVBstorezero [off1+int32(off2)] {sym} ptr mem) + // result: (MOVBstorezero [off1+int32(off2)] {sym} base mem) for { off1 := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -4641,7 +4649,7 @@ func rewriteValueRISCV64_OpRISCV64MOVBstorezero(v *Value) bool { break } off2 := auxIntToInt64(v_0.AuxInt) - ptr := v_0.Args[0] + base := v_0.Args[0] mem := v_1 if !(is32Bit(int64(off1) + off2)) { break @@ -4649,7 +4657,7 @@ func rewriteValueRISCV64_OpRISCV64MOVBstorezero(v *Value) bool { v.reset(OpRISCV64MOVBstorezero) v.AuxInt = int32ToAuxInt(off1 + int32(off2)) v.Aux = symToAux(sym) - v.AddArg2(ptr, mem) + v.AddArg2(base, mem) return true } return false @@ -4657,8 +4665,10 @@ func rewriteValueRISCV64_OpRISCV64MOVBstorezero(v *Value) bool { func rewriteValueRISCV64_OpRISCV64MOVDload(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] + b := v.Block + config := b.Func.Config // match: (MOVDload [off1] {sym1} (MOVaddr [off2] {sym2} base) mem) - // cond: is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) + // cond: is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_dynlink) // result: (MOVDload [off1+off2] {mergeSym(sym1,sym2)} base mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -4670,7 +4680,7 @@ func rewriteValueRISCV64_OpRISCV64MOVDload(v *Value) bool { sym2 := auxToSym(v_0.Aux) base := v_0.Args[0] mem := v_1 - if !(is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2)) { + if !(is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_dynlink)) { break } v.reset(OpRISCV64MOVDload) @@ -4737,8 +4747,10 @@ func rewriteValueRISCV64_OpRISCV64MOVDstore(v *Value) bool { v_2 := v.Args[2] v_1 := v.Args[1] v_0 := v.Args[0] + b := v.Block + config := b.Func.Config // match: (MOVDstore [off1] {sym1} (MOVaddr [off2] {sym2} base) val mem) - // cond: is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) + // cond: is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_dynlink) // result: (MOVDstore [off1+off2] {mergeSym(sym1,sym2)} base val mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -4751,7 +4763,7 @@ func rewriteValueRISCV64_OpRISCV64MOVDstore(v *Value) bool { base := v_0.Args[0] val := v_1 mem := v_2 - if !(is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2)) { + if !(is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_dynlink)) { break } v.reset(OpRISCV64MOVDstore) @@ -4803,9 +4815,11 @@ func rewriteValueRISCV64_OpRISCV64MOVDstore(v *Value) bool { func rewriteValueRISCV64_OpRISCV64MOVDstorezero(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] - // match: (MOVDstorezero [off1] {sym1} (MOVaddr [off2] {sym2} ptr) mem) - // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) - // result: (MOVDstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem) + b := v.Block + config := b.Func.Config + // match: (MOVDstorezero [off1] {sym1} (MOVaddr [off2] {sym2} base) mem) + // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) && (base.Op != OpSB || !config.ctxt.Flag_dynlink) + // result: (MOVDstorezero [off1+off2] {mergeSym(sym1,sym2)} base mem) for { off1 := auxIntToInt32(v.AuxInt) sym1 := auxToSym(v.Aux) @@ -4814,20 +4828,20 @@ func rewriteValueRISCV64_OpRISCV64MOVDstorezero(v *Value) bool { } off2 := auxIntToInt32(v_0.AuxInt) sym2 := auxToSym(v_0.Aux) - ptr := v_0.Args[0] + base := v_0.Args[0] mem := v_1 - if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))) { + if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) && (base.Op != OpSB || !config.ctxt.Flag_dynlink)) { break } v.reset(OpRISCV64MOVDstorezero) v.AuxInt = int32ToAuxInt(off1 + off2) v.Aux = symToAux(mergeSym(sym1, sym2)) - v.AddArg2(ptr, mem) + v.AddArg2(base, mem) return true } - // match: (MOVDstorezero [off1] {sym} (ADDI [off2] ptr) mem) + // match: (MOVDstorezero [off1] {sym} (ADDI [off2] base) mem) // cond: is32Bit(int64(off1)+off2) - // result: (MOVDstorezero [off1+int32(off2)] {sym} ptr mem) + // result: (MOVDstorezero [off1+int32(off2)] {sym} base mem) for { off1 := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -4835,7 +4849,7 @@ func rewriteValueRISCV64_OpRISCV64MOVDstorezero(v *Value) bool { break } off2 := auxIntToInt64(v_0.AuxInt) - ptr := v_0.Args[0] + base := v_0.Args[0] mem := v_1 if !(is32Bit(int64(off1) + off2)) { break @@ -4843,7 +4857,7 @@ func rewriteValueRISCV64_OpRISCV64MOVDstorezero(v *Value) bool { v.reset(OpRISCV64MOVDstorezero) v.AuxInt = int32ToAuxInt(off1 + int32(off2)) v.Aux = symToAux(sym) - v.AddArg2(ptr, mem) + v.AddArg2(base, mem) return true } return false @@ -4851,8 +4865,10 @@ func rewriteValueRISCV64_OpRISCV64MOVDstorezero(v *Value) bool { func rewriteValueRISCV64_OpRISCV64MOVHUload(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] + b := v.Block + config := b.Func.Config // match: (MOVHUload [off1] {sym1} (MOVaddr [off2] {sym2} base) mem) - // cond: is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) + // cond: is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_dynlink) // result: (MOVHUload [off1+off2] {mergeSym(sym1,sym2)} base mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -4864,7 +4880,7 @@ func rewriteValueRISCV64_OpRISCV64MOVHUload(v *Value) bool { sym2 := auxToSym(v_0.Aux) base := v_0.Args[0] mem := v_1 - if !(is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2)) { + if !(is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_dynlink)) { break } v.reset(OpRISCV64MOVHUload) @@ -5015,8 +5031,10 @@ func rewriteValueRISCV64_OpRISCV64MOVHUreg(v *Value) bool { func rewriteValueRISCV64_OpRISCV64MOVHload(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] + b := v.Block + config := b.Func.Config // match: (MOVHload [off1] {sym1} (MOVaddr [off2] {sym2} base) mem) - // cond: is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) + // cond: is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_dynlink) // result: (MOVHload [off1+off2] {mergeSym(sym1,sym2)} base mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -5028,7 +5046,7 @@ func rewriteValueRISCV64_OpRISCV64MOVHload(v *Value) bool { sym2 := auxToSym(v_0.Aux) base := v_0.Args[0] mem := v_1 - if !(is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2)) { + if !(is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_dynlink)) { break } v.reset(OpRISCV64MOVHload) @@ -5185,8 +5203,10 @@ func rewriteValueRISCV64_OpRISCV64MOVHstore(v *Value) bool { v_2 := v.Args[2] v_1 := v.Args[1] v_0 := v.Args[0] + b := v.Block + config := b.Func.Config // match: (MOVHstore [off1] {sym1} (MOVaddr [off2] {sym2} base) val mem) - // cond: is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) + // cond: is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_dynlink) // result: (MOVHstore [off1+off2] {mergeSym(sym1,sym2)} base val mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -5199,7 +5219,7 @@ func rewriteValueRISCV64_OpRISCV64MOVHstore(v *Value) bool { base := v_0.Args[0] val := v_1 mem := v_2 - if !(is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2)) { + if !(is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_dynlink)) { break } v.reset(OpRISCV64MOVHstore) @@ -5319,9 +5339,11 @@ func rewriteValueRISCV64_OpRISCV64MOVHstore(v *Value) bool { func rewriteValueRISCV64_OpRISCV64MOVHstorezero(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] - // match: (MOVHstorezero [off1] {sym1} (MOVaddr [off2] {sym2} ptr) mem) - // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) - // result: (MOVHstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem) + b := v.Block + config := b.Func.Config + // match: (MOVHstorezero [off1] {sym1} (MOVaddr [off2] {sym2} base) mem) + // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) && (base.Op != OpSB || !config.ctxt.Flag_dynlink) + // result: (MOVHstorezero [off1+off2] {mergeSym(sym1,sym2)} base mem) for { off1 := auxIntToInt32(v.AuxInt) sym1 := auxToSym(v.Aux) @@ -5330,20 +5352,20 @@ func rewriteValueRISCV64_OpRISCV64MOVHstorezero(v *Value) bool { } off2 := auxIntToInt32(v_0.AuxInt) sym2 := auxToSym(v_0.Aux) - ptr := v_0.Args[0] + base := v_0.Args[0] mem := v_1 - if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))) { + if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) && (base.Op != OpSB || !config.ctxt.Flag_dynlink)) { break } v.reset(OpRISCV64MOVHstorezero) v.AuxInt = int32ToAuxInt(off1 + off2) v.Aux = symToAux(mergeSym(sym1, sym2)) - v.AddArg2(ptr, mem) + v.AddArg2(base, mem) return true } - // match: (MOVHstorezero [off1] {sym} (ADDI [off2] ptr) mem) + // match: (MOVHstorezero [off1] {sym} (ADDI [off2] base) mem) // cond: is32Bit(int64(off1)+off2) - // result: (MOVHstorezero [off1+int32(off2)] {sym} ptr mem) + // result: (MOVHstorezero [off1+int32(off2)] {sym} base mem) for { off1 := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -5351,7 +5373,7 @@ func rewriteValueRISCV64_OpRISCV64MOVHstorezero(v *Value) bool { break } off2 := auxIntToInt64(v_0.AuxInt) - ptr := v_0.Args[0] + base := v_0.Args[0] mem := v_1 if !(is32Bit(int64(off1) + off2)) { break @@ -5359,7 +5381,7 @@ func rewriteValueRISCV64_OpRISCV64MOVHstorezero(v *Value) bool { v.reset(OpRISCV64MOVHstorezero) v.AuxInt = int32ToAuxInt(off1 + int32(off2)) v.Aux = symToAux(sym) - v.AddArg2(ptr, mem) + v.AddArg2(base, mem) return true } return false @@ -5367,8 +5389,10 @@ func rewriteValueRISCV64_OpRISCV64MOVHstorezero(v *Value) bool { func rewriteValueRISCV64_OpRISCV64MOVWUload(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] + b := v.Block + config := b.Func.Config // match: (MOVWUload [off1] {sym1} (MOVaddr [off2] {sym2} base) mem) - // cond: is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) + // cond: is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_dynlink) // result: (MOVWUload [off1+off2] {mergeSym(sym1,sym2)} base mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -5380,7 +5404,7 @@ func rewriteValueRISCV64_OpRISCV64MOVWUload(v *Value) bool { sym2 := auxToSym(v_0.Aux) base := v_0.Args[0] mem := v_1 - if !(is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2)) { + if !(is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_dynlink)) { break } v.reset(OpRISCV64MOVWUload) @@ -5555,8 +5579,10 @@ func rewriteValueRISCV64_OpRISCV64MOVWUreg(v *Value) bool { func rewriteValueRISCV64_OpRISCV64MOVWload(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] + b := v.Block + config := b.Func.Config // match: (MOVWload [off1] {sym1} (MOVaddr [off2] {sym2} base) mem) - // cond: is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) + // cond: is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_dynlink) // result: (MOVWload [off1+off2] {mergeSym(sym1,sym2)} base mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -5568,7 +5594,7 @@ func rewriteValueRISCV64_OpRISCV64MOVWload(v *Value) bool { sym2 := auxToSym(v_0.Aux) base := v_0.Args[0] mem := v_1 - if !(is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2)) { + if !(is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_dynlink)) { break } v.reset(OpRISCV64MOVWload) @@ -5879,8 +5905,10 @@ func rewriteValueRISCV64_OpRISCV64MOVWstore(v *Value) bool { v_2 := v.Args[2] v_1 := v.Args[1] v_0 := v.Args[0] + b := v.Block + config := b.Func.Config // match: (MOVWstore [off1] {sym1} (MOVaddr [off2] {sym2} base) val mem) - // cond: is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) + // cond: is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_dynlink) // result: (MOVWstore [off1+off2] {mergeSym(sym1,sym2)} base val mem) for { off1 := auxIntToInt32(v.AuxInt) @@ -5893,7 +5921,7 @@ func rewriteValueRISCV64_OpRISCV64MOVWstore(v *Value) bool { base := v_0.Args[0] val := v_1 mem := v_2 - if !(is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2)) { + if !(is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_dynlink)) { break } v.reset(OpRISCV64MOVWstore) @@ -5979,9 +6007,11 @@ func rewriteValueRISCV64_OpRISCV64MOVWstore(v *Value) bool { func rewriteValueRISCV64_OpRISCV64MOVWstorezero(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] - // match: (MOVWstorezero [off1] {sym1} (MOVaddr [off2] {sym2} ptr) mem) - // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) - // result: (MOVWstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem) + b := v.Block + config := b.Func.Config + // match: (MOVWstorezero [off1] {sym1} (MOVaddr [off2] {sym2} base) mem) + // cond: canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2)) && (base.Op != OpSB || !config.ctxt.Flag_dynlink) + // result: (MOVWstorezero [off1+off2] {mergeSym(sym1,sym2)} base mem) for { off1 := auxIntToInt32(v.AuxInt) sym1 := auxToSym(v.Aux) @@ -5990,20 +6020,20 @@ func rewriteValueRISCV64_OpRISCV64MOVWstorezero(v *Value) bool { } off2 := auxIntToInt32(v_0.AuxInt) sym2 := auxToSym(v_0.Aux) - ptr := v_0.Args[0] + base := v_0.Args[0] mem := v_1 - if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2))) { + if !(canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) && (base.Op != OpSB || !config.ctxt.Flag_dynlink)) { break } v.reset(OpRISCV64MOVWstorezero) v.AuxInt = int32ToAuxInt(off1 + off2) v.Aux = symToAux(mergeSym(sym1, sym2)) - v.AddArg2(ptr, mem) + v.AddArg2(base, mem) return true } - // match: (MOVWstorezero [off1] {sym} (ADDI [off2] ptr) mem) + // match: (MOVWstorezero [off1] {sym} (ADDI [off2] base) mem) // cond: is32Bit(int64(off1)+off2) - // result: (MOVWstorezero [off1+int32(off2)] {sym} ptr mem) + // result: (MOVWstorezero [off1+int32(off2)] {sym} base mem) for { off1 := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -6011,7 +6041,7 @@ func rewriteValueRISCV64_OpRISCV64MOVWstorezero(v *Value) bool { break } off2 := auxIntToInt64(v_0.AuxInt) - ptr := v_0.Args[0] + base := v_0.Args[0] mem := v_1 if !(is32Bit(int64(off1) + off2)) { break @@ -6019,7 +6049,7 @@ func rewriteValueRISCV64_OpRISCV64MOVWstorezero(v *Value) bool { v.reset(OpRISCV64MOVWstorezero) v.AuxInt = int32ToAuxInt(off1 + int32(off2)) v.Aux = symToAux(sym) - v.AddArg2(ptr, mem) + v.AddArg2(base, mem) return true } return false From ff27d270c9f95178f9749bc8e1f15957b1c1d5b3 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Fri, 7 Feb 2025 17:42:02 -0500 Subject: [PATCH 285/397] bytes: use "subslice" instead of "substring" in doc comments The bytes package iterators return subslices, not substrings. Updates #61901. Change-Id: Ida91d3e33a0f178edfe9a267861adf4f13f9a965 Reviewed-on: https://go-review.googlesource.com/c/go/+/647875 Reviewed-by: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI --- src/bytes/iter.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/bytes/iter.go b/src/bytes/iter.go index 9890a478a8b2e8..799602d9e3667d 100644 --- a/src/bytes/iter.go +++ b/src/bytes/iter.go @@ -67,26 +67,26 @@ func splitSeq(s, sep []byte, sepSave int) iter.Seq[[]byte] { } } -// SplitSeq returns an iterator over all substrings of s separated by sep. -// The iterator yields the same strings that would be returned by [Split](s, sep), -// but without constructing the slice. +// SplitSeq returns an iterator over all subslices of s separated by sep. +// The iterator yields the same subslices that would be returned by [Split](s, sep), +// but without constructing a new slice containing the subslices. // It returns a single-use iterator. func SplitSeq(s, sep []byte) iter.Seq[[]byte] { return splitSeq(s, sep, 0) } -// SplitAfterSeq returns an iterator over substrings of s split after each instance of sep. -// The iterator yields the same strings that would be returned by [SplitAfter](s, sep), -// but without constructing the slice. +// SplitAfterSeq returns an iterator over subslices of s split after each instance of sep. +// The iterator yields the same subslices that would be returned by [SplitAfter](s, sep), +// but without constructing a new slice containing the subslices. // It returns a single-use iterator. func SplitAfterSeq(s, sep []byte) iter.Seq[[]byte] { return splitSeq(s, sep, len(sep)) } -// FieldsSeq returns an iterator over substrings of s split around runs of +// FieldsSeq returns an iterator over subslices of s split around runs of // whitespace characters, as defined by [unicode.IsSpace]. -// The iterator yields the same strings that would be returned by [Fields](s), -// but without constructing the slice. +// The iterator yields the same subslices that would be returned by [Fields](s), +// but without constructing a new slice containing the subslices. func FieldsSeq(s []byte) iter.Seq[[]byte] { return func(yield func([]byte) bool) { start := -1 @@ -116,10 +116,10 @@ func FieldsSeq(s []byte) iter.Seq[[]byte] { } } -// FieldsFuncSeq returns an iterator over substrings of s split around runs of +// FieldsFuncSeq returns an iterator over subslices of s split around runs of // Unicode code points satisfying f(c). -// The iterator yields the same strings that would be returned by [FieldsFunc](s), -// but without constructing the slice. +// The iterator yields the same subslices that would be returned by [FieldsFunc](s), +// but without constructing a new slice containing the subslices. func FieldsFuncSeq(s []byte, f func(rune) bool) iter.Seq[[]byte] { return func(yield func([]byte) bool) { start := -1 From ae26a30bb0cda77799334152a85eb63bb5cce0dc Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Fri, 13 Dec 2024 14:17:48 -0500 Subject: [PATCH 286/397] crypto/internal/fips140test: add CMAC-AES ACVP tests Adds ACVP test coverage for CMAC-AES based on the NIST spec: https://pages.nist.gov/ACVP/draft-fussell-acvp-mac.html Updates #69642 Change-Id: Ie731863b84c6f8d74c64daa6a6848354420151b2 Reviewed-on: https://go-review.googlesource.com/c/go/+/635762 Reviewed-by: Roland Shoemaker Reviewed-by: Cherry Mui LUCI-TryBot-Result: Go LUCI --- .../fips140test/acvp_capabilities.json | 3 +- .../fips140test/acvp_test.config.json | 4 +- src/crypto/internal/fips140test/acvp_test.go | 55 +++++++++++++++++++ 3 files changed, 60 insertions(+), 2 deletions(-) diff --git a/src/crypto/internal/fips140test/acvp_capabilities.json b/src/crypto/internal/fips140test/acvp_capabilities.json index 68d8e3bd2a6a25..117bd9e30b3f8a 100644 --- a/src/crypto/internal/fips140test/acvp_capabilities.json +++ b/src/crypto/internal/fips140test/acvp_capabilities.json @@ -53,5 +53,6 @@ {"algorithm":"ACVP-AES-CBC","direction":["encrypt","decrypt"],"keyLen":[128,192,256],"revision":"1.0"}, {"algorithm":"ACVP-AES-CTR","direction":["encrypt","decrypt"],"keyLen":[128,192,256],"payloadLen":[{"min":8,"max":128,"increment":8}],"incrementalCounter":true,"overflowCounter":true,"performCounterTests":true,"revision":"1.0"}, {"algorithm":"ACVP-AES-GCM","direction":["encrypt","decrypt"],"keyLen":[128,192,256],"payloadLen":[{"min":0,"max":65536,"increment":8}],"aadLen":[{"min":0,"max":65536,"increment":8}],"tagLen":[96,104,112,120,128],"ivLen":[96],"ivGen":"external","revision":"1.0"}, - {"algorithm":"ACVP-AES-GCM","direction":["encrypt","decrypt"],"keyLen":[128,192,256],"payloadLen":[{"min":0,"max":65536,"increment":8}],"aadLen":[{"min":0,"max":65536,"increment":8}],"tagLen":[128],"ivLen":[96],"ivGen":"internal","ivGenMode":"8.2.2","revision":"1.0"} + {"algorithm":"ACVP-AES-GCM","direction":["encrypt","decrypt"],"keyLen":[128,192,256],"payloadLen":[{"min":0,"max":65536,"increment":8}],"aadLen":[{"min":0,"max":65536,"increment":8}],"tagLen":[128],"ivLen":[96],"ivGen":"internal","ivGenMode":"8.2.2","revision":"1.0"}, + {"algorithm":"CMAC-AES","capabilities":[{"direction":["gen","ver"],"msgLen":[{"min":0,"max":524288,"increment":8}],"keyLen":[128,256],"macLen":[{"min":8,"max":128,"increment":8}]}],"revision":"1.0"} ] diff --git a/src/crypto/internal/fips140test/acvp_test.config.json b/src/crypto/internal/fips140test/acvp_test.config.json index d994f5b7c552b0..c2bb9fc662dceb 100644 --- a/src/crypto/internal/fips140test/acvp_test.config.json +++ b/src/crypto/internal/fips140test/acvp_test.config.json @@ -35,5 +35,7 @@ {"Wrapper": "go", "In": "vectors/ACVP-AES-CBC.bz2", "Out": "expected/ACVP-AES-CBC.bz2"}, {"Wrapper": "go", "In": "vectors/ACVP-AES-CTR.bz2", "Out": "expected/ACVP-AES-CTR.bz2"}, - {"Wrapper": "go", "In": "vectors/ACVP-AES-GCM.bz2", "Out": "expected/ACVP-AES-GCM.bz2"} + {"Wrapper": "go", "In": "vectors/ACVP-AES-GCM.bz2", "Out": "expected/ACVP-AES-GCM.bz2"}, + + {"Wrapper": "go", "In": "vectors/CMAC-AES.bz2", "Out": "expected/CMAC-AES.bz2"} ] \ No newline at end of file diff --git a/src/crypto/internal/fips140test/acvp_test.go b/src/crypto/internal/fips140test/acvp_test.go index 2637ccc3e40add..2f425effd5a11c 100644 --- a/src/crypto/internal/fips140test/acvp_test.go +++ b/src/crypto/internal/fips140test/acvp_test.go @@ -35,6 +35,7 @@ import ( "crypto/internal/fips140/sha256" "crypto/internal/fips140/sha3" "crypto/internal/fips140/sha512" + "crypto/internal/fips140/subtle" "crypto/rand" _ "embed" "encoding/binary" @@ -189,6 +190,9 @@ var ( "AES-GCM/open": cmdAesGcmOpen(false), "AES-GCM-randnonce/seal": cmdAesGcmSeal(true), "AES-GCM-randnonce/open": cmdAesGcmOpen(true), + + "CMAC-AES": cmdCmacAesAft(), + "CMAC-AES/verify": cmdCmacAesVerifyAft(), } ) @@ -1154,6 +1158,57 @@ func cmdAesGcmOpen(randNonce bool) command { } } +func cmdCmacAesAft() command { + return command{ + requiredArgs: 3, // Number of output bytes, key, message + handler: func(args [][]byte) ([][]byte, error) { + // safe to truncate to int based on our capabilities describing a max MAC output len of 128 bits. + outputLen := int(binary.LittleEndian.Uint32(args[0])) + key := args[1] + message := args[2] + + blockCipher, err := aes.New(key) + if err != nil { + return nil, fmt.Errorf("creating AES block cipher with key len %d: %w", len(key), err) + } + + cmac := gcm.NewCMAC(blockCipher) + tag := cmac.MAC(message) + + if outputLen > len(tag) { + return nil, fmt.Errorf("invalid output length: expected %d, got %d", outputLen, len(tag)) + } + + return [][]byte{tag[:outputLen]}, nil + }, + } +} + +func cmdCmacAesVerifyAft() command { + return command{ + requiredArgs: 3, // Key, message, claimed MAC + handler: func(args [][]byte) ([][]byte, error) { + key := args[0] + message := args[1] + claimedMAC := args[2] + + blockCipher, err := aes.New(key) + if err != nil { + return nil, fmt.Errorf("creating AES block cipher with key len %d: %w", len(key), err) + } + + cmac := gcm.NewCMAC(blockCipher) + tag := cmac.MAC(message) + + if subtle.ConstantTimeCompare(tag[:len(claimedMAC)], claimedMAC) != 1 { + return [][]byte{{0}}, nil + } + + return [][]byte{{1}}, nil + }, + } +} + func TestACVP(t *testing.T) { testenv.SkipIfShortAndSlow(t) From 181cf3c95ec99a44babb0e64c8f66956d2ac3a78 Mon Sep 17 00:00:00 2001 From: pgxiaolianzi Date: Fri, 7 Feb 2025 08:37:50 +0000 Subject: [PATCH 287/397] text/template: handle UnsafePointer in isTrue Change-Id: I4d0b5919d109f768ba04ab519e8f948a5749a752 GitHub-Last-Rev: 6f27f1193c21bb10e3b81660b4271f2c1f33be1e GitHub-Pull-Request: golang/go#70520 Reviewed-on: https://go-review.googlesource.com/c/go/+/631076 Run-TryBot: Rob Pike Auto-Submit: Ian Lance Taylor Reviewed-by: Rob Pike Reviewed-by: Ian Lance Taylor Reviewed-by: Dmitri Shuralyov LUCI-TryBot-Result: Go LUCI TryBot-Result: Gopher Robot --- src/text/template/exec.go | 2 +- src/text/template/exec_test.go | 50 ++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/text/template/exec.go b/src/text/template/exec.go index ed6ae43671a127..7a67ec6824f5e5 100644 --- a/src/text/template/exec.go +++ b/src/text/template/exec.go @@ -333,7 +333,7 @@ func isTrue(val reflect.Value) (truth, ok bool) { truth = val.Bool() case reflect.Complex64, reflect.Complex128: truth = val.Complex() != 0 - case reflect.Chan, reflect.Func, reflect.Pointer, reflect.Interface: + case reflect.Chan, reflect.Func, reflect.Pointer, reflect.UnsafePointer, reflect.Interface: truth = !val.IsNil() case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: truth = val.Int() != 0 diff --git a/src/text/template/exec_test.go b/src/text/template/exec_test.go index 03ec9d759a0dd7..0a0be43baa4f49 100644 --- a/src/text/template/exec_test.go +++ b/src/text/template/exec_test.go @@ -15,6 +15,7 @@ import ( "strings" "sync" "testing" + "unsafe" ) var debug = flag.Bool("debug", false, "show the errors produced by the tests") @@ -75,6 +76,8 @@ type T struct { PS *string PSI *[]int NIL *int + UPI unsafe.Pointer + EmptyUPI unsafe.Pointer // Function (not method) BinaryFunc func(string, string) string VariadicFunc func(...string) string @@ -166,6 +169,7 @@ var tVal = &T{ PI: newInt(23), PS: newString("a string"), PSI: newIntSlice(21, 22, 23), + UPI: newUnsafePointer(23), BinaryFunc: func(a, b string) string { return fmt.Sprintf("[%s=%s]", a, b) }, VariadicFunc: func(s ...string) string { return fmt.Sprint("<", strings.Join(s, "+"), ">") }, VariadicFuncInt: func(a int, s ...string) string { return fmt.Sprint(a, "=<", strings.Join(s, "+"), ">") }, @@ -192,6 +196,10 @@ func newInt(n int) *int { return &n } +func newUnsafePointer(n int) unsafe.Pointer { + return unsafe.Pointer(&n) +} + func newString(s string) *string { return &s } @@ -443,6 +451,10 @@ var execTests = []execTest{ {"if 0.0", "{{if .FloatZero}}NON-ZERO{{else}}ZERO{{end}}", "ZERO", tVal, true}, {"if 1.5i", "{{if 1.5i}}NON-ZERO{{else}}ZERO{{end}}", "NON-ZERO", tVal, true}, {"if 0.0i", "{{if .ComplexZero}}NON-ZERO{{else}}ZERO{{end}}", "ZERO", tVal, true}, + {"if nonNilPointer", "{{if .PI}}NON-ZERO{{else}}ZERO{{end}}", "NON-ZERO", tVal, true}, + {"if nilPointer", "{{if .NIL}}NON-ZERO{{else}}ZERO{{end}}", "ZERO", tVal, true}, + {"if UPI", "{{if .UPI}}NON-ZERO{{else}}ZERO{{end}}", "NON-ZERO", tVal, true}, + {"if EmptyUPI", "{{if .EmptyUPI}}NON-ZERO{{else}}ZERO{{end}}", "ZERO", tVal, true}, {"if emptystring", "{{if ``}}NON-EMPTY{{else}}EMPTY{{end}}", "EMPTY", tVal, true}, {"if string", "{{if `notempty`}}NON-EMPTY{{else}}EMPTY{{end}}", "NON-EMPTY", tVal, true}, {"if emptyslice", "{{if .SIEmpty}}NON-EMPTY{{else}}EMPTY{{end}}", "EMPTY", tVal, true}, @@ -1493,6 +1505,44 @@ func TestBadFuncNames(t *testing.T) { } } +func TestIsTrue(t *testing.T) { + var nil_ptr *int + var nil_chan chan int + tests := []struct{ + v any + want bool + }{ + {1, true}, + {0, false}, + {uint8(1), true}, + {uint8(0), false}, + {float64(1.0), true}, + {float64(0.0), false}, + {complex64(1.0), true}, + {complex64(0.0), false}, + {true, true}, + {false, false}, + {[2]int{1,2}, true}, + {[0]int{}, false}, + {[]byte("abc"), true}, + {[]byte(""), false}, + {map[string] int {"a": 1, "b": 2}, true}, + {map[string] int {}, false}, + {make(chan int), true}, + {nil_chan, false}, + {new(int), true}, + {nil_ptr, false}, + {unsafe.Pointer(new(int)), true}, + {unsafe.Pointer(nil_ptr), false}, + } + for _, test_case := range tests { + got, _ := IsTrue(test_case.v) + if got != test_case.want { + t.Fatalf("expect result %v, got %v", test_case.want, got) + } + } +} + func testBadFuncName(name string, t *testing.T) { t.Helper() defer func() { From 74c3b3784ea09e75f8c94ef5bf306c55c2e463a7 Mon Sep 17 00:00:00 2001 From: Mateusz Poliwczak Date: Sat, 8 Feb 2025 13:51:31 +0000 Subject: [PATCH 288/397] cmd/internal/bio: remove unused MustWriter Change-Id: I70435781fbaeca2b6927a74afd79a3ff123b527b GitHub-Last-Rev: cae569f4c4bf73a9a6cd8d26fb080962f94bf1b1 GitHub-Pull-Request: golang/go#71622 Reviewed-on: https://go-review.googlesource.com/c/go/+/647916 Reviewed-by: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Reviewed-by: Jorropo Auto-Submit: Ian Lance Taylor Reviewed-by: Dmitri Shuralyov Auto-Submit: Jorropo --- src/cmd/internal/bio/must.go | 43 ------------------------------------ 1 file changed, 43 deletions(-) delete mode 100644 src/cmd/internal/bio/must.go diff --git a/src/cmd/internal/bio/must.go b/src/cmd/internal/bio/must.go deleted file mode 100644 index 3604b291757479..00000000000000 --- a/src/cmd/internal/bio/must.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package bio - -import ( - "io" - "log" -) - -// MustClose closes Closer c and calls log.Fatal if it returns a non-nil error. -func MustClose(c io.Closer) { - if err := c.Close(); err != nil { - log.Fatal(err) - } -} - -// MustWriter returns a Writer that wraps the provided Writer, -// except that it calls log.Fatal instead of returning a non-nil error. -func MustWriter(w io.Writer) io.Writer { - return mustWriter{w} -} - -type mustWriter struct { - w io.Writer -} - -func (w mustWriter) Write(b []byte) (int, error) { - n, err := w.w.Write(b) - if err != nil { - log.Fatal(err) - } - return n, nil -} - -func (w mustWriter) WriteString(s string) (int, error) { - n, err := io.WriteString(w.w, s) - if err != nil { - log.Fatal(err) - } - return n, nil -} From 472d2859066d98961b5a7f09556f6bd7ca216701 Mon Sep 17 00:00:00 2001 From: Pasha Radchenko Date: Thu, 6 Feb 2025 18:42:28 +0000 Subject: [PATCH 289/397] crypto/aes: more precise description for AES keys requirements The existing documentation is not certain in the place regarding requirements about AES key. Added some notes for precise description. Change-Id: I190562ab7c1566cce8e7771f9927d738c72880ce GitHub-Last-Rev: 6565a8f4e5b37220fd14d55e876b809b2d763b7c GitHub-Pull-Request: golang/go#71589 Reviewed-on: https://go-review.googlesource.com/c/go/+/647336 LUCI-TryBot-Result: Go LUCI Reviewed-by: Dmitri Shuralyov Reviewed-by: Jorropo Auto-Submit: Jorropo Reviewed-by: Roland Shoemaker --- src/crypto/aes/aes.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crypto/aes/aes.go b/src/crypto/aes/aes.go index 5bc2d13d673e0a..22ea8819ed239a 100644 --- a/src/crypto/aes/aes.go +++ b/src/crypto/aes/aes.go @@ -30,7 +30,7 @@ func (k KeySizeError) Error() string { } // NewCipher creates and returns a new [cipher.Block]. -// The key argument should be the AES key, +// The key argument must be the AES key, // either 16, 24, or 32 bytes to select // AES-128, AES-192, or AES-256. func NewCipher(key []byte) (cipher.Block, error) { From 8cb6d3b826e25619de2f57d0aaf850a4116a2511 Mon Sep 17 00:00:00 2001 From: Jakub Ciolek Date: Sat, 8 Feb 2025 23:35:51 +0100 Subject: [PATCH 290/397] cmd/compile: mark PCMPEQB as commutative compilecmp linux/amd64: internal/runtime/maps internal/runtime/maps.(*table).Delete changed internal/runtime/maps [cmd/compile] internal/runtime/maps.(*Map).Delete changed internal/runtime/maps.(*table).Delete changed Change-Id: Ic3c95411c23cab7427e63105170de41e5766f809 Reviewed-on: https://go-review.googlesource.com/c/go/+/647935 LUCI-TryBot-Result: Go LUCI Reviewed-by: Dmitri Shuralyov Reviewed-by: Keith Randall Reviewed-by: Keith Randall Auto-Submit: Keith Randall --- src/cmd/compile/internal/ssa/_gen/AMD64Ops.go | 4 ++-- src/cmd/compile/internal/ssa/opGen.go | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go b/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go index 23fb2361b56198..7be70c77372403 100644 --- a/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go +++ b/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go @@ -1156,7 +1156,7 @@ func init() { // // output[i] = input. {name: "PSHUFBbroadcast", argLength: 1, reg: fp11, resultInArg0: true, asm: "PSHUFB"}, // PSHUFB with mask zero, (GOAMD64=v1) - {name: "VPBROADCASTB", argLength: 1, reg: gpfp, asm: "VPBROADCASTB"}, // Broadcast input byte from gp (GOAMD64=v3) + {name: "VPBROADCASTB", argLength: 1, reg: gpfp, asm: "VPBROADCASTB"}, // Broadcast input byte from gp (GOAMD64=v3) // Byte negate/zero/preserve (GOAMD64=v2). // @@ -1180,7 +1180,7 @@ func init() { // } else { // output[i] = 0 // } - {name: "PCMPEQB", argLength: 2, reg: fp21, resultInArg0: true, asm: "PCMPEQB"}, + {name: "PCMPEQB", argLength: 2, reg: fp21, resultInArg0: true, asm: "PCMPEQB", commutative: true}, // Byte sign mask. Output is a bitmap of sign bits from each input byte. // diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index df1ddfa69edfc1..13ec9dc9e3fc3a 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -15414,6 +15414,7 @@ var opcodeTable = [...]opInfo{ { name: "PCMPEQB", argLen: 2, + commutative: true, resultInArg0: true, asm: x86.APCMPEQB, reg: regInfo{ From 035d3c8f530cadfb89654e27065c0e5230e36f69 Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Sat, 19 Oct 2024 14:10:28 -0400 Subject: [PATCH 291/397] crypto/internal/fips140test: add SHAKE-* ACVP tests This commit adds ACVP test coverage for SHAKE-128 and SHAKE-256 based on the NIST spec: https://pages.nist.gov/ACVP/draft-celi-acvp-sha3.html Updates #69642 Change-Id: Ia6899def452fcb63a03603b7919fcb0c3576474b Reviewed-on: https://go-review.googlesource.com/c/go/+/622395 Reviewed-by: Dmitri Shuralyov TryBot-Bypass: Dmitri Shuralyov Auto-Submit: Dmitri Shuralyov Reviewed-by: Cherry Mui Reviewed-by: Dmitri Shuralyov --- .../fips140test/acvp_capabilities.json | 3 + .../fips140test/acvp_test.config.json | 3 + src/crypto/internal/fips140test/acvp_test.go | 77 +++++++++++++++++++ 3 files changed, 83 insertions(+) diff --git a/src/crypto/internal/fips140test/acvp_capabilities.json b/src/crypto/internal/fips140test/acvp_capabilities.json index 117bd9e30b3f8a..77f21c3347efdc 100644 --- a/src/crypto/internal/fips140test/acvp_capabilities.json +++ b/src/crypto/internal/fips140test/acvp_capabilities.json @@ -11,6 +11,9 @@ {"algorithm":"SHA3-384","messageLength":[{"increment":8,"max":65528,"min":0}],"revision":"2.0"}, {"algorithm":"SHA3-512","messageLength":[{"increment":8,"max":65528,"min":0}],"revision":"2.0"}, + {"algorithm":"SHAKE-128","inBit":false,"outBit":false,"inEmpty":true,"outputLen":[{"min":16,"max":65536,"increment":8}],"revision":"1.0"}, + {"algorithm":"SHAKE-256","inBit":false,"outBit":false,"inEmpty":true,"outputLen":[{"min":16,"max":65536,"increment":8}],"revision":"1.0"}, + {"algorithm":"HMAC-SHA2-224","keyLen":[{"increment":8,"max":524288,"min":8}],"macLen":[{"increment":8,"max":224,"min":32}],"revision":"1.0"}, {"algorithm":"HMAC-SHA2-256","keyLen":[{"increment":8,"max":524288,"min":8}],"macLen":[{"increment":8,"max":256,"min":32}],"revision":"1.0"}, {"algorithm":"HMAC-SHA2-384","keyLen":[{"increment":8,"max":524288,"min":8}],"macLen":[{"increment":8,"max":384,"min":32}],"revision":"1.0"}, diff --git a/src/crypto/internal/fips140test/acvp_test.config.json b/src/crypto/internal/fips140test/acvp_test.config.json index c2bb9fc662dceb..1cdfd8f85edae7 100644 --- a/src/crypto/internal/fips140test/acvp_test.config.json +++ b/src/crypto/internal/fips140test/acvp_test.config.json @@ -11,6 +11,9 @@ {"Wrapper": "go", "In": "vectors/SHA3-384.bz2", "Out": "expected/SHA3-384.bz2"}, {"Wrapper": "go", "In": "vectors/SHA3-512.bz2", "Out": "expected/SHA3-512.bz2"}, + {"Wrapper": "go", "In": "vectors/SHAKE-128.bz2", "Out": "expected/SHAKE-128.bz2"}, + {"Wrapper": "go", "In": "vectors/SHAKE-256.bz2", "Out": "expected/SHAKE-256.bz2"}, + {"Wrapper": "go", "In": "vectors/HMAC-SHA2-224.bz2", "Out": "expected/HMAC-SHA2-224.bz2"}, {"Wrapper": "go", "In": "vectors/HMAC-SHA2-256.bz2", "Out": "expected/HMAC-SHA2-256.bz2"}, {"Wrapper": "go", "In": "vectors/HMAC-SHA2-384.bz2", "Out": "expected/HMAC-SHA2-384.bz2"}, diff --git a/src/crypto/internal/fips140test/acvp_test.go b/src/crypto/internal/fips140test/acvp_test.go index 2f425effd5a11c..23dcdecd9328a3 100644 --- a/src/crypto/internal/fips140test/acvp_test.go +++ b/src/crypto/internal/fips140test/acvp_test.go @@ -95,6 +95,8 @@ const ( var ( // SHA2 algorithm capabilities: // https://pages.nist.gov/ACVP/draft-celi-acvp-sha.html#section-7.2 + // SHA3 and SHAKE algorithm capabilities: + // https://pages.nist.gov/ACVP/draft-celi-acvp-sha3.html#name-sha3-and-shake-algorithm-ca // HMAC algorithm capabilities: // https://pages.nist.gov/ACVP/draft-fussell-acvp-mac.html#section-7 // PBKDF2 algorithm capabilities: @@ -140,6 +142,17 @@ var ( "SHA3-512": cmdHashAft(sha3.New512()), "SHA3-512/MCT": cmdSha3Mct(sha3.New512()), + // Note: SHAKE AFT and VOT test types can be handled by the same command + // handler impl, but use distinct acvptool command names, and so are + // registered twice with the same digest: once under "SHAKE-xxx" for AFT, + // and once under"SHAKE-xxx/VOT" for VOT. + "SHAKE-128": cmdShakeAftVot(sha3.NewShake128()), + "SHAKE-128/VOT": cmdShakeAftVot(sha3.NewShake128()), + "SHAKE-128/MCT": cmdShakeMct(sha3.NewShake128()), + "SHAKE-256": cmdShakeAftVot(sha3.NewShake256()), + "SHAKE-256/VOT": cmdShakeAftVot(sha3.NewShake256()), + "SHAKE-256/MCT": cmdShakeMct(sha3.NewShake256()), + "HMAC-SHA2-224": cmdHmacAft(func() fips140.Hash { return sha256.New224() }), "HMAC-SHA2-256": cmdHmacAft(func() fips140.Hash { return sha256.New() }), "HMAC-SHA2-384": cmdHmacAft(func() fips140.Hash { return sha512.New384() }), @@ -410,6 +423,70 @@ func cmdSha3Mct(h fips140.Hash) command { } } +func cmdShakeAftVot(h *sha3.SHAKE) command { + return command{ + requiredArgs: 2, // Message, output length (bytes) + handler: func(args [][]byte) ([][]byte, error) { + msg := args[0] + + outLenBytes := binary.LittleEndian.Uint32(args[1]) + digest := make([]byte, outLenBytes) + + h.Reset() + h.Write(msg) + h.Read(digest) + + return [][]byte{digest}, nil + }, + } +} + +func cmdShakeMct(h *sha3.SHAKE) command { + return command{ + requiredArgs: 4, // Seed message, min output length (bytes), max output length (bytes), output length (bytes) + handler: func(args [][]byte) ([][]byte, error) { + md := args[0] + minOutBytes := binary.LittleEndian.Uint32(args[1]) + maxOutBytes := binary.LittleEndian.Uint32(args[2]) + + outputLenBytes := binary.LittleEndian.Uint32(args[3]) + if outputLenBytes < 2 { + return nil, fmt.Errorf("invalid output length: %d", outputLenBytes) + } + + rangeBytes := maxOutBytes - minOutBytes + 1 + if rangeBytes == 0 { + return nil, fmt.Errorf("invalid maxOutBytes and minOutBytes: %d, %d", maxOutBytes, minOutBytes) + } + + for i := 0; i < 1000; i++ { + // "The MSG[i] input to SHAKE MUST always contain at least 128 bits. If this is not the case + // as the previous digest was too short, append empty bits to the rightmost side of the digest." + boundary := min(len(md), 16) + msg := make([]byte, 16) + copy(msg, md[:boundary]) + + // MD[i] = SHAKE(MSG[i], OutputLen * 8) + h.Reset() + h.Write(msg) + digest := make([]byte, outputLenBytes) + h.Read(digest) + md = digest + + // RightmostOutputBits = 16 rightmost bits of MD[i] as an integer + // OutputLen = minOutBytes + (RightmostOutputBits % Range) + rightmostOutput := uint32(md[outputLenBytes-2])<<8 | uint32(md[outputLenBytes-1]) + outputLenBytes = minOutBytes + (rightmostOutput % rangeBytes) + } + + encodedOutputLenBytes := make([]byte, 4) + binary.LittleEndian.PutUint32(encodedOutputLenBytes, outputLenBytes) + + return [][]byte{md, encodedOutputLenBytes}, nil + }, + } +} + func cmdHmacAft(h func() fips140.Hash) command { return command{ requiredArgs: 2, // Message and key From 0580e2a4964b634c24d9dfaa1fbb4e4886dd1a5d Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Fri, 13 Dec 2024 16:21:45 -0500 Subject: [PATCH 292/397] crypto/internal/fips140test: add KDA HKDF ACVP tests Adds ACVP test coverage for the SP 800-56Crev2 HKDF KDA based on the NIST spec: https://pages.nist.gov/ACVP/draft-hammett-acvp-kas-kdf-hkdf.html Updates #69642 Change-Id: Ie4f48f9b0181eaf6c2201a9796d366a31c474eba Reviewed-on: https://go-review.googlesource.com/c/go/+/636115 LUCI-TryBot-Result: Go LUCI Reviewed-by: Filippo Valsorda Auto-Submit: Filippo Valsorda Reviewed-by: Dmitri Shuralyov Reviewed-by: Roland Shoemaker --- .../fips140test/acvp_capabilities.json | 2 ++ .../fips140test/acvp_test.config.json | 4 ++- src/crypto/internal/fips140test/acvp_test.go | 28 +++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/crypto/internal/fips140test/acvp_capabilities.json b/src/crypto/internal/fips140test/acvp_capabilities.json index 77f21c3347efdc..7577e76c929e5a 100644 --- a/src/crypto/internal/fips140test/acvp_capabilities.json +++ b/src/crypto/internal/fips140test/acvp_capabilities.json @@ -26,6 +26,8 @@ {"algorithm":"HMAC-SHA3-384","keyLen":[{"increment":8,"max":524288,"min":8}],"macLen":[{"increment":8,"max":384,"min":32}],"revision":"1.0"}, {"algorithm":"HMAC-SHA3-512","keyLen":[{"increment":8,"max":524288,"min":8}],"macLen":[{"increment":8,"max":512,"min":32}],"revision":"1.0"}, + {"algorithm":"KDA","mode":"HKDF","revision":"Sp800-56Cr1","fixedInfoPattern":"uPartyInfo||vPartyInfo","encoding":["concatenation"],"hmacAlg":["SHA2-224","SHA2-256","SHA2-384","SHA2-512","SHA2-512/224","SHA2-512/256","SHA3-224","SHA3-256","SHA3-384","SHA3-512"],"macSaltMethods":["default","random"],"l":2048,"z":[{"min":224,"max":65336,"increment":8}]}, + {"algorithm":"PBKDF","capabilities":[{"iterationCount":[{"min":1,"max":10000,"increment":1}],"keyLen":[{"min":112,"max":4096,"increment":8}],"passwordLen":[{"min":8,"max":64,"increment":1}],"saltLen":[{"min":128,"max":512,"increment":8}],"hmacAlg":["SHA2-224","SHA2-256","SHA2-384","SHA2-512","SHA2-512/224","SHA2-512/256","SHA3-224","SHA3-256","SHA3-384","SHA3-512"]}],"revision":"1.0"}, {"algorithm":"ML-KEM","mode":"keyGen","revision":"FIPS203","parameterSets":["ML-KEM-768","ML-KEM-1024"]}, diff --git a/src/crypto/internal/fips140test/acvp_test.config.json b/src/crypto/internal/fips140test/acvp_test.config.json index 1cdfd8f85edae7..2be909f1a47e7c 100644 --- a/src/crypto/internal/fips140test/acvp_test.config.json +++ b/src/crypto/internal/fips140test/acvp_test.config.json @@ -21,6 +21,8 @@ {"Wrapper": "go", "In": "vectors/HMAC-SHA2-512-224.bz2", "Out": "expected/HMAC-SHA2-512-224.bz2"}, {"Wrapper": "go", "In": "vectors/HMAC-SHA2-512-256.bz2", "Out": "expected/HMAC-SHA2-512-256.bz2"}, + {"Wrapper": "go", "In": "vectors/KDA.bz2", "Out": "expected/KDA.bz2"}, + {"Wrapper": "go", "In": "vectors/HMAC-SHA3-224.bz2", "Out": "expected/HMAC-SHA3-224.bz2"}, {"Wrapper": "go", "In": "vectors/HMAC-SHA3-256.bz2", "Out": "expected/HMAC-SHA3-256.bz2"}, {"Wrapper": "go", "In": "vectors/HMAC-SHA3-384.bz2", "Out": "expected/HMAC-SHA3-384.bz2"}, @@ -41,4 +43,4 @@ {"Wrapper": "go", "In": "vectors/ACVP-AES-GCM.bz2", "Out": "expected/ACVP-AES-GCM.bz2"}, {"Wrapper": "go", "In": "vectors/CMAC-AES.bz2", "Out": "expected/CMAC-AES.bz2"} -] \ No newline at end of file +] diff --git a/src/crypto/internal/fips140test/acvp_test.go b/src/crypto/internal/fips140test/acvp_test.go index 23dcdecd9328a3..7e3ab4031edc96 100644 --- a/src/crypto/internal/fips140test/acvp_test.go +++ b/src/crypto/internal/fips140test/acvp_test.go @@ -29,6 +29,7 @@ import ( "crypto/internal/fips140/ecdsa" "crypto/internal/fips140/ed25519" "crypto/internal/fips140/edwards25519" + "crypto/internal/fips140/hkdf" "crypto/internal/fips140/hmac" "crypto/internal/fips140/mlkem" "crypto/internal/fips140/pbkdf2" @@ -111,6 +112,8 @@ var ( // https://pages.nist.gov/ACVP/draft-fussell-acvp-ecdsa.html#section-7 // AES algorithm capabilities: // https://pages.nist.gov/ACVP/draft-celi-acvp-symmetric.html#section-7.3 + // HKDF KDA algorithm capabilities: + // https://pages.nist.gov/ACVP/draft-hammett-acvp-kas-kdf-hkdf.html#section-7.3 //go:embed acvp_capabilities.json capabilitiesJson []byte @@ -164,6 +167,17 @@ var ( "HMAC-SHA3-384": cmdHmacAft(func() fips140.Hash { return sha3.New384() }), "HMAC-SHA3-512": cmdHmacAft(func() fips140.Hash { return sha3.New512() }), + "HKDF/SHA2-224": cmdHkdfAft(func() fips140.Hash { return sha256.New224() }), + "HKDF/SHA2-256": cmdHkdfAft(func() fips140.Hash { return sha256.New() }), + "HKDF/SHA2-384": cmdHkdfAft(func() fips140.Hash { return sha512.New384() }), + "HKDF/SHA2-512": cmdHkdfAft(func() fips140.Hash { return sha512.New() }), + "HKDF/SHA2-512/224": cmdHkdfAft(func() fips140.Hash { return sha512.New512_224() }), + "HKDF/SHA2-512/256": cmdHkdfAft(func() fips140.Hash { return sha512.New512_256() }), + "HKDF/SHA3-224": cmdHkdfAft(func() fips140.Hash { return sha3.New224() }), + "HKDF/SHA3-256": cmdHkdfAft(func() fips140.Hash { return sha3.New256() }), + "HKDF/SHA3-384": cmdHkdfAft(func() fips140.Hash { return sha3.New384() }), + "HKDF/SHA3-512": cmdHkdfAft(func() fips140.Hash { return sha3.New512() }), + "PBKDF": cmdPbkdf(), "ML-KEM-768/keyGen": cmdMlKem768KeyGenAft(), @@ -500,6 +514,20 @@ func cmdHmacAft(h func() fips140.Hash) command { } } +func cmdHkdfAft(h func() fips140.Hash) command { + return command{ + requiredArgs: 4, // Key, salt, info, length bytes + handler: func(args [][]byte) ([][]byte, error) { + key := args[0] + salt := args[1] + info := args[2] + keyLen := int(binary.LittleEndian.Uint32(args[3])) + + return [][]byte{hkdf.Key(h, key, salt, string(info), keyLen)}, nil + }, + } +} + func cmdPbkdf() command { return command{ // Hash name, key length, salt, password, iteration count From 3310f324ad33571f68d3f0534dd4ebe9872ab2bd Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Sat, 14 Dec 2024 12:53:29 -0500 Subject: [PATCH 293/397] crypto/internal/fips140test: add TLS-v1.2 ACVP tests Adds ACVP test coverage for the SP 800-135rev1 RFC 7627 TLS v1.2 KDF based on the NIST spec: https://pages.nist.gov/ACVP/draft-celi-acvp-kdf-tls.html Only SHA2-256, SHA2-384 and SHA2-512 are valid hash algorithms for the TLSKDF algorithm. Updates #69642 Change-Id: I553d4f6a1d6652ed486af0e2c94730c8063fb47f Reviewed-on: https://go-review.googlesource.com/c/go/+/636116 LUCI-TryBot-Result: Go LUCI Reviewed-by: Roland Shoemaker Reviewed-by: Filippo Valsorda Auto-Submit: Filippo Valsorda Reviewed-by: David Chase --- .../fips140test/acvp_capabilities.json | 4 +++- .../fips140test/acvp_test.config.json | 4 +++- src/crypto/internal/fips140test/acvp_test.go | 24 +++++++++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/crypto/internal/fips140test/acvp_capabilities.json b/src/crypto/internal/fips140test/acvp_capabilities.json index 7577e76c929e5a..74317deb417d9a 100644 --- a/src/crypto/internal/fips140test/acvp_capabilities.json +++ b/src/crypto/internal/fips140test/acvp_capabilities.json @@ -59,5 +59,7 @@ {"algorithm":"ACVP-AES-CTR","direction":["encrypt","decrypt"],"keyLen":[128,192,256],"payloadLen":[{"min":8,"max":128,"increment":8}],"incrementalCounter":true,"overflowCounter":true,"performCounterTests":true,"revision":"1.0"}, {"algorithm":"ACVP-AES-GCM","direction":["encrypt","decrypt"],"keyLen":[128,192,256],"payloadLen":[{"min":0,"max":65536,"increment":8}],"aadLen":[{"min":0,"max":65536,"increment":8}],"tagLen":[96,104,112,120,128],"ivLen":[96],"ivGen":"external","revision":"1.0"}, {"algorithm":"ACVP-AES-GCM","direction":["encrypt","decrypt"],"keyLen":[128,192,256],"payloadLen":[{"min":0,"max":65536,"increment":8}],"aadLen":[{"min":0,"max":65536,"increment":8}],"tagLen":[128],"ivLen":[96],"ivGen":"internal","ivGenMode":"8.2.2","revision":"1.0"}, - {"algorithm":"CMAC-AES","capabilities":[{"direction":["gen","ver"],"msgLen":[{"min":0,"max":524288,"increment":8}],"keyLen":[128,256],"macLen":[{"min":8,"max":128,"increment":8}]}],"revision":"1.0"} + {"algorithm":"CMAC-AES","capabilities":[{"direction":["gen","ver"],"msgLen":[{"min":0,"max":524288,"increment":8}],"keyLen":[128,256],"macLen":[{"min":8,"max":128,"increment":8}]}],"revision":"1.0"}, + + {"algorithm":"TLS-v1.2","mode":"KDF","revision":"RFC7627","hashAlg":["SHA2-256","SHA2-384","SHA2-512"]} ] diff --git a/src/crypto/internal/fips140test/acvp_test.config.json b/src/crypto/internal/fips140test/acvp_test.config.json index 2be909f1a47e7c..a25d38fd68b467 100644 --- a/src/crypto/internal/fips140test/acvp_test.config.json +++ b/src/crypto/internal/fips140test/acvp_test.config.json @@ -42,5 +42,7 @@ {"Wrapper": "go", "In": "vectors/ACVP-AES-CTR.bz2", "Out": "expected/ACVP-AES-CTR.bz2"}, {"Wrapper": "go", "In": "vectors/ACVP-AES-GCM.bz2", "Out": "expected/ACVP-AES-GCM.bz2"}, - {"Wrapper": "go", "In": "vectors/CMAC-AES.bz2", "Out": "expected/CMAC-AES.bz2"} + {"Wrapper": "go", "In": "vectors/CMAC-AES.bz2", "Out": "expected/CMAC-AES.bz2"}, + + {"Wrapper": "go", "In": "vectors/TLS-v1.2.bz2", "Out": "expected/TLS-v1.2.bz2"} ] diff --git a/src/crypto/internal/fips140test/acvp_test.go b/src/crypto/internal/fips140test/acvp_test.go index 7e3ab4031edc96..97c0c26aed07b8 100644 --- a/src/crypto/internal/fips140test/acvp_test.go +++ b/src/crypto/internal/fips140test/acvp_test.go @@ -37,6 +37,7 @@ import ( "crypto/internal/fips140/sha3" "crypto/internal/fips140/sha512" "crypto/internal/fips140/subtle" + "crypto/internal/fips140/tls12" "crypto/rand" _ "embed" "encoding/binary" @@ -114,6 +115,8 @@ var ( // https://pages.nist.gov/ACVP/draft-celi-acvp-symmetric.html#section-7.3 // HKDF KDA algorithm capabilities: // https://pages.nist.gov/ACVP/draft-hammett-acvp-kas-kdf-hkdf.html#section-7.3 + // TLS 1.2 KDF algorithm capabilities: + // https://pages.nist.gov/ACVP/draft-celi-acvp-kdf-tls.html#section-7.2 //go:embed acvp_capabilities.json capabilitiesJson []byte @@ -220,6 +223,12 @@ var ( "CMAC-AES": cmdCmacAesAft(), "CMAC-AES/verify": cmdCmacAesVerifyAft(), + + // Note: Only SHA2-256, SHA2-384 and SHA2-512 are valid hash functions for TLSKDF. + // See https://pages.nist.gov/ACVP/draft-celi-acvp-kdf-tls.html#section-7.2.1 + "TLSKDF/1.2/SHA2-256": cmdTlsKdf12Aft(func() fips140.Hash { return sha256.New() }), + "TLSKDF/1.2/SHA2-384": cmdTlsKdf12Aft(func() fips140.Hash { return sha512.New384() }), + "TLSKDF/1.2/SHA2-512": cmdTlsKdf12Aft(func() fips140.Hash { return sha512.New() }), } ) @@ -1314,6 +1323,21 @@ func cmdCmacAesVerifyAft() command { } } +func cmdTlsKdf12Aft(h func() fips140.Hash) command { + return command{ + requiredArgs: 5, // Number output bytes, secret, label, seed1, seed2 + handler: func(args [][]byte) ([][]byte, error) { + outputLen := binary.LittleEndian.Uint32(args[0]) + secret := args[1] + label := string(args[2]) + seed1 := args[3] + seed2 := args[4] + + return [][]byte{tls12.PRF(h, secret, label, append(seed1, seed2...), int(outputLen))}, nil + }, + } +} + func TestACVP(t *testing.T) { testenv.SkipIfShortAndSlow(t) From 47d0b0f2bf9d507d5bc9ea8f456cc821829fe21c Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Sat, 14 Dec 2024 14:36:21 -0500 Subject: [PATCH 294/397] crypto/internal/fips140test: add TLS-v1.3 ACVP tests Adds ACVP test coverage for the SP 800-56Crev2 IG 2.4.B TLS v1.3 KDF based on the NIST spec: https://pages.nist.gov/ACVP/draft-hammett-acvp-kdf-tls-v1.3.html Only SHA2-256 and SHA2-384 are valid hash algorithms for the TLS1.3 KDF algorithm. The BoringSSL acvptool "lowers" the more complicated TLS 1.3 KDF ACVP test cases into simple invocations of our module wrapper's pre-existing HKDF commands, and the new "HKDFExtract/$HASH" and "HKDFExpandLabel/$HASH" commands added in this branch. Updates #69642 Change-Id: I5fb1af5b5b33c1845b27cf8968e6523e89bcc589 Reviewed-on: https://go-review.googlesource.com/c/go/+/636117 Reviewed-by: Roland Shoemaker Reviewed-by: Dmitri Shuralyov LUCI-TryBot-Result: Go LUCI Auto-Submit: Filippo Valsorda Reviewed-by: Filippo Valsorda --- .../fips140test/acvp_capabilities.json | 3 +- .../fips140test/acvp_test.config.json | 3 +- src/crypto/internal/fips140test/acvp_test.go | 34 +++++++++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/crypto/internal/fips140test/acvp_capabilities.json b/src/crypto/internal/fips140test/acvp_capabilities.json index 74317deb417d9a..02098306740494 100644 --- a/src/crypto/internal/fips140test/acvp_capabilities.json +++ b/src/crypto/internal/fips140test/acvp_capabilities.json @@ -61,5 +61,6 @@ {"algorithm":"ACVP-AES-GCM","direction":["encrypt","decrypt"],"keyLen":[128,192,256],"payloadLen":[{"min":0,"max":65536,"increment":8}],"aadLen":[{"min":0,"max":65536,"increment":8}],"tagLen":[128],"ivLen":[96],"ivGen":"internal","ivGenMode":"8.2.2","revision":"1.0"}, {"algorithm":"CMAC-AES","capabilities":[{"direction":["gen","ver"],"msgLen":[{"min":0,"max":524288,"increment":8}],"keyLen":[128,256],"macLen":[{"min":8,"max":128,"increment":8}]}],"revision":"1.0"}, - {"algorithm":"TLS-v1.2","mode":"KDF","revision":"RFC7627","hashAlg":["SHA2-256","SHA2-384","SHA2-512"]} + {"algorithm":"TLS-v1.2","mode":"KDF","revision":"RFC7627","hashAlg":["SHA2-256","SHA2-384","SHA2-512"]}, + {"algorithm":"TLS-v1.3","mode":"KDF","revision":"RFC8446","hmacAlg":["SHA2-256","SHA2-384"],"runningMode":["DHE","PSK","PSK-DHE"]} ] diff --git a/src/crypto/internal/fips140test/acvp_test.config.json b/src/crypto/internal/fips140test/acvp_test.config.json index a25d38fd68b467..3cfe80cce0117e 100644 --- a/src/crypto/internal/fips140test/acvp_test.config.json +++ b/src/crypto/internal/fips140test/acvp_test.config.json @@ -44,5 +44,6 @@ {"Wrapper": "go", "In": "vectors/CMAC-AES.bz2", "Out": "expected/CMAC-AES.bz2"}, - {"Wrapper": "go", "In": "vectors/TLS-v1.2.bz2", "Out": "expected/TLS-v1.2.bz2"} + {"Wrapper": "go", "In": "vectors/TLS-v1.2.bz2", "Out": "expected/TLS-v1.2.bz2"}, + {"Wrapper": "go", "In": "vectors/TLS-v1.3.bz2", "Out": "expected/TLS-v1.3.bz2"} ] diff --git a/src/crypto/internal/fips140test/acvp_test.go b/src/crypto/internal/fips140test/acvp_test.go index 97c0c26aed07b8..2d46ceaf70f545 100644 --- a/src/crypto/internal/fips140test/acvp_test.go +++ b/src/crypto/internal/fips140test/acvp_test.go @@ -38,6 +38,7 @@ import ( "crypto/internal/fips140/sha512" "crypto/internal/fips140/subtle" "crypto/internal/fips140/tls12" + "crypto/internal/fips140/tls13" "crypto/rand" _ "embed" "encoding/binary" @@ -117,6 +118,8 @@ var ( // https://pages.nist.gov/ACVP/draft-hammett-acvp-kas-kdf-hkdf.html#section-7.3 // TLS 1.2 KDF algorithm capabilities: // https://pages.nist.gov/ACVP/draft-celi-acvp-kdf-tls.html#section-7.2 + // TLS 1.3 KDF algorithm capabilities: + // https://pages.nist.gov/ACVP/draft-hammett-acvp-kdf-tls-v1.3.html#section-7.2 //go:embed acvp_capabilities.json capabilitiesJson []byte @@ -181,6 +184,11 @@ var ( "HKDF/SHA3-384": cmdHkdfAft(func() fips140.Hash { return sha3.New384() }), "HKDF/SHA3-512": cmdHkdfAft(func() fips140.Hash { return sha3.New512() }), + "HKDFExtract/SHA2-256": cmdHkdfExtractAft(func() fips140.Hash { return sha256.New() }), + "HKDFExtract/SHA2-384": cmdHkdfExtractAft(func() fips140.Hash { return sha512.New384() }), + "HKDFExpandLabel/SHA2-256": cmdHkdfExpandLabelAft(func() fips140.Hash { return sha256.New() }), + "HKDFExpandLabel/SHA2-384": cmdHkdfExpandLabelAft(func() fips140.Hash { return sha512.New384() }), + "PBKDF": cmdPbkdf(), "ML-KEM-768/keyGen": cmdMlKem768KeyGenAft(), @@ -537,6 +545,32 @@ func cmdHkdfAft(h func() fips140.Hash) command { } } +func cmdHkdfExtractAft(h func() fips140.Hash) command { + return command{ + requiredArgs: 2, // secret, salt + handler: func(args [][]byte) ([][]byte, error) { + secret := args[0] + salt := args[1] + + return [][]byte{hkdf.Extract(h, secret, salt)}, nil + }, + } +} + +func cmdHkdfExpandLabelAft(h func() fips140.Hash) command { + return command{ + requiredArgs: 4, // output length, secret, label, transcript hash + handler: func(args [][]byte) ([][]byte, error) { + keyLen := int(binary.LittleEndian.Uint32(args[0])) + secret := args[1] + label := args[2] + transcriptHash := args[3] + + return [][]byte{tls13.ExpandLabel(h, secret, string(label), transcriptHash, keyLen)}, nil + }, + } +} + func cmdPbkdf() command { return command{ // Hash name, key length, salt, password, iteration count From a704d39b29dfc21599f644909c0f98bbfa745cb4 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Fri, 7 Feb 2025 23:22:50 +0000 Subject: [PATCH 295/397] os: hide SetFinalizer from users of Root Currently Root embeds a root and calls SetFinalizer on &r.root. This sets the finalizer on the outer root, which is visible to users of os.Root, and thus they can mutate the finalizer attached to it. This change modifies Root to not embed its inner root, but rather to refer to it by pointer. This allows us to set the finalizer on this independent inner object, preventing users of os.Root from changing the finalizer. This follows the same pattern as os.File's finalizer. Fixes #71617. Change-Id: Ibd199bab1b3c877d5e12ef380fd4647b4e10221f Reviewed-on: https://go-review.googlesource.com/c/go/+/647876 Auto-Submit: Michael Knyszek Reviewed-by: Damien Neil LUCI-TryBot-Result: Go LUCI --- src/os/root.go | 2 +- src/os/root_noopenat.go | 2 +- src/os/root_unix.go | 4 ++-- src/os/root_windows.go | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/os/root.go b/src/os/root.go index 04741c02810baa..f91c0f75f30e2a 100644 --- a/src/os/root.go +++ b/src/os/root.go @@ -60,7 +60,7 @@ func OpenInRoot(dir, name string) (*File, error) { // - When GOOS=plan9 or GOOS=js, Root does not track directories across renames. // On these platforms, a Root references a directory name, not a file descriptor. type Root struct { - root root + root *root } const ( diff --git a/src/os/root_noopenat.go b/src/os/root_noopenat.go index 8d5ead32b9cd0a..8be55a029fa2b6 100644 --- a/src/os/root_noopenat.go +++ b/src/os/root_noopenat.go @@ -49,7 +49,7 @@ func newRoot(name string) (*Root, error) { if !fi.IsDir() { return nil, errors.New("not a directory") } - return &Root{root{name: name}}, nil + return &Root{&root{name: name}}, nil } func (r *root) Close() error { diff --git a/src/os/root_unix.go b/src/os/root_unix.go index 4b52b81de71e81..02d3b4bdad007e 100644 --- a/src/os/root_unix.go +++ b/src/os/root_unix.go @@ -48,11 +48,11 @@ func newRoot(fd int, name string) (*Root, error) { syscall.CloseOnExec(fd) } - r := &Root{root{ + r := &Root{&root{ fd: fd, name: name, }} - runtime.SetFinalizer(&r.root, (*root).Close) + runtime.SetFinalizer(r.root, (*root).Close) return r, nil } diff --git a/src/os/root_windows.go b/src/os/root_windows.go index dcc311cf86f731..32dfa070b740fd 100644 --- a/src/os/root_windows.go +++ b/src/os/root_windows.go @@ -105,11 +105,11 @@ func newRoot(fd syscall.Handle, name string) (*Root, error) { return nil, &PathError{Op: "open", Path: name, Err: errors.New("not a directory")} } - r := &Root{root{ + r := &Root{&root{ fd: fd, name: name, }} - runtime.SetFinalizer(&r.root, (*root).Close) + runtime.SetFinalizer(r.root, (*root).Close) return r, nil } From 3924fe92b61042df7bef5c19db0ab0316d111e9b Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Fri, 7 Feb 2025 09:55:15 -0800 Subject: [PATCH 296/397] runtime: establish happens-before between goroutine and bubble exit synctest.Run waits for all bubbled goroutines to exit before returning. Establish a happens-before relationship between the bubbled goroutines exiting and Run returning. For #67434 Change-Id: Ibda7ec2075ae50838c0851e60dc5b3c6f3ca70fb Reviewed-on: https://go-review.googlesource.com/c/go/+/647755 LUCI-TryBot-Result: Go LUCI Auto-Submit: Damien Neil Reviewed-by: Michael Pratt --- src/internal/synctest/synctest_test.go | 26 ++++++++++++++++++++++++++ src/runtime/synctest.go | 7 +++++++ 2 files changed, 33 insertions(+) diff --git a/src/internal/synctest/synctest_test.go b/src/internal/synctest/synctest_test.go index 7d1e04e2ba34e2..450d5f54166943 100644 --- a/src/internal/synctest/synctest_test.go +++ b/src/internal/synctest/synctest_test.go @@ -433,6 +433,32 @@ func TestWaitGroup(t *testing.T) { }) } +func TestHappensBefore(t *testing.T) { + var v int + synctest.Run(func() { + go func() { + v++ // 1 + }() + // Wait creates a happens-before relationship on the above goroutine exiting. + synctest.Wait() + go func() { + v++ // 2 + }() + }) + // Run exiting creates a happens-before relationship on goroutines started in the bubble. + synctest.Run(func() { + v++ // 3 + // There is a happens-before relationship between the time.AfterFunc call, + // and the func running. + time.AfterFunc(0, func() { + v++ // 4 + }) + }) + if got, want := v, 4; got != want { + t.Errorf("v = %v, want %v", got, want) + } +} + func wantPanic(t *testing.T, want string) { if e := recover(); e != nil { if got := fmt.Sprint(e); got != want { diff --git a/src/runtime/synctest.go b/src/runtime/synctest.go index 498c3b92dd0796..65bb15dfbb0455 100644 --- a/src/runtime/synctest.go +++ b/src/runtime/synctest.go @@ -182,6 +182,8 @@ func synctestRun(f func()) { sg.active++ for { if raceenabled { + // Establish a happens-before relationship between a timer being created, + // and the timer running. raceacquireg(gp, gp.syncGroup.raceaddr()) } unlock(&sg.mu) @@ -205,6 +207,11 @@ func synctestRun(f func()) { total := sg.total unlock(&sg.mu) + if raceenabled { + // Establish a happens-before relationship between bubbled goroutines exiting + // and Run returning. + raceacquireg(gp, gp.syncGroup.raceaddr()) + } if total != 1 { panic("deadlock: all goroutines in bubble are blocked") } From 0f62125487d572168b71be7acb3b9efead55b37c Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Fri, 24 Jan 2025 20:36:51 +0000 Subject: [PATCH 297/397] internal/trace: rename go122 to tracev2 This change follows up from the previous one which renamed oldtrace to tracev1, defining everything Go 1.22+ as trace v2. This change also re-maps some packages in preparation for sharing with other parts of the standard library, like the runtime. It also cleans up some other uses of 'go122' that are just a bit misleading. The mappings are as follows: - internal/trace/event -> internal/trace/tracev2/event - internal/trace/event/go122 -> internal/trace/tracev2 - internal/trace/internal/testgen/go122 -> internal/trace/internal/testgen The CL updates all import paths and runs gofmt -w -s on the entire subdirectory. Change-Id: I35476c679a96d4eafad6b94bac5f88aa7b085d2f Reviewed-on: https://go-review.googlesource.com/c/go/+/644218 Auto-Submit: Michael Knyszek Reviewed-by: Michael Pratt LUCI-TryBot-Result: Go LUCI --- src/cmd/trace/main.go | 2 +- src/go/build/deps_test.go | 12 +- src/internal/trace/base.go | 8 +- src/internal/trace/batch.go | 22 +- src/internal/trace/batchcursor.go | 6 +- src/internal/trace/event.go | 236 +++++++-------- src/internal/trace/generation.go | 24 +- .../internal/testgen/{go122 => }/trace.go | 28 +- src/internal/trace/internal/tracev1/parser.go | 2 +- src/internal/trace/order.go | 286 +++++++++--------- src/internal/trace/raw/event.go | 2 +- src/internal/trace/raw/reader.go | 2 +- src/internal/trace/raw/textreader.go | 2 +- src/internal/trace/raw/writer.go | 2 +- src/internal/trace/reader.go | 4 +- src/internal/trace/summary_test.go | 8 +- .../go122-confuse-seq-across-generations.go | 16 +- .../go122-create-syscall-reuse-thread-id.go | 10 +- .../generators/go122-create-syscall-with-p.go | 6 +- .../generators/go122-fail-first-gen-first.go | 14 +- .../go122-go-create-without-running-g.go | 6 +- .../go122-syscall-steal-proc-ambiguous.go | 12 +- ...-syscall-steal-proc-gen-boundary-bare-m.go | 10 +- ...-gen-boundary-reacquire-new-proc-bare-m.go | 10 +- ...al-proc-gen-boundary-reacquire-new-proc.go | 14 +- .../go122-syscall-steal-proc-gen-boundary.go | 14 +- ...ll-steal-proc-reacquire-new-proc-bare-m.go | 10 +- ...2-syscall-steal-proc-reacquire-new-proc.go | 14 +- .../go122-syscall-steal-proc-self.go | 8 +- .../go122-syscall-steal-proc-simple-bare-m.go | 8 +- .../go122-syscall-steal-proc-simple.go | 12 +- ...2-syscall-steal-proc-sitting-in-syscall.go | 8 +- .../go122-task-across-generations.go | 12 +- src/internal/trace/tracev1.go | 112 +++---- src/internal/trace/tracev1_test.go | 6 +- .../trace/{event/go122 => tracev2}/event.go | 4 +- .../trace/{ => tracev2}/event/event.go | 0 src/internal/trace/version/version.go | 8 +- 38 files changed, 480 insertions(+), 480 deletions(-) rename src/internal/trace/internal/testgen/{go122 => }/trace.go (94%) rename src/internal/trace/{event/go122 => tracev2}/event.go (99%) rename src/internal/trace/{ => tracev2}/event/event.go (100%) diff --git a/src/cmd/trace/main.go b/src/cmd/trace/main.go index 075212eacb1490..625adb1c0c3d99 100644 --- a/src/cmd/trace/main.go +++ b/src/cmd/trace/main.go @@ -11,8 +11,8 @@ import ( "flag" "fmt" "internal/trace" - "internal/trace/event" "internal/trace/raw" + "internal/trace/tracev2/event" "internal/trace/traceviewer" "io" "log" diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index e992681da4d4b4..5212db740ee6fa 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -699,18 +699,18 @@ var depsRules = ` # v2 execution trace parser. FMT - < internal/trace/event; + < internal/trace/tracev2/event; - internal/trace/event - < internal/trace/event/go122; + internal/trace/tracev2/event + < internal/trace/tracev2; - FMT, io, internal/trace/event/go122 + FMT, io, internal/trace/tracev2 < internal/trace/version; FMT, encoding/binary, internal/trace/version < internal/trace/raw; - FMT, internal/trace/event, internal/trace/version, io, sort, encoding/binary + FMT, internal/trace/tracev2/event, internal/trace/version, io, sort, encoding/binary < internal/trace/internal/tracev1; FMT, encoding/binary, internal/trace/version, internal/trace/internal/tracev1, container/heap, math/rand @@ -720,7 +720,7 @@ var depsRules = ` < internal/trace/testtrace; regexp, internal/txtar, internal/trace, internal/trace/raw - < internal/trace/internal/testgen/go122; + < internal/trace/internal/testgen; # cmd/trace dependencies. FMT, diff --git a/src/internal/trace/base.go b/src/internal/trace/base.go index 5d707bd6cc376b..c6cc08ff69464d 100644 --- a/src/internal/trace/base.go +++ b/src/internal/trace/base.go @@ -12,8 +12,8 @@ import ( "math" "strings" - "internal/trace/event" - "internal/trace/event/go122" + "internal/trace/tracev2" + "internal/trace/tracev2/event" "internal/trace/version" ) @@ -38,7 +38,7 @@ type baseEvent struct { func (e *baseEvent) extra(v version.Version) []uint64 { switch v { case version.Go122: - return e.args[len(go122.Specs()[e.typ].Args)-1:] + return e.args[len(tracev2.Specs()[e.typ].Args)-1:] } panic(fmt.Sprintf("unsupported version: go 1.%d", v)) } @@ -239,7 +239,7 @@ func (s cpuSample) asEvent(table *evTable) Event { table: table, ctx: s.schedCtx, base: baseEvent{ - typ: go122.EvCPUSample, + typ: tracev2.EvCPUSample, time: s.time, }, } diff --git a/src/internal/trace/batch.go b/src/internal/trace/batch.go index 2b47c9b72cb8d9..ba22bfde38dc27 100644 --- a/src/internal/trace/batch.go +++ b/src/internal/trace/batch.go @@ -10,8 +10,8 @@ import ( "fmt" "io" - "internal/trace/event" - "internal/trace/event/go122" + "internal/trace/tracev2" + "internal/trace/tracev2/event" ) // timestamp is an unprocessed timestamp. @@ -27,19 +27,19 @@ type batch struct { } func (b *batch) isStringsBatch() bool { - return b.exp == event.NoExperiment && len(b.data) > 0 && event.Type(b.data[0]) == go122.EvStrings + return b.exp == event.NoExperiment && len(b.data) > 0 && event.Type(b.data[0]) == tracev2.EvStrings } func (b *batch) isStacksBatch() bool { - return b.exp == event.NoExperiment && len(b.data) > 0 && event.Type(b.data[0]) == go122.EvStacks + return b.exp == event.NoExperiment && len(b.data) > 0 && event.Type(b.data[0]) == tracev2.EvStacks } func (b *batch) isCPUSamplesBatch() bool { - return b.exp == event.NoExperiment && len(b.data) > 0 && event.Type(b.data[0]) == go122.EvCPUSamples + return b.exp == event.NoExperiment && len(b.data) > 0 && event.Type(b.data[0]) == tracev2.EvCPUSamples } func (b *batch) isFreqBatch() bool { - return b.exp == event.NoExperiment && len(b.data) > 0 && event.Type(b.data[0]) == go122.EvFrequency + return b.exp == event.NoExperiment && len(b.data) > 0 && event.Type(b.data[0]) == tracev2.EvFrequency } // readBatch reads the next full batch from r. @@ -52,13 +52,13 @@ func readBatch(r interface { if err != nil { return batch{}, 0, err } - if typ := event.Type(b); typ != go122.EvEventBatch && typ != go122.EvExperimentalBatch { - return batch{}, 0, fmt.Errorf("expected batch event, got %s", go122.EventString(typ)) + if typ := event.Type(b); typ != tracev2.EvEventBatch && typ != tracev2.EvExperimentalBatch { + return batch{}, 0, fmt.Errorf("expected batch event, got %s", tracev2.EventString(typ)) } // Read the experiment of we have one. exp := event.NoExperiment - if event.Type(b) == go122.EvExperimentalBatch { + if event.Type(b) == tracev2.EvExperimentalBatch { e, err := r.ReadByte() if err != nil { return batch{}, 0, err @@ -86,8 +86,8 @@ func readBatch(r interface { if err != nil { return batch{}, gen, fmt.Errorf("error reading batch size: %w", err) } - if size > go122.MaxBatchSize { - return batch{}, gen, fmt.Errorf("invalid batch size %d, maximum is %d", size, go122.MaxBatchSize) + if size > tracev2.MaxBatchSize { + return batch{}, gen, fmt.Errorf("invalid batch size %d, maximum is %d", size, tracev2.MaxBatchSize) } // Copy out the batch for later processing. diff --git a/src/internal/trace/batchcursor.go b/src/internal/trace/batchcursor.go index 66d297ee33a486..026f24f8b1ee61 100644 --- a/src/internal/trace/batchcursor.go +++ b/src/internal/trace/batchcursor.go @@ -9,8 +9,8 @@ import ( "encoding/binary" "fmt" - "internal/trace/event" - "internal/trace/event/go122" + "internal/trace/tracev2" + "internal/trace/tracev2/event" ) type batchCursor struct { @@ -67,7 +67,7 @@ func (b *batchCursor) compare(a *batchCursor) int { func readTimedBaseEvent(b []byte, e *baseEvent) (int, timestamp, error) { // Get the event type. typ := event.Type(b[0]) - specs := go122.Specs() + specs := tracev2.Specs() if int(typ) >= len(specs) { return 0, 0, fmt.Errorf("found invalid event type: %v", typ) } diff --git a/src/internal/trace/event.go b/src/internal/trace/event.go index c86c3c0c99c0b1..67f1e382306d27 100644 --- a/src/internal/trace/event.go +++ b/src/internal/trace/event.go @@ -11,8 +11,8 @@ import ( "strings" "time" - "internal/trace/event" - "internal/trace/event/go122" + "internal/trace/tracev2" + "internal/trace/tracev2/event" "internal/trace/version" ) @@ -342,7 +342,7 @@ type Event struct { // Kind returns the kind of event that this is. func (e Event) Kind() EventKind { - return go122Type2Kind[e.base.typ] + return tracev2Type2Kind[e.base.typ] } // Time returns the timestamp of the event. @@ -394,10 +394,10 @@ func (e Event) Stack() Stack { if e.base.typ == evSync { return NoStack } - if e.base.typ == go122.EvCPUSample { + if e.base.typ == tracev2.EvCPUSample { return Stack{table: e.table, id: stackID(e.base.args[0])} } - spec := go122.Specs()[e.base.typ] + spec := tracev2.Specs()[e.base.typ] if len(spec.StackIDs) == 0 { return NoStack } @@ -420,17 +420,17 @@ func (e Event) Metric() Metric { } var m Metric switch e.base.typ { - case go122.EvProcsChange: + case tracev2.EvProcsChange: m.Name = "/sched/gomaxprocs:threads" m.Value = Value{kind: ValueUint64, scalar: e.base.args[0]} - case go122.EvHeapAlloc: + case tracev2.EvHeapAlloc: m.Name = "/memory/classes/heap/objects:bytes" m.Value = Value{kind: ValueUint64, scalar: e.base.args[0]} - case go122.EvHeapGoal: + case tracev2.EvHeapGoal: m.Name = "/gc/heap/goal:bytes" m.Value = Value{kind: ValueUint64, scalar: e.base.args[0]} default: - panic(fmt.Sprintf("internal error: unexpected event type for Metric kind: %s", go122.EventString(e.base.typ))) + panic(fmt.Sprintf("internal error: unexpected event type for Metric kind: %s", tracev2.EventString(e.base.typ))) } return m } @@ -442,8 +442,8 @@ func (e Event) Label() Label { if e.Kind() != EventLabel { panic("Label called on non-Label event") } - if e.base.typ != go122.EvGoLabel { - panic(fmt.Sprintf("internal error: unexpected event type for Label kind: %s", go122.EventString(e.base.typ))) + if e.base.typ != tracev2.EvGoLabel { + panic(fmt.Sprintf("internal error: unexpected event type for Label kind: %s", tracev2.EventString(e.base.typ))) } return Label{ Label: e.table.strings.mustGet(stringID(e.base.args[0])), @@ -460,33 +460,33 @@ func (e Event) Range() Range { } var r Range switch e.base.typ { - case go122.EvSTWBegin, go122.EvSTWEnd: + case tracev2.EvSTWBegin, tracev2.EvSTWEnd: // N.B. ordering.advance smuggles in the STW reason as e.base.args[0] - // for go122.EvSTWEnd (it's already there for Begin). + // for tracev2.EvSTWEnd (it's already there for Begin). r.Name = "stop-the-world (" + e.table.strings.mustGet(stringID(e.base.args[0])) + ")" r.Scope = ResourceID{Kind: ResourceGoroutine, id: int64(e.Goroutine())} - case go122.EvGCBegin, go122.EvGCActive, go122.EvGCEnd: + case tracev2.EvGCBegin, tracev2.EvGCActive, tracev2.EvGCEnd: r.Name = "GC concurrent mark phase" r.Scope = ResourceID{Kind: ResourceNone} - case go122.EvGCSweepBegin, go122.EvGCSweepActive, go122.EvGCSweepEnd: + case tracev2.EvGCSweepBegin, tracev2.EvGCSweepActive, tracev2.EvGCSweepEnd: r.Name = "GC incremental sweep" r.Scope = ResourceID{Kind: ResourceProc} - if e.base.typ == go122.EvGCSweepActive { + if e.base.typ == tracev2.EvGCSweepActive { r.Scope.id = int64(e.base.args[0]) } else { r.Scope.id = int64(e.Proc()) } r.Scope.id = int64(e.Proc()) - case go122.EvGCMarkAssistBegin, go122.EvGCMarkAssistActive, go122.EvGCMarkAssistEnd: + case tracev2.EvGCMarkAssistBegin, tracev2.EvGCMarkAssistActive, tracev2.EvGCMarkAssistEnd: r.Name = "GC mark assist" r.Scope = ResourceID{Kind: ResourceGoroutine} - if e.base.typ == go122.EvGCMarkAssistActive { + if e.base.typ == tracev2.EvGCMarkAssistActive { r.Scope.id = int64(e.base.args[0]) } else { r.Scope.id = int64(e.Goroutine()) } default: - panic(fmt.Sprintf("internal error: unexpected event type for Range kind: %s", go122.EventString(e.base.typ))) + panic(fmt.Sprintf("internal error: unexpected event type for Range kind: %s", tracev2.EventString(e.base.typ))) } return r } @@ -498,7 +498,7 @@ func (e Event) RangeAttributes() []RangeAttribute { if e.Kind() != EventRangeEnd { panic("Range called on non-Range event") } - if e.base.typ != go122.EvGCSweepEnd { + if e.base.typ != tracev2.EvGCSweepEnd { return nil } return []RangeAttribute{ @@ -523,14 +523,14 @@ func (e Event) Task() Task { parentID := NoTask var typ string switch e.base.typ { - case go122.EvUserTaskBegin: + case tracev2.EvUserTaskBegin: parentID = TaskID(e.base.args[1]) typ = e.table.strings.mustGet(stringID(e.base.args[2])) - case go122.EvUserTaskEnd: + case tracev2.EvUserTaskEnd: parentID = TaskID(e.base.extra(version.Go122)[0]) typ = e.table.getExtraString(extraStringID(e.base.extra(version.Go122)[1])) default: - panic(fmt.Sprintf("internal error: unexpected event type for Task kind: %s", go122.EventString(e.base.typ))) + panic(fmt.Sprintf("internal error: unexpected event type for Task kind: %s", tracev2.EventString(e.base.typ))) } return Task{ ID: TaskID(e.base.args[0]), @@ -546,8 +546,8 @@ func (e Event) Region() Region { if kind := e.Kind(); kind != EventRegionBegin && kind != EventRegionEnd { panic("Region called on non-Region event") } - if e.base.typ != go122.EvUserRegionBegin && e.base.typ != go122.EvUserRegionEnd { - panic(fmt.Sprintf("internal error: unexpected event type for Region kind: %s", go122.EventString(e.base.typ))) + if e.base.typ != tracev2.EvUserRegionBegin && e.base.typ != tracev2.EvUserRegionEnd { + panic(fmt.Sprintf("internal error: unexpected event type for Region kind: %s", tracev2.EventString(e.base.typ))) } return Region{ Task: TaskID(e.base.args[0]), @@ -562,8 +562,8 @@ func (e Event) Log() Log { if e.Kind() != EventLog { panic("Log called on non-Log event") } - if e.base.typ != go122.EvUserLog { - panic(fmt.Sprintf("internal error: unexpected event type for Log kind: %s", go122.EventString(e.base.typ))) + if e.base.typ != tracev2.EvUserLog { + panic(fmt.Sprintf("internal error: unexpected event type for Log kind: %s", tracev2.EventString(e.base.typ))) } return Log{ Task: TaskID(e.base.args[0]), @@ -581,14 +581,14 @@ func (e Event) StateTransition() StateTransition { } var s StateTransition switch e.base.typ { - case go122.EvProcStart: + case tracev2.EvProcStart: s = procStateTransition(ProcID(e.base.args[0]), ProcIdle, ProcRunning) - case go122.EvProcStop: + case tracev2.EvProcStop: s = procStateTransition(e.ctx.P, ProcRunning, ProcIdle) - case go122.EvProcSteal: + case tracev2.EvProcSteal: // N.B. ordering.advance populates e.base.extra. beforeState := ProcRunning - if go122.ProcStatus(e.base.extra(version.Go122)[0]) == go122.ProcSyscallAbandoned { + if tracev2.ProcStatus(e.base.extra(version.Go122)[0]) == tracev2.ProcSyscallAbandoned { // We've lost information because this ProcSteal advanced on a // SyscallAbandoned state. Treat the P as idle because ProcStatus // treats SyscallAbandoned as Idle. Otherwise we'll have an invalid @@ -596,53 +596,53 @@ func (e Event) StateTransition() StateTransition { beforeState = ProcIdle } s = procStateTransition(ProcID(e.base.args[0]), beforeState, ProcIdle) - case go122.EvProcStatus: + case tracev2.EvProcStatus: // N.B. ordering.advance populates e.base.extra. - s = procStateTransition(ProcID(e.base.args[0]), ProcState(e.base.extra(version.Go122)[0]), go122ProcStatus2ProcState[e.base.args[1]]) - case go122.EvGoCreate, go122.EvGoCreateBlocked: + s = procStateTransition(ProcID(e.base.args[0]), ProcState(e.base.extra(version.Go122)[0]), tracev2ProcStatus2ProcState[e.base.args[1]]) + case tracev2.EvGoCreate, tracev2.EvGoCreateBlocked: status := GoRunnable - if e.base.typ == go122.EvGoCreateBlocked { + if e.base.typ == tracev2.EvGoCreateBlocked { status = GoWaiting } s = goStateTransition(GoID(e.base.args[0]), GoNotExist, status) s.Stack = Stack{table: e.table, id: stackID(e.base.args[1])} - case go122.EvGoCreateSyscall: + case tracev2.EvGoCreateSyscall: s = goStateTransition(GoID(e.base.args[0]), GoNotExist, GoSyscall) - case go122.EvGoStart: + case tracev2.EvGoStart: s = goStateTransition(GoID(e.base.args[0]), GoRunnable, GoRunning) - case go122.EvGoDestroy: + case tracev2.EvGoDestroy: s = goStateTransition(e.ctx.G, GoRunning, GoNotExist) s.Stack = e.Stack() // This event references the resource the event happened on. - case go122.EvGoDestroySyscall: + case tracev2.EvGoDestroySyscall: s = goStateTransition(e.ctx.G, GoSyscall, GoNotExist) - case go122.EvGoStop: + case tracev2.EvGoStop: s = goStateTransition(e.ctx.G, GoRunning, GoRunnable) s.Reason = e.table.strings.mustGet(stringID(e.base.args[0])) s.Stack = e.Stack() // This event references the resource the event happened on. - case go122.EvGoBlock: + case tracev2.EvGoBlock: s = goStateTransition(e.ctx.G, GoRunning, GoWaiting) s.Reason = e.table.strings.mustGet(stringID(e.base.args[0])) s.Stack = e.Stack() // This event references the resource the event happened on. - case go122.EvGoUnblock, go122.EvGoSwitch, go122.EvGoSwitchDestroy: + case tracev2.EvGoUnblock, tracev2.EvGoSwitch, tracev2.EvGoSwitchDestroy: // N.B. GoSwitch and GoSwitchDestroy both emit additional events, but // the first thing they both do is unblock the goroutine they name, // identically to an unblock event (even their arguments match). s = goStateTransition(GoID(e.base.args[0]), GoWaiting, GoRunnable) - case go122.EvGoSyscallBegin: + case tracev2.EvGoSyscallBegin: s = goStateTransition(e.ctx.G, GoRunning, GoSyscall) s.Stack = e.Stack() // This event references the resource the event happened on. - case go122.EvGoSyscallEnd: + case tracev2.EvGoSyscallEnd: s = goStateTransition(e.ctx.G, GoSyscall, GoRunning) s.Stack = e.Stack() // This event references the resource the event happened on. - case go122.EvGoSyscallEndBlocked: + case tracev2.EvGoSyscallEndBlocked: s = goStateTransition(e.ctx.G, GoSyscall, GoRunnable) s.Stack = e.Stack() // This event references the resource the event happened on. - case go122.EvGoStatus, go122.EvGoStatusStack: + case tracev2.EvGoStatus, tracev2.EvGoStatusStack: packedStatus := e.base.args[2] from, to := packedStatus>>32, packedStatus&((1<<32)-1) - s = goStateTransition(GoID(e.base.args[0]), GoState(from), go122GoStatus2GoState[to]) + s = goStateTransition(GoID(e.base.args[0]), GoState(from), tracev2GoStatus2GoState[to]) default: - panic(fmt.Sprintf("internal error: unexpected event type for StateTransition kind: %s", go122.EventString(e.base.typ))) + panic(fmt.Sprintf("internal error: unexpected event type for StateTransition kind: %s", tracev2.EventString(e.base.typ))) } return s } @@ -657,7 +657,7 @@ func (e Event) Sync() Sync { if e.table != nil { expBatches = make(map[string][]ExperimentalBatch) for exp, batches := range e.table.expBatches { - expBatches[go122.Experiments()[exp]] = batches + expBatches[tracev2.Experiments()[exp]] = batches } } return Sync{ @@ -683,11 +683,11 @@ func (e Event) Experimental() ExperimentalEvent { if e.Kind() != EventExperimental { panic("Experimental called on non-Experimental event") } - spec := go122.Specs()[e.base.typ] + spec := tracev2.Specs()[e.base.typ] argNames := spec.Args[1:] // Skip timestamp; already handled. return ExperimentalEvent{ Name: spec.Name, - Experiment: go122.Experiments()[spec.Experiment], + Experiment: tracev2.Experiments()[spec.Experiment], ArgNames: argNames, Args: e.base.args[:len(argNames)], } @@ -695,72 +695,72 @@ func (e Event) Experimental() ExperimentalEvent { const evSync = ^event.Type(0) -var go122Type2Kind = [...]EventKind{ - go122.EvCPUSample: EventStackSample, - go122.EvProcsChange: EventMetric, - go122.EvProcStart: EventStateTransition, - go122.EvProcStop: EventStateTransition, - go122.EvProcSteal: EventStateTransition, - go122.EvProcStatus: EventStateTransition, - go122.EvGoCreate: EventStateTransition, - go122.EvGoCreateSyscall: EventStateTransition, - go122.EvGoStart: EventStateTransition, - go122.EvGoDestroy: EventStateTransition, - go122.EvGoDestroySyscall: EventStateTransition, - go122.EvGoStop: EventStateTransition, - go122.EvGoBlock: EventStateTransition, - go122.EvGoUnblock: EventStateTransition, - go122.EvGoSyscallBegin: EventStateTransition, - go122.EvGoSyscallEnd: EventStateTransition, - go122.EvGoSyscallEndBlocked: EventStateTransition, - go122.EvGoStatus: EventStateTransition, - go122.EvSTWBegin: EventRangeBegin, - go122.EvSTWEnd: EventRangeEnd, - go122.EvGCActive: EventRangeActive, - go122.EvGCBegin: EventRangeBegin, - go122.EvGCEnd: EventRangeEnd, - go122.EvGCSweepActive: EventRangeActive, - go122.EvGCSweepBegin: EventRangeBegin, - go122.EvGCSweepEnd: EventRangeEnd, - go122.EvGCMarkAssistActive: EventRangeActive, - go122.EvGCMarkAssistBegin: EventRangeBegin, - go122.EvGCMarkAssistEnd: EventRangeEnd, - go122.EvHeapAlloc: EventMetric, - go122.EvHeapGoal: EventMetric, - go122.EvGoLabel: EventLabel, - go122.EvUserTaskBegin: EventTaskBegin, - go122.EvUserTaskEnd: EventTaskEnd, - go122.EvUserRegionBegin: EventRegionBegin, - go122.EvUserRegionEnd: EventRegionEnd, - go122.EvUserLog: EventLog, - go122.EvGoSwitch: EventStateTransition, - go122.EvGoSwitchDestroy: EventStateTransition, - go122.EvGoCreateBlocked: EventStateTransition, - go122.EvGoStatusStack: EventStateTransition, - go122.EvSpan: EventExperimental, - go122.EvSpanAlloc: EventExperimental, - go122.EvSpanFree: EventExperimental, - go122.EvHeapObject: EventExperimental, - go122.EvHeapObjectAlloc: EventExperimental, - go122.EvHeapObjectFree: EventExperimental, - go122.EvGoroutineStack: EventExperimental, - go122.EvGoroutineStackAlloc: EventExperimental, - go122.EvGoroutineStackFree: EventExperimental, - evSync: EventSync, -} - -var go122GoStatus2GoState = [...]GoState{ - go122.GoRunnable: GoRunnable, - go122.GoRunning: GoRunning, - go122.GoWaiting: GoWaiting, - go122.GoSyscall: GoSyscall, -} - -var go122ProcStatus2ProcState = [...]ProcState{ - go122.ProcRunning: ProcRunning, - go122.ProcIdle: ProcIdle, - go122.ProcSyscall: ProcRunning, - go122.ProcSyscallAbandoned: ProcIdle, +var tracev2Type2Kind = [...]EventKind{ + tracev2.EvCPUSample: EventStackSample, + tracev2.EvProcsChange: EventMetric, + tracev2.EvProcStart: EventStateTransition, + tracev2.EvProcStop: EventStateTransition, + tracev2.EvProcSteal: EventStateTransition, + tracev2.EvProcStatus: EventStateTransition, + tracev2.EvGoCreate: EventStateTransition, + tracev2.EvGoCreateSyscall: EventStateTransition, + tracev2.EvGoStart: EventStateTransition, + tracev2.EvGoDestroy: EventStateTransition, + tracev2.EvGoDestroySyscall: EventStateTransition, + tracev2.EvGoStop: EventStateTransition, + tracev2.EvGoBlock: EventStateTransition, + tracev2.EvGoUnblock: EventStateTransition, + tracev2.EvGoSyscallBegin: EventStateTransition, + tracev2.EvGoSyscallEnd: EventStateTransition, + tracev2.EvGoSyscallEndBlocked: EventStateTransition, + tracev2.EvGoStatus: EventStateTransition, + tracev2.EvSTWBegin: EventRangeBegin, + tracev2.EvSTWEnd: EventRangeEnd, + tracev2.EvGCActive: EventRangeActive, + tracev2.EvGCBegin: EventRangeBegin, + tracev2.EvGCEnd: EventRangeEnd, + tracev2.EvGCSweepActive: EventRangeActive, + tracev2.EvGCSweepBegin: EventRangeBegin, + tracev2.EvGCSweepEnd: EventRangeEnd, + tracev2.EvGCMarkAssistActive: EventRangeActive, + tracev2.EvGCMarkAssistBegin: EventRangeBegin, + tracev2.EvGCMarkAssistEnd: EventRangeEnd, + tracev2.EvHeapAlloc: EventMetric, + tracev2.EvHeapGoal: EventMetric, + tracev2.EvGoLabel: EventLabel, + tracev2.EvUserTaskBegin: EventTaskBegin, + tracev2.EvUserTaskEnd: EventTaskEnd, + tracev2.EvUserRegionBegin: EventRegionBegin, + tracev2.EvUserRegionEnd: EventRegionEnd, + tracev2.EvUserLog: EventLog, + tracev2.EvGoSwitch: EventStateTransition, + tracev2.EvGoSwitchDestroy: EventStateTransition, + tracev2.EvGoCreateBlocked: EventStateTransition, + tracev2.EvGoStatusStack: EventStateTransition, + tracev2.EvSpan: EventExperimental, + tracev2.EvSpanAlloc: EventExperimental, + tracev2.EvSpanFree: EventExperimental, + tracev2.EvHeapObject: EventExperimental, + tracev2.EvHeapObjectAlloc: EventExperimental, + tracev2.EvHeapObjectFree: EventExperimental, + tracev2.EvGoroutineStack: EventExperimental, + tracev2.EvGoroutineStackAlloc: EventExperimental, + tracev2.EvGoroutineStackFree: EventExperimental, + evSync: EventSync, +} + +var tracev2GoStatus2GoState = [...]GoState{ + tracev2.GoRunnable: GoRunnable, + tracev2.GoRunning: GoRunning, + tracev2.GoWaiting: GoWaiting, + tracev2.GoSyscall: GoSyscall, +} + +var tracev2ProcStatus2ProcState = [...]ProcState{ + tracev2.ProcRunning: ProcRunning, + tracev2.ProcIdle: ProcIdle, + tracev2.ProcSyscall: ProcRunning, + tracev2.ProcSyscallAbandoned: ProcIdle, } // String returns the event as a human-readable string. @@ -842,7 +842,7 @@ func (e Event) validateTableIDs() error { if e.base.typ == evSync { return nil } - spec := go122.Specs()[e.base.typ] + spec := tracev2.Specs()[e.base.typ] // Check stacks. for _, i := range spec.StackIDs { diff --git a/src/internal/trace/generation.go b/src/internal/trace/generation.go index 42c2526a202968..89d0f6509bbbaf 100644 --- a/src/internal/trace/generation.go +++ b/src/internal/trace/generation.go @@ -14,8 +14,8 @@ import ( "slices" "strings" - "internal/trace/event" - "internal/trace/event/go122" + "internal/trace/tracev2" + "internal/trace/tracev2/event" ) // generation contains all the trace data for a single @@ -222,7 +222,7 @@ func addStrings(stringTable *dataTable[stringID, string], b batch) error { } r := bytes.NewReader(b.data) hdr, err := r.ReadByte() // Consume the EvStrings byte. - if err != nil || event.Type(hdr) != go122.EvStrings { + if err != nil || event.Type(hdr) != tracev2.EvStrings { return fmt.Errorf("missing strings batch header") } @@ -233,7 +233,7 @@ func addStrings(stringTable *dataTable[stringID, string], b batch) error { if err != nil { return err } - if event.Type(ev) != go122.EvString { + if event.Type(ev) != tracev2.EvString { return fmt.Errorf("expected string event, got %d", ev) } @@ -248,8 +248,8 @@ func addStrings(stringTable *dataTable[stringID, string], b batch) error { if err != nil { return err } - if len > go122.MaxStringSize { - return fmt.Errorf("invalid string size %d, maximum is %d", len, go122.MaxStringSize) + if len > tracev2.MaxStringSize { + return fmt.Errorf("invalid string size %d, maximum is %d", len, tracev2.MaxStringSize) } // Copy out the string. @@ -280,7 +280,7 @@ func addStacks(stackTable *dataTable[stackID, stack], pcs map[uint64]frame, b ba } r := bytes.NewReader(b.data) hdr, err := r.ReadByte() // Consume the EvStacks byte. - if err != nil || event.Type(hdr) != go122.EvStacks { + if err != nil || event.Type(hdr) != tracev2.EvStacks { return fmt.Errorf("missing stacks batch header") } @@ -290,7 +290,7 @@ func addStacks(stackTable *dataTable[stackID, stack], pcs map[uint64]frame, b ba if err != nil { return err } - if event.Type(ev) != go122.EvStack { + if event.Type(ev) != tracev2.EvStack { return fmt.Errorf("expected stack event, got %d", ev) } @@ -305,8 +305,8 @@ func addStacks(stackTable *dataTable[stackID, stack], pcs map[uint64]frame, b ba if err != nil { return err } - if nFrames > go122.MaxFramesPerStack { - return fmt.Errorf("invalid stack size %d, maximum is %d", nFrames, go122.MaxFramesPerStack) + if nFrames > tracev2.MaxFramesPerStack { + return fmt.Errorf("invalid stack size %d, maximum is %d", nFrames, tracev2.MaxFramesPerStack) } // Each frame consists of 4 fields: pc, funcID (string), fileID (string), line. @@ -358,7 +358,7 @@ func addCPUSamples(samples []cpuSample, b batch) ([]cpuSample, error) { } r := bytes.NewReader(b.data) hdr, err := r.ReadByte() // Consume the EvCPUSamples byte. - if err != nil || event.Type(hdr) != go122.EvCPUSamples { + if err != nil || event.Type(hdr) != tracev2.EvCPUSamples { return nil, fmt.Errorf("missing CPU samples batch header") } @@ -368,7 +368,7 @@ func addCPUSamples(samples []cpuSample, b batch) ([]cpuSample, error) { if err != nil { return nil, err } - if event.Type(ev) != go122.EvCPUSample { + if event.Type(ev) != tracev2.EvCPUSample { return nil, fmt.Errorf("expected CPU sample event, got %d", ev) } diff --git a/src/internal/trace/internal/testgen/go122/trace.go b/src/internal/trace/internal/testgen/trace.go similarity index 94% rename from src/internal/trace/internal/testgen/go122/trace.go rename to src/internal/trace/internal/testgen/trace.go index 5fd995ae9aeee3..9e797da509d81e 100644 --- a/src/internal/trace/internal/testgen/go122/trace.go +++ b/src/internal/trace/internal/testgen/trace.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package testkit +package testgen import ( "bytes" @@ -13,9 +13,9 @@ import ( "strings" "internal/trace" - "internal/trace/event" - "internal/trace/event/go122" "internal/trace/raw" + "internal/trace/tracev2" + "internal/trace/tracev2/event" "internal/trace/version" "internal/txtar" ) @@ -149,7 +149,7 @@ func (t *Trace) Generate() []byte { func (t *Trace) createEvent(ev event.Type, data []byte, args ...uint64) raw.Event { spec := t.specs[ev] - if ev != go122.EvStack { + if ev != tracev2.EvStack { if arity := len(spec.Args); len(args) != arity { panic(fmt.Sprintf("expected %d args for %s, got %d", arity, spec.Name, len(args))) } @@ -248,22 +248,22 @@ func (g *Generation) writeEventsTo(tw *raw.TextWriter) { // Write frequency. b := g.newStructuralBatch() - b.RawEvent(go122.EvFrequency, nil, 15625000) + b.RawEvent(tracev2.EvFrequency, nil, 15625000) b.writeEventsTo(tw) // Write stacks. b = g.newStructuralBatch() - b.RawEvent(go122.EvStacks, nil) + b.RawEvent(tracev2.EvStacks, nil) for stk, id := range g.stacks { stk := stk.stk[:stk.len] args := []uint64{id} for _, f := range stk { args = append(args, f.PC, g.String(f.Func), g.String(f.File), f.Line) } - b.RawEvent(go122.EvStack, nil, args...) + b.RawEvent(tracev2.EvStack, nil, args...) // Flush the batch if necessary. - if !g.ignoreStackBatchSizeLimit && b.size > go122.MaxBatchSize/2 { + if !g.ignoreStackBatchSizeLimit && b.size > tracev2.MaxBatchSize/2 { b.writeEventsTo(tw) b = g.newStructuralBatch() } @@ -272,12 +272,12 @@ func (g *Generation) writeEventsTo(tw *raw.TextWriter) { // Write strings. b = g.newStructuralBatch() - b.RawEvent(go122.EvStrings, nil) + b.RawEvent(tracev2.EvStrings, nil) for s, id := range g.strings { - b.RawEvent(go122.EvString, []byte(s), id) + b.RawEvent(tracev2.EvString, []byte(s), id) // Flush the batch if necessary. - if !g.ignoreStringBatchSizeLimit && b.size > go122.MaxBatchSize/2 { + if !g.ignoreStringBatchSizeLimit && b.size > tracev2.MaxBatchSize/2 { b.writeEventsTo(tw) b = g.newStructuralBatch() } @@ -341,9 +341,9 @@ func (b *Batch) uintArgFor(arg any, argSpec string) uint64 { case "seq": u = uint64(arg.(Seq)) case "pstatus": - u = uint64(arg.(go122.ProcStatus)) + u = uint64(arg.(tracev2.ProcStatus)) case "gstatus": - u = uint64(arg.(go122.GoStatus)) + u = uint64(arg.(tracev2.GoStatus)) case "g": u = uint64(arg.(trace.GoID)) case "m": @@ -385,7 +385,7 @@ func (b *Batch) RawEvent(typ event.Type, data []byte, args ...uint64) { func (b *Batch) writeEventsTo(tw *raw.TextWriter) { tw.WriteEvent(raw.Event{ Version: version.Go122, - Ev: go122.EvEventBatch, + Ev: tracev2.EvEventBatch, Args: []uint64{b.gen.gen, uint64(b.thread), uint64(b.timestamp), b.size}, }) for _, e := range b.events { diff --git a/src/internal/trace/internal/tracev1/parser.go b/src/internal/trace/internal/tracev1/parser.go index b95f86e43d202f..b4ec7a342c8280 100644 --- a/src/internal/trace/internal/tracev1/parser.go +++ b/src/internal/trace/internal/tracev1/parser.go @@ -17,7 +17,7 @@ import ( "encoding/binary" "errors" "fmt" - "internal/trace/event" + "internal/trace/tracev2/event" "internal/trace/version" "io" "math" diff --git a/src/internal/trace/order.go b/src/internal/trace/order.go index 131e05ce249f61..8028f61a83e57a 100644 --- a/src/internal/trace/order.go +++ b/src/internal/trace/order.go @@ -9,8 +9,8 @@ import ( "slices" "strings" - "internal/trace/event" - "internal/trace/event/go122" + "internal/trace/tracev2" + "internal/trace/tracev2/event" "internal/trace/version" ) @@ -92,97 +92,97 @@ type orderingHandleFunc func(o *ordering, ev *baseEvent, evt *evTable, m ThreadI var orderingDispatch = [256]orderingHandleFunc{ // Procs. - go122.EvProcsChange: (*ordering).advanceAnnotation, - go122.EvProcStart: (*ordering).advanceProcStart, - go122.EvProcStop: (*ordering).advanceProcStop, - go122.EvProcSteal: (*ordering).advanceProcSteal, - go122.EvProcStatus: (*ordering).advanceProcStatus, + tracev2.EvProcsChange: (*ordering).advanceAnnotation, + tracev2.EvProcStart: (*ordering).advanceProcStart, + tracev2.EvProcStop: (*ordering).advanceProcStop, + tracev2.EvProcSteal: (*ordering).advanceProcSteal, + tracev2.EvProcStatus: (*ordering).advanceProcStatus, // Goroutines. - go122.EvGoCreate: (*ordering).advanceGoCreate, - go122.EvGoCreateSyscall: (*ordering).advanceGoCreateSyscall, - go122.EvGoStart: (*ordering).advanceGoStart, - go122.EvGoDestroy: (*ordering).advanceGoStopExec, - go122.EvGoDestroySyscall: (*ordering).advanceGoDestroySyscall, - go122.EvGoStop: (*ordering).advanceGoStopExec, - go122.EvGoBlock: (*ordering).advanceGoStopExec, - go122.EvGoUnblock: (*ordering).advanceGoUnblock, - go122.EvGoSyscallBegin: (*ordering).advanceGoSyscallBegin, - go122.EvGoSyscallEnd: (*ordering).advanceGoSyscallEnd, - go122.EvGoSyscallEndBlocked: (*ordering).advanceGoSyscallEndBlocked, - go122.EvGoStatus: (*ordering).advanceGoStatus, + tracev2.EvGoCreate: (*ordering).advanceGoCreate, + tracev2.EvGoCreateSyscall: (*ordering).advanceGoCreateSyscall, + tracev2.EvGoStart: (*ordering).advanceGoStart, + tracev2.EvGoDestroy: (*ordering).advanceGoStopExec, + tracev2.EvGoDestroySyscall: (*ordering).advanceGoDestroySyscall, + tracev2.EvGoStop: (*ordering).advanceGoStopExec, + tracev2.EvGoBlock: (*ordering).advanceGoStopExec, + tracev2.EvGoUnblock: (*ordering).advanceGoUnblock, + tracev2.EvGoSyscallBegin: (*ordering).advanceGoSyscallBegin, + tracev2.EvGoSyscallEnd: (*ordering).advanceGoSyscallEnd, + tracev2.EvGoSyscallEndBlocked: (*ordering).advanceGoSyscallEndBlocked, + tracev2.EvGoStatus: (*ordering).advanceGoStatus, // STW. - go122.EvSTWBegin: (*ordering).advanceGoRangeBegin, - go122.EvSTWEnd: (*ordering).advanceGoRangeEnd, + tracev2.EvSTWBegin: (*ordering).advanceGoRangeBegin, + tracev2.EvSTWEnd: (*ordering).advanceGoRangeEnd, // GC events. - go122.EvGCActive: (*ordering).advanceGCActive, - go122.EvGCBegin: (*ordering).advanceGCBegin, - go122.EvGCEnd: (*ordering).advanceGCEnd, - go122.EvGCSweepActive: (*ordering).advanceGCSweepActive, - go122.EvGCSweepBegin: (*ordering).advanceGCSweepBegin, - go122.EvGCSweepEnd: (*ordering).advanceGCSweepEnd, - go122.EvGCMarkAssistActive: (*ordering).advanceGoRangeActive, - go122.EvGCMarkAssistBegin: (*ordering).advanceGoRangeBegin, - go122.EvGCMarkAssistEnd: (*ordering).advanceGoRangeEnd, - go122.EvHeapAlloc: (*ordering).advanceHeapMetric, - go122.EvHeapGoal: (*ordering).advanceHeapMetric, + tracev2.EvGCActive: (*ordering).advanceGCActive, + tracev2.EvGCBegin: (*ordering).advanceGCBegin, + tracev2.EvGCEnd: (*ordering).advanceGCEnd, + tracev2.EvGCSweepActive: (*ordering).advanceGCSweepActive, + tracev2.EvGCSweepBegin: (*ordering).advanceGCSweepBegin, + tracev2.EvGCSweepEnd: (*ordering).advanceGCSweepEnd, + tracev2.EvGCMarkAssistActive: (*ordering).advanceGoRangeActive, + tracev2.EvGCMarkAssistBegin: (*ordering).advanceGoRangeBegin, + tracev2.EvGCMarkAssistEnd: (*ordering).advanceGoRangeEnd, + tracev2.EvHeapAlloc: (*ordering).advanceHeapMetric, + tracev2.EvHeapGoal: (*ordering).advanceHeapMetric, // Annotations. - go122.EvGoLabel: (*ordering).advanceAnnotation, - go122.EvUserTaskBegin: (*ordering).advanceUserTaskBegin, - go122.EvUserTaskEnd: (*ordering).advanceUserTaskEnd, - go122.EvUserRegionBegin: (*ordering).advanceUserRegionBegin, - go122.EvUserRegionEnd: (*ordering).advanceUserRegionEnd, - go122.EvUserLog: (*ordering).advanceAnnotation, + tracev2.EvGoLabel: (*ordering).advanceAnnotation, + tracev2.EvUserTaskBegin: (*ordering).advanceUserTaskBegin, + tracev2.EvUserTaskEnd: (*ordering).advanceUserTaskEnd, + tracev2.EvUserRegionBegin: (*ordering).advanceUserRegionBegin, + tracev2.EvUserRegionEnd: (*ordering).advanceUserRegionEnd, + tracev2.EvUserLog: (*ordering).advanceAnnotation, // Coroutines. Added in Go 1.23. - go122.EvGoSwitch: (*ordering).advanceGoSwitch, - go122.EvGoSwitchDestroy: (*ordering).advanceGoSwitch, - go122.EvGoCreateBlocked: (*ordering).advanceGoCreate, + tracev2.EvGoSwitch: (*ordering).advanceGoSwitch, + tracev2.EvGoSwitchDestroy: (*ordering).advanceGoSwitch, + tracev2.EvGoCreateBlocked: (*ordering).advanceGoCreate, // GoStatus event with a stack. Added in Go 1.23. - go122.EvGoStatusStack: (*ordering).advanceGoStatus, + tracev2.EvGoStatusStack: (*ordering).advanceGoStatus, // Experimental events. // Experimental heap span events. Added in Go 1.23. - go122.EvSpan: (*ordering).advanceAllocFree, - go122.EvSpanAlloc: (*ordering).advanceAllocFree, - go122.EvSpanFree: (*ordering).advanceAllocFree, + tracev2.EvSpan: (*ordering).advanceAllocFree, + tracev2.EvSpanAlloc: (*ordering).advanceAllocFree, + tracev2.EvSpanFree: (*ordering).advanceAllocFree, // Experimental heap object events. Added in Go 1.23. - go122.EvHeapObject: (*ordering).advanceAllocFree, - go122.EvHeapObjectAlloc: (*ordering).advanceAllocFree, - go122.EvHeapObjectFree: (*ordering).advanceAllocFree, + tracev2.EvHeapObject: (*ordering).advanceAllocFree, + tracev2.EvHeapObjectAlloc: (*ordering).advanceAllocFree, + tracev2.EvHeapObjectFree: (*ordering).advanceAllocFree, // Experimental goroutine stack events. Added in Go 1.23. - go122.EvGoroutineStack: (*ordering).advanceAllocFree, - go122.EvGoroutineStackAlloc: (*ordering).advanceAllocFree, - go122.EvGoroutineStackFree: (*ordering).advanceAllocFree, + tracev2.EvGoroutineStack: (*ordering).advanceAllocFree, + tracev2.EvGoroutineStackAlloc: (*ordering).advanceAllocFree, + tracev2.EvGoroutineStackFree: (*ordering).advanceAllocFree, } func (o *ordering) advanceProcStatus(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) { pid := ProcID(ev.args[0]) - status := go122.ProcStatus(ev.args[1]) - if int(status) >= len(go122ProcStatus2ProcState) { + status := tracev2.ProcStatus(ev.args[1]) + if int(status) >= len(tracev2ProcStatus2ProcState) { return curCtx, false, fmt.Errorf("invalid status for proc %d: %d", pid, status) } - oldState := go122ProcStatus2ProcState[status] + oldState := tracev2ProcStatus2ProcState[status] if s, ok := o.pStates[pid]; ok { - if status == go122.ProcSyscallAbandoned && s.status == go122.ProcSyscall { + if status == tracev2.ProcSyscallAbandoned && s.status == tracev2.ProcSyscall { // ProcSyscallAbandoned is a special case of ProcSyscall. It indicates a // potential loss of information, but if we're already in ProcSyscall, // we haven't lost the relevant information. Promote the status and advance. oldState = ProcRunning - ev.args[1] = uint64(go122.ProcSyscall) - } else if status == go122.ProcSyscallAbandoned && s.status == go122.ProcSyscallAbandoned { + ev.args[1] = uint64(tracev2.ProcSyscall) + } else if status == tracev2.ProcSyscallAbandoned && s.status == tracev2.ProcSyscallAbandoned { // If we're passing through ProcSyscallAbandoned, then there's no promotion // to do. We've lost the M that this P is associated with. However it got there, // it's going to appear as idle in the API, so pass through as idle. oldState = ProcIdle - ev.args[1] = uint64(go122.ProcSyscallAbandoned) + ev.args[1] = uint64(tracev2.ProcSyscallAbandoned) } else if s.status != status { return curCtx, false, fmt.Errorf("inconsistent status for proc %d: old %v vs. new %v", pid, s.status, status) } @@ -199,7 +199,7 @@ func (o *ordering) advanceProcStatus(ev *baseEvent, evt *evTable, m ThreadID, ge // Bind the proc to the new context, if it's running. newCtx := curCtx - if status == go122.ProcRunning || status == go122.ProcSyscall { + if status == tracev2.ProcRunning || status == tracev2.ProcSyscall { newCtx.P = pid } // If we're advancing through ProcSyscallAbandoned *but* oldState is running then we've @@ -208,7 +208,7 @@ func (o *ordering) advanceProcStatus(ev *baseEvent, evt *evTable, m ThreadID, ge // thread it was bound to. Since this status is Running -> Running and Running is binding, // we need to make sure we emit it in the right context: the context to which it is bound. // Find it, and set our current context to it. - if status == go122.ProcSyscallAbandoned && oldState == ProcRunning { + if status == tracev2.ProcSyscallAbandoned && oldState == ProcRunning { // N.B. This is slow but it should be fairly rare. found := false for mid, ms := range o.mStates { @@ -235,7 +235,7 @@ func (o *ordering) advanceProcStart(ev *baseEvent, evt *evTable, m ThreadID, gen // had a status emitted, or because we already have a P and we're in a syscall, // and we haven't observed that it was stolen from us yet. state, ok := o.pStates[pid] - if !ok || state.status != go122.ProcIdle || !seq.succeeds(state.seq) || curCtx.P != NoProc { + if !ok || state.status != tracev2.ProcIdle || !seq.succeeds(state.seq) || curCtx.P != NoProc { // We can't make an inference as to whether this is bad. We could just be seeing // a ProcStart on a different M before the proc's state was emitted, or before we // got to the right point in the trace. @@ -250,7 +250,7 @@ func (o *ordering) advanceProcStart(ev *baseEvent, evt *evTable, m ThreadID, gen if err := validateCtx(curCtx, reqs); err != nil { return curCtx, false, err } - state.status = go122.ProcRunning + state.status = tracev2.ProcRunning state.seq = seq newCtx := curCtx newCtx.P = pid @@ -270,16 +270,16 @@ func (o *ordering) advanceProcStop(ev *baseEvent, evt *evTable, m ThreadID, gen // ProcStop doesn't need a sequence number. state, ok := o.pStates[curCtx.P] if !ok { - return curCtx, false, fmt.Errorf("event %s for proc (%v) that doesn't exist", go122.EventString(ev.typ), curCtx.P) + return curCtx, false, fmt.Errorf("event %s for proc (%v) that doesn't exist", tracev2.EventString(ev.typ), curCtx.P) } - if state.status != go122.ProcRunning && state.status != go122.ProcSyscall { - return curCtx, false, fmt.Errorf("%s event for proc that's not %s or %s", go122.EventString(ev.typ), go122.ProcRunning, go122.ProcSyscall) + if state.status != tracev2.ProcRunning && state.status != tracev2.ProcSyscall { + return curCtx, false, fmt.Errorf("%s event for proc that's not %s or %s", tracev2.EventString(ev.typ), tracev2.ProcRunning, tracev2.ProcSyscall) } reqs := schedReqs{M: mustHave, P: mustHave, G: mayHave} if err := validateCtx(curCtx, reqs); err != nil { return curCtx, false, err } - state.status = go122.ProcIdle + state.status = tracev2.ProcIdle newCtx := curCtx newCtx.P = NoProc o.queue.push(Event{table: evt, ctx: curCtx, base: *ev}) @@ -290,7 +290,7 @@ func (o *ordering) advanceProcSteal(ev *baseEvent, evt *evTable, m ThreadID, gen pid := ProcID(ev.args[0]) seq := makeSeq(gen, ev.args[1]) state, ok := o.pStates[pid] - if !ok || (state.status != go122.ProcSyscall && state.status != go122.ProcSyscallAbandoned) || !seq.succeeds(state.seq) { + if !ok || (state.status != tracev2.ProcSyscall && state.status != tracev2.ProcSyscallAbandoned) || !seq.succeeds(state.seq) { // We can't make an inference as to whether this is bad. We could just be seeing // a ProcStart on a different M before the proc's state was emitted, or before we // got to the right point in the trace. @@ -311,12 +311,12 @@ func (o *ordering) advanceProcSteal(ev *baseEvent, evt *evTable, m ThreadID, gen ev.extra(version.Go122)[0] = uint64(oldStatus) // Update the P's status and sequence number. - state.status = go122.ProcIdle + state.status = tracev2.ProcIdle state.seq = seq // If we've lost information then don't try to do anything with the M. // It may have moved on and we can't be sure. - if oldStatus == go122.ProcSyscallAbandoned { + if oldStatus == tracev2.ProcSyscallAbandoned { o.queue.push(Event{table: evt, ctx: curCtx, base: *ev}) return curCtx, true, nil } @@ -360,12 +360,12 @@ func (o *ordering) advanceProcSteal(ev *baseEvent, evt *evTable, m ThreadID, gen func (o *ordering) advanceGoStatus(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) { gid := GoID(ev.args[0]) mid := ThreadID(ev.args[1]) - status := go122.GoStatus(ev.args[2]) + status := tracev2.GoStatus(ev.args[2]) - if int(status) >= len(go122GoStatus2GoState) { + if int(status) >= len(tracev2GoStatus2GoState) { return curCtx, false, fmt.Errorf("invalid status for goroutine %d: %d", gid, status) } - oldState := go122GoStatus2GoState[status] + oldState := tracev2GoStatus2GoState[status] if s, ok := o.gStates[gid]; ok { if s.status != status { return curCtx, false, fmt.Errorf("inconsistent status for goroutine %d: old %v vs. new %v", gid, s.status, status) @@ -382,10 +382,10 @@ func (o *ordering) advanceGoStatus(ev *baseEvent, evt *evTable, m ThreadID, gen newCtx := curCtx switch status { - case go122.GoRunning: + case tracev2.GoRunning: // Bind the goroutine to the new context, since it's running. newCtx.G = gid - case go122.GoSyscall: + case tracev2.GoSyscall: if mid == NoThread { return curCtx, false, fmt.Errorf("found goroutine %d in syscall without a thread", gid) } @@ -442,17 +442,17 @@ func (o *ordering) advanceGoCreate(ev *baseEvent, evt *evTable, m ThreadID, gen return curCtx, false, err } // If we have a goroutine, it must be running. - if state, ok := o.gStates[curCtx.G]; ok && state.status != go122.GoRunning { - return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", go122.EventString(ev.typ), GoRunning) + if state, ok := o.gStates[curCtx.G]; ok && state.status != tracev2.GoRunning { + return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", tracev2.EventString(ev.typ), GoRunning) } // This goroutine created another. Add a state for it. newgid := GoID(ev.args[0]) if _, ok := o.gStates[newgid]; ok { return curCtx, false, fmt.Errorf("tried to create goroutine (%v) that already exists", newgid) } - status := go122.GoRunnable - if ev.typ == go122.EvGoCreateBlocked { - status = go122.GoWaiting + status := tracev2.GoRunnable + if ev.typ == tracev2.EvGoCreateBlocked { + status = tracev2.GoWaiting } o.gStates[newgid] = &gState{id: newgid, status: status, seq: makeSeq(gen, 0)} o.queue.push(Event{table: evt, ctx: curCtx, base: *ev}) @@ -468,26 +468,26 @@ func (o *ordering) advanceGoStopExec(ev *baseEvent, evt *evTable, m ThreadID, ge } state, ok := o.gStates[curCtx.G] if !ok { - return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", go122.EventString(ev.typ), curCtx.G) + return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", tracev2.EventString(ev.typ), curCtx.G) } - if state.status != go122.GoRunning { - return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", go122.EventString(ev.typ), GoRunning) + if state.status != tracev2.GoRunning { + return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", tracev2.EventString(ev.typ), GoRunning) } // Handle each case slightly differently; we just group them together // because they have shared preconditions. newCtx := curCtx switch ev.typ { - case go122.EvGoDestroy: + case tracev2.EvGoDestroy: // This goroutine is exiting itself. delete(o.gStates, curCtx.G) newCtx.G = NoGoroutine - case go122.EvGoStop: + case tracev2.EvGoStop: // Goroutine stopped (yielded). It's runnable but not running on this M. - state.status = go122.GoRunnable + state.status = tracev2.GoRunnable newCtx.G = NoGoroutine - case go122.EvGoBlock: + case tracev2.EvGoBlock: // Goroutine blocked. It's waiting now and not running on this M. - state.status = go122.GoWaiting + state.status = tracev2.GoWaiting newCtx.G = NoGoroutine } o.queue.push(Event{table: evt, ctx: curCtx, base: *ev}) @@ -498,7 +498,7 @@ func (o *ordering) advanceGoStart(ev *baseEvent, evt *evTable, m ThreadID, gen u gid := GoID(ev.args[0]) seq := makeSeq(gen, ev.args[1]) state, ok := o.gStates[gid] - if !ok || state.status != go122.GoRunnable || !seq.succeeds(state.seq) { + if !ok || state.status != tracev2.GoRunnable || !seq.succeeds(state.seq) { // We can't make an inference as to whether this is bad. We could just be seeing // a GoStart on a different M before the goroutine was created, before it had its // state emitted, or before we got to the right point in the trace yet. @@ -509,7 +509,7 @@ func (o *ordering) advanceGoStart(ev *baseEvent, evt *evTable, m ThreadID, gen u if err := validateCtx(curCtx, reqs); err != nil { return curCtx, false, err } - state.status = go122.GoRunning + state.status = tracev2.GoRunning state.seq = seq newCtx := curCtx newCtx.G = gid @@ -522,13 +522,13 @@ func (o *ordering) advanceGoUnblock(ev *baseEvent, evt *evTable, m ThreadID, gen gid := GoID(ev.args[0]) seq := makeSeq(gen, ev.args[1]) state, ok := o.gStates[gid] - if !ok || state.status != go122.GoWaiting || !seq.succeeds(state.seq) { + if !ok || state.status != tracev2.GoWaiting || !seq.succeeds(state.seq) { // We can't make an inference as to whether this is bad. We could just be seeing // a GoUnblock on a different M before the goroutine was created and blocked itself, // before it had its state emitted, or before we got to the right point in the trace yet. return curCtx, false, nil } - state.status = go122.GoRunnable + state.status = tracev2.GoRunnable state.seq = seq // N.B. No context to validate. Basically anything can unblock // a goroutine (e.g. sysmon). @@ -551,15 +551,15 @@ func (o *ordering) advanceGoSwitch(ev *baseEvent, evt *evTable, m ThreadID, gen } curGState, ok := o.gStates[curCtx.G] if !ok { - return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", go122.EventString(ev.typ), curCtx.G) + return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", tracev2.EventString(ev.typ), curCtx.G) } - if curGState.status != go122.GoRunning { - return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", go122.EventString(ev.typ), GoRunning) + if curGState.status != tracev2.GoRunning { + return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", tracev2.EventString(ev.typ), GoRunning) } nextg := GoID(ev.args[0]) seq := makeSeq(gen, ev.args[1]) // seq is for nextg, not curCtx.G. nextGState, ok := o.gStates[nextg] - if !ok || nextGState.status != go122.GoWaiting || !seq.succeeds(nextGState.seq) { + if !ok || nextGState.status != tracev2.GoWaiting || !seq.succeeds(nextGState.seq) { // We can't make an inference as to whether this is bad. We could just be seeing // a GoSwitch on a different M before the goroutine was created, before it had its // state emitted, or before we got to the right point in the trace yet. @@ -571,22 +571,22 @@ func (o *ordering) advanceGoSwitch(ev *baseEvent, evt *evTable, m ThreadID, gen // (GoSwitch and GoSwitchDestroy will be interpreted as GoUnblock events // for nextg). switch ev.typ { - case go122.EvGoSwitch: + case tracev2.EvGoSwitch: // Goroutine blocked. It's waiting now and not running on this M. - curGState.status = go122.GoWaiting + curGState.status = tracev2.GoWaiting // Emit a GoBlock event. // TODO(mknyszek): Emit a reason. - o.queue.push(makeEvent(evt, curCtx, go122.EvGoBlock, ev.time, 0 /* no reason */, 0 /* no stack */)) - case go122.EvGoSwitchDestroy: + o.queue.push(makeEvent(evt, curCtx, tracev2.EvGoBlock, ev.time, 0 /* no reason */, 0 /* no stack */)) + case tracev2.EvGoSwitchDestroy: // This goroutine is exiting itself. delete(o.gStates, curCtx.G) // Emit a GoDestroy event. - o.queue.push(makeEvent(evt, curCtx, go122.EvGoDestroy, ev.time)) + o.queue.push(makeEvent(evt, curCtx, tracev2.EvGoDestroy, ev.time)) } // Update the state of the next goroutine. - nextGState.status = go122.GoRunning + nextGState.status = tracev2.GoRunning nextGState.seq = seq newCtx := curCtx newCtx.G = nextg @@ -594,7 +594,7 @@ func (o *ordering) advanceGoSwitch(ev *baseEvent, evt *evTable, m ThreadID, gen // Queue an event for the next goroutine starting to run. startCtx := curCtx startCtx.G = NoGoroutine - o.queue.push(makeEvent(evt, startCtx, go122.EvGoStart, ev.time, uint64(nextg), ev.args[1])) + o.queue.push(makeEvent(evt, startCtx, tracev2.EvGoStart, ev.time, uint64(nextg), ev.args[1])) return newCtx, true, nil } @@ -606,18 +606,18 @@ func (o *ordering) advanceGoSyscallBegin(ev *baseEvent, evt *evTable, m ThreadID } state, ok := o.gStates[curCtx.G] if !ok { - return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", go122.EventString(ev.typ), curCtx.G) + return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", tracev2.EventString(ev.typ), curCtx.G) } - if state.status != go122.GoRunning { - return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", go122.EventString(ev.typ), GoRunning) + if state.status != tracev2.GoRunning { + return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", tracev2.EventString(ev.typ), GoRunning) } // Goroutine entered a syscall. It's still running on this P and M. - state.status = go122.GoSyscall + state.status = tracev2.GoSyscall pState, ok := o.pStates[curCtx.P] if !ok { - return curCtx, false, fmt.Errorf("uninitialized proc %d found during %s", curCtx.P, go122.EventString(ev.typ)) + return curCtx, false, fmt.Errorf("uninitialized proc %d found during %s", curCtx.P, tracev2.EventString(ev.typ)) } - pState.status = go122.ProcSyscall + pState.status = tracev2.ProcSyscall // Validate the P sequence number on the event and advance it. // // We have a P sequence number for what is supposed to be a goroutine event @@ -631,7 +631,7 @@ func (o *ordering) advanceGoSyscallBegin(ev *baseEvent, evt *evTable, m ThreadID // to back off and see if any other events will advance. This is a running P. pSeq := makeSeq(gen, ev.args[0]) if !pSeq.succeeds(pState.seq) { - return curCtx, false, fmt.Errorf("failed to advance %s: can't make sequence: %s -> %s", go122.EventString(ev.typ), pState.seq, pSeq) + return curCtx, false, fmt.Errorf("failed to advance %s: can't make sequence: %s -> %s", tracev2.EventString(ev.typ), pState.seq, pSeq) } pState.seq = pSeq o.queue.push(Event{table: evt, ctx: curCtx, base: *ev}) @@ -647,22 +647,22 @@ func (o *ordering) advanceGoSyscallEnd(ev *baseEvent, evt *evTable, m ThreadID, } state, ok := o.gStates[curCtx.G] if !ok { - return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", go122.EventString(ev.typ), curCtx.G) + return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", tracev2.EventString(ev.typ), curCtx.G) } - if state.status != go122.GoSyscall { - return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", go122.EventString(ev.typ), GoRunning) + if state.status != tracev2.GoSyscall { + return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", tracev2.EventString(ev.typ), GoRunning) } - state.status = go122.GoRunning + state.status = tracev2.GoRunning // Transfer the P back to running from syscall. pState, ok := o.pStates[curCtx.P] if !ok { - return curCtx, false, fmt.Errorf("uninitialized proc %d found during %s", curCtx.P, go122.EventString(ev.typ)) + return curCtx, false, fmt.Errorf("uninitialized proc %d found during %s", curCtx.P, tracev2.EventString(ev.typ)) } - if pState.status != go122.ProcSyscall { - return curCtx, false, fmt.Errorf("expected proc %d in state %v, but got %v instead", curCtx.P, go122.ProcSyscall, pState.status) + if pState.status != tracev2.ProcSyscall { + return curCtx, false, fmt.Errorf("expected proc %d in state %v, but got %v instead", curCtx.P, tracev2.ProcSyscall, pState.status) } - pState.status = go122.ProcRunning + pState.status = tracev2.ProcRunning o.queue.push(Event{table: evt, ctx: curCtx, base: *ev}) return curCtx, true, nil } @@ -681,9 +681,9 @@ func (o *ordering) advanceGoSyscallEndBlocked(ev *baseEvent, evt *evTable, m Thr if curCtx.P != NoProc { pState, ok := o.pStates[curCtx.P] if !ok { - return curCtx, false, fmt.Errorf("uninitialized proc %d found during %s", curCtx.P, go122.EventString(ev.typ)) + return curCtx, false, fmt.Errorf("uninitialized proc %d found during %s", curCtx.P, tracev2.EventString(ev.typ)) } - if pState.status == go122.ProcSyscall { + if pState.status == tracev2.ProcSyscall { return curCtx, false, nil } } @@ -694,14 +694,14 @@ func (o *ordering) advanceGoSyscallEndBlocked(ev *baseEvent, evt *evTable, m Thr } state, ok := o.gStates[curCtx.G] if !ok { - return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", go122.EventString(ev.typ), curCtx.G) + return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", tracev2.EventString(ev.typ), curCtx.G) } - if state.status != go122.GoSyscall { - return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", go122.EventString(ev.typ), GoRunning) + if state.status != tracev2.GoSyscall { + return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", tracev2.EventString(ev.typ), GoRunning) } newCtx := curCtx newCtx.G = NoGoroutine - state.status = go122.GoRunnable + state.status = tracev2.GoRunnable o.queue.push(Event{table: evt, ctx: curCtx, base: *ev}) return newCtx, true, nil } @@ -718,7 +718,7 @@ func (o *ordering) advanceGoCreateSyscall(ev *baseEvent, evt *evTable, m ThreadI if _, ok := o.gStates[newgid]; ok { return curCtx, false, fmt.Errorf("tried to create goroutine (%v) in syscall that already exists", newgid) } - o.gStates[newgid] = &gState{id: newgid, status: go122.GoSyscall, seq: makeSeq(gen, 0)} + o.gStates[newgid] = &gState{id: newgid, status: tracev2.GoSyscall, seq: makeSeq(gen, 0)} // Goroutine is executing. Bind it to the context. newCtx := curCtx newCtx.G = newgid @@ -749,10 +749,10 @@ func (o *ordering) advanceGoDestroySyscall(ev *baseEvent, evt *evTable, m Thread // Check to make sure the goroutine exists in the right state. state, ok := o.gStates[curCtx.G] if !ok { - return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", go122.EventString(ev.typ), curCtx.G) + return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", tracev2.EventString(ev.typ), curCtx.G) } - if state.status != go122.GoSyscall { - return curCtx, false, fmt.Errorf("%s event for goroutine that's not %v", go122.EventString(ev.typ), GoSyscall) + if state.status != tracev2.GoSyscall { + return curCtx, false, fmt.Errorf("%s event for goroutine that's not %v", tracev2.EventString(ev.typ), GoSyscall) } // This goroutine is exiting itself. delete(o.gStates, curCtx.G) @@ -763,18 +763,18 @@ func (o *ordering) advanceGoDestroySyscall(ev *baseEvent, evt *evTable, m Thread if curCtx.P != NoProc { pState, ok := o.pStates[curCtx.P] if !ok { - return curCtx, false, fmt.Errorf("found invalid proc %d during %s", curCtx.P, go122.EventString(ev.typ)) + return curCtx, false, fmt.Errorf("found invalid proc %d during %s", curCtx.P, tracev2.EventString(ev.typ)) } - if pState.status != go122.ProcSyscall { - return curCtx, false, fmt.Errorf("proc %d in unexpected state %s during %s", curCtx.P, pState.status, go122.EventString(ev.typ)) + if pState.status != tracev2.ProcSyscall { + return curCtx, false, fmt.Errorf("proc %d in unexpected state %s during %s", curCtx.P, pState.status, tracev2.EventString(ev.typ)) } // See the go122-create-syscall-reuse-thread-id test case for more details. - pState.status = go122.ProcSyscallAbandoned + pState.status = tracev2.ProcSyscallAbandoned newCtx.P = NoProc // Queue an extra self-ProcSteal event. - extra := makeEvent(evt, curCtx, go122.EvProcSteal, ev.time, uint64(curCtx.P)) - extra.base.extra(version.Go122)[0] = uint64(go122.ProcSyscall) + extra := makeEvent(evt, curCtx, tracev2.EvProcSteal, ev.time, uint64(curCtx.P)) + extra.base.extra(version.Go122)[0] = uint64(tracev2.ProcSyscall) o.queue.push(extra) } o.queue.push(Event{table: evt, ctx: curCtx, base: *ev}) @@ -1025,7 +1025,7 @@ func (o *ordering) advanceGoRangeBegin(ev *baseEvent, evt *evTable, m ThreadID, return curCtx, false, err } desc := stringID(0) - if ev.typ == go122.EvSTWBegin { + if ev.typ == tracev2.EvSTWBegin { desc = stringID(ev.args[0]) } gState, ok := o.gStates[curCtx.G] @@ -1046,7 +1046,7 @@ func (o *ordering) advanceGoRangeActive(ev *baseEvent, evt *evTable, m ThreadID, // current scheduler context. gState, ok := o.gStates[gid] if !ok { - return curCtx, false, fmt.Errorf("uninitialized goroutine %d found during %s", gid, go122.EventString(ev.typ)) + return curCtx, false, fmt.Errorf("uninitialized goroutine %d found during %s", gid, tracev2.EventString(ev.typ)) } if err := gState.activeRange(makeRangeType(ev.typ, 0), gen == o.initialGen); err != nil { return curCtx, false, err @@ -1067,7 +1067,7 @@ func (o *ordering) advanceGoRangeEnd(ev *baseEvent, evt *evTable, m ThreadID, ge if err != nil { return curCtx, false, err } - if ev.typ == go122.EvSTWEnd { + if ev.typ == tracev2.EvSTWEnd { // Smuggle the kind into the event. // Don't use ev.extra here so we have symmetry with STWBegin. ev.args[0] = uint64(desc) @@ -1168,7 +1168,7 @@ type rangeType struct { // makeRangeType constructs a new rangeType. func makeRangeType(typ event.Type, desc stringID) rangeType { - if styp := go122.Specs()[typ].StartEv; styp != go122.EvNone { + if styp := tracev2.Specs()[typ].StartEv; styp != tracev2.EvNone { typ = styp } return rangeType{typ, desc} @@ -1177,7 +1177,7 @@ func makeRangeType(typ event.Type, desc stringID) rangeType { // gState is the state of a goroutine at a point in the trace. type gState struct { id GoID - status go122.GoStatus + status tracev2.GoStatus seq seqCounter // regions are the active user regions for this goroutine. @@ -1209,7 +1209,7 @@ func (s *gState) endRegion(r userRegion) error { // pState is the state of a proc at a point in the trace. type pState struct { id ProcID - status go122.ProcStatus + status tracev2.ProcStatus seq seqCounter // rangeState is the state of special time ranges bound to this proc. @@ -1233,7 +1233,7 @@ type rangeState struct { // Returns an error if the range is already in progress. func (s *rangeState) beginRange(typ rangeType) error { if s.hasRange(typ) { - return fmt.Errorf("discovered event already in-flight for when starting event %v", go122.Specs()[typ.typ].Name) + return fmt.Errorf("discovered event already in-flight for when starting event %v", tracev2.Specs()[typ.typ].Name) } s.inFlight = append(s.inFlight, typ) return nil @@ -1248,7 +1248,7 @@ func (s *rangeState) activeRange(typ rangeType, isInitialGen bool) error { } s.inFlight = append(s.inFlight, typ) } else if !s.hasRange(typ) { - return fmt.Errorf("resource is missing active range: %v %v", go122.Specs()[typ.typ].Name, s.inFlight) + return fmt.Errorf("resource is missing active range: %v %v", tracev2.Specs()[typ.typ].Name, s.inFlight) } return nil } @@ -1262,7 +1262,7 @@ func (s *rangeState) hasRange(typ rangeType) bool { // // This must line up with the start event type of the range the goroutine is currently in. func (s *rangeState) endRange(typ event.Type) (stringID, error) { - st := go122.Specs()[typ].StartEv + st := tracev2.Specs()[typ].StartEv idx := -1 for i, r := range s.inFlight { if r.typ == st { @@ -1271,7 +1271,7 @@ func (s *rangeState) endRange(typ event.Type) (stringID, error) { } } if idx < 0 { - return 0, fmt.Errorf("tried to end event %v, but not in-flight", go122.Specs()[st].Name) + return 0, fmt.Errorf("tried to end event %v, but not in-flight", tracev2.Specs()[st].Name) } // Swap remove. desc := s.inFlight[idx].desc diff --git a/src/internal/trace/raw/event.go b/src/internal/trace/raw/event.go index e163a2c6ef820b..e3b6b5cd458f7c 100644 --- a/src/internal/trace/raw/event.go +++ b/src/internal/trace/raw/event.go @@ -9,7 +9,7 @@ import ( "strconv" "strings" - "internal/trace/event" + "internal/trace/tracev2/event" "internal/trace/version" ) diff --git a/src/internal/trace/raw/reader.go b/src/internal/trace/raw/reader.go index 37f36a1a24b712..3f90e2d454725d 100644 --- a/src/internal/trace/raw/reader.go +++ b/src/internal/trace/raw/reader.go @@ -10,7 +10,7 @@ import ( "fmt" "io" - "internal/trace/event" + "internal/trace/tracev2/event" "internal/trace/version" ) diff --git a/src/internal/trace/raw/textreader.go b/src/internal/trace/raw/textreader.go index 37bfcfefdf62f7..666db134f1a9d1 100644 --- a/src/internal/trace/raw/textreader.go +++ b/src/internal/trace/raw/textreader.go @@ -12,7 +12,7 @@ import ( "strings" "unicode" - "internal/trace/event" + "internal/trace/tracev2/event" "internal/trace/version" ) diff --git a/src/internal/trace/raw/writer.go b/src/internal/trace/raw/writer.go index 9b87995aa77738..971839b8d71fc3 100644 --- a/src/internal/trace/raw/writer.go +++ b/src/internal/trace/raw/writer.go @@ -9,7 +9,7 @@ import ( "fmt" "io" - "internal/trace/event" + "internal/trace/tracev2/event" "internal/trace/version" ) diff --git a/src/internal/trace/reader.go b/src/internal/trace/reader.go index 6fc39e28acdfb0..699febeed4b327 100644 --- a/src/internal/trace/reader.go +++ b/src/internal/trace/reader.go @@ -11,8 +11,8 @@ import ( "slices" "strings" - "internal/trace/event/go122" "internal/trace/internal/tracev1" + "internal/trace/tracev2" "internal/trace/version" ) @@ -248,7 +248,7 @@ func (r *Reader) ReadEvent() (e Event, err error) { func dumpFrontier(frontier []*batchCursor) string { var sb strings.Builder for _, bc := range frontier { - spec := go122.Specs()[bc.ev.typ] + spec := tracev2.Specs()[bc.ev.typ] fmt.Fprintf(&sb, "M %d [%s time=%d", bc.m, spec.Name, bc.ev.time) for i, arg := range spec.Args[1:] { fmt.Fprintf(&sb, " %s=%d", arg, bc.ev.args[i]) diff --git a/src/internal/trace/summary_test.go b/src/internal/trace/summary_test.go index 73865652ebac44..396bd5f0969f06 100644 --- a/src/internal/trace/summary_test.go +++ b/src/internal/trace/summary_test.go @@ -416,10 +416,10 @@ func TestRelatedGoroutinesV2Trace(t *testing.T) { targetg := trace.GoID(86) got := trace.RelatedGoroutinesV2(events, targetg) want := map[trace.GoID]struct{}{ - trace.GoID(86): struct{}{}, // N.B. Result includes target. - trace.GoID(71): struct{}{}, - trace.GoID(25): struct{}{}, - trace.GoID(122): struct{}{}, + trace.GoID(86): {}, // N.B. Result includes target. + trace.GoID(71): {}, + trace.GoID(25): {}, + trace.GoID(122): {}, } for goid := range got { if _, ok := want[goid]; ok { diff --git a/src/internal/trace/testdata/generators/go122-confuse-seq-across-generations.go b/src/internal/trace/testdata/generators/go122-confuse-seq-across-generations.go index 9f27ae046ff49c..30f859779011d6 100644 --- a/src/internal/trace/testdata/generators/go122-confuse-seq-across-generations.go +++ b/src/internal/trace/testdata/generators/go122-confuse-seq-across-generations.go @@ -23,8 +23,8 @@ package main import ( "internal/trace" - "internal/trace/event/go122" - testgen "internal/trace/internal/testgen/go122" + "internal/trace/internal/testgen" + "internal/trace/tracev2" ) func main() { @@ -36,13 +36,13 @@ func gen(t *testgen.Trace) { // A running goroutine blocks. b10 := g1.Batch(trace.ThreadID(0), 0) - b10.Event("ProcStatus", trace.ProcID(0), go122.ProcRunning) - b10.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), go122.GoRunning) + b10.Event("ProcStatus", trace.ProcID(0), tracev2.ProcRunning) + b10.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), tracev2.GoRunning) b10.Event("GoStop", "whatever", testgen.NoStack) // The running goroutine gets unblocked. b11 := g1.Batch(trace.ThreadID(1), 0) - b11.Event("ProcStatus", trace.ProcID(1), go122.ProcRunning) + b11.Event("ProcStatus", trace.ProcID(1), tracev2.ProcRunning) b11.Event("GoStart", trace.GoID(1), testgen.Seq(1)) b11.Event("GoStop", "whatever", testgen.NoStack) @@ -50,13 +50,13 @@ func gen(t *testgen.Trace) { // Start running the goroutine, but later. b21 := g2.Batch(trace.ThreadID(1), 3) - b21.Event("ProcStatus", trace.ProcID(1), go122.ProcRunning) + b21.Event("ProcStatus", trace.ProcID(1), tracev2.ProcRunning) b21.Event("GoStart", trace.GoID(1), testgen.Seq(2)) // The goroutine starts running, then stops, then starts again. b20 := g2.Batch(trace.ThreadID(0), 5) - b20.Event("ProcStatus", trace.ProcID(0), go122.ProcRunning) - b20.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), go122.GoRunnable) + b20.Event("ProcStatus", trace.ProcID(0), tracev2.ProcRunning) + b20.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), tracev2.GoRunnable) b20.Event("GoStart", trace.GoID(1), testgen.Seq(1)) b20.Event("GoStop", "whatever", testgen.NoStack) } diff --git a/src/internal/trace/testdata/generators/go122-create-syscall-reuse-thread-id.go b/src/internal/trace/testdata/generators/go122-create-syscall-reuse-thread-id.go index e5081598325c06..cdb53785b09ef1 100644 --- a/src/internal/trace/testdata/generators/go122-create-syscall-reuse-thread-id.go +++ b/src/internal/trace/testdata/generators/go122-create-syscall-reuse-thread-id.go @@ -25,8 +25,8 @@ package main import ( "internal/trace" - "internal/trace/event/go122" - testgen "internal/trace/internal/testgen/go122" + "internal/trace/internal/testgen" + "internal/trace/tracev2" ) func main() { @@ -41,9 +41,9 @@ func gen(t *testgen.Trace) { b0 := g.Batch(trace.ThreadID(0), 0) b0.Event("GoCreateSyscall", trace.GoID(4)) b0.Event("GoSyscallEndBlocked") - b0.Event("ProcStatus", trace.ProcID(0), go122.ProcIdle) + b0.Event("ProcStatus", trace.ProcID(0), tracev2.ProcIdle) b0.Event("ProcStart", trace.ProcID(0), testgen.Seq(1)) - b0.Event("GoStatus", trace.GoID(4), trace.NoThread, go122.GoRunnable) + b0.Event("GoStatus", trace.GoID(4), trace.NoThread, tracev2.GoRunnable) b0.Event("GoStart", trace.GoID(4), testgen.Seq(1)) b0.Event("GoSyscallBegin", testgen.Seq(2), testgen.NoStack) b0.Event("GoDestroySyscall") @@ -55,7 +55,7 @@ func gen(t *testgen.Trace) { // have a self-steal here potentially that doesn't make // sense. b1 := g.Batch(trace.ThreadID(0), 0) - b1.Event("ProcStatus", trace.ProcID(1), go122.ProcIdle) + b1.Event("ProcStatus", trace.ProcID(1), tracev2.ProcIdle) b1.Event("ProcStart", trace.ProcID(1), testgen.Seq(1)) b1.Event("ProcSteal", trace.ProcID(0), testgen.Seq(3), trace.ThreadID(0)) } diff --git a/src/internal/trace/testdata/generators/go122-create-syscall-with-p.go b/src/internal/trace/testdata/generators/go122-create-syscall-with-p.go index 681464ce19d2f5..ba74144e92a01c 100644 --- a/src/internal/trace/testdata/generators/go122-create-syscall-with-p.go +++ b/src/internal/trace/testdata/generators/go122-create-syscall-with-p.go @@ -16,8 +16,8 @@ package main import ( "internal/trace" - "internal/trace/event/go122" - testgen "internal/trace/internal/testgen/go122" + "internal/trace/internal/testgen" + "internal/trace/tracev2" ) func main() { @@ -39,7 +39,7 @@ func gen(t *testgen.Trace) { // possible on other platforms, however. b0 := g.Batch(trace.ThreadID(0), 0) b0.Event("GoCreateSyscall", trace.GoID(4)) - b0.Event("ProcStatus", trace.ProcID(0), go122.ProcIdle) + b0.Event("ProcStatus", trace.ProcID(0), tracev2.ProcIdle) b0.Event("ProcStart", trace.ProcID(0), testgen.Seq(1)) b0.Event("GoSyscallEndBlocked") b0.Event("GoStart", trace.GoID(4), testgen.Seq(1)) diff --git a/src/internal/trace/testdata/generators/go122-fail-first-gen-first.go b/src/internal/trace/testdata/generators/go122-fail-first-gen-first.go index f0e02be15560d2..ab396fcd4af33d 100644 --- a/src/internal/trace/testdata/generators/go122-fail-first-gen-first.go +++ b/src/internal/trace/testdata/generators/go122-fail-first-gen-first.go @@ -19,8 +19,8 @@ package main import ( - "internal/trace/event/go122" - testgen "internal/trace/internal/testgen/go122" + "internal/trace/internal/testgen" + "internal/trace/tracev2" ) func main() { @@ -29,15 +29,15 @@ func main() { func gen(t *testgen.Trace) { // A running goroutine emits a task begin. - t.RawEvent(go122.EvEventBatch, nil, 1 /*gen*/, 0 /*thread ID*/, 0 /*timestamp*/, 5 /*batch length*/) - t.RawEvent(go122.EvFrequency, nil, 15625000) + t.RawEvent(tracev2.EvEventBatch, nil, 1 /*gen*/, 0 /*thread ID*/, 0 /*timestamp*/, 5 /*batch length*/) + t.RawEvent(tracev2.EvFrequency, nil, 15625000) // A running goroutine emits a task begin. - t.RawEvent(go122.EvEventBatch, nil, 1 /*gen*/, 0 /*thread ID*/, 0 /*timestamp*/, 5 /*batch length*/) - t.RawEvent(go122.EvGoCreate, nil, 0 /*timestamp delta*/, 1 /*go ID*/, 0, 0) + t.RawEvent(tracev2.EvEventBatch, nil, 1 /*gen*/, 0 /*thread ID*/, 0 /*timestamp*/, 5 /*batch length*/) + t.RawEvent(tracev2.EvGoCreate, nil, 0 /*timestamp delta*/, 1 /*go ID*/, 0, 0) // Write an invalid batch event for the next generation. - t.RawEvent(go122.EvEventBatch, nil, 2 /*gen*/, 0 /*thread ID*/, 0 /*timestamp*/, 50 /*batch length (invalid)*/) + t.RawEvent(tracev2.EvEventBatch, nil, 2 /*gen*/, 0 /*thread ID*/, 0 /*timestamp*/, 50 /*batch length (invalid)*/) // We should fail at the first issue, not the second one. t.ExpectFailure("expected a proc but didn't have one") diff --git a/src/internal/trace/testdata/generators/go122-go-create-without-running-g.go b/src/internal/trace/testdata/generators/go122-go-create-without-running-g.go index 217089975861fd..3ce4f0243d0672 100644 --- a/src/internal/trace/testdata/generators/go122-go-create-without-running-g.go +++ b/src/internal/trace/testdata/generators/go122-go-create-without-running-g.go @@ -13,8 +13,8 @@ package main import ( "internal/trace" - "internal/trace/event/go122" - testgen "internal/trace/internal/testgen/go122" + "internal/trace/internal/testgen" + "internal/trace/tracev2" ) func main() { @@ -26,7 +26,7 @@ func gen(t *testgen.Trace) { // A goroutine gets created on a running P, then starts running. b0 := g1.Batch(trace.ThreadID(0), 0) - b0.Event("ProcStatus", trace.ProcID(0), go122.ProcRunning) + b0.Event("ProcStatus", trace.ProcID(0), tracev2.ProcRunning) b0.Event("GoCreate", trace.GoID(5), testgen.NoStack, testgen.NoStack) b0.Event("GoStart", trace.GoID(5), testgen.Seq(1)) b0.Event("GoStop", "whatever", testgen.NoStack) diff --git a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-ambiguous.go b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-ambiguous.go index 4e7296983309b8..57d2a1a126bc27 100644 --- a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-ambiguous.go +++ b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-ambiguous.go @@ -15,8 +15,8 @@ package main import ( "internal/trace" - "internal/trace/event/go122" - testgen "internal/trace/internal/testgen/go122" + "internal/trace/internal/testgen" + "internal/trace/tracev2" ) func main() { @@ -31,8 +31,8 @@ func gen(t *testgen.Trace) { // One goroutine does a syscall without blocking, then another one where // it's P gets stolen. b0 := g.Batch(trace.ThreadID(0), 0) - b0.Event("ProcStatus", trace.ProcID(0), go122.ProcRunning) - b0.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), go122.GoRunning) + b0.Event("ProcStatus", trace.ProcID(0), tracev2.ProcRunning) + b0.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), tracev2.GoRunning) b0.Event("GoSyscallBegin", testgen.Seq(1), testgen.NoStack) b0.Event("GoSyscallEnd") b0.Event("GoSyscallBegin", testgen.Seq(2), testgen.NoStack) @@ -40,7 +40,7 @@ func gen(t *testgen.Trace) { // A running goroutine steals proc 0. b1 := g.Batch(trace.ThreadID(1), 0) - b1.Event("ProcStatus", trace.ProcID(2), go122.ProcRunning) - b1.Event("GoStatus", trace.GoID(2), trace.ThreadID(1), go122.GoRunning) + b1.Event("ProcStatus", trace.ProcID(2), tracev2.ProcRunning) + b1.Event("GoStatus", trace.GoID(2), trace.ThreadID(1), tracev2.GoRunning) b1.Event("ProcSteal", trace.ProcID(0), testgen.Seq(3), trace.ThreadID(0)) } diff --git a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary-bare-m.go b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary-bare-m.go index 1d7fe9c57c55d8..e4f97ba5304464 100644 --- a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary-bare-m.go +++ b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary-bare-m.go @@ -8,8 +8,8 @@ package main import ( "internal/trace" - "internal/trace/event/go122" - testgen "internal/trace/internal/testgen/go122" + "internal/trace/internal/testgen" + "internal/trace/tracev2" ) func main() { @@ -22,12 +22,12 @@ func gen(t *testgen.Trace) { // One goroutine is exiting with a syscall. It already // acquired a new P. b0 := g.Batch(trace.ThreadID(0), 0) - b0.Event("ProcStatus", trace.ProcID(1), go122.ProcRunning) - b0.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), go122.GoSyscall) + b0.Event("ProcStatus", trace.ProcID(1), tracev2.ProcRunning) + b0.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), tracev2.GoSyscall) b0.Event("GoSyscallEndBlocked") // A bare M stole the goroutine's P at the generation boundary. b1 := g.Batch(trace.ThreadID(1), 0) - b1.Event("ProcStatus", trace.ProcID(0), go122.ProcSyscallAbandoned) + b1.Event("ProcStatus", trace.ProcID(0), tracev2.ProcSyscallAbandoned) b1.Event("ProcSteal", trace.ProcID(0), testgen.Seq(1), trace.ThreadID(0)) } diff --git a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary-reacquire-new-proc-bare-m.go b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary-reacquire-new-proc-bare-m.go index a94b8f058d5922..fc8549814f1cbe 100644 --- a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary-reacquire-new-proc-bare-m.go +++ b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary-reacquire-new-proc-bare-m.go @@ -8,8 +8,8 @@ package main import ( "internal/trace" - "internal/trace/event/go122" - testgen "internal/trace/internal/testgen/go122" + "internal/trace/internal/testgen" + "internal/trace/tracev2" ) func main() { @@ -22,13 +22,13 @@ func gen(t *testgen.Trace) { // One goroutine is exiting with a syscall. It already // acquired a new P. b0 := g.Batch(trace.ThreadID(0), 0) - b0.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), go122.GoSyscall) - b0.Event("ProcStatus", trace.ProcID(1), go122.ProcIdle) + b0.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), tracev2.GoSyscall) + b0.Event("ProcStatus", trace.ProcID(1), tracev2.ProcIdle) b0.Event("ProcStart", trace.ProcID(1), testgen.Seq(1)) b0.Event("GoSyscallEndBlocked") // A bare M stole the goroutine's P at the generation boundary. b1 := g.Batch(trace.ThreadID(1), 0) - b1.Event("ProcStatus", trace.ProcID(0), go122.ProcSyscallAbandoned) + b1.Event("ProcStatus", trace.ProcID(0), tracev2.ProcSyscallAbandoned) b1.Event("ProcSteal", trace.ProcID(0), testgen.Seq(1), trace.ThreadID(0)) } diff --git a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary-reacquire-new-proc.go b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary-reacquire-new-proc.go index 04aef0644cdffb..6a4f8bd1e31ff1 100644 --- a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary-reacquire-new-proc.go +++ b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary-reacquire-new-proc.go @@ -8,8 +8,8 @@ package main import ( "internal/trace" - "internal/trace/event/go122" - testgen "internal/trace/internal/testgen/go122" + "internal/trace/internal/testgen" + "internal/trace/tracev2" ) func main() { @@ -22,15 +22,15 @@ func gen(t *testgen.Trace) { // One goroutine is exiting with a syscall. It already // acquired a new P. b0 := g.Batch(trace.ThreadID(0), 0) - b0.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), go122.GoSyscall) - b0.Event("ProcStatus", trace.ProcID(1), go122.ProcIdle) + b0.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), tracev2.GoSyscall) + b0.Event("ProcStatus", trace.ProcID(1), tracev2.ProcIdle) b0.Event("ProcStart", trace.ProcID(1), testgen.Seq(1)) b0.Event("GoSyscallEndBlocked") // A running goroutine stole P0 at the generation boundary. b1 := g.Batch(trace.ThreadID(1), 0) - b1.Event("ProcStatus", trace.ProcID(2), go122.ProcRunning) - b1.Event("GoStatus", trace.GoID(2), trace.ThreadID(1), go122.GoRunning) - b1.Event("ProcStatus", trace.ProcID(0), go122.ProcSyscallAbandoned) + b1.Event("ProcStatus", trace.ProcID(2), tracev2.ProcRunning) + b1.Event("GoStatus", trace.GoID(2), trace.ThreadID(1), tracev2.GoRunning) + b1.Event("ProcStatus", trace.ProcID(0), tracev2.ProcSyscallAbandoned) b1.Event("ProcSteal", trace.ProcID(0), testgen.Seq(1), trace.ThreadID(0)) } diff --git a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary.go b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary.go index 769203ab4ae9dc..0660996f3f67d3 100644 --- a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary.go +++ b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary.go @@ -8,8 +8,8 @@ package main import ( "internal/trace" - "internal/trace/event/go122" - testgen "internal/trace/internal/testgen/go122" + "internal/trace/internal/testgen" + "internal/trace/tracev2" ) func main() { @@ -22,14 +22,14 @@ func gen(t *testgen.Trace) { // One goroutine is exiting with a syscall. It already // acquired a new P. b0 := g.Batch(trace.ThreadID(0), 0) - b0.Event("ProcStatus", trace.ProcID(1), go122.ProcRunning) - b0.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), go122.GoSyscall) + b0.Event("ProcStatus", trace.ProcID(1), tracev2.ProcRunning) + b0.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), tracev2.GoSyscall) b0.Event("GoSyscallEndBlocked") // A running goroutine stole P0 at the generation boundary. b1 := g.Batch(trace.ThreadID(1), 0) - b1.Event("ProcStatus", trace.ProcID(2), go122.ProcRunning) - b1.Event("GoStatus", trace.GoID(2), trace.ThreadID(1), go122.GoRunning) - b1.Event("ProcStatus", trace.ProcID(0), go122.ProcSyscallAbandoned) + b1.Event("ProcStatus", trace.ProcID(2), tracev2.ProcRunning) + b1.Event("GoStatus", trace.GoID(2), trace.ThreadID(1), tracev2.GoRunning) + b1.Event("ProcStatus", trace.ProcID(0), tracev2.ProcSyscallAbandoned) b1.Event("ProcSteal", trace.ProcID(0), testgen.Seq(1), trace.ThreadID(0)) } diff --git a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-reacquire-new-proc-bare-m.go b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-reacquire-new-proc-bare-m.go index c1c39569f8e7f7..4a286b5eeab227 100644 --- a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-reacquire-new-proc-bare-m.go +++ b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-reacquire-new-proc-bare-m.go @@ -8,8 +8,8 @@ package main import ( "internal/trace" - "internal/trace/event/go122" - testgen "internal/trace/internal/testgen/go122" + "internal/trace/internal/testgen" + "internal/trace/tracev2" ) func main() { @@ -21,9 +21,9 @@ func gen(t *testgen.Trace) { // One goroutine enters a syscall, grabs a P, and starts running. b0 := g.Batch(trace.ThreadID(0), 0) - b0.Event("ProcStatus", trace.ProcID(1), go122.ProcIdle) - b0.Event("ProcStatus", trace.ProcID(0), go122.ProcRunning) - b0.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), go122.GoRunning) + b0.Event("ProcStatus", trace.ProcID(1), tracev2.ProcIdle) + b0.Event("ProcStatus", trace.ProcID(0), tracev2.ProcRunning) + b0.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), tracev2.GoRunning) b0.Event("GoSyscallBegin", testgen.Seq(1), testgen.NoStack) b0.Event("ProcStart", trace.ProcID(1), testgen.Seq(1)) b0.Event("GoSyscallEndBlocked") diff --git a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-reacquire-new-proc.go b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-reacquire-new-proc.go index 217e4e6f962045..98ab35bad60107 100644 --- a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-reacquire-new-proc.go +++ b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-reacquire-new-proc.go @@ -8,8 +8,8 @@ package main import ( "internal/trace" - "internal/trace/event/go122" - testgen "internal/trace/internal/testgen/go122" + "internal/trace/internal/testgen" + "internal/trace/tracev2" ) func main() { @@ -21,16 +21,16 @@ func gen(t *testgen.Trace) { // One goroutine enters a syscall, grabs a P, and starts running. b0 := g.Batch(trace.ThreadID(0), 0) - b0.Event("ProcStatus", trace.ProcID(1), go122.ProcIdle) - b0.Event("ProcStatus", trace.ProcID(0), go122.ProcRunning) - b0.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), go122.GoRunning) + b0.Event("ProcStatus", trace.ProcID(1), tracev2.ProcIdle) + b0.Event("ProcStatus", trace.ProcID(0), tracev2.ProcRunning) + b0.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), tracev2.GoRunning) b0.Event("GoSyscallBegin", testgen.Seq(1), testgen.NoStack) b0.Event("ProcStart", trace.ProcID(1), testgen.Seq(1)) b0.Event("GoSyscallEndBlocked") // A running goroutine steals proc 0. b1 := g.Batch(trace.ThreadID(1), 0) - b1.Event("ProcStatus", trace.ProcID(2), go122.ProcRunning) - b1.Event("GoStatus", trace.GoID(2), trace.ThreadID(1), go122.GoRunning) + b1.Event("ProcStatus", trace.ProcID(2), tracev2.ProcRunning) + b1.Event("GoStatus", trace.GoID(2), trace.ThreadID(1), tracev2.GoRunning) b1.Event("ProcSteal", trace.ProcID(0), testgen.Seq(2), trace.ThreadID(0)) } diff --git a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-self.go b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-self.go index a12f47177fb988..2c5aac39d693b4 100644 --- a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-self.go +++ b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-self.go @@ -12,8 +12,8 @@ package main import ( "internal/trace" - "internal/trace/event/go122" - testgen "internal/trace/internal/testgen/go122" + "internal/trace/internal/testgen" + "internal/trace/tracev2" ) func main() { @@ -28,8 +28,8 @@ func gen(t *testgen.Trace) { // A goroutine execute a syscall and steals its own P, then starts running // on that P. b0 := g.Batch(trace.ThreadID(0), 0) - b0.Event("ProcStatus", trace.ProcID(0), go122.ProcRunning) - b0.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), go122.GoRunning) + b0.Event("ProcStatus", trace.ProcID(0), tracev2.ProcRunning) + b0.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), tracev2.GoRunning) b0.Event("GoSyscallBegin", testgen.Seq(1), testgen.NoStack) b0.Event("ProcSteal", trace.ProcID(0), testgen.Seq(2), trace.ThreadID(0)) b0.Event("ProcStart", trace.ProcID(0), testgen.Seq(3)) diff --git a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-simple-bare-m.go b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-simple-bare-m.go index 34c7415cae613f..91dfa3774022e3 100644 --- a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-simple-bare-m.go +++ b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-simple-bare-m.go @@ -8,8 +8,8 @@ package main import ( "internal/trace" - "internal/trace/event/go122" - testgen "internal/trace/internal/testgen/go122" + "internal/trace/internal/testgen" + "internal/trace/tracev2" ) func main() { @@ -21,8 +21,8 @@ func gen(t *testgen.Trace) { // One goroutine enters a syscall. b0 := g.Batch(trace.ThreadID(0), 0) - b0.Event("ProcStatus", trace.ProcID(0), go122.ProcRunning) - b0.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), go122.GoRunning) + b0.Event("ProcStatus", trace.ProcID(0), tracev2.ProcRunning) + b0.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), tracev2.GoRunning) b0.Event("GoSyscallBegin", testgen.Seq(1), testgen.NoStack) b0.Event("GoSyscallEndBlocked") diff --git a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-simple.go b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-simple.go index 6304105af04cff..e09a70c7c9a671 100644 --- a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-simple.go +++ b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-simple.go @@ -8,8 +8,8 @@ package main import ( "internal/trace" - "internal/trace/event/go122" - testgen "internal/trace/internal/testgen/go122" + "internal/trace/internal/testgen" + "internal/trace/tracev2" ) func main() { @@ -21,14 +21,14 @@ func gen(t *testgen.Trace) { // One goroutine enters a syscall. b0 := g.Batch(trace.ThreadID(0), 0) - b0.Event("ProcStatus", trace.ProcID(0), go122.ProcRunning) - b0.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), go122.GoRunning) + b0.Event("ProcStatus", trace.ProcID(0), tracev2.ProcRunning) + b0.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), tracev2.GoRunning) b0.Event("GoSyscallBegin", testgen.Seq(1), testgen.NoStack) b0.Event("GoSyscallEndBlocked") // A running goroutine steals proc 0. b1 := g.Batch(trace.ThreadID(1), 0) - b1.Event("ProcStatus", trace.ProcID(2), go122.ProcRunning) - b1.Event("GoStatus", trace.GoID(2), trace.ThreadID(1), go122.GoRunning) + b1.Event("ProcStatus", trace.ProcID(2), tracev2.ProcRunning) + b1.Event("GoStatus", trace.GoID(2), trace.ThreadID(1), tracev2.GoRunning) b1.Event("ProcSteal", trace.ProcID(0), testgen.Seq(2), trace.ThreadID(0)) } diff --git a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-sitting-in-syscall.go b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-sitting-in-syscall.go index ac84261f020593..d3600e43e8e7b6 100644 --- a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-sitting-in-syscall.go +++ b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-sitting-in-syscall.go @@ -9,8 +9,8 @@ package main import ( "internal/trace" - "internal/trace/event/go122" - testgen "internal/trace/internal/testgen/go122" + "internal/trace/internal/testgen" + "internal/trace/tracev2" ) func main() { @@ -23,10 +23,10 @@ func gen(t *testgen.Trace) { // Steal proc from a goroutine that's been blocked // in a syscall the entire generation. b0 := g.Batch(trace.ThreadID(0), 0) - b0.Event("ProcStatus", trace.ProcID(0), go122.ProcSyscallAbandoned) + b0.Event("ProcStatus", trace.ProcID(0), tracev2.ProcSyscallAbandoned) b0.Event("ProcSteal", trace.ProcID(0), testgen.Seq(1), trace.ThreadID(1)) // Status event for a goroutine blocked in a syscall for the entire generation. bz := g.Batch(trace.NoThread, 0) - bz.Event("GoStatus", trace.GoID(1), trace.ThreadID(1), go122.GoSyscall) + bz.Event("GoStatus", trace.GoID(1), trace.ThreadID(1), tracev2.GoSyscall) } diff --git a/src/internal/trace/testdata/generators/go122-task-across-generations.go b/src/internal/trace/testdata/generators/go122-task-across-generations.go index 83b1bcdb5ef491..644176a1e3093a 100644 --- a/src/internal/trace/testdata/generators/go122-task-across-generations.go +++ b/src/internal/trace/testdata/generators/go122-task-across-generations.go @@ -14,8 +14,8 @@ package main import ( "internal/trace" - "internal/trace/event/go122" - testgen "internal/trace/internal/testgen/go122" + "internal/trace/internal/testgen" + "internal/trace/tracev2" ) func main() { @@ -27,15 +27,15 @@ func gen(t *testgen.Trace) { // A running goroutine emits a task begin. b1 := g1.Batch(trace.ThreadID(0), 0) - b1.Event("ProcStatus", trace.ProcID(0), go122.ProcRunning) - b1.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), go122.GoRunning) + b1.Event("ProcStatus", trace.ProcID(0), tracev2.ProcRunning) + b1.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), tracev2.GoRunning) b1.Event("UserTaskBegin", trace.TaskID(2), trace.TaskID(0) /* 0 means no parent, not background */, "my task", testgen.NoStack) g2 := t.Generation(2) // That same goroutine emits a task end in the following generation. b2 := g2.Batch(trace.ThreadID(0), 5) - b2.Event("ProcStatus", trace.ProcID(0), go122.ProcRunning) - b2.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), go122.GoRunning) + b2.Event("ProcStatus", trace.ProcID(0), tracev2.ProcRunning) + b2.Event("GoStatus", trace.GoID(1), trace.ThreadID(0), tracev2.GoRunning) b2.Event("UserTaskEnd", trace.TaskID(2), testgen.NoStack) } diff --git a/src/internal/trace/tracev1.go b/src/internal/trace/tracev1.go index 91752efa99d22a..9c2a1ebc14c6b5 100644 --- a/src/internal/trace/tracev1.go +++ b/src/internal/trace/tracev1.go @@ -30,9 +30,9 @@ package trace import ( "errors" "fmt" - "internal/trace/event" - "internal/trace/event/go122" "internal/trace/internal/tracev1" + "internal/trace/tracev2" + "internal/trace/tracev2/event" "io" ) @@ -259,7 +259,7 @@ func (it *traceV1Converter) convertEvent(ev *tracev1.Event) (OUT Event, ERR erro switch ev.Type { case tracev1.EvGomaxprocs: - mappedType = go122.EvProcsChange + mappedType = tracev2.EvProcsChange if it.preInit { // The first EvGomaxprocs signals the end of trace initialization. At this point we've seen // all goroutines that already existed at trace begin. @@ -277,9 +277,9 @@ func (it *traceV1Converter) convertEvent(ev *tracev1.Event) (OUT Event, ERR erro }, table: it.evt, base: baseEvent{ - typ: go122.EvGoStatus, + typ: tracev2.EvGoStatus, time: Time(ev.Ts), - args: timedEventArgs{uint64(gid), ^uint64(0), uint64(go122.GoRunnable)}, + args: timedEventArgs{uint64(gid), ^uint64(0), uint64(tracev2.GoRunnable)}, }, }) } @@ -289,51 +289,51 @@ func (it *traceV1Converter) convertEvent(ev *tracev1.Event) (OUT Event, ERR erro case tracev1.EvProcStart: it.procMs[ProcID(ev.P)] = ThreadID(ev.Args[0]) if _, ok := it.seenProcs[ProcID(ev.P)]; ok { - mappedType = go122.EvProcStart + mappedType = tracev2.EvProcStart mappedArgs = timedEventArgs{uint64(ev.P)} } else { it.seenProcs[ProcID(ev.P)] = struct{}{} - mappedType = go122.EvProcStatus - mappedArgs = timedEventArgs{uint64(ev.P), uint64(go122.ProcRunning)} + mappedType = tracev2.EvProcStatus + mappedArgs = timedEventArgs{uint64(ev.P), uint64(tracev2.ProcRunning)} } case tracev1.EvProcStop: if _, ok := it.seenProcs[ProcID(ev.P)]; ok { - mappedType = go122.EvProcStop + mappedType = tracev2.EvProcStop mappedArgs = timedEventArgs{uint64(ev.P)} } else { it.seenProcs[ProcID(ev.P)] = struct{}{} - mappedType = go122.EvProcStatus - mappedArgs = timedEventArgs{uint64(ev.P), uint64(go122.ProcIdle)} + mappedType = tracev2.EvProcStatus + mappedArgs = timedEventArgs{uint64(ev.P), uint64(tracev2.ProcIdle)} } case tracev1.EvGCStart: - mappedType = go122.EvGCBegin + mappedType = tracev2.EvGCBegin case tracev1.EvGCDone: - mappedType = go122.EvGCEnd + mappedType = tracev2.EvGCEnd case tracev1.EvSTWStart: sid := it.builtinToStringID[sSTWUnknown+it.trace.STWReason(ev.Args[0])] it.lastStwReason = sid - mappedType = go122.EvSTWBegin + mappedType = tracev2.EvSTWBegin mappedArgs = timedEventArgs{uint64(sid)} case tracev1.EvSTWDone: - mappedType = go122.EvSTWEnd + mappedType = tracev2.EvSTWEnd mappedArgs = timedEventArgs{it.lastStwReason} case tracev1.EvGCSweepStart: - mappedType = go122.EvGCSweepBegin + mappedType = tracev2.EvGCSweepBegin case tracev1.EvGCSweepDone: - mappedType = go122.EvGCSweepEnd + mappedType = tracev2.EvGCSweepEnd case tracev1.EvGoCreate: if it.preInit { it.createdPreInit[GoID(ev.Args[0])] = struct{}{} return Event{}, errSkip } - mappedType = go122.EvGoCreate + mappedType = tracev2.EvGoCreate case tracev1.EvGoStart: if it.preInit { - mappedType = go122.EvGoStatus - mappedArgs = timedEventArgs{ev.Args[0], ^uint64(0), uint64(go122.GoRunning)} + mappedType = tracev2.EvGoStatus + mappedArgs = timedEventArgs{ev.Args[0], ^uint64(0), uint64(tracev2.GoRunning)} delete(it.createdPreInit, GoID(ev.Args[0])) } else { - mappedType = go122.EvGoStart + mappedType = tracev2.EvGoStart } case tracev1.EvGoStartLabel: it.extra = []Event{{ @@ -344,7 +344,7 @@ func (it *traceV1Converter) convertEvent(ev *tracev1.Event) (OUT Event, ERR erro }, table: it.evt, base: baseEvent{ - typ: go122.EvGoLabel, + typ: tracev2.EvGoLabel, time: Time(ev.Ts), args: timedEventArgs{ev.Args[2]}, }, @@ -357,50 +357,50 @@ func (it *traceV1Converter) convertEvent(ev *tracev1.Event) (OUT Event, ERR erro }, table: it.evt, base: baseEvent{ - typ: go122.EvGoStart, + typ: tracev2.EvGoStart, time: Time(ev.Ts), args: mappedArgs, }, }, nil case tracev1.EvGoEnd: - mappedType = go122.EvGoDestroy + mappedType = tracev2.EvGoDestroy case tracev1.EvGoStop: - mappedType = go122.EvGoBlock + mappedType = tracev2.EvGoBlock mappedArgs = timedEventArgs{uint64(it.builtinToStringID[sForever]), uint64(ev.StkID)} case tracev1.EvGoSched: - mappedType = go122.EvGoStop + mappedType = tracev2.EvGoStop mappedArgs = timedEventArgs{uint64(it.builtinToStringID[sGosched]), uint64(ev.StkID)} case tracev1.EvGoPreempt: - mappedType = go122.EvGoStop + mappedType = tracev2.EvGoStop mappedArgs = timedEventArgs{uint64(it.builtinToStringID[sPreempted]), uint64(ev.StkID)} case tracev1.EvGoSleep: - mappedType = go122.EvGoBlock + mappedType = tracev2.EvGoBlock mappedArgs = timedEventArgs{uint64(it.builtinToStringID[sSleep]), uint64(ev.StkID)} case tracev1.EvGoBlock: - mappedType = go122.EvGoBlock + mappedType = tracev2.EvGoBlock mappedArgs = timedEventArgs{uint64(it.builtinToStringID[sEmpty]), uint64(ev.StkID)} case tracev1.EvGoUnblock: - mappedType = go122.EvGoUnblock + mappedType = tracev2.EvGoUnblock case tracev1.EvGoBlockSend: - mappedType = go122.EvGoBlock + mappedType = tracev2.EvGoBlock mappedArgs = timedEventArgs{uint64(it.builtinToStringID[sChanSend]), uint64(ev.StkID)} case tracev1.EvGoBlockRecv: - mappedType = go122.EvGoBlock + mappedType = tracev2.EvGoBlock mappedArgs = timedEventArgs{uint64(it.builtinToStringID[sChanRecv]), uint64(ev.StkID)} case tracev1.EvGoBlockSelect: - mappedType = go122.EvGoBlock + mappedType = tracev2.EvGoBlock mappedArgs = timedEventArgs{uint64(it.builtinToStringID[sSelect]), uint64(ev.StkID)} case tracev1.EvGoBlockSync: - mappedType = go122.EvGoBlock + mappedType = tracev2.EvGoBlock mappedArgs = timedEventArgs{uint64(it.builtinToStringID[sSync]), uint64(ev.StkID)} case tracev1.EvGoBlockCond: - mappedType = go122.EvGoBlock + mappedType = tracev2.EvGoBlock mappedArgs = timedEventArgs{uint64(it.builtinToStringID[sSyncCond]), uint64(ev.StkID)} case tracev1.EvGoBlockNet: - mappedType = go122.EvGoBlock + mappedType = tracev2.EvGoBlock mappedArgs = timedEventArgs{uint64(it.builtinToStringID[sNetwork]), uint64(ev.StkID)} case tracev1.EvGoBlockGC: - mappedType = go122.EvGoBlock + mappedType = tracev2.EvGoBlock mappedArgs = timedEventArgs{uint64(it.builtinToStringID[sMarkAssistWait]), uint64(ev.StkID)} case tracev1.EvGoSysCall: // Look for the next event for the same G to determine if the syscall @@ -419,7 +419,7 @@ func (it *traceV1Converter) convertEvent(ev *tracev1.Event) (OUT Event, ERR erro return false }) if blocked { - mappedType = go122.EvGoSyscallBegin + mappedType = tracev2.EvGoSyscallBegin mappedArgs = timedEventArgs{1: uint64(ev.StkID)} } else { // Convert the old instantaneous syscall event to a pair of syscall @@ -433,7 +433,7 @@ func (it *traceV1Converter) convertEvent(ev *tracev1.Event) (OUT Event, ERR erro }, table: it.evt, base: baseEvent{ - typ: go122.EvGoSyscallBegin, + typ: tracev2.EvGoSyscallBegin, time: Time(ev.Ts), args: timedEventArgs{1: uint64(ev.StkID)}, }, @@ -443,7 +443,7 @@ func (it *traceV1Converter) convertEvent(ev *tracev1.Event) (OUT Event, ERR erro ctx: out1.ctx, table: it.evt, base: baseEvent{ - typ: go122.EvGoSyscallEnd, + typ: tracev2.EvGoSyscallEnd, time: Time(ev.Ts + 1), args: timedEventArgs{}, }, @@ -454,30 +454,30 @@ func (it *traceV1Converter) convertEvent(ev *tracev1.Event) (OUT Event, ERR erro } case tracev1.EvGoSysExit: - mappedType = go122.EvGoSyscallEndBlocked + mappedType = tracev2.EvGoSyscallEndBlocked case tracev1.EvGoSysBlock: return Event{}, errSkip case tracev1.EvGoWaiting: - mappedType = go122.EvGoStatus - mappedArgs = timedEventArgs{ev.Args[0], ^uint64(0), uint64(go122.GoWaiting)} + mappedType = tracev2.EvGoStatus + mappedArgs = timedEventArgs{ev.Args[0], ^uint64(0), uint64(tracev2.GoWaiting)} delete(it.createdPreInit, GoID(ev.Args[0])) case tracev1.EvGoInSyscall: - mappedType = go122.EvGoStatus + mappedType = tracev2.EvGoStatus // In the new tracer, GoStatus with GoSyscall knows what thread the // syscall is on. In trace v1, EvGoInSyscall doesn't contain that // information and all we can do here is specify NoThread. - mappedArgs = timedEventArgs{ev.Args[0], ^uint64(0), uint64(go122.GoSyscall)} + mappedArgs = timedEventArgs{ev.Args[0], ^uint64(0), uint64(tracev2.GoSyscall)} delete(it.createdPreInit, GoID(ev.Args[0])) case tracev1.EvHeapAlloc: - mappedType = go122.EvHeapAlloc + mappedType = tracev2.EvHeapAlloc case tracev1.EvHeapGoal: - mappedType = go122.EvHeapGoal + mappedType = tracev2.EvHeapGoal case tracev1.EvGCMarkAssistStart: - mappedType = go122.EvGCMarkAssistBegin + mappedType = tracev2.EvGCMarkAssistBegin case tracev1.EvGCMarkAssistDone: - mappedType = go122.EvGCMarkAssistEnd + mappedType = tracev2.EvGCMarkAssistEnd case tracev1.EvUserTaskCreate: - mappedType = go122.EvUserTaskBegin + mappedType = tracev2.EvUserTaskBegin parent := ev.Args[1] if parent == 0 { parent = uint64(NoTask) @@ -486,7 +486,7 @@ func (it *traceV1Converter) convertEvent(ev *tracev1.Event) (OUT Event, ERR erro name, _ := it.evt.strings.get(stringID(ev.Args[2])) it.tasks[TaskID(ev.Args[0])] = taskState{name: name, parentID: TaskID(ev.Args[1])} case tracev1.EvUserTaskEnd: - mappedType = go122.EvUserTaskEnd + mappedType = tracev2.EvUserTaskEnd // Event.Task expects the parent and name to be smuggled in extra args // and as extra strings. ts, ok := it.tasks[TaskID(ev.Args[0])] @@ -504,16 +504,16 @@ func (it *traceV1Converter) convertEvent(ev *tracev1.Event) (OUT Event, ERR erro case tracev1.EvUserRegion: switch ev.Args[1] { case 0: // start - mappedType = go122.EvUserRegionBegin + mappedType = tracev2.EvUserRegionBegin case 1: // end - mappedType = go122.EvUserRegionEnd + mappedType = tracev2.EvUserRegionEnd } mappedArgs = timedEventArgs{ev.Args[0], ev.Args[2], uint64(ev.StkID)} case tracev1.EvUserLog: - mappedType = go122.EvUserLog + mappedType = tracev2.EvUserLog mappedArgs = timedEventArgs{ev.Args[0], ev.Args[1], it.inlineToStringID[ev.Args[3]], uint64(ev.StkID)} case tracev1.EvCPUSample: - mappedType = go122.EvCPUSample + mappedType = tracev2.EvCPUSample // When emitted by the Go 1.22 tracer, CPU samples have 5 arguments: // timestamp, M, P, G, stack. However, after they get turned into Event, // they have the arguments stack, M, P, G. @@ -525,7 +525,7 @@ func (it *traceV1Converter) convertEvent(ev *tracev1.Event) (OUT Event, ERR erro } if tracev1.EventDescriptions[ev.Type].Stack { - if stackIDs := go122.Specs()[mappedType].StackIDs; len(stackIDs) > 0 { + if stackIDs := tracev2.Specs()[mappedType].StackIDs; len(stackIDs) > 0 { mappedArgs[stackIDs[0]-1] = uint64(ev.StkID) } } diff --git a/src/internal/trace/tracev1_test.go b/src/internal/trace/tracev1_test.go index 0f8e24d2c4ec17..008c7535c9f35f 100644 --- a/src/internal/trace/tracev1_test.go +++ b/src/internal/trace/tracev1_test.go @@ -54,9 +54,9 @@ func TestTraceV1(t *testing.T) { if testName == "user_task_region_1_21_good" { testedUserRegions = true validRegions := map[string]struct{}{ - "post-existing region": struct{}{}, - "region0": struct{}{}, - "region1": struct{}{}, + "post-existing region": {}, + "region0": {}, + "region1": {}, } // Check that we correctly convert user regions. These // strings were generated by diff --git a/src/internal/trace/event/go122/event.go b/src/internal/trace/tracev2/event.go similarity index 99% rename from src/internal/trace/event/go122/event.go rename to src/internal/trace/tracev2/event.go index 5eadf0e571f28a..48ed0eba1bc415 100644 --- a/src/internal/trace/event/go122/event.go +++ b/src/internal/trace/tracev2/event.go @@ -2,11 +2,11 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package go122 +package tracev2 import ( "fmt" - "internal/trace/event" + "internal/trace/tracev2/event" ) const ( diff --git a/src/internal/trace/event/event.go b/src/internal/trace/tracev2/event/event.go similarity index 100% rename from src/internal/trace/event/event.go rename to src/internal/trace/tracev2/event/event.go diff --git a/src/internal/trace/version/version.go b/src/internal/trace/version/version.go index 4951bd97d76645..a42cc708d241a0 100644 --- a/src/internal/trace/version/version.go +++ b/src/internal/trace/version/version.go @@ -8,8 +8,8 @@ import ( "fmt" "io" - "internal/trace/event" - "internal/trace/event/go122" + "internal/trace/tracev2" + "internal/trace/tracev2/event" ) // Version represents the version of a trace file. @@ -31,11 +31,11 @@ var versions = map[Version][]event.Spec{ Go119: nil, Go121: nil, - Go122: go122.Specs(), + Go122: tracev2.Specs(), // Go 1.23 adds backwards-incompatible events, but // traces produced by Go 1.22 are also always valid // Go 1.23 traces. - Go123: go122.Specs(), + Go123: tracev2.Specs(), } // Specs returns the set of event.Specs for this version. From 715754ba86665b860c7245759149f1e86c24ee8d Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Fri, 24 Jan 2025 20:56:47 +0000 Subject: [PATCH 298/397] internal/trace: be stricter about allowed events in v2 trace versions Currently all v2 trace versions, Go 1.22 and Go 1.23, share a full set of specs. This is mostly OK, but it means quite a few events will be accepted for 1.22 traces that should be rejected. This change fixes that by limiting which event specs are returned by version.Version.Specs for Go 1.22. While we're here, let's be stricter about event names too, and move tracev2.EventString to be a method on the version, so we can be more precise. An intended consequence of this move is that tracev2 no longer depends on fmt, since we will want the runtime to depend on tracev2 in the near future. Change-Id: If7285460c8ba59ab73da00993b7b12e61cdfe6a9 Reviewed-on: https://go-review.googlesource.com/c/go/+/644219 LUCI-TryBot-Result: Go LUCI Auto-Submit: Michael Knyszek Reviewed-by: Michael Pratt --- src/go/build/deps_test.go | 4 +-- src/internal/trace/batch.go | 2 +- src/internal/trace/event.go | 14 ++++---- src/internal/trace/order.go | 49 +++++++++++++++------------ src/internal/trace/reader.go | 5 ++- src/internal/trace/tracev2/event.go | 9 ----- src/internal/trace/version/version.go | 31 ++++++++++++----- 7 files changed, 62 insertions(+), 52 deletions(-) diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index 5212db740ee6fa..f2de39a0825f60 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -58,6 +58,7 @@ var depsRules = ` internal/platform, internal/profilerecord, internal/syslist, + internal/trace/tracev2/event, internal/trace/traceviewer/format, log/internal, math/bits, @@ -698,9 +699,6 @@ var depsRules = ` < crypto/internal/fips140/check/checktest; # v2 execution trace parser. - FMT - < internal/trace/tracev2/event; - internal/trace/tracev2/event < internal/trace/tracev2; diff --git a/src/internal/trace/batch.go b/src/internal/trace/batch.go index ba22bfde38dc27..0dc87321a69364 100644 --- a/src/internal/trace/batch.go +++ b/src/internal/trace/batch.go @@ -53,7 +53,7 @@ func readBatch(r interface { return batch{}, 0, err } if typ := event.Type(b); typ != tracev2.EvEventBatch && typ != tracev2.EvExperimentalBatch { - return batch{}, 0, fmt.Errorf("expected batch event, got %s", tracev2.EventString(typ)) + return batch{}, 0, fmt.Errorf("expected batch event, got event %d", typ) } // Read the experiment of we have one. diff --git a/src/internal/trace/event.go b/src/internal/trace/event.go index 67f1e382306d27..fa1daf3698004d 100644 --- a/src/internal/trace/event.go +++ b/src/internal/trace/event.go @@ -430,7 +430,7 @@ func (e Event) Metric() Metric { m.Name = "/gc/heap/goal:bytes" m.Value = Value{kind: ValueUint64, scalar: e.base.args[0]} default: - panic(fmt.Sprintf("internal error: unexpected event type for Metric kind: %s", tracev2.EventString(e.base.typ))) + panic(fmt.Sprintf("internal error: unexpected wire-format event type for Metric kind: %d", e.base.typ)) } return m } @@ -443,7 +443,7 @@ func (e Event) Label() Label { panic("Label called on non-Label event") } if e.base.typ != tracev2.EvGoLabel { - panic(fmt.Sprintf("internal error: unexpected event type for Label kind: %s", tracev2.EventString(e.base.typ))) + panic(fmt.Sprintf("internal error: unexpected wire-format event type for Label kind: %d", e.base.typ)) } return Label{ Label: e.table.strings.mustGet(stringID(e.base.args[0])), @@ -486,7 +486,7 @@ func (e Event) Range() Range { r.Scope.id = int64(e.Goroutine()) } default: - panic(fmt.Sprintf("internal error: unexpected event type for Range kind: %s", tracev2.EventString(e.base.typ))) + panic(fmt.Sprintf("internal error: unexpected wire-event type for Range kind: %d", e.base.typ)) } return r } @@ -530,7 +530,7 @@ func (e Event) Task() Task { parentID = TaskID(e.base.extra(version.Go122)[0]) typ = e.table.getExtraString(extraStringID(e.base.extra(version.Go122)[1])) default: - panic(fmt.Sprintf("internal error: unexpected event type for Task kind: %s", tracev2.EventString(e.base.typ))) + panic(fmt.Sprintf("internal error: unexpected wire-format event type for Task kind: %d", e.base.typ)) } return Task{ ID: TaskID(e.base.args[0]), @@ -547,7 +547,7 @@ func (e Event) Region() Region { panic("Region called on non-Region event") } if e.base.typ != tracev2.EvUserRegionBegin && e.base.typ != tracev2.EvUserRegionEnd { - panic(fmt.Sprintf("internal error: unexpected event type for Region kind: %s", tracev2.EventString(e.base.typ))) + panic(fmt.Sprintf("internal error: unexpected wire-format event type for Region kind: %d", e.base.typ)) } return Region{ Task: TaskID(e.base.args[0]), @@ -563,7 +563,7 @@ func (e Event) Log() Log { panic("Log called on non-Log event") } if e.base.typ != tracev2.EvUserLog { - panic(fmt.Sprintf("internal error: unexpected event type for Log kind: %s", tracev2.EventString(e.base.typ))) + panic(fmt.Sprintf("internal error: unexpected wire-format event type for Log kind: %d", e.base.typ)) } return Log{ Task: TaskID(e.base.args[0]), @@ -642,7 +642,7 @@ func (e Event) StateTransition() StateTransition { from, to := packedStatus>>32, packedStatus&((1<<32)-1) s = goStateTransition(GoID(e.base.args[0]), GoState(from), tracev2GoStatus2GoState[to]) default: - panic(fmt.Sprintf("internal error: unexpected event type for StateTransition kind: %s", tracev2.EventString(e.base.typ))) + panic(fmt.Sprintf("internal error: unexpected wire-format event type for StateTransition kind: %d", e.base.typ)) } return s } diff --git a/src/internal/trace/order.go b/src/internal/trace/order.go index 8028f61a83e57a..3e7ed8941b55e1 100644 --- a/src/internal/trace/order.go +++ b/src/internal/trace/order.go @@ -22,6 +22,7 @@ import ( // add completed events to the ordering. Next is used to pick // off events in the ordering. type ordering struct { + traceVer version.Version gStates map[GoID]*gState pStates map[ProcID]*pState // TODO: The keys are dense, so this can be a slice. mStates map[ThreadID]*mState @@ -88,6 +89,10 @@ func (o *ordering) Advance(ev *baseEvent, evt *evTable, m ThreadID, gen uint64) return ok, err } +func (o *ordering) evName(typ event.Type) string { + return o.traceVer.EventName(typ) +} + type orderingHandleFunc func(o *ordering, ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) var orderingDispatch = [256]orderingHandleFunc{ @@ -270,10 +275,10 @@ func (o *ordering) advanceProcStop(ev *baseEvent, evt *evTable, m ThreadID, gen // ProcStop doesn't need a sequence number. state, ok := o.pStates[curCtx.P] if !ok { - return curCtx, false, fmt.Errorf("event %s for proc (%v) that doesn't exist", tracev2.EventString(ev.typ), curCtx.P) + return curCtx, false, fmt.Errorf("event %s for proc (%v) that doesn't exist", o.evName(ev.typ), curCtx.P) } if state.status != tracev2.ProcRunning && state.status != tracev2.ProcSyscall { - return curCtx, false, fmt.Errorf("%s event for proc that's not %s or %s", tracev2.EventString(ev.typ), tracev2.ProcRunning, tracev2.ProcSyscall) + return curCtx, false, fmt.Errorf("%s event for proc that's not %s or %s", o.evName(ev.typ), tracev2.ProcRunning, tracev2.ProcSyscall) } reqs := schedReqs{M: mustHave, P: mustHave, G: mayHave} if err := validateCtx(curCtx, reqs); err != nil { @@ -443,7 +448,7 @@ func (o *ordering) advanceGoCreate(ev *baseEvent, evt *evTable, m ThreadID, gen } // If we have a goroutine, it must be running. if state, ok := o.gStates[curCtx.G]; ok && state.status != tracev2.GoRunning { - return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", tracev2.EventString(ev.typ), GoRunning) + return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", o.evName(ev.typ), GoRunning) } // This goroutine created another. Add a state for it. newgid := GoID(ev.args[0]) @@ -468,10 +473,10 @@ func (o *ordering) advanceGoStopExec(ev *baseEvent, evt *evTable, m ThreadID, ge } state, ok := o.gStates[curCtx.G] if !ok { - return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", tracev2.EventString(ev.typ), curCtx.G) + return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", o.evName(ev.typ), curCtx.G) } if state.status != tracev2.GoRunning { - return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", tracev2.EventString(ev.typ), GoRunning) + return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", o.evName(ev.typ), GoRunning) } // Handle each case slightly differently; we just group them together // because they have shared preconditions. @@ -551,10 +556,10 @@ func (o *ordering) advanceGoSwitch(ev *baseEvent, evt *evTable, m ThreadID, gen } curGState, ok := o.gStates[curCtx.G] if !ok { - return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", tracev2.EventString(ev.typ), curCtx.G) + return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", o.evName(ev.typ), curCtx.G) } if curGState.status != tracev2.GoRunning { - return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", tracev2.EventString(ev.typ), GoRunning) + return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", o.evName(ev.typ), GoRunning) } nextg := GoID(ev.args[0]) seq := makeSeq(gen, ev.args[1]) // seq is for nextg, not curCtx.G. @@ -606,16 +611,16 @@ func (o *ordering) advanceGoSyscallBegin(ev *baseEvent, evt *evTable, m ThreadID } state, ok := o.gStates[curCtx.G] if !ok { - return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", tracev2.EventString(ev.typ), curCtx.G) + return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", o.evName(ev.typ), curCtx.G) } if state.status != tracev2.GoRunning { - return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", tracev2.EventString(ev.typ), GoRunning) + return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", o.evName(ev.typ), GoRunning) } // Goroutine entered a syscall. It's still running on this P and M. state.status = tracev2.GoSyscall pState, ok := o.pStates[curCtx.P] if !ok { - return curCtx, false, fmt.Errorf("uninitialized proc %d found during %s", curCtx.P, tracev2.EventString(ev.typ)) + return curCtx, false, fmt.Errorf("uninitialized proc %d found during %s", curCtx.P, o.evName(ev.typ)) } pState.status = tracev2.ProcSyscall // Validate the P sequence number on the event and advance it. @@ -631,7 +636,7 @@ func (o *ordering) advanceGoSyscallBegin(ev *baseEvent, evt *evTable, m ThreadID // to back off and see if any other events will advance. This is a running P. pSeq := makeSeq(gen, ev.args[0]) if !pSeq.succeeds(pState.seq) { - return curCtx, false, fmt.Errorf("failed to advance %s: can't make sequence: %s -> %s", tracev2.EventString(ev.typ), pState.seq, pSeq) + return curCtx, false, fmt.Errorf("failed to advance %s: can't make sequence: %s -> %s", o.evName(ev.typ), pState.seq, pSeq) } pState.seq = pSeq o.queue.push(Event{table: evt, ctx: curCtx, base: *ev}) @@ -647,17 +652,17 @@ func (o *ordering) advanceGoSyscallEnd(ev *baseEvent, evt *evTable, m ThreadID, } state, ok := o.gStates[curCtx.G] if !ok { - return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", tracev2.EventString(ev.typ), curCtx.G) + return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", o.evName(ev.typ), curCtx.G) } if state.status != tracev2.GoSyscall { - return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", tracev2.EventString(ev.typ), GoRunning) + return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", o.evName(ev.typ), GoRunning) } state.status = tracev2.GoRunning // Transfer the P back to running from syscall. pState, ok := o.pStates[curCtx.P] if !ok { - return curCtx, false, fmt.Errorf("uninitialized proc %d found during %s", curCtx.P, tracev2.EventString(ev.typ)) + return curCtx, false, fmt.Errorf("uninitialized proc %d found during %s", curCtx.P, o.evName(ev.typ)) } if pState.status != tracev2.ProcSyscall { return curCtx, false, fmt.Errorf("expected proc %d in state %v, but got %v instead", curCtx.P, tracev2.ProcSyscall, pState.status) @@ -681,7 +686,7 @@ func (o *ordering) advanceGoSyscallEndBlocked(ev *baseEvent, evt *evTable, m Thr if curCtx.P != NoProc { pState, ok := o.pStates[curCtx.P] if !ok { - return curCtx, false, fmt.Errorf("uninitialized proc %d found during %s", curCtx.P, tracev2.EventString(ev.typ)) + return curCtx, false, fmt.Errorf("uninitialized proc %d found during %s", curCtx.P, o.evName(ev.typ)) } if pState.status == tracev2.ProcSyscall { return curCtx, false, nil @@ -694,10 +699,10 @@ func (o *ordering) advanceGoSyscallEndBlocked(ev *baseEvent, evt *evTable, m Thr } state, ok := o.gStates[curCtx.G] if !ok { - return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", tracev2.EventString(ev.typ), curCtx.G) + return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", o.evName(ev.typ), curCtx.G) } if state.status != tracev2.GoSyscall { - return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", tracev2.EventString(ev.typ), GoRunning) + return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", o.evName(ev.typ), GoRunning) } newCtx := curCtx newCtx.G = NoGoroutine @@ -749,10 +754,10 @@ func (o *ordering) advanceGoDestroySyscall(ev *baseEvent, evt *evTable, m Thread // Check to make sure the goroutine exists in the right state. state, ok := o.gStates[curCtx.G] if !ok { - return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", tracev2.EventString(ev.typ), curCtx.G) + return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", o.evName(ev.typ), curCtx.G) } if state.status != tracev2.GoSyscall { - return curCtx, false, fmt.Errorf("%s event for goroutine that's not %v", tracev2.EventString(ev.typ), GoSyscall) + return curCtx, false, fmt.Errorf("%s event for goroutine that's not %v", o.evName(ev.typ), GoSyscall) } // This goroutine is exiting itself. delete(o.gStates, curCtx.G) @@ -763,10 +768,10 @@ func (o *ordering) advanceGoDestroySyscall(ev *baseEvent, evt *evTable, m Thread if curCtx.P != NoProc { pState, ok := o.pStates[curCtx.P] if !ok { - return curCtx, false, fmt.Errorf("found invalid proc %d during %s", curCtx.P, tracev2.EventString(ev.typ)) + return curCtx, false, fmt.Errorf("found invalid proc %d during %s", curCtx.P, o.evName(ev.typ)) } if pState.status != tracev2.ProcSyscall { - return curCtx, false, fmt.Errorf("proc %d in unexpected state %s during %s", curCtx.P, pState.status, tracev2.EventString(ev.typ)) + return curCtx, false, fmt.Errorf("proc %d in unexpected state %s during %s", curCtx.P, pState.status, o.evName(ev.typ)) } // See the go122-create-syscall-reuse-thread-id test case for more details. pState.status = tracev2.ProcSyscallAbandoned @@ -1046,7 +1051,7 @@ func (o *ordering) advanceGoRangeActive(ev *baseEvent, evt *evTable, m ThreadID, // current scheduler context. gState, ok := o.gStates[gid] if !ok { - return curCtx, false, fmt.Errorf("uninitialized goroutine %d found during %s", gid, tracev2.EventString(ev.typ)) + return curCtx, false, fmt.Errorf("uninitialized goroutine %d found during %s", gid, o.evName(ev.typ)) } if err := gState.activeRange(makeRangeType(ev.typ, 0), gen == o.initialGen); err != nil { return curCtx, false, err diff --git a/src/internal/trace/reader.go b/src/internal/trace/reader.go index 699febeed4b327..81710c0125eda5 100644 --- a/src/internal/trace/reader.go +++ b/src/internal/trace/reader.go @@ -22,6 +22,7 @@ import ( // event as the first event, and a Sync event as the last event. // (There may also be any number of Sync events in the middle, too.) type Reader struct { + version version.Version r *bufio.Reader lastTs Time gen *generation @@ -54,8 +55,10 @@ func NewReader(r io.Reader) (*Reader, error) { }, nil case version.Go122, version.Go123: return &Reader{ - r: br, + version: v, + r: br, order: ordering{ + traceVer: v, mStates: make(map[ThreadID]*mState), pStates: make(map[ProcID]*pState), gStates: make(map[GoID]*gState), diff --git a/src/internal/trace/tracev2/event.go b/src/internal/trace/tracev2/event.go index 48ed0eba1bc415..308ae679e977a0 100644 --- a/src/internal/trace/tracev2/event.go +++ b/src/internal/trace/tracev2/event.go @@ -5,7 +5,6 @@ package tracev2 import ( - "fmt" "internal/trace/tracev2/event" ) @@ -116,14 +115,6 @@ const ( EvGoroutineStackFree // stack free [timestamp, id] ) -// EventString returns the name of a Go 1.22 event. -func EventString(typ event.Type) string { - if int(typ) < len(specs) { - return specs[typ].Name - } - return fmt.Sprintf("Invalid(%d)", typ) -} - func Specs() []event.Spec { return specs[:] } diff --git a/src/internal/trace/version/version.go b/src/internal/trace/version/version.go index a42cc708d241a0..50a674bd234cdb 100644 --- a/src/internal/trace/version/version.go +++ b/src/internal/trace/version/version.go @@ -16,11 +16,11 @@ import ( type Version uint32 const ( - Go111 Version = 11 - Go119 Version = 19 - Go121 Version = 21 - Go122 Version = 22 - Go123 Version = 23 + Go111 Version = 11 // v1 + Go119 Version = 19 // v1 + Go121 Version = 21 // v1 + Go122 Version = 22 // v2 + Go123 Version = 23 // v2 Current = Go123 ) @@ -31,10 +31,7 @@ var versions = map[Version][]event.Spec{ Go119: nil, Go121: nil, - Go122: tracev2.Specs(), - // Go 1.23 adds backwards-incompatible events, but - // traces produced by Go 1.22 are also always valid - // Go 1.23 traces. + Go122: tracev2.Specs()[:tracev2.EvUserLog+1], // All events after are Go 1.23+. Go123: tracev2.Specs(), } @@ -43,6 +40,22 @@ func (v Version) Specs() []event.Spec { return versions[v] } +// EventName returns a string name of a wire format event +// for a particular trace version. +func (v Version) EventName(typ event.Type) string { + if !v.Valid() { + return "" + } + s := v.Specs() + if len(s) == 0 { + return "" + } + if int(typ) < len(s) && s[typ].Name != "" { + return s[typ].Name + } + return fmt.Sprintf("Invalid(%d)", typ) +} + func (v Version) Valid() bool { _, ok := versions[v] return ok From 9faa00af74206dfc26c3d38cd56590abc4b2b960 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Fri, 24 Jan 2025 21:04:01 +0000 Subject: [PATCH 299/397] internal/trace/internal/testgen: force trace version selection Currently testgen only generates Go 1.22 tests. Allow generating tests for different versions, especially now that we've tightened up which events can be emitted by different versions. Change-Id: Ia64309c6934f34eace03b3229d05fca5acfc7366 Reviewed-on: https://go-review.googlesource.com/c/go/+/644220 Reviewed-by: Michael Pratt Auto-Submit: Michael Knyszek LUCI-TryBot-Result: Go LUCI --- src/internal/trace/internal/testgen/trace.go | 7 +++---- .../generators/go122-confuse-seq-across-generations.go | 3 ++- .../generators/go122-create-syscall-reuse-thread-id.go | 3 ++- .../testdata/generators/go122-create-syscall-with-p.go | 3 ++- .../testdata/generators/go122-fail-first-gen-first.go | 3 ++- .../generators/go122-go-create-without-running-g.go | 3 ++- .../generators/go122-syscall-steal-proc-ambiguous.go | 3 ++- .../go122-syscall-steal-proc-gen-boundary-bare-m.go | 3 ++- ...ll-steal-proc-gen-boundary-reacquire-new-proc-bare-m.go | 3 ++- ...2-syscall-steal-proc-gen-boundary-reacquire-new-proc.go | 3 ++- .../generators/go122-syscall-steal-proc-gen-boundary.go | 3 ++- .../go122-syscall-steal-proc-reacquire-new-proc-bare-m.go | 3 ++- .../go122-syscall-steal-proc-reacquire-new-proc.go | 3 ++- .../testdata/generators/go122-syscall-steal-proc-self.go | 3 ++- .../generators/go122-syscall-steal-proc-simple-bare-m.go | 3 ++- .../testdata/generators/go122-syscall-steal-proc-simple.go | 3 ++- .../go122-syscall-steal-proc-sitting-in-syscall.go | 3 ++- .../testdata/generators/go122-task-across-generations.go | 3 ++- 18 files changed, 37 insertions(+), 21 deletions(-) diff --git a/src/internal/trace/internal/testgen/trace.go b/src/internal/trace/internal/testgen/trace.go index 9e797da509d81e..19d76d1367f6df 100644 --- a/src/internal/trace/internal/testgen/trace.go +++ b/src/internal/trace/internal/testgen/trace.go @@ -20,7 +20,7 @@ import ( "internal/txtar" ) -func Main(f func(*Trace)) { +func Main(ver version.Version, f func(*Trace)) { // Create an output file. out, err := os.Create(os.Args[1]) if err != nil { @@ -29,7 +29,7 @@ func Main(f func(*Trace)) { defer out.Close() // Create a new trace. - trace := NewTrace() + trace := NewTrace(ver) // Call the generator. f(trace) @@ -63,8 +63,7 @@ type Trace struct { } // NewTrace creates a new trace. -func NewTrace() *Trace { - ver := version.Go122 +func NewTrace(ver version.Version) *Trace { return &Trace{ names: event.Names(ver.Specs()), specs: ver.Specs(), diff --git a/src/internal/trace/testdata/generators/go122-confuse-seq-across-generations.go b/src/internal/trace/testdata/generators/go122-confuse-seq-across-generations.go index 30f859779011d6..9b98723c4de8b1 100644 --- a/src/internal/trace/testdata/generators/go122-confuse-seq-across-generations.go +++ b/src/internal/trace/testdata/generators/go122-confuse-seq-across-generations.go @@ -25,10 +25,11 @@ import ( "internal/trace" "internal/trace/internal/testgen" "internal/trace/tracev2" + "internal/trace/version" ) func main() { - testgen.Main(gen) + testgen.Main(version.Go122, gen) } func gen(t *testgen.Trace) { diff --git a/src/internal/trace/testdata/generators/go122-create-syscall-reuse-thread-id.go b/src/internal/trace/testdata/generators/go122-create-syscall-reuse-thread-id.go index cdb53785b09ef1..dc5c4a52572caf 100644 --- a/src/internal/trace/testdata/generators/go122-create-syscall-reuse-thread-id.go +++ b/src/internal/trace/testdata/generators/go122-create-syscall-reuse-thread-id.go @@ -27,10 +27,11 @@ import ( "internal/trace" "internal/trace/internal/testgen" "internal/trace/tracev2" + "internal/trace/version" ) func main() { - testgen.Main(gen) + testgen.Main(version.Go122, gen) } func gen(t *testgen.Trace) { diff --git a/src/internal/trace/testdata/generators/go122-create-syscall-with-p.go b/src/internal/trace/testdata/generators/go122-create-syscall-with-p.go index ba74144e92a01c..90729d7c528881 100644 --- a/src/internal/trace/testdata/generators/go122-create-syscall-with-p.go +++ b/src/internal/trace/testdata/generators/go122-create-syscall-with-p.go @@ -18,10 +18,11 @@ import ( "internal/trace" "internal/trace/internal/testgen" "internal/trace/tracev2" + "internal/trace/version" ) func main() { - testgen.Main(gen) + testgen.Main(version.Go122, gen) } func gen(t *testgen.Trace) { diff --git a/src/internal/trace/testdata/generators/go122-fail-first-gen-first.go b/src/internal/trace/testdata/generators/go122-fail-first-gen-first.go index ab396fcd4af33d..c8ead6772c0dcb 100644 --- a/src/internal/trace/testdata/generators/go122-fail-first-gen-first.go +++ b/src/internal/trace/testdata/generators/go122-fail-first-gen-first.go @@ -21,10 +21,11 @@ package main import ( "internal/trace/internal/testgen" "internal/trace/tracev2" + "internal/trace/version" ) func main() { - testgen.Main(gen) + testgen.Main(version.Go122, gen) } func gen(t *testgen.Trace) { diff --git a/src/internal/trace/testdata/generators/go122-go-create-without-running-g.go b/src/internal/trace/testdata/generators/go122-go-create-without-running-g.go index 3ce4f0243d0672..2e9b571d46ecca 100644 --- a/src/internal/trace/testdata/generators/go122-go-create-without-running-g.go +++ b/src/internal/trace/testdata/generators/go122-go-create-without-running-g.go @@ -15,10 +15,11 @@ import ( "internal/trace" "internal/trace/internal/testgen" "internal/trace/tracev2" + "internal/trace/version" ) func main() { - testgen.Main(gen) + testgen.Main(version.Go122, gen) } func gen(t *testgen.Trace) { diff --git a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-ambiguous.go b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-ambiguous.go index 57d2a1a126bc27..28d187c37e4782 100644 --- a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-ambiguous.go +++ b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-ambiguous.go @@ -17,10 +17,11 @@ import ( "internal/trace" "internal/trace/internal/testgen" "internal/trace/tracev2" + "internal/trace/version" ) func main() { - testgen.Main(gen) + testgen.Main(version.Go122, gen) } func gen(t *testgen.Trace) { diff --git a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary-bare-m.go b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary-bare-m.go index e4f97ba5304464..5350b197404fe1 100644 --- a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary-bare-m.go +++ b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary-bare-m.go @@ -10,10 +10,11 @@ import ( "internal/trace" "internal/trace/internal/testgen" "internal/trace/tracev2" + "internal/trace/version" ) func main() { - testgen.Main(gen) + testgen.Main(version.Go122, gen) } func gen(t *testgen.Trace) { diff --git a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary-reacquire-new-proc-bare-m.go b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary-reacquire-new-proc-bare-m.go index fc8549814f1cbe..f7611c5c0824c5 100644 --- a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary-reacquire-new-proc-bare-m.go +++ b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary-reacquire-new-proc-bare-m.go @@ -10,10 +10,11 @@ import ( "internal/trace" "internal/trace/internal/testgen" "internal/trace/tracev2" + "internal/trace/version" ) func main() { - testgen.Main(gen) + testgen.Main(version.Go122, gen) } func gen(t *testgen.Trace) { diff --git a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary-reacquire-new-proc.go b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary-reacquire-new-proc.go index 6a4f8bd1e31ff1..521363b0942b99 100644 --- a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary-reacquire-new-proc.go +++ b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary-reacquire-new-proc.go @@ -10,10 +10,11 @@ import ( "internal/trace" "internal/trace/internal/testgen" "internal/trace/tracev2" + "internal/trace/version" ) func main() { - testgen.Main(gen) + testgen.Main(version.Go122, gen) } func gen(t *testgen.Trace) { diff --git a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary.go b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary.go index 0660996f3f67d3..6c171c9cd1f89e 100644 --- a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary.go +++ b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-gen-boundary.go @@ -10,10 +10,11 @@ import ( "internal/trace" "internal/trace/internal/testgen" "internal/trace/tracev2" + "internal/trace/version" ) func main() { - testgen.Main(gen) + testgen.Main(version.Go122, gen) } func gen(t *testgen.Trace) { diff --git a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-reacquire-new-proc-bare-m.go b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-reacquire-new-proc-bare-m.go index 4a286b5eeab227..18493dd5c383aa 100644 --- a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-reacquire-new-proc-bare-m.go +++ b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-reacquire-new-proc-bare-m.go @@ -10,10 +10,11 @@ import ( "internal/trace" "internal/trace/internal/testgen" "internal/trace/tracev2" + "internal/trace/version" ) func main() { - testgen.Main(gen) + testgen.Main(version.Go122, gen) } func gen(t *testgen.Trace) { diff --git a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-reacquire-new-proc.go b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-reacquire-new-proc.go index 98ab35bad60107..d4e6ed3e2a2ed4 100644 --- a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-reacquire-new-proc.go +++ b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-reacquire-new-proc.go @@ -10,10 +10,11 @@ import ( "internal/trace" "internal/trace/internal/testgen" "internal/trace/tracev2" + "internal/trace/version" ) func main() { - testgen.Main(gen) + testgen.Main(version.Go122, gen) } func gen(t *testgen.Trace) { diff --git a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-self.go b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-self.go index 2c5aac39d693b4..6dfb465b0a1819 100644 --- a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-self.go +++ b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-self.go @@ -14,10 +14,11 @@ import ( "internal/trace" "internal/trace/internal/testgen" "internal/trace/tracev2" + "internal/trace/version" ) func main() { - testgen.Main(gen) + testgen.Main(version.Go122, gen) } func gen(t *testgen.Trace) { diff --git a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-simple-bare-m.go b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-simple-bare-m.go index 91dfa3774022e3..ac314a66478049 100644 --- a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-simple-bare-m.go +++ b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-simple-bare-m.go @@ -10,10 +10,11 @@ import ( "internal/trace" "internal/trace/internal/testgen" "internal/trace/tracev2" + "internal/trace/version" ) func main() { - testgen.Main(gen) + testgen.Main(version.Go122, gen) } func gen(t *testgen.Trace) { diff --git a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-simple.go b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-simple.go index e09a70c7c9a671..010272e5523c17 100644 --- a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-simple.go +++ b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-simple.go @@ -10,10 +10,11 @@ import ( "internal/trace" "internal/trace/internal/testgen" "internal/trace/tracev2" + "internal/trace/version" ) func main() { - testgen.Main(gen) + testgen.Main(version.Go122, gen) } func gen(t *testgen.Trace) { diff --git a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-sitting-in-syscall.go b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-sitting-in-syscall.go index d3600e43e8e7b6..410f9b7a089be8 100644 --- a/src/internal/trace/testdata/generators/go122-syscall-steal-proc-sitting-in-syscall.go +++ b/src/internal/trace/testdata/generators/go122-syscall-steal-proc-sitting-in-syscall.go @@ -11,10 +11,11 @@ import ( "internal/trace" "internal/trace/internal/testgen" "internal/trace/tracev2" + "internal/trace/version" ) func main() { - testgen.Main(gen) + testgen.Main(version.Go122, gen) } func gen(t *testgen.Trace) { diff --git a/src/internal/trace/testdata/generators/go122-task-across-generations.go b/src/internal/trace/testdata/generators/go122-task-across-generations.go index 644176a1e3093a..e8def318b403c5 100644 --- a/src/internal/trace/testdata/generators/go122-task-across-generations.go +++ b/src/internal/trace/testdata/generators/go122-task-across-generations.go @@ -16,10 +16,11 @@ import ( "internal/trace" "internal/trace/internal/testgen" "internal/trace/tracev2" + "internal/trace/version" ) func main() { - testgen.Main(gen) + testgen.Main(version.Go122, gen) } func gen(t *testgen.Trace) { From 8b8ab2584d52c96ed84207208f13a37272cab217 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Wed, 29 Jan 2025 17:16:02 +0000 Subject: [PATCH 300/397] internal/trace: merge event and tracev2 packages These two packages were historically separate in an attempt to provide a unified description of trace v1 and trace v2 formats. In practice this turned out to be pointless, since it made more sense to keep the trace v1 parser in a self-contained bubble with a converter to v2. Future trace wire format migrations should probably just follow the same general strategy, if there's a substantial change. (Minor changes can be handled more organically.) Change-Id: Ic765df62065fe53cfae59b505297527c3fa42dfb Reviewed-on: https://go-review.googlesource.com/c/go/+/645395 Auto-Submit: Michael Knyszek LUCI-TryBot-Result: Go LUCI Reviewed-by: Michael Pratt --- src/cmd/trace/main.go | 6 +- src/go/build/deps_test.go | 8 +- src/internal/trace/base.go | 5 +- src/internal/trace/batch.go | 19 ++- src/internal/trace/batchcursor.go | 3 +- src/internal/trace/event.go | 3 +- src/internal/trace/generation.go | 25 ++-- src/internal/trace/internal/testgen/trace.go | 13 +- src/internal/trace/internal/tracev1/parser.go | 121 +++++++++--------- src/internal/trace/order.go | 13 +- src/internal/trace/raw/event.go | 4 +- src/internal/trace/raw/reader.go | 6 +- src/internal/trace/raw/textreader.go | 8 +- src/internal/trace/raw/writer.go | 4 +- src/internal/trace/tracev1.go | 3 +- .../trace/tracev2/{event.go => events.go} | 72 +++++++++-- .../trace/tracev2/{event/event.go => spec.go} | 24 ++-- src/internal/trace/version/version.go | 7 +- 18 files changed, 190 insertions(+), 154 deletions(-) rename src/internal/trace/tracev2/{event.go => events.go} (86%) rename src/internal/trace/tracev2/{event/event.go => spec.go} (84%) diff --git a/src/cmd/trace/main.go b/src/cmd/trace/main.go index 625adb1c0c3d99..7786e02d00b2a7 100644 --- a/src/cmd/trace/main.go +++ b/src/cmd/trace/main.go @@ -12,7 +12,7 @@ import ( "fmt" "internal/trace" "internal/trace/raw" - "internal/trace/tracev2/event" + "internal/trace/tracev2" "internal/trace/traceviewer" "io" "log" @@ -372,13 +372,13 @@ func debugEventsFootprint(trc io.Reader) error { return err } type eventStats struct { - typ event.Type + typ tracev2.EventType count int bytes int } var stats [256]eventStats for i := range stats { - stats[i].typ = event.Type(i) + stats[i].typ = tracev2.EventType(i) } eventsRead := 0 for { diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index f2de39a0825f60..29773486dd8176 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -58,7 +58,7 @@ var depsRules = ` internal/platform, internal/profilerecord, internal/syslist, - internal/trace/tracev2/event, + internal/trace/tracev2, internal/trace/traceviewer/format, log/internal, math/bits, @@ -80,6 +80,7 @@ var depsRules = ` internal/goexperiment, internal/goos, internal/profilerecord, + internal/trace/tracev2, math/bits, structs < internal/bytealg @@ -699,16 +700,13 @@ var depsRules = ` < crypto/internal/fips140/check/checktest; # v2 execution trace parser. - internal/trace/tracev2/event - < internal/trace/tracev2; - FMT, io, internal/trace/tracev2 < internal/trace/version; FMT, encoding/binary, internal/trace/version < internal/trace/raw; - FMT, internal/trace/tracev2/event, internal/trace/version, io, sort, encoding/binary + FMT, internal/trace/version, io, sort, encoding/binary < internal/trace/internal/tracev1; FMT, encoding/binary, internal/trace/version, internal/trace/internal/tracev1, container/heap, math/rand diff --git a/src/internal/trace/base.go b/src/internal/trace/base.go index c6cc08ff69464d..5e11c6f0498a66 100644 --- a/src/internal/trace/base.go +++ b/src/internal/trace/base.go @@ -13,7 +13,6 @@ import ( "strings" "internal/trace/tracev2" - "internal/trace/tracev2/event" "internal/trace/version" ) @@ -28,7 +27,7 @@ type timedEventArgs [maxArgs - 1]uint64 // baseEvent is the basic unprocessed event. This serves as a common // fundamental data structure across. type baseEvent struct { - typ event.Type + typ tracev2.EventType time Time args timedEventArgs } @@ -59,7 +58,7 @@ type evTable struct { nextExtra extraStringID // expBatches contains extra unparsed data relevant to a specific experiment. - expBatches map[event.Experiment][]ExperimentalBatch + expBatches map[tracev2.Experiment][]ExperimentalBatch } // addExtraString adds an extra string to the evTable and returns diff --git a/src/internal/trace/batch.go b/src/internal/trace/batch.go index 0dc87321a69364..58f18d63819c53 100644 --- a/src/internal/trace/batch.go +++ b/src/internal/trace/batch.go @@ -11,7 +11,6 @@ import ( "io" "internal/trace/tracev2" - "internal/trace/tracev2/event" ) // timestamp is an unprocessed timestamp. @@ -23,23 +22,23 @@ type batch struct { m ThreadID time timestamp data []byte - exp event.Experiment + exp tracev2.Experiment } func (b *batch) isStringsBatch() bool { - return b.exp == event.NoExperiment && len(b.data) > 0 && event.Type(b.data[0]) == tracev2.EvStrings + return b.exp == tracev2.NoExperiment && len(b.data) > 0 && tracev2.EventType(b.data[0]) == tracev2.EvStrings } func (b *batch) isStacksBatch() bool { - return b.exp == event.NoExperiment && len(b.data) > 0 && event.Type(b.data[0]) == tracev2.EvStacks + return b.exp == tracev2.NoExperiment && len(b.data) > 0 && tracev2.EventType(b.data[0]) == tracev2.EvStacks } func (b *batch) isCPUSamplesBatch() bool { - return b.exp == event.NoExperiment && len(b.data) > 0 && event.Type(b.data[0]) == tracev2.EvCPUSamples + return b.exp == tracev2.NoExperiment && len(b.data) > 0 && tracev2.EventType(b.data[0]) == tracev2.EvCPUSamples } func (b *batch) isFreqBatch() bool { - return b.exp == event.NoExperiment && len(b.data) > 0 && event.Type(b.data[0]) == tracev2.EvFrequency + return b.exp == tracev2.NoExperiment && len(b.data) > 0 && tracev2.EventType(b.data[0]) == tracev2.EvFrequency } // readBatch reads the next full batch from r. @@ -52,18 +51,18 @@ func readBatch(r interface { if err != nil { return batch{}, 0, err } - if typ := event.Type(b); typ != tracev2.EvEventBatch && typ != tracev2.EvExperimentalBatch { + if typ := tracev2.EventType(b); typ != tracev2.EvEventBatch && typ != tracev2.EvExperimentalBatch { return batch{}, 0, fmt.Errorf("expected batch event, got event %d", typ) } // Read the experiment of we have one. - exp := event.NoExperiment - if event.Type(b) == tracev2.EvExperimentalBatch { + exp := tracev2.NoExperiment + if tracev2.EventType(b) == tracev2.EvExperimentalBatch { e, err := r.ReadByte() if err != nil { return batch{}, 0, err } - exp = event.Experiment(e) + exp = tracev2.Experiment(e) } // Read the batch header: gen (generation), thread (M) ID, base timestamp diff --git a/src/internal/trace/batchcursor.go b/src/internal/trace/batchcursor.go index 026f24f8b1ee61..8582f30bb06e88 100644 --- a/src/internal/trace/batchcursor.go +++ b/src/internal/trace/batchcursor.go @@ -10,7 +10,6 @@ import ( "fmt" "internal/trace/tracev2" - "internal/trace/tracev2/event" ) type batchCursor struct { @@ -66,7 +65,7 @@ func (b *batchCursor) compare(a *batchCursor) int { // be the case for every event in a plain EventBatch. func readTimedBaseEvent(b []byte, e *baseEvent) (int, timestamp, error) { // Get the event type. - typ := event.Type(b[0]) + typ := tracev2.EventType(b[0]) specs := tracev2.Specs() if int(typ) >= len(specs) { return 0, 0, fmt.Errorf("found invalid event type: %v", typ) diff --git a/src/internal/trace/event.go b/src/internal/trace/event.go index fa1daf3698004d..ebf8aaa97790ba 100644 --- a/src/internal/trace/event.go +++ b/src/internal/trace/event.go @@ -12,7 +12,6 @@ import ( "time" "internal/trace/tracev2" - "internal/trace/tracev2/event" "internal/trace/version" ) @@ -693,7 +692,7 @@ func (e Event) Experimental() ExperimentalEvent { } } -const evSync = ^event.Type(0) +const evSync = ^tracev2.EventType(0) var tracev2Type2Kind = [...]EventKind{ tracev2.EvCPUSample: EventStackSample, diff --git a/src/internal/trace/generation.go b/src/internal/trace/generation.go index 89d0f6509bbbaf..90a7f3b6c6bd0e 100644 --- a/src/internal/trace/generation.go +++ b/src/internal/trace/generation.go @@ -15,7 +15,6 @@ import ( "strings" "internal/trace/tracev2" - "internal/trace/tracev2/event" ) // generation contains all the trace data for a single @@ -166,9 +165,9 @@ func processBatch(g *generation, b batch) error { return fmt.Errorf("found multiple frequency events") } g.freq = freq - case b.exp != event.NoExperiment: + case b.exp != tracev2.NoExperiment: if g.expBatches == nil { - g.expBatches = make(map[event.Experiment][]ExperimentalBatch) + g.expBatches = make(map[tracev2.Experiment][]ExperimentalBatch) } if err := addExperimentalBatch(g.expBatches, b); err != nil { return err @@ -222,7 +221,7 @@ func addStrings(stringTable *dataTable[stringID, string], b batch) error { } r := bytes.NewReader(b.data) hdr, err := r.ReadByte() // Consume the EvStrings byte. - if err != nil || event.Type(hdr) != tracev2.EvStrings { + if err != nil || tracev2.EventType(hdr) != tracev2.EvStrings { return fmt.Errorf("missing strings batch header") } @@ -233,7 +232,7 @@ func addStrings(stringTable *dataTable[stringID, string], b batch) error { if err != nil { return err } - if event.Type(ev) != tracev2.EvString { + if tracev2.EventType(ev) != tracev2.EvString { return fmt.Errorf("expected string event, got %d", ev) } @@ -248,8 +247,8 @@ func addStrings(stringTable *dataTable[stringID, string], b batch) error { if err != nil { return err } - if len > tracev2.MaxStringSize { - return fmt.Errorf("invalid string size %d, maximum is %d", len, tracev2.MaxStringSize) + if len > tracev2.MaxEventTrailerDataSize { + return fmt.Errorf("invalid string size %d, maximum is %d", len, tracev2.MaxEventTrailerDataSize) } // Copy out the string. @@ -280,7 +279,7 @@ func addStacks(stackTable *dataTable[stackID, stack], pcs map[uint64]frame, b ba } r := bytes.NewReader(b.data) hdr, err := r.ReadByte() // Consume the EvStacks byte. - if err != nil || event.Type(hdr) != tracev2.EvStacks { + if err != nil || tracev2.EventType(hdr) != tracev2.EvStacks { return fmt.Errorf("missing stacks batch header") } @@ -290,7 +289,7 @@ func addStacks(stackTable *dataTable[stackID, stack], pcs map[uint64]frame, b ba if err != nil { return err } - if event.Type(ev) != tracev2.EvStack { + if tracev2.EventType(ev) != tracev2.EvStack { return fmt.Errorf("expected stack event, got %d", ev) } @@ -358,7 +357,7 @@ func addCPUSamples(samples []cpuSample, b batch) ([]cpuSample, error) { } r := bytes.NewReader(b.data) hdr, err := r.ReadByte() // Consume the EvCPUSamples byte. - if err != nil || event.Type(hdr) != tracev2.EvCPUSamples { + if err != nil || tracev2.EventType(hdr) != tracev2.EvCPUSamples { return nil, fmt.Errorf("missing CPU samples batch header") } @@ -368,7 +367,7 @@ func addCPUSamples(samples []cpuSample, b batch) ([]cpuSample, error) { if err != nil { return nil, err } - if event.Type(ev) != tracev2.EvCPUSample { + if tracev2.EventType(ev) != tracev2.EvCPUSample { return nil, fmt.Errorf("expected CPU sample event, got %d", ev) } @@ -441,8 +440,8 @@ func parseFreq(b batch) (frequency, error) { // addExperimentalBatch takes an experimental batch and adds it to the list of experimental // batches for the experiment its a part of. -func addExperimentalBatch(expBatches map[event.Experiment][]ExperimentalBatch, b batch) error { - if b.exp == event.NoExperiment { +func addExperimentalBatch(expBatches map[tracev2.Experiment][]ExperimentalBatch, b batch) error { + if b.exp == tracev2.NoExperiment { return fmt.Errorf("internal error: addExperimentalBatch called on non-experimental batch") } expBatches[b.exp] = append(expBatches[b.exp], ExperimentalBatch{ diff --git a/src/internal/trace/internal/testgen/trace.go b/src/internal/trace/internal/testgen/trace.go index 19d76d1367f6df..0ae7e9924ed4d5 100644 --- a/src/internal/trace/internal/testgen/trace.go +++ b/src/internal/trace/internal/testgen/trace.go @@ -15,7 +15,6 @@ import ( "internal/trace" "internal/trace/raw" "internal/trace/tracev2" - "internal/trace/tracev2/event" "internal/trace/version" "internal/txtar" ) @@ -51,8 +50,8 @@ func Main(ver version.Version, f func(*Trace)) { type Trace struct { // Trace data state. ver version.Version - names map[string]event.Type - specs []event.Spec + names map[string]tracev2.EventType + specs []tracev2.EventSpec events []raw.Event gens []*Generation validTimestamps bool @@ -65,7 +64,7 @@ type Trace struct { // NewTrace creates a new trace. func NewTrace(ver version.Version) *Trace { return &Trace{ - names: event.Names(ver.Specs()), + names: tracev2.EventNames(ver.Specs()), specs: ver.Specs(), validTimestamps: true, } @@ -86,7 +85,7 @@ func (t *Trace) ExpectSuccess() { // RawEvent emits an event into the trace. name must correspond to one // of the names in Specs() result for the version that was passed to // this trace. -func (t *Trace) RawEvent(typ event.Type, data []byte, args ...uint64) { +func (t *Trace) RawEvent(typ tracev2.EventType, data []byte, args ...uint64) { t.events = append(t.events, t.createEvent(typ, data, args...)) } @@ -146,7 +145,7 @@ func (t *Trace) Generate() []byte { }) } -func (t *Trace) createEvent(ev event.Type, data []byte, args ...uint64) raw.Event { +func (t *Trace) createEvent(ev tracev2.EventType, data []byte, args ...uint64) raw.Event { spec := t.specs[ev] if ev != tracev2.EvStack { if arity := len(spec.Args); len(args) != arity { @@ -362,7 +361,7 @@ func (b *Batch) uintArgFor(arg any, argSpec string) uint64 { // RawEvent emits an event into a batch. name must correspond to one // of the names in Specs() result for the version that was passed to // this trace. -func (b *Batch) RawEvent(typ event.Type, data []byte, args ...uint64) { +func (b *Batch) RawEvent(typ tracev2.EventType, data []byte, args ...uint64) { ev := b.gen.trace.createEvent(typ, data, args...) // Compute the size of the event and add it to the batch. diff --git a/src/internal/trace/internal/tracev1/parser.go b/src/internal/trace/internal/tracev1/parser.go index b4ec7a342c8280..d47de9088a992b 100644 --- a/src/internal/trace/internal/tracev1/parser.go +++ b/src/internal/trace/internal/tracev1/parser.go @@ -17,7 +17,6 @@ import ( "encoding/binary" "errors" "fmt" - "internal/trace/tracev2/event" "internal/trace/version" "io" "math" @@ -36,12 +35,12 @@ type Event struct { // pointers, the latter so that the garbage collector won't have to scan any // memory of our millions of events. - Ts Timestamp // timestamp in nanoseconds - G uint64 // G on which the event happened - Args [4]uint64 // event-type-specific arguments - StkID uint32 // unique stack ID - P int32 // P on which the event happened (can be a real P or one of TimerP, NetpollP, SyscallP) - Type event.Type // one of Ev* + Ts Timestamp // timestamp in nanoseconds + G uint64 // G on which the event happened + Args [4]uint64 // event-type-specific arguments + StkID uint32 // unique stack ID + P int32 // P on which the event happened (can be a real P or one of TimerP, NetpollP, SyscallP) + Type EventType // one of Ev* } // Frame is a frame in stack traces. @@ -253,7 +252,7 @@ func (p *parser) parse() (Trace, error) { // rawEvent is a helper type used during parsing. type rawEvent struct { - typ event.Type + typ EventType args []uint64 sargs []string @@ -643,7 +642,7 @@ func (p *parser) readRawEvent(flags uint, ev *rawEvent) error { if !ok { return io.EOF } - typ := event.Type(b << 2 >> 2) + typ := EventType(b << 2 >> 2) // Most events have a timestamp before the actual arguments, so we add 1 and // parse it like it's the first argument. EvString has a special format and // the number of arguments doesn't matter. EvBatch writes '1' as the number @@ -1376,60 +1375,62 @@ func (raw *rawEvent) argNum() int { return narg } +type EventType uint8 + // Event types in the trace. // Verbatim copy from src/runtime/trace.go with the "trace" prefix removed. const ( - EvNone event.Type = 0 // unused - EvBatch event.Type = 1 // start of per-P batch of events [pid, timestamp] - EvFrequency event.Type = 2 // contains tracer timer frequency [frequency (ticks per second)] - EvStack event.Type = 3 // stack [stack id, number of PCs, array of {PC, func string ID, file string ID, line}] - EvGomaxprocs event.Type = 4 // current value of GOMAXPROCS [timestamp, GOMAXPROCS, stack id] - EvProcStart event.Type = 5 // start of P [timestamp, thread id] - EvProcStop event.Type = 6 // stop of P [timestamp] - EvGCStart event.Type = 7 // GC start [timestamp, seq, stack id] - EvGCDone event.Type = 8 // GC done [timestamp] - EvSTWStart event.Type = 9 // GC mark termination start [timestamp, kind] - EvSTWDone event.Type = 10 // GC mark termination done [timestamp] - EvGCSweepStart event.Type = 11 // GC sweep start [timestamp, stack id] - EvGCSweepDone event.Type = 12 // GC sweep done [timestamp, swept, reclaimed] - EvGoCreate event.Type = 13 // goroutine creation [timestamp, new goroutine id, new stack id, stack id] - EvGoStart event.Type = 14 // goroutine starts running [timestamp, goroutine id, seq] - EvGoEnd event.Type = 15 // goroutine ends [timestamp] - EvGoStop event.Type = 16 // goroutine stops (like in select{}) [timestamp, stack] - EvGoSched event.Type = 17 // goroutine calls Gosched [timestamp, stack] - EvGoPreempt event.Type = 18 // goroutine is preempted [timestamp, stack] - EvGoSleep event.Type = 19 // goroutine calls Sleep [timestamp, stack] - EvGoBlock event.Type = 20 // goroutine blocks [timestamp, stack] - EvGoUnblock event.Type = 21 // goroutine is unblocked [timestamp, goroutine id, seq, stack] - EvGoBlockSend event.Type = 22 // goroutine blocks on chan send [timestamp, stack] - EvGoBlockRecv event.Type = 23 // goroutine blocks on chan recv [timestamp, stack] - EvGoBlockSelect event.Type = 24 // goroutine blocks on select [timestamp, stack] - EvGoBlockSync event.Type = 25 // goroutine blocks on Mutex/RWMutex [timestamp, stack] - EvGoBlockCond event.Type = 26 // goroutine blocks on Cond [timestamp, stack] - EvGoBlockNet event.Type = 27 // goroutine blocks on network [timestamp, stack] - EvGoSysCall event.Type = 28 // syscall enter [timestamp, stack] - EvGoSysExit event.Type = 29 // syscall exit [timestamp, goroutine id, seq, real timestamp] - EvGoSysBlock event.Type = 30 // syscall blocks [timestamp] - EvGoWaiting event.Type = 31 // denotes that goroutine is blocked when tracing starts [timestamp, goroutine id] - EvGoInSyscall event.Type = 32 // denotes that goroutine is in syscall when tracing starts [timestamp, goroutine id] - EvHeapAlloc event.Type = 33 // gcController.heapLive change [timestamp, heap live bytes] - EvHeapGoal event.Type = 34 // gcController.heapGoal change [timestamp, heap goal bytes] - EvTimerGoroutine event.Type = 35 // denotes timer goroutine [timer goroutine id] - EvFutileWakeup event.Type = 36 // denotes that the previous wakeup of this goroutine was futile [timestamp] - EvString event.Type = 37 // string dictionary entry [ID, length, string] - EvGoStartLocal event.Type = 38 // goroutine starts running on the same P as the last event [timestamp, goroutine id] - EvGoUnblockLocal event.Type = 39 // goroutine is unblocked on the same P as the last event [timestamp, goroutine id, stack] - EvGoSysExitLocal event.Type = 40 // syscall exit on the same P as the last event [timestamp, goroutine id, real timestamp] - EvGoStartLabel event.Type = 41 // goroutine starts running with label [timestamp, goroutine id, seq, label string id] - EvGoBlockGC event.Type = 42 // goroutine blocks on GC assist [timestamp, stack] - EvGCMarkAssistStart event.Type = 43 // GC mark assist start [timestamp, stack] - EvGCMarkAssistDone event.Type = 44 // GC mark assist done [timestamp] - EvUserTaskCreate event.Type = 45 // trace.NewTask [timestamp, internal task id, internal parent id, stack, name string] - EvUserTaskEnd event.Type = 46 // end of task [timestamp, internal task id, stack] - EvUserRegion event.Type = 47 // trace.WithRegion [timestamp, internal task id, mode(0:start, 1:end), name string] - EvUserLog event.Type = 48 // trace.Log [timestamp, internal id, key string id, stack, value string] - EvCPUSample event.Type = 49 // CPU profiling sample [timestamp, stack, real timestamp, real P id (-1 when absent), goroutine id] - EvCount event.Type = 50 + EvNone EventType = 0 // unused + EvBatch EventType = 1 // start of per-P batch of events [pid, timestamp] + EvFrequency EventType = 2 // contains tracer timer frequency [frequency (ticks per second)] + EvStack EventType = 3 // stack [stack id, number of PCs, array of {PC, func string ID, file string ID, line}] + EvGomaxprocs EventType = 4 // current value of GOMAXPROCS [timestamp, GOMAXPROCS, stack id] + EvProcStart EventType = 5 // start of P [timestamp, thread id] + EvProcStop EventType = 6 // stop of P [timestamp] + EvGCStart EventType = 7 // GC start [timestamp, seq, stack id] + EvGCDone EventType = 8 // GC done [timestamp] + EvSTWStart EventType = 9 // GC mark termination start [timestamp, kind] + EvSTWDone EventType = 10 // GC mark termination done [timestamp] + EvGCSweepStart EventType = 11 // GC sweep start [timestamp, stack id] + EvGCSweepDone EventType = 12 // GC sweep done [timestamp, swept, reclaimed] + EvGoCreate EventType = 13 // goroutine creation [timestamp, new goroutine id, new stack id, stack id] + EvGoStart EventType = 14 // goroutine starts running [timestamp, goroutine id, seq] + EvGoEnd EventType = 15 // goroutine ends [timestamp] + EvGoStop EventType = 16 // goroutine stops (like in select{}) [timestamp, stack] + EvGoSched EventType = 17 // goroutine calls Gosched [timestamp, stack] + EvGoPreempt EventType = 18 // goroutine is preempted [timestamp, stack] + EvGoSleep EventType = 19 // goroutine calls Sleep [timestamp, stack] + EvGoBlock EventType = 20 // goroutine blocks [timestamp, stack] + EvGoUnblock EventType = 21 // goroutine is unblocked [timestamp, goroutine id, seq, stack] + EvGoBlockSend EventType = 22 // goroutine blocks on chan send [timestamp, stack] + EvGoBlockRecv EventType = 23 // goroutine blocks on chan recv [timestamp, stack] + EvGoBlockSelect EventType = 24 // goroutine blocks on select [timestamp, stack] + EvGoBlockSync EventType = 25 // goroutine blocks on Mutex/RWMutex [timestamp, stack] + EvGoBlockCond EventType = 26 // goroutine blocks on Cond [timestamp, stack] + EvGoBlockNet EventType = 27 // goroutine blocks on network [timestamp, stack] + EvGoSysCall EventType = 28 // syscall enter [timestamp, stack] + EvGoSysExit EventType = 29 // syscall exit [timestamp, goroutine id, seq, real timestamp] + EvGoSysBlock EventType = 30 // syscall blocks [timestamp] + EvGoWaiting EventType = 31 // denotes that goroutine is blocked when tracing starts [timestamp, goroutine id] + EvGoInSyscall EventType = 32 // denotes that goroutine is in syscall when tracing starts [timestamp, goroutine id] + EvHeapAlloc EventType = 33 // gcController.heapLive change [timestamp, heap live bytes] + EvHeapGoal EventType = 34 // gcController.heapGoal change [timestamp, heap goal bytes] + EvTimerGoroutine EventType = 35 // denotes timer goroutine [timer goroutine id] + EvFutileWakeup EventType = 36 // denotes that the previous wakeup of this goroutine was futile [timestamp] + EvString EventType = 37 // string dictionary entry [ID, length, string] + EvGoStartLocal EventType = 38 // goroutine starts running on the same P as the last event [timestamp, goroutine id] + EvGoUnblockLocal EventType = 39 // goroutine is unblocked on the same P as the last event [timestamp, goroutine id, stack] + EvGoSysExitLocal EventType = 40 // syscall exit on the same P as the last event [timestamp, goroutine id, real timestamp] + EvGoStartLabel EventType = 41 // goroutine starts running with label [timestamp, goroutine id, seq, label string id] + EvGoBlockGC EventType = 42 // goroutine blocks on GC assist [timestamp, stack] + EvGCMarkAssistStart EventType = 43 // GC mark assist start [timestamp, stack] + EvGCMarkAssistDone EventType = 44 // GC mark assist done [timestamp] + EvUserTaskCreate EventType = 45 // trace.NewTask [timestamp, internal task id, internal parent id, stack, name string] + EvUserTaskEnd EventType = 46 // end of task [timestamp, internal task id, stack] + EvUserRegion EventType = 47 // trace.WithRegion [timestamp, internal task id, mode(0:start, 1:end), name string] + EvUserLog EventType = 48 // trace.Log [timestamp, internal id, key string id, stack, value string] + EvCPUSample EventType = 49 // CPU profiling sample [timestamp, stack, real timestamp, real P id (-1 when absent), goroutine id] + EvCount EventType = 50 ) var EventDescriptions = [256]struct { diff --git a/src/internal/trace/order.go b/src/internal/trace/order.go index 3e7ed8941b55e1..7b6075d5637732 100644 --- a/src/internal/trace/order.go +++ b/src/internal/trace/order.go @@ -10,7 +10,6 @@ import ( "strings" "internal/trace/tracev2" - "internal/trace/tracev2/event" "internal/trace/version" ) @@ -89,7 +88,7 @@ func (o *ordering) Advance(ev *baseEvent, evt *evTable, m ThreadID, gen uint64) return ok, err } -func (o *ordering) evName(typ event.Type) string { +func (o *ordering) evName(typ tracev2.EventType) string { return o.traceVer.EventName(typ) } @@ -1167,12 +1166,12 @@ type userRegion struct { // they may have an optional subtype that describes the range // in more detail. type rangeType struct { - typ event.Type // "Begin" event. - desc stringID // Optional subtype. + typ tracev2.EventType // "Begin" event. + desc stringID // Optional subtype. } // makeRangeType constructs a new rangeType. -func makeRangeType(typ event.Type, desc stringID) rangeType { +func makeRangeType(typ tracev2.EventType, desc stringID) rangeType { if styp := tracev2.Specs()[typ].StartEv; styp != tracev2.EvNone { typ = styp } @@ -1266,7 +1265,7 @@ func (s *rangeState) hasRange(typ rangeType) bool { // endRange ends a special range in time on the goroutine. // // This must line up with the start event type of the range the goroutine is currently in. -func (s *rangeState) endRange(typ event.Type) (stringID, error) { +func (s *rangeState) endRange(typ tracev2.EventType) (stringID, error) { st := tracev2.Specs()[typ].StartEv idx := -1 for i, r := range s.inFlight { @@ -1386,7 +1385,7 @@ func (q *queue[T]) pop() (T, bool) { // It's just a convenience function; it's always OK to construct // an Event manually if this isn't quite the right way to express // the contents of the event. -func makeEvent(table *evTable, ctx schedCtx, typ event.Type, time Time, args ...uint64) Event { +func makeEvent(table *evTable, ctx schedCtx, typ tracev2.EventType, time Time, args ...uint64) Event { ev := Event{ table: table, ctx: ctx, diff --git a/src/internal/trace/raw/event.go b/src/internal/trace/raw/event.go index e3b6b5cd458f7c..9042d3f2151eb4 100644 --- a/src/internal/trace/raw/event.go +++ b/src/internal/trace/raw/event.go @@ -9,7 +9,7 @@ import ( "strconv" "strings" - "internal/trace/tracev2/event" + "internal/trace/tracev2" "internal/trace/version" ) @@ -20,7 +20,7 @@ import ( // trace format's framing. (But not interpreted.) type Event struct { Version version.Version - Ev event.Type + Ev tracev2.EventType Args []uint64 Data []byte } diff --git a/src/internal/trace/raw/reader.go b/src/internal/trace/raw/reader.go index 3f90e2d454725d..af5dfac0e77a72 100644 --- a/src/internal/trace/raw/reader.go +++ b/src/internal/trace/raw/reader.go @@ -10,7 +10,7 @@ import ( "fmt" "io" - "internal/trace/tracev2/event" + "internal/trace/tracev2" "internal/trace/version" ) @@ -19,7 +19,7 @@ import ( type Reader struct { r *bufio.Reader v version.Version - specs []event.Spec + specs []tracev2.EventSpec } // NewReader creates a new reader for the trace wire format. @@ -49,7 +49,7 @@ func (r *Reader) ReadEvent() (Event, error) { if int(evb) >= len(r.specs) || evb == 0 { return Event{}, fmt.Errorf("invalid event type: %d", evb) } - ev := event.Type(evb) + ev := tracev2.EventType(evb) spec := r.specs[ev] args, err := r.readArgs(len(spec.Args)) if err != nil { diff --git a/src/internal/trace/raw/textreader.go b/src/internal/trace/raw/textreader.go index 666db134f1a9d1..adb111550d1ee7 100644 --- a/src/internal/trace/raw/textreader.go +++ b/src/internal/trace/raw/textreader.go @@ -12,7 +12,7 @@ import ( "strings" "unicode" - "internal/trace/tracev2/event" + "internal/trace/tracev2" "internal/trace/version" ) @@ -20,8 +20,8 @@ import ( // into an event stream. type TextReader struct { v version.Version - specs []event.Spec - names map[string]event.Type + specs []tracev2.EventSpec + names map[string]tracev2.EventType s *bufio.Scanner } @@ -50,7 +50,7 @@ func NewTextReader(r io.Reader) (*TextReader, error) { } tr.v = v tr.specs = v.Specs() - tr.names = event.Names(tr.specs) + tr.names = tracev2.EventNames(tr.specs) for _, r := range line { if !unicode.IsSpace(r) { return nil, fmt.Errorf("encountered unexpected non-space at the end of the header: %q", line) diff --git a/src/internal/trace/raw/writer.go b/src/internal/trace/raw/writer.go index 971839b8d71fc3..6b7042cf2af101 100644 --- a/src/internal/trace/raw/writer.go +++ b/src/internal/trace/raw/writer.go @@ -9,7 +9,7 @@ import ( "fmt" "io" - "internal/trace/tracev2/event" + "internal/trace/tracev2" "internal/trace/version" ) @@ -23,7 +23,7 @@ type Writer struct { w io.Writer buf []byte v version.Version - specs []event.Spec + specs []tracev2.EventSpec } // NewWriter creates a new byte format writer. diff --git a/src/internal/trace/tracev1.go b/src/internal/trace/tracev1.go index 9c2a1ebc14c6b5..667d7be1cd1b4b 100644 --- a/src/internal/trace/tracev1.go +++ b/src/internal/trace/tracev1.go @@ -32,7 +32,6 @@ import ( "fmt" "internal/trace/internal/tracev1" "internal/trace/tracev2" - "internal/trace/tracev2/event" "io" ) @@ -253,7 +252,7 @@ var errSkip = errors.New("skip event") // encountering events that tracev1 shouldn't be able to emit, ocnvertEvent // returns a descriptive error. func (it *traceV1Converter) convertEvent(ev *tracev1.Event) (OUT Event, ERR error) { - var mappedType event.Type + var mappedType tracev2.EventType var mappedArgs timedEventArgs copy(mappedArgs[:], ev.Args[:]) diff --git a/src/internal/trace/tracev2/event.go b/src/internal/trace/tracev2/events.go similarity index 86% rename from src/internal/trace/tracev2/event.go rename to src/internal/trace/tracev2/events.go index 308ae679e977a0..778ef8d005b9ed 100644 --- a/src/internal/trace/tracev2/event.go +++ b/src/internal/trace/tracev2/events.go @@ -4,12 +4,17 @@ package tracev2 -import ( - "internal/trace/tracev2/event" -) - +// Event types in the trace, args are given in square brackets. +// +// Naming scheme: +// - Time range event pairs have suffixes "Begin" and "End". +// - "Start", "Stop", "Create", "Destroy", "Block", "Unblock" +// are suffixes reserved for scheduling resources. +// +// NOTE: If you add an event type, make sure you also update all +// tables in this file! const ( - EvNone event.Type = iota // unused + EvNone EventType = iota // unused // Structural events. EvEventBatch // start of per-M batch of events [generation, M ID, timestamp, batch length] @@ -82,7 +87,9 @@ const ( // Experiments. const ( // AllocFree is the alloc-free events experiment. - AllocFree event.Experiment = 1 + iota + AllocFree Experiment = 1 + iota + + NumExperiments ) func Experiments() []string { @@ -90,12 +97,13 @@ func Experiments() []string { } var experiments = [...]string{ - AllocFree: "AllocFree", + NoExperiment: "None", + AllocFree: "AllocFree", } // Experimental events. const ( - _ event.Type = 127 + iota + _ EventType = 127 + iota // Experimental events for AllocFree. @@ -115,11 +123,11 @@ const ( EvGoroutineStackFree // stack free [timestamp, id] ) -func Specs() []event.Spec { +func Specs() []EventSpec { return specs[:] } -var specs = [...]event.Spec{ +var specs = [...]EventSpec{ // "Structural" Events. EvEventBatch: { Name: "EventBatch", @@ -456,6 +464,9 @@ var specs = [...]event.Spec{ }, } +// GoStatus is the status of a goroutine. +// +// They correspond directly to the various goroutine states. type GoStatus uint8 const ( @@ -480,6 +491,9 @@ func (s GoStatus) String() string { return "Bad" } +// ProcStatus is the status of a P. +// +// They mostly correspond to the various P states. type ProcStatus uint8 const ( @@ -487,6 +501,16 @@ const ( ProcRunning ProcIdle ProcSyscall + + // ProcSyscallAbandoned is a special case of + // ProcSyscall. It's used in the very specific case + // where the first a P is mentioned in a generation is + // part of a ProcSteal event. If that's the first time + // it's mentioned, then there's no GoSyscallBegin to + // connect the P stealing back to at that point. This + // special state indicates this to the parser, so it + // doesn't try to find a GoSyscallEndBlocked that + // corresponds with the ProcSteal. ProcSyscallAbandoned ) @@ -503,8 +527,30 @@ func (s ProcStatus) String() string { } const ( - // Various format-specific constants. - MaxBatchSize = 64 << 10 + // MaxBatchSize sets the maximum size that a batch can be. + // + // Directly controls the trace batch size in the runtime. + // + // NOTE: If this number decreases, the trace format version must change. + MaxBatchSize = 64 << 10 + + // Maximum number of PCs in a single stack trace. + // + // Since events contain only stack ID rather than whole stack trace, + // we can allow quite large values here. + // + // Directly controls the maximum number of frames per stack + // in the runtime. + // + // NOTE: If this number decreases, the trace format version must change. MaxFramesPerStack = 128 - MaxStringSize = 1 << 10 + + // MaxEventTrailerDataSize controls the amount of trailer data that + // an event can have in bytes. Must be smaller than MaxBatchSize. + // Controls the maximum string size in the trace. + // + // Directly controls the maximum such value in the runtime. + // + // NOTE: If this number decreases, the trace format version must change. + MaxEventTrailerDataSize = 1 << 10 ) diff --git a/src/internal/trace/tracev2/event/event.go b/src/internal/trace/tracev2/spec.go similarity index 84% rename from src/internal/trace/tracev2/event/event.go rename to src/internal/trace/tracev2/spec.go index b8b6af00533231..3ea3c5988908b4 100644 --- a/src/internal/trace/tracev2/event/event.go +++ b/src/internal/trace/tracev2/spec.go @@ -2,16 +2,16 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package event +package tracev2 -// Type indicates an event's type from which its arguments and semantics can be +// EventType indicates an event's type from which its arguments and semantics can be // derived. Its representation matches the wire format's representation of the event // types that precede all event data. -type Type uint8 +type EventType uint8 -// Spec is a specification for a trace event. It contains sufficient information +// EventSpec is a specification for a trace event. It contains sufficient information // to perform basic parsing of any trace event for any version of Go. -type Spec struct { +type EventSpec struct { // Name is the human-readable name of the trace event. Name string @@ -42,7 +42,7 @@ type Spec struct { // StartEv indicates the event type of the corresponding "start" // event, if this event is an "end," for a pair of events that // represent a time range. - StartEv Type + StartEv EventType // IsTimedEvent indicates whether this is an event that both // appears in the main event stream and is surfaced to the @@ -72,10 +72,10 @@ type Spec struct { Experiment Experiment } -// ArgTypes is a list of valid argument types for use in Args. +// EventArgTypes is a list of valid argument types for use in Args. // // See the documentation of Args for more details. -var ArgTypes = [...]string{ +var EventArgTypes = [...]string{ "seq", // sequence number "pstatus", // P status "gstatus", // G status @@ -88,11 +88,11 @@ var ArgTypes = [...]string{ "task", // trace.TaskID } -// Names is a helper that produces a mapping of event names to event types. -func Names(specs []Spec) map[string]Type { - nameToType := make(map[string]Type) +// EventNames is a helper that produces a mapping of event names to event types. +func EventNames(specs []EventSpec) map[string]EventType { + nameToType := make(map[string]EventType) for i, spec := range specs { - nameToType[spec.Name] = Type(byte(i)) + nameToType[spec.Name] = EventType(byte(i)) } return nameToType } diff --git a/src/internal/trace/version/version.go b/src/internal/trace/version/version.go index 50a674bd234cdb..8c460734cef268 100644 --- a/src/internal/trace/version/version.go +++ b/src/internal/trace/version/version.go @@ -9,7 +9,6 @@ import ( "io" "internal/trace/tracev2" - "internal/trace/tracev2/event" ) // Version represents the version of a trace file. @@ -24,7 +23,7 @@ const ( Current = Go123 ) -var versions = map[Version][]event.Spec{ +var versions = map[Version][]tracev2.EventSpec{ // Go 1.11–1.21 use a different parser and are only set here for the sake of // Version.Valid. Go111: nil, @@ -36,13 +35,13 @@ var versions = map[Version][]event.Spec{ } // Specs returns the set of event.Specs for this version. -func (v Version) Specs() []event.Spec { +func (v Version) Specs() []tracev2.EventSpec { return versions[v] } // EventName returns a string name of a wire format event // for a particular trace version. -func (v Version) EventName(typ event.Type) string { +func (v Version) EventName(typ tracev2.EventType) string { if !v.Valid() { return "" } From 6fd3ce52bbc628225e67f8811ff2f6db17a7bec6 Mon Sep 17 00:00:00 2001 From: Tom Thorogood Date: Sun, 9 Feb 2025 12:42:25 +1030 Subject: [PATCH 301/397] net/http: use standard time formatting methods time.Time has had an AppendFormat method since go1.5 so there's no need to carry around a custom implementation. Change-Id: I8e7e5a9ac34e8bf251f5d70555405777ce4e22a8 Reviewed-on: https://go-review.googlesource.com/c/go/+/647955 LUCI-TryBot-Result: Go LUCI Reviewed-by: Dmitri Shuralyov Reviewed-by: Damien Neil Auto-Submit: Ian Lance Taylor --- src/net/http/export_test.go | 1 - src/net/http/serve_test.go | 13 ------------- src/net/http/server.go | 24 +----------------------- 3 files changed, 1 insertion(+), 37 deletions(-) diff --git a/src/net/http/export_test.go b/src/net/http/export_test.go index 56ebda180bb085..f2aa663a990d5f 100644 --- a/src/net/http/export_test.go +++ b/src/net/http/export_test.go @@ -21,7 +21,6 @@ import ( var ( DefaultUserAgent = defaultUserAgent NewLoggingConn = newLoggingConn - ExportAppendTime = appendTime ExportRefererForURL = refererForURL ExportServerNewConn = (*Server).newConn ExportCloseWriteAndWait = (*conn).closeWriteAndWait diff --git a/src/net/http/serve_test.go b/src/net/http/serve_test.go index 0c46b1ecc3e0b1..e551732016e81e 100644 --- a/src/net/http/serve_test.go +++ b/src/net/http/serve_test.go @@ -4302,19 +4302,6 @@ func TestResponseWriterWriteString(t *testing.T) { } } -func TestAppendTime(t *testing.T) { - var b [len(TimeFormat)]byte - t1 := time.Date(2013, 9, 21, 15, 41, 0, 0, time.FixedZone("CEST", 2*60*60)) - res := ExportAppendTime(b[:0], t1) - t2, err := ParseTime(string(res)) - if err != nil { - t.Fatalf("Error parsing time: %s", err) - } - if !t1.Equal(t2) { - t.Fatalf("Times differ; expected: %v, got %v (%s)", t1, t2, string(res)) - } -} - func TestServerConnState(t *testing.T) { run(t, testServerConnState, []testMode{http1Mode}) } func testServerConnState(t *testing.T, mode testMode) { handler := map[string]func(w ResponseWriter, r *Request){ diff --git a/src/net/http/server.go b/src/net/http/server.go index cbdc9dd0e3af60..439efa0c753068 100644 --- a/src/net/http/server.go +++ b/src/net/http/server.go @@ -991,28 +991,6 @@ func (ecr *expectContinueReader) Close() error { // For parsing this time format, see [ParseTime]. const TimeFormat = "Mon, 02 Jan 2006 15:04:05 GMT" -// appendTime is a non-allocating version of []byte(t.UTC().Format(TimeFormat)) -func appendTime(b []byte, t time.Time) []byte { - const days = "SunMonTueWedThuFriSat" - const months = "JanFebMarAprMayJunJulAugSepOctNovDec" - - t = t.UTC() - yy, mm, dd := t.Date() - hh, mn, ss := t.Clock() - day := days[3*t.Weekday():] - mon := months[3*(mm-1):] - - return append(b, - day[0], day[1], day[2], ',', ' ', - byte('0'+dd/10), byte('0'+dd%10), ' ', - mon[0], mon[1], mon[2], ' ', - byte('0'+yy/1000), byte('0'+(yy/100)%10), byte('0'+(yy/10)%10), byte('0'+yy%10), ' ', - byte('0'+hh/10), byte('0'+hh%10), ':', - byte('0'+mn/10), byte('0'+mn%10), ':', - byte('0'+ss/10), byte('0'+ss%10), ' ', - 'G', 'M', 'T') -} - var errTooLarge = errors.New("http: request too large") // Read next request from connection. @@ -1506,7 +1484,7 @@ func (cw *chunkWriter) writeHeader(p []byte) { } if !header.has("Date") { - setHeader.date = appendTime(cw.res.dateBuf[:0], time.Now()) + setHeader.date = time.Now().UTC().AppendFormat(cw.res.dateBuf[:0], TimeFormat) } if hasCL && hasTE && te != "identity" { From 7715ca32fcaad84059752c944f40768374796651 Mon Sep 17 00:00:00 2001 From: apocelipes Date: Sat, 8 Feb 2025 01:15:29 +0000 Subject: [PATCH 302/397] database/sql: use t.Context in tests Replace "context.WithCancel(context.Background())" with "t.Context()". Updates #36532 Change-Id: I78a8ba422f076f4c697910922cf6dc35c628b1a7 GitHub-Last-Rev: 2eacdbe9ea97ac8d928704c2b605b276626d95dd GitHub-Pull-Request: golang/go#71599 Reviewed-on: https://go-review.googlesource.com/c/go/+/647555 Reviewed-by: Jorropo LUCI-TryBot-Result: Go LUCI Auto-Submit: Ian Lance Taylor Reviewed-by: Dmitri Shuralyov Reviewed-by: Cherry Mui --- src/database/sql/sql_test.go | 32 ++++++++++---------------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/src/database/sql/sql_test.go b/src/database/sql/sql_test.go index db1d8b3c6b65ef..74b9bf550249c7 100644 --- a/src/database/sql/sql_test.go +++ b/src/database/sql/sql_test.go @@ -1374,8 +1374,7 @@ func TestConnQuery(t *testing.T) { db := newTestDB(t, "people") defer closeDB(t, db) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() conn, err := db.Conn(ctx) if err != nil { t.Fatal(err) @@ -1402,8 +1401,7 @@ func TestConnRaw(t *testing.T) { db := newTestDB(t, "people") defer closeDB(t, db) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() conn, err := db.Conn(ctx) if err != nil { t.Fatal(err) @@ -1518,8 +1516,7 @@ func TestInvalidNilValues(t *testing.T) { db := newTestDB(t, "people") defer closeDB(t, db) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() conn, err := db.Conn(ctx) if err != nil { t.Fatal(err) @@ -1547,8 +1544,7 @@ func TestConnTx(t *testing.T) { db := newTestDB(t, "people") defer closeDB(t, db) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() conn, err := db.Conn(ctx) if err != nil { t.Fatal(err) @@ -2793,8 +2789,7 @@ func TestManyErrBadConn(t *testing.T) { // Conn db = manyErrBadConnSetup() defer closeDB(t, db) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() conn, err := db.Conn(ctx) if err != nil { t.Fatal(err) @@ -2935,8 +2930,7 @@ func TestConnExpiresFreshOutOfPool(t *testing.T) { } defer func() { nowFunc = time.Now }() - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() db := newTestDB(t, "magicquery") defer closeDB(t, db) @@ -3786,8 +3780,7 @@ func TestIssue20647(t *testing.T) { db := newTestDB(t, "people") defer closeDB(t, db) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() conn, err := db.Conn(ctx) if err != nil { @@ -4142,9 +4135,7 @@ func TestNamedValueChecker(t *testing.T) { } defer db.Close() - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - + ctx := t.Context() _, err = db.ExecContext(ctx, "WIPE") if err != nil { t.Fatal("exec wipe", err) @@ -4192,9 +4183,7 @@ func TestNamedValueCheckerSkip(t *testing.T) { } defer db.Close() - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - + ctx := t.Context() _, err = db.ExecContext(ctx, "WIPE") if err != nil { t.Fatal("exec wipe", err) @@ -4305,8 +4294,7 @@ func TestQueryExecContextOnly(t *testing.T) { } defer db.Close() - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() conn, err := db.Conn(ctx) if err != nil { From 3105e3dca7be281cb12ff5cc88349c26827edfd0 Mon Sep 17 00:00:00 2001 From: WANG Xuerui Date: Sun, 9 Feb 2025 18:57:49 +0800 Subject: [PATCH 303/397] cmd/go/internal/work: allow a bunch of loong64-specific flags Recognize and allow all LoongArch-specific CFLAGS as standardized in the LoongArch Toolchain Conventions v1.1, and implemented in current versions of GCC and Clang, to enable advanced cgo use cases on loong64. These flags are also allowed for linker invocations in case of possible LTO. See: https://github.com/loongson/la-toolchain-conventions/blob/releases/v1.1/LoongArch-toolchain-conventions-EN.adoc#list While at it, also add support for -mtls-dialect as some C programs may benefit performance-wise from the optional TLSDESC usage. This flag is not specific to loong64 though; it is available for amd64, arm, arm64, loong64, riscv64 and x86. Fixes #71597. Change-Id: I35d2507edb71fa324ae429a3ae3c739644a9cac1 Reviewed-on: https://go-review.googlesource.com/c/go/+/647956 LUCI-TryBot-Result: Go LUCI Commit-Queue: Ian Lance Taylor Reviewed-by: Ian Lance Taylor Auto-Submit: Ian Lance Taylor Reviewed-by: Cherry Mui Reviewed-by: abner chenc Reviewed-by: Meidan Li --- src/cmd/go/internal/work/security.go | 13 ++++++++-- src/cmd/go/internal/work/security_test.go | 31 +++++++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/cmd/go/internal/work/security.go b/src/cmd/go/internal/work/security.go index 50bfd0ab705383..c3d62ddc23d83a 100644 --- a/src/cmd/go/internal/work/security.go +++ b/src/cmd/go/internal/work/security.go @@ -96,17 +96,21 @@ var validCompilerFlags = []*lazyregexp.Regexp{ re(`-g([^@\-].*)?`), re(`-m32`), re(`-m64`), - re(`-m(abi|arch|cpu|fpu|tune)=([^@\-].*)`), + re(`-m(abi|arch|cpu|fpu|simd|tls-dialect|tune)=([^@\-].*)`), re(`-m(no-)?v?aes`), re(`-marm`), re(`-m(no-)?avx[0-9a-z]*`), re(`-mcmodel=[0-9a-z-]+`), re(`-mfloat-abi=([^@\-].*)`), + re(`-m(soft|single|double)-float`), re(`-mfpmath=[0-9a-z,+]*`), re(`-m(no-)?avx[0-9a-z.]*`), re(`-m(no-)?ms-bitfields`), re(`-m(no-)?stack-(.+)`), re(`-mmacosx-(.+)`), + re(`-m(no-)?relax`), + re(`-m(no-)?strict-align`), + re(`-m(no-)?(lsx|lasx|frecipe|div32|lam-bh|lamcas|ld-seq-sa)`), re(`-mios-simulator-version-min=(.+)`), re(`-miphoneos-version-min=(.+)`), re(`-mlarge-data-threshold=[0-9]+`), @@ -166,8 +170,13 @@ var validLinkerFlags = []*lazyregexp.Regexp{ re(`-flat_namespace`), re(`-g([^@\-].*)?`), re(`-headerpad_max_install_names`), - re(`-m(abi|arch|cpu|fpu|tune)=([^@\-].*)`), + re(`-m(abi|arch|cpu|fpu|simd|tls-dialect|tune)=([^@\-].*)`), + re(`-mcmodel=[0-9a-z-]+`), re(`-mfloat-abi=([^@\-].*)`), + re(`-m(soft|single|double)-float`), + re(`-m(no-)?relax`), + re(`-m(no-)?strict-align`), + re(`-m(no-)?(lsx|lasx|frecipe|div32|lam-bh|lamcas|ld-seq-sa)`), re(`-mmacosx-(.+)`), re(`-mios-simulator-version-min=(.+)`), re(`-miphoneos-version-min=(.+)`), diff --git a/src/cmd/go/internal/work/security_test.go b/src/cmd/go/internal/work/security_test.go index 35af62176472b4..48f98100a51bd1 100644 --- a/src/cmd/go/internal/work/security_test.go +++ b/src/cmd/go/internal/work/security_test.go @@ -50,10 +50,35 @@ var goodCompilerFlags = [][]string{ {"-ftls-model=local-dynamic"}, {"-g"}, {"-ggdb"}, + {"-mabi=lp64d"}, {"-march=souza"}, {"-mcmodel=medium"}, {"-mcpu=123"}, {"-mfpu=123"}, + {"-mtls-dialect=gnu"}, + {"-mtls-dialect=gnu2"}, + {"-mtls-dialect=trad"}, + {"-mtls-dialect=desc"}, + {"-mtls-dialect=xyz"}, + {"-msimd=lasx"}, + {"-msimd=xyz"}, + {"-mdouble-float"}, + {"-mrelax"}, + {"-mstrict-align"}, + {"-mlsx"}, + {"-mlasx"}, + {"-mfrecipe"}, + {"-mlam-bh"}, + {"-mlamcas"}, + {"-mld-seq-sa"}, + {"-mno-relax"}, + {"-mno-strict-align"}, + {"-mno-lsx"}, + {"-mno-lasx"}, + {"-mno-frecipe"}, + {"-mno-lam-bh"}, + {"-mno-lamcas"}, + {"-mno-ld-seq-sa"}, {"-mlarge-data-threshold=16"}, {"-mtune=happybirthday"}, {"-mstack-overflow"}, @@ -96,7 +121,13 @@ var badCompilerFlags = [][]string{ {"-march=@dawn"}, {"-march=-dawn"}, {"-mcmodel=@model"}, + {"-mfpu=@0"}, + {"-mfpu=-0"}, {"-mlarge-data-threshold=@12"}, + {"-mtls-dialect=@gnu"}, + {"-mtls-dialect=-gnu"}, + {"-msimd=@none"}, + {"-msimd=-none"}, {"-std=@c99"}, {"-std=-c99"}, {"-x@c"}, From c8664ced4ef61456a98acb9f910b1646ae81e3b5 Mon Sep 17 00:00:00 2001 From: Mateusz Poliwczak Date: Sat, 8 Feb 2025 13:59:18 +0000 Subject: [PATCH 304/397] cmd/compile/internal/gc: handle errors from *bio.Writer The error is stored internally in *bio.Writer, more specifically in *bufio.Writer and the current code does not handle it, ignoring errors silently. Change-Id: Iefa9bf7ddabb3c4fc03377e676a8098dcad9be6d GitHub-Last-Rev: a5d36223312773039c37bb1c52fffc96fff04fba GitHub-Pull-Request: golang/go#71621 Reviewed-on: https://go-review.googlesource.com/c/go/+/647915 Reviewed-by: Keith Randall LUCI-TryBot-Result: Go LUCI Reviewed-by: Keith Randall Reviewed-by: Dmitri Shuralyov Auto-Submit: Keith Randall --- src/cmd/compile/internal/gc/export.go | 4 +++- src/cmd/compile/internal/gc/obj.go | 8 +++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/cmd/compile/internal/gc/export.go b/src/cmd/compile/internal/gc/export.go index c93f008ba2c26b..9afbeb9d3b5c91 100644 --- a/src/cmd/compile/internal/gc/export.go +++ b/src/cmd/compile/internal/gc/export.go @@ -47,5 +47,7 @@ func dumpasmhdr() { } } - b.Close() + if err := b.Close(); err != nil { + base.Fatalf("%v", err) + } } diff --git a/src/cmd/compile/internal/gc/obj.go b/src/cmd/compile/internal/gc/obj.go index 4b42c81ef81845..37bbce03189c24 100644 --- a/src/cmd/compile/internal/gc/obj.go +++ b/src/cmd/compile/internal/gc/obj.go @@ -57,7 +57,7 @@ func dumpobj1(outfile string, mode int) { fmt.Printf("can't create %s: %v\n", outfile, err) base.ErrorExit() } - defer bout.Close() + bout.WriteString("!\n") if mode&modeCompilerObj != 0 { @@ -70,6 +70,12 @@ func dumpobj1(outfile string, mode int) { dumpLinkerObj(bout) finishArchiveEntry(bout, start, "_go_.o") } + + if err := bout.Close(); err != nil { + base.FlushErrors() + fmt.Printf("error while writing to file %s: %v\n", outfile, err) + base.ErrorExit() + } } func printObjHeader(bout *bio.Writer) { From 072eea9b3b8e3c871707b5661948edd4090fc56a Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Mon, 9 Dec 2024 12:55:33 -0800 Subject: [PATCH 305/397] cmd/compile: avoid ifaceeq call if we know the interface is direct We can just use == if the interface is direct. Fixes #70738 Change-Id: Ia9a644791a370fec969c04c42d28a9b58f16911f Reviewed-on: https://go-review.googlesource.com/c/go/+/635435 Auto-Submit: Keith Randall Reviewed-by: Cuong Manh Le Reviewed-by: Cherry Mui Reviewed-by: David Chase LUCI-TryBot-Result: Go LUCI --- .../compile/internal/reflectdata/reflect.go | 20 +++-- .../compile/internal/ssa/_gen/generic.rules | 21 +++++ src/cmd/compile/internal/ssa/rewrite.go | 83 +++++++++++++++++++ .../compile/internal/ssa/rewritegeneric.go | 53 ++++++++++++ src/cmd/compile/internal/walk/compare.go | 9 ++ src/cmd/internal/obj/link.go | 16 ++++ test/codegen/ifaces.go | 36 ++++++++ 7 files changed, 230 insertions(+), 8 deletions(-) diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go index a4a701c9a2e54d..4202ff3358f51d 100644 --- a/src/cmd/compile/internal/reflectdata/reflect.go +++ b/src/cmd/compile/internal/reflectdata/reflect.go @@ -592,11 +592,21 @@ func TypePtrAt(pos src.XPos, t *types.Type) *ir.AddrExpr { // it may sometimes, but not always, be a type that can't implement the specified // interface. func ITabLsym(typ, iface *types.Type) *obj.LSym { + return itabLsym(typ, iface, true) +} + +func itabLsym(typ, iface *types.Type, allowNonImplement bool) *obj.LSym { s, existed := ir.Pkgs.Itab.LookupOK(typ.LinkString() + "," + iface.LinkString()) lsym := s.Linksym() + signatmu.Lock() + if lsym.Extra == nil { + ii := lsym.NewItabInfo() + ii.Type = typ + } + signatmu.Unlock() if !existed { - writeITab(lsym, typ, iface, true) + writeITab(lsym, typ, iface, allowNonImplement) } return lsym } @@ -605,13 +615,7 @@ func ITabLsym(typ, iface *types.Type) *obj.LSym { // *runtime.itab value for concrete type typ implementing interface // iface. func ITabAddrAt(pos src.XPos, typ, iface *types.Type) *ir.AddrExpr { - s, existed := ir.Pkgs.Itab.LookupOK(typ.LinkString() + "," + iface.LinkString()) - lsym := s.Linksym() - - if !existed { - writeITab(lsym, typ, iface, false) - } - + lsym := itabLsym(typ, iface, false) return typecheck.LinksymAddr(pos, lsym, types.Types[types.TUINT8]) } diff --git a/src/cmd/compile/internal/ssa/_gen/generic.rules b/src/cmd/compile/internal/ssa/_gen/generic.rules index 8ad246830e386f..9188eff2ecc448 100644 --- a/src/cmd/compile/internal/ssa/_gen/generic.rules +++ b/src/cmd/compile/internal/ssa/_gen/generic.rules @@ -2072,6 +2072,11 @@ (NilCheck ptr:(Addr {_} (SB)) _) => ptr (NilCheck ptr:(Convert (Addr {_} (SB)) _) _) => ptr +// Addresses of locals are always non-nil. +(NilCheck ptr:(LocalAddr _ _) _) + && warnRule(fe.Debug_checknil(), v, "removed nil check") + => ptr + // Nil checks of nil checks are redundant. // See comment at the end of https://go-review.googlesource.com/c/go/+/537775. (NilCheck ptr:(NilCheck _ _) _ ) => ptr @@ -2774,3 +2779,19 @@ // If we don't use the result of cmpstring, might as well not call it. // Note that this could pretty easily generalize to any pure function. (SelectN [1] c:(StaticLECall {f} _ _ mem)) && c.Uses == 1 && isSameCall(f, "runtime.cmpstring") && clobber(c) => mem + +// We can easily compute the result of efaceeq if +// we know the underlying type is pointer-ish. +(StaticLECall {f} typ_ x y mem) + && isSameCall(f, "runtime.efaceeq") + && isDirectType(typ_) + && clobber(v) + => (MakeResult (EqPtr x y) mem) + +// We can easily compute the result of ifaceeq if +// we know the underlying type is pointer-ish. +(StaticLECall {f} itab x y mem) + && isSameCall(f, "runtime.ifaceeq") + && isDirectIface(itab) + && clobber(v) + => (MakeResult (EqPtr x y) mem) diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go index 5630bfd72934d7..383cb23dae4982 100644 --- a/src/cmd/compile/internal/ssa/rewrite.go +++ b/src/cmd/compile/internal/ssa/rewrite.go @@ -2424,3 +2424,86 @@ func rewriteStructStore(v *Value) *Value { return mem } + +// isDirectType reports whether v represents a type +// (a *runtime._type) whose value is stored directly in an +// interface (i.e., is pointer or pointer-like). +func isDirectType(v *Value) bool { + return isDirectType1(v) +} + +// v is a type +func isDirectType1(v *Value) bool { + switch v.Op { + case OpITab: + return isDirectType2(v.Args[0]) + case OpAddr: + lsym := v.Aux.(*obj.LSym) + if lsym.Extra == nil { + return false + } + if ti, ok := (*lsym.Extra).(*obj.TypeInfo); ok { + return types.IsDirectIface(ti.Type.(*types.Type)) + } + } + return false +} + +// v is an empty interface +func isDirectType2(v *Value) bool { + switch v.Op { + case OpIMake: + return isDirectType1(v.Args[0]) + } + return false +} + +// isDirectIface reports whether v represents an itab +// (a *runtime._itab) for a type whose value is stored directly +// in an interface (i.e., is pointer or pointer-like). +func isDirectIface(v *Value) bool { + return isDirectIface1(v, 9) +} + +// v is an itab +func isDirectIface1(v *Value, depth int) bool { + if depth == 0 { + return false + } + switch v.Op { + case OpITab: + return isDirectIface2(v.Args[0], depth-1) + case OpAddr: + lsym := v.Aux.(*obj.LSym) + if lsym.Extra == nil { + return false + } + if ii, ok := (*lsym.Extra).(*obj.ItabInfo); ok { + return types.IsDirectIface(ii.Type.(*types.Type)) + } + case OpConstNil: + // We can treat this as direct, because if the itab is + // nil, the data field must be nil also. + return true + } + return false +} + +// v is an interface +func isDirectIface2(v *Value, depth int) bool { + if depth == 0 { + return false + } + switch v.Op { + case OpIMake: + return isDirectIface1(v.Args[0], depth-1) + case OpPhi: + for _, a := range v.Args { + if !isDirectIface2(a, depth-1) { + return false + } + } + return true + } + return false +} diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go index fa771bf27ddea0..b3161ad50d4448 100644 --- a/src/cmd/compile/internal/ssa/rewritegeneric.go +++ b/src/cmd/compile/internal/ssa/rewritegeneric.go @@ -20678,6 +20678,17 @@ func rewriteValuegeneric_OpNilCheck(v *Value) bool { v.copyOf(ptr) return true } + // match: (NilCheck ptr:(LocalAddr _ _) _) + // cond: warnRule(fe.Debug_checknil(), v, "removed nil check") + // result: ptr + for { + ptr := v_0 + if ptr.Op != OpLocalAddr || !(warnRule(fe.Debug_checknil(), v, "removed nil check")) { + break + } + v.copyOf(ptr) + return true + } // match: (NilCheck ptr:(NilCheck _ _) _ ) // result: ptr for { @@ -30297,6 +30308,48 @@ func rewriteValuegeneric_OpStaticLECall(v *Value) bool { v.AddArg2(v0, mem) return true } + // match: (StaticLECall {f} typ_ x y mem) + // cond: isSameCall(f, "runtime.efaceeq") && isDirectType(typ_) && clobber(v) + // result: (MakeResult (EqPtr x y) mem) + for { + if len(v.Args) != 4 { + break + } + f := auxToCall(v.Aux) + mem := v.Args[3] + typ_ := v.Args[0] + x := v.Args[1] + y := v.Args[2] + if !(isSameCall(f, "runtime.efaceeq") && isDirectType(typ_) && clobber(v)) { + break + } + v.reset(OpMakeResult) + v0 := b.NewValue0(v.Pos, OpEqPtr, typ.Bool) + v0.AddArg2(x, y) + v.AddArg2(v0, mem) + return true + } + // match: (StaticLECall {f} itab x y mem) + // cond: isSameCall(f, "runtime.ifaceeq") && isDirectIface(itab) && clobber(v) + // result: (MakeResult (EqPtr x y) mem) + for { + if len(v.Args) != 4 { + break + } + f := auxToCall(v.Aux) + mem := v.Args[3] + itab := v.Args[0] + x := v.Args[1] + y := v.Args[2] + if !(isSameCall(f, "runtime.ifaceeq") && isDirectIface(itab) && clobber(v)) { + break + } + v.reset(OpMakeResult) + v0 := b.NewValue0(v.Pos, OpEqPtr, typ.Bool) + v0.AddArg2(x, y) + v.AddArg2(v0, mem) + return true + } return false } func rewriteValuegeneric_OpStore(v *Value) bool { diff --git a/src/cmd/compile/internal/walk/compare.go b/src/cmd/compile/internal/walk/compare.go index 25160008ee90ba..d3a91f30b9e8d4 100644 --- a/src/cmd/compile/internal/walk/compare.go +++ b/src/cmd/compile/internal/walk/compare.go @@ -317,8 +317,17 @@ func walkCompare(n *ir.BinaryExpr, init *ir.Nodes) ir.Node { } func walkCompareInterface(n *ir.BinaryExpr, init *ir.Nodes) ir.Node { + swap := n.X.Op() != ir.OCONVIFACE && n.Y.Op() == ir.OCONVIFACE n.Y = cheapExpr(n.Y, init) n.X = cheapExpr(n.X, init) + if swap { + // Put the concrete type first in the comparison. + // This passes a constant type (itab) to efaceeq (ifaceeq) + // which is easier to match against in rewrite rules. + // See issue 70738. + n.X, n.Y = n.Y, n.X + } + eqtab, eqdata := compare.EqInterface(n.X, n.Y) var cmp ir.Node if n.Op() == ir.OEQ { diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go index 1b2d344eaf8311..6d6a5fd44df1a5 100644 --- a/src/cmd/internal/obj/link.go +++ b/src/cmd/internal/obj/link.go @@ -603,6 +603,22 @@ func (s *LSym) NewTypeInfo() *TypeInfo { return t } +// An ItabInfo contains information for a symbol +// that contains a runtime.itab. +type ItabInfo struct { + Type interface{} // a *cmd/compile/internal/types.Type +} + +func (s *LSym) NewItabInfo() *ItabInfo { + if s.Extra != nil { + panic(fmt.Sprintf("invalid use of LSym - NewItabInfo with Extra of type %T", *s.Extra)) + } + t := new(ItabInfo) + s.Extra = new(interface{}) + *s.Extra = t + return t +} + // WasmImport represents a WebAssembly (WASM) imported function with // parameters and results translated into WASM types based on the Go function // declaration. diff --git a/test/codegen/ifaces.go b/test/codegen/ifaces.go index 2be3fa5146a7ac..cc67a047405445 100644 --- a/test/codegen/ifaces.go +++ b/test/codegen/ifaces.go @@ -25,3 +25,39 @@ func ConvToM(x any) I { // arm64:`CALL\truntime.typeAssert`,`LDAR`,`MOVWU`,`MOVD\t\(R.*\)\(R.*\)` return x.(I) } + +func e1(x any, y *int) bool { + // amd64:-`.*faceeq`,`SETEQ` + // arm64:-`.*faceeq`,`CSET\tEQ` + return x == y +} + +func e2(x any, y *int) bool { + // amd64:-`.*faceeq`,`SETEQ` + // arm64:-`.*faceeq`,`CSET\tEQ` + return y == x +} + +type E *int + +func e3(x any, y E) bool { + // amd64:-`.*faceeq`,`SETEQ` + // arm64:-`.*faceeq`,`CSET\tEQ` + return x == y +} + +type T int + +func (t *T) M() {} + +func i1(x I, y *T) bool { + // amd64:-`.*faceeq`,`SETEQ` + // arm64:-`.*faceeq`,`CSET\tEQ` + return x == y +} + +func i2(x I, y *T) bool { + // amd64:-`.*faceeq`,`SETEQ` + // arm64:-`.*faceeq`,`CSET\tEQ` + return y == x +} From 86aca8778871c02eae6a7c4164ef1f004cd72814 Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Sun, 15 Dec 2024 17:33:48 -0500 Subject: [PATCH 306/397] crypto/internal/fips140test: add SSH KDF ACVP tests Adds ACVP test coverage for the SP 800-135rev1 SSH KDF based on the NIST spec: https://pages.nist.gov/ACVP/draft-celi-acvp-kdf-ssh.html Only SHA1, SHA2-224, SHA2-256, SHA2-384, and SHA2-512 are valid hash algorithms for the SSH KDF algorithm. We do not include SHA-1 since it is out of scope for our FIPS module. Similarly only TDES, AES-128, AES-192 and AES-256 are valid ciphers, and we do not include TDES. Updates #69642 Change-Id: I70e45b77a91bd8aa631da30fab54c97e974f433c Reviewed-on: https://go-review.googlesource.com/c/go/+/636355 LUCI-TryBot-Result: Go LUCI Reviewed-by: Roland Shoemaker Reviewed-by: Filippo Valsorda Reviewed-by: Dmitri Shuralyov Auto-Submit: Filippo Valsorda --- .../fips140test/acvp_capabilities.json | 3 +- .../fips140test/acvp_test.config.json | 3 +- src/crypto/internal/fips140test/acvp_test.go | 43 ++++++++++++++++++- 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/src/crypto/internal/fips140test/acvp_capabilities.json b/src/crypto/internal/fips140test/acvp_capabilities.json index 02098306740494..02940a2e6f4b30 100644 --- a/src/crypto/internal/fips140test/acvp_capabilities.json +++ b/src/crypto/internal/fips140test/acvp_capabilities.json @@ -62,5 +62,6 @@ {"algorithm":"CMAC-AES","capabilities":[{"direction":["gen","ver"],"msgLen":[{"min":0,"max":524288,"increment":8}],"keyLen":[128,256],"macLen":[{"min":8,"max":128,"increment":8}]}],"revision":"1.0"}, {"algorithm":"TLS-v1.2","mode":"KDF","revision":"RFC7627","hashAlg":["SHA2-256","SHA2-384","SHA2-512"]}, - {"algorithm":"TLS-v1.3","mode":"KDF","revision":"RFC8446","hmacAlg":["SHA2-256","SHA2-384"],"runningMode":["DHE","PSK","PSK-DHE"]} + {"algorithm":"TLS-v1.3","mode":"KDF","revision":"RFC8446","hmacAlg":["SHA2-256","SHA2-384"],"runningMode":["DHE","PSK","PSK-DHE"]}, + {"algorithm":"kdf-components","mode":"ssh","revision":"1.0","hashAlg":["SHA2-224","SHA2-256","SHA2-384","SHA2-512"],"cipher":["AES-128","AES-192","AES-256"]} ] diff --git a/src/crypto/internal/fips140test/acvp_test.config.json b/src/crypto/internal/fips140test/acvp_test.config.json index 3cfe80cce0117e..2339c478c80870 100644 --- a/src/crypto/internal/fips140test/acvp_test.config.json +++ b/src/crypto/internal/fips140test/acvp_test.config.json @@ -45,5 +45,6 @@ {"Wrapper": "go", "In": "vectors/CMAC-AES.bz2", "Out": "expected/CMAC-AES.bz2"}, {"Wrapper": "go", "In": "vectors/TLS-v1.2.bz2", "Out": "expected/TLS-v1.2.bz2"}, - {"Wrapper": "go", "In": "vectors/TLS-v1.3.bz2", "Out": "expected/TLS-v1.3.bz2"} + {"Wrapper": "go", "In": "vectors/TLS-v1.3.bz2", "Out": "expected/TLS-v1.3.bz2"}, + {"Wrapper": "go", "In": "vectors/kdf-components.bz2", "Out": "expected/kdf-components.bz2"} ] diff --git a/src/crypto/internal/fips140test/acvp_test.go b/src/crypto/internal/fips140test/acvp_test.go index 2d46ceaf70f545..ded66b79ae911b 100644 --- a/src/crypto/internal/fips140test/acvp_test.go +++ b/src/crypto/internal/fips140test/acvp_test.go @@ -36,6 +36,7 @@ import ( "crypto/internal/fips140/sha256" "crypto/internal/fips140/sha3" "crypto/internal/fips140/sha512" + "crypto/internal/fips140/ssh" "crypto/internal/fips140/subtle" "crypto/internal/fips140/tls12" "crypto/internal/fips140/tls13" @@ -120,6 +121,8 @@ var ( // https://pages.nist.gov/ACVP/draft-celi-acvp-kdf-tls.html#section-7.2 // TLS 1.3 KDF algorithm capabilities: // https://pages.nist.gov/ACVP/draft-hammett-acvp-kdf-tls-v1.3.html#section-7.2 + // SSH KDF algorithm capabilities: + // https://pages.nist.gov/ACVP/draft-celi-acvp-kdf-ssh.html#section-7.2 //go:embed acvp_capabilities.json capabilitiesJson []byte @@ -237,6 +240,17 @@ var ( "TLSKDF/1.2/SHA2-256": cmdTlsKdf12Aft(func() fips140.Hash { return sha256.New() }), "TLSKDF/1.2/SHA2-384": cmdTlsKdf12Aft(func() fips140.Hash { return sha512.New384() }), "TLSKDF/1.2/SHA2-512": cmdTlsKdf12Aft(func() fips140.Hash { return sha512.New() }), + + // Note: only SHA2-224, SHA2-256, SHA2-384 and SHA2-512 are valid hash functions for SSHKDF. + // See https://pages.nist.gov/ACVP/draft-celi-acvp-kdf-ssh.html#section-7.2.1 + "SSHKDF/SHA2-224/client": cmdSshKdfAft(func() fips140.Hash { return sha256.New224() }, ssh.ClientKeys), + "SSHKDF/SHA2-224/server": cmdSshKdfAft(func() fips140.Hash { return sha256.New224() }, ssh.ServerKeys), + "SSHKDF/SHA2-256/client": cmdSshKdfAft(func() fips140.Hash { return sha256.New() }, ssh.ClientKeys), + "SSHKDF/SHA2-256/server": cmdSshKdfAft(func() fips140.Hash { return sha256.New() }, ssh.ServerKeys), + "SSHKDF/SHA2-384/client": cmdSshKdfAft(func() fips140.Hash { return sha512.New384() }, ssh.ClientKeys), + "SSHKDF/SHA2-384/server": cmdSshKdfAft(func() fips140.Hash { return sha512.New384() }, ssh.ServerKeys), + "SSHKDF/SHA2-512/client": cmdSshKdfAft(func() fips140.Hash { return sha512.New() }, ssh.ClientKeys), + "SSHKDF/SHA2-512/server": cmdSshKdfAft(func() fips140.Hash { return sha512.New() }, ssh.ServerKeys), } ) @@ -1372,12 +1386,39 @@ func cmdTlsKdf12Aft(h func() fips140.Hash) command { } } +func cmdSshKdfAft(hFunc func() fips140.Hash, direction ssh.Direction) command { + return command{ + requiredArgs: 4, // K, H, SessionID, cipher + handler: func(args [][]byte) ([][]byte, error) { + k := args[0] + h := args[1] + sessionID := args[2] + cipher := string(args[3]) + + var keyLen int + switch cipher { + case "AES-128": + keyLen = 16 + case "AES-192": + keyLen = 24 + case "AES-256": + keyLen = 32 + default: + return nil, fmt.Errorf("unsupported cipher: %q", cipher) + } + + ivKey, encKey, intKey := ssh.Keys(hFunc, direction, k, h, sessionID, 16, keyLen, hFunc().Size()) + return [][]byte{ivKey, encKey, intKey}, nil + }, + } +} + func TestACVP(t *testing.T) { testenv.SkipIfShortAndSlow(t) const ( bsslModule = "boringssl.googlesource.com/boringssl.git" - bsslVersion = "v0.0.0-20250108043213-d3f61eeacbf7" + bsslVersion = "v0.0.0-20250116010235-21f54b2730ee" goAcvpModule = "github.com/cpu/go-acvp" goAcvpVersion = "v0.0.0-20250102201911-6839fc40f9f8" ) From ee8db080c8ca99bae0288f4cf19110cdfb179e35 Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Thu, 19 Dec 2024 14:02:05 -0500 Subject: [PATCH 307/397] crypto/internal/fips140test: add KAS-ECC-SSC ACVP tests Adds ACVP test coverage for the Sp800-56Ar3 KAS-ECC-SSC algorithm based on the NIST spec: https://pages.nist.gov/ACVP/draft-hammett-acvp-kas-ssc-ecc.html There's no acvp_test.config.json update for this algorithm as one test type type requires random key generation and can't be separated from the test type that doesn't, making it a bad fit for static data testing. Updates #69642 Change-Id: I3b6538fad1c1e5c8b14b638ff3b933f11e98f75a Reviewed-on: https://go-review.googlesource.com/c/go/+/637916 Reviewed-by: Roland Shoemaker LUCI-TryBot-Result: Go LUCI Auto-Submit: Filippo Valsorda Reviewed-by: Filippo Valsorda Reviewed-by: Dmitri Shuralyov --- .../fips140test/acvp_capabilities.json | 4 +- src/crypto/internal/fips140test/acvp_test.go | 47 +++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/crypto/internal/fips140test/acvp_capabilities.json b/src/crypto/internal/fips140test/acvp_capabilities.json index 02940a2e6f4b30..5b318500874d95 100644 --- a/src/crypto/internal/fips140test/acvp_capabilities.json +++ b/src/crypto/internal/fips140test/acvp_capabilities.json @@ -63,5 +63,7 @@ {"algorithm":"TLS-v1.2","mode":"KDF","revision":"RFC7627","hashAlg":["SHA2-256","SHA2-384","SHA2-512"]}, {"algorithm":"TLS-v1.3","mode":"KDF","revision":"RFC8446","hmacAlg":["SHA2-256","SHA2-384"],"runningMode":["DHE","PSK","PSK-DHE"]}, - {"algorithm":"kdf-components","mode":"ssh","revision":"1.0","hashAlg":["SHA2-224","SHA2-256","SHA2-384","SHA2-512"],"cipher":["AES-128","AES-192","AES-256"]} + {"algorithm":"kdf-components","mode":"ssh","revision":"1.0","hashAlg":["SHA2-224","SHA2-256","SHA2-384","SHA2-512"],"cipher":["AES-128","AES-192","AES-256"]}, + + {"algorithm":"KAS-ECC-SSC","revision":"Sp800-56Ar3","scheme":{"ephemeralUnified":{"kasRole":["initiator","responder"]},"staticUnified":{"kasRole":["initiator","responder"]}},"domainParameterGenerationMethods":["P-224","P-256","P-384","P-521"]} ] diff --git a/src/crypto/internal/fips140test/acvp_test.go b/src/crypto/internal/fips140test/acvp_test.go index ded66b79ae911b..8c51538cabd9ab 100644 --- a/src/crypto/internal/fips140test/acvp_test.go +++ b/src/crypto/internal/fips140test/acvp_test.go @@ -26,6 +26,7 @@ import ( "crypto/internal/fips140" "crypto/internal/fips140/aes" "crypto/internal/fips140/aes/gcm" + "crypto/internal/fips140/ecdh" "crypto/internal/fips140/ecdsa" "crypto/internal/fips140/ed25519" "crypto/internal/fips140/edwards25519" @@ -123,6 +124,8 @@ var ( // https://pages.nist.gov/ACVP/draft-hammett-acvp-kdf-tls-v1.3.html#section-7.2 // SSH KDF algorithm capabilities: // https://pages.nist.gov/ACVP/draft-celi-acvp-kdf-ssh.html#section-7.2 + // ECDH algorithm capabilities: + // https://pages.nist.gov/ACVP/draft-hammett-acvp-kas-ssc-ecc.html //go:embed acvp_capabilities.json capabilitiesJson []byte @@ -251,6 +254,11 @@ var ( "SSHKDF/SHA2-384/server": cmdSshKdfAft(func() fips140.Hash { return sha512.New384() }, ssh.ServerKeys), "SSHKDF/SHA2-512/client": cmdSshKdfAft(func() fips140.Hash { return sha512.New() }, ssh.ClientKeys), "SSHKDF/SHA2-512/server": cmdSshKdfAft(func() fips140.Hash { return sha512.New() }, ssh.ServerKeys), + + "ECDH/P-224": cmdEcdhAftVal(ecdh.P224()), + "ECDH/P-256": cmdEcdhAftVal(ecdh.P256()), + "ECDH/P-384": cmdEcdhAftVal(ecdh.P384()), + "ECDH/P-521": cmdEcdhAftVal(ecdh.P521()), } ) @@ -1413,6 +1421,45 @@ func cmdSshKdfAft(hFunc func() fips140.Hash, direction ssh.Direction) command { } } +func cmdEcdhAftVal[P ecdh.Point[P]](curve *ecdh.Curve[P]) command { + return command{ + requiredArgs: 3, // X, Y, private key (empty for Val type tests) + handler: func(args [][]byte) ([][]byte, error) { + peerX := args[0] + peerY := args[1] + rawSk := args[2] + + uncompressedPk := append([]byte{4}, append(peerX, peerY...)...) // 4 for uncompressed point format + pk, err := ecdh.NewPublicKey(curve, uncompressedPk) + if err != nil { + return nil, fmt.Errorf("invalid peer public key x,y: %v", err) + } + + var sk *ecdh.PrivateKey + if len(rawSk) > 0 { + sk, err = ecdh.NewPrivateKey(curve, rawSk) + } else { + sk, err = ecdh.GenerateKey(curve, rand.Reader) + } + if err != nil { + return nil, fmt.Errorf("private key error: %v", err) + } + + pubBytes := sk.PublicKey().Bytes() + coordLen := (len(pubBytes) - 1) / 2 + x := pubBytes[1 : 1+coordLen] + y := pubBytes[1+coordLen:] + + secret, err := ecdh.ECDH(curve, sk, pk) + if err != nil { + return nil, fmt.Errorf("key agreement failed: %v", err) + } + + return [][]byte{x, y, secret}, nil + }, + } +} + func TestACVP(t *testing.T) { testenv.SkipIfShortAndSlow(t) From 283296195b7a06239310871a4321bd649a078924 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Mon, 10 Feb 2025 20:10:22 +0000 Subject: [PATCH 308/397] internal/trace: emit a Sync event even if the next generation is broken Since CL 644215 each Sync event now represents the coming generation, with a final Sync event emitted even when there's nothing ahead. This change however failed to emit a Sync event at the end of a completely valid generation when the next generation was invalid, causing the runtime test TestCrashWhileTracing to start failing. Fix this by emitting a final Sync event even when the next generation is broken. We hold onto the error in parsing the next generation and emit it after that final Sync event. (Should these "final" Sync events distinguish themselves in some way?) Fixes #71615. Change-Id: I1f8abee5abaa39e1219e6fa05e9f82f1478db4c9 Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest Reviewed-on: https://go-review.googlesource.com/c/go/+/648195 Auto-Submit: Michael Knyszek LUCI-TryBot-Result: Go LUCI Reviewed-by: Cherry Mui --- src/internal/trace/reader.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/internal/trace/reader.go b/src/internal/trace/reader.go index 81710c0125eda5..75b88f7bac5fbc 100644 --- a/src/internal/trace/reader.go +++ b/src/internal/trace/reader.go @@ -152,12 +152,10 @@ func (r *Reader) ReadEvent() (e Event, err error) { return syncEvent(nil, r.lastTs, r.syncs), nil } // Read the next generation. - var err error - r.gen, r.spill, err = readGeneration(r.r, r.spill) + r.gen, r.spill, r.spillErr = readGeneration(r.r, r.spill) if r.gen == nil { - return Event{}, err + return syncEvent(nil, r.lastTs, r.syncs), nil } - r.spillErr = err // Reset CPU samples cursor. r.cpuSamples = r.gen.cpuSamples From 0bc57a3e7f941f6a1aa32e0b0f708a1e02aa842e Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Thu, 2 Jan 2025 15:09:39 -0500 Subject: [PATCH 309/397] crypto/internal/fips140test: add ctr DRBG ACVP tests Adds ACVP test coverage for the SP 800-90A rev 1 ctrDRBG algorithm based on the NIST spec: https://pages.nist.gov/ACVP/draft-vassilev-acvp-drbg.html#section-7.2 The implementation in our FIPS module is a minimal implementation tailored to the specific needs of stdlib crypto. As a result we customize the ACVP capability registration so that: * predResistanceEnabled is false * only mode AES-256 is supported * for that mode, * derFuncEnabled is false * persoStringLen is 0 to disable personalization * additionalInputLen is 384 to match the [48]byte argument in our API Other capability values are chosen based on Table 4's ctrDRBG AES-256 w/o `derFuncEnabled` row: https://pages.nist.gov/ACVP/draft-vassilev-acvp-drbg.html#section-7.4 We do enable reseed in the capability, necessitating two acvptool commands: one that expects only 6 args and doesn't reseed ("ctrDRBG/AES-256"), and one that expects 8 args and does ("ctrDRBG-reseed/AES-256"). Updates #69642 Change-Id: I0f01a2f9496f45b130ee7d10916708093236f473 Reviewed-on: https://go-review.googlesource.com/c/go/+/639795 Reviewed-by: Roland Shoemaker Reviewed-by: Dmitri Shuralyov Reviewed-by: Filippo Valsorda Auto-Submit: Filippo Valsorda LUCI-TryBot-Result: Go LUCI --- .../fips140test/acvp_capabilities.json | 2 + .../fips140test/acvp_test.config.json | 3 + src/crypto/internal/fips140test/acvp_test.go | 187 ++++++++++++++---- 3 files changed, 158 insertions(+), 34 deletions(-) diff --git a/src/crypto/internal/fips140test/acvp_capabilities.json b/src/crypto/internal/fips140test/acvp_capabilities.json index 5b318500874d95..e2a49530fa5a82 100644 --- a/src/crypto/internal/fips140test/acvp_capabilities.json +++ b/src/crypto/internal/fips140test/acvp_capabilities.json @@ -44,6 +44,8 @@ {"algorithm":"hmacDRBG","revision":"1.0","predResistanceEnabled":[false],"reseedImplemented":false,"capabilities":[{"mode":"SHA3-384","derFuncEnabled":false,"entropyInputLen":[256],"nonceLen":[128],"persoStringLen":[256],"additionalInputLen":[0],"returnedBitsLen":384}]}, {"algorithm":"hmacDRBG","revision":"1.0","predResistanceEnabled":[false],"reseedImplemented":false,"capabilities":[{"mode":"SHA3-512","derFuncEnabled":false,"entropyInputLen":[256],"nonceLen":[128],"persoStringLen":[256],"additionalInputLen":[0],"returnedBitsLen":512}]}, + {"algorithm":"ctrDRBG","revision":"1.0","predResistanceEnabled":[false],"reseedImplemented":true,"capabilities":[{"mode":"AES-256","derFuncEnabled":false,"entropyInputLen":[384],"nonceLen":[0],"persoStringLen":[0],"additionalInputLen":[384],"returnedBitsLen":128}]}, + {"algorithm":"EDDSA","mode":"keyGen","revision":"1.0","curve":["ED-25519"]}, {"algorithm":"EDDSA","mode":"keyVer","revision":"1.0","curve":["ED-25519"]}, {"algorithm":"EDDSA","mode":"sigGen","revision":"1.0","pure":true,"preHash":true,"contextLength":[{"min":0,"max":255,"increment":1}],"curve":["ED-25519"]}, diff --git a/src/crypto/internal/fips140test/acvp_test.config.json b/src/crypto/internal/fips140test/acvp_test.config.json index 2339c478c80870..10f73faac775ae 100644 --- a/src/crypto/internal/fips140test/acvp_test.config.json +++ b/src/crypto/internal/fips140test/acvp_test.config.json @@ -34,6 +34,8 @@ {"Wrapper": "go", "In": "vectors/hmacDRBG.bz2", "Out": "expected/hmacDRBG.bz2"}, + {"Wrapper": "go", "In": "vectors/ctrDRBG.bz2", "Out": "expected/ctrDRBG.bz2"}, + {"Wrapper": "go", "In": "vectors/EDDSA.bz2", "Out": "expected/EDDSA.bz2"}, {"Wrapper": "go", "In": "vectors/ECDSA.bz2", "Out": "expected/ECDSA.bz2"}, @@ -46,5 +48,6 @@ {"Wrapper": "go", "In": "vectors/TLS-v1.2.bz2", "Out": "expected/TLS-v1.2.bz2"}, {"Wrapper": "go", "In": "vectors/TLS-v1.3.bz2", "Out": "expected/TLS-v1.3.bz2"}, + {"Wrapper": "go", "In": "vectors/kdf-components.bz2", "Out": "expected/kdf-components.bz2"} ] diff --git a/src/crypto/internal/fips140test/acvp_test.go b/src/crypto/internal/fips140test/acvp_test.go index 8c51538cabd9ab..62a7dee6eb4510 100644 --- a/src/crypto/internal/fips140test/acvp_test.go +++ b/src/crypto/internal/fips140test/acvp_test.go @@ -26,6 +26,7 @@ import ( "crypto/internal/fips140" "crypto/internal/fips140/aes" "crypto/internal/fips140/aes/gcm" + "crypto/internal/fips140/drbg" "crypto/internal/fips140/ecdh" "crypto/internal/fips140/ecdsa" "crypto/internal/fips140/ed25519" @@ -125,7 +126,9 @@ var ( // SSH KDF algorithm capabilities: // https://pages.nist.gov/ACVP/draft-celi-acvp-kdf-ssh.html#section-7.2 // ECDH algorithm capabilities: - // https://pages.nist.gov/ACVP/draft-hammett-acvp-kas-ssc-ecc.html + // https://pages.nist.gov/ACVP/draft-hammett-acvp-kas-ssc-ecc.html#section-7.3 + // HMAC DRBG and CTR DRBG algorithm capabilities: + // https://pages.nist.gov/ACVP/draft-vassilev-acvp-drbg.html#section-7.2 //go:embed acvp_capabilities.json capabilitiesJson []byte @@ -259,6 +262,9 @@ var ( "ECDH/P-256": cmdEcdhAftVal(ecdh.P256()), "ECDH/P-384": cmdEcdhAftVal(ecdh.P384()), "ECDH/P-521": cmdEcdhAftVal(ecdh.P521()), + + "ctrDRBG/AES-256": cmdCtrDrbgAft(), + "ctrDRBG-reseed/AES-256": cmdCtrDrbgReseedAft(), } ) @@ -1103,39 +1109,6 @@ func cmdMlKem1024DecapAft() command { } } -func cmdHmacDrbgAft(h func() fips140.Hash) command { - return command{ - requiredArgs: 6, // Output length, entropy, personalization, ad1, ad2, nonce - handler: func(args [][]byte) ([][]byte, error) { - outLen := binary.LittleEndian.Uint32(args[0]) - entropy := args[1] - personalization := args[2] - ad1 := args[3] - ad2 := args[4] - nonce := args[5] - - // Our capabilities describe no additional data support. - if len(ad1) != 0 || len(ad2) != 0 { - return nil, errors.New("additional data not supported") - } - - // Our capabilities describe no prediction resistance (requires reseed) and no reseed. - // So the test procedure is: - // * Instantiate DRBG - // * Generate but don't output - // * Generate output - // * Uninstantiate - // See Table 7 in draft-vassilev-acvp-drbg - out := make([]byte, outLen) - drbg := ecdsa.TestingOnlyNewDRBG(h, entropy, nonce, personalization) - drbg.Generate(out) - drbg.Generate(out) - - return [][]byte{out}, nil - }, - } -} - func lookupCurve(name string) (elliptic.Curve, error) { var c elliptic.Curve @@ -1460,6 +1433,152 @@ func cmdEcdhAftVal[P ecdh.Point[P]](curve *ecdh.Curve[P]) command { } } +func cmdHmacDrbgAft(h func() fips140.Hash) command { + return command{ + requiredArgs: 6, // Output length, entropy, personalization, ad1, ad2, nonce + handler: func(args [][]byte) ([][]byte, error) { + outLen := binary.LittleEndian.Uint32(args[0]) + entropy := args[1] + personalization := args[2] + ad1 := args[3] + ad2 := args[4] + nonce := args[5] + + // Our capabilities describe no additional data support. + if len(ad1) != 0 || len(ad2) != 0 { + return nil, errors.New("additional data not supported") + } + + // Our capabilities describe no prediction resistance (requires reseed) and no reseed. + // So the test procedure is: + // * Instantiate DRBG + // * Generate but don't output + // * Generate output + // * Uninstantiate + // See Table 7 in draft-vassilev-acvp-drbg + out := make([]byte, outLen) + drbg := ecdsa.TestingOnlyNewDRBG(h, entropy, nonce, personalization) + drbg.Generate(out) + drbg.Generate(out) + + return [][]byte{out}, nil + }, + } +} + +func cmdCtrDrbgAft() command { + return command{ + requiredArgs: 6, // Output length, entropy, personalization, ad1, ad2, nonce + handler: func(args [][]byte) ([][]byte, error) { + return acvpCtrDrbg{ + outLen: binary.LittleEndian.Uint32(args[0]), + entropy: args[1], + personalization: args[2], + ad1: args[3], + ad2: args[4], + nonce: args[5], + }.process() + }, + } +} + +func cmdCtrDrbgReseedAft() command { + return command{ + requiredArgs: 8, // Output length, entropy, personalization, reseedAD, reseedEntropy, ad1, ad2, nonce + handler: func(args [][]byte) ([][]byte, error) { + return acvpCtrDrbg{ + outLen: binary.LittleEndian.Uint32(args[0]), + entropy: args[1], + personalization: args[2], + reseedAd: args[3], + reseedEntropy: args[4], + ad1: args[5], + ad2: args[6], + nonce: args[7], + }.process() + }, + } +} + +type acvpCtrDrbg struct { + outLen uint32 + entropy []byte + personalization []byte + ad1 []byte + ad2 []byte + nonce []byte + reseedAd []byte // May be empty for no reseed + reseedEntropy []byte // May be empty for no reseed +} + +func (args acvpCtrDrbg) process() ([][]byte, error) { + // Our capability describes no personalization support. + if len(args.personalization) > 0 { + return nil, errors.New("personalization string not supported") + } + + // Our capability describes no derivation function support, so the nonce + // should be empty. + if len(args.nonce) > 0 { + return nil, errors.New("unexpected nonce value") + } + + // Our capability describes entropy input len of 384 bits. + entropy, err := require48Bytes(args.entropy) + if err != nil { + return nil, fmt.Errorf("entropy: %w", err) + } + + // Our capability describes additional input len of 384 bits. + ad1, err := require48Bytes(args.ad1) + if err != nil { + return nil, fmt.Errorf("AD1: %w", err) + } + ad2, err := require48Bytes(args.ad2) + if err != nil { + return nil, fmt.Errorf("AD2: %w", err) + } + + withReseed := len(args.reseedAd) > 0 + var reseedAd, reseedEntropy *[48]byte + if withReseed { + // Ditto RE: entropy and additional data lengths for reseeding. + if reseedAd, err = require48Bytes(args.reseedAd); err != nil { + return nil, fmt.Errorf("reseed AD: %w", err) + } + if reseedEntropy, err = require48Bytes(args.reseedEntropy); err != nil { + return nil, fmt.Errorf("reseed entropy: %w", err) + } + } + + // Our capabilities describe no prediction resistance and allow both + // reseed and no reseed, so the test procedure is: + // * Instantiate DRBG + // * Reseed (if enabled) + // * Generate but don't output + // * Generate output + // * Uninstantiate + // See Table 7 in draft-vassilev-acvp-drbg + out := make([]byte, args.outLen) + ctrDrbg := drbg.NewCounter(entropy) + if withReseed { + ctrDrbg.Reseed(reseedEntropy, reseedAd) + } + ctrDrbg.Generate(out, ad1) + ctrDrbg.Generate(out, ad2) + + return [][]byte{out}, nil +} + +// Verify input is 48 byte slice, and cast it to a pointer to a fixed-size array +// of 48 bytes, or return an error. +func require48Bytes(input []byte) (*[48]byte, error) { + if inputLen := len(input); inputLen != 48 { + return nil, fmt.Errorf("invalid length: %d", inputLen) + } + return (*[48]byte)(input), nil +} + func TestACVP(t *testing.T) { testenv.SkipIfShortAndSlow(t) From 0c94c5fcae909de059ff5c9273e2839e0d5742bf Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Thu, 19 Dec 2024 12:45:57 -0500 Subject: [PATCH 310/397] crypto/internal/fips140test: add counter KDF ACVP tests Adds ACVP test coverage for the SP 800-108r1 KDF counter mode algorithm based on the NIST spec: https://pages.nist.gov/ACVP/draft-celi-acvp-kbkdf.html The implementation in our FIPS module fixes some parameters, requiring tailoring of the advertised capability to match. Notably: * We only support macModes CMAC-AES-128, -192, and -256 * We only support supportedLengths 256 (matching the [32]byte output from CounterKDF.DeriveKey) * We only support fixedDataOrder "before fixed data" * We only support counterLength 16 No acvp_test.config.json update accompanies this support because the ACVP tests for this algorithm aren't amenable to fixed data testing. Updates #69642 Change-Id: I9e02d6c8cb6e209ac8e4c9fba926fffbad916098 Reviewed-on: https://go-review.googlesource.com/c/go/+/639776 Reviewed-by: Filippo Valsorda Reviewed-by: Dmitri Shuralyov Reviewed-by: Roland Shoemaker Auto-Submit: Filippo Valsorda LUCI-TryBot-Result: Go LUCI --- .../fips140test/acvp_capabilities.json | 4 +- src/crypto/internal/fips140test/acvp_test.go | 55 +++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/crypto/internal/fips140test/acvp_capabilities.json b/src/crypto/internal/fips140test/acvp_capabilities.json index e2a49530fa5a82..ecfb6b9e0fef0b 100644 --- a/src/crypto/internal/fips140test/acvp_capabilities.json +++ b/src/crypto/internal/fips140test/acvp_capabilities.json @@ -67,5 +67,7 @@ {"algorithm":"TLS-v1.3","mode":"KDF","revision":"RFC8446","hmacAlg":["SHA2-256","SHA2-384"],"runningMode":["DHE","PSK","PSK-DHE"]}, {"algorithm":"kdf-components","mode":"ssh","revision":"1.0","hashAlg":["SHA2-224","SHA2-256","SHA2-384","SHA2-512"],"cipher":["AES-128","AES-192","AES-256"]}, - {"algorithm":"KAS-ECC-SSC","revision":"Sp800-56Ar3","scheme":{"ephemeralUnified":{"kasRole":["initiator","responder"]},"staticUnified":{"kasRole":["initiator","responder"]}},"domainParameterGenerationMethods":["P-224","P-256","P-384","P-521"]} + {"algorithm":"KAS-ECC-SSC","revision":"Sp800-56Ar3","scheme":{"ephemeralUnified":{"kasRole":["initiator","responder"]},"staticUnified":{"kasRole":["initiator","responder"]}},"domainParameterGenerationMethods":["P-224","P-256","P-384","P-521"]}, + + {"algorithm":"KDF","revision":"1.0","capabilities":[{"kdfMode":"counter","macMode":["CMAC-AES128","CMAC-AES192","CMAC-AES256"],"supportedLengths":[256],"fixedDataOrder":["before fixed data"],"counterLength":[16]}]} ] diff --git a/src/crypto/internal/fips140test/acvp_test.go b/src/crypto/internal/fips140test/acvp_test.go index 62a7dee6eb4510..e76d2daf1ce52e 100644 --- a/src/crypto/internal/fips140test/acvp_test.go +++ b/src/crypto/internal/fips140test/acvp_test.go @@ -129,6 +129,8 @@ var ( // https://pages.nist.gov/ACVP/draft-hammett-acvp-kas-ssc-ecc.html#section-7.3 // HMAC DRBG and CTR DRBG algorithm capabilities: // https://pages.nist.gov/ACVP/draft-vassilev-acvp-drbg.html#section-7.2 + // KDF-Counter algorithm capabilities: + // https://pages.nist.gov/ACVP/draft-celi-acvp-kbkdf.html#section-7.3 //go:embed acvp_capabilities.json capabilitiesJson []byte @@ -265,6 +267,8 @@ var ( "ctrDRBG/AES-256": cmdCtrDrbgAft(), "ctrDRBG-reseed/AES-256": cmdCtrDrbgReseedAft(), + + "KDF-counter": cmdKdfCounterAft(), } ) @@ -1579,6 +1583,57 @@ func require48Bytes(input []byte) (*[48]byte, error) { return (*[48]byte)(input), nil } +func cmdKdfCounterAft() command { + return command{ + requiredArgs: 5, // Number output bytes, PRF name, counter location string, key, number of counter bits + handler: func(args [][]byte) ([][]byte, error) { + outputBytes := binary.LittleEndian.Uint32(args[0]) + prf := args[1] + counterLocation := args[2] + key := args[3] + counterBits := binary.LittleEndian.Uint32(args[4]) + + if outputBytes != 32 { + return nil, fmt.Errorf("KDF received unsupported output length %d bytes", outputBytes) + } + if !bytes.Equal(prf, []byte("CMAC-AES128")) && !bytes.Equal(prf, []byte("CMAC-AES192")) && !bytes.Equal(prf, []byte("CMAC-AES256")) { + return nil, fmt.Errorf("KDF received unsupported PRF %q", string(prf)) + } + if !bytes.Equal(counterLocation, []byte("before fixed data")) { + return nil, fmt.Errorf("KDF received unsupported counter location %q", string(counterLocation)) + } + // The spec doesn't describe the "deferred" property for a KDF counterMode test case. + // BoringSSL's acvptool sends an empty key when deferred=true, but with the capabilities + // we register all test cases ahve deferred=false and provide a key from the populated + // keyIn property. + if len(key) == 0 { + return nil, errors.New("deferred test cases are not supported") + } + if counterBits != 16 { + return nil, fmt.Errorf("KDF received unsupported counter length %d", counterBits) + } + + block, err := aes.New(key) + if err != nil { + return nil, fmt.Errorf("failed to create cipher: %v", err) + } + kdf := gcm.NewCounterKDF(block) + + var label byte + var context [12]byte + rand.Reader.Read(context[:]) + + result := kdf.DeriveKey(label, context) + + fixedData := make([]byte, 1+1+12) // 1 byte label, 1 null byte, 12 bytes context. + fixedData[0] = label + copy(fixedData[2:], context[:]) + + return [][]byte{key, fixedData, result[:]}, nil + }, + } +} + func TestACVP(t *testing.T) { testenv.SkipIfShortAndSlow(t) From ea54d8a0efc22c092c1f714cb3c6f12f429c1459 Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Fri, 10 Jan 2025 11:10:12 -0500 Subject: [PATCH 311/397] crypto/internal/fips140test: add RSA ACVP tests Adds ACVP test coverage for the RSA algorithm based on the NIST spec: https://pages.nist.gov/ACVP/draft-celi-acvp-rsa.html Includes coverage for keyGen, sigGen and sigVer across a variety of modulus sizes. For sigGen and sigVer both PKCS1v1.5 and PSS are supported with a variety of SHA2 digests. The static test data from go-acvp only includes sigVer vectors/expected. The keyGen and sigGen test types aren't amenable to fixed data testing. Updates #69642 Change-Id: Ia61a69115f2d2a984b95435a37d4c9c6db90a89a Reviewed-on: https://go-review.googlesource.com/c/go/+/642135 Reviewed-by: Filippo Valsorda Auto-Submit: Filippo Valsorda Reviewed-by: Dmitri Shuralyov LUCI-TryBot-Result: Go LUCI Reviewed-by: Roland Shoemaker --- .../fips140test/acvp_capabilities.json | 6 +- .../fips140test/acvp_test.config.json | 4 +- src/crypto/internal/fips140test/acvp_test.go | 145 +++++++++++++++++- 3 files changed, 152 insertions(+), 3 deletions(-) diff --git a/src/crypto/internal/fips140test/acvp_capabilities.json b/src/crypto/internal/fips140test/acvp_capabilities.json index ecfb6b9e0fef0b..d6c1b02b43e98e 100644 --- a/src/crypto/internal/fips140test/acvp_capabilities.json +++ b/src/crypto/internal/fips140test/acvp_capabilities.json @@ -69,5 +69,9 @@ {"algorithm":"KAS-ECC-SSC","revision":"Sp800-56Ar3","scheme":{"ephemeralUnified":{"kasRole":["initiator","responder"]},"staticUnified":{"kasRole":["initiator","responder"]}},"domainParameterGenerationMethods":["P-224","P-256","P-384","P-521"]}, - {"algorithm":"KDF","revision":"1.0","capabilities":[{"kdfMode":"counter","macMode":["CMAC-AES128","CMAC-AES192","CMAC-AES256"],"supportedLengths":[256],"fixedDataOrder":["before fixed data"],"counterLength":[16]}]} + {"algorithm":"KDF","revision":"1.0","capabilities":[{"kdfMode":"counter","macMode":["CMAC-AES128","CMAC-AES192","CMAC-AES256"],"supportedLengths":[256],"fixedDataOrder":["before fixed data"],"counterLength":[16]}]}, + + {"algorithm":"RSA","mode":"keyGen","revision":"FIPS186-5","infoGeneratedByServer":true,"pubExpMode":"fixed","fixedPubExp":"010001","keyFormat":"standard","capabilities":[{"randPQ":"probable","properties":[{"modulo":2048,"primeTest":["2powSecStr"]},{"modulo":3072,"primeTest":["2powSecStr"]},{"modulo":4096,"primeTest":["2powSecStr"]}]}]}, + {"algorithm":"RSA","mode":"sigGen","revision":"FIPS186-5","capabilities":[{"sigType":"pkcs1v1.5","properties":[{"modulo":2048,"hashPair":[{"hashAlg":"SHA2-224"},{"hashAlg":"SHA2-256"},{"hashAlg":"SHA2-384"},{"hashAlg":"SHA2-512"}]},{"modulo":3072,"hashPair":[{"hashAlg":"SHA2-224"},{"hashAlg":"SHA2-256"},{"hashAlg":"SHA2-384"},{"hashAlg":"SHA2-512"}]},{"modulo":4096,"hashPair":[{"hashAlg":"SHA2-224"},{"hashAlg":"SHA2-256"},{"hashAlg":"SHA2-384"},{"hashAlg":"SHA2-512"}]}]},{"sigType":"pss","properties":[{"maskFunction":["mgf1"],"modulo":2048,"hashPair":[{"hashAlg":"SHA2-224","saltLen":28},{"hashAlg":"SHA2-256","saltLen":32},{"hashAlg":"SHA2-384","saltLen":48},{"hashAlg":"SHA2-512","saltLen":64}]},{"maskFunction":["mgf1"],"modulo":3072,"hashPair":[{"hashAlg":"SHA2-224","saltLen":28},{"hashAlg":"SHA2-256","saltLen":32},{"hashAlg":"SHA2-384","saltLen":48},{"hashAlg":"SHA2-512","saltLen":64}]},{"maskFunction":["mgf1"],"modulo":4096,"hashPair":[{"hashAlg":"SHA2-224","saltLen":28},{"hashAlg":"SHA2-256","saltLen":32},{"hashAlg":"SHA2-384","saltLen":48},{"hashAlg":"SHA2-512","saltLen":64}]}]}]}, + {"algorithm":"RSA","mode":"sigVer","revision":"FIPS186-5","pubExpMode":"fixed","fixedPubExp":"010001","capabilities":[{"sigType":"pkcs1v1.5","properties":[{"modulo":2048,"hashPair":[{"hashAlg":"SHA2-224"},{"hashAlg":"SHA2-256"},{"hashAlg":"SHA2-384"},{"hashAlg":"SHA2-512"}]}]},{"sigType":"pkcs1v1.5","properties":[{"modulo":3072,"hashPair":[{"hashAlg":"SHA2-224"},{"hashAlg":"SHA2-256"},{"hashAlg":"SHA2-384"},{"hashAlg":"SHA2-512"}]}]},{"sigType":"pkcs1v1.5","properties":[{"modulo":4096,"hashPair":[{"hashAlg":"SHA2-224"},{"hashAlg":"SHA2-256"},{"hashAlg":"SHA2-384"},{"hashAlg":"SHA2-512"}]}]},{"sigType":"pss","properties":[{"maskFunction":["mgf1"],"modulo":2048,"hashPair":[{"hashAlg":"SHA2-224","saltLen":28},{"hashAlg":"SHA2-256","saltLen":32},{"hashAlg":"SHA2-384","saltLen":48},{"hashAlg":"SHA2-512","saltLen":64}]}]},{"sigType":"pss","properties":[{"maskFunction":["mgf1"],"modulo":3072,"hashPair":[{"hashAlg":"SHA2-224","saltLen":28},{"hashAlg":"SHA2-256","saltLen":32},{"hashAlg":"SHA2-384","saltLen":48},{"hashAlg":"SHA2-512","saltLen":64}]}]},{"sigType":"pss","properties":[{"maskFunction":["mgf1"],"modulo":4096,"hashPair":[{"hashAlg":"SHA2-224","saltLen":28},{"hashAlg":"SHA2-256","saltLen":32},{"hashAlg":"SHA2-384","saltLen":48},{"hashAlg":"SHA2-512","saltLen":64}]}]}]} ] diff --git a/src/crypto/internal/fips140test/acvp_test.config.json b/src/crypto/internal/fips140test/acvp_test.config.json index 10f73faac775ae..2f905e0870376e 100644 --- a/src/crypto/internal/fips140test/acvp_test.config.json +++ b/src/crypto/internal/fips140test/acvp_test.config.json @@ -49,5 +49,7 @@ {"Wrapper": "go", "In": "vectors/TLS-v1.2.bz2", "Out": "expected/TLS-v1.2.bz2"}, {"Wrapper": "go", "In": "vectors/TLS-v1.3.bz2", "Out": "expected/TLS-v1.3.bz2"}, - {"Wrapper": "go", "In": "vectors/kdf-components.bz2", "Out": "expected/kdf-components.bz2"} + {"Wrapper": "go", "In": "vectors/kdf-components.bz2", "Out": "expected/kdf-components.bz2"}, + + {"Wrapper": "go", "In": "vectors/RSA.bz2", "Out": "expected/RSA.bz2"} ] diff --git a/src/crypto/internal/fips140test/acvp_test.go b/src/crypto/internal/fips140test/acvp_test.go index e76d2daf1ce52e..1552a07d61846f 100644 --- a/src/crypto/internal/fips140test/acvp_test.go +++ b/src/crypto/internal/fips140test/acvp_test.go @@ -26,6 +26,7 @@ import ( "crypto/internal/fips140" "crypto/internal/fips140/aes" "crypto/internal/fips140/aes/gcm" + "crypto/internal/fips140/bigmod" "crypto/internal/fips140/drbg" "crypto/internal/fips140/ecdh" "crypto/internal/fips140/ecdsa" @@ -35,6 +36,7 @@ import ( "crypto/internal/fips140/hmac" "crypto/internal/fips140/mlkem" "crypto/internal/fips140/pbkdf2" + "crypto/internal/fips140/rsa" "crypto/internal/fips140/sha256" "crypto/internal/fips140/sha3" "crypto/internal/fips140/sha512" @@ -131,6 +133,8 @@ var ( // https://pages.nist.gov/ACVP/draft-vassilev-acvp-drbg.html#section-7.2 // KDF-Counter algorithm capabilities: // https://pages.nist.gov/ACVP/draft-celi-acvp-kbkdf.html#section-7.3 + // RSA algorithm capabilities: + // https://pages.nist.gov/ACVP/draft-celi-acvp-rsa.html#section-7.3 //go:embed acvp_capabilities.json capabilitiesJson []byte @@ -269,6 +273,26 @@ var ( "ctrDRBG-reseed/AES-256": cmdCtrDrbgReseedAft(), "KDF-counter": cmdKdfCounterAft(), + + "RSA/keyGen": cmdRsaKeyGenAft(), + + "RSA/sigGen/SHA2-224/pkcs1v1.5": cmdRsaSigGenAft(func() fips140.Hash { return sha256.New224() }, "SHA-224", false), + "RSA/sigGen/SHA2-256/pkcs1v1.5": cmdRsaSigGenAft(func() fips140.Hash { return sha256.New() }, "SHA-256", false), + "RSA/sigGen/SHA2-384/pkcs1v1.5": cmdRsaSigGenAft(func() fips140.Hash { return sha512.New384() }, "SHA-384", false), + "RSA/sigGen/SHA2-512/pkcs1v1.5": cmdRsaSigGenAft(func() fips140.Hash { return sha512.New() }, "SHA-512", false), + "RSA/sigGen/SHA2-224/pss": cmdRsaSigGenAft(func() fips140.Hash { return sha256.New224() }, "SHA-224", true), + "RSA/sigGen/SHA2-256/pss": cmdRsaSigGenAft(func() fips140.Hash { return sha256.New() }, "SHA-256", true), + "RSA/sigGen/SHA2-384/pss": cmdRsaSigGenAft(func() fips140.Hash { return sha512.New384() }, "SHA-384", true), + "RSA/sigGen/SHA2-512/pss": cmdRsaSigGenAft(func() fips140.Hash { return sha512.New() }, "SHA-512", true), + + "RSA/sigVer/SHA2-224/pkcs1v1.5": cmdRsaSigVerAft(func() fips140.Hash { return sha256.New224() }, "SHA-224", false), + "RSA/sigVer/SHA2-256/pkcs1v1.5": cmdRsaSigVerAft(func() fips140.Hash { return sha256.New() }, "SHA-256", false), + "RSA/sigVer/SHA2-384/pkcs1v1.5": cmdRsaSigVerAft(func() fips140.Hash { return sha512.New384() }, "SHA-384", false), + "RSA/sigVer/SHA2-512/pkcs1v1.5": cmdRsaSigVerAft(func() fips140.Hash { return sha512.New() }, "SHA-512", false), + "RSA/sigVer/SHA2-224/pss": cmdRsaSigVerAft(func() fips140.Hash { return sha256.New224() }, "SHA-224", true), + "RSA/sigVer/SHA2-256/pss": cmdRsaSigVerAft(func() fips140.Hash { return sha256.New() }, "SHA-256", true), + "RSA/sigVer/SHA2-384/pss": cmdRsaSigVerAft(func() fips140.Hash { return sha512.New384() }, "SHA-384", true), + "RSA/sigVer/SHA2-512/pss": cmdRsaSigVerAft(func() fips140.Hash { return sha512.New() }, "SHA-512", true), } ) @@ -1634,6 +1658,125 @@ func cmdKdfCounterAft() command { } } +func cmdRsaKeyGenAft() command { + return command{ + requiredArgs: 1, // Modulus bit-size + handler: func(args [][]byte) ([][]byte, error) { + bitSize := binary.LittleEndian.Uint32(args[0]) + + key, err := getRSAKey((int)(bitSize)) + if err != nil { + return nil, fmt.Errorf("generating RSA key: %w", err) + } + + N, e, d, P, Q, _, _, _ := key.Export() + + eBytes := make([]byte, 4) + binary.BigEndian.PutUint32(eBytes, uint32(e)) + + return [][]byte{eBytes, P, Q, N, d}, nil + }, + } +} + +func cmdRsaSigGenAft(hashFunc func() fips140.Hash, hashName string, pss bool) command { + return command{ + requiredArgs: 2, // Modulus bit-size, message + handler: func(args [][]byte) ([][]byte, error) { + bitSize := binary.LittleEndian.Uint32(args[0]) + msg := args[1] + + key, err := getRSAKey((int)(bitSize)) + if err != nil { + return nil, fmt.Errorf("generating RSA key: %w", err) + } + + h := hashFunc() + h.Write(msg) + digest := h.Sum(nil) + + var sig []byte + if !pss { + sig, err = rsa.SignPKCS1v15(key, hashName, digest) + if err != nil { + return nil, fmt.Errorf("signing RSA message: %w", err) + } + } else { + sig, err = rsa.SignPSS(rand.Reader, key, hashFunc(), digest, h.Size()) + if err != nil { + return nil, fmt.Errorf("signing RSA message: %w", err) + } + } + + N, e, _, _, _, _, _, _ := key.Export() + eBytes := make([]byte, 4) + binary.BigEndian.PutUint32(eBytes, uint32(e)) + + return [][]byte{N, eBytes, sig}, nil + }, + } +} + +func cmdRsaSigVerAft(hashFunc func() fips140.Hash, hashName string, pss bool) command { + return command{ + requiredArgs: 4, // n, e, message, signature + handler: func(args [][]byte) ([][]byte, error) { + nBytes := args[0] + eBytes := args[1] + msg := args[2] + sig := args[3] + + paddedE := make([]byte, 4) + copy(paddedE[4-len(eBytes):], eBytes) + e := int(binary.BigEndian.Uint32(paddedE)) + + n, err := bigmod.NewModulus(nBytes) + if err != nil { + return nil, fmt.Errorf("invalid RSA modulus: %w", err) + } + + pub := &rsa.PublicKey{ + N: n, + E: e, + } + + h := hashFunc() + h.Write(msg) + digest := h.Sum(nil) + + if !pss { + err = rsa.VerifyPKCS1v15(pub, hashName, digest, sig) + } else { + err = rsa.VerifyPSS(pub, hashFunc(), digest, sig) + } + if err != nil { + return [][]byte{{0}}, nil + } + + return [][]byte{{1}}, nil + }, + } +} + +// rsaKeyCache caches generated keys by modulus bit-size. +var rsaKeyCache = map[int]*rsa.PrivateKey{} + +// getRSAKey returns a cached RSA private key with the specified modulus bit-size +// or generates one if necessary. +func getRSAKey(bits int) (*rsa.PrivateKey, error) { + if key, exists := rsaKeyCache[bits]; exists { + return key, nil + } + + key, err := rsa.GenerateKey(rand.Reader, bits) + if err != nil { + return nil, err + } + + rsaKeyCache[bits] = key + return key, nil +} + func TestACVP(t *testing.T) { testenv.SkipIfShortAndSlow(t) @@ -1641,7 +1784,7 @@ func TestACVP(t *testing.T) { bsslModule = "boringssl.googlesource.com/boringssl.git" bsslVersion = "v0.0.0-20250116010235-21f54b2730ee" goAcvpModule = "github.com/cpu/go-acvp" - goAcvpVersion = "v0.0.0-20250102201911-6839fc40f9f8" + goAcvpVersion = "v0.0.0-20250110181646-e47fea3b5d7d" ) // In crypto/tls/bogo_shim_test.go the test is skipped if run on a builder with runtime.GOOS == "windows" From 2e8973aeea66f01d9770e1d307330a2d188b27cc Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Fri, 3 Jan 2025 14:30:02 -0500 Subject: [PATCH 312/397] crypto/internal/fips140test: add feedback KDF ACVP tests Adds ACVP test coverage for the SP 800-108r1 KDF feedback mode algorithm based on the NIST spec: https://pages.nist.gov/ACVP/draft-celi-acvp-kbkdf.html The HKDF-based implementation in our FIPS module fixes some parameters, requiring tailoring of the advertised capability to match. Notably: * We only support fixedDataOrder "after fixed data" * We only support a counter length of 8 bits * We only support empty IVs No acvp_test.config.json update accompanies this support because the ACVP tests for this algorithm aren't amenable to fixed data testing. Updates #69642 Change-Id: I729e899377a64d2b613d6435241aebabeef93bca Reviewed-on: https://go-review.googlesource.com/c/go/+/640016 Reviewed-by: Filippo Valsorda Reviewed-by: Dmitri Shuralyov Reviewed-by: Roland Shoemaker LUCI-TryBot-Result: Go LUCI Auto-Submit: Filippo Valsorda --- .../fips140test/acvp_capabilities.json | 2 +- src/crypto/internal/fips140test/acvp_test.go | 60 +++++++++++++++++-- 2 files changed, 57 insertions(+), 5 deletions(-) diff --git a/src/crypto/internal/fips140test/acvp_capabilities.json b/src/crypto/internal/fips140test/acvp_capabilities.json index d6c1b02b43e98e..90e77ec8fa38d4 100644 --- a/src/crypto/internal/fips140test/acvp_capabilities.json +++ b/src/crypto/internal/fips140test/acvp_capabilities.json @@ -69,7 +69,7 @@ {"algorithm":"KAS-ECC-SSC","revision":"Sp800-56Ar3","scheme":{"ephemeralUnified":{"kasRole":["initiator","responder"]},"staticUnified":{"kasRole":["initiator","responder"]}},"domainParameterGenerationMethods":["P-224","P-256","P-384","P-521"]}, - {"algorithm":"KDF","revision":"1.0","capabilities":[{"kdfMode":"counter","macMode":["CMAC-AES128","CMAC-AES192","CMAC-AES256"],"supportedLengths":[256],"fixedDataOrder":["before fixed data"],"counterLength":[16]}]}, + {"algorithm":"KDF","revision":"1.0","capabilities":[{"kdfMode":"counter","macMode":["CMAC-AES128","CMAC-AES192","CMAC-AES256"],"supportedLengths":[256],"fixedDataOrder":["before fixed data"],"counterLength":[16]},{"kdfMode":"feedback","macMode":["HMAC-SHA2-224","HMAC-SHA2-256","HMAC-SHA2-384","HMAC-SHA2-512","HMAC-SHA2-512/224","HMAC-SHA2-512/256","HMAC-SHA3-224","HMAC-SHA3-256","HMAC-SHA3-384","HMAC-SHA3-512"],"customKeyInLength":0,"supportedLengths":[{"min":8,"max":4096,"increment":8}],"fixedDataOrder":["after fixed data"],"counterLength":[8],"supportsEmptyIv":true,"requiresEmptyIv":true}]}, {"algorithm":"RSA","mode":"keyGen","revision":"FIPS186-5","infoGeneratedByServer":true,"pubExpMode":"fixed","fixedPubExp":"010001","keyFormat":"standard","capabilities":[{"randPQ":"probable","properties":[{"modulo":2048,"primeTest":["2powSecStr"]},{"modulo":3072,"primeTest":["2powSecStr"]},{"modulo":4096,"primeTest":["2powSecStr"]}]}]}, {"algorithm":"RSA","mode":"sigGen","revision":"FIPS186-5","capabilities":[{"sigType":"pkcs1v1.5","properties":[{"modulo":2048,"hashPair":[{"hashAlg":"SHA2-224"},{"hashAlg":"SHA2-256"},{"hashAlg":"SHA2-384"},{"hashAlg":"SHA2-512"}]},{"modulo":3072,"hashPair":[{"hashAlg":"SHA2-224"},{"hashAlg":"SHA2-256"},{"hashAlg":"SHA2-384"},{"hashAlg":"SHA2-512"}]},{"modulo":4096,"hashPair":[{"hashAlg":"SHA2-224"},{"hashAlg":"SHA2-256"},{"hashAlg":"SHA2-384"},{"hashAlg":"SHA2-512"}]}]},{"sigType":"pss","properties":[{"maskFunction":["mgf1"],"modulo":2048,"hashPair":[{"hashAlg":"SHA2-224","saltLen":28},{"hashAlg":"SHA2-256","saltLen":32},{"hashAlg":"SHA2-384","saltLen":48},{"hashAlg":"SHA2-512","saltLen":64}]},{"maskFunction":["mgf1"],"modulo":3072,"hashPair":[{"hashAlg":"SHA2-224","saltLen":28},{"hashAlg":"SHA2-256","saltLen":32},{"hashAlg":"SHA2-384","saltLen":48},{"hashAlg":"SHA2-512","saltLen":64}]},{"maskFunction":["mgf1"],"modulo":4096,"hashPair":[{"hashAlg":"SHA2-224","saltLen":28},{"hashAlg":"SHA2-256","saltLen":32},{"hashAlg":"SHA2-384","saltLen":48},{"hashAlg":"SHA2-512","saltLen":64}]}]}]}, diff --git a/src/crypto/internal/fips140test/acvp_test.go b/src/crypto/internal/fips140test/acvp_test.go index 1552a07d61846f..5d16e521f9ce3f 100644 --- a/src/crypto/internal/fips140test/acvp_test.go +++ b/src/crypto/internal/fips140test/acvp_test.go @@ -131,7 +131,7 @@ var ( // https://pages.nist.gov/ACVP/draft-hammett-acvp-kas-ssc-ecc.html#section-7.3 // HMAC DRBG and CTR DRBG algorithm capabilities: // https://pages.nist.gov/ACVP/draft-vassilev-acvp-drbg.html#section-7.2 - // KDF-Counter algorithm capabilities: + // KDF-Counter and KDF-Feedback algorithm capabilities: // https://pages.nist.gov/ACVP/draft-celi-acvp-kbkdf.html#section-7.3 // RSA algorithm capabilities: // https://pages.nist.gov/ACVP/draft-celi-acvp-rsa.html#section-7.3 @@ -272,8 +272,6 @@ var ( "ctrDRBG/AES-256": cmdCtrDrbgAft(), "ctrDRBG-reseed/AES-256": cmdCtrDrbgReseedAft(), - "KDF-counter": cmdKdfCounterAft(), - "RSA/keyGen": cmdRsaKeyGenAft(), "RSA/sigGen/SHA2-224/pkcs1v1.5": cmdRsaSigGenAft(func() fips140.Hash { return sha256.New224() }, "SHA-224", false), @@ -293,6 +291,9 @@ var ( "RSA/sigVer/SHA2-256/pss": cmdRsaSigVerAft(func() fips140.Hash { return sha256.New() }, "SHA-256", true), "RSA/sigVer/SHA2-384/pss": cmdRsaSigVerAft(func() fips140.Hash { return sha512.New384() }, "SHA-384", true), "RSA/sigVer/SHA2-512/pss": cmdRsaSigVerAft(func() fips140.Hash { return sha512.New() }, "SHA-512", true), + + "KDF-counter": cmdKdfCounterAft(), + "KDF-feedback": cmdKdfFeedbackAft(), } ) @@ -1658,6 +1659,57 @@ func cmdKdfCounterAft() command { } } +func cmdKdfFeedbackAft() command { + return command{ + requiredArgs: 5, // Number output bytes, PRF name, counter location string, key, number of counter bits, IV + handler: func(args [][]byte) ([][]byte, error) { + // The max supported output len for the KDF algorithm type is 4096 bits, making an int cast + // here safe. + // See https://pages.nist.gov/ACVP/draft-celi-acvp-kbkdf.html#section-7.3.2 + outputBytes := int(binary.LittleEndian.Uint32(args[0])) + prf := string(args[1]) + counterLocation := args[2] + key := args[3] + counterBits := binary.LittleEndian.Uint32(args[4]) + + if !strings.HasPrefix(prf, "HMAC-") { + return nil, fmt.Errorf("feedback KDF received unsupported PRF %q", prf) + } + prf = prf[len("HMAC-"):] + + h, err := lookupHash(prf) + if err != nil { + return nil, fmt.Errorf("feedback KDF received unsupported PRF %q: %w", prf, err) + } + + if !bytes.Equal(counterLocation, []byte("after fixed data")) { + return nil, fmt.Errorf("feedback KDF received unsupported counter location %q", string(counterLocation)) + } + + // The spec doesn't describe the "deferred" property for a KDF counterMode test case. + // BoringSSL's acvptool sends an empty key when deferred=true, but with the capabilities + // we register all test cases have deferred=false and provide a key from the populated + // keyIn property. + if len(key) == 0 { + return nil, errors.New("deferred test cases are not supported") + } + + if counterBits != 8 { + return nil, fmt.Errorf("feedback KDF received unsupported counter length %d", counterBits) + } + + var context [12]byte + rand.Reader.Read(context[:]) + fixedData := make([]byte, 1+1+12) // 1 byte label (we pick null), 1 null byte, 12 bytes context. + copy(fixedData[2:], context[:]) + + result := hkdf.Expand(h, key, string(fixedData[:]), outputBytes) + + return [][]byte{key, fixedData[:], result[:]}, nil + }, + } +} + func cmdRsaKeyGenAft() command { return command{ requiredArgs: 1, // Modulus bit-size @@ -1782,7 +1834,7 @@ func TestACVP(t *testing.T) { const ( bsslModule = "boringssl.googlesource.com/boringssl.git" - bsslVersion = "v0.0.0-20250116010235-21f54b2730ee" + bsslVersion = "v0.0.0-20250123161947-ba24bde161f7" goAcvpModule = "github.com/cpu/go-acvp" goAcvpVersion = "v0.0.0-20250110181646-e47fea3b5d7d" ) From 371e83cd7b309988bbe6b1bc7d0bd72aff52aa08 Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Thu, 30 Jan 2025 15:53:06 -0800 Subject: [PATCH 313/397] os: add Root.Chmod For #67002 Change-Id: Id6c3a2096bd10f5f5f6921a0441dc6d9e6cdeb3b Reviewed-on: https://go-review.googlesource.com/c/go/+/645718 Commit-Queue: Damien Neil Reviewed-by: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Auto-Submit: Damien Neil --- api/next/67002.txt | 1 + doc/next/6-stdlib/99-minor/os/67002.md | 3 + src/internal/syscall/unix/asm_darwin.s | 1 + src/internal/syscall/unix/asm_openbsd.s | 2 + src/internal/syscall/unix/at.go | 17 +++++ src/internal/syscall/unix/at_darwin.go | 22 +++++++ src/internal/syscall/unix/at_libc.go | 21 +++++- src/internal/syscall/unix/at_openbsd.go | 22 +++++++ .../syscall/unix/at_sysnum_dragonfly.go | 1 + .../syscall/unix/at_sysnum_freebsd.go | 1 + src/internal/syscall/unix/at_sysnum_linux.go | 1 + src/internal/syscall/unix/at_sysnum_netbsd.go | 1 + src/internal/syscall/unix/at_wasip1.go | 5 ++ src/internal/syscall/windows/at_windows.go | 8 ++- .../syscall/windows/at_windows_test.go | 2 +- src/os/root.go | 11 ++++ src/os/root_noopenat.go | 10 +++ src/os/root_openat.go | 10 +++ src/os/root_test.go | 66 +++++++++++++++++++ src/os/root_unix.go | 26 ++++++++ src/os/root_windows.go | 46 ++++++++++++- src/syscall/types_windows.go | 1 + 22 files changed, 273 insertions(+), 5 deletions(-) create mode 100644 api/next/67002.txt create mode 100644 doc/next/6-stdlib/99-minor/os/67002.md diff --git a/api/next/67002.txt b/api/next/67002.txt new file mode 100644 index 00000000000000..06119c0e754589 --- /dev/null +++ b/api/next/67002.txt @@ -0,0 +1 @@ +pkg os, method (*Root) Chmod(string, fs.FileMode) error #67002 diff --git a/doc/next/6-stdlib/99-minor/os/67002.md b/doc/next/6-stdlib/99-minor/os/67002.md new file mode 100644 index 00000000000000..a0751c30e2fec3 --- /dev/null +++ b/doc/next/6-stdlib/99-minor/os/67002.md @@ -0,0 +1,3 @@ +The [os.Root] type supports the following additional methods: + + * [os.Root.Chmod] diff --git a/src/internal/syscall/unix/asm_darwin.s b/src/internal/syscall/unix/asm_darwin.s index b96eb1e80752fa..de6e01ee4a4fe3 100644 --- a/src/internal/syscall/unix/asm_darwin.s +++ b/src/internal/syscall/unix/asm_darwin.s @@ -25,3 +25,4 @@ TEXT ·libc_sysconf_trampoline(SB),NOSPLIT,$0-0; JMP libc_sysconf(SB) TEXT ·libc_faccessat_trampoline(SB),NOSPLIT,$0-0; JMP libc_faccessat(SB) TEXT ·libc_readlinkat_trampoline(SB),NOSPLIT,$0-0; JMP libc_readlinkat(SB) TEXT ·libc_mkdirat_trampoline(SB),NOSPLIT,$0-0; JMP libc_mkdirat(SB) +TEXT ·libc_fchmodat_trampoline(SB),NOSPLIT,$0-0; JMP libc_fchmodat(SB) diff --git a/src/internal/syscall/unix/asm_openbsd.s b/src/internal/syscall/unix/asm_openbsd.s index 90f6831e4e53dc..306ef4664d57d8 100644 --- a/src/internal/syscall/unix/asm_openbsd.s +++ b/src/internal/syscall/unix/asm_openbsd.s @@ -14,3 +14,5 @@ TEXT ·libc_readlinkat_trampoline(SB),NOSPLIT,$0-0 JMP libc_readlinkat(SB) TEXT ·libc_mkdirat_trampoline(SB),NOSPLIT,$0-0 JMP libc_mkdirat(SB) +TEXT ·libc_fchmodat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fchmodat(SB) diff --git a/src/internal/syscall/unix/at.go b/src/internal/syscall/unix/at.go index 27a798e0461d70..2a29dd6a5a3ac7 100644 --- a/src/internal/syscall/unix/at.go +++ b/src/internal/syscall/unix/at.go @@ -79,3 +79,20 @@ func Mkdirat(dirfd int, path string, mode uint32) error { } return nil } + +func Fchmodat(dirfd int, path string, mode uint32, flags int) error { + p, err := syscall.BytePtrFromString(path) + if err != nil { + return err + } + _, _, errno := syscall.Syscall6(fchmodatTrap, + uintptr(dirfd), + uintptr(unsafe.Pointer(p)), + uintptr(mode), + uintptr(flags), + 0, 0) + if errno != 0 { + return errno + } + return nil +} diff --git a/src/internal/syscall/unix/at_darwin.go b/src/internal/syscall/unix/at_darwin.go index dbcae5a7889a0a..759b0943f558c3 100644 --- a/src/internal/syscall/unix/at_darwin.go +++ b/src/internal/syscall/unix/at_darwin.go @@ -58,3 +58,25 @@ func Mkdirat(dirfd int, path string, mode uint32) error { } return nil } + +func libc_fchmodat_trampoline() + +//go:cgo_import_dynamic libc_fchmodat fchmodat "/usr/lib/libSystem.B.dylib" + +func Fchmodat(dirfd int, path string, mode uint32, flags int) error { + p, err := syscall.BytePtrFromString(path) + if err != nil { + return err + } + _, _, errno := syscall_syscall6(abi.FuncPCABI0(libc_fchmodat_trampoline), + uintptr(dirfd), + uintptr(unsafe.Pointer(p)), + uintptr(mode), + uintptr(flags), + 0, + 0) + if errno != 0 { + return errno + } + return nil +} diff --git a/src/internal/syscall/unix/at_libc.go b/src/internal/syscall/unix/at_libc.go index faf38be602af65..f88e09d31db417 100644 --- a/src/internal/syscall/unix/at_libc.go +++ b/src/internal/syscall/unix/at_libc.go @@ -16,13 +16,15 @@ import ( //go:linkname procUnlinkat libc_unlinkat //go:linkname procReadlinkat libc_readlinkat //go:linkname procMkdirat libc_mkdirat +//go:linkname procFchmodat libc_fchmodat var ( procFstatat, procOpenat, procUnlinkat, procReadlinkat, - procMkdirat uintptr + procMkdirat, + procFchmodat uintptr ) func Unlinkat(dirfd int, path string, flags int) error { @@ -107,3 +109,20 @@ func Mkdirat(dirfd int, path string, mode uint32) error { } return nil } + +func Fchmodat(dirfd int, path string, mode uint32, flags int) error { + p, err := syscall.BytePtrFromString(path) + if err != nil { + return err + } + _, _, errno := syscall6(uintptr(unsafe.Pointer(&procFchmodat)), 4, + uintptr(dirfd), + uintptr(unsafe.Pointer(p)), + uintptr(mode), + uintptr(flags), + 0, 0) + if errno != 0 { + return errno + } + return nil +} diff --git a/src/internal/syscall/unix/at_openbsd.go b/src/internal/syscall/unix/at_openbsd.go index 69463e00b94be9..26ca70322b7f15 100644 --- a/src/internal/syscall/unix/at_openbsd.go +++ b/src/internal/syscall/unix/at_openbsd.go @@ -49,3 +49,25 @@ func Mkdirat(dirfd int, path string, mode uint32) error { } return nil } + +//go:cgo_import_dynamic libc_fchmodat fchmodat "libc.so" + +func libc_fchmodat_trampoline() + +func Fchmodat(dirfd int, path string, mode uint32, flags int) error { + p, err := syscall.BytePtrFromString(path) + if err != nil { + return err + } + _, _, errno := syscall_syscall6(abi.FuncPCABI0(libc_fchmodat_trampoline), + uintptr(dirfd), + uintptr(unsafe.Pointer(p)), + uintptr(mode), + uintptr(flags), + 0, + 0) + if errno != 0 { + return errno + } + return nil +} diff --git a/src/internal/syscall/unix/at_sysnum_dragonfly.go b/src/internal/syscall/unix/at_sysnum_dragonfly.go index d0ba12a78af055..84c60c47b8ac5c 100644 --- a/src/internal/syscall/unix/at_sysnum_dragonfly.go +++ b/src/internal/syscall/unix/at_sysnum_dragonfly.go @@ -12,6 +12,7 @@ const ( fstatatTrap uintptr = syscall.SYS_FSTATAT readlinkatTrap uintptr = syscall.SYS_READLINKAT mkdiratTrap uintptr = syscall.SYS_MKDIRAT + fchmodatTrap uintptr = syscall.SYS_FCHMODAT AT_EACCESS = 0x4 AT_FDCWD = 0xfffafdcd diff --git a/src/internal/syscall/unix/at_sysnum_freebsd.go b/src/internal/syscall/unix/at_sysnum_freebsd.go index 0f347224322653..22ff4e7e895c58 100644 --- a/src/internal/syscall/unix/at_sysnum_freebsd.go +++ b/src/internal/syscall/unix/at_sysnum_freebsd.go @@ -19,4 +19,5 @@ const ( posixFallocateTrap uintptr = syscall.SYS_POSIX_FALLOCATE readlinkatTrap uintptr = syscall.SYS_READLINKAT mkdiratTrap uintptr = syscall.SYS_MKDIRAT + fchmodatTrap uintptr = syscall.SYS_FCHMODAT ) diff --git a/src/internal/syscall/unix/at_sysnum_linux.go b/src/internal/syscall/unix/at_sysnum_linux.go index 2885c7c68106e9..8fba319cab7dbd 100644 --- a/src/internal/syscall/unix/at_sysnum_linux.go +++ b/src/internal/syscall/unix/at_sysnum_linux.go @@ -11,6 +11,7 @@ const ( openatTrap uintptr = syscall.SYS_OPENAT readlinkatTrap uintptr = syscall.SYS_READLINKAT mkdiratTrap uintptr = syscall.SYS_MKDIRAT + fchmodatTrap uintptr = syscall.SYS_FCHMODAT ) const ( diff --git a/src/internal/syscall/unix/at_sysnum_netbsd.go b/src/internal/syscall/unix/at_sysnum_netbsd.go index 820b977436377f..f2b7a4f9ebfe8a 100644 --- a/src/internal/syscall/unix/at_sysnum_netbsd.go +++ b/src/internal/syscall/unix/at_sysnum_netbsd.go @@ -12,6 +12,7 @@ const ( fstatatTrap uintptr = syscall.SYS_FSTATAT readlinkatTrap uintptr = syscall.SYS_READLINKAT mkdiratTrap uintptr = syscall.SYS_MKDIRAT + fchmodatTrap uintptr = syscall.SYS_FCHMODAT ) const ( diff --git a/src/internal/syscall/unix/at_wasip1.go b/src/internal/syscall/unix/at_wasip1.go index cd0cb4b7e47350..7289317110f855 100644 --- a/src/internal/syscall/unix/at_wasip1.go +++ b/src/internal/syscall/unix/at_wasip1.go @@ -101,6 +101,11 @@ func Mkdirat(dirfd int, path string, mode uint32) error { )) } +func Fchmodat(dirfd int, path string, mode uint32, flags int) error { + // WASI preview 1 doesn't support changing file modes. + return syscall.ENOSYS +} + //go:wasmimport wasi_snapshot_preview1 path_create_directory //go:noescape func path_create_directory(fd int32, path *byte, pathLen size) syscall.Errno diff --git a/src/internal/syscall/windows/at_windows.go b/src/internal/syscall/windows/at_windows.go index 18429773c060e7..19bcc0dbac10ce 100644 --- a/src/internal/syscall/windows/at_windows.go +++ b/src/internal/syscall/windows/at_windows.go @@ -20,9 +20,10 @@ const ( O_DIRECTORY = 0x100000 // target must be a directory O_NOFOLLOW_ANY = 0x20000000 // disallow symlinks anywhere in the path O_OPEN_REPARSE = 0x40000000 // FILE_OPEN_REPARSE_POINT, used by Lstat + O_WRITE_ATTRS = 0x80000000 // FILE_WRITE_ATTRIBUTES, used by Chmod ) -func Openat(dirfd syscall.Handle, name string, flag int, perm uint32) (_ syscall.Handle, e1 error) { +func Openat(dirfd syscall.Handle, name string, flag uint64, perm uint32) (_ syscall.Handle, e1 error) { if len(name) == 0 { return syscall.InvalidHandle, syscall.ERROR_FILE_NOT_FOUND } @@ -61,6 +62,9 @@ func Openat(dirfd syscall.Handle, name string, flag int, perm uint32) (_ syscall if flag&syscall.O_SYNC != 0 { options |= FILE_WRITE_THROUGH } + if flag&O_WRITE_ATTRS != 0 { + access |= FILE_WRITE_ATTRIBUTES + } // Allow File.Stat. access |= STANDARD_RIGHTS_READ | FILE_READ_ATTRIBUTES | FILE_READ_EA @@ -129,7 +133,7 @@ func Openat(dirfd syscall.Handle, name string, flag int, perm uint32) (_ syscall } // ntCreateFileError maps error returns from NTCreateFile to user-visible errors. -func ntCreateFileError(err error, flag int) error { +func ntCreateFileError(err error, flag uint64) error { s, ok := err.(NTStatus) if !ok { // Shouldn't really be possible, NtCreateFile always returns NTStatus. diff --git a/src/internal/syscall/windows/at_windows_test.go b/src/internal/syscall/windows/at_windows_test.go index 7da9ecf07a2f73..daeb4fcde37d70 100644 --- a/src/internal/syscall/windows/at_windows_test.go +++ b/src/internal/syscall/windows/at_windows_test.go @@ -46,7 +46,7 @@ func TestOpen(t *testing.T) { continue } base := filepath.Base(tt.path) - h, err := windows.Openat(dirfd, base, tt.flag, 0o660) + h, err := windows.Openat(dirfd, base, uint64(tt.flag), 0o660) syscall.CloseHandle(dirfd) if err == nil { syscall.CloseHandle(h) diff --git a/src/os/root.go b/src/os/root.go index f91c0f75f30e2a..cd26144ab7410f 100644 --- a/src/os/root.go +++ b/src/os/root.go @@ -54,11 +54,16 @@ func OpenInRoot(dir, name string) (*File, error) { // // - When GOOS=windows, file names may not reference Windows reserved device names // such as NUL and COM1. +// - On Unix, [Root.Chmod] and [Root.Chown] are vulnerable to a race condition. +// If the target of the operation is changed from a regular file to a symlink +// while the operation is in progress, the operation may be peformed on the link +// rather than the link target. // - When GOOS=js, Root is vulnerable to TOCTOU (time-of-check-time-of-use) // attacks in symlink validation, and cannot ensure that operations will not // escape the root. // - When GOOS=plan9 or GOOS=js, Root does not track directories across renames. // On these platforms, a Root references a directory name, not a file descriptor. +// - WASI preview 1 (GOOS=wasip1) does not support [Root.Chmod]. type Root struct { root *root } @@ -127,6 +132,12 @@ func (r *Root) OpenRoot(name string) (*Root, error) { return openRootInRoot(r, name) } +// Chmod changes the mode of the named file in the root to mode. +// See [Chmod] for more details. +func (r *Root) Chmod(name string, mode FileMode) error { + return rootChmod(r, name, mode) +} + // Mkdir creates a new directory in the root // with the specified name and permission bits (before umask). // See [Mkdir] for more details. diff --git a/src/os/root_noopenat.go b/src/os/root_noopenat.go index 8be55a029fa2b6..819486f289f397 100644 --- a/src/os/root_noopenat.go +++ b/src/os/root_noopenat.go @@ -95,6 +95,16 @@ func rootStat(r *Root, name string, lstat bool) (FileInfo, error) { return fi, nil } +func rootChmod(r *Root, name string, mode FileMode) error { + if err := checkPathEscapes(r, name); err != nil { + return &PathError{Op: "chmodat", Path: name, Err: err} + } + if err := Chmod(joinPath(r.root.name, name), mode); err != nil { + return &PathError{Op: "chmodat", Path: name, Err: underlyingError(err)} + } + return nil +} + func rootMkdir(r *Root, name string, perm FileMode) error { if err := checkPathEscapes(r, name); err != nil { return &PathError{Op: "mkdirat", Path: name, Err: err} diff --git a/src/os/root_openat.go b/src/os/root_openat.go index a03208b4c170e9..97e389db8d2352 100644 --- a/src/os/root_openat.go +++ b/src/os/root_openat.go @@ -64,6 +64,16 @@ func (r *root) Name() string { return r.name } +func rootChmod(r *Root, name string, mode FileMode) error { + _, err := doInRoot(r, name, func(parent sysfdType, name string) (struct{}, error) { + return struct{}{}, chmodat(parent, name, mode) + }) + if err != nil { + return &PathError{Op: "chmodat", Path: name, Err: err} + } + return err +} + func rootMkdir(r *Root, name string, perm FileMode) error { _, err := doInRoot(r, name, func(parent sysfdType, name string) (struct{}, error) { return struct{}{}, mkdirat(parent, name, perm) diff --git a/src/os/root_test.go b/src/os/root_test.go index cbb985b2ceeb48..3591214ffd7043 100644 --- a/src/os/root_test.go +++ b/src/os/root_test.go @@ -389,6 +389,43 @@ func TestRootCreate(t *testing.T) { } } +func TestRootChmod(t *testing.T) { + if runtime.GOOS == "wasip1" { + t.Skip("Chmod not supported on " + runtime.GOOS) + } + for _, test := range rootTestCases { + test.run(t, func(t *testing.T, target string, root *os.Root) { + if target != "" { + // Create a file with no read/write permissions, + // to ensure we can use Chmod on an inaccessible file. + if err := os.WriteFile(target, nil, 0o000); err != nil { + t.Fatal(err) + } + } + if runtime.GOOS == "windows" { + // On Windows, Chmod("symlink") affects the link, not its target. + // See issue 71492. + fi, err := root.Lstat(test.open) + if err == nil && !fi.Mode().IsRegular() { + t.Skip("https://go.dev/issue/71492") + } + } + want := os.FileMode(0o666) + err := root.Chmod(test.open, want) + if errEndsTest(t, err, test.wantError, "root.Chmod(%q)", test.open) { + return + } + st, err := os.Stat(target) + if err != nil { + t.Fatalf("os.Stat(%q) = %v", target, err) + } + if got := st.Mode(); got != want { + t.Errorf("after root.Chmod(%q, %v): file mode = %v, want %v", test.open, want, got, want) + } + }) + } +} + func TestRootMkdir(t *testing.T) { for _, test := range rootTestCases { test.run(t, func(t *testing.T, target string, root *os.Root) { @@ -877,6 +914,35 @@ func TestRootConsistencyCreate(t *testing.T) { } } +func TestRootConsistencyChmod(t *testing.T) { + if runtime.GOOS == "wasip1" { + t.Skip("Chmod not supported on " + runtime.GOOS) + } + for _, test := range rootConsistencyTestCases { + test.run(t, func(t *testing.T, path string, r *os.Root) (string, error) { + chmod := os.Chmod + lstat := os.Lstat + if r != nil { + chmod = r.Chmod + lstat = r.Lstat + } + + var m1, m2 os.FileMode + err := chmod(path, 0o555) + fi, err := lstat(path) + if err == nil { + m1 = fi.Mode() + } + err = chmod(path, 0o777) + fi, err = lstat(path) + if err == nil { + m2 = fi.Mode() + } + return fmt.Sprintf("%v %v", m1, m2), err + }) + } +} + func TestRootConsistencyMkdir(t *testing.T) { for _, test := range rootConsistencyTestCases { test.run(t, func(t *testing.T, path string, r *os.Root) (string, error) { diff --git a/src/os/root_unix.go b/src/os/root_unix.go index 02d3b4bdad007e..31773ef6817b92 100644 --- a/src/os/root_unix.go +++ b/src/os/root_unix.go @@ -131,6 +131,32 @@ func rootStat(r *Root, name string, lstat bool) (FileInfo, error) { return fi, nil } +// On systems which use fchmodat, fchownat, etc., we have a race condition: +// When "name" is a symlink, Root.Chmod("name") should act on the target of that link. +// However, fchmodat doesn't allow us to chmod a file only if it is not a symlink; +// the AT_SYMLINK_NOFOLLOW parameter causes the operation to act on the symlink itself. +// +// We do the best we can by first checking to see if the target of the operation is a symlink, +// and only attempting the fchmodat if it is not. If the target is replaced between the check +// and the fchmodat, we will chmod the symlink rather than following it. +// +// This race condition is unfortunate, but does not permit escaping a root: +// We may act on the wrong file, but that file will be contained within the root. +func afterResolvingSymlink(parent int, name string, f func() error) error { + if err := checkSymlink(parent, name, nil); err != nil { + return err + } + return f() +} + +func chmodat(parent int, name string, mode FileMode) error { + return afterResolvingSymlink(parent, name, func() error { + return ignoringEINTR(func() error { + return unix.Fchmodat(parent, name, syscallMode(mode), unix.AT_SYMLINK_NOFOLLOW) + }) + }) +} + func mkdirat(fd int, name string, perm FileMode) error { return ignoringEINTR(func() error { return unix.Mkdirat(fd, name, syscallMode(perm)) diff --git a/src/os/root_windows.go b/src/os/root_windows.go index 32dfa070b740fd..ba809bd6e0ba94 100644 --- a/src/os/root_windows.go +++ b/src/os/root_windows.go @@ -134,7 +134,7 @@ func rootOpenFileNolog(root *Root, name string, flag int, perm FileMode) (*File, } func openat(dirfd syscall.Handle, name string, flag int, perm FileMode) (syscall.Handle, error) { - h, err := windows.Openat(dirfd, name, flag|syscall.O_CLOEXEC|windows.O_NOFOLLOW_ANY, syscallMode(perm)) + h, err := windows.Openat(dirfd, name, uint64(flag)|syscall.O_CLOEXEC|windows.O_NOFOLLOW_ANY, syscallMode(perm)) if err == syscall.ELOOP || err == syscall.ENOTDIR { if link, err := readReparseLinkAt(dirfd, name); err == nil { return syscall.InvalidHandle, errSymlink(link) @@ -232,6 +232,50 @@ func rootStat(r *Root, name string, lstat bool) (FileInfo, error) { return fi, nil } +func chmodat(parent syscall.Handle, name string, mode FileMode) error { + // Currently, on Windows os.Chmod("symlink") will act on "symlink", + // not on any file it points to. + // + // This may or may not be the desired behavior: https://go.dev/issue/71492 + // + // For now, be consistent with os.Symlink. + // Passing O_OPEN_REPARSE causes us to open the named file itself, + // not any file that it links to. + // + // If we want to change this in the future, pass O_NOFOLLOW_ANY instead + // and return errSymlink when encountering a symlink: + // + // if err == syscall.ELOOP || err == syscall.ENOTDIR { + // if link, err := readReparseLinkAt(parent, name); err == nil { + // return errSymlink(link) + // } + // } + h, err := windows.Openat(parent, name, syscall.O_CLOEXEC|windows.O_OPEN_REPARSE|windows.O_WRITE_ATTRS, 0) + if err != nil { + return err + } + defer syscall.CloseHandle(h) + + var d syscall.ByHandleFileInformation + if err := syscall.GetFileInformationByHandle(h, &d); err != nil { + return err + } + attrs := d.FileAttributes + + if mode&syscall.S_IWRITE != 0 { + attrs &^= syscall.FILE_ATTRIBUTE_READONLY + } else { + attrs |= syscall.FILE_ATTRIBUTE_READONLY + } + if attrs == d.FileAttributes { + return nil + } + + var fbi windows.FILE_BASIC_INFO + fbi.FileAttributes = attrs + return windows.SetFileInformationByHandle(h, windows.FileBasicInfo, unsafe.Pointer(&fbi), uint32(unsafe.Sizeof(fbi))) +} + func mkdirat(dirfd syscall.Handle, name string, perm FileMode) error { return windows.Mkdirat(dirfd, name, syscallMode(perm)) } diff --git a/src/syscall/types_windows.go b/src/syscall/types_windows.go index fa340531782bd5..b61889cc438640 100644 --- a/src/syscall/types_windows.go +++ b/src/syscall/types_windows.go @@ -49,6 +49,7 @@ const ( o_DIRECTORY = 0x100000 // used by internal/syscall/windows o_NOFOLLOW_ANY = 0x20000000 // used by internal/syscall/windows o_OPEN_REPARSE = 0x40000000 // used by internal/syscall/windows + o_WRITE_ATTRS = 0x80000000 // used by internal/syscall/windows ) const ( From 7c1a4134b4191e87ae05d07343329e83aada6132 Mon Sep 17 00:00:00 2001 From: cuishuang Date: Fri, 7 Feb 2025 17:11:36 +0800 Subject: [PATCH 314/397] strings: add examples for Lines, SplitSeq, SplitAfterSeq, FieldsSeq and FieldsFuncSeq Change-Id: I1e5085ff2ed7f3d75ac3dc34ab72be6b55729fb7 Reviewed-on: https://go-review.googlesource.com/c/go/+/647575 Auto-Submit: Ian Lance Taylor Auto-Submit: Dmitri Shuralyov Reviewed-by: Dmitri Shuralyov Commit-Queue: Ian Lance Taylor Reviewed-by: Ian Lance Taylor Reviewed-by: Dmitri Shuralyov LUCI-TryBot-Result: Go LUCI --- src/strings/example_test.go | 90 +++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/src/strings/example_test.go b/src/strings/example_test.go index 08efcbf68ff0f6..da95d1e58e6499 100644 --- a/src/strings/example_test.go +++ b/src/strings/example_test.go @@ -458,3 +458,93 @@ func ExampleToValidUTF8() { // abc // abc } + +func ExampleLines() { + text := "Hello\nWorld\nGo Programming\n" + for line := range strings.Lines(text) { + fmt.Printf("%q\n", line) + } + + // Output: + // "Hello\n" + // "World\n" + // "Go Programming\n" +} + +func ExampleSplitSeq() { + s := "a,b,c,d" + for part := range strings.SplitSeq(s, ",") { + fmt.Printf("%q\n", part) + } + + // Output: + // "a" + // "b" + // "c" + // "d" +} + +func ExampleSplitAfterSeq() { + s := "a,b,c,d" + for part := range strings.SplitAfterSeq(s, ",") { + fmt.Printf("%q\n", part) + } + + // Output: + // "a," + // "b," + // "c," + // "d" +} + +func ExampleFieldsSeq() { + text := "The quick brown fox" + fmt.Println("Split string into fields:") + for word := range strings.FieldsSeq(text) { + fmt.Printf("%q\n", word) + } + + textWithSpaces := " lots of spaces " + fmt.Println("\nSplit string with multiple spaces:") + for word := range strings.FieldsSeq(textWithSpaces) { + fmt.Printf("%q\n", word) + } + + // Output: + // Split string into fields: + // "The" + // "quick" + // "brown" + // "fox" + // + // Split string with multiple spaces: + // "lots" + // "of" + // "spaces" +} + +func ExampleFieldsFuncSeq() { + text := "The quick brown fox" + fmt.Println("Split on whitespace(similar to FieldsSeq):") + for word := range strings.FieldsFuncSeq(text, unicode.IsSpace) { + fmt.Printf("%q\n", word) + } + + mixedText := "abc123def456ghi" + fmt.Println("\nSplit on digits:") + for word := range strings.FieldsFuncSeq(mixedText, unicode.IsDigit) { + fmt.Printf("%q\n", word) + } + + // Output: + // Split on whitespace(similar to FieldsSeq): + // "The" + // "quick" + // "brown" + // "fox" + // + // Split on digits: + // "abc" + // "def" + // "ghi" +} From 887d9ef6101c6efeef00b0c7c80e634ff983fdcc Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Mon, 10 Feb 2025 23:54:56 +0000 Subject: [PATCH 315/397] internal/trace: increment sync counter before final Sync on error CL 648195 was supposed to have fixed #71615, but it didn't include an update to r.syncs. I can confirm this CL fixes the issue even when running the test many times in a row. Fixes #71615. Change-Id: I97db3d639dc5bc8648a191696f90b0e5087307c8 Reviewed-on: https://go-review.googlesource.com/c/go/+/648315 Auto-Submit: Michael Knyszek Reviewed-by: Cherry Mui TryBot-Bypass: Michael Knyszek --- src/internal/trace/reader.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/internal/trace/reader.go b/src/internal/trace/reader.go index 75b88f7bac5fbc..f5f871763fd9cf 100644 --- a/src/internal/trace/reader.go +++ b/src/internal/trace/reader.go @@ -154,6 +154,7 @@ func (r *Reader) ReadEvent() (e Event, err error) { // Read the next generation. r.gen, r.spill, r.spillErr = readGeneration(r.r, r.spill) if r.gen == nil { + r.syncs++ return syncEvent(nil, r.lastTs, r.syncs), nil } From dcbdc1a2f7368ad8a9193e969cc76c7ffd2f7685 Mon Sep 17 00:00:00 2001 From: Sean Liao Date: Sun, 9 Feb 2025 13:32:27 +0000 Subject: [PATCH 316/397] cmd/go/internal/modload: don't set GIT_SSH_COMMAND MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allows git core.sshcommand to take effect when set by the user. This was originally added to work around an issue in OpenSSH < 7.3 (2016), see https://go.dev/issue/13453 . A fixed version of OpenSSH should be widely available enough that it is no longer necessary Fixes #71482 Change-Id: I6f44cc354e8a4063e226cac78ec27117fcc40e93 Reviewed-on: https://go-review.googlesource.com/c/go/+/647995 Reviewed-by: Sam Thanawalla Auto-Submit: Daniel Martí LUCI-TryBot-Result: Go LUCI Reviewed-by: Michael Matloob --- src/cmd/go/internal/modload/init.go | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/cmd/go/internal/modload/init.go b/src/cmd/go/internal/modload/init.go index 8fdcd0da6328f6..5d01aedc2f3f8e 100644 --- a/src/cmd/go/internal/modload/init.go +++ b/src/cmd/go/internal/modload/init.go @@ -452,23 +452,6 @@ func Init() { os.Setenv("GIT_TERMINAL_PROMPT", "0") } - // Disable any ssh connection pooling by Git. - // If a Git subprocess forks a child into the background to cache a new connection, - // that child keeps stdout/stderr open. After the Git subprocess exits, - // os/exec expects to be able to read from the stdout/stderr pipe - // until EOF to get all the data that the Git subprocess wrote before exiting. - // The EOF doesn't come until the child exits too, because the child - // is holding the write end of the pipe. - // This is unfortunate, but it has come up at least twice - // (see golang.org/issue/13453 and golang.org/issue/16104) - // and confuses users when it does. - // If the user has explicitly set GIT_SSH or GIT_SSH_COMMAND, - // assume they know what they are doing and don't step on it. - // But default to turning off ControlMaster. - if os.Getenv("GIT_SSH") == "" && os.Getenv("GIT_SSH_COMMAND") == "" { - os.Setenv("GIT_SSH_COMMAND", "ssh -o ControlMaster=no -o BatchMode=yes") - } - if os.Getenv("GCM_INTERACTIVE") == "" { os.Setenv("GCM_INTERACTIVE", "never") } From 450f3f608d409e2b3d76af071ec726efacbdd17b Mon Sep 17 00:00:00 2001 From: Sean Liao Date: Fri, 19 Jul 2024 23:28:54 +0100 Subject: [PATCH 317/397] net/http/httptest: match net/http ContentLength behavior for http.NoBody MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #68476 Change-Id: I05122e5ec5e6b290eec93f3db444fcf1de19c030 Reviewed-on: https://go-review.googlesource.com/c/go/+/599815 LUCI-TryBot-Result: Go LUCI Reviewed-by: Damien Neil Reviewed-by: Dmitri Shuralyov Auto-Submit: Daniel Martí --- src/net/http/httptest/httptest.go | 9 ++++++--- src/net/http/httptest/httptest_test.go | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/net/http/httptest/httptest.go b/src/net/http/httptest/httptest.go index 0c0dbb40e89bc5..7fe7107a9a191c 100644 --- a/src/net/http/httptest/httptest.go +++ b/src/net/http/httptest/httptest.go @@ -34,9 +34,9 @@ func NewRequest(method, target string, body io.Reader) *http.Request { // // An empty method means "GET". // -// The provided body may be nil. If the body is of type *bytes.Reader, -// *strings.Reader, or *bytes.Buffer, the Request.ContentLength is -// set. +// The provided body may be nil. If the body is of type [bytes.Reader], +// [strings.Reader], [bytes.Buffer], or the value [http.NoBody], +// the Request.ContentLength is set. // // NewRequest panics on error for ease of use in testing, where a // panic is acceptable. @@ -69,6 +69,9 @@ func NewRequestWithContext(ctx context.Context, method, target string, body io.R default: req.ContentLength = -1 } + if body == http.NoBody { + req.ContentLength = 0 + } if rc, ok := body.(io.ReadCloser); ok { req.Body = rc } else { diff --git a/src/net/http/httptest/httptest_test.go b/src/net/http/httptest/httptest_test.go index d5a4c3dc9d19a1..5f2215cfc6cdc1 100644 --- a/src/net/http/httptest/httptest_test.go +++ b/src/net/http/httptest/httptest_test.go @@ -156,6 +156,24 @@ func TestNewRequestWithContext(t *testing.T) { wantBody: "foo", }, + { + name: "Post with NoBody", + method: "POST", + uri: "/", + body: http.NoBody, + want: &http.Request{ + Method: "POST", + Host: "example.com", + URL: &url.URL{Path: "/"}, + Header: http.Header{}, + Proto: "HTTP/1.1", + ProtoMajor: 1, + ProtoMinor: 1, + RemoteAddr: "192.0.2.1:1234", + RequestURI: "/", + }, + }, + { name: "OPTIONS *", method: "OPTIONS", From e9eb88ae7291bf9f1b05e8e4860474c734c5448d Mon Sep 17 00:00:00 2001 From: qmuntal Date: Tue, 11 Feb 2025 09:17:08 +0100 Subject: [PATCH 318/397] {all,clean,make,race,run}.bat: simplify error handling The bat files can use "if" + parentheses to make it easier to understand how the if-case is handled rather than the more cryptic "if" + "goto". While here, replace some "goto"s with direct "exit" calls. Change-Id: I20e1804439b5088f8f1e5cbf8676f3d58560109d Reviewed-on: https://go-review.googlesource.com/c/go/+/648375 Auto-Submit: Damien Neil Reviewed-by: Damien Neil LUCI-TryBot-Result: Go LUCI Reviewed-by: Cherry Mui --- src/all.bat | 16 ++++++---------- src/clean.bat | 15 +++++---------- src/make.bat | 28 ++++++++++++---------------- src/race.bat | 34 +++++++++++++--------------------- src/run.bat | 16 ++++++---------- 5 files changed, 42 insertions(+), 67 deletions(-) diff --git a/src/all.bat b/src/all.bat index cb4536284e1a58..4c681d15eb643e 100644 --- a/src/all.bat +++ b/src/all.bat @@ -6,15 +6,11 @@ setlocal -if exist make.bat goto ok -echo all.bat must be run from go\src -exit /b 1 -:ok +if not exist make.bat ( + echo all.bat must be run from go\src + exit /b 1 +) -call .\make.bat --no-banner || goto fail -call .\run.bat --no-rebuild || goto fail +call .\make.bat --no-banner || exit /b 1 +call .\run.bat --no-rebuild || exit /b 1 ..\bin\go tool dist banner -goto :eof - -:fail -exit /b 1 diff --git a/src/clean.bat b/src/clean.bat index 51fa857b7c7ac7..2e03806305b433 100644 --- a/src/clean.bat +++ b/src/clean.bat @@ -6,21 +6,16 @@ setlocal -go tool dist env -w -p >env.bat || goto fail +go tool dist env -w -p >env.bat || exit /b 1 call .\env.bat del env.bat echo. -if exist %GOTOOLDIR%\dist.exe goto distok -echo cannot find %GOTOOLDIR%\dist; nothing to clean -goto fail -:distok +if not exist %GOTOOLDIR%\dist.exe ( + echo cannot find %GOTOOLDIR%\dist.exe; nothing to clean + exit /b 1 +) "%GOBIN%\go" clean -i std "%GOBIN%\go" tool dist clean "%GOBIN%\go" clean -i cmd - -goto :eof - -:fail -exit /b 1 diff --git a/src/make.bat b/src/make.bat index 0d5dd2761a7155..890829131ba317 100644 --- a/src/make.bat +++ b/src/make.bat @@ -36,10 +36,10 @@ setlocal -if exist make.bat goto ok -echo Must run make.bat from Go src directory. -goto fail -:ok +if not exist make.bat ( + echo Must run make.bat from Go src directory. + exit /b 1 +) :: Clean old generated file that will cause problems in the build. del /F ".\pkg\runtime\runtime_defs.go" 2>NUL @@ -78,7 +78,11 @@ if "x%GOROOT_BOOTSTRAP%"=="x" if exist "%HOMEDRIVE%%HOMEPATH%\sdk\go%bootgo%" se if "x%GOROOT_BOOTSTRAP%"=="x" set GOROOT_BOOTSTRAP=%HOMEDRIVE%%HOMEPATH%\Go1.4 :bootstrapset -if not exist "%GOROOT_BOOTSTRAP%\bin\go.exe" goto bootstrapfail +if not exist "%GOROOT_BOOTSTRAP%\bin\go.exe" ( + echo ERROR: Cannot find %GOROOT_BOOTSTRAP%\bin\go.exe + echo Set GOROOT_BOOTSTRAP to a working Go tree ^>= Go %bootgo%. + exit /b 1 +) set GOROOT=%GOROOT_TEMP% set GOROOT_TEMP= @@ -90,9 +94,9 @@ echo Building Go cmd/dist using %GOROOT_BOOTSTRAP%. (%GOROOT_BOOTSTRAP_VERSION%) if x%vflag==x-v echo cmd/dist set GOROOT=%GOROOT_BOOTSTRAP% set GOBIN= -"%GOROOT_BOOTSTRAP%\bin\go.exe" build -o cmd\dist\dist.exe .\cmd\dist || goto fail +"%GOROOT_BOOTSTRAP%\bin\go.exe" build -o cmd\dist\dist.exe .\cmd\dist || exit /b 1 endlocal -.\cmd\dist\dist.exe env -w -p >env.bat || goto fail +.\cmd\dist\dist.exe env -w -p >env.bat || exit /b 1 call .\env.bat del env.bat if x%vflag==x-v echo. @@ -109,7 +113,7 @@ if x%4==x--dist-tool goto copydist :: Run dist bootstrap to complete make.bash. :: Bootstrap installs a proper cmd/dist, built with the new toolchain. :: Throw ours, built with the bootstrap toolchain, away after bootstrap. -.\cmd\dist\dist.exe bootstrap -a %* || goto fail +.\cmd\dist\dist.exe bootstrap -a %* || exit /b 1 del .\cmd\dist\dist.exe goto :eof @@ -131,11 +135,3 @@ set GOOS= set GOARCH= set GOEXPERIMENT= set GOFLAGS= -goto :eof - -:bootstrapfail -echo ERROR: Cannot find %GOROOT_BOOTSTRAP%\bin\go.exe -echo Set GOROOT_BOOTSTRAP to a working Go tree ^>= Go %bootgo%. - -:fail -exit /b 1 diff --git a/src/race.bat b/src/race.bat index 7f1e0a1987230f..60fcfb90c76275 100644 --- a/src/race.bat +++ b/src/race.bat @@ -9,30 +9,22 @@ setlocal -if exist make.bat goto ok -echo race.bat must be run from go\src -exit /b 1 -:ok +if not exist make.bat ( + echo race.bat must be run from go\src + exit /b 1 +) set GOROOT=%CD%\.. -call .\make.bat --dist-tool >NUL || goto fail -.\cmd\dist\dist.exe env -w -p >env.bat || goto fail +call .\make.bat --dist-tool >NUL || exit /b 1 +.\cmd\dist\dist.exe env -w -p >env.bat || exit /b 1 call .\env.bat del env.bat -if %GOHOSTARCH% == amd64 goto continue -echo Race detector is only supported on windows/amd64. -goto fail +if not %GOHOSTARCH% == amd64 ( + echo Race detector is only supported on windows/amd64. + exit /b 1 +) -:continue -call .\make.bat --no-banner || goto fail -echo # go install -race std -go install -race std || goto fail -go tool dist test -race || goto fail - -echo All tests passed. -goto :eof - -:fail -echo Fail. -exit /b 1 +call .\make.bat --no-banner || exit /b 1 +go install -race std || exit /b 1 +go tool dist test -race || exit /b 1 diff --git a/src/run.bat b/src/run.bat index 3e7b1a1b0c25b0..b6a101b2ff0fae 100644 --- a/src/run.bat +++ b/src/run.bat @@ -4,21 +4,17 @@ @echo off -if exist ..\bin\go.exe goto ok -echo Must run run.bat from Go src directory after installing cmd/go. -goto fail -:ok +if not exist ..\bin\go.exe ( + echo Must run run.bat from Go src directory after installing cmd/go. + exit /b 1 +) setlocal set GOENV=off -..\bin\go tool dist env > env.bat || goto fail +..\bin\go tool dist env > env.bat || exit /b 1 call .\env.bat del env.bat set GOPATH=c:\nonexist-gopath -..\bin\go tool dist test --rebuild %* || goto fail -goto :eof - -:fail -exit /b 1 +..\bin\go tool dist test --rebuild %* || exit /b 1 From fadfe2fc80f6b37e99b3e7aa068112ff539717c9 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Sat, 1 Feb 2025 04:52:57 +0000 Subject: [PATCH 319/397] internal/trace/tracev2: add test to validate spec invariants This change adds a test to help guide people adding experiments to this package by validating that the spec is written correctly. Also, makes some minor tweaks to the package in order to get the tests to pass. Change-Id: I3daa420c5a9ec3ea536415c8e5d06f41666a9566 Reviewed-on: https://go-review.googlesource.com/c/go/+/646015 LUCI-TryBot-Result: Go LUCI Reviewed-by: Michael Pratt Auto-Submit: Michael Knyszek --- src/internal/trace/tracev2/events.go | 13 ++- src/internal/trace/tracev2/events_test.go | 98 +++++++++++++++++++++++ src/internal/trace/tracev2/spec.go | 7 +- 3 files changed, 114 insertions(+), 4 deletions(-) create mode 100644 src/internal/trace/tracev2/events_test.go diff --git a/src/internal/trace/tracev2/events.go b/src/internal/trace/tracev2/events.go index 778ef8d005b9ed..c6dd162a6312a6 100644 --- a/src/internal/trace/tracev2/events.go +++ b/src/internal/trace/tracev2/events.go @@ -82,8 +82,14 @@ const ( // Batch event for an experimental batch with a custom format. Added in Go 1.23. EvExperimentalBatch // start of extra data [experiment ID, generation, M ID, timestamp, batch length, batch data...] + + NumEvents ) +func (ev EventType) Experimental() bool { + return ev > MaxEvent && ev < MaxExperimentalEvent +} + // Experiments. const ( // AllocFree is the alloc-free events experiment. @@ -103,7 +109,7 @@ var experiments = [...]string{ // Experimental events. const ( - _ EventType = 127 + iota + MaxEvent EventType = 127 + iota // Experimental events for AllocFree. @@ -121,8 +127,12 @@ const ( EvGoroutineStack // stack exists [timestamp, id, order] EvGoroutineStackAlloc // stack alloc [timestamp, id, order] EvGoroutineStackFree // stack free [timestamp, id] + + MaxExperimentalEvent ) +const NumExperimentalEvents = MaxExperimentalEvent - MaxEvent + func Specs() []EventSpec { return specs[:] } @@ -158,6 +168,7 @@ var specs = [...]EventSpec{ // N.B. There's clearly a timestamp here, but these Events // are special in that they don't appear in the regular // M streams. + StackIDs: []int{4}, }, EvFrequency: { Name: "Frequency", diff --git a/src/internal/trace/tracev2/events_test.go b/src/internal/trace/tracev2/events_test.go new file mode 100644 index 00000000000000..1f2fbf7610a086 --- /dev/null +++ b/src/internal/trace/tracev2/events_test.go @@ -0,0 +1,98 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package tracev2_test + +import ( + "internal/trace/tracev2" + "iter" + "regexp" + "slices" + "strings" + "testing" +) + +var argNameRegexp = regexp.MustCompile(`((?P[A-Za-z]+)_)?(?P[A-Za-z]+)`) + +func TestSpecs(t *testing.T) { + if tracev2.NumEvents <= 0 { + t.Fatalf("no trace events?") + } + if tracev2.MaxExperimentalEvent < tracev2.MaxEvent { + t.Fatalf("max experimental event (%d) is < max event (%d)", tracev2.MaxExperimentalEvent, tracev2.MaxEvent) + } + specs := tracev2.Specs() + for ev := range allEvents() { + spec := &specs[ev] + if spec.Name == "" { + t.Errorf("expected event %d to be defined in specs", ev) + continue + } + if spec.IsTimedEvent && spec.Args[0] != "dt" { + t.Errorf("%s is a timed event, but its first argument is not 'dt'", spec.Name) + } + if spec.HasData && spec.Name != "String" && spec.Name != "ExperimentalBatch" { + t.Errorf("%s has data, but is not a special kind of event (unsupported, but could be)", spec.Name) + } + if spec.IsStack && spec.Name != "Stack" { + t.Errorf("%s listed as being a stack, but is not the Stack event (unsupported)", spec.Name) + } + if ev.Experimental() && spec.Experiment == tracev2.NoExperiment { + t.Errorf("experimental event %s must have an experiment", spec.Name) + } + + // Check arg types. + for _, arg := range spec.Args { + matches := argNameRegexp.FindStringSubmatch(arg) + if len(matches) == 0 { + t.Errorf("malformed argument %s for event %s", arg, spec.Name) + } + } + + // Check stacks. + for _, i := range spec.StackIDs { + if !strings.HasSuffix(spec.Args[i], "stack") { + t.Errorf("stack argument listed at %d in %s, but argument name %s does not imply stack type", i, spec.Name, spec.Args[i]) + } + } + for i, arg := range spec.Args { + if !strings.HasSuffix(spec.Args[i], "stack") { + continue + } + if !slices.Contains(spec.StackIDs, i) { + t.Errorf("found stack argument %s in %s at index %d not listed in StackIDs", arg, spec.Name, i) + } + } + + // Check strings. + for _, i := range spec.StringIDs { + if !strings.HasSuffix(spec.Args[i], "string") { + t.Errorf("string argument listed at %d in %s, but argument name %s does not imply string type", i, spec.Name, spec.Args[i]) + } + } + for i, arg := range spec.Args { + if !strings.HasSuffix(spec.Args[i], "string") { + continue + } + if !slices.Contains(spec.StringIDs, i) { + t.Errorf("found string argument %s in %s at index %d not listed in StringIDs", arg, spec.Name, i) + } + } + } +} + +func allEvents() iter.Seq[tracev2.EventType] { + return func(yield func(tracev2.EventType) bool) { + for ev := tracev2.EvNone + 1; ev < tracev2.NumEvents; ev++ { + if !yield(ev) { + return + } + } + for ev := tracev2.MaxEvent + 1; ev < tracev2.NumExperimentalEvents; ev++ { + if !yield(ev) { + return + } + } + } +} diff --git a/src/internal/trace/tracev2/spec.go b/src/internal/trace/tracev2/spec.go index 3ea3c5988908b4..af92865781741d 100644 --- a/src/internal/trace/tracev2/spec.go +++ b/src/internal/trace/tracev2/spec.go @@ -22,10 +22,11 @@ type EventSpec struct { // is relied on by the testing framework to type-check arguments. // The structure is: // - // (?P[A-Za-z]+_)?(?P[A-Za-z]+) + // (?P[A-Za-z]+)(_(?P[A-Za-z]+))? // - // In sum, it's an optional name followed by a type. If the name - // is present, it is separated from the type with an underscore. + // In sum, it's a name followed by an optional type. + // If the type is present, it is preceded with an underscore. + // Arguments without types will be interpreted as just raw uint64s. // The valid argument types and the Go types they map to are listed // in the ArgTypes variable. Args []string From 0158ddad9893ea1ab332be39f192aefdbd7b65c8 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Sat, 1 Feb 2025 05:26:17 +0000 Subject: [PATCH 320/397] internal/trace: move maxArgs into tracev2 and validate specs This change moves maxArgs to tracev2 and renames it MaxTimedEventArgs. It also updates the tests to make sure the specs conform to this requirement. Change-Id: I7b0c888a4dfd83306a470a4c9b0f9e44fe2e7818 Reviewed-on: https://go-review.googlesource.com/c/go/+/646016 TryBot-Bypass: Michael Knyszek Reviewed-by: Michael Pratt Auto-Submit: Michael Knyszek --- src/internal/trace/base.go | 6 +----- src/internal/trace/tracev2/events.go | 3 +++ src/internal/trace/tracev2/events_test.go | 3 +++ 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/internal/trace/base.go b/src/internal/trace/base.go index 5e11c6f0498a66..693dbc6fa68d1a 100644 --- a/src/internal/trace/base.go +++ b/src/internal/trace/base.go @@ -16,13 +16,9 @@ import ( "internal/trace/version" ) -// maxArgs is the maximum number of arguments for "plain" events, -// i.e. anything that could reasonably be represented as a baseEvent. -const maxArgs = 5 - // timedEventArgs is an array that is able to hold the arguments for any // timed event. -type timedEventArgs [maxArgs - 1]uint64 +type timedEventArgs [tracev2.MaxTimedEventArgs - 1]uint64 // baseEvent is the basic unprocessed event. This serves as a common // fundamental data structure across. diff --git a/src/internal/trace/tracev2/events.go b/src/internal/trace/tracev2/events.go index c6dd162a6312a6..2f3581ab5b7ccb 100644 --- a/src/internal/trace/tracev2/events.go +++ b/src/internal/trace/tracev2/events.go @@ -133,6 +133,9 @@ const ( const NumExperimentalEvents = MaxExperimentalEvent - MaxEvent +// MaxTimedEventArgs is the maximum number of arguments for timed events. +const MaxTimedEventArgs = 5 + func Specs() []EventSpec { return specs[:] } diff --git a/src/internal/trace/tracev2/events_test.go b/src/internal/trace/tracev2/events_test.go index 1f2fbf7610a086..60c4c08c34a127 100644 --- a/src/internal/trace/tracev2/events_test.go +++ b/src/internal/trace/tracev2/events_test.go @@ -38,6 +38,9 @@ func TestSpecs(t *testing.T) { if spec.IsStack && spec.Name != "Stack" { t.Errorf("%s listed as being a stack, but is not the Stack event (unsupported)", spec.Name) } + if spec.IsTimedEvent && len(spec.Args) > tracev2.MaxTimedEventArgs { + t.Errorf("%s has too many timed event args: have %d, want %d at most", spec.Name, len(spec.Args), tracev2.MaxTimedEventArgs) + } if ev.Experimental() && spec.Experiment == tracev2.NoExperiment { t.Errorf("experimental event %s must have an experiment", spec.Name) } From b5f34aa4abc1ae49b9f97355deb5ab097d0c68a9 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Wed, 29 Jan 2025 17:17:04 +0000 Subject: [PATCH 321/397] runtime: use internal/trace/tracev2 definitions This change deduplicates trace wire format definitions between the runtime and the trace parser by making the internal/trace/tracev2 package the source of truth. Change-Id: Ia0721d3484a80417e40ac473ec32870bee73df09 Reviewed-on: https://go-review.googlesource.com/c/go/+/644221 Auto-Submit: Michael Knyszek Reviewed-by: Michael Pratt LUCI-TryBot-Result: Go LUCI --- src/internal/trace/tracev2/doc.go | 11 +++ src/runtime/mgc.go | 2 +- src/runtime/proc.go | 4 +- src/runtime/traceallocfree.go | 21 +++--- src/runtime/tracebuf.go | 36 ++++++++-- src/runtime/tracecpu.go | 10 +-- src/runtime/traceevent.go | 89 ++---------------------- src/runtime/traceexp.go | 63 ----------------- src/runtime/traceruntime.go | 109 +++++++++++++++--------------- src/runtime/tracestack.go | 18 ++--- src/runtime/tracestatus.go | 84 +++++++---------------- src/runtime/tracestring.go | 14 ++-- src/runtime/tracetime.go | 5 +- src/runtime/tracetype.go | 3 +- 14 files changed, 163 insertions(+), 306 deletions(-) create mode 100644 src/internal/trace/tracev2/doc.go delete mode 100644 src/runtime/traceexp.go diff --git a/src/internal/trace/tracev2/doc.go b/src/internal/trace/tracev2/doc.go new file mode 100644 index 00000000000000..725fc0821d0fd7 --- /dev/null +++ b/src/internal/trace/tracev2/doc.go @@ -0,0 +1,11 @@ +// Copyright 2025 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +Package tracev2 contains definitions for the v2 execution trace wire format. + +These definitions are shared between the trace parser and the runtime, so it +must not depend on any package that depends on the runtime (most packages). +*/ +package tracev2 diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go index d7d97ad244a8a4..d10f3c09cf1da0 100644 --- a/src/runtime/mgc.go +++ b/src/runtime/mgc.go @@ -1553,7 +1553,7 @@ func gcBgMarkWorker(ready chan struct{}) { // We'll releasem after this point and thus this P may run // something else. We must clear the worker mode to avoid // attributing the mode to a different (non-worker) G in - // traceGoStart. + // tracev2.GoStart. pp.gcMarkWorkerMode = gcMarkWorkerNotWorker // If this worker reached a background mark completion diff --git a/src/runtime/proc.go b/src/runtime/proc.go index e9873e54cd5709..ce6cf88d0cb19f 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -4693,7 +4693,7 @@ func exitsyscall() { trace.GoSysExit(lostP) if lostP { // We lost the P at some point, even though we got it back here. - // Trace that we're starting again, because there was a traceGoSysBlock + // Trace that we're starting again, because there was a tracev2.GoSysBlock // call somewhere in exitsyscallfast (indicating that this goroutine // had blocked) and we're about to start running again. trace.GoStart() @@ -4790,7 +4790,7 @@ func exitsyscallfast_reacquired(trace traceLocker) { if gp.m.syscalltick != gp.m.p.ptr().syscalltick { if trace.ok() { // The p was retaken and then enter into syscall again (since gp.m.syscalltick has changed). - // traceGoSysBlock for this syscall was already emitted, + // tracev2.GoSysBlock for this syscall was already emitted, // but here we effectively retake the p from the new syscall running on the same p. systemstack(func() { // We're stealing the P. It's treated diff --git a/src/runtime/traceallocfree.go b/src/runtime/traceallocfree.go index 84188a55c45bad..40f1cfe8ab3d2f 100644 --- a/src/runtime/traceallocfree.go +++ b/src/runtime/traceallocfree.go @@ -9,6 +9,7 @@ package runtime import ( "internal/abi" "internal/runtime/sys" + "internal/trace/tracev2" ) // Batch type values for the alloc/free experiment. @@ -27,7 +28,7 @@ func traceSnapshotMemory(gen uintptr) { // Write a batch containing information that'll be necessary to // interpret the events. var flushed bool - w := unsafeTraceExpWriter(gen, nil, traceExperimentAllocFree) + w := unsafeTraceExpWriter(gen, nil, tracev2.AllocFree) w, flushed = w.ensure(1 + 4*traceBytesPerNumber) if flushed { // Annotate the batch as containing additional info. @@ -89,17 +90,17 @@ func traceSpanTypeAndClass(s *mspan) traceArg { // SpanExists records an event indicating that the span exists. func (tl traceLocker) SpanExists(s *mspan) { - tl.eventWriter(traceGoRunning, traceProcRunning).event(traceEvSpan, traceSpanID(s), traceArg(s.npages), traceSpanTypeAndClass(s)) + tl.eventWriter(tracev2.GoRunning, tracev2.ProcRunning).event(tracev2.EvSpan, traceSpanID(s), traceArg(s.npages), traceSpanTypeAndClass(s)) } // SpanAlloc records an event indicating that the span has just been allocated. func (tl traceLocker) SpanAlloc(s *mspan) { - tl.eventWriter(traceGoRunning, traceProcRunning).event(traceEvSpanAlloc, traceSpanID(s), traceArg(s.npages), traceSpanTypeAndClass(s)) + tl.eventWriter(tracev2.GoRunning, tracev2.ProcRunning).event(tracev2.EvSpanAlloc, traceSpanID(s), traceArg(s.npages), traceSpanTypeAndClass(s)) } // SpanFree records an event indicating that the span is about to be freed. func (tl traceLocker) SpanFree(s *mspan) { - tl.eventWriter(traceGoRunning, traceProcRunning).event(traceEvSpanFree, traceSpanID(s)) + tl.eventWriter(tracev2.GoRunning, tracev2.ProcRunning).event(tracev2.EvSpanFree, traceSpanID(s)) } // traceSpanID creates a trace ID for the span s for the trace. @@ -111,19 +112,19 @@ func traceSpanID(s *mspan) traceArg { // The type is optional, and the size of the slot occupied the object is inferred from the // span containing it. func (tl traceLocker) HeapObjectExists(addr uintptr, typ *abi.Type) { - tl.eventWriter(traceGoRunning, traceProcRunning).event(traceEvHeapObject, traceHeapObjectID(addr), tl.rtype(typ)) + tl.eventWriter(tracev2.GoRunning, tracev2.ProcRunning).event(tracev2.EvHeapObject, traceHeapObjectID(addr), tl.rtype(typ)) } // HeapObjectAlloc records that an object was newly allocated at addr with the provided type. // The type is optional, and the size of the slot occupied the object is inferred from the // span containing it. func (tl traceLocker) HeapObjectAlloc(addr uintptr, typ *abi.Type) { - tl.eventWriter(traceGoRunning, traceProcRunning).event(traceEvHeapObjectAlloc, traceHeapObjectID(addr), tl.rtype(typ)) + tl.eventWriter(tracev2.GoRunning, tracev2.ProcRunning).event(tracev2.EvHeapObjectAlloc, traceHeapObjectID(addr), tl.rtype(typ)) } // HeapObjectFree records that an object at addr is about to be freed. func (tl traceLocker) HeapObjectFree(addr uintptr) { - tl.eventWriter(traceGoRunning, traceProcRunning).event(traceEvHeapObjectFree, traceHeapObjectID(addr)) + tl.eventWriter(tracev2.GoRunning, tracev2.ProcRunning).event(tracev2.EvHeapObjectFree, traceHeapObjectID(addr)) } // traceHeapObjectID creates a trace ID for a heap object at address addr. @@ -134,18 +135,18 @@ func traceHeapObjectID(addr uintptr) traceArg { // GoroutineStackExists records that a goroutine stack already exists at address base with the provided size. func (tl traceLocker) GoroutineStackExists(base, size uintptr) { order := traceCompressStackSize(size) - tl.eventWriter(traceGoRunning, traceProcRunning).event(traceEvGoroutineStack, traceGoroutineStackID(base), order) + tl.eventWriter(tracev2.GoRunning, tracev2.ProcRunning).event(tracev2.EvGoroutineStack, traceGoroutineStackID(base), order) } // GoroutineStackAlloc records that a goroutine stack was newly allocated at address base with the provided size.. func (tl traceLocker) GoroutineStackAlloc(base, size uintptr) { order := traceCompressStackSize(size) - tl.eventWriter(traceGoRunning, traceProcRunning).event(traceEvGoroutineStackAlloc, traceGoroutineStackID(base), order) + tl.eventWriter(tracev2.GoRunning, tracev2.ProcRunning).event(tracev2.EvGoroutineStackAlloc, traceGoroutineStackID(base), order) } // GoroutineStackFree records that a goroutine stack at address base is about to be freed. func (tl traceLocker) GoroutineStackFree(base uintptr) { - tl.eventWriter(traceGoRunning, traceProcRunning).event(traceEvGoroutineStackFree, traceGoroutineStackID(base)) + tl.eventWriter(tracev2.GoRunning, tracev2.ProcRunning).event(tracev2.EvGoroutineStackFree, traceGoroutineStackID(base)) } // traceGoroutineStackID creates a trace ID for the goroutine stack from its base address. diff --git a/src/runtime/tracebuf.go b/src/runtime/tracebuf.go index 0849a57809e2ca..63803a90f5a32f 100644 --- a/src/runtime/tracebuf.go +++ b/src/runtime/tracebuf.go @@ -8,6 +8,7 @@ package runtime import ( "internal/runtime/sys" + "internal/trace/tracev2" "unsafe" ) @@ -24,7 +25,7 @@ const traceBytesPerNumber = 10 // we can change it if it's deemed too error-prone. type traceWriter struct { traceLocker - exp traceExperiment + exp tracev2.Experiment *traceBuf } @@ -48,7 +49,7 @@ func (tl traceLocker) writer() traceWriter { gp.throwsplit = true } } - return traceWriter{traceLocker: tl, traceBuf: tl.mp.trace.buf[tl.gen%2][traceNoExperiment]} + return traceWriter{traceLocker: tl, traceBuf: tl.mp.trace.buf[tl.gen%2][tracev2.NoExperiment]} } // unsafeTraceWriter produces a traceWriter that doesn't lock the trace. @@ -70,7 +71,7 @@ func unsafeTraceWriter(gen uintptr, buf *traceBuf) traceWriter { // have any stack growth. // //go:nosplit -func (w traceWriter) event(ev traceEv, args ...traceArg) traceWriter { +func (w traceWriter) event(ev tracev2.EventType, args ...traceArg) traceWriter { // N.B. Everything in this call must be nosplit to maintain // the stack growth related invariants for writing events. @@ -186,10 +187,10 @@ func (w traceWriter) refill() traceWriter { } // Write the buffer's header. - if w.exp == traceNoExperiment { - w.byte(byte(traceEvEventBatch)) + if w.exp == tracev2.NoExperiment { + w.byte(byte(tracev2.EvEventBatch)) } else { - w.byte(byte(traceEvExperimentalBatch)) + w.byte(byte(tracev2.EvExperimentalBatch)) w.byte(byte(w.exp)) } w.varint(uint64(w.gen)) @@ -199,6 +200,27 @@ func (w traceWriter) refill() traceWriter { return w } +// expWriter returns a traceWriter that writes into the current M's stream for +// the given experiment. +func (tl traceLocker) expWriter(exp tracev2.Experiment) traceWriter { + return traceWriter{traceLocker: tl, traceBuf: tl.mp.trace.buf[tl.gen%2][exp], exp: exp} +} + +// unsafeTraceExpWriter produces a traceWriter for experimental trace batches +// that doesn't lock the trace. Data written to experimental batches need not +// conform to the standard trace format. +// +// It should only be used in contexts where either: +// - Another traceLocker is held. +// - trace.gen is prevented from advancing. +// +// This does not have the same stack growth restrictions as traceLocker.writer. +// +// buf may be nil. +func unsafeTraceExpWriter(gen uintptr, buf *traceBuf, exp tracev2.Experiment) traceWriter { + return traceWriter{traceLocker: traceLocker{gen: gen}, traceBuf: buf, exp: exp} +} + // traceBufQueue is a FIFO of traceBufs. type traceBufQueue struct { head, tail *traceBuf @@ -247,7 +269,7 @@ type traceBufHeader struct { type traceBuf struct { _ sys.NotInHeap traceBufHeader - arr [64<<10 - unsafe.Sizeof(traceBufHeader{})]byte // underlying buffer for traceBufHeader.buf + arr [tracev2.MaxBatchSize - unsafe.Sizeof(traceBufHeader{})]byte // underlying buffer for traceBufHeader.buf } // byte appends v to buf. diff --git a/src/runtime/tracecpu.go b/src/runtime/tracecpu.go index c8a6f56ff2f684..092c707f83335f 100644 --- a/src/runtime/tracecpu.go +++ b/src/runtime/tracecpu.go @@ -6,6 +6,8 @@ package runtime +import "internal/trace/tracev2" + // traceInitReadCPU initializes CPU profile -> tracer state for tracing. // // Returns a profBuf for reading from. @@ -114,7 +116,7 @@ func traceStopReadCPU() { // Must not run on the system stack because profBuf.read performs race // operations. func traceReadCPU(gen uintptr) bool { - var pcBuf [traceStackSize]uintptr + var pcBuf [tracev2.MaxFramesPerStack]uintptr data, tags, eof := trace.cpuLogRead[gen%2].read(profBufNonBlocking) for len(data) > 0 { @@ -169,17 +171,17 @@ func traceReadCPU(gen uintptr) bool { // Ensure we have a place to write to. var flushed bool - w, flushed = w.ensure(2 + 5*traceBytesPerNumber /* traceEvCPUSamples + traceEvCPUSample + timestamp + g + m + p + stack ID */) + w, flushed = w.ensure(2 + 5*traceBytesPerNumber /* tracev2.EvCPUSamples + tracev2.EvCPUSample + timestamp + g + m + p + stack ID */) if flushed { // Annotate the batch as containing strings. - w.byte(byte(traceEvCPUSamples)) + w.byte(byte(tracev2.EvCPUSamples)) } // Add the stack to the table. stackID := trace.stackTab[gen%2].put(pcBuf[:nstk]) // Write out the CPU sample. - w.byte(byte(traceEvCPUSample)) + w.byte(byte(tracev2.EvCPUSample)) w.varint(timestamp) w.varint(mpid) w.varint(ppid) diff --git a/src/runtime/traceevent.go b/src/runtime/traceevent.go index 51d23688425ff3..9d1a93d3f9f255 100644 --- a/src/runtime/traceevent.go +++ b/src/runtime/traceevent.go @@ -9,88 +9,7 @@ package runtime import ( "internal/abi" "internal/runtime/sys" -) - -// Event types in the trace, args are given in square brackets. -// -// Naming scheme: -// - Time range event pairs have suffixes "Begin" and "End". -// - "Start", "Stop", "Create", "Destroy", "Block", "Unblock" -// are suffixes reserved for scheduling resources. -// -// NOTE: If you add an event type, make sure you also update all -// tables in this file! -type traceEv uint8 - -const ( - traceEvNone traceEv = iota // unused - - // Structural events. - traceEvEventBatch // start of per-M batch of events [generation, M ID, timestamp, batch length] - traceEvStacks // start of a section of the stack table [...traceEvStack] - traceEvStack // stack table entry [ID, ...{PC, func string ID, file string ID, line #}] - traceEvStrings // start of a section of the string dictionary [...traceEvString] - traceEvString // string dictionary entry [ID, length, string] - traceEvCPUSamples // start of a section of CPU samples [...traceEvCPUSample] - traceEvCPUSample // CPU profiling sample [timestamp, M ID, P ID, goroutine ID, stack ID] - traceEvFrequency // timestamp units per sec [freq] - - // Procs. - traceEvProcsChange // current value of GOMAXPROCS [timestamp, GOMAXPROCS, stack ID] - traceEvProcStart // start of P [timestamp, P ID, P seq] - traceEvProcStop // stop of P [timestamp] - traceEvProcSteal // P was stolen [timestamp, P ID, P seq, M ID] - traceEvProcStatus // P status at the start of a generation [timestamp, P ID, status] - - // Goroutines. - traceEvGoCreate // goroutine creation [timestamp, new goroutine ID, new stack ID, stack ID] - traceEvGoCreateSyscall // goroutine appears in syscall (cgo callback) [timestamp, new goroutine ID] - traceEvGoStart // goroutine starts running [timestamp, goroutine ID, goroutine seq] - traceEvGoDestroy // goroutine ends [timestamp] - traceEvGoDestroySyscall // goroutine ends in syscall (cgo callback) [timestamp] - traceEvGoStop // goroutine yields its time, but is runnable [timestamp, reason, stack ID] - traceEvGoBlock // goroutine blocks [timestamp, reason, stack ID] - traceEvGoUnblock // goroutine is unblocked [timestamp, goroutine ID, goroutine seq, stack ID] - traceEvGoSyscallBegin // syscall enter [timestamp, P seq, stack ID] - traceEvGoSyscallEnd // syscall exit [timestamp] - traceEvGoSyscallEndBlocked // syscall exit and it blocked at some point [timestamp] - traceEvGoStatus // goroutine status at the start of a generation [timestamp, goroutine ID, M ID, status] - - // STW. - traceEvSTWBegin // STW start [timestamp, kind] - traceEvSTWEnd // STW done [timestamp] - - // GC events. - traceEvGCActive // GC active [timestamp, seq] - traceEvGCBegin // GC start [timestamp, seq, stack ID] - traceEvGCEnd // GC done [timestamp, seq] - traceEvGCSweepActive // GC sweep active [timestamp, P ID] - traceEvGCSweepBegin // GC sweep start [timestamp, stack ID] - traceEvGCSweepEnd // GC sweep done [timestamp, swept bytes, reclaimed bytes] - traceEvGCMarkAssistActive // GC mark assist active [timestamp, goroutine ID] - traceEvGCMarkAssistBegin // GC mark assist start [timestamp, stack ID] - traceEvGCMarkAssistEnd // GC mark assist done [timestamp] - traceEvHeapAlloc // gcController.heapLive change [timestamp, heap alloc in bytes] - traceEvHeapGoal // gcController.heapGoal() change [timestamp, heap goal in bytes] - - // Annotations. - traceEvGoLabel // apply string label to current running goroutine [timestamp, label string ID] - traceEvUserTaskBegin // trace.NewTask [timestamp, internal task ID, internal parent task ID, name string ID, stack ID] - traceEvUserTaskEnd // end of a task [timestamp, internal task ID, stack ID] - traceEvUserRegionBegin // trace.{Start,With}Region [timestamp, internal task ID, name string ID, stack ID] - traceEvUserRegionEnd // trace.{End,With}Region [timestamp, internal task ID, name string ID, stack ID] - traceEvUserLog // trace.Log [timestamp, internal task ID, key string ID, stack, value string ID] - - // Coroutines. - traceEvGoSwitch // goroutine switch (coroswitch) [timestamp, goroutine ID, goroutine seq] - traceEvGoSwitchDestroy // goroutine switch and destroy [timestamp, goroutine ID, goroutine seq] - traceEvGoCreateBlocked // goroutine creation (starts blocked) [timestamp, new goroutine ID, new stack ID, stack ID] - - // GoStatus with stack. - traceEvGoStatusStack // goroutine status at the start of a generation, with a stack [timestamp, goroutine ID, M ID, status, stack ID] - - // Batch event for an experimental batch with a custom format. - traceEvExperimentalBatch // start of extra data [experiment ID, generation, M ID, timestamp, batch length, batch data...] + "internal/trace/tracev2" ) // traceArg is a simple wrapper type to help ensure that arguments passed @@ -117,8 +36,8 @@ type traceEventWriter struct { // been Runnable before a GoStart). Otherwise, callers can query the status of either the goroutine // or P and pass the appropriate status. // -// In this case, the default status should be traceGoBad or traceProcBad to help identify bugs sooner. -func (tl traceLocker) eventWriter(goStatus traceGoStatus, procStatus traceProcStatus) traceEventWriter { +// In this case, the default status should be tracev2.GoBad or tracev2.ProcBad to help identify bugs sooner. +func (tl traceLocker) eventWriter(goStatus tracev2.GoStatus, procStatus tracev2.ProcStatus) traceEventWriter { if pp := tl.mp.p.ptr(); pp != nil && !pp.trace.statusWasTraced(tl.gen) && pp.trace.acquireStatus(tl.gen) { tl.writer().writeProcStatus(uint64(pp.id), procStatus, pp.trace.inSweep).end() } @@ -129,7 +48,7 @@ func (tl traceLocker) eventWriter(goStatus traceGoStatus, procStatus traceProcSt } // event writes out a trace event. -func (e traceEventWriter) event(ev traceEv, args ...traceArg) { +func (e traceEventWriter) event(ev tracev2.EventType, args ...traceArg) { e.tl.writer().event(ev, args...).end() } diff --git a/src/runtime/traceexp.go b/src/runtime/traceexp.go deleted file mode 100644 index 13eec0c0b66706..00000000000000 --- a/src/runtime/traceexp.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2024 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -// expWriter returns a traceWriter that writes into the current M's stream for -// the given experiment. -func (tl traceLocker) expWriter(exp traceExperiment) traceWriter { - return traceWriter{traceLocker: tl, traceBuf: tl.mp.trace.buf[tl.gen%2][exp], exp: exp} -} - -// unsafeTraceExpWriter produces a traceWriter for experimental trace batches -// that doesn't lock the trace. Data written to experimental batches need not -// conform to the standard trace format. -// -// It should only be used in contexts where either: -// - Another traceLocker is held. -// - trace.gen is prevented from advancing. -// -// This does not have the same stack growth restrictions as traceLocker.writer. -// -// buf may be nil. -func unsafeTraceExpWriter(gen uintptr, buf *traceBuf, exp traceExperiment) traceWriter { - return traceWriter{traceLocker: traceLocker{gen: gen}, traceBuf: buf, exp: exp} -} - -// traceExperiment is an enumeration of the different kinds of experiments supported for tracing. -type traceExperiment uint8 - -const ( - // traceNoExperiment indicates no experiment. - traceNoExperiment traceExperiment = iota - - // traceExperimentAllocFree is an experiment to add alloc/free events to the trace. - traceExperimentAllocFree - - // traceNumExperiments is the number of trace experiments (and 1 higher than - // the highest numbered experiment). - traceNumExperiments -) - -// Experimental events. -const ( - _ traceEv = 127 + iota - - // Experimental events for ExperimentAllocFree. - - // Experimental heap span events. IDs map reversibly to base addresses. - traceEvSpan // heap span exists [timestamp, id, npages, type/class] - traceEvSpanAlloc // heap span alloc [timestamp, id, npages, type/class] - traceEvSpanFree // heap span free [timestamp, id] - - // Experimental heap object events. IDs map reversibly to addresses. - traceEvHeapObject // heap object exists [timestamp, id, type] - traceEvHeapObjectAlloc // heap object alloc [timestamp, id, type] - traceEvHeapObjectFree // heap object free [timestamp, id] - - // Experimental goroutine stack events. IDs map reversibly to addresses. - traceEvGoroutineStack // stack exists [timestamp, id, order] - traceEvGoroutineStackAlloc // stack alloc [timestamp, id, order] - traceEvGoroutineStackFree // stack free [timestamp, id] -) diff --git a/src/runtime/traceruntime.go b/src/runtime/traceruntime.go index 284e61301b19ab..98ac1082a824b2 100644 --- a/src/runtime/traceruntime.go +++ b/src/runtime/traceruntime.go @@ -8,6 +8,7 @@ package runtime import ( "internal/runtime/atomic" + "internal/trace/tracev2" _ "unsafe" // for go:linkname ) @@ -24,11 +25,11 @@ func (s *gTraceState) reset() { // mTraceState is per-M state for the tracer. type mTraceState struct { - seqlock atomic.Uintptr // seqlock indicating that this M is writing to a trace buffer. - buf [2][traceNumExperiments]*traceBuf // Per-M traceBuf for writing. Indexed by trace.gen%2. - link *m // Snapshot of alllink or freelink. - reentered uint32 // Whether we've reentered tracing from within tracing. - oldthrowsplit bool // gp.throwsplit upon calling traceLocker.writer. For debugging. + seqlock atomic.Uintptr // seqlock indicating that this M is writing to a trace buffer. + buf [2][tracev2.NumExperiments]*traceBuf // Per-M traceBuf for writing. Indexed by trace.gen%2. + link *m // Snapshot of alllink or freelink. + reentered uint32 // Whether we've reentered tracing from within tracing. + oldthrowsplit bool // gp.throwsplit upon calling traceLocker.writer. For debugging. } // pTraceState is per-P state for the tracer. @@ -283,7 +284,7 @@ func traceExitedSyscall() { // Gomaxprocs emits a ProcsChange event. func (tl traceLocker) Gomaxprocs(procs int32) { - tl.eventWriter(traceGoRunning, traceProcRunning).event(traceEvProcsChange, traceArg(procs), tl.stack(1)) + tl.eventWriter(tracev2.GoRunning, tracev2.ProcRunning).event(tracev2.EvProcsChange, traceArg(procs), tl.stack(1)) } // ProcStart traces a ProcStart event. @@ -294,14 +295,14 @@ func (tl traceLocker) ProcStart() { // Procs are typically started within the scheduler when there is no user goroutine. If there is a user goroutine, // it must be in _Gsyscall because the only time a goroutine is allowed to have its Proc moved around from under it // is during a syscall. - tl.eventWriter(traceGoSyscall, traceProcIdle).event(traceEvProcStart, traceArg(pp.id), pp.trace.nextSeq(tl.gen)) + tl.eventWriter(tracev2.GoSyscall, tracev2.ProcIdle).event(tracev2.EvProcStart, traceArg(pp.id), pp.trace.nextSeq(tl.gen)) } // ProcStop traces a ProcStop event. func (tl traceLocker) ProcStop(pp *p) { // The only time a goroutine is allowed to have its Proc moved around // from under it is during a syscall. - tl.eventWriter(traceGoSyscall, traceProcRunning).event(traceEvProcStop) + tl.eventWriter(tracev2.GoSyscall, tracev2.ProcRunning).event(tracev2.EvProcStop) } // GCActive traces a GCActive event. @@ -309,7 +310,7 @@ func (tl traceLocker) ProcStop(pp *p) { // Must be emitted by an actively running goroutine on an active P. This restriction can be changed // easily and only depends on where it's currently called. func (tl traceLocker) GCActive() { - tl.eventWriter(traceGoRunning, traceProcRunning).event(traceEvGCActive, traceArg(trace.seqGC)) + tl.eventWriter(tracev2.GoRunning, tracev2.ProcRunning).event(tracev2.EvGCActive, traceArg(trace.seqGC)) // N.B. Only one GC can be running at a time, so this is naturally // serialized by the caller. trace.seqGC++ @@ -320,7 +321,7 @@ func (tl traceLocker) GCActive() { // Must be emitted by an actively running goroutine on an active P. This restriction can be changed // easily and only depends on where it's currently called. func (tl traceLocker) GCStart() { - tl.eventWriter(traceGoRunning, traceProcRunning).event(traceEvGCBegin, traceArg(trace.seqGC), tl.stack(3)) + tl.eventWriter(tracev2.GoRunning, tracev2.ProcRunning).event(tracev2.EvGCBegin, traceArg(trace.seqGC), tl.stack(3)) // N.B. Only one GC can be running at a time, so this is naturally // serialized by the caller. trace.seqGC++ @@ -331,7 +332,7 @@ func (tl traceLocker) GCStart() { // Must be emitted by an actively running goroutine on an active P. This restriction can be changed // easily and only depends on where it's currently called. func (tl traceLocker) GCDone() { - tl.eventWriter(traceGoRunning, traceProcRunning).event(traceEvGCEnd, traceArg(trace.seqGC)) + tl.eventWriter(tracev2.GoRunning, tracev2.ProcRunning).event(tracev2.EvGCEnd, traceArg(trace.seqGC)) // N.B. Only one GC can be running at a time, so this is naturally // serialized by the caller. trace.seqGC++ @@ -341,14 +342,14 @@ func (tl traceLocker) GCDone() { func (tl traceLocker) STWStart(reason stwReason) { // Although the current P may be in _Pgcstop here, we model the P as running during the STW. This deviates from the // runtime's state tracking, but it's more accurate and doesn't result in any loss of information. - tl.eventWriter(traceGoRunning, traceProcRunning).event(traceEvSTWBegin, tl.string(reason.String()), tl.stack(2)) + tl.eventWriter(tracev2.GoRunning, tracev2.ProcRunning).event(tracev2.EvSTWBegin, tl.string(reason.String()), tl.stack(2)) } // STWDone traces a STWEnd event. func (tl traceLocker) STWDone() { // Although the current P may be in _Pgcstop here, we model the P as running during the STW. This deviates from the // runtime's state tracking, but it's more accurate and doesn't result in any loss of information. - tl.eventWriter(traceGoRunning, traceProcRunning).event(traceEvSTWEnd) + tl.eventWriter(tracev2.GoRunning, tracev2.ProcRunning).event(tracev2.EvSTWEnd) } // GCSweepStart prepares to trace a sweep loop. This does not @@ -380,7 +381,7 @@ func (tl traceLocker) GCSweepSpan(bytesSwept uintptr) { pp := tl.mp.p.ptr() if pp.trace.maySweep { if pp.trace.swept == 0 { - tl.eventWriter(traceGoRunning, traceProcRunning).event(traceEvGCSweepBegin, tl.stack(1)) + tl.eventWriter(tracev2.GoRunning, tracev2.ProcRunning).event(tracev2.EvGCSweepBegin, tl.stack(1)) pp.trace.inSweep = true } pp.trace.swept += bytesSwept @@ -398,7 +399,7 @@ func (tl traceLocker) GCSweepDone() { throw("missing traceGCSweepStart") } if pp.trace.inSweep { - tl.eventWriter(traceGoRunning, traceProcRunning).event(traceEvGCSweepEnd, traceArg(pp.trace.swept), traceArg(pp.trace.reclaimed)) + tl.eventWriter(tracev2.GoRunning, tracev2.ProcRunning).event(tracev2.EvGCSweepEnd, traceArg(pp.trace.swept), traceArg(pp.trace.reclaimed)) pp.trace.inSweep = false } pp.trace.maySweep = false @@ -406,22 +407,22 @@ func (tl traceLocker) GCSweepDone() { // GCMarkAssistStart emits a MarkAssistBegin event. func (tl traceLocker) GCMarkAssistStart() { - tl.eventWriter(traceGoRunning, traceProcRunning).event(traceEvGCMarkAssistBegin, tl.stack(1)) + tl.eventWriter(tracev2.GoRunning, tracev2.ProcRunning).event(tracev2.EvGCMarkAssistBegin, tl.stack(1)) } // GCMarkAssistDone emits a MarkAssistEnd event. func (tl traceLocker) GCMarkAssistDone() { - tl.eventWriter(traceGoRunning, traceProcRunning).event(traceEvGCMarkAssistEnd) + tl.eventWriter(tracev2.GoRunning, tracev2.ProcRunning).event(tracev2.EvGCMarkAssistEnd) } // GoCreate emits a GoCreate event. func (tl traceLocker) GoCreate(newg *g, pc uintptr, blocked bool) { newg.trace.setStatusTraced(tl.gen) - ev := traceEvGoCreate + ev := tracev2.EvGoCreate if blocked { - ev = traceEvGoCreateBlocked + ev = tracev2.EvGoCreateBlocked } - tl.eventWriter(traceGoRunning, traceProcRunning).event(ev, traceArg(newg.goid), tl.startPC(pc), tl.stack(2)) + tl.eventWriter(tracev2.GoRunning, tracev2.ProcRunning).event(ev, traceArg(newg.goid), tl.startPC(pc), tl.stack(2)) } // GoStart emits a GoStart event. @@ -430,10 +431,10 @@ func (tl traceLocker) GoCreate(newg *g, pc uintptr, blocked bool) { func (tl traceLocker) GoStart() { gp := getg().m.curg pp := gp.m.p - w := tl.eventWriter(traceGoRunnable, traceProcRunning) - w.event(traceEvGoStart, traceArg(gp.goid), gp.trace.nextSeq(tl.gen)) + w := tl.eventWriter(tracev2.GoRunnable, tracev2.ProcRunning) + w.event(tracev2.EvGoStart, traceArg(gp.goid), gp.trace.nextSeq(tl.gen)) if pp.ptr().gcMarkWorkerMode != gcMarkWorkerNotWorker { - w.event(traceEvGoLabel, trace.markWorkerLabels[tl.gen%2][pp.ptr().gcMarkWorkerMode]) + w.event(tracev2.EvGoLabel, trace.markWorkerLabels[tl.gen%2][pp.ptr().gcMarkWorkerMode]) } } @@ -441,7 +442,7 @@ func (tl traceLocker) GoStart() { // // TODO(mknyszek): Rename this to GoDestroy. func (tl traceLocker) GoEnd() { - tl.eventWriter(traceGoRunning, traceProcRunning).event(traceEvGoDestroy) + tl.eventWriter(tracev2.GoRunning, tracev2.ProcRunning).event(tracev2.EvGoDestroy) } // GoSched emits a GoStop event with a GoSched reason. @@ -456,7 +457,7 @@ func (tl traceLocker) GoPreempt() { // GoStop emits a GoStop event with the provided reason. func (tl traceLocker) GoStop(reason traceGoStopReason) { - tl.eventWriter(traceGoRunning, traceProcRunning).event(traceEvGoStop, traceArg(trace.goStopReasons[tl.gen%2][reason]), tl.stack(1)) + tl.eventWriter(tracev2.GoRunning, tracev2.ProcRunning).event(tracev2.EvGoStop, traceArg(trace.goStopReasons[tl.gen%2][reason]), tl.stack(1)) } // GoPark emits a GoBlock event with the provided reason. @@ -464,14 +465,14 @@ func (tl traceLocker) GoStop(reason traceGoStopReason) { // TODO(mknyszek): Replace traceBlockReason with waitReason. It's silly // that we have both, and waitReason is way more descriptive. func (tl traceLocker) GoPark(reason traceBlockReason, skip int) { - tl.eventWriter(traceGoRunning, traceProcRunning).event(traceEvGoBlock, traceArg(trace.goBlockReasons[tl.gen%2][reason]), tl.stack(skip)) + tl.eventWriter(tracev2.GoRunning, tracev2.ProcRunning).event(tracev2.EvGoBlock, traceArg(trace.goBlockReasons[tl.gen%2][reason]), tl.stack(skip)) } // GoUnpark emits a GoUnblock event. func (tl traceLocker) GoUnpark(gp *g, skip int) { // Emit a GoWaiting status if necessary for the unblocked goroutine. tl.emitUnblockStatus(gp, tl.gen) - tl.eventWriter(traceGoRunning, traceProcRunning).event(traceEvGoUnblock, traceArg(gp.goid), gp.trace.nextSeq(tl.gen), tl.stack(skip)) + tl.eventWriter(tracev2.GoRunning, tracev2.ProcRunning).event(tracev2.EvGoUnblock, traceArg(gp.goid), gp.trace.nextSeq(tl.gen), tl.stack(skip)) } // GoSwitch emits a GoSwitch event. If destroy is true, the calling goroutine @@ -479,10 +480,10 @@ func (tl traceLocker) GoUnpark(gp *g, skip int) { func (tl traceLocker) GoSwitch(nextg *g, destroy bool) { // Emit a GoWaiting status if necessary for the unblocked goroutine. tl.emitUnblockStatus(nextg, tl.gen) - w := tl.eventWriter(traceGoRunning, traceProcRunning) - ev := traceEvGoSwitch + w := tl.eventWriter(tracev2.GoRunning, tracev2.ProcRunning) + ev := tracev2.EvGoSwitch if destroy { - ev = traceEvGoSwitchDestroy + ev = tracev2.EvGoSwitchDestroy } w.event(ev, traceArg(nextg.goid), nextg.trace.nextSeq(tl.gen)) } @@ -494,7 +495,7 @@ func (tl traceLocker) emitUnblockStatus(gp *g, gen uintptr) { // TODO(go.dev/issue/65634): Although it would be nice to add a stack trace here of gp, // we cannot safely do so. gp is in _Gwaiting and so we don't have ownership of its stack. // We can fix this by acquiring the goroutine's scan bit. - tl.writer().writeGoStatus(gp.goid, -1, traceGoWaiting, gp.inMarkAssist, 0).end() + tl.writer().writeGoStatus(gp.goid, -1, tracev2.GoWaiting, gp.inMarkAssist, 0).end() } } @@ -505,7 +506,7 @@ func (tl traceLocker) GoSysCall() { // Scribble down the M that the P is currently attached to. pp := tl.mp.p.ptr() pp.trace.mSyscallID = int64(tl.mp.procid) - tl.eventWriter(traceGoRunning, traceProcRunning).event(traceEvGoSyscallBegin, pp.trace.nextSeq(tl.gen), tl.stack(1)) + tl.eventWriter(tracev2.GoRunning, tracev2.ProcRunning).event(tracev2.EvGoSyscallBegin, pp.trace.nextSeq(tl.gen), tl.stack(1)) } // GoSysExit emits a GoSyscallEnd event, possibly along with a GoSyscallBlocked event @@ -518,15 +519,15 @@ func (tl traceLocker) GoSysCall() { // - The goroutine lost its P and was unable to reacquire it, and is now running without a P. // - The goroutine lost its P and acquired a different one, and is now running with that P. func (tl traceLocker) GoSysExit(lostP bool) { - ev := traceEvGoSyscallEnd - procStatus := traceProcSyscall // Procs implicitly enter traceProcSyscall on GoSyscallBegin. + ev := tracev2.EvGoSyscallEnd + procStatus := tracev2.ProcSyscall // Procs implicitly enter tracev2.ProcSyscall on GoSyscallBegin. if lostP { - ev = traceEvGoSyscallEndBlocked - procStatus = traceProcRunning // If a G has a P when emitting this event, it reacquired a P and is indeed running. + ev = tracev2.EvGoSyscallEndBlocked + procStatus = tracev2.ProcRunning // If a G has a P when emitting this event, it reacquired a P and is indeed running. } else { tl.mp.p.ptr().trace.mSyscallID = -1 } - tl.eventWriter(traceGoSyscall, procStatus).event(ev) + tl.eventWriter(tracev2.GoSyscall, procStatus).event(ev) } // ProcSteal indicates that our current M stole a P from another M. @@ -547,7 +548,7 @@ func (tl traceLocker) ProcSteal(pp *p, inSyscall bool) { if !pp.trace.statusWasTraced(tl.gen) && pp.trace.acquireStatus(tl.gen) { // Careful: don't use the event writer. We never want status or in-progress events // to trigger more in-progress events. - tl.writer().writeProcStatus(uint64(pp.id), traceProcSyscallAbandoned, pp.trace.inSweep).end() + tl.writer().writeProcStatus(uint64(pp.id), tracev2.ProcSyscallAbandoned, pp.trace.inSweep).end() } // The status of the proc and goroutine, if we need to emit one here, is not evident from the @@ -556,18 +557,18 @@ func (tl traceLocker) ProcSteal(pp *p, inSyscall bool) { // ourselves specifically to keep running. The two contexts look different, but can be summarized // fairly succinctly. In the former, we're a regular running goroutine and proc, if we have either. // In the latter, we're a goroutine in a syscall. - goStatus := traceGoRunning - procStatus := traceProcRunning + goStatus := tracev2.GoRunning + procStatus := tracev2.ProcRunning if inSyscall { - goStatus = traceGoSyscall - procStatus = traceProcSyscallAbandoned + goStatus = tracev2.GoSyscall + procStatus = tracev2.ProcSyscallAbandoned } - tl.eventWriter(goStatus, procStatus).event(traceEvProcSteal, traceArg(pp.id), pp.trace.nextSeq(tl.gen), traceArg(mStolenFrom)) + tl.eventWriter(goStatus, procStatus).event(tracev2.EvProcSteal, traceArg(pp.id), pp.trace.nextSeq(tl.gen), traceArg(mStolenFrom)) } // HeapAlloc emits a HeapAlloc event. func (tl traceLocker) HeapAlloc(live uint64) { - tl.eventWriter(traceGoRunning, traceProcRunning).event(traceEvHeapAlloc, traceArg(live)) + tl.eventWriter(tracev2.GoRunning, tracev2.ProcRunning).event(tracev2.EvHeapAlloc, traceArg(live)) } // HeapGoal reads the current heap goal and emits a HeapGoal event. @@ -577,7 +578,7 @@ func (tl traceLocker) HeapGoal() { // Heap-based triggering is disabled. heapGoal = 0 } - tl.eventWriter(traceGoRunning, traceProcRunning).event(traceEvHeapGoal, traceArg(heapGoal)) + tl.eventWriter(tracev2.GoRunning, tracev2.ProcRunning).event(tracev2.EvHeapGoal, traceArg(heapGoal)) } // GoCreateSyscall indicates that a goroutine has transitioned from dead to GoSyscall. @@ -590,7 +591,7 @@ func (tl traceLocker) GoCreateSyscall(gp *g) { // N.B. We should never trace a status for this goroutine (which we're currently running on), // since we want this to appear like goroutine creation. gp.trace.setStatusTraced(tl.gen) - tl.eventWriter(traceGoBad, traceProcBad).event(traceEvGoCreateSyscall, traceArg(gp.goid)) + tl.eventWriter(tracev2.GoBad, tracev2.ProcBad).event(tracev2.EvGoCreateSyscall, traceArg(gp.goid)) } // GoDestroySyscall indicates that a goroutine has transitioned from GoSyscall to dead. @@ -602,7 +603,7 @@ func (tl traceLocker) GoCreateSyscall(gp *g) { func (tl traceLocker) GoDestroySyscall() { // N.B. If we trace a status here, we must never have a P, and we must be on a goroutine // that is in the syscall state. - tl.eventWriter(traceGoSyscall, traceProcBad).event(traceEvGoDestroySyscall) + tl.eventWriter(tracev2.GoSyscall, tracev2.ProcBad).event(tracev2.EvGoDestroySyscall) } // To access runtime functions from runtime/trace. @@ -617,7 +618,7 @@ func trace_userTaskCreate(id, parentID uint64, taskType string) { // Need to do this check because the caller won't have it. return } - tl.eventWriter(traceGoRunning, traceProcRunning).event(traceEvUserTaskBegin, traceArg(id), traceArg(parentID), tl.string(taskType), tl.stack(3)) + tl.eventWriter(tracev2.GoRunning, tracev2.ProcRunning).event(tracev2.EvUserTaskBegin, traceArg(id), traceArg(parentID), tl.string(taskType), tl.stack(3)) traceRelease(tl) } @@ -630,7 +631,7 @@ func trace_userTaskEnd(id uint64) { // Need to do this check because the caller won't have it. return } - tl.eventWriter(traceGoRunning, traceProcRunning).event(traceEvUserTaskEnd, traceArg(id), tl.stack(2)) + tl.eventWriter(tracev2.GoRunning, tracev2.ProcRunning).event(tracev2.EvUserTaskEnd, traceArg(id), tl.stack(2)) traceRelease(tl) } @@ -646,16 +647,16 @@ func trace_userRegion(id, mode uint64, name string) { // Need to do this check because the caller won't have it. return } - var ev traceEv + var ev tracev2.EventType switch mode { case 0: - ev = traceEvUserRegionBegin + ev = tracev2.EvUserRegionBegin case 1: - ev = traceEvUserRegionEnd + ev = tracev2.EvUserRegionEnd default: return } - tl.eventWriter(traceGoRunning, traceProcRunning).event(ev, traceArg(id), tl.string(name), tl.stack(3)) + tl.eventWriter(tracev2.GoRunning, tracev2.ProcRunning).event(ev, traceArg(id), tl.string(name), tl.stack(3)) traceRelease(tl) } @@ -668,7 +669,7 @@ func trace_userLog(id uint64, category, message string) { // Need to do this check because the caller won't have it. return } - tl.eventWriter(traceGoRunning, traceProcRunning).event(traceEvUserLog, traceArg(id), tl.string(category), tl.uniqueString(message), tl.stack(3)) + tl.eventWriter(tracev2.GoRunning, tracev2.ProcRunning).event(tracev2.EvUserLog, traceArg(id), tl.string(category), tl.uniqueString(message), tl.stack(3)) traceRelease(tl) } diff --git a/src/runtime/tracestack.go b/src/runtime/tracestack.go index 225566d1020fc3..bca2d0a88deec4 100644 --- a/src/runtime/tracestack.go +++ b/src/runtime/tracestack.go @@ -9,15 +9,11 @@ package runtime import ( "internal/abi" "internal/goarch" + "internal/trace/tracev2" "unsafe" ) const ( - // Maximum number of PCs in a single stack trace. - // Since events contain only stack id rather than whole stack trace, - // we can allow quite large values here. - traceStackSize = 128 - // logicalStackSentinel is a sentinel value at pcBuf[0] signifying that // pcBuf[1:] holds a logical stack requiring no further processing. Any other // value at pcBuf[0] represents a skip value to apply to the physical stack in @@ -36,7 +32,7 @@ const ( // that this stack trace is being written out for, which needs to be synchronized with // generations moving forward. Prefer traceEventWriter.stack. func traceStack(skip int, gp *g, gen uintptr) uint64 { - var pcBuf [traceStackSize]uintptr + var pcBuf [tracev2.MaxFramesPerStack]uintptr // Figure out gp and mp for the backtrace. var mp *m @@ -55,7 +51,7 @@ func traceStack(skip int, gp *g, gen uintptr) uint64 { // are totally fine for taking a stack trace. They're captured // correctly in goStatusToTraceGoStatus. switch goStatusToTraceGoStatus(status, gp.waitreason) { - case traceGoRunning, traceGoSyscall: + case tracev2.GoRunning, tracev2.GoSyscall: if getg() == gp || mp.curg == gp { break } @@ -147,7 +143,7 @@ func (t *traceStackTable) put(pcs []uintptr) uint64 { // releases all memory and resets state. It must only be called once the caller // can guarantee that there are no more writers to the table. func (t *traceStackTable) dump(gen uintptr) { - stackBuf := make([]uintptr, traceStackSize) + stackBuf := make([]uintptr, tracev2.MaxFramesPerStack) w := unsafeTraceWriter(gen, nil) if root := (*traceMapNode)(t.tab.root.Load()); root != nil { w = dumpStacksRec(root, w, stackBuf) @@ -172,15 +168,15 @@ func dumpStacksRec(node *traceMapNode, w traceWriter, stackBuf []uintptr) traceW // bound is pretty loose, but avoids counting // lots of varint sizes. // - // Add 1 because we might also write traceEvStacks. + // Add 1 because we might also write tracev2.EvStacks. var flushed bool w, flushed = w.ensure(1 + maxBytes) if flushed { - w.byte(byte(traceEvStacks)) + w.byte(byte(tracev2.EvStacks)) } // Emit stack event. - w.byte(byte(traceEvStack)) + w.byte(byte(tracev2.EvStack)) w.varint(uint64(node.id)) w.varint(uint64(len(frames))) for _, frame := range frames { diff --git a/src/runtime/tracestatus.go b/src/runtime/tracestatus.go index 425ac37ba04ee0..4dabc8e562f3de 100644 --- a/src/runtime/tracestatus.go +++ b/src/runtime/tracestatus.go @@ -6,43 +6,9 @@ package runtime -import "internal/runtime/atomic" - -// traceGoStatus is the status of a goroutine. -// -// They correspond directly to the various goroutine -// statuses. -type traceGoStatus uint8 - -const ( - traceGoBad traceGoStatus = iota - traceGoRunnable - traceGoRunning - traceGoSyscall - traceGoWaiting -) - -// traceProcStatus is the status of a P. -// -// They mostly correspond to the various P statuses. -type traceProcStatus uint8 - -const ( - traceProcBad traceProcStatus = iota - traceProcRunning - traceProcIdle - traceProcSyscall - - // traceProcSyscallAbandoned is a special case of - // traceProcSyscall. It's used in the very specific case - // where the first a P is mentioned in a generation is - // part of a ProcSteal event. If that's the first time - // it's mentioned, then there's no GoSyscallBegin to - // connect the P stealing back to at that point. This - // special state indicates this to the parser, so it - // doesn't try to find a GoSyscallEndBlocked that - // corresponds with the ProcSteal. - traceProcSyscallAbandoned +import ( + "internal/runtime/atomic" + "internal/trace/tracev2" ) // writeGoStatus emits a GoStatus event as well as any active ranges on the goroutine. @@ -51,23 +17,23 @@ const ( // have any stack growth. // //go:nosplit -func (w traceWriter) writeGoStatus(goid uint64, mid int64, status traceGoStatus, markAssist bool, stackID uint64) traceWriter { +func (w traceWriter) writeGoStatus(goid uint64, mid int64, status tracev2.GoStatus, markAssist bool, stackID uint64) traceWriter { // The status should never be bad. Some invariant must have been violated. - if status == traceGoBad { + if status == tracev2.GoBad { print("runtime: goid=", goid, "\n") throw("attempted to trace a bad status for a goroutine") } // Trace the status. if stackID == 0 { - w = w.event(traceEvGoStatus, traceArg(goid), traceArg(uint64(mid)), traceArg(status)) + w = w.event(tracev2.EvGoStatus, traceArg(goid), traceArg(uint64(mid)), traceArg(status)) } else { - w = w.event(traceEvGoStatusStack, traceArg(goid), traceArg(uint64(mid)), traceArg(status), traceArg(stackID)) + w = w.event(tracev2.EvGoStatusStack, traceArg(goid), traceArg(uint64(mid)), traceArg(status), traceArg(stackID)) } // Trace any special ranges that are in-progress. if markAssist { - w = w.event(traceEvGCMarkAssistActive, traceArg(goid)) + w = w.event(tracev2.EvGCMarkAssistActive, traceArg(goid)) } return w } @@ -85,26 +51,26 @@ func (w traceWriter) writeProcStatusForP(pp *p, inSTW bool) traceWriter { if !pp.trace.acquireStatus(w.gen) { return w } - var status traceProcStatus + var status tracev2.ProcStatus switch pp.status { case _Pidle, _Pgcstop: - status = traceProcIdle + status = tracev2.ProcIdle if pp.status == _Pgcstop && inSTW { // N.B. a P that is running and currently has the world stopped will be // in _Pgcstop, but we model it as running in the tracer. - status = traceProcRunning + status = tracev2.ProcRunning } case _Prunning: - status = traceProcRunning + status = tracev2.ProcRunning // There's a short window wherein the goroutine may have entered _Gsyscall // but it still owns the P (it's not in _Psyscall yet). The goroutine entering // _Gsyscall is the tracer's signal that the P its bound to is also in a syscall, // so we need to emit a status that matches. See #64318. if w.mp.p.ptr() == pp && w.mp.curg != nil && readgstatus(w.mp.curg)&^_Gscan == _Gsyscall { - status = traceProcSyscall + status = tracev2.ProcSyscall } case _Psyscall: - status = traceProcSyscall + status = tracev2.ProcSyscall default: throw("attempt to trace invalid or unsupported P status") } @@ -121,19 +87,19 @@ func (w traceWriter) writeProcStatusForP(pp *p, inSTW bool) traceWriter { // have any stack growth. // //go:nosplit -func (w traceWriter) writeProcStatus(pid uint64, status traceProcStatus, inSweep bool) traceWriter { +func (w traceWriter) writeProcStatus(pid uint64, status tracev2.ProcStatus, inSweep bool) traceWriter { // The status should never be bad. Some invariant must have been violated. - if status == traceProcBad { + if status == tracev2.ProcBad { print("runtime: pid=", pid, "\n") throw("attempted to trace a bad status for a proc") } // Trace the status. - w = w.event(traceEvProcStatus, traceArg(pid), traceArg(status)) + w = w.event(tracev2.EvProcStatus, traceArg(pid), traceArg(status)) // Trace any special ranges that are in-progress. if inSweep { - w = w.event(traceEvGCSweepActive, traceArg(pid)) + w = w.event(tracev2.EvGCSweepActive, traceArg(pid)) } return w } @@ -146,16 +112,16 @@ func (w traceWriter) writeProcStatus(pid uint64, status traceProcStatus, inSweep // have any stack growth. // //go:nosplit -func goStatusToTraceGoStatus(status uint32, wr waitReason) traceGoStatus { +func goStatusToTraceGoStatus(status uint32, wr waitReason) tracev2.GoStatus { // N.B. Ignore the _Gscan bit. We don't model it in the tracer. - var tgs traceGoStatus + var tgs tracev2.GoStatus switch status &^ _Gscan { case _Grunnable: - tgs = traceGoRunnable + tgs = tracev2.GoRunnable case _Grunning, _Gcopystack: - tgs = traceGoRunning + tgs = tracev2.GoRunning case _Gsyscall: - tgs = traceGoSyscall + tgs = tracev2.GoSyscall case _Gwaiting, _Gpreempted: // There are a number of cases where a G might end up in // _Gwaiting but it's actually running in a non-preemptive @@ -163,9 +129,9 @@ func goStatusToTraceGoStatus(status uint32, wr waitReason) traceGoStatus { // garbage collector. In these cases, we're not going to // emit an event, and we want these goroutines to appear in // the final trace as if they're running, not blocked. - tgs = traceGoWaiting + tgs = tracev2.GoWaiting if status == _Gwaiting && wr.isWaitingForGC() { - tgs = traceGoRunning + tgs = tracev2.GoRunning } case _Gdead: throw("tried to trace dead goroutine") diff --git a/src/runtime/tracestring.go b/src/runtime/tracestring.go index 2585c69cc0b7ff..d486f9efbdf8b5 100644 --- a/src/runtime/tracestring.go +++ b/src/runtime/tracestring.go @@ -6,9 +6,9 @@ package runtime -// Trace strings. +import "internal/trace/tracev2" -const maxTraceStringLen = 1024 +// Trace strings. // traceStringTable is map of string -> unique ID that also manages // writing strings out into the trace. @@ -52,8 +52,8 @@ func (t *traceStringTable) emit(gen uintptr, s string) uint64 { //go:systemstack func (t *traceStringTable) writeString(gen uintptr, id uint64, s string) { // Truncate the string if necessary. - if len(s) > maxTraceStringLen { - s = s[:maxTraceStringLen] + if len(s) > tracev2.MaxEventTrailerDataSize { + s = s[:tracev2.MaxEventTrailerDataSize] } lock(&t.lock) @@ -61,14 +61,14 @@ func (t *traceStringTable) writeString(gen uintptr, id uint64, s string) { // Ensure we have a place to write to. var flushed bool - w, flushed = w.ensure(2 + 2*traceBytesPerNumber + len(s) /* traceEvStrings + traceEvString + ID + len + string data */) + w, flushed = w.ensure(2 + 2*traceBytesPerNumber + len(s) /* tracev2.EvStrings + tracev2.EvString + ID + len + string data */) if flushed { // Annotate the batch as containing strings. - w.byte(byte(traceEvStrings)) + w.byte(byte(tracev2.EvStrings)) } // Write out the string. - w.byte(byte(traceEvString)) + w.byte(byte(tracev2.EvString)) w.varint(id) w.varint(uint64(len(s))) w.stringData(s) diff --git a/src/runtime/tracetime.go b/src/runtime/tracetime.go index d5ee2b078fc022..bfda0aac9a24d8 100644 --- a/src/runtime/tracetime.go +++ b/src/runtime/tracetime.go @@ -8,6 +8,7 @@ package runtime import ( "internal/goarch" + "internal/trace/tracev2" _ "unsafe" ) @@ -80,10 +81,10 @@ func traceFrequency(gen uintptr) { w := unsafeTraceWriter(gen, nil) // Ensure we have a place to write to. - w, _ = w.ensure(1 + traceBytesPerNumber /* traceEvFrequency + frequency */) + w, _ = w.ensure(1 + traceBytesPerNumber /* tracev2.EvFrequency + frequency */) // Write out the string. - w.byte(byte(traceEvFrequency)) + w.byte(byte(tracev2.EvFrequency)) w.varint(traceClockUnitsPerSecond()) // Immediately flush the buffer. diff --git a/src/runtime/tracetype.go b/src/runtime/tracetype.go index d9e340f64a4cb1..f54f8125784e24 100644 --- a/src/runtime/tracetype.go +++ b/src/runtime/tracetype.go @@ -9,6 +9,7 @@ package runtime import ( "internal/abi" "internal/goarch" + "internal/trace/tracev2" "unsafe" ) @@ -35,7 +36,7 @@ func (t *traceTypeTable) put(typ *abi.Type) uint64 { // releases all memory and resets state. It must only be called once the caller // can guarantee that there are no more writers to the table. func (t *traceTypeTable) dump(gen uintptr) { - w := unsafeTraceExpWriter(gen, nil, traceExperimentAllocFree) + w := unsafeTraceExpWriter(gen, nil, tracev2.AllocFree) if root := (*traceMapNode)(t.tab.root.Load()); root != nil { w = dumpTypesRec(root, w) } From 0be3701cb618713611fe3c21c13b2aee34020fff Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Mon, 27 Jan 2025 21:42:34 +0000 Subject: [PATCH 322/397] internal/trace: clean up parser.go parser.go is an old file that contains trace v1 definitions and a second equivalent definition for stack frames. These are redundant and useless. Delete these definitions and rename the file to fakep.go, which describes the only thing left in this file, a bunch of fake P IDs used by the trace viewer. We should consider moving the fake P definitions elsewhere, too. Change-Id: Ifd0768bd73c39009069445afe0155f1e352f00c3 Reviewed-on: https://go-review.googlesource.com/c/go/+/644875 Reviewed-by: Michael Pratt Auto-Submit: Michael Knyszek LUCI-TryBot-Result: Go LUCI --- src/cmd/trace/pprof.go | 11 ++-- src/cmd/trace/viewer.go | 14 +--- src/internal/trace/fakep.go | 15 +++++ src/internal/trace/parser.go | 79 ----------------------- src/internal/trace/traceviewer/emitter.go | 6 +- src/internal/trace/traceviewer/pprof.go | 10 +-- 6 files changed, 30 insertions(+), 105 deletions(-) create mode 100644 src/internal/trace/fakep.go delete mode 100644 src/internal/trace/parser.go diff --git a/src/cmd/trace/pprof.go b/src/cmd/trace/pprof.go index d27dfa7aa33100..a66419aedf764e 100644 --- a/src/cmd/trace/pprof.go +++ b/src/cmd/trace/pprof.go @@ -306,18 +306,15 @@ func (m *stackMap) profile() []traceviewer.ProfileRecord { prof := make([]traceviewer.ProfileRecord, 0, len(m.stacks)) for stack, record := range m.stacks { rec := *record - for i, frame := range slices.Collect(stack.Frames()) { - rec.Stack = append(rec.Stack, &trace.Frame{ - PC: frame.PC, - Fn: frame.Func, - File: frame.File, - Line: int(frame.Line), - }) + var i int + for frame := range stack.Frames() { + rec.Stack = append(rec.Stack, frame) // Cut this off at pprofMaxStack because that's as far // as our deduplication goes. if i >= pprofMaxStack { break } + i++ } prof = append(prof, rec) } diff --git a/src/cmd/trace/viewer.go b/src/cmd/trace/viewer.go index 6ce74b75b8dbba..da83e81ab9327e 100644 --- a/src/cmd/trace/viewer.go +++ b/src/cmd/trace/viewer.go @@ -8,22 +8,14 @@ import ( "fmt" "internal/trace" "internal/trace/traceviewer" + "slices" "time" ) // viewerFrames returns the frames of the stack of ev. The given frame slice is // used to store the frames to reduce allocations. -func viewerFrames(stk trace.Stack) []*trace.Frame { - var frames []*trace.Frame - for f := range stk.Frames() { - frames = append(frames, &trace.Frame{ - PC: f.PC, - Fn: f.Func, - File: f.File, - Line: int(f.Line), - }) - } - return frames +func viewerFrames(stk trace.Stack) []trace.StackFrame { + return slices.Collect(stk.Frames()) } func viewerGState(state trace.GoState, inMarkAssist bool) traceviewer.GState { diff --git a/src/internal/trace/fakep.go b/src/internal/trace/fakep.go new file mode 100644 index 00000000000000..8d580c3a3aa285 --- /dev/null +++ b/src/internal/trace/fakep.go @@ -0,0 +1,15 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package trace + +const ( + // Special P identifiers: + FakeP = 1000000 + iota + TimerP // depicts timer unblocks + NetpollP // depicts network unblocks + SyscallP // depicts returns from syscalls + GCP // depicts GC state + ProfileP // depicts recording of CPU profile samples +) diff --git a/src/internal/trace/parser.go b/src/internal/trace/parser.go deleted file mode 100644 index d6fff84d55b63e..00000000000000 --- a/src/internal/trace/parser.go +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package trace - -// Frame is a frame in stack traces. -type Frame struct { - PC uint64 - Fn string - File string - Line int -} - -const ( - // Special P identifiers: - FakeP = 1000000 + iota - TimerP // depicts timer unblocks - NetpollP // depicts network unblocks - SyscallP // depicts returns from syscalls - GCP // depicts GC state - ProfileP // depicts recording of CPU profile samples -) - -// Event types in the trace. -// Verbatim copy from src/runtime/trace.go with the "trace" prefix removed. -const ( - EvNone = 0 // unused - EvBatch = 1 // start of per-P batch of events [pid, timestamp] - EvFrequency = 2 // contains tracer timer frequency [frequency (ticks per second)] - EvStack = 3 // stack [stack id, number of PCs, array of {PC, func string ID, file string ID, line}] - EvGomaxprocs = 4 // current value of GOMAXPROCS [timestamp, GOMAXPROCS, stack id] - EvProcStart = 5 // start of P [timestamp, thread id] - EvProcStop = 6 // stop of P [timestamp] - EvGCStart = 7 // GC start [timestamp, seq, stack id] - EvGCDone = 8 // GC done [timestamp] - EvSTWStart = 9 // GC mark termination start [timestamp, kind] - EvSTWDone = 10 // GC mark termination done [timestamp] - EvGCSweepStart = 11 // GC sweep start [timestamp, stack id] - EvGCSweepDone = 12 // GC sweep done [timestamp, swept, reclaimed] - EvGoCreate = 13 // goroutine creation [timestamp, new goroutine id, new stack id, stack id] - EvGoStart = 14 // goroutine starts running [timestamp, goroutine id, seq] - EvGoEnd = 15 // goroutine ends [timestamp] - EvGoStop = 16 // goroutine stops (like in select{}) [timestamp, stack] - EvGoSched = 17 // goroutine calls Gosched [timestamp, stack] - EvGoPreempt = 18 // goroutine is preempted [timestamp, stack] - EvGoSleep = 19 // goroutine calls Sleep [timestamp, stack] - EvGoBlock = 20 // goroutine blocks [timestamp, stack] - EvGoUnblock = 21 // goroutine is unblocked [timestamp, goroutine id, seq, stack] - EvGoBlockSend = 22 // goroutine blocks on chan send [timestamp, stack] - EvGoBlockRecv = 23 // goroutine blocks on chan recv [timestamp, stack] - EvGoBlockSelect = 24 // goroutine blocks on select [timestamp, stack] - EvGoBlockSync = 25 // goroutine blocks on Mutex/RWMutex [timestamp, stack] - EvGoBlockCond = 26 // goroutine blocks on Cond [timestamp, stack] - EvGoBlockNet = 27 // goroutine blocks on network [timestamp, stack] - EvGoSysCall = 28 // syscall enter [timestamp, stack] - EvGoSysExit = 29 // syscall exit [timestamp, goroutine id, seq, real timestamp] - EvGoSysBlock = 30 // syscall blocks [timestamp] - EvGoWaiting = 31 // denotes that goroutine is blocked when tracing starts [timestamp, goroutine id] - EvGoInSyscall = 32 // denotes that goroutine is in syscall when tracing starts [timestamp, goroutine id] - EvHeapAlloc = 33 // gcController.heapLive change [timestamp, heap live bytes] - EvHeapGoal = 34 // gcController.heapGoal change [timestamp, heap goal bytes] - EvTimerGoroutine = 35 // denotes timer goroutine [timer goroutine id] - EvFutileWakeup = 36 // denotes that the previous wakeup of this goroutine was futile [timestamp] - EvString = 37 // string dictionary entry [ID, length, string] - EvGoStartLocal = 38 // goroutine starts running on the same P as the last event [timestamp, goroutine id] - EvGoUnblockLocal = 39 // goroutine is unblocked on the same P as the last event [timestamp, goroutine id, stack] - EvGoSysExitLocal = 40 // syscall exit on the same P as the last event [timestamp, goroutine id, real timestamp] - EvGoStartLabel = 41 // goroutine starts running with label [timestamp, goroutine id, seq, label string id] - EvGoBlockGC = 42 // goroutine blocks on GC assist [timestamp, stack] - EvGCMarkAssistStart = 43 // GC mark assist start [timestamp, stack] - EvGCMarkAssistDone = 44 // GC mark assist done [timestamp] - EvUserTaskCreate = 45 // trace.NewTask [timestamp, internal task id, internal parent id, name string, stack] - EvUserTaskEnd = 46 // end of task [timestamp, internal task id, stack] - EvUserRegion = 47 // trace.WithRegion [timestamp, internal task id, mode(0:start, 1:end), name string, stack] - EvUserLog = 48 // trace.Log [timestamp, internal id, key string id, stack, value string] - EvCPUSample = 49 // CPU profiling sample [timestamp, real timestamp, real P id (-1 when absent), goroutine id, stack] - EvCount = 50 -) diff --git a/src/internal/trace/traceviewer/emitter.go b/src/internal/trace/traceviewer/emitter.go index c74f1c2ecf583d..d2227d681e7943 100644 --- a/src/internal/trace/traceviewer/emitter.go +++ b/src/internal/trace/traceviewer/emitter.go @@ -683,12 +683,12 @@ func (e *Emitter) processMeta(sectionID uint64, name string, priority int) { // Stack emits the given frames and returns a unique id for the stack. No // pointers to the given data are being retained beyond the call to Stack. -func (e *Emitter) Stack(stk []*trace.Frame) int { +func (e *Emitter) Stack(stk []trace.StackFrame) int { return e.buildBranch(e.frameTree, stk) } // buildBranch builds one branch in the prefix tree rooted at ctx.frameTree. -func (e *Emitter) buildBranch(parent frameNode, stk []*trace.Frame) int { +func (e *Emitter) buildBranch(parent frameNode, stk []trace.StackFrame) int { if len(stk) == 0 { return parent.id } @@ -702,7 +702,7 @@ func (e *Emitter) buildBranch(parent frameNode, stk []*trace.Frame) int { node.id = e.frameSeq node.children = make(map[uint64]frameNode) parent.children[frame.PC] = node - e.c.ConsumeViewerFrame(strconv.Itoa(node.id), format.Frame{Name: fmt.Sprintf("%v:%v", frame.Fn, frame.Line), Parent: parent.id}) + e.c.ConsumeViewerFrame(strconv.Itoa(node.id), format.Frame{Name: fmt.Sprintf("%v:%v", frame.Func, frame.Line), Parent: parent.id}) } return e.buildBranch(node, stk) } diff --git a/src/internal/trace/traceviewer/pprof.go b/src/internal/trace/traceviewer/pprof.go index 1377b3c614c81c..141b2687b781ac 100644 --- a/src/internal/trace/traceviewer/pprof.go +++ b/src/internal/trace/traceviewer/pprof.go @@ -82,7 +82,7 @@ func SVGProfileHandlerFunc(f ProfileFunc) http.HandlerFunc { } type ProfileRecord struct { - Stack []*trace.Frame + Stack []trace.StackFrame Count uint64 Time time.Duration } @@ -103,16 +103,16 @@ func BuildProfile(prof []ProfileRecord) *profile.Profile { for _, frame := range rec.Stack { loc := locs[frame.PC] if loc == nil { - fn := funcs[frame.File+frame.Fn] + fn := funcs[frame.File+frame.Func] if fn == nil { fn = &profile.Function{ ID: uint64(len(p.Function) + 1), - Name: frame.Fn, - SystemName: frame.Fn, + Name: frame.Func, + SystemName: frame.Func, Filename: frame.File, } p.Function = append(p.Function, fn) - funcs[frame.File+frame.Fn] = fn + funcs[frame.File+frame.Func] = fn } loc = &profile.Location{ ID: uint64(len(p.Location) + 1), From 659b895067400e1db64c57712729623970149e99 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Mon, 27 Jan 2025 21:47:24 +0000 Subject: [PATCH 323/397] internal/trace: move fake P IDs to internal/trace/traceviewer These fake P IDs really only belong to the traceviewer. Change-Id: I7976beb5750f1efca85e28975074a8c570a9c959 Reviewed-on: https://go-review.googlesource.com/c/go/+/644876 Reviewed-by: Michael Pratt LUCI-TryBot-Result: Go LUCI Auto-Submit: Michael Knyszek --- src/cmd/trace/gen.go | 4 ++-- src/cmd/trace/gstate.go | 6 +++--- src/cmd/trace/jsontrace_test.go | 4 ++-- src/internal/trace/traceviewer/emitter.go | 8 ++++---- src/internal/trace/{ => traceviewer}/fakep.go | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) rename src/internal/trace/{ => traceviewer}/fakep.go (95%) diff --git a/src/cmd/trace/gen.go b/src/cmd/trace/gen.go index 67811ca04d8678..03ee5037e9f779 100644 --- a/src/cmd/trace/gen.go +++ b/src/cmd/trace/gen.go @@ -248,7 +248,7 @@ func (g *globalRangeGenerator) GlobalRange(ctx *traceContext, ev *trace.Event) { Name: r.Name, Ts: ctx.elapsed(ar.time), Dur: ev.Time().Sub(ar.time), - Resource: trace.GCP, + Resource: traceviewer.GCP, Stack: ctx.Stack(viewerFrames(ar.stack)), EndStack: ctx.Stack(viewerFrames(ev.Stack())), }) @@ -267,7 +267,7 @@ func (g *globalRangeGenerator) Finish(ctx *traceContext) { Name: name, Ts: ctx.elapsed(ar.time), Dur: ctx.endTime.Sub(ar.time), - Resource: trace.GCP, + Resource: traceviewer.GCP, Stack: ctx.Stack(viewerFrames(ar.stack)), }) } diff --git a/src/cmd/trace/gstate.go b/src/cmd/trace/gstate.go index c883166e06da2e..9c3da66217fd07 100644 --- a/src/cmd/trace/gstate.go +++ b/src/cmd/trace/gstate.go @@ -202,13 +202,13 @@ func (gs *gState[R]) syscallEnd(ts trace.Time, blocked bool, ctx *traceContext) // to emit a flow event from, indicating explicitly that this goroutine was unblocked by the system. func (gs *gState[R]) blockedSyscallEnd(ts trace.Time, stack trace.Stack, ctx *traceContext) { name := "exit blocked syscall" - gs.setStartCause(ts, name, trace.SyscallP, stack) + gs.setStartCause(ts, name, traceviewer.SyscallP, stack) // Emit an syscall exit instant event for the "Syscall" lane. ctx.Instant(traceviewer.InstantEvent{ Name: name, Ts: ctx.elapsed(ts), - Resource: trace.SyscallP, + Resource: traceviewer.SyscallP, Stack: ctx.Stack(viewerFrames(stack)), }) } @@ -228,7 +228,7 @@ func (gs *gState[R]) unblock(ts trace.Time, stack trace.Stack, resource R, ctx * // TODO(mknyszek): Handle this invalidness in a more general way. if _, ok := any(resource).(trace.ThreadID); !ok { // Emit an unblock instant event for the "Network" lane. - viewerResource = trace.NetpollP + viewerResource = traceviewer.NetpollP } ctx.Instant(traceviewer.InstantEvent{ Name: name, diff --git a/src/cmd/trace/jsontrace_test.go b/src/cmd/trace/jsontrace_test.go index 5f89b275dca197..c9df45040f7d17 100644 --- a/src/cmd/trace/jsontrace_test.go +++ b/src/cmd/trace/jsontrace_test.go @@ -7,7 +7,6 @@ package main import ( "bytes" "encoding/json" - "internal/trace" "io" "net/http/httptest" "os" @@ -19,6 +18,7 @@ import ( "time" "internal/trace/raw" + "internal/trace/traceviewer" "internal/trace/traceviewer/format" ) @@ -159,7 +159,7 @@ func checkNetworkUnblock(t *testing.T, data format.Data) { count := 0 var netBlockEv *format.Event for _, e := range data.Events { - if e.TID == trace.NetpollP && e.Name == "unblock (network)" && e.Phase == "I" && e.Scope == "t" { + if e.TID == traceviewer.NetpollP && e.Name == "unblock (network)" && e.Phase == "I" && e.Scope == "t" { count++ netBlockEv = e } diff --git a/src/internal/trace/traceviewer/emitter.go b/src/internal/trace/traceviewer/emitter.go index d2227d681e7943..9167ff81b45f83 100644 --- a/src/internal/trace/traceviewer/emitter.go +++ b/src/internal/trace/traceviewer/emitter.go @@ -632,10 +632,10 @@ func (e *Emitter) Flush() { e.processMeta(format.ProcsSection, e.resourceType, 2) - e.threadMeta(format.ProcsSection, trace.GCP, "GC", -6) - e.threadMeta(format.ProcsSection, trace.NetpollP, "Network", -5) - e.threadMeta(format.ProcsSection, trace.TimerP, "Timers", -4) - e.threadMeta(format.ProcsSection, trace.SyscallP, "Syscalls", -3) + e.threadMeta(format.ProcsSection, GCP, "GC", -6) + e.threadMeta(format.ProcsSection, NetpollP, "Network", -5) + e.threadMeta(format.ProcsSection, TimerP, "Timers", -4) + e.threadMeta(format.ProcsSection, SyscallP, "Syscalls", -3) for id, name := range e.resources { priority := int(id) diff --git a/src/internal/trace/fakep.go b/src/internal/trace/traceviewer/fakep.go similarity index 95% rename from src/internal/trace/fakep.go rename to src/internal/trace/traceviewer/fakep.go index 8d580c3a3aa285..655938b213bc36 100644 --- a/src/internal/trace/fakep.go +++ b/src/internal/trace/traceviewer/fakep.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package trace +package traceviewer const ( // Special P identifiers: From 49eba8b15bcfc07eb272f23f1b6810d37e6fe342 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Tue, 28 Jan 2025 20:54:34 +0000 Subject: [PATCH 324/397] internal/trace: interpret string ID arguments for experimental events Currently one of the reasons experimental events are tricky to use is because: - There's no way to take advantage of the existing infrastructure, like strings and stacks, and - There's no way to attach arbitrary data to an event (except through strings, possibly). Fix this by abstracting away the raw arguments in an ExperimentalEvent and requiring access to the arguments via a new method, ArgValue. This returns a Value, which gives us an opportunity to construct a typed value for the raw argument dynamically, and a way to access existing tables. The type of the argument is deduced from conventions for the argument's name. This seems more than sufficient for experimental events. To make this work, we also need to add a "string" variant to the Value type. This may be a little confusing since they're primarily used for metrics, but one could imagine other scenarios in which this is useful, such as including build information in the trace as a metric, so I think this is fine. This change also updates the Value API to accomodate a String method for use with things that expect a fmt.Stringer, which means renaming the value assertion methods to have a "To" prefix. Change-Id: I43a2334f6cd306122c5b94641a6252ca4258b39f Reviewed-on: https://go-review.googlesource.com/c/go/+/645135 Reviewed-by: Michael Pratt LUCI-TryBot-Result: Go LUCI Auto-Submit: Michael Knyszek --- src/cmd/trace/gen.go | 6 +-- src/internal/trace/event.go | 51 +++++++++++++++------- src/internal/trace/gc.go | 2 +- src/internal/trace/testtrace/validation.go | 2 +- src/internal/trace/tracev2/spec.go | 4 +- src/internal/trace/value.go | 48 ++++++++++++++------ 6 files changed, 79 insertions(+), 34 deletions(-) diff --git a/src/cmd/trace/gen.go b/src/cmd/trace/gen.go index 03ee5037e9f779..6e4d82799e581d 100644 --- a/src/cmd/trace/gen.go +++ b/src/cmd/trace/gen.go @@ -282,11 +282,11 @@ func (g *globalMetricGenerator) GlobalMetric(ctx *traceContext, ev *trace.Event) m := ev.Metric() switch m.Name { case "/memory/classes/heap/objects:bytes": - ctx.HeapAlloc(ctx.elapsed(ev.Time()), m.Value.Uint64()) + ctx.HeapAlloc(ctx.elapsed(ev.Time()), m.Value.ToUint64()) case "/gc/heap/goal:bytes": - ctx.HeapGoal(ctx.elapsed(ev.Time()), m.Value.Uint64()) + ctx.HeapGoal(ctx.elapsed(ev.Time()), m.Value.ToUint64()) case "/sched/gomaxprocs:threads": - ctx.Gomaxprocs(m.Value.Uint64()) + ctx.Gomaxprocs(m.Value.ToUint64()) } } diff --git a/src/internal/trace/event.go b/src/internal/trace/event.go index ebf8aaa97790ba..896ab7f73a1f1c 100644 --- a/src/internal/trace/event.go +++ b/src/internal/trace/event.go @@ -315,12 +315,25 @@ type ExperimentalEvent struct { // Experiment is the name of the experiment this event is a part of. Experiment string - // ArgNames is the names of the event's arguments in order. - // This may refer to a globally shared slice. Copy before mutating. - ArgNames []string + // Args lists the names of the event's arguments in order. + Args []string - // Args contains the event's arguments. - Args []uint64 + // argValues contains the raw integer arguments which are interpreted + // by ArgValue using table. + table *evTable + argValues []uint64 +} + +// ArgValue returns a typed Value for the i'th argument in the experimental event. +func (e ExperimentalEvent) ArgValue(i int) Value { + if i < 0 || i >= len(e.Args) { + panic(fmt.Sprintf("experimental event argument index %d out of bounds [0, %d)", i, len(e.Args))) + } + if strings.HasSuffix(e.Args[i], "string") { + s := e.table.strings.mustGet(stringID(e.argValues[i])) + return stringValue(s) + } + return uint64Value(e.argValues[i]) } // ExperimentalBatch represents a packet of unparsed data along with metadata about that packet. @@ -421,13 +434,13 @@ func (e Event) Metric() Metric { switch e.base.typ { case tracev2.EvProcsChange: m.Name = "/sched/gomaxprocs:threads" - m.Value = Value{kind: ValueUint64, scalar: e.base.args[0]} + m.Value = uint64Value(e.base.args[0]) case tracev2.EvHeapAlloc: m.Name = "/memory/classes/heap/objects:bytes" - m.Value = Value{kind: ValueUint64, scalar: e.base.args[0]} + m.Value = uint64Value(e.base.args[0]) case tracev2.EvHeapGoal: m.Name = "/gc/heap/goal:bytes" - m.Value = Value{kind: ValueUint64, scalar: e.base.args[0]} + m.Value = uint64Value(e.base.args[0]) default: panic(fmt.Sprintf("internal error: unexpected wire-format event type for Metric kind: %d", e.base.typ)) } @@ -503,11 +516,11 @@ func (e Event) RangeAttributes() []RangeAttribute { return []RangeAttribute{ { Name: "bytes swept", - Value: Value{kind: ValueUint64, scalar: e.base.args[0]}, + Value: uint64Value(e.base.args[0]), }, { Name: "bytes reclaimed", - Value: Value{kind: ValueUint64, scalar: e.base.args[1]}, + Value: uint64Value(e.base.args[1]), }, } } @@ -687,8 +700,9 @@ func (e Event) Experimental() ExperimentalEvent { return ExperimentalEvent{ Name: spec.Name, Experiment: tracev2.Experiments()[spec.Experiment], - ArgNames: argNames, - Args: e.base.args[:len(argNames)], + Args: argNames, + table: e.table, + argValues: e.base.args[:len(argNames)], } } @@ -773,7 +787,7 @@ func (e Event) String() string { switch kind := e.Kind(); kind { case EventMetric: m := e.Metric() - fmt.Fprintf(&sb, " Name=%q Value=%s", m.Name, valueAsString(m.Value)) + fmt.Fprintf(&sb, " Name=%q Value=%s", m.Name, m.Value) case EventLabel: l := e.Label() fmt.Fprintf(&sb, " Label=%q Resource=%s", l.Label, l.Resource) @@ -786,7 +800,7 @@ func (e Event) String() string { if i != 0 { fmt.Fprintf(&sb, " ") } - fmt.Fprintf(&sb, "%q=%s", attr.Name, valueAsString(attr.Value)) + fmt.Fprintf(&sb, "%q=%s", attr.Name, attr.Value) } fmt.Fprintf(&sb, "]") } @@ -822,7 +836,14 @@ func (e Event) String() string { } case EventExperimental: r := e.Experimental() - fmt.Fprintf(&sb, " Name=%s ArgNames=%v Args=%v", r.Name, r.ArgNames, r.Args) + fmt.Fprintf(&sb, " Name=%s Args=[", r.Name) + for i, arg := range r.Args { + if i != 0 { + fmt.Fprintf(&sb, ", ") + } + fmt.Fprintf(&sb, "%s=%s", arg, r.ArgValue(i).String()) + } + fmt.Fprintf(&sb, "]") } if stk := e.Stack(); stk != NoStack { fmt.Fprintln(&sb) diff --git a/src/internal/trace/gc.go b/src/internal/trace/gc.go index 46890e784df24c..f5e8fe79f293be 100644 --- a/src/internal/trace/gc.go +++ b/src/internal/trace/gc.go @@ -103,7 +103,7 @@ func MutatorUtilizationV2(events []Event, flags UtilFlags) [][]MutatorUtil { if m.Name != "/sched/gomaxprocs:threads" { break } - gomaxprocs := int(m.Value.Uint64()) + gomaxprocs := int(m.Value.ToUint64()) if len(ps) > gomaxprocs { if flags&UtilPerProc != 0 { // End each P's series. diff --git a/src/internal/trace/testtrace/validation.go b/src/internal/trace/testtrace/validation.go index 3d12f75c499ff6..f61f7a3ffa6031 100644 --- a/src/internal/trace/testtrace/validation.go +++ b/src/internal/trace/testtrace/validation.go @@ -91,7 +91,7 @@ func (v *Validator) Event(ev trace.Event) error { switch m.Value.Kind() { case trace.ValueUint64: // Just make sure it doesn't panic. - _ = m.Value.Uint64() + _ = m.Value.ToUint64() } case trace.EventLabel: l := ev.Label() diff --git a/src/internal/trace/tracev2/spec.go b/src/internal/trace/tracev2/spec.go index af92865781741d..6e54c399f49ddf 100644 --- a/src/internal/trace/tracev2/spec.go +++ b/src/internal/trace/tracev2/spec.go @@ -19,7 +19,9 @@ type EventSpec struct { // Its length determines the number of arguments an event has. // // Argument names follow a certain structure and this structure - // is relied on by the testing framework to type-check arguments. + // is relied on by the testing framework to type-check arguments + // and to produce Values for experimental events. + // // The structure is: // // (?P[A-Za-z]+)(_(?P[A-Za-z]+))? diff --git a/src/internal/trace/value.go b/src/internal/trace/value.go index bd2cba7878355d..bf396b6a9ee394 100644 --- a/src/internal/trace/value.go +++ b/src/internal/trace/value.go @@ -4,12 +4,16 @@ package trace -import "fmt" +import ( + "fmt" + "unsafe" +) // Value is a dynamically-typed value obtained from a trace. type Value struct { - kind ValueKind - scalar uint64 + kind ValueKind + pointer unsafe.Pointer + scalar uint64 } // ValueKind is the type of a dynamically-typed value from a trace. @@ -18,6 +22,7 @@ type ValueKind uint8 const ( ValueBad ValueKind = iota ValueUint64 + ValueString ) // Kind returns the ValueKind of the value. @@ -30,24 +35,41 @@ func (v Value) Kind() ValueKind { return v.kind } -// Uint64 returns the uint64 value for a MetricSampleUint64. +// ToUint64 returns the uint64 value for a ValueUint64. // -// Panics if this metric sample's Kind is not MetricSampleUint64. -func (v Value) Uint64() uint64 { +// Panics if this Value's Kind is not ValueUint64. +func (v Value) ToUint64() uint64 { if v.kind != ValueUint64 { - panic("Uint64 called on Value of a different Kind") + panic("ToUint64 called on Value of a different Kind") } return v.scalar } -// valueAsString produces a debug string value. +// ToString returns the uint64 value for a ValueString. // -// This isn't just Value.String because we may want to use that to store -// string values in the future. -func valueAsString(v Value) string { +// Panics if this Value's Kind is not ValueString. +func (v Value) ToString() string { + if v.kind != ValueString { + panic("ToString called on Value of a different Kind") + } + return unsafe.String((*byte)(v.pointer), int(v.scalar)) +} + +func uint64Value(x uint64) Value { + return Value{kind: ValueUint64, scalar: x} +} + +func stringValue(s string) Value { + return Value{kind: ValueString, scalar: uint64(len(s)), pointer: unsafe.Pointer(unsafe.StringData(s))} +} + +// String returns the string representation of the value. +func (v Value) String() string { switch v.Kind() { case ValueUint64: - return fmt.Sprintf("Uint64(%d)", v.scalar) + return fmt.Sprintf("Value{Uint64(%d)}", v.ToUint64()) + case ValueString: + return fmt.Sprintf("Value{String(%s)}", v.ToString()) } - return "Bad" + return "Value{Bad}" } From 34e8541d24b5b6624ccc252125f832c1ea0bfa00 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Tue, 28 Jan 2025 20:59:54 +0000 Subject: [PATCH 325/397] internal/trace/tracev2: add guide for trace experiments Change-Id: I6fb354a57f3e73bd6589570868c7d68369adcf3c Reviewed-on: https://go-review.googlesource.com/c/go/+/645136 Reviewed-by: Michael Pratt Auto-Submit: Michael Knyszek LUCI-TryBot-Result: Go LUCI --- src/internal/trace/tracev2/EXPERIMENTS.md | 101 ++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 src/internal/trace/tracev2/EXPERIMENTS.md diff --git a/src/internal/trace/tracev2/EXPERIMENTS.md b/src/internal/trace/tracev2/EXPERIMENTS.md new file mode 100644 index 00000000000000..fedf7bdbdc8db7 --- /dev/null +++ b/src/internal/trace/tracev2/EXPERIMENTS.md @@ -0,0 +1,101 @@ +# Trace experiments + +Execution traces allow for trialing new events on an experimental basis via +trace experiments. +This document is a guide that explains how you can define your own trace +experiments. + +Note that if you're just trying to do some debugging or perform some light +instrumentation, then a trace experiment is way overkill. +Use `runtime/trace.Log` instead. +Even if you're just trying to create a proof-of-concept for a low-frequency +event, `runtime/trace.Log` will probably be easier overall if you can make +it work. + +Consider a trace experiment if: +- The volume of new trace events will be relatively high, and so the events + would benefit from a more compact representation (creating new tables to + deduplicate data, taking advantage of the varint representation, etc.). +- It's not safe to call `runtime/trace.Log` (or its runtime equivalent) in + the contexts you want to generate an event (for example, for events about + timers). + +## Defining a new experiment + +To define a new experiment, modify `internal/trace/tracev2` to define a +new `Experiment` enum value. + +An experiment consists of two parts: timed events and experimental batches. +Timed events are events like any other and follow the same format. +They are easier to order and require less work to make use of. +Experimental batches are essentially bags of bytes that correspond to +an entire trace generation. +What they contain and how they're interpreted is totally up to you, but +they're most often useful for tables that your other events can refer into. +For example, the AllocFree experiment uses them to store type information +that allocation events can refer to. + +### Defining new events + +1. Define your new experiment event types (by convention, experimental events + types start at ID 127, so look for the `const` block defining events + starting there). +2. Describe your new events in `specs`. + Use the documentation for `Spec` to write your new specs, and check your + work by running the tests in the `internal/trace/tracev2` package. + If you wish for your event argument to be interpreted in a particular + way, follow the naming convention in + `src/internal/trace/tracev2/spec.go`. + For example, if you intend to emit a string argument, make sure the + argument name has the suffix `string`. +3. Add ordering and validation logic for your new events to + `src/internal/trace/order.go` by listing handlers for those events in + the `orderingDispatch` table. + If your events are always emitted in a regular user goroutine context, + then the handler should be trivial and just validate the scheduling + context to match userGoReqs. + If it's more complicated, see `(*ordering).advanceAllocFree` for a + slightly more complicated example that handles events from a larger + variety of execution environments. + If you need to encode a partial ordering, look toward the scheduler + events (names beginning with `Go`) or just ask someone for help. +4. Add your new events to the `tracev2Type2Kind` table in + `src/internal/trace/event.go`. + +## Emitting data + +### Emitting your new events + +1. Define helper methods on `runtime.traceEventWriter` for emitting your + events. +2. Instrument the runtime with calls to these helper methods. + Make sure to call `traceAcquire` and `traceRelease` around the operation + your event represents, otherwise it will not be emitted atomically with + that operation completing, resulting in a potentially misleading trace. + +### Emitting experimental batches + +To emit experimental batches, use the `runtime.unsafeTraceExpWriter` to +write experimental batches associated with your experiment. +Heed the warnings and make sure that while you write them, the trace +generation cannot advance. +Note that each experiment can only have one distinguishable set of +batches. + +## Recovering experimental data + +### Recovering experimental events from the trace + +Experimental events will appear in the event stream as an event with the +`EventExperimental` `Kind`. +Use the `Experimental` method to collect the raw data inserted into the +trace. +It's essentially up to you to interpret the event from here. +I recommend writing a thin wrapper API to present a cleaner interface if you +so desire. + +### Recovering experimental batches + +Parse out all the experimental batches from `Sync` events as they come. +These experimental batches are all for the same generation as all the +experimental events up until the next `Sync` event. From 8c6fec6d25e7c83780d8b020e3e4f81051645d65 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Sat, 1 Feb 2025 05:51:33 +0000 Subject: [PATCH 326/397] runtime: update HACKING.md with execution traces and debuglog Change-Id: Iedd3c6f292ad76f57c6c04beafd655e2e4d83043 Reviewed-on: https://go-review.googlesource.com/c/go/+/646017 LUCI-TryBot-Result: Go LUCI Reviewed-by: Michael Pratt Auto-Submit: Michael Knyszek --- src/runtime/HACKING.md | 66 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/src/runtime/HACKING.md b/src/runtime/HACKING.md index f0c60f3af9e131..141fae9914afd5 100644 --- a/src/runtime/HACKING.md +++ b/src/runtime/HACKING.md @@ -330,3 +330,69 @@ transitive calls) to prevent stack growth. The conversion from pointer to uintptr must appear in the argument list of any call to this function. This directive is used for some low-level system call implementations. + +Execution tracer +================ + +The execution tracer is a way for users to see what their goroutines are doing, +but they're also useful for runtime hacking. + +Using execution traces to debug runtime problems +------------------------------------------------ + +Execution traces contain a wealth of information about what the runtime is +doing. They contain all goroutine scheduling actions, data about time spent in +the scheduler (P running without a G), data about time spent in the garbage +collector, and more. Use `go tool trace` or [gotraceui](https://gotraceui.dev) +to inspect traces. + +Traces are especially useful for debugging latency issues, and especially if you +can catch the problem in the act. Consider using the flight recorder to help +with this. + +Turn on CPU profiling when you take a trace. This will put the CPU profiling +samples as timestamped events into the trace, allowing you to see execution with +greater detail. If you see CPU profiling sample events appear at a rate that does +not match the sample rate, consider that the OS or platform might be taking away +CPU time from the process, and that you might not be debugging a Go issue. + +If you're really stuck on a problem, adding new instrumentation with the tracer +might help, especially if it's helpful to see events in relation to other +scheduling events. See the next section on modifying the execution tracer. +However, consider using `debuglog` for additional instrumentation first, as that +is far easier to get started with. + +Notes on modifying the execution tracer +--------------------------------------- + +The execution tracer lives in the files whose names start with "trace." +The parser for the execution trace format lives in the `internal/trace` package. + +If you plan on adding new trace events, consider starting with a [trace +experiment](../internal/trace/tracev2/EXPERIMENTS.md). + +If you plan to add new trace instrumentation to the runtime, wrap whatever operation +you're tracing in `traceAcquire` and `traceRelease` fully. These functions mark a +critical section that appears atomic to the execution tracer (but nothing else). + +debuglog +======== + +`debuglog` is a powerful runtime-only debugging tool. Think of it as an +ultra-low-overhead `println` that works just about anywhere in the runtime. +These properties are invaluable when debugging subtle problems in tricky parts +of the codebase. `println` can often perturb code enough to stop data races from +happening, while `debuglog` perturbs execution far less. + +`debuglog` accumulates log messages in a ring buffer on each M, and dumps out +the contents, ordering it by timestamp, on certain kinds of crashes. Some messages +might be lost if the ring buffer gets full, in which case consider increasing the +size, or just work with a partial log. + +1. Add `debuglog` instrumentation to the runtime. Don't forget to call `end`! + Example: `dlog().s("hello world").u32(5).end()` +2. By default, `debuglog` only dumps its contents in certain kinds of crashes. + Consider adding more calls to `printDebugLog` if you're not getting any output. +3. Build the program you wish to debug with the `debuglog` build tag. + +`debuglog` is lower level than execution traces, and much easier to set up. From 11c642c2d33ebc5a76c2579d81b24c2d0e10e38f Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Tue, 14 Jan 2025 14:56:20 -0500 Subject: [PATCH 327/397] crypto/internal/fips140test: add OneStepNoCounter ACVP tests Adds ACVP test coverage for the SP 800-56Crev2 IG D.P KDA OneStepNoCounter mode algorithm based on the NIST spec: https://pages.nist.gov/ACVP/draft-hammett-acvp-kas-kdf-onestepnocounter.html Coverage is added for all SHA2 and SHA3 HMACs. Updates #69642 Change-Id: I337bf824a71fce6c796a1440b7f08c4f5413d92f Reviewed-on: https://go-review.googlesource.com/c/go/+/648435 Reviewed-by: Roland Shoemaker Reviewed-by: Dmitri Shuralyov LUCI-TryBot-Result: Go LUCI Auto-Submit: Roland Shoemaker --- .../fips140test/acvp_capabilities.json | 1 + src/crypto/internal/fips140test/acvp_test.go | 45 ++++++++++++++++++- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/crypto/internal/fips140test/acvp_capabilities.json b/src/crypto/internal/fips140test/acvp_capabilities.json index 90e77ec8fa38d4..c7157793700949 100644 --- a/src/crypto/internal/fips140test/acvp_capabilities.json +++ b/src/crypto/internal/fips140test/acvp_capabilities.json @@ -27,6 +27,7 @@ {"algorithm":"HMAC-SHA3-512","keyLen":[{"increment":8,"max":524288,"min":8}],"macLen":[{"increment":8,"max":512,"min":32}],"revision":"1.0"}, {"algorithm":"KDA","mode":"HKDF","revision":"Sp800-56Cr1","fixedInfoPattern":"uPartyInfo||vPartyInfo","encoding":["concatenation"],"hmacAlg":["SHA2-224","SHA2-256","SHA2-384","SHA2-512","SHA2-512/224","SHA2-512/256","SHA3-224","SHA3-256","SHA3-384","SHA3-512"],"macSaltMethods":["default","random"],"l":2048,"z":[{"min":224,"max":65336,"increment":8}]}, + {"algorithm":"KDA","mode":"OneStepNoCounter","revision":"Sp800-56Cr2","auxFunctions":[{"auxFunctionName":"HMAC-SHA2-224","l":224,"macSaltMethods":["default","random"]},{"auxFunctionName":"HMAC-SHA2-256","l":256,"macSaltMethods":["default","random"]},{"auxFunctionName":"HMAC-SHA2-384","l":384,"macSaltMethods":["default","random"]},{"auxFunctionName":"HMAC-SHA2-512","l":512,"macSaltMethods":["default","random"]},{"auxFunctionName":"HMAC-SHA2-512/224","l":224,"macSaltMethods":["default","random"]},{"auxFunctionName":"HMAC-SHA2-512/256","l":256,"macSaltMethods":["default","random"]},{"auxFunctionName":"HMAC-SHA3-224","l":224,"macSaltMethods":["default","random"]},{"auxFunctionName":"HMAC-SHA3-256","l":256,"macSaltMethods":["default","random"]},{"auxFunctionName":"HMAC-SHA3-384","l":384,"macSaltMethods":["default","random"]},{"auxFunctionName":"HMAC-SHA3-512","l":512,"macSaltMethods":["default","random"]}],"fixedInfoPattern":"uPartyInfo||vPartyInfo","encoding":["concatenation"],"z":[{"min":224,"max":65336,"increment":8}]}, {"algorithm":"PBKDF","capabilities":[{"iterationCount":[{"min":1,"max":10000,"increment":1}],"keyLen":[{"min":112,"max":4096,"increment":8}],"passwordLen":[{"min":8,"max":64,"increment":1}],"saltLen":[{"min":128,"max":512,"increment":8}],"hmacAlg":["SHA2-224","SHA2-256","SHA2-384","SHA2-512","SHA2-512/224","SHA2-512/256","SHA3-224","SHA3-256","SHA3-384","SHA3-512"]}],"revision":"1.0"}, diff --git a/src/crypto/internal/fips140test/acvp_test.go b/src/crypto/internal/fips140test/acvp_test.go index 5d16e521f9ce3f..697bfd06087d34 100644 --- a/src/crypto/internal/fips140test/acvp_test.go +++ b/src/crypto/internal/fips140test/acvp_test.go @@ -121,6 +121,8 @@ var ( // https://pages.nist.gov/ACVP/draft-celi-acvp-symmetric.html#section-7.3 // HKDF KDA algorithm capabilities: // https://pages.nist.gov/ACVP/draft-hammett-acvp-kas-kdf-hkdf.html#section-7.3 + // OneStepNoCounter KDA algorithm capabilities: + // https://pages.nist.gov/ACVP/draft-hammett-acvp-kas-kdf-onestepnocounter.html#section-7.2 // TLS 1.2 KDF algorithm capabilities: // https://pages.nist.gov/ACVP/draft-celi-acvp-kdf-tls.html#section-7.2 // TLS 1.3 KDF algorithm capabilities: @@ -294,6 +296,17 @@ var ( "KDF-counter": cmdKdfCounterAft(), "KDF-feedback": cmdKdfFeedbackAft(), + + "OneStepNoCounter/HMAC-SHA2-224": cmdOneStepNoCounterHmacAft(func() fips140.Hash { return sha256.New224() }), + "OneStepNoCounter/HMAC-SHA2-256": cmdOneStepNoCounterHmacAft(func() fips140.Hash { return sha256.New() }), + "OneStepNoCounter/HMAC-SHA2-384": cmdOneStepNoCounterHmacAft(func() fips140.Hash { return sha512.New384() }), + "OneStepNoCounter/HMAC-SHA2-512": cmdOneStepNoCounterHmacAft(func() fips140.Hash { return sha512.New() }), + "OneStepNoCounter/HMAC-SHA2-512/224": cmdOneStepNoCounterHmacAft(func() fips140.Hash { return sha512.New512_224() }), + "OneStepNoCounter/HMAC-SHA2-512/256": cmdOneStepNoCounterHmacAft(func() fips140.Hash { return sha512.New512_256() }), + "OneStepNoCounter/HMAC-SHA3-224": cmdOneStepNoCounterHmacAft(func() fips140.Hash { return sha3.New224() }), + "OneStepNoCounter/HMAC-SHA3-256": cmdOneStepNoCounterHmacAft(func() fips140.Hash { return sha3.New256() }), + "OneStepNoCounter/HMAC-SHA3-384": cmdOneStepNoCounterHmacAft(func() fips140.Hash { return sha3.New384() }), + "OneStepNoCounter/HMAC-SHA3-512": cmdOneStepNoCounterHmacAft(func() fips140.Hash { return sha3.New512() }), } ) @@ -1829,14 +1842,42 @@ func getRSAKey(bits int) (*rsa.PrivateKey, error) { return key, nil } +func cmdOneStepNoCounterHmacAft(h func() fips140.Hash) command { + return command{ + requiredArgs: 4, // key, info, salt, outBytes + handler: func(args [][]byte) ([][]byte, error) { + key := args[0] + info := args[1] + salt := args[2] + outBytes := binary.LittleEndian.Uint32(args[3]) + + mac := hmac.New(h, salt) + mac.Size() + + if outBytes != uint32(mac.Size()) { + return nil, fmt.Errorf("invalid output length: got %d, want %d", outBytes, mac.Size()) + } + + data := make([]byte, 0, len(key)+len(info)) + data = append(data, key...) + data = append(data, info...) + + mac.Write(data) + out := mac.Sum(nil) + + return [][]byte{out}, nil + }, + } +} + func TestACVP(t *testing.T) { testenv.SkipIfShortAndSlow(t) const ( bsslModule = "boringssl.googlesource.com/boringssl.git" - bsslVersion = "v0.0.0-20250123161947-ba24bde161f7" + bsslVersion = "v0.0.0-20250207174145-0bb19f6126cb" goAcvpModule = "github.com/cpu/go-acvp" - goAcvpVersion = "v0.0.0-20250110181646-e47fea3b5d7d" + goAcvpVersion = "v0.0.0-20250117180340-0406d83a4b0d" ) // In crypto/tls/bogo_shim_test.go the test is skipped if run on a builder with runtime.GOOS == "windows" From 102406edbfff616ad5a56df5e7347ae97804ea58 Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Wed, 22 Jan 2025 14:49:46 -0500 Subject: [PATCH 328/397] crypto/internal/fips140test: add KTS-IFC ACVP tests Adds ACVP test coverage for the SP 800-56Brev2 KTS-OAEP-basic algorithm based on the NIST spec: https://pages.nist.gov/ACVP/draft-hammett-acvp-kas-ifc.html Change-Id: I31240af30a73ee9f0ef00f47129738860378ea8f Reviewed-on: https://go-review.googlesource.com/c/go/+/648436 Reviewed-by: Dmitri Shuralyov Reviewed-by: Roland Shoemaker Auto-Submit: Roland Shoemaker LUCI-TryBot-Result: Go LUCI --- .../fips140test/acvp_capabilities.json | 4 +- src/crypto/internal/fips140test/acvp_test.go | 96 +++++++++++++++++++ 2 files changed, 99 insertions(+), 1 deletion(-) diff --git a/src/crypto/internal/fips140test/acvp_capabilities.json b/src/crypto/internal/fips140test/acvp_capabilities.json index c7157793700949..b7fa63f75ef103 100644 --- a/src/crypto/internal/fips140test/acvp_capabilities.json +++ b/src/crypto/internal/fips140test/acvp_capabilities.json @@ -74,5 +74,7 @@ {"algorithm":"RSA","mode":"keyGen","revision":"FIPS186-5","infoGeneratedByServer":true,"pubExpMode":"fixed","fixedPubExp":"010001","keyFormat":"standard","capabilities":[{"randPQ":"probable","properties":[{"modulo":2048,"primeTest":["2powSecStr"]},{"modulo":3072,"primeTest":["2powSecStr"]},{"modulo":4096,"primeTest":["2powSecStr"]}]}]}, {"algorithm":"RSA","mode":"sigGen","revision":"FIPS186-5","capabilities":[{"sigType":"pkcs1v1.5","properties":[{"modulo":2048,"hashPair":[{"hashAlg":"SHA2-224"},{"hashAlg":"SHA2-256"},{"hashAlg":"SHA2-384"},{"hashAlg":"SHA2-512"}]},{"modulo":3072,"hashPair":[{"hashAlg":"SHA2-224"},{"hashAlg":"SHA2-256"},{"hashAlg":"SHA2-384"},{"hashAlg":"SHA2-512"}]},{"modulo":4096,"hashPair":[{"hashAlg":"SHA2-224"},{"hashAlg":"SHA2-256"},{"hashAlg":"SHA2-384"},{"hashAlg":"SHA2-512"}]}]},{"sigType":"pss","properties":[{"maskFunction":["mgf1"],"modulo":2048,"hashPair":[{"hashAlg":"SHA2-224","saltLen":28},{"hashAlg":"SHA2-256","saltLen":32},{"hashAlg":"SHA2-384","saltLen":48},{"hashAlg":"SHA2-512","saltLen":64}]},{"maskFunction":["mgf1"],"modulo":3072,"hashPair":[{"hashAlg":"SHA2-224","saltLen":28},{"hashAlg":"SHA2-256","saltLen":32},{"hashAlg":"SHA2-384","saltLen":48},{"hashAlg":"SHA2-512","saltLen":64}]},{"maskFunction":["mgf1"],"modulo":4096,"hashPair":[{"hashAlg":"SHA2-224","saltLen":28},{"hashAlg":"SHA2-256","saltLen":32},{"hashAlg":"SHA2-384","saltLen":48},{"hashAlg":"SHA2-512","saltLen":64}]}]}]}, - {"algorithm":"RSA","mode":"sigVer","revision":"FIPS186-5","pubExpMode":"fixed","fixedPubExp":"010001","capabilities":[{"sigType":"pkcs1v1.5","properties":[{"modulo":2048,"hashPair":[{"hashAlg":"SHA2-224"},{"hashAlg":"SHA2-256"},{"hashAlg":"SHA2-384"},{"hashAlg":"SHA2-512"}]}]},{"sigType":"pkcs1v1.5","properties":[{"modulo":3072,"hashPair":[{"hashAlg":"SHA2-224"},{"hashAlg":"SHA2-256"},{"hashAlg":"SHA2-384"},{"hashAlg":"SHA2-512"}]}]},{"sigType":"pkcs1v1.5","properties":[{"modulo":4096,"hashPair":[{"hashAlg":"SHA2-224"},{"hashAlg":"SHA2-256"},{"hashAlg":"SHA2-384"},{"hashAlg":"SHA2-512"}]}]},{"sigType":"pss","properties":[{"maskFunction":["mgf1"],"modulo":2048,"hashPair":[{"hashAlg":"SHA2-224","saltLen":28},{"hashAlg":"SHA2-256","saltLen":32},{"hashAlg":"SHA2-384","saltLen":48},{"hashAlg":"SHA2-512","saltLen":64}]}]},{"sigType":"pss","properties":[{"maskFunction":["mgf1"],"modulo":3072,"hashPair":[{"hashAlg":"SHA2-224","saltLen":28},{"hashAlg":"SHA2-256","saltLen":32},{"hashAlg":"SHA2-384","saltLen":48},{"hashAlg":"SHA2-512","saltLen":64}]}]},{"sigType":"pss","properties":[{"maskFunction":["mgf1"],"modulo":4096,"hashPair":[{"hashAlg":"SHA2-224","saltLen":28},{"hashAlg":"SHA2-256","saltLen":32},{"hashAlg":"SHA2-384","saltLen":48},{"hashAlg":"SHA2-512","saltLen":64}]}]}]} + {"algorithm":"RSA","mode":"sigVer","revision":"FIPS186-5","pubExpMode":"fixed","fixedPubExp":"010001","capabilities":[{"sigType":"pkcs1v1.5","properties":[{"modulo":2048,"hashPair":[{"hashAlg":"SHA2-224"},{"hashAlg":"SHA2-256"},{"hashAlg":"SHA2-384"},{"hashAlg":"SHA2-512"}]}]},{"sigType":"pkcs1v1.5","properties":[{"modulo":3072,"hashPair":[{"hashAlg":"SHA2-224"},{"hashAlg":"SHA2-256"},{"hashAlg":"SHA2-384"},{"hashAlg":"SHA2-512"}]}]},{"sigType":"pkcs1v1.5","properties":[{"modulo":4096,"hashPair":[{"hashAlg":"SHA2-224"},{"hashAlg":"SHA2-256"},{"hashAlg":"SHA2-384"},{"hashAlg":"SHA2-512"}]}]},{"sigType":"pss","properties":[{"maskFunction":["mgf1"],"modulo":2048,"hashPair":[{"hashAlg":"SHA2-224","saltLen":28},{"hashAlg":"SHA2-256","saltLen":32},{"hashAlg":"SHA2-384","saltLen":48},{"hashAlg":"SHA2-512","saltLen":64}]}]},{"sigType":"pss","properties":[{"maskFunction":["mgf1"],"modulo":3072,"hashPair":[{"hashAlg":"SHA2-224","saltLen":28},{"hashAlg":"SHA2-256","saltLen":32},{"hashAlg":"SHA2-384","saltLen":48},{"hashAlg":"SHA2-512","saltLen":64}]}]},{"sigType":"pss","properties":[{"maskFunction":["mgf1"],"modulo":4096,"hashPair":[{"hashAlg":"SHA2-224","saltLen":28},{"hashAlg":"SHA2-256","saltLen":32},{"hashAlg":"SHA2-384","saltLen":48},{"hashAlg":"SHA2-512","saltLen":64}]}]}]}, + + {"algorithm":"KTS-IFC","revision":"Sp800-56Br2","fixedPubExp":"010001","iutId":"C0FFEE","modulo":[2048,3072,4096],"keyGenerationMethods":["rsakpg1-basic"],"scheme":{"KTS-OAEP-basic":{"l":1024,"kasRole":["responder","initiator"],"ktsMethod":{"hashAlgs":["SHA2-224","SHA2-256","SHA2-384","SHA2-512","SHA2-512/224","SHA2-512/256","SHA3-224","SHA3-256","SHA3-384","SHA3-512"],"supportsNullAssociatedData":true,"encoding":["concatenation"]}}}} ] diff --git a/src/crypto/internal/fips140test/acvp_test.go b/src/crypto/internal/fips140test/acvp_test.go index 697bfd06087d34..b1857c892c836d 100644 --- a/src/crypto/internal/fips140test/acvp_test.go +++ b/src/crypto/internal/fips140test/acvp_test.go @@ -307,6 +307,27 @@ var ( "OneStepNoCounter/HMAC-SHA3-256": cmdOneStepNoCounterHmacAft(func() fips140.Hash { return sha3.New256() }), "OneStepNoCounter/HMAC-SHA3-384": cmdOneStepNoCounterHmacAft(func() fips140.Hash { return sha3.New384() }), "OneStepNoCounter/HMAC-SHA3-512": cmdOneStepNoCounterHmacAft(func() fips140.Hash { return sha3.New512() }), + + "KTS-IFC/SHA2-224/initiator": cmdKtsIfcInitiatorAft(func() fips140.Hash { return sha256.New224() }), + "KTS-IFC/SHA2-224/responder": cmdKtsIfcResponderAft(func() fips140.Hash { return sha256.New224() }), + "KTS-IFC/SHA2-256/initiator": cmdKtsIfcInitiatorAft(func() fips140.Hash { return sha256.New() }), + "KTS-IFC/SHA2-256/responder": cmdKtsIfcResponderAft(func() fips140.Hash { return sha256.New() }), + "KTS-IFC/SHA2-384/initiator": cmdKtsIfcInitiatorAft(func() fips140.Hash { return sha512.New384() }), + "KTS-IFC/SHA2-384/responder": cmdKtsIfcResponderAft(func() fips140.Hash { return sha512.New384() }), + "KTS-IFC/SHA2-512/initiator": cmdKtsIfcInitiatorAft(func() fips140.Hash { return sha512.New() }), + "KTS-IFC/SHA2-512/responder": cmdKtsIfcResponderAft(func() fips140.Hash { return sha512.New() }), + "KTS-IFC/SHA2-512/224/initiator": cmdKtsIfcInitiatorAft(func() fips140.Hash { return sha512.New512_224() }), + "KTS-IFC/SHA2-512/224/responder": cmdKtsIfcResponderAft(func() fips140.Hash { return sha512.New512_224() }), + "KTS-IFC/SHA2-512/256/initiator": cmdKtsIfcInitiatorAft(func() fips140.Hash { return sha512.New512_256() }), + "KTS-IFC/SHA2-512/256/responder": cmdKtsIfcResponderAft(func() fips140.Hash { return sha512.New512_256() }), + "KTS-IFC/SHA3-224/initiator": cmdKtsIfcInitiatorAft(func() fips140.Hash { return sha3.New224() }), + "KTS-IFC/SHA3-224/responder": cmdKtsIfcResponderAft(func() fips140.Hash { return sha3.New224() }), + "KTS-IFC/SHA3-256/initiator": cmdKtsIfcInitiatorAft(func() fips140.Hash { return sha3.New256() }), + "KTS-IFC/SHA3-256/responder": cmdKtsIfcResponderAft(func() fips140.Hash { return sha3.New256() }), + "KTS-IFC/SHA3-384/initiator": cmdKtsIfcInitiatorAft(func() fips140.Hash { return sha3.New384() }), + "KTS-IFC/SHA3-384/responder": cmdKtsIfcResponderAft(func() fips140.Hash { return sha3.New384() }), + "KTS-IFC/SHA3-512/initiator": cmdKtsIfcInitiatorAft(func() fips140.Hash { return sha3.New512() }), + "KTS-IFC/SHA3-512/responder": cmdKtsIfcResponderAft(func() fips140.Hash { return sha3.New512() }), } ) @@ -1870,6 +1891,81 @@ func cmdOneStepNoCounterHmacAft(h func() fips140.Hash) command { } } +func cmdKtsIfcInitiatorAft(h func() fips140.Hash) command { + return command{ + requiredArgs: 3, // output bytes, n bytes, e bytes + handler: func(args [][]byte) ([][]byte, error) { + outputBytes := binary.LittleEndian.Uint32(args[0]) + nBytes := args[1] + eBytes := args[2] + + n, err := bigmod.NewModulus(nBytes) + if err != nil { + return nil, fmt.Errorf("invalid RSA modulus: %w", err) + } + + paddedE := make([]byte, 4) + copy(paddedE[4-len(eBytes):], eBytes) + e := int(binary.BigEndian.Uint32(paddedE)) + if e != 0x10001 { + return nil, errors.New("e must be 0x10001") + } + + pub := &rsa.PublicKey{ + N: n, + E: e, + } + + dkm := make([]byte, outputBytes) + if _, err := rand.Read(dkm); err != nil { + return nil, fmt.Errorf("failed to generate random DKM: %v", err) + } + + iutC, err := rsa.EncryptOAEP(h(), h(), rand.Reader, pub, dkm, nil) + if err != nil { + return nil, fmt.Errorf("OAEP encryption failed: %v", err) + } + + return [][]byte{iutC, dkm}, nil + }, + } +} + +func cmdKtsIfcResponderAft(h func() fips140.Hash) command { + return command{ + requiredArgs: 6, // n bytes, e bytes, p bytes, q bytes, d bytes, c bytes + handler: func(args [][]byte) ([][]byte, error) { + nBytes := args[0] + eBytes := args[1] + + pBytes := args[2] + qBytes := args[3] + dBytes := args[4] + + cBytes := args[5] + + paddedE := make([]byte, 4) + copy(paddedE[4-len(eBytes):], eBytes) + e := int(binary.BigEndian.Uint32(paddedE)) + if e != 0x10001 { + return nil, errors.New("e must be 0x10001") + } + + priv, err := rsa.NewPrivateKey(nBytes, int(e), dBytes, pBytes, qBytes) + if err != nil { + return nil, fmt.Errorf("failed to create private key: %v", err) + } + + dkm, err := rsa.DecryptOAEP(h(), h(), priv, cBytes, nil) + if err != nil { + return nil, fmt.Errorf("OAEP decryption failed: %v", err) + } + + return [][]byte{dkm}, nil + }, + } +} + func TestACVP(t *testing.T) { testenv.SkipIfShortAndSlow(t) From b941d2b6d8bd9663abec7761de366b09a2be7445 Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Thu, 23 Jan 2025 14:34:46 -0500 Subject: [PATCH 329/397] crypto/internal/fips140test: add cSHAKE ACVP tests Adds ACVP test coverage for the SP 800-185 cSHAKE-128 and cSHAKE-256 algorithms based on the NIST spec: https://pages.nist.gov/ACVP/draft-celi-acvp-xof.html Updates #69642 Change-Id: I4a6ef9a99dfe520f3177e0e7c258326475690f5f Reviewed-on: https://go-review.googlesource.com/c/go/+/648455 LUCI-TryBot-Result: Go LUCI Reviewed-by: Roland Shoemaker Auto-Submit: Roland Shoemaker Reviewed-by: Dmitri Shuralyov --- .../fips140test/acvp_capabilities.json | 2 + .../fips140test/acvp_test.config.json | 2 + src/crypto/internal/fips140test/acvp_test.go | 93 ++++++++++++++++++- 3 files changed, 96 insertions(+), 1 deletion(-) diff --git a/src/crypto/internal/fips140test/acvp_capabilities.json b/src/crypto/internal/fips140test/acvp_capabilities.json index b7fa63f75ef103..b2007438ec1f4f 100644 --- a/src/crypto/internal/fips140test/acvp_capabilities.json +++ b/src/crypto/internal/fips140test/acvp_capabilities.json @@ -13,6 +13,8 @@ {"algorithm":"SHAKE-128","inBit":false,"outBit":false,"inEmpty":true,"outputLen":[{"min":16,"max":65536,"increment":8}],"revision":"1.0"}, {"algorithm":"SHAKE-256","inBit":false,"outBit":false,"inEmpty":true,"outputLen":[{"min":16,"max":65536,"increment":8}],"revision":"1.0"}, + {"algorithm":"cSHAKE-128","hexCustomization":false,"outputLen":[{"min":16,"max":65536,"increment":8}],"msgLen":[{"min":0,"max":65536,"increment":8}],"revision":"1.0"}, + {"algorithm":"cSHAKE-256","hexCustomization":false,"outputLen":[{"min":16,"max":65536,"increment":8}],"msgLen":[{"min":0,"max":65536,"increment":8}],"revision":"1.0"}, {"algorithm":"HMAC-SHA2-224","keyLen":[{"increment":8,"max":524288,"min":8}],"macLen":[{"increment":8,"max":224,"min":32}],"revision":"1.0"}, {"algorithm":"HMAC-SHA2-256","keyLen":[{"increment":8,"max":524288,"min":8}],"macLen":[{"increment":8,"max":256,"min":32}],"revision":"1.0"}, diff --git a/src/crypto/internal/fips140test/acvp_test.config.json b/src/crypto/internal/fips140test/acvp_test.config.json index 2f905e0870376e..e14a28126715f3 100644 --- a/src/crypto/internal/fips140test/acvp_test.config.json +++ b/src/crypto/internal/fips140test/acvp_test.config.json @@ -13,6 +13,8 @@ {"Wrapper": "go", "In": "vectors/SHAKE-128.bz2", "Out": "expected/SHAKE-128.bz2"}, {"Wrapper": "go", "In": "vectors/SHAKE-256.bz2", "Out": "expected/SHAKE-256.bz2"}, + {"Wrapper": "go", "In": "vectors/cSHAKE-128.bz2", "Out": "expected/cSHAKE-128.bz2"}, + {"Wrapper": "go", "In": "vectors/cSHAKE-256.bz2", "Out": "expected/cSHAKE-256.bz2"}, {"Wrapper": "go", "In": "vectors/HMAC-SHA2-224.bz2", "Out": "expected/HMAC-SHA2-224.bz2"}, {"Wrapper": "go", "In": "vectors/HMAC-SHA2-256.bz2", "Out": "expected/HMAC-SHA2-256.bz2"}, diff --git a/src/crypto/internal/fips140test/acvp_test.go b/src/crypto/internal/fips140test/acvp_test.go index b1857c892c836d..f25f3d4f0f7cbe 100644 --- a/src/crypto/internal/fips140test/acvp_test.go +++ b/src/crypto/internal/fips140test/acvp_test.go @@ -105,6 +105,8 @@ var ( // https://pages.nist.gov/ACVP/draft-celi-acvp-sha.html#section-7.2 // SHA3 and SHAKE algorithm capabilities: // https://pages.nist.gov/ACVP/draft-celi-acvp-sha3.html#name-sha3-and-shake-algorithm-ca + // cSHAKE algorithm capabilities: + // https://pages.nist.gov/ACVP/draft-celi-acvp-xof.html#section-7.2 // HMAC algorithm capabilities: // https://pages.nist.gov/ACVP/draft-fussell-acvp-mac.html#section-7 // PBKDF2 algorithm capabilities: @@ -179,6 +181,11 @@ var ( "SHAKE-256/VOT": cmdShakeAftVot(sha3.NewShake256()), "SHAKE-256/MCT": cmdShakeMct(sha3.NewShake256()), + "cSHAKE-128": cmdCShakeAft(func(N, S []byte) *sha3.SHAKE { return sha3.NewCShake128(N, S) }), + "cSHAKE-128/MCT": cmdCShakeMct(func(N, S []byte) *sha3.SHAKE { return sha3.NewCShake128(N, S) }), + "cSHAKE-256": cmdCShakeAft(func(N, S []byte) *sha3.SHAKE { return sha3.NewCShake256(N, S) }), + "cSHAKE-256/MCT": cmdCShakeMct(func(N, S []byte) *sha3.SHAKE { return sha3.NewCShake256(N, S) }), + "HMAC-SHA2-224": cmdHmacAft(func() fips140.Hash { return sha256.New224() }), "HMAC-SHA2-256": cmdHmacAft(func() fips140.Hash { return sha256.New() }), "HMAC-SHA2-384": cmdHmacAft(func() fips140.Hash { return sha512.New384() }), @@ -609,6 +616,90 @@ func cmdShakeMct(h *sha3.SHAKE) command { } } +func cmdCShakeAft(hFn func(N, S []byte) *sha3.SHAKE) command { + return command{ + requiredArgs: 4, // Message, output length bytes, function name, customization + handler: func(args [][]byte) ([][]byte, error) { + msg := args[0] + outLenBytes := binary.LittleEndian.Uint32(args[1]) + functionName := args[2] + customization := args[3] + + h := hFn(functionName, customization) + h.Write(msg) + + out := make([]byte, outLenBytes) + h.Read(out) + + return [][]byte{out}, nil + }, + } +} + +func cmdCShakeMct(hFn func(N, S []byte) *sha3.SHAKE) command { + return command{ + requiredArgs: 6, // Message, min output length (bits), max output length (bits), output length (bits), increment (bits), customization + handler: func(args [][]byte) ([][]byte, error) { + message := args[0] + minOutLenBytes := binary.LittleEndian.Uint32(args[1]) + maxOutLenBytes := binary.LittleEndian.Uint32(args[2]) + outputLenBytes := binary.LittleEndian.Uint32(args[3]) + incrementBytes := binary.LittleEndian.Uint32(args[4]) + customization := args[5] + + if outputLenBytes < 2 { + return nil, fmt.Errorf("invalid output length: %d", outputLenBytes) + } + + rangeBits := (maxOutLenBytes*8 - minOutLenBytes*8) + 1 + if rangeBits == 0 { + return nil, fmt.Errorf("invalid maxOutLenBytes and minOutLenBytes: %d, %d", maxOutLenBytes, minOutLenBytes) + } + + // cSHAKE Monte Carlo test inner loop: + // https://pages.nist.gov/ACVP/draft-celi-acvp-xof.html#section-6.2.1 + for i := 0; i < 1000; i++ { + // InnerMsg = Left(Output[i-1] || ZeroBits(128), 128); + boundary := min(len(message), 16) + innerMsg := make([]byte, 16) + copy(innerMsg, message[:boundary]) + + // Output[i] = CSHAKE(InnerMsg, OutputLen, FunctionName, Customization); + h := hFn(nil, customization) // Note: function name fixed to "" for MCT. + h.Write(innerMsg) + digest := make([]byte, outputLenBytes) + h.Read(digest) + message = digest + + // Rightmost_Output_bits = Right(Output[i], 16); + rightmostOutput := digest[outputLenBytes-2:] + // IMPORTANT: the specification says: + // NOTE: For the "Rightmost_Output_bits % Range" operation, the Rightmost_Output_bits bit string + // should be interpretted as a little endian-encoded number. + // This is **a lie**! It has to be interpreted as a big-endian number. + rightmostOutputBE := binary.BigEndian.Uint16(rightmostOutput) + + // OutputLen = MinOutLen + (floor((Rightmost_Output_bits % Range) / OutLenIncrement) * OutLenIncrement); + incrementBits := incrementBytes * 8 + outputLenBits := (minOutLenBytes * 8) + (((uint32)(rightmostOutputBE)%rangeBits)/incrementBits)*incrementBits + outputLenBytes = outputLenBits / 8 + + // Customization = BitsToString(InnerMsg || Rightmost_Output_bits); + msgWithBits := append(innerMsg, rightmostOutput...) + customization = make([]byte, len(msgWithBits)) + for i, b := range msgWithBits { + customization[i] = (b % 26) + 65 + } + } + + encodedOutputLenBytes := make([]byte, 4) + binary.LittleEndian.PutUint32(encodedOutputLenBytes, outputLenBytes) + + return [][]byte{message, encodedOutputLenBytes, customization}, nil + }, + } +} + func cmdHmacAft(h func() fips140.Hash) command { return command{ requiredArgs: 2, // Message and key @@ -1973,7 +2064,7 @@ func TestACVP(t *testing.T) { bsslModule = "boringssl.googlesource.com/boringssl.git" bsslVersion = "v0.0.0-20250207174145-0bb19f6126cb" goAcvpModule = "github.com/cpu/go-acvp" - goAcvpVersion = "v0.0.0-20250117180340-0406d83a4b0d" + goAcvpVersion = "v0.0.0-20250126154732-de1ba727a0be" ) // In crypto/tls/bogo_shim_test.go the test is skipped if run on a builder with runtime.GOOS == "windows" From 30f515898c9852f0529fe42b46c8b89d00e14949 Mon Sep 17 00:00:00 2001 From: qmuntal Date: Tue, 11 Feb 2025 18:23:11 +0000 Subject: [PATCH 330/397] make.bat,race.bat: simplify --dist-tool handling make.bat accepts the --dist-tool flag on multiple flag positions and also allows omitting the trailing dash. Doing so adds complexity and is not aligned with the make.bash and make.rc behavior. Remove that flexibility to simplify the code and make it more consistent. This also fixes a bug where dist.exe wouldn't be removed from cmd\dist when running make.bat --dist-tool. Also, there is no need for race.bat to invoke make.bat with --dist-tool. It uses it to get the GOHOSTARCH env value, but we can already get that from the built-in PROCESSOR_ARCHITECTURE env variable. Change-Id: Ia673562c1ae6aff9bd3ec7aa8cdd25ff187eeb79 Reviewed-on: https://go-review.googlesource.com/c/go/+/648615 Reviewed-by: Damien Neil Reviewed-by: Dmitri Shuralyov LUCI-TryBot-Result: Go LUCI Reviewed-by: Cherry Mui --- src/make.bat | 21 ++++++++------------- src/race.bat | 8 +------- 2 files changed, 9 insertions(+), 20 deletions(-) diff --git a/src/make.bat b/src/make.bat index 890829131ba317..6c683230ce1714 100644 --- a/src/make.bat +++ b/src/make.bat @@ -101,14 +101,14 @@ call .\env.bat del env.bat if x%vflag==x-v echo. -if x%1==x-dist-tool goto copydist -if x%2==x-dist-tool goto copydist -if x%3==x-dist-tool goto copydist -if x%4==x-dist-tool goto copydist -if x%1==x--dist-tool goto copydist -if x%2==x--dist-tool goto copydist -if x%3==x--dist-tool goto copydist -if x%4==x--dist-tool goto copydist +if x%1==x--dist-tool ( + mkdir "%GOTOOLDIR%" 2>NUL + if not x%2==x ( + copy cmd\dist\dist.exe "%2" + ) + move cmd\dist\dist.exe "%GOTOOLDIR%\dist.exe" + goto :eof +) :: Run dist bootstrap to complete make.bash. :: Bootstrap installs a proper cmd/dist, built with the new toolchain. @@ -123,11 +123,6 @@ goto :eof :: to avoid needing three copies in three different shell languages :: (make.bash, make.bat, make.rc). -:copydist -mkdir "%GOTOOLDIR%" 2>NUL -copy cmd\dist\dist.exe "%GOTOOLDIR%\" -goto :eof - :nogoenv set GO111MODULE=off set GOENV=off diff --git a/src/race.bat b/src/race.bat index 60fcfb90c76275..206d4126eea648 100644 --- a/src/race.bat +++ b/src/race.bat @@ -14,13 +14,7 @@ if not exist make.bat ( exit /b 1 ) -set GOROOT=%CD%\.. -call .\make.bat --dist-tool >NUL || exit /b 1 -.\cmd\dist\dist.exe env -w -p >env.bat || exit /b 1 -call .\env.bat -del env.bat - -if not %GOHOSTARCH% == amd64 ( +if not "%PROCESSOR_ARCHITECTURE%"=="AMD64" ( echo Race detector is only supported on windows/amd64. exit /b 1 ) From d9cc4944ce3f36fc8fd1c63f35c206b308a3503f Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Tue, 11 Feb 2025 20:47:55 -0500 Subject: [PATCH 331/397] cmd/dist: correct gccheckmark test name The test actually runs with gccheckmark=1, not gcstoptheworld=2. Make the name match. Change-Id: If38822a3f1ef65bc92fe47b375381df49a684c1d Reviewed-on: https://go-review.googlesource.com/c/go/+/648755 Reviewed-by: Michael Knyszek LUCI-TryBot-Result: Go LUCI --- src/cmd/dist/test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index ba273d79234b3a..005e1da86a1dc2 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -762,7 +762,7 @@ func (t *tester) registerTests() { }) t.registerTest("GODEBUG=gccheckmark=1 runtime", &goTest{ - variant: "runtime:gcstoptheworld2", + variant: "runtime:gccheckmark", timeout: 300 * time.Second, short: true, env: []string{"GODEBUG=gccheckmark=1"}, From b574590c36b7ede1492239db2d55c35e8818c7a7 Mon Sep 17 00:00:00 2001 From: thepudds Date: Tue, 11 Feb 2025 12:59:54 -0500 Subject: [PATCH 332/397] cmd/go: document -modfile and other flags for 'go tool' Mention -modfile, -C, -overlay, and -modcacherw in the 'go tool' documentation. We let a reference to 'go help build' give a pointer to more detailed information. The -modfile flag in particular is newly useful with the Go 1.24 support for user-defined tools with 'go tool'. Updates #48429 Updates #33926 Updates #71663 Fixes #71502 Change-Id: Ida67df50ff774a0886733d661a40e27c2cadc0f6 Reviewed-on: https://go-review.googlesource.com/c/go/+/648577 LUCI-TryBot-Result: Go LUCI Reviewed-by: Conrad Irwin Reviewed-by: Michael Matloob Reviewed-by: Sam Thanawalla Auto-Submit: Sam Thanawalla --- src/cmd/go/alldocs.go | 7 +++++++ src/cmd/go/internal/tool/tool.go | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index 7289b5f4b1e16f..fc85995373017d 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -1953,6 +1953,13 @@ // The -n flag causes tool to print the command that would be // executed but not execute it. // +// The -modfile=file.mod build flag causes tool to use an alternate file +// instead of the go.mod in the module root directory. +// +// Tool also provides the -C, -overlay, and -modcacherw build flags. +// +// For more about build flags, see 'go help build'. +// // For more about each builtin tool command, see 'go doc cmd/'. // // # Print Go version diff --git a/src/cmd/go/internal/tool/tool.go b/src/cmd/go/internal/tool/tool.go index 64c40adab2baa9..7033eb1d9c3587 100644 --- a/src/cmd/go/internal/tool/tool.go +++ b/src/cmd/go/internal/tool/tool.go @@ -46,6 +46,13 @@ With no arguments it prints the list of known tools. The -n flag causes tool to print the command that would be executed but not execute it. +The -modfile=file.mod build flag causes tool to use an alternate file +instead of the go.mod in the module root directory. + +Tool also provides the -C, -overlay, and -modcacherw build flags. + +For more about build flags, see 'go help build'. + For more about each builtin tool command, see 'go doc cmd/'. `, } From 58834c3ee08ea85b764c7cc3318ce7a68ea92cbd Mon Sep 17 00:00:00 2001 From: Quan Tong Date: Fri, 7 Feb 2025 18:42:26 +0700 Subject: [PATCH 333/397] cmd/go: initialize req.Header when loading git credential Fixes #71604 Change-Id: I3d733a50b4451dfb571aba91a28387ba9e0614dc Reviewed-on: https://go-review.googlesource.com/c/go/+/647615 Reviewed-by: Michael Matloob Reviewed-by: Sam Thanawalla LUCI-TryBot-Result: Go LUCI Reviewed-by: Dmitri Shuralyov --- src/cmd/go/internal/auth/auth.go | 3 ++- src/cmd/go/testdata/script/goauth_git.txt | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/cmd/go/internal/auth/auth.go b/src/cmd/go/internal/auth/auth.go index 79e0d8b5e8f2f6..83c28d160c9d90 100644 --- a/src/cmd/go/internal/auth/auth.go +++ b/src/cmd/go/internal/auth/auth.go @@ -128,7 +128,8 @@ func runGoAuth(client *http.Client, res *http.Response, url string) { // If no GOAUTH command provided a credential for the given url // and an error occurred, log the error. if cfg.BuildX && url != "" { - if ok := loadCredential(&http.Request{}, url); !ok && len(cmdErrs) > 0 { + req := &http.Request{Header: make(http.Header)} + if ok := loadCredential(req, url); !ok && len(cmdErrs) > 0 { log.Printf("GOAUTH encountered errors for %s:", url) for _, err := range cmdErrs { log.Printf(" %v", err) diff --git a/src/cmd/go/testdata/script/goauth_git.txt b/src/cmd/go/testdata/script/goauth_git.txt index 4fae39aaa71040..37c9b19a045806 100644 --- a/src/cmd/go/testdata/script/goauth_git.txt +++ b/src/cmd/go/testdata/script/goauth_git.txt @@ -49,6 +49,8 @@ go get vcs-test.golang.org/auth/or401 go mod tidy go list all stdout vcs-test.golang.org/auth/or404 +# With cached credentials, re-downloading in debug mode should succeed. +go get -x vcs-test.golang.org/auth/or401 # Clearing GOAUTH credentials should result in failures. env GOAUTH='off' From a9357490919feed070e952ebc681b1a7af30aac2 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Tue, 11 Feb 2025 17:56:21 +0000 Subject: [PATCH 334/397] runtime: make TestSpuriousWakeupsNeverHangSemasleep more robust This change modifies this test (which involves an arbitrary timeout) to be a little less flaky by double-checking that our subprocess program completed even if the ticker fires and we've exceeded our timeout. The logic behind this change is that the testing goroutine might get delayed for any number of reasons, but the subprocess could still complete in time. Still, the goroutine will wake up to handle the ticker and see its over time, even though the event it was waiting for did actually happen. I can't reproduce #71548 locally, so I suspect because this test calls t.Parallel other load can delay the testing goroutine enough for this to happen (especially with GODEBUG=gccheckmark=1, which pauses everything to perform a full mark and sweep, and runtime tests love to call runtime.GC). For #71548. Change-Id: I83e86a0115f65950886b57b5af0b4a517ef5f90f Reviewed-on: https://go-review.googlesource.com/c/go/+/648576 LUCI-TryBot-Result: Go LUCI Reviewed-by: Cherry Mui Auto-Submit: Michael Knyszek Commit-Queue: Michael Knyszek --- src/runtime/semasleep_test.go | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/src/runtime/semasleep_test.go b/src/runtime/semasleep_test.go index 711d5df7352565..c891bc7e0c4671 100644 --- a/src/runtime/semasleep_test.go +++ b/src/runtime/semasleep_test.go @@ -91,10 +91,31 @@ func TestSpuriousWakeupsNeverHangSemasleep(t *testing.T) { // pthread_cond_timedwait_relative_np. ticker := time.NewTicker(200 * time.Millisecond) defer ticker.Stop() + + checkDoneErr := func(err error) { + if err != nil { + t.Fatalf("The program returned but unfortunately with an error: %v", err) + } + if time.Since(beforeStart) < 1*time.Second { + // The program was supposed to sleep for a full (monotonic) second; + // it should not return before that has elapsed. + t.Fatalf("The program stopped too quickly.") + } + } for { select { case now := <-ticker.C: if now.Sub(ready) > timeout { + // If we got paused for a long time, for example if GODEBUG=gcstoptheworld=2, + // it could be that the subprocess did actually finish and not deadlock, we + // just got stuck as runnable or our wakeup was delayed. Double-check that + // we don't have anything from doneCh before declaring failure. + select { + case err := <-doneCh: + checkDoneErr(err) + return + default: + } t.Error("Program failed to return on time and has to be killed, issue #27520 still exists") // Send SIGQUIT to get a goroutine dump. // Stop sending SIGIO so that the program can clean up and actually terminate. @@ -107,14 +128,7 @@ func TestSpuriousWakeupsNeverHangSemasleep(t *testing.T) { cmd.Process.Signal(syscall.SIGIO) case err := <-doneCh: - if err != nil { - t.Fatalf("The program returned but unfortunately with an error: %v", err) - } - if time.Since(beforeStart) < 1*time.Second { - // The program was supposed to sleep for a full (monotonic) second; - // it should not return before that has elapsed. - t.Fatalf("The program stopped too quickly.") - } + checkDoneErr(err) return } } From b1a11c54465f24d1861c3568ea3b1bb6304b450d Mon Sep 17 00:00:00 2001 From: Dmitri Shuralyov Date: Tue, 11 Feb 2025 17:59:59 -0500 Subject: [PATCH 335/397] all: update vendored dependencies [generated] The tree has opened for Go 1.25 development. This is a time to update all golang.org/x/... module versions that contribute packages to the std and cmd modules in the standard library to latest master versions. For #36905. [git-generate] go install golang.org/x/build/cmd/updatestd@latest go install golang.org/x/tools/cmd/bundle@latest updatestd -goroot=$(pwd) -branch=master # Update a cmd/vet test case. cat < Reviewed-by: Cherry Mui LUCI-TryBot-Result: Go LUCI Auto-Submit: Dmitri Shuralyov --- src/cmd/go.mod | 20 +- src/cmd/go.sum | 36 +- .../x/arch/riscv64/riscv64asm/gnu.go | 5 + .../golang.org/x/arch/x86/x86asm/tables.go | 2 +- .../golang.org/x/build/relnote/links.go | 2 +- .../golang.org/x/build/relnote/relnote.go | 3 + .../vendor/golang.org/x/mod/modfile/read.go | 5 + .../golang.org/x/sync/errgroup/errgroup.go | 1 + src/cmd/vendor/golang.org/x/sys/unix/auxv.go | 36 ++ .../golang.org/x/sys/unix/auxv_unsupported.go | 13 + .../x/sys/unix/syscall_dragonfly.go | 12 + .../golang.org/x/sys/unix/syscall_solaris.go | 87 ++++ .../golang.org/x/sys/unix/zerrors_linux.go | 20 +- .../x/sys/unix/zerrors_linux_386.go | 3 + .../x/sys/unix/zerrors_linux_amd64.go | 3 + .../x/sys/unix/zerrors_linux_arm.go | 3 + .../x/sys/unix/zerrors_linux_arm64.go | 4 + .../x/sys/unix/zerrors_linux_loong64.go | 3 + .../x/sys/unix/zerrors_linux_mips.go | 3 + .../x/sys/unix/zerrors_linux_mips64.go | 3 + .../x/sys/unix/zerrors_linux_mips64le.go | 3 + .../x/sys/unix/zerrors_linux_mipsle.go | 3 + .../x/sys/unix/zerrors_linux_ppc.go | 3 + .../x/sys/unix/zerrors_linux_ppc64.go | 3 + .../x/sys/unix/zerrors_linux_ppc64le.go | 3 + .../x/sys/unix/zerrors_linux_riscv64.go | 3 + .../x/sys/unix/zerrors_linux_s390x.go | 3 + .../x/sys/unix/zerrors_linux_sparc64.go | 3 + .../x/sys/unix/zsyscall_solaris_amd64.go | 114 ++++++ .../x/sys/unix/zsysnum_linux_386.go | 4 + .../x/sys/unix/zsysnum_linux_amd64.go | 4 + .../x/sys/unix/zsysnum_linux_arm.go | 4 + .../x/sys/unix/zsysnum_linux_arm64.go | 4 + .../x/sys/unix/zsysnum_linux_loong64.go | 4 + .../x/sys/unix/zsysnum_linux_mips.go | 4 + .../x/sys/unix/zsysnum_linux_mips64.go | 4 + .../x/sys/unix/zsysnum_linux_mips64le.go | 4 + .../x/sys/unix/zsysnum_linux_mipsle.go | 4 + .../x/sys/unix/zsysnum_linux_ppc.go | 4 + .../x/sys/unix/zsysnum_linux_ppc64.go | 4 + .../x/sys/unix/zsysnum_linux_ppc64le.go | 4 + .../x/sys/unix/zsysnum_linux_riscv64.go | 4 + .../x/sys/unix/zsysnum_linux_s390x.go | 4 + .../x/sys/unix/zsysnum_linux_sparc64.go | 4 + .../golang.org/x/sys/unix/ztypes_linux.go | 6 +- .../golang.org/x/sys/windows/dll_windows.go | 11 +- .../internal/crashmonitor/monitor.go | 113 +++++- .../golang.org/x/tools/cmd/bisect/main.go | 2 +- .../x/tools/go/analysis/analysis.go | 7 + .../x/tools/go/analysis/diagnostic.go | 4 +- .../analysis/internal/analysisflags/flags.go | 9 - .../go/analysis/passes/asmdecl/asmdecl.go | 4 +- .../tools/go/analysis/passes/assign/assign.go | 17 +- .../tools/go/analysis/passes/atomic/atomic.go | 11 +- .../x/tools/go/analysis/passes/bools/bools.go | 9 +- .../go/analysis/passes/cgocall/cgocall.go | 6 +- .../go/analysis/passes/copylock/copylock.go | 14 +- .../tools/go/analysis/passes/defers/defers.go | 7 +- .../go/analysis/passes/errorsas/errorsas.go | 10 +- .../passes/framepointer/framepointer.go | 108 ++++- .../passes/httpresponse/httpresponse.go | 12 +- .../passes/internal/analysisutil/util.go | 62 --- .../passes/loopclosure/loopclosure.go | 3 +- .../analysis/passes/lostcancel/lostcancel.go | 3 +- .../tools/go/analysis/passes/printf/printf.go | 336 +++++----------- .../x/tools/go/analysis/passes/shift/shift.go | 4 +- .../passes/sigchanyzer/sigchanyzer.go | 9 +- .../x/tools/go/analysis/passes/slog/slog.go | 7 +- .../analysis/passes/stdversion/stdversion.go | 32 +- .../analysis/passes/stringintconv/string.go | 6 +- .../go/analysis/passes/structtag/structtag.go | 2 +- .../testinggoroutine/testinggoroutine.go | 3 +- .../analysis/passes/testinggoroutine/util.go | 2 + .../x/tools/go/analysis/passes/tests/tests.go | 3 +- .../analysis/passes/timeformat/timeformat.go | 24 +- .../go/analysis/passes/unmarshal/unmarshal.go | 2 +- .../go/analysis/passes/unreachable/doc.go | 2 +- .../go/analysis/passes/unsafeptr/unsafeptr.go | 5 +- .../passes/unusedresult/unusedresult.go | 2 +- .../go/analysis/unitchecker/unitchecker.go | 33 +- .../x/tools/go/ast/inspector/inspector.go | 135 +++++-- .../x/tools/go/ast/inspector/iter.go | 4 +- .../x/tools/go/ast/inspector/typeof.go | 5 +- .../x/tools/go/ast/inspector/walk.go | 341 ++++++++++++++++ .../x/tools/go/types/typeutil/map.go | 252 +++++------- .../internal/analysisinternal/analysis.go | 363 +++++++++++------ .../x/tools/internal/astutil/edge/edge.go | 295 ++++++++++++++ .../x/tools/internal/fmtstr/parse.go | 370 ++++++++++++++++++ .../x/tools/internal/stdlib/manifest.go | 216 ++++++++++ .../x/tools/internal/typeparams/common.go | 72 ---- .../x/tools/internal/typeparams/coretype.go | 11 +- .../tools/internal/typesinternal/errorcode.go | 2 +- .../tools/internal/typesinternal/qualifier.go | 46 +++ .../x/tools/internal/typesinternal/recv.go | 3 + .../x/tools/internal/typesinternal/types.go | 6 + .../x/tools/internal/typesinternal/varkind.go | 40 ++ .../tools/internal/typesinternal/zerovalue.go | 254 ++++++++---- src/cmd/vendor/modules.txt | 20 +- src/cmd/vet/testdata/print/print.go | 4 +- src/go.mod | 10 +- src/go.sum | 16 +- src/net/http/h2_bundle.go | 17 +- src/vendor/golang.org/x/sys/cpu/cpu.go | 3 + src/vendor/golang.org/x/sys/cpu/cpu_x86.go | 21 +- src/vendor/modules.txt | 8 +- 105 files changed, 2868 insertions(+), 998 deletions(-) create mode 100644 src/cmd/vendor/golang.org/x/sys/unix/auxv.go create mode 100644 src/cmd/vendor/golang.org/x/sys/unix/auxv_unsupported.go create mode 100644 src/cmd/vendor/golang.org/x/tools/go/ast/inspector/walk.go create mode 100644 src/cmd/vendor/golang.org/x/tools/internal/astutil/edge/edge.go create mode 100644 src/cmd/vendor/golang.org/x/tools/internal/fmtstr/parse.go create mode 100644 src/cmd/vendor/golang.org/x/tools/internal/typesinternal/qualifier.go create mode 100644 src/cmd/vendor/golang.org/x/tools/internal/typesinternal/varkind.go diff --git a/src/cmd/go.mod b/src/cmd/go.mod index 9c29c3ac74d197..5f4e4186160dd1 100644 --- a/src/cmd/go.mod +++ b/src/cmd/go.mod @@ -1,21 +1,21 @@ module cmd -go 1.24 +go 1.25 require ( github.com/google/pprof v0.0.0-20241101162523-b92577c0c142 - golang.org/x/arch v0.12.0 - golang.org/x/build v0.0.0-20241205234318-b850320af2a4 - golang.org/x/mod v0.22.0 - golang.org/x/sync v0.10.0 - golang.org/x/sys v0.28.0 - golang.org/x/telemetry v0.0.0-20241204182053-c0ac0e154df3 - golang.org/x/term v0.27.0 - golang.org/x/tools v0.28.1-0.20250131145412-98746475647e + golang.org/x/arch v0.14.0 + golang.org/x/build v0.0.0-20250211223606-a5e3f75caa63 + golang.org/x/mod v0.23.0 + golang.org/x/sync v0.11.0 + golang.org/x/sys v0.30.0 + golang.org/x/telemetry v0.0.0-20250212145848-75305293b65a + golang.org/x/term v0.29.0 + golang.org/x/tools v0.30.1-0.20250212161021-f9aad7054b5f ) require ( github.com/ianlancetaylor/demangle v0.0.0-20240912202439-0a2b6291aafd // indirect - golang.org/x/text v0.21.0 // indirect + golang.org/x/text v0.22.0 // indirect rsc.io/markdown v0.0.0-20240306144322-0bf8f97ee8ef // indirect ) diff --git a/src/cmd/go.sum b/src/cmd/go.sum index 593063a9daa351..75299131f6a996 100644 --- a/src/cmd/go.sum +++ b/src/cmd/go.sum @@ -6,23 +6,23 @@ github.com/ianlancetaylor/demangle v0.0.0-20240912202439-0a2b6291aafd h1:EVX1s+X github.com/ianlancetaylor/demangle v0.0.0-20240912202439-0a2b6291aafd/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw= github.com/yuin/goldmark v1.6.0 h1:boZcn2GTjpsynOsC0iJHnBWa4Bi0qzfJjthwauItG68= github.com/yuin/goldmark v1.6.0/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -golang.org/x/arch v0.12.0 h1:UsYJhbzPYGsT0HbEdmYcqtCv8UNGvnaL561NnIUvaKg= -golang.org/x/arch v0.12.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= -golang.org/x/build v0.0.0-20241205234318-b850320af2a4 h1:ri5CIHQTJCd3jd0Jez97HiPE+VMT0hFNKqLHn2EjrXk= -golang.org/x/build v0.0.0-20241205234318-b850320af2a4/go.mod h1:9O1P9bdbWH7KXtcbo+6amI/59H5mNq7+CTE1eKqNsjg= -golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= -golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= -golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/telemetry v0.0.0-20241204182053-c0ac0e154df3 h1:rCLsPBq7l0E9Z451UgkWFkaWYhgt7dGmAlpD6hLjK5I= -golang.org/x/telemetry v0.0.0-20241204182053-c0ac0e154df3/go.mod h1:8h4Hgq+jcTvCDv2+i7NrfWwpYHcESleo2nGHxLbFLJ4= -golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= -golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -golang.org/x/tools v0.28.1-0.20250131145412-98746475647e h1:6Kzwg7JxW2HRWToKpIKqlpF8l8XMasoALX3OcAMdgL8= -golang.org/x/tools v0.28.1-0.20250131145412-98746475647e/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw= +golang.org/x/arch v0.14.0 h1:z9JUEZWr8x4rR0OU6c4/4t6E6jOZ8/QBS2bBYBm4tx4= +golang.org/x/arch v0.14.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= +golang.org/x/build v0.0.0-20250211223606-a5e3f75caa63 h1:QZ8/V1B4oK7N5t6w0zX5dAxFIHt0WaTX+r1z29cWXjY= +golang.org/x/build v0.0.0-20250211223606-a5e3f75caa63/go.mod h1:JhINjMoWj8G2oLkaBLNDBIr/GLqJNOkCr4XzFWWYCf4= +golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= +golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/telemetry v0.0.0-20250212145848-75305293b65a h1:3fgycqG+90xOafOruMBVZXa8DUeOt5qbGLjQoNvZ8Ew= +golang.org/x/telemetry v0.0.0-20250212145848-75305293b65a/go.mod h1:Ng+6E7PnWNge4EifZkPKeQUnm5iyAoH8qQgw3pLCiF4= +golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU= +golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s= +golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= +golang.org/x/tools v0.30.1-0.20250212161021-f9aad7054b5f h1:wN7/h1uT0B8rVpI6iWEPBC6qO1tdoMaNR6cOwdqqy/s= +golang.org/x/tools v0.30.1-0.20250212161021-f9aad7054b5f/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= rsc.io/markdown v0.0.0-20240306144322-0bf8f97ee8ef h1:mqLYrXCXYEZOop9/Dbo6RPX11539nwiCNBb1icVPmw8= rsc.io/markdown v0.0.0-20240306144322-0bf8f97ee8ef/go.mod h1:8xcPgWmwlZONN1D9bjxtHEjrUtSEa3fakVF8iaewYKQ= diff --git a/src/cmd/vendor/golang.org/x/arch/riscv64/riscv64asm/gnu.go b/src/cmd/vendor/golang.org/x/arch/riscv64/riscv64asm/gnu.go index d6b3dc040e8bcc..3ee0449640aa5a 100644 --- a/src/cmd/vendor/golang.org/x/arch/riscv64/riscv64asm/gnu.go +++ b/src/cmd/vendor/golang.org/x/arch/riscv64/riscv64asm/gnu.go @@ -42,6 +42,11 @@ func GNUSyntax(inst Inst) string { } } + if inst.Op == ANDI && inst.Args[2].(Simm).Imm == 255 { + op = "zext.b" + args = args[:len(args)-1] + } + if inst.Op == ADDIW && inst.Args[2].(Simm).Imm == 0 { op = "sext.w" args = args[:len(args)-1] diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/tables.go b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/tables.go index 6f57c70bf1529a..9710bbd8bd0c5b 100644 --- a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/tables.go +++ b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/tables.go @@ -1,4 +1,4 @@ -// Code generated by x86map -fmt=decoder x86.csv DO NOT EDIT. +// Code generated by x86map -fmt=decoder ../x86.csv DO NOT EDIT. package x86asm diff --git a/src/cmd/vendor/golang.org/x/build/relnote/links.go b/src/cmd/vendor/golang.org/x/build/relnote/links.go index b8e3a0f4b08f16..ff62cdabfa3c5f 100644 --- a/src/cmd/vendor/golang.org/x/build/relnote/links.go +++ b/src/cmd/vendor/golang.org/x/build/relnote/links.go @@ -158,7 +158,7 @@ func symbolLinkText(i int, ins []md.Inline) string { if plainText(i) != "[" { return "" } - // The open bracket must be preceeded by a link-adjacent rune (or by nothing). + // The open bracket must be preceded by a link-adjacent rune (or by nothing). if t := plainText(i - 1); t != "" { r, _ := utf8.DecodeLastRuneInString(t) if !isLinkAdjacentRune(r) { diff --git a/src/cmd/vendor/golang.org/x/build/relnote/relnote.go b/src/cmd/vendor/golang.org/x/build/relnote/relnote.go index ba48e6f576fc2a..eeb12ce9e3ea28 100644 --- a/src/cmd/vendor/golang.org/x/build/relnote/relnote.go +++ b/src/cmd/vendor/golang.org/x/build/relnote/relnote.go @@ -462,5 +462,8 @@ func checkFragmentFile(fsys fs.FS, filename string) error { } defer f.Close() data, err := io.ReadAll(f) + if err != nil { + return err + } return CheckFragment(string(data)) } diff --git a/src/cmd/vendor/golang.org/x/mod/modfile/read.go b/src/cmd/vendor/golang.org/x/mod/modfile/read.go index de1b98211a1907..2d7486804f5060 100644 --- a/src/cmd/vendor/golang.org/x/mod/modfile/read.go +++ b/src/cmd/vendor/golang.org/x/mod/modfile/read.go @@ -877,6 +877,11 @@ func (in *input) parseLineBlock(start Position, token []string, lparen token) *L in.Error(fmt.Sprintf("syntax error (unterminated block started at %s:%d:%d)", in.filename, x.Start.Line, x.Start.LineRune)) case ')': rparen := in.lex() + // Don't preserve blank lines (denoted by a single empty comment, added above) + // at the end of the block. + if len(comments) == 1 && comments[0] == (Comment{}) { + comments = nil + } x.RParen.Before = comments x.RParen.Pos = rparen.pos if !in.peek().isEOL() { diff --git a/src/cmd/vendor/golang.org/x/sync/errgroup/errgroup.go b/src/cmd/vendor/golang.org/x/sync/errgroup/errgroup.go index 948a3ee63d4ffe..b8322598ae3ea0 100644 --- a/src/cmd/vendor/golang.org/x/sync/errgroup/errgroup.go +++ b/src/cmd/vendor/golang.org/x/sync/errgroup/errgroup.go @@ -118,6 +118,7 @@ func (g *Group) TryGo(f func() error) bool { // SetLimit limits the number of active goroutines in this group to at most n. // A negative value indicates no limit. +// A limit of zero will prevent any new goroutines from being added. // // Any subsequent call to the Go method will block until it can add an active // goroutine without exceeding the configured limit. diff --git a/src/cmd/vendor/golang.org/x/sys/unix/auxv.go b/src/cmd/vendor/golang.org/x/sys/unix/auxv.go new file mode 100644 index 00000000000000..37a82528f580f1 --- /dev/null +++ b/src/cmd/vendor/golang.org/x/sys/unix/auxv.go @@ -0,0 +1,36 @@ +// Copyright 2025 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. + +//go:build go1.21 && (aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos) + +package unix + +import ( + "syscall" + "unsafe" +) + +//go:linkname runtime_getAuxv runtime.getAuxv +func runtime_getAuxv() []uintptr + +// Auxv returns the ELF auxiliary vector as a sequence of key/value pairs. +// The returned slice is always a fresh copy, owned by the caller. +// It returns an error on non-ELF platforms, or if the auxiliary vector cannot be accessed, +// which happens in some locked-down environments and build modes. +func Auxv() ([][2]uintptr, error) { + vec := runtime_getAuxv() + vecLen := len(vec) + + if vecLen == 0 { + return nil, syscall.ENOENT + } + + if vecLen%2 != 0 { + return nil, syscall.EINVAL + } + + result := make([]uintptr, vecLen) + copy(result, vec) + return unsafe.Slice((*[2]uintptr)(unsafe.Pointer(&result[0])), vecLen/2), nil +} diff --git a/src/cmd/vendor/golang.org/x/sys/unix/auxv_unsupported.go b/src/cmd/vendor/golang.org/x/sys/unix/auxv_unsupported.go new file mode 100644 index 00000000000000..1200487f2e86c6 --- /dev/null +++ b/src/cmd/vendor/golang.org/x/sys/unix/auxv_unsupported.go @@ -0,0 +1,13 @@ +// Copyright 2025 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. + +//go:build !go1.21 && (aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos) + +package unix + +import "syscall" + +func Auxv() ([][2]uintptr, error) { + return nil, syscall.ENOTSUP +} diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_dragonfly.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_dragonfly.go index 97cb916f2c90ef..be8c0020701ee4 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/syscall_dragonfly.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/syscall_dragonfly.go @@ -246,6 +246,18 @@ func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err e return sendfile(outfd, infd, offset, count) } +func Dup3(oldfd, newfd, flags int) error { + if oldfd == newfd || flags&^O_CLOEXEC != 0 { + return EINVAL + } + how := F_DUP2FD + if flags&O_CLOEXEC != 0 { + how = F_DUP2FD_CLOEXEC + } + _, err := fcntl(oldfd, how, newfd) + return err +} + /* * Exposed directly */ diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_solaris.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_solaris.go index 21974af064ddc3..abc3955477c7d3 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/syscall_solaris.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/syscall_solaris.go @@ -1102,3 +1102,90 @@ func (s *Strioctl) SetInt(i int) { func IoctlSetStrioctlRetInt(fd int, req int, s *Strioctl) (int, error) { return ioctlPtrRet(fd, req, unsafe.Pointer(s)) } + +// Ucred Helpers +// See ucred(3c) and getpeerucred(3c) + +//sys getpeerucred(fd uintptr, ucred *uintptr) (err error) +//sys ucredFree(ucred uintptr) = ucred_free +//sys ucredGet(pid int) (ucred uintptr, err error) = ucred_get +//sys ucredGeteuid(ucred uintptr) (uid int) = ucred_geteuid +//sys ucredGetegid(ucred uintptr) (gid int) = ucred_getegid +//sys ucredGetruid(ucred uintptr) (uid int) = ucred_getruid +//sys ucredGetrgid(ucred uintptr) (gid int) = ucred_getrgid +//sys ucredGetsuid(ucred uintptr) (uid int) = ucred_getsuid +//sys ucredGetsgid(ucred uintptr) (gid int) = ucred_getsgid +//sys ucredGetpid(ucred uintptr) (pid int) = ucred_getpid + +// Ucred is an opaque struct that holds user credentials. +type Ucred struct { + ucred uintptr +} + +// We need to ensure that ucredFree is called on the underlying ucred +// when the Ucred is garbage collected. +func ucredFinalizer(u *Ucred) { + ucredFree(u.ucred) +} + +func GetPeerUcred(fd uintptr) (*Ucred, error) { + var ucred uintptr + err := getpeerucred(fd, &ucred) + if err != nil { + return nil, err + } + result := &Ucred{ + ucred: ucred, + } + // set the finalizer on the result so that the ucred will be freed + runtime.SetFinalizer(result, ucredFinalizer) + return result, nil +} + +func UcredGet(pid int) (*Ucred, error) { + ucred, err := ucredGet(pid) + if err != nil { + return nil, err + } + result := &Ucred{ + ucred: ucred, + } + // set the finalizer on the result so that the ucred will be freed + runtime.SetFinalizer(result, ucredFinalizer) + return result, nil +} + +func (u *Ucred) Geteuid() int { + defer runtime.KeepAlive(u) + return ucredGeteuid(u.ucred) +} + +func (u *Ucred) Getruid() int { + defer runtime.KeepAlive(u) + return ucredGetruid(u.ucred) +} + +func (u *Ucred) Getsuid() int { + defer runtime.KeepAlive(u) + return ucredGetsuid(u.ucred) +} + +func (u *Ucred) Getegid() int { + defer runtime.KeepAlive(u) + return ucredGetegid(u.ucred) +} + +func (u *Ucred) Getrgid() int { + defer runtime.KeepAlive(u) + return ucredGetrgid(u.ucred) +} + +func (u *Ucred) Getsgid() int { + defer runtime.KeepAlive(u) + return ucredGetsgid(u.ucred) +} + +func (u *Ucred) Getpid() int { + defer runtime.KeepAlive(u) + return ucredGetpid(u.ucred) +} diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux.go b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux.go index 6ebc48b3fecd71..4f432bfe8feeee 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux.go @@ -1245,6 +1245,7 @@ const ( FAN_REPORT_DFID_NAME = 0xc00 FAN_REPORT_DFID_NAME_TARGET = 0x1e00 FAN_REPORT_DIR_FID = 0x400 + FAN_REPORT_FD_ERROR = 0x2000 FAN_REPORT_FID = 0x200 FAN_REPORT_NAME = 0x800 FAN_REPORT_PIDFD = 0x80 @@ -1330,8 +1331,10 @@ const ( FUSE_SUPER_MAGIC = 0x65735546 FUTEXFS_SUPER_MAGIC = 0xbad1dea F_ADD_SEALS = 0x409 + F_CREATED_QUERY = 0x404 F_DUPFD = 0x0 F_DUPFD_CLOEXEC = 0x406 + F_DUPFD_QUERY = 0x403 F_EXLCK = 0x4 F_GETFD = 0x1 F_GETFL = 0x3 @@ -1551,6 +1554,7 @@ const ( IPPROTO_ROUTING = 0x2b IPPROTO_RSVP = 0x2e IPPROTO_SCTP = 0x84 + IPPROTO_SMC = 0x100 IPPROTO_TCP = 0x6 IPPROTO_TP = 0x1d IPPROTO_UDP = 0x11 @@ -1623,6 +1627,8 @@ const ( IPV6_UNICAST_IF = 0x4c IPV6_USER_FLOW = 0xe IPV6_V6ONLY = 0x1a + IPV6_VERSION = 0x60 + IPV6_VERSION_MASK = 0xf0 IPV6_XFRM_POLICY = 0x23 IP_ADD_MEMBERSHIP = 0x23 IP_ADD_SOURCE_MEMBERSHIP = 0x27 @@ -1867,6 +1873,7 @@ const ( MADV_UNMERGEABLE = 0xd MADV_WILLNEED = 0x3 MADV_WIPEONFORK = 0x12 + MAP_DROPPABLE = 0x8 MAP_FILE = 0x0 MAP_FIXED = 0x10 MAP_FIXED_NOREPLACE = 0x100000 @@ -1967,6 +1974,7 @@ const ( MSG_PEEK = 0x2 MSG_PROXY = 0x10 MSG_RST = 0x1000 + MSG_SOCK_DEVMEM = 0x2000000 MSG_SYN = 0x400 MSG_TRUNC = 0x20 MSG_TRYHARD = 0x4 @@ -2083,6 +2091,7 @@ const ( NFC_ATR_REQ_MAXSIZE = 0x40 NFC_ATR_RES_GB_MAXSIZE = 0x2f NFC_ATR_RES_MAXSIZE = 0x40 + NFC_ATS_MAXSIZE = 0x14 NFC_COMM_ACTIVE = 0x0 NFC_COMM_PASSIVE = 0x1 NFC_DEVICE_NAME_MAXSIZE = 0x8 @@ -2163,6 +2172,7 @@ const ( NFNL_SUBSYS_QUEUE = 0x3 NFNL_SUBSYS_ULOG = 0x4 NFS_SUPER_MAGIC = 0x6969 + NFT_BITWISE_BOOL = 0x0 NFT_CHAIN_FLAGS = 0x7 NFT_CHAIN_MAXNAMELEN = 0x100 NFT_CT_MAX = 0x17 @@ -2491,6 +2501,7 @@ const ( PR_GET_PDEATHSIG = 0x2 PR_GET_SECCOMP = 0x15 PR_GET_SECUREBITS = 0x1b + PR_GET_SHADOW_STACK_STATUS = 0x4a PR_GET_SPECULATION_CTRL = 0x34 PR_GET_TAGGED_ADDR_CTRL = 0x38 PR_GET_THP_DISABLE = 0x2a @@ -2499,6 +2510,7 @@ const ( PR_GET_TIMING = 0xd PR_GET_TSC = 0x19 PR_GET_UNALIGN = 0x5 + PR_LOCK_SHADOW_STACK_STATUS = 0x4c PR_MCE_KILL = 0x21 PR_MCE_KILL_CLEAR = 0x0 PR_MCE_KILL_DEFAULT = 0x2 @@ -2525,6 +2537,8 @@ const ( PR_PAC_GET_ENABLED_KEYS = 0x3d PR_PAC_RESET_KEYS = 0x36 PR_PAC_SET_ENABLED_KEYS = 0x3c + PR_PMLEN_MASK = 0x7f000000 + PR_PMLEN_SHIFT = 0x18 PR_PPC_DEXCR_CTRL_CLEAR = 0x4 PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC = 0x10 PR_PPC_DEXCR_CTRL_EDITABLE = 0x1 @@ -2592,6 +2606,7 @@ const ( PR_SET_PTRACER = 0x59616d61 PR_SET_SECCOMP = 0x16 PR_SET_SECUREBITS = 0x1c + PR_SET_SHADOW_STACK_STATUS = 0x4b PR_SET_SPECULATION_CTRL = 0x35 PR_SET_SYSCALL_USER_DISPATCH = 0x3b PR_SET_TAGGED_ADDR_CTRL = 0x37 @@ -2602,6 +2617,9 @@ const ( PR_SET_UNALIGN = 0x6 PR_SET_VMA = 0x53564d41 PR_SET_VMA_ANON_NAME = 0x0 + PR_SHADOW_STACK_ENABLE = 0x1 + PR_SHADOW_STACK_PUSH = 0x4 + PR_SHADOW_STACK_WRITE = 0x2 PR_SME_GET_VL = 0x40 PR_SME_SET_VL = 0x3f PR_SME_SET_VL_ONEXEC = 0x40000 @@ -2911,7 +2929,6 @@ const ( RTM_NEWNEXTHOP = 0x68 RTM_NEWNEXTHOPBUCKET = 0x74 RTM_NEWNSID = 0x58 - RTM_NEWNVLAN = 0x70 RTM_NEWPREFIX = 0x34 RTM_NEWQDISC = 0x24 RTM_NEWROUTE = 0x18 @@ -2920,6 +2937,7 @@ const ( RTM_NEWTCLASS = 0x28 RTM_NEWTFILTER = 0x2c RTM_NEWTUNNEL = 0x78 + RTM_NEWVLAN = 0x70 RTM_NR_FAMILIES = 0x1b RTM_NR_MSGTYPES = 0x6c RTM_SETDCB = 0x4f diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_386.go b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_386.go index c0d45e320505ff..75207613c785db 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_386.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_386.go @@ -116,6 +116,8 @@ const ( IN_CLOEXEC = 0x80000 IN_NONBLOCK = 0x800 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x7b9 + IPV6_FLOWINFO_MASK = 0xffffff0f + IPV6_FLOWLABEL_MASK = 0xffff0f00 ISIG = 0x1 IUCLC = 0x200 IXOFF = 0x1000 @@ -304,6 +306,7 @@ const ( SCM_TIMESTAMPING_OPT_STATS = 0x36 SCM_TIMESTAMPING_PKTINFO = 0x3a SCM_TIMESTAMPNS = 0x23 + SCM_TS_OPT_ID = 0x51 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go index c731d24f025291..c68acda53522d1 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go @@ -116,6 +116,8 @@ const ( IN_CLOEXEC = 0x80000 IN_NONBLOCK = 0x800 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x7b9 + IPV6_FLOWINFO_MASK = 0xffffff0f + IPV6_FLOWLABEL_MASK = 0xffff0f00 ISIG = 0x1 IUCLC = 0x200 IXOFF = 0x1000 @@ -305,6 +307,7 @@ const ( SCM_TIMESTAMPING_OPT_STATS = 0x36 SCM_TIMESTAMPING_PKTINFO = 0x3a SCM_TIMESTAMPNS = 0x23 + SCM_TS_OPT_ID = 0x51 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go index 680018a4a7c9f0..a8c607ab86b51b 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go @@ -115,6 +115,8 @@ const ( IN_CLOEXEC = 0x80000 IN_NONBLOCK = 0x800 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x7b9 + IPV6_FLOWINFO_MASK = 0xffffff0f + IPV6_FLOWLABEL_MASK = 0xffff0f00 ISIG = 0x1 IUCLC = 0x200 IXOFF = 0x1000 @@ -310,6 +312,7 @@ const ( SCM_TIMESTAMPING_OPT_STATS = 0x36 SCM_TIMESTAMPING_PKTINFO = 0x3a SCM_TIMESTAMPNS = 0x23 + SCM_TS_OPT_ID = 0x51 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go index a63909f308d6d7..18563dd8d33a0f 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go @@ -109,6 +109,7 @@ const ( F_SETOWN = 0x8 F_UNLCK = 0x2 F_WRLCK = 0x1 + GCS_MAGIC = 0x47435300 HIDIOCGRAWINFO = 0x80084803 HIDIOCGRDESC = 0x90044802 HIDIOCGRDESCSIZE = 0x80044801 @@ -119,6 +120,8 @@ const ( IN_CLOEXEC = 0x80000 IN_NONBLOCK = 0x800 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x7b9 + IPV6_FLOWINFO_MASK = 0xffffff0f + IPV6_FLOWLABEL_MASK = 0xffff0f00 ISIG = 0x1 IUCLC = 0x200 IXOFF = 0x1000 @@ -302,6 +305,7 @@ const ( SCM_TIMESTAMPING_OPT_STATS = 0x36 SCM_TIMESTAMPING_PKTINFO = 0x3a SCM_TIMESTAMPNS = 0x23 + SCM_TS_OPT_ID = 0x51 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go index 9b0a2573fe3fb3..22912cdaa94483 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go @@ -116,6 +116,8 @@ const ( IN_CLOEXEC = 0x80000 IN_NONBLOCK = 0x800 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x7b9 + IPV6_FLOWINFO_MASK = 0xffffff0f + IPV6_FLOWLABEL_MASK = 0xffff0f00 ISIG = 0x1 IUCLC = 0x200 IXOFF = 0x1000 @@ -297,6 +299,7 @@ const ( SCM_TIMESTAMPING_OPT_STATS = 0x36 SCM_TIMESTAMPING_PKTINFO = 0x3a SCM_TIMESTAMPNS = 0x23 + SCM_TS_OPT_ID = 0x51 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go index 958e6e0645acdd..29344eb37ab55a 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go @@ -115,6 +115,8 @@ const ( IN_CLOEXEC = 0x80000 IN_NONBLOCK = 0x80 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9 + IPV6_FLOWINFO_MASK = 0xfffffff + IPV6_FLOWLABEL_MASK = 0xfffff ISIG = 0x1 IUCLC = 0x200 IXOFF = 0x1000 @@ -303,6 +305,7 @@ const ( SCM_TIMESTAMPING_OPT_STATS = 0x36 SCM_TIMESTAMPING_PKTINFO = 0x3a SCM_TIMESTAMPNS = 0x23 + SCM_TS_OPT_ID = 0x51 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go index 50c7f25bd16c6b..20d51fb96a897f 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go @@ -115,6 +115,8 @@ const ( IN_CLOEXEC = 0x80000 IN_NONBLOCK = 0x80 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9 + IPV6_FLOWINFO_MASK = 0xfffffff + IPV6_FLOWLABEL_MASK = 0xfffff ISIG = 0x1 IUCLC = 0x200 IXOFF = 0x1000 @@ -303,6 +305,7 @@ const ( SCM_TIMESTAMPING_OPT_STATS = 0x36 SCM_TIMESTAMPING_PKTINFO = 0x3a SCM_TIMESTAMPNS = 0x23 + SCM_TS_OPT_ID = 0x51 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go index ced21d66d955aa..321b60902ae5cd 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go @@ -115,6 +115,8 @@ const ( IN_CLOEXEC = 0x80000 IN_NONBLOCK = 0x80 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9 + IPV6_FLOWINFO_MASK = 0xffffff0f + IPV6_FLOWLABEL_MASK = 0xffff0f00 ISIG = 0x1 IUCLC = 0x200 IXOFF = 0x1000 @@ -303,6 +305,7 @@ const ( SCM_TIMESTAMPING_OPT_STATS = 0x36 SCM_TIMESTAMPING_PKTINFO = 0x3a SCM_TIMESTAMPNS = 0x23 + SCM_TS_OPT_ID = 0x51 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go index 226c0441902358..9bacdf1e27910f 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go @@ -115,6 +115,8 @@ const ( IN_CLOEXEC = 0x80000 IN_NONBLOCK = 0x80 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9 + IPV6_FLOWINFO_MASK = 0xffffff0f + IPV6_FLOWLABEL_MASK = 0xffff0f00 ISIG = 0x1 IUCLC = 0x200 IXOFF = 0x1000 @@ -303,6 +305,7 @@ const ( SCM_TIMESTAMPING_OPT_STATS = 0x36 SCM_TIMESTAMPING_PKTINFO = 0x3a SCM_TIMESTAMPNS = 0x23 + SCM_TS_OPT_ID = 0x51 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go index 3122737cd464f0..c2242726156a94 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go @@ -115,6 +115,8 @@ const ( IN_CLOEXEC = 0x80000 IN_NONBLOCK = 0x800 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9 + IPV6_FLOWINFO_MASK = 0xfffffff + IPV6_FLOWLABEL_MASK = 0xfffff ISIG = 0x80 IUCLC = 0x1000 IXOFF = 0x400 @@ -358,6 +360,7 @@ const ( SCM_TIMESTAMPING_OPT_STATS = 0x36 SCM_TIMESTAMPING_PKTINFO = 0x3a SCM_TIMESTAMPNS = 0x23 + SCM_TS_OPT_ID = 0x51 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go index eb5d3467edf0c1..6270c8ee13e3f5 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go @@ -115,6 +115,8 @@ const ( IN_CLOEXEC = 0x80000 IN_NONBLOCK = 0x800 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9 + IPV6_FLOWINFO_MASK = 0xfffffff + IPV6_FLOWLABEL_MASK = 0xfffff ISIG = 0x80 IUCLC = 0x1000 IXOFF = 0x400 @@ -362,6 +364,7 @@ const ( SCM_TIMESTAMPING_OPT_STATS = 0x36 SCM_TIMESTAMPING_PKTINFO = 0x3a SCM_TIMESTAMPNS = 0x23 + SCM_TS_OPT_ID = 0x51 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go index e921ebc60b7142..9966c1941f8301 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go @@ -115,6 +115,8 @@ const ( IN_CLOEXEC = 0x80000 IN_NONBLOCK = 0x800 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9 + IPV6_FLOWINFO_MASK = 0xffffff0f + IPV6_FLOWLABEL_MASK = 0xffff0f00 ISIG = 0x80 IUCLC = 0x1000 IXOFF = 0x400 @@ -362,6 +364,7 @@ const ( SCM_TIMESTAMPING_OPT_STATS = 0x36 SCM_TIMESTAMPING_PKTINFO = 0x3a SCM_TIMESTAMPNS = 0x23 + SCM_TS_OPT_ID = 0x51 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go index 38ba81c55c1fd3..848e5fcc42e6f2 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go @@ -115,6 +115,8 @@ const ( IN_CLOEXEC = 0x80000 IN_NONBLOCK = 0x800 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x7b9 + IPV6_FLOWINFO_MASK = 0xffffff0f + IPV6_FLOWLABEL_MASK = 0xffff0f00 ISIG = 0x1 IUCLC = 0x200 IXOFF = 0x1000 @@ -294,6 +296,7 @@ const ( SCM_TIMESTAMPING_OPT_STATS = 0x36 SCM_TIMESTAMPING_PKTINFO = 0x3a SCM_TIMESTAMPNS = 0x23 + SCM_TS_OPT_ID = 0x51 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go index 71f0400977b367..669b2adb80b778 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go @@ -115,6 +115,8 @@ const ( IN_CLOEXEC = 0x80000 IN_NONBLOCK = 0x800 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x7b9 + IPV6_FLOWINFO_MASK = 0xfffffff + IPV6_FLOWLABEL_MASK = 0xfffff ISIG = 0x1 IUCLC = 0x200 IXOFF = 0x1000 @@ -366,6 +368,7 @@ const ( SCM_TIMESTAMPING_OPT_STATS = 0x36 SCM_TIMESTAMPING_PKTINFO = 0x3a SCM_TIMESTAMPNS = 0x23 + SCM_TS_OPT_ID = 0x51 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go index c44a313322c54c..4834e57514e44a 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go @@ -119,6 +119,8 @@ const ( IN_CLOEXEC = 0x400000 IN_NONBLOCK = 0x4000 IOCTL_VM_SOCKETS_GET_LOCAL_CID = 0x200007b9 + IPV6_FLOWINFO_MASK = 0xfffffff + IPV6_FLOWLABEL_MASK = 0xfffff ISIG = 0x1 IUCLC = 0x200 IXOFF = 0x1000 @@ -357,6 +359,7 @@ const ( SCM_TIMESTAMPING_OPT_STATS = 0x38 SCM_TIMESTAMPING_PKTINFO = 0x3c SCM_TIMESTAMPNS = 0x21 + SCM_TS_OPT_ID = 0x5a SCM_TXTIME = 0x3f SCM_WIFI_STATUS = 0x25 SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_solaris_amd64.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_solaris_amd64.go index 829b87feb8da62..c6545413c45b44 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_solaris_amd64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_solaris_amd64.go @@ -141,6 +141,16 @@ import ( //go:cgo_import_dynamic libc_getpeername getpeername "libsocket.so" //go:cgo_import_dynamic libc_setsockopt setsockopt "libsocket.so" //go:cgo_import_dynamic libc_recvfrom recvfrom "libsocket.so" +//go:cgo_import_dynamic libc_getpeerucred getpeerucred "libc.so" +//go:cgo_import_dynamic libc_ucred_get ucred_get "libc.so" +//go:cgo_import_dynamic libc_ucred_geteuid ucred_geteuid "libc.so" +//go:cgo_import_dynamic libc_ucred_getegid ucred_getegid "libc.so" +//go:cgo_import_dynamic libc_ucred_getruid ucred_getruid "libc.so" +//go:cgo_import_dynamic libc_ucred_getrgid ucred_getrgid "libc.so" +//go:cgo_import_dynamic libc_ucred_getsuid ucred_getsuid "libc.so" +//go:cgo_import_dynamic libc_ucred_getsgid ucred_getsgid "libc.so" +//go:cgo_import_dynamic libc_ucred_getpid ucred_getpid "libc.so" +//go:cgo_import_dynamic libc_ucred_free ucred_free "libc.so" //go:cgo_import_dynamic libc_port_create port_create "libc.so" //go:cgo_import_dynamic libc_port_associate port_associate "libc.so" //go:cgo_import_dynamic libc_port_dissociate port_dissociate "libc.so" @@ -280,6 +290,16 @@ import ( //go:linkname procgetpeername libc_getpeername //go:linkname procsetsockopt libc_setsockopt //go:linkname procrecvfrom libc_recvfrom +//go:linkname procgetpeerucred libc_getpeerucred +//go:linkname procucred_get libc_ucred_get +//go:linkname procucred_geteuid libc_ucred_geteuid +//go:linkname procucred_getegid libc_ucred_getegid +//go:linkname procucred_getruid libc_ucred_getruid +//go:linkname procucred_getrgid libc_ucred_getrgid +//go:linkname procucred_getsuid libc_ucred_getsuid +//go:linkname procucred_getsgid libc_ucred_getsgid +//go:linkname procucred_getpid libc_ucred_getpid +//go:linkname procucred_free libc_ucred_free //go:linkname procport_create libc_port_create //go:linkname procport_associate libc_port_associate //go:linkname procport_dissociate libc_port_dissociate @@ -420,6 +440,16 @@ var ( procgetpeername, procsetsockopt, procrecvfrom, + procgetpeerucred, + procucred_get, + procucred_geteuid, + procucred_getegid, + procucred_getruid, + procucred_getrgid, + procucred_getsuid, + procucred_getsgid, + procucred_getpid, + procucred_free, procport_create, procport_associate, procport_dissociate, @@ -2029,6 +2059,90 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func getpeerucred(fd uintptr, ucred *uintptr) (err error) { + _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procgetpeerucred)), 2, uintptr(fd), uintptr(unsafe.Pointer(ucred)), 0, 0, 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ucredGet(pid int) (ucred uintptr, err error) { + r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procucred_get)), 1, uintptr(pid), 0, 0, 0, 0, 0) + ucred = uintptr(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ucredGeteuid(ucred uintptr) (uid int) { + r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&procucred_geteuid)), 1, uintptr(ucred), 0, 0, 0, 0, 0) + uid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ucredGetegid(ucred uintptr) (gid int) { + r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&procucred_getegid)), 1, uintptr(ucred), 0, 0, 0, 0, 0) + gid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ucredGetruid(ucred uintptr) (uid int) { + r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&procucred_getruid)), 1, uintptr(ucred), 0, 0, 0, 0, 0) + uid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ucredGetrgid(ucred uintptr) (gid int) { + r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&procucred_getrgid)), 1, uintptr(ucred), 0, 0, 0, 0, 0) + gid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ucredGetsuid(ucred uintptr) (uid int) { + r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&procucred_getsuid)), 1, uintptr(ucred), 0, 0, 0, 0, 0) + uid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ucredGetsgid(ucred uintptr) (gid int) { + r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&procucred_getsgid)), 1, uintptr(ucred), 0, 0, 0, 0, 0) + gid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ucredGetpid(ucred uintptr) (pid int) { + r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&procucred_getpid)), 1, uintptr(ucred), 0, 0, 0, 0, 0) + pid = int(r0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ucredFree(ucred uintptr) { + sysvicall6(uintptr(unsafe.Pointer(&procucred_free)), 1, uintptr(ucred), 0, 0, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func port_create() (n int, err error) { r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procport_create)), 0, 0, 0, 0, 0, 0, 0) n = int(r0) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go index 524b0820cbc2ee..c79aaff306ae3e 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go @@ -458,4 +458,8 @@ const ( SYS_LSM_SET_SELF_ATTR = 460 SYS_LSM_LIST_MODULES = 461 SYS_MSEAL = 462 + SYS_SETXATTRAT = 463 + SYS_GETXATTRAT = 464 + SYS_LISTXATTRAT = 465 + SYS_REMOVEXATTRAT = 466 ) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go index f485dbf4565671..5eb450695e95a8 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go @@ -381,4 +381,8 @@ const ( SYS_LSM_SET_SELF_ATTR = 460 SYS_LSM_LIST_MODULES = 461 SYS_MSEAL = 462 + SYS_SETXATTRAT = 463 + SYS_GETXATTRAT = 464 + SYS_LISTXATTRAT = 465 + SYS_REMOVEXATTRAT = 466 ) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go index 70b35bf3b09f68..05e50297445861 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go @@ -422,4 +422,8 @@ const ( SYS_LSM_SET_SELF_ATTR = 460 SYS_LSM_LIST_MODULES = 461 SYS_MSEAL = 462 + SYS_SETXATTRAT = 463 + SYS_GETXATTRAT = 464 + SYS_LISTXATTRAT = 465 + SYS_REMOVEXATTRAT = 466 ) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go index 1893e2fe884044..38c53ec51bb3e6 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go @@ -325,4 +325,8 @@ const ( SYS_LSM_SET_SELF_ATTR = 460 SYS_LSM_LIST_MODULES = 461 SYS_MSEAL = 462 + SYS_SETXATTRAT = 463 + SYS_GETXATTRAT = 464 + SYS_LISTXATTRAT = 465 + SYS_REMOVEXATTRAT = 466 ) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go index 16a4017da0ab2f..31d2e71a18e17f 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go @@ -321,4 +321,8 @@ const ( SYS_LSM_SET_SELF_ATTR = 460 SYS_LSM_LIST_MODULES = 461 SYS_MSEAL = 462 + SYS_SETXATTRAT = 463 + SYS_GETXATTRAT = 464 + SYS_LISTXATTRAT = 465 + SYS_REMOVEXATTRAT = 466 ) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go index 7e567f1efff21d..f4184a336b0e02 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go @@ -442,4 +442,8 @@ const ( SYS_LSM_SET_SELF_ATTR = 4460 SYS_LSM_LIST_MODULES = 4461 SYS_MSEAL = 4462 + SYS_SETXATTRAT = 4463 + SYS_GETXATTRAT = 4464 + SYS_LISTXATTRAT = 4465 + SYS_REMOVEXATTRAT = 4466 ) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go index 38ae55e5ef8564..05b9962278f276 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go @@ -372,4 +372,8 @@ const ( SYS_LSM_SET_SELF_ATTR = 5460 SYS_LSM_LIST_MODULES = 5461 SYS_MSEAL = 5462 + SYS_SETXATTRAT = 5463 + SYS_GETXATTRAT = 5464 + SYS_LISTXATTRAT = 5465 + SYS_REMOVEXATTRAT = 5466 ) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go index 55e92e60a82abe..43a256e9e67585 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go @@ -372,4 +372,8 @@ const ( SYS_LSM_SET_SELF_ATTR = 5460 SYS_LSM_LIST_MODULES = 5461 SYS_MSEAL = 5462 + SYS_SETXATTRAT = 5463 + SYS_GETXATTRAT = 5464 + SYS_LISTXATTRAT = 5465 + SYS_REMOVEXATTRAT = 5466 ) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go index 60658d6a021f66..eea5ddfc220774 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go @@ -442,4 +442,8 @@ const ( SYS_LSM_SET_SELF_ATTR = 4460 SYS_LSM_LIST_MODULES = 4461 SYS_MSEAL = 4462 + SYS_SETXATTRAT = 4463 + SYS_GETXATTRAT = 4464 + SYS_LISTXATTRAT = 4465 + SYS_REMOVEXATTRAT = 4466 ) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go index e203e8a7ed4b2c..0d777bfbb1408e 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go @@ -449,4 +449,8 @@ const ( SYS_LSM_SET_SELF_ATTR = 460 SYS_LSM_LIST_MODULES = 461 SYS_MSEAL = 462 + SYS_SETXATTRAT = 463 + SYS_GETXATTRAT = 464 + SYS_LISTXATTRAT = 465 + SYS_REMOVEXATTRAT = 466 ) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go index 5944b97d54604e..b44636502561e6 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go @@ -421,4 +421,8 @@ const ( SYS_LSM_SET_SELF_ATTR = 460 SYS_LSM_LIST_MODULES = 461 SYS_MSEAL = 462 + SYS_SETXATTRAT = 463 + SYS_GETXATTRAT = 464 + SYS_LISTXATTRAT = 465 + SYS_REMOVEXATTRAT = 466 ) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go index c66d416dad1ccb..0c7d21c1881653 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go @@ -421,4 +421,8 @@ const ( SYS_LSM_SET_SELF_ATTR = 460 SYS_LSM_LIST_MODULES = 461 SYS_MSEAL = 462 + SYS_SETXATTRAT = 463 + SYS_GETXATTRAT = 464 + SYS_LISTXATTRAT = 465 + SYS_REMOVEXATTRAT = 466 ) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go index a5459e766f59db..8405391698787a 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go @@ -326,4 +326,8 @@ const ( SYS_LSM_SET_SELF_ATTR = 460 SYS_LSM_LIST_MODULES = 461 SYS_MSEAL = 462 + SYS_SETXATTRAT = 463 + SYS_GETXATTRAT = 464 + SYS_LISTXATTRAT = 465 + SYS_REMOVEXATTRAT = 466 ) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go index 01d86825bb9264..fcf1b790d6cfd3 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go @@ -387,4 +387,8 @@ const ( SYS_LSM_SET_SELF_ATTR = 460 SYS_LSM_LIST_MODULES = 461 SYS_MSEAL = 462 + SYS_SETXATTRAT = 463 + SYS_GETXATTRAT = 464 + SYS_LISTXATTRAT = 465 + SYS_REMOVEXATTRAT = 466 ) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go index 7b703e77cda845..52d15b5f9d4597 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go @@ -400,4 +400,8 @@ const ( SYS_LSM_SET_SELF_ATTR = 460 SYS_LSM_LIST_MODULES = 461 SYS_MSEAL = 462 + SYS_SETXATTRAT = 463 + SYS_GETXATTRAT = 464 + SYS_LISTXATTRAT = 465 + SYS_REMOVEXATTRAT = 466 ) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux.go index 5537148dcbb3de..a46abe64720547 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux.go @@ -4747,7 +4747,7 @@ const ( NL80211_ATTR_MAC_HINT = 0xc8 NL80211_ATTR_MAC_MASK = 0xd7 NL80211_ATTR_MAX_AP_ASSOC_STA = 0xca - NL80211_ATTR_MAX = 0x14c + NL80211_ATTR_MAX = 0x14d NL80211_ATTR_MAX_CRIT_PROT_DURATION = 0xb4 NL80211_ATTR_MAX_CSA_COUNTERS = 0xce NL80211_ATTR_MAX_MATCH_SETS = 0x85 @@ -5519,7 +5519,7 @@ const ( NL80211_MNTR_FLAG_CONTROL = 0x3 NL80211_MNTR_FLAG_COOK_FRAMES = 0x5 NL80211_MNTR_FLAG_FCSFAIL = 0x1 - NL80211_MNTR_FLAG_MAX = 0x6 + NL80211_MNTR_FLAG_MAX = 0x7 NL80211_MNTR_FLAG_OTHER_BSS = 0x4 NL80211_MNTR_FLAG_PLCPFAIL = 0x2 NL80211_MPATH_FLAG_ACTIVE = 0x1 @@ -6174,3 +6174,5 @@ type SockDiagReq struct { Family uint8 Protocol uint8 } + +const RTM_NEWNVLAN = 0x70 diff --git a/src/cmd/vendor/golang.org/x/sys/windows/dll_windows.go b/src/cmd/vendor/golang.org/x/sys/windows/dll_windows.go index 4e613cf6335cea..3ca814f54d44eb 100644 --- a/src/cmd/vendor/golang.org/x/sys/windows/dll_windows.go +++ b/src/cmd/vendor/golang.org/x/sys/windows/dll_windows.go @@ -43,8 +43,8 @@ type DLL struct { // LoadDLL loads DLL file into memory. // // Warning: using LoadDLL without an absolute path name is subject to -// DLL preloading attacks. To safely load a system DLL, use LazyDLL -// with System set to true, or use LoadLibraryEx directly. +// DLL preloading attacks. To safely load a system DLL, use [NewLazySystemDLL], +// or use [LoadLibraryEx] directly. func LoadDLL(name string) (dll *DLL, err error) { namep, err := UTF16PtrFromString(name) if err != nil { @@ -271,6 +271,9 @@ func (d *LazyDLL) NewProc(name string) *LazyProc { } // NewLazyDLL creates new LazyDLL associated with DLL file. +// +// Warning: using NewLazyDLL without an absolute path name is subject to +// DLL preloading attacks. To safely load a system DLL, use [NewLazySystemDLL]. func NewLazyDLL(name string) *LazyDLL { return &LazyDLL{Name: name} } @@ -410,7 +413,3 @@ func loadLibraryEx(name string, system bool) (*DLL, error) { } return &DLL{Name: name, Handle: h}, nil } - -type errString string - -func (s errString) Error() string { return string(s) } diff --git a/src/cmd/vendor/golang.org/x/telemetry/internal/crashmonitor/monitor.go b/src/cmd/vendor/golang.org/x/telemetry/internal/crashmonitor/monitor.go index 612f7563a74c9f..f43d2cd455b638 100644 --- a/src/cmd/vendor/golang.org/x/telemetry/internal/crashmonitor/monitor.go +++ b/src/cmd/vendor/golang.org/x/telemetry/internal/crashmonitor/monitor.go @@ -170,6 +170,35 @@ func telemetryCounterName(crash []byte) (string, error) { // there is no possibility of strings from the crash report (which may // contain PII) leaking into the telemetry system. func parseStackPCs(crash string) ([]uintptr, error) { + // getSymbol parses the symbol name out of a line of the form: + // SYMBOL(ARGS) + // + // Note: SYMBOL may contain parens "pkg.(*T).method". However, type + // parameters are always replaced with ..., so they cannot introduce + // more parens. e.g., "pkg.(*T[...]).method". + // + // ARGS can contain parens. We want the first paren that is not + // immediately preceded by a ".". + // + // TODO(prattmic): This is mildly complicated and is only used to find + // runtime.sigpanic, so perhaps simplify this by checking explicitly + // for sigpanic. + getSymbol := func(line string) (string, error) { + var prev rune + for i, c := range line { + if line[i] != '(' { + prev = c + continue + } + if prev == '.' { + prev = c + continue + } + return line[:i], nil + } + return "", fmt.Errorf("no symbol for stack frame: %s", line) + } + // getPC parses the PC out of a line of the form: // \tFILE:LINE +0xRELPC sp=... fp=... pc=... getPC := func(line string) (uint64, error) { @@ -186,6 +215,9 @@ func parseStackPCs(crash string) ([]uintptr, error) { childSentinel = sentinel() on = false // are we in the first running goroutine? lines = strings.Split(crash, "\n") + symLine = true // within a goroutine, every other line is a symbol or file/line/pc location, starting with symbol. + currSymbol string + prevSymbol string // symbol of the most recent previous frame with a PC. ) for i := 0; i < len(lines); i++ { line := lines[i] @@ -228,21 +260,76 @@ func parseStackPCs(crash string) ([]uintptr, error) { // Note: SYMBOL may contain parens "pkg.(*T).method" // The RELPC is sometimes missing. - // Skip the symbol(args) line. - i++ - if i == len(lines) { - break - } - line = lines[i] + if symLine { + var err error + currSymbol, err = getSymbol(line) + if err != nil { + return nil, fmt.Errorf("error extracting symbol: %v", err) + } - // Parse the PC, and correct for the parent and child's - // different mappings of the text section. - pc, err := getPC(line) - if err != nil { - // Inlined frame, perhaps; skip it. - continue + symLine = false // Next line is FILE:LINE. + } else { + // Parse the PC, and correct for the parent and child's + // different mappings of the text section. + pc, err := getPC(line) + if err != nil { + // Inlined frame, perhaps; skip it. + + // Done with this frame. Next line is a new frame. + // + // Don't update prevSymbol; we only want to + // track frames with a PC. + currSymbol = "" + symLine = true + continue + } + + pc = pc-parentSentinel+childSentinel + + // If the previous frame was sigpanic, then this frame + // was a trap (e.g., SIGSEGV). + // + // Typically all middle frames are calls, and report + // the "return PC". That is, the instruction following + // the CALL where the callee will eventually return to. + // + // runtime.CallersFrames is aware of this property and + // will decrement each PC by 1 to "back up" to the + // location of the CALL, which is the actual line + // number the user expects. + // + // This does not work for traps, as a trap is not a + // call, so the reported PC is not the return PC, but + // the actual PC of the trap. + // + // runtime.Callers is aware of this and will + // intentionally increment trap PCs in order to correct + // for the decrement performed by + // runtime.CallersFrames. See runtime.tracebackPCs and + // runtume.(*unwinder).symPC. + // + // We must emulate the same behavior, otherwise we will + // report the location of the instruction immediately + // prior to the trap, which may be on a different line, + // or even a different inlined functions. + // + // TODO(prattmic): The runtime applies the same trap + // behavior for other "injected calls", see injectCall + // in runtime.(*unwinder).next. Do we want to handle + // those as well? I don't believe we'd ever see + // runtime.asyncPreempt or runtime.debugCallV2 in a + // typical crash. + if prevSymbol == "runtime.sigpanic" { + pc++ + } + + pcs = append(pcs, uintptr(pc)) + + // Done with this frame. Next line is a new frame. + prevSymbol = currSymbol + currSymbol = "" + symLine = true } - pcs = append(pcs, uintptr(pc-parentSentinel+childSentinel)) } return pcs, nil } diff --git a/src/cmd/vendor/golang.org/x/tools/cmd/bisect/main.go b/src/cmd/vendor/golang.org/x/tools/cmd/bisect/main.go index 6a3745c0582ae2..a152fbd37c7ef5 100644 --- a/src/cmd/vendor/golang.org/x/tools/cmd/bisect/main.go +++ b/src/cmd/vendor/golang.org/x/tools/cmd/bisect/main.go @@ -262,7 +262,7 @@ type Bisect struct { // each pattern starts with a !. Disable bool - // SkipDigits is the number of hex digits to use in skip messages. + // SkipHexDigits is the number of hex digits to use in skip messages. // If the set of available changes is the same in each run, as it should be, // then this doesn't matter: we'll only exclude suffixes that uniquely identify // a given change. But for some programs, especially bisecting runtime diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/analysis.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/analysis.go index d384aa89b8ebde..3a73084a53c2e6 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/analysis.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/analysis.go @@ -156,10 +156,17 @@ type Pass struct { // AllPackageFacts returns a new slice containing all package // facts of the analysis's FactTypes in unspecified order. + // See comments for AllObjectFacts. AllPackageFacts func() []PackageFact // AllObjectFacts returns a new slice containing all object // facts of the analysis's FactTypes in unspecified order. + // + // The result includes all facts exported by packages + // whose symbols are referenced by the current package + // (by qualified identifiers or field/method selections). + // And it includes all facts exported from the current + // package by the current analysis pass. AllObjectFacts func() []ObjectFact /* Further fields may be added in future. */ diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/diagnostic.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/diagnostic.go index ee083a2d686723..f6118bec647620 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/diagnostic.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/diagnostic.go @@ -65,7 +65,9 @@ type RelatedInformation struct { // user can choose to apply to their code. Usually the SuggestedFix is // meant to fix the issue flagged by the diagnostic. // -// The TextEdits must not overlap, nor contain edits for other packages. +// The TextEdits must not overlap, nor contain edits for other +// packages. Edits need not be totally ordered, but the order +// determines how insertions at the same point will be applied. type SuggestedFix struct { // A verb phrase describing the fix, to be shown to // a user trying to decide whether to accept it. diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/internal/analysisflags/flags.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/internal/analysisflags/flags.go index 1282e70d41f703..c2445575cff8cf 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/internal/analysisflags/flags.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/internal/analysisflags/flags.go @@ -250,21 +250,12 @@ const ( setFalse ) -func triStateFlag(name string, value triState, usage string) *triState { - flag.Var(&value, name, usage) - return &value -} - // triState implements flag.Value, flag.Getter, and flag.boolFlag. // They work like boolean flags: we can say vet -printf as well as vet -printf=true func (ts *triState) Get() interface{} { return *ts == setTrue } -func (ts triState) isTrue() bool { - return ts == setTrue -} - func (ts *triState) Set(value string) error { b, err := strconv.ParseBool(value) if err != nil { diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go index b622dfdf3a06aa..a47ecbae731a51 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go @@ -542,8 +542,8 @@ func appendComponentsRecursive(arch *asmArch, t types.Type, cc []component, suff elem := tu.Elem() // Calculate offset of each element array. fields := []*types.Var{ - types.NewVar(token.NoPos, nil, "fake0", elem), - types.NewVar(token.NoPos, nil, "fake1", elem), + types.NewField(token.NoPos, nil, "fake0", elem, false), + types.NewField(token.NoPos, nil, "fake1", elem, false), } offsets := arch.sizes.Offsetsof(fields) elemoff := int(offsets[1]) diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/assign/assign.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/assign/assign.go index 0d95fefcb5a286..1413ee13d293e0 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/assign/assign.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/assign/assign.go @@ -19,6 +19,7 @@ import ( "golang.org/x/tools/go/analysis/passes/inspect" "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" + "golang.org/x/tools/internal/analysisinternal" ) //go:embed doc.go @@ -32,7 +33,7 @@ var Analyzer = &analysis.Analyzer{ Run: run, } -func run(pass *analysis.Pass) (interface{}, error) { +func run(pass *analysis.Pass) (any, error) { inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) nodeFilter := []ast.Node{ @@ -57,15 +58,17 @@ func run(pass *analysis.Pass) (interface{}, error) { if reflect.TypeOf(lhs) != reflect.TypeOf(rhs) { continue // short-circuit the heavy-weight gofmt check } - le := analysisutil.Format(pass.Fset, lhs) - re := analysisutil.Format(pass.Fset, rhs) + le := analysisinternal.Format(pass.Fset, lhs) + re := analysisinternal.Format(pass.Fset, rhs) if le == re { pass.Report(analysis.Diagnostic{ Pos: stmt.Pos(), Message: fmt.Sprintf("self-assignment of %s to %s", re, le), - SuggestedFixes: []analysis.SuggestedFix{ - {Message: "Remove", TextEdits: []analysis.TextEdit{ - {Pos: stmt.Pos(), End: stmt.End(), NewText: []byte{}}, - }}, + SuggestedFixes: []analysis.SuggestedFix{{ + Message: "Remove self-assignment", + TextEdits: []analysis.TextEdit{{ + Pos: stmt.Pos(), + End: stmt.End(), + }}}, }, }) } diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/atomic/atomic.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/atomic/atomic.go index 931f9ca7540f65..82d5439ce571e9 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/atomic/atomic.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/atomic/atomic.go @@ -14,6 +14,7 @@ import ( "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" "golang.org/x/tools/go/types/typeutil" + "golang.org/x/tools/internal/analysisinternal" ) //go:embed doc.go @@ -28,8 +29,8 @@ var Analyzer = &analysis.Analyzer{ Run: run, } -func run(pass *analysis.Pass) (interface{}, error) { - if !analysisutil.Imports(pass.Pkg, "sync/atomic") { +func run(pass *analysis.Pass) (any, error) { + if !analysisinternal.Imports(pass.Pkg, "sync/atomic") { return nil, nil // doesn't directly import sync/atomic } @@ -52,8 +53,8 @@ func run(pass *analysis.Pass) (interface{}, error) { if !ok { continue } - fn := typeutil.StaticCallee(pass.TypesInfo, call) - if analysisutil.IsFunctionNamed(fn, "sync/atomic", "AddInt32", "AddInt64", "AddUint32", "AddUint64", "AddUintptr") { + obj := typeutil.Callee(pass.TypesInfo, call) + if analysisinternal.IsFunctionNamed(obj, "sync/atomic", "AddInt32", "AddInt64", "AddUint32", "AddUint64", "AddUintptr") { checkAtomicAddAssignment(pass, n.Lhs[i], call) } } @@ -71,7 +72,7 @@ func checkAtomicAddAssignment(pass *analysis.Pass, left ast.Expr, call *ast.Call arg := call.Args[0] broken := false - gofmt := func(e ast.Expr) string { return analysisutil.Format(pass.Fset, e) } + gofmt := func(e ast.Expr) string { return analysisinternal.Format(pass.Fset, e) } if uarg, ok := arg.(*ast.UnaryExpr); ok && uarg.Op == token.AND { broken = gofmt(left) == gofmt(uarg.X) diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/bools/bools.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/bools/bools.go index 8cec6e8224a5dc..e1cf9f9b7ade10 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/bools/bools.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/bools/bools.go @@ -15,6 +15,7 @@ import ( "golang.org/x/tools/go/analysis/passes/inspect" "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" + "golang.org/x/tools/internal/analysisinternal" ) const Doc = "check for common mistakes involving boolean operators" @@ -27,7 +28,7 @@ var Analyzer = &analysis.Analyzer{ Run: run, } -func run(pass *analysis.Pass) (interface{}, error) { +func run(pass *analysis.Pass) (any, error) { inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) nodeFilter := []ast.Node{ @@ -103,7 +104,7 @@ func (op boolOp) commutativeSets(info *types.Info, e *ast.BinaryExpr, seen map[* func (op boolOp) checkRedundant(pass *analysis.Pass, exprs []ast.Expr) { seen := make(map[string]bool) for _, e := range exprs { - efmt := analysisutil.Format(pass.Fset, e) + efmt := analysisinternal.Format(pass.Fset, e) if seen[efmt] { pass.ReportRangef(e, "redundant %s: %s %s %s", op.name, efmt, op.tok, efmt) } else { @@ -149,8 +150,8 @@ func (op boolOp) checkSuspect(pass *analysis.Pass, exprs []ast.Expr) { } // e is of the form 'x != c' or 'x == c'. - xfmt := analysisutil.Format(pass.Fset, x) - efmt := analysisutil.Format(pass.Fset, e) + xfmt := analysisinternal.Format(pass.Fset, x) + efmt := analysisinternal.Format(pass.Fset, e) if prev, found := seen[xfmt]; found { // checkRedundant handles the case in which efmt == prev. if efmt != prev { diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go index 613583a1a64909..4f3bb035d65783 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go @@ -18,7 +18,7 @@ import ( "strconv" "golang.org/x/tools/go/analysis" - "golang.org/x/tools/go/analysis/passes/internal/analysisutil" + "golang.org/x/tools/internal/analysisinternal" ) const debug = false @@ -40,8 +40,8 @@ var Analyzer = &analysis.Analyzer{ Run: run, } -func run(pass *analysis.Pass) (interface{}, error) { - if !analysisutil.Imports(pass.Pkg, "runtime/cgo") { +func run(pass *analysis.Pass) (any, error) { + if !analysisinternal.Imports(pass.Pkg, "runtime/cgo") { return nil, nil // doesn't use cgo } diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/copylock/copylock.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/copylock/copylock.go index 03496cb3037d14..a9f02ac62e6405 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/copylock/copylock.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/copylock/copylock.go @@ -15,8 +15,8 @@ import ( "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" - "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" + "golang.org/x/tools/internal/analysisinternal" "golang.org/x/tools/internal/typeparams" "golang.org/x/tools/internal/versions" ) @@ -86,7 +86,7 @@ func checkCopyLocksAssign(pass *analysis.Pass, assign *ast.AssignStmt, goversion lhs := assign.Lhs for i, x := range assign.Rhs { if path := lockPathRhs(pass, x); path != nil { - pass.ReportRangef(x, "assignment copies lock value to %v: %v", analysisutil.Format(pass.Fset, assign.Lhs[i]), path) + pass.ReportRangef(x, "assignment copies lock value to %v: %v", analysisinternal.Format(pass.Fset, assign.Lhs[i]), path) lhs = nil // An lhs has been reported. We prefer the assignment warning and do not report twice. } } @@ -100,7 +100,7 @@ func checkCopyLocksAssign(pass *analysis.Pass, assign *ast.AssignStmt, goversion if id, ok := l.(*ast.Ident); ok && id.Name != "_" { if obj := pass.TypesInfo.Defs[id]; obj != nil && obj.Type() != nil { if path := lockPath(pass.Pkg, obj.Type(), nil); path != nil { - pass.ReportRangef(l, "for loop iteration copies lock value to %v: %v", analysisutil.Format(pass.Fset, l), path) + pass.ReportRangef(l, "for loop iteration copies lock value to %v: %v", analysisinternal.Format(pass.Fset, l), path) } } } @@ -132,7 +132,7 @@ func checkCopyLocksCompositeLit(pass *analysis.Pass, cl *ast.CompositeLit) { x = node.Value } if path := lockPathRhs(pass, x); path != nil { - pass.ReportRangef(x, "literal copies lock value from %v: %v", analysisutil.Format(pass.Fset, x), path) + pass.ReportRangef(x, "literal copies lock value from %v: %v", analysisinternal.Format(pass.Fset, x), path) } } } @@ -163,7 +163,7 @@ func checkCopyLocksCallExpr(pass *analysis.Pass, ce *ast.CallExpr) { } for _, x := range ce.Args { if path := lockPathRhs(pass, x); path != nil { - pass.ReportRangef(x, "call of %s copies lock value: %v", analysisutil.Format(pass.Fset, ce.Fun), path) + pass.ReportRangef(x, "call of %s copies lock value: %v", analysisinternal.Format(pass.Fset, ce.Fun), path) } } } @@ -230,7 +230,7 @@ func checkCopyLocksRangeVar(pass *analysis.Pass, rtok token.Token, e ast.Expr) { return } if path := lockPath(pass.Pkg, typ, nil); path != nil { - pass.Reportf(e.Pos(), "range var %s copies lock: %v", analysisutil.Format(pass.Fset, e), path) + pass.Reportf(e.Pos(), "range var %s copies lock: %v", analysisinternal.Format(pass.Fset, e), path) } } @@ -350,7 +350,7 @@ func lockPath(tpkg *types.Package, typ types.Type, seen map[types.Type]bool) typ // In go1.10, sync.noCopy did not implement Locker. // (The Unlock method was added only in CL 121876.) // TODO(adonovan): remove workaround when we drop go1.10. - if analysisutil.IsNamedType(typ, "sync", "noCopy") { + if analysisinternal.IsTypeNamed(typ, "sync", "noCopy") { return []string{typ.String()} } diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/defers/defers.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/defers/defers.go index 5e8e80a6a77cd2..e11957f2d099d1 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/defers/defers.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/defers/defers.go @@ -13,6 +13,7 @@ import ( "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" "golang.org/x/tools/go/types/typeutil" + "golang.org/x/tools/internal/analysisinternal" ) //go:embed doc.go @@ -27,15 +28,15 @@ var Analyzer = &analysis.Analyzer{ Run: run, } -func run(pass *analysis.Pass) (interface{}, error) { - if !analysisutil.Imports(pass.Pkg, "time") { +func run(pass *analysis.Pass) (any, error) { + if !analysisinternal.Imports(pass.Pkg, "time") { return nil, nil } checkDeferCall := func(node ast.Node) bool { switch v := node.(type) { case *ast.CallExpr: - if analysisutil.IsFunctionNamed(typeutil.StaticCallee(pass.TypesInfo, v), "time", "Since") { + if analysisinternal.IsFunctionNamed(typeutil.Callee(pass.TypesInfo, v), "time", "Since") { pass.Reportf(v.Pos(), "call to time.Since is not deferred") } case *ast.FuncLit: diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go index 7f62ad4c825d6a..b8d29d019db0b0 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go @@ -13,9 +13,9 @@ import ( "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" - "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" "golang.org/x/tools/go/types/typeutil" + "golang.org/x/tools/internal/analysisinternal" ) const Doc = `report passing non-pointer or non-error values to errors.As @@ -31,7 +31,7 @@ var Analyzer = &analysis.Analyzer{ Run: run, } -func run(pass *analysis.Pass) (interface{}, error) { +func run(pass *analysis.Pass) (any, error) { switch pass.Pkg.Path() { case "errors", "errors_test": // These packages know how to use their own APIs. @@ -39,7 +39,7 @@ func run(pass *analysis.Pass) (interface{}, error) { return nil, nil } - if !analysisutil.Imports(pass.Pkg, "errors") { + if !analysisinternal.Imports(pass.Pkg, "errors") { return nil, nil // doesn't directly import errors } @@ -50,8 +50,8 @@ func run(pass *analysis.Pass) (interface{}, error) { } inspect.Preorder(nodeFilter, func(n ast.Node) { call := n.(*ast.CallExpr) - fn := typeutil.StaticCallee(pass.TypesInfo, call) - if !analysisutil.IsFunctionNamed(fn, "errors", "As") { + obj := typeutil.Callee(pass.TypesInfo, call) + if !analysisinternal.IsFunctionNamed(obj, "errors", "As") { return } if len(call.Args) < 2 { diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/framepointer/framepointer.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/framepointer/framepointer.go index 6eff3a20feae11..8012de99daaedb 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/framepointer/framepointer.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/framepointer/framepointer.go @@ -10,6 +10,7 @@ import ( "go/build" "regexp" "strings" + "unicode" "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/internal/analysisutil" @@ -24,15 +25,97 @@ var Analyzer = &analysis.Analyzer{ Run: run, } -var ( - re = regexp.MustCompile - asmWriteBP = re(`,\s*BP$`) // TODO: can have false positive, e.g. for TESTQ BP,BP. Seems unlikely. - asmMentionBP = re(`\bBP\b`) - asmControlFlow = re(`^(J|RET)`) -) +// Per-architecture checks for instructions. +// Assume comments, leading and trailing spaces are removed. +type arch struct { + isFPWrite func(string) bool + isFPRead func(string) bool + isBranch func(string) bool +} + +var re = regexp.MustCompile + +func hasAnyPrefix(s string, prefixes ...string) bool { + for _, p := range prefixes { + if strings.HasPrefix(s, p) { + return true + } + } + return false +} + +var arches = map[string]arch{ + "amd64": { + isFPWrite: re(`,\s*BP$`).MatchString, // TODO: can have false positive, e.g. for TESTQ BP,BP. Seems unlikely. + isFPRead: re(`\bBP\b`).MatchString, + isBranch: func(s string) bool { + return hasAnyPrefix(s, "J", "RET") + }, + }, + "arm64": { + isFPWrite: func(s string) bool { + if i := strings.LastIndex(s, ","); i > 0 && strings.HasSuffix(s[i:], "R29") { + return true + } + if hasAnyPrefix(s, "LDP", "LDAXP", "LDXP", "CASP") { + // Instructions which write to a pair of registers, e.g. + // LDP 8(R0), (R26, R29) + // CASPD (R2, R3), (R2), (R26, R29) + lp := strings.LastIndex(s, "(") + rp := strings.LastIndex(s, ")") + if lp > -1 && lp < rp { + return strings.Contains(s[lp:rp], ",") && strings.Contains(s[lp:rp], "R29") + } + } + return false + }, + isFPRead: re(`\bR29\b`).MatchString, + isBranch: func(s string) bool { + // Get just the instruction + if i := strings.IndexFunc(s, unicode.IsSpace); i > 0 { + s = s[:i] + } + return arm64Branch[s] + }, + }, +} + +// arm64 has many control flow instructions. +// ^(B|RET) isn't sufficient or correct (e.g. BIC, BFI aren't control flow.) +// It's easier to explicitly enumerate them in a map than to write a regex. +// Borrowed from Go tree, cmd/asm/internal/arch/arm64.go +var arm64Branch = map[string]bool{ + "B": true, + "BL": true, + "BEQ": true, + "BNE": true, + "BCS": true, + "BHS": true, + "BCC": true, + "BLO": true, + "BMI": true, + "BPL": true, + "BVS": true, + "BVC": true, + "BHI": true, + "BLS": true, + "BGE": true, + "BLT": true, + "BGT": true, + "BLE": true, + "CBZ": true, + "CBZW": true, + "CBNZ": true, + "CBNZW": true, + "JMP": true, + "TBNZ": true, + "TBZ": true, + "RET": true, +} func run(pass *analysis.Pass) (interface{}, error) { - if build.Default.GOARCH != "amd64" { // TODO: arm64 also? + arch, ok := arches[build.Default.GOARCH] + if !ok { return nil, nil } if build.Default.GOOS != "linux" && build.Default.GOOS != "darwin" { @@ -63,6 +146,9 @@ func run(pass *analysis.Pass) (interface{}, error) { line = line[:i] } line = strings.TrimSpace(line) + if line == "" { + continue + } // We start checking code at a TEXT line for a frameless function. if strings.HasPrefix(line, "TEXT") && strings.Contains(line, "(SB)") && strings.Contains(line, "$0") { @@ -73,16 +159,12 @@ func run(pass *analysis.Pass) (interface{}, error) { continue } - if asmWriteBP.MatchString(line) { // clobber of BP, function is not OK + if arch.isFPWrite(line) { pass.Reportf(analysisutil.LineStart(tf, lineno), "frame pointer is clobbered before saving") active = false continue } - if asmMentionBP.MatchString(line) { // any other use of BP might be a read, so function is OK - active = false - continue - } - if asmControlFlow.MatchString(line) { // give up after any branch instruction + if arch.isFPRead(line) || arch.isBranch(line) { active = false continue } diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/httpresponse/httpresponse.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/httpresponse/httpresponse.go index 91ebe29de117a3..e9acd96547e1a7 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/httpresponse/httpresponse.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/httpresponse/httpresponse.go @@ -12,8 +12,8 @@ import ( "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" - "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" + "golang.org/x/tools/internal/analysisinternal" "golang.org/x/tools/internal/typesinternal" ) @@ -41,12 +41,12 @@ var Analyzer = &analysis.Analyzer{ Run: run, } -func run(pass *analysis.Pass) (interface{}, error) { +func run(pass *analysis.Pass) (any, error) { inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) // Fast path: if the package doesn't import net/http, // skip the traversal. - if !analysisutil.Imports(pass.Pkg, "net/http") { + if !analysisinternal.Imports(pass.Pkg, "net/http") { return nil, nil } @@ -118,7 +118,7 @@ func isHTTPFuncOrMethodOnClient(info *types.Info, expr *ast.CallExpr) bool { return false // the function called does not return two values. } isPtr, named := typesinternal.ReceiverNamed(res.At(0)) - if !isPtr || named == nil || !analysisutil.IsNamedType(named, "net/http", "Response") { + if !isPtr || named == nil || !analysisinternal.IsTypeNamed(named, "net/http", "Response") { return false // the first return type is not *http.Response. } @@ -133,11 +133,11 @@ func isHTTPFuncOrMethodOnClient(info *types.Info, expr *ast.CallExpr) bool { return ok && id.Name == "http" // function in net/http package. } - if analysisutil.IsNamedType(typ, "net/http", "Client") { + if analysisinternal.IsTypeNamed(typ, "net/http", "Client") { return true // method on http.Client. } ptr, ok := types.Unalias(typ).(*types.Pointer) - return ok && analysisutil.IsNamedType(ptr.Elem(), "net/http", "Client") // method on *http.Client. + return ok && analysisinternal.IsTypeNamed(ptr.Elem(), "net/http", "Client") // method on *http.Client. } // restOfBlock, given a traversal stack, finds the innermost containing diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil/util.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil/util.go index a4fa8d31c4ed5b..d3df898d3011cd 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil/util.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil/util.go @@ -7,9 +7,7 @@ package analysisutil import ( - "bytes" "go/ast" - "go/printer" "go/token" "go/types" "os" @@ -18,13 +16,6 @@ import ( "golang.org/x/tools/internal/analysisinternal" ) -// Format returns a string representation of the expression. -func Format(fset *token.FileSet, x ast.Expr) string { - var b bytes.Buffer - printer.Fprint(&b, fset, x) - return b.String() -} - // HasSideEffects reports whether evaluation of e has side effects. func HasSideEffects(info *types.Info, e ast.Expr) bool { safe := true @@ -105,57 +96,4 @@ func LineStart(f *token.File, line int) token.Pos { } } -// Imports returns true if path is imported by pkg. -func Imports(pkg *types.Package, path string) bool { - for _, imp := range pkg.Imports() { - if imp.Path() == path { - return true - } - } - return false -} - -// IsNamedType reports whether t is the named type with the given package path -// and one of the given names. -// This function avoids allocating the concatenation of "pkg.Name", -// which is important for the performance of syntax matching. -func IsNamedType(t types.Type, pkgPath string, names ...string) bool { - n, ok := types.Unalias(t).(*types.Named) - if !ok { - return false - } - obj := n.Obj() - if obj == nil || obj.Pkg() == nil || obj.Pkg().Path() != pkgPath { - return false - } - name := obj.Name() - for _, n := range names { - if name == n { - return true - } - } - return false -} - -// IsFunctionNamed reports whether f is a top-level function defined in the -// given package and has one of the given names. -// It returns false if f is nil or a method. -func IsFunctionNamed(f *types.Func, pkgPath string, names ...string) bool { - if f == nil { - return false - } - if f.Pkg() == nil || f.Pkg().Path() != pkgPath { - return false - } - if f.Type().(*types.Signature).Recv() != nil { - return false - } - for _, n := range names { - if f.Name() == n { - return true - } - } - return false -} - var MustExtractDoc = analysisinternal.MustExtractDoc diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/loopclosure.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/loopclosure.go index fe05eda44e49d3..d3181242153764 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/loopclosure.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/loopclosure.go @@ -14,6 +14,7 @@ import ( "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" "golang.org/x/tools/go/types/typeutil" + "golang.org/x/tools/internal/analysisinternal" "golang.org/x/tools/internal/typesinternal" "golang.org/x/tools/internal/versions" ) @@ -368,5 +369,5 @@ func isMethodCall(info *types.Info, expr ast.Expr, pkgPath, typeName, method str // Check that the receiver is a . or // *.. _, named := typesinternal.ReceiverNamed(recv) - return analysisutil.IsNamedType(named, pkgPath, typeName) + return analysisinternal.IsTypeNamed(named, pkgPath, typeName) } diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/lostcancel/lostcancel.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/lostcancel/lostcancel.go index 26fdc1206f8055..f8a661aa5db059 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/lostcancel/lostcancel.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/lostcancel/lostcancel.go @@ -16,6 +16,7 @@ import ( "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" "golang.org/x/tools/go/cfg" + "golang.org/x/tools/internal/analysisinternal" ) //go:embed doc.go @@ -48,7 +49,7 @@ var contextPackage = "context" // checkLostCancel analyzes a single named or literal function. func run(pass *analysis.Pass) (interface{}, error) { // Fast path: bypass check if file doesn't use context.WithCancel. - if !analysisutil.Imports(pass.Pkg, contextPackage) { + if !analysisinternal.Imports(pass.Pkg, contextPackage) { return nil, nil } diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go index 011ea8bef62925..81600a283aa21c 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go @@ -5,7 +5,6 @@ package printf import ( - "bytes" _ "embed" "fmt" "go/ast" @@ -15,15 +14,15 @@ import ( "reflect" "regexp" "sort" - "strconv" "strings" - "unicode/utf8" "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" "golang.org/x/tools/go/types/typeutil" + "golang.org/x/tools/internal/analysisinternal" + "golang.org/x/tools/internal/fmtstr" "golang.org/x/tools/internal/typeparams" "golang.org/x/tools/internal/versions" ) @@ -429,9 +428,9 @@ func checkCalls(pass *analysis.Pass) { fn, kind := printfNameAndKind(pass, n) switch kind { case KindPrintf, KindErrorf: - checkPrintf(pass, fileVersion, kind, n, fn) + checkPrintf(pass, fileVersion, kind, n, fn.FullName()) case KindPrint: - checkPrint(pass, n, fn) + checkPrint(pass, n, fn.FullName()) } } }) @@ -490,30 +489,12 @@ func isFormatter(typ types.Type) bool { sig := fn.Type().(*types.Signature) return sig.Params().Len() == 2 && sig.Results().Len() == 0 && - analysisutil.IsNamedType(sig.Params().At(0).Type(), "fmt", "State") && + analysisinternal.IsTypeNamed(sig.Params().At(0).Type(), "fmt", "State") && types.Identical(sig.Params().At(1).Type(), types.Typ[types.Rune]) } -// formatState holds the parsed representation of a printf directive such as "%3.*[4]d". -// It is constructed by parsePrintfVerb. -type formatState struct { - verb rune // the format verb: 'd' for "%d" - format string // the full format directive from % through verb, "%.3d". - name string // Printf, Sprintf etc. - flags []byte // the list of # + etc. - argNums []int // the successive argument numbers that are consumed, adjusted to refer to actual arg in call - firstArg int // Index of first argument after the format in the Printf call. - // Used only during parse. - pass *analysis.Pass - call *ast.CallExpr - argNum int // Which argument we're expecting to format now. - hasIndex bool // Whether the argument is indexed. - indexPending bool // Whether we have an indexed argument that has not resolved. - nbytes int // number of bytes of the format string consumed. -} - // checkPrintf checks a call to a formatted print routine such as Printf. -func checkPrintf(pass *analysis.Pass, fileVersion string, kind Kind, call *ast.CallExpr, fn *types.Func) { +func checkPrintf(pass *analysis.Pass, fileVersion string, kind Kind, call *ast.CallExpr, name string) { idx := formatStringIndex(pass, call) if idx < 0 || idx >= len(call.Args) { return @@ -542,7 +523,7 @@ func checkPrintf(pass *analysis.Pass, fileVersion string, kind Kind, call *ast.C Pos: formatArg.Pos(), End: formatArg.End(), Message: fmt.Sprintf("non-constant format string in call to %s", - fn.FullName()), + name), SuggestedFixes: []analysis.SuggestedFix{{ Message: `Insert "%s" format string`, TextEdits: []analysis.TextEdit{{ @@ -559,49 +540,46 @@ func checkPrintf(pass *analysis.Pass, fileVersion string, kind Kind, call *ast.C firstArg := idx + 1 // Arguments are immediately after format string. if !strings.Contains(format, "%") { if len(call.Args) > firstArg { - pass.Reportf(call.Lparen, "%s call has arguments but no formatting directives", fn.FullName()) + pass.Reportf(call.Lparen, "%s call has arguments but no formatting directives", name) } return } - // Hard part: check formats against args. - argNum := firstArg - maxArgNum := firstArg + + // Pass the string constant value so + // fmt.Sprintf("%"+("s"), "hi", 3) can be reported as + // "fmt.Sprintf call needs 1 arg but has 2 args". + operations, err := fmtstr.Parse(format, idx) + if err != nil { + // All error messages are in predicate form ("call has a problem") + // so that they may be affixed into a subject ("log.Printf "). + pass.ReportRangef(call.Args[idx], "%s %s", name, err) + return + } + + // index of the highest used index. + maxArgIndex := firstArg - 1 anyIndex := false - for i, w := 0, 0; i < len(format); i += w { - w = 1 - if format[i] != '%' { - continue - } - state := parsePrintfVerb(pass, call, fn.FullName(), format[i:], firstArg, argNum) - if state == nil { - return + // Check formats against args. + for _, operation := range operations { + if operation.Prec.Index != -1 || + operation.Width.Index != -1 || + operation.Verb.Index != -1 { + anyIndex = true } - w = len(state.format) - if !okPrintfArg(pass, call, state) { // One error per format is enough. + if !okPrintfArg(pass, call, &maxArgIndex, firstArg, name, operation) { + // One error per format is enough. return } - if state.hasIndex { - anyIndex = true - } - if state.verb == 'w' { + if operation.Verb.Verb == 'w' { switch kind { case KindNone, KindPrint, KindPrintf: - pass.Reportf(call.Pos(), "%s does not support error-wrapping directive %%w", state.name) + pass.Reportf(call.Pos(), "%s does not support error-wrapping directive %%w", name) return } } - if len(state.argNums) > 0 { - // Continue with the next sequential argument. - argNum = state.argNums[len(state.argNums)-1] + 1 - } - for _, n := range state.argNums { - if n >= maxArgNum { - maxArgNum = n + 1 - } - } } // Dotdotdot is hard. - if call.Ellipsis.IsValid() && maxArgNum >= len(call.Args)-1 { + if call.Ellipsis.IsValid() && maxArgIndex >= len(call.Args)-2 { return } // If any formats are indexed, extra arguments are ignored. @@ -609,147 +587,13 @@ func checkPrintf(pass *analysis.Pass, fileVersion string, kind Kind, call *ast.C return } // There should be no leftover arguments. - if maxArgNum != len(call.Args) { - expect := maxArgNum - firstArg + if maxArgIndex+1 < len(call.Args) { + expect := maxArgIndex + 1 - firstArg numArgs := len(call.Args) - firstArg - pass.ReportRangef(call, "%s call needs %v but has %v", fn.FullName(), count(expect, "arg"), count(numArgs, "arg")) - } -} - -// parseFlags accepts any printf flags. -func (s *formatState) parseFlags() { - for s.nbytes < len(s.format) { - switch c := s.format[s.nbytes]; c { - case '#', '0', '+', '-', ' ': - s.flags = append(s.flags, c) - s.nbytes++ - default: - return - } + pass.ReportRangef(call, "%s call needs %v but has %v", name, count(expect, "arg"), count(numArgs, "arg")) } } -// scanNum advances through a decimal number if present. -func (s *formatState) scanNum() { - for ; s.nbytes < len(s.format); s.nbytes++ { - c := s.format[s.nbytes] - if c < '0' || '9' < c { - return - } - } -} - -// parseIndex scans an index expression. It returns false if there is a syntax error. -func (s *formatState) parseIndex() bool { - if s.nbytes == len(s.format) || s.format[s.nbytes] != '[' { - return true - } - // Argument index present. - s.nbytes++ // skip '[' - start := s.nbytes - s.scanNum() - ok := true - if s.nbytes == len(s.format) || s.nbytes == start || s.format[s.nbytes] != ']' { - ok = false // syntax error is either missing "]" or invalid index. - s.nbytes = strings.Index(s.format[start:], "]") - if s.nbytes < 0 { - s.pass.ReportRangef(s.call, "%s format %s is missing closing ]", s.name, s.format) - return false - } - s.nbytes = s.nbytes + start - } - arg32, err := strconv.ParseInt(s.format[start:s.nbytes], 10, 32) - if err != nil || !ok || arg32 <= 0 || arg32 > int64(len(s.call.Args)-s.firstArg) { - s.pass.ReportRangef(s.call, "%s format has invalid argument index [%s]", s.name, s.format[start:s.nbytes]) - return false - } - s.nbytes++ // skip ']' - arg := int(arg32) - arg += s.firstArg - 1 // We want to zero-index the actual arguments. - s.argNum = arg - s.hasIndex = true - s.indexPending = true - return true -} - -// parseNum scans a width or precision (or *). It returns false if there's a bad index expression. -func (s *formatState) parseNum() bool { - if s.nbytes < len(s.format) && s.format[s.nbytes] == '*' { - if s.indexPending { // Absorb it. - s.indexPending = false - } - s.nbytes++ - s.argNums = append(s.argNums, s.argNum) - s.argNum++ - } else { - s.scanNum() - } - return true -} - -// parsePrecision scans for a precision. It returns false if there's a bad index expression. -func (s *formatState) parsePrecision() bool { - // If there's a period, there may be a precision. - if s.nbytes < len(s.format) && s.format[s.nbytes] == '.' { - s.flags = append(s.flags, '.') // Treat precision as a flag. - s.nbytes++ - if !s.parseIndex() { - return false - } - if !s.parseNum() { - return false - } - } - return true -} - -// parsePrintfVerb looks the formatting directive that begins the format string -// and returns a formatState that encodes what the directive wants, without looking -// at the actual arguments present in the call. The result is nil if there is an error. -func parsePrintfVerb(pass *analysis.Pass, call *ast.CallExpr, name, format string, firstArg, argNum int) *formatState { - state := &formatState{ - format: format, - name: name, - flags: make([]byte, 0, 5), - argNum: argNum, - argNums: make([]int, 0, 1), - nbytes: 1, // There's guaranteed to be a percent sign. - firstArg: firstArg, - pass: pass, - call: call, - } - // There may be flags. - state.parseFlags() - // There may be an index. - if !state.parseIndex() { - return nil - } - // There may be a width. - if !state.parseNum() { - return nil - } - // There may be a precision. - if !state.parsePrecision() { - return nil - } - // Now a verb, possibly prefixed by an index (which we may already have). - if !state.indexPending && !state.parseIndex() { - return nil - } - if state.nbytes == len(state.format) { - pass.ReportRangef(call.Fun, "%s format %s is missing verb at end of string", name, state.format) - return nil - } - verb, w := utf8.DecodeRuneInString(state.format[state.nbytes:]) - state.verb = verb - state.nbytes += w - if verb != '%' { - state.argNums = append(state.argNums, state.argNum) - } - state.format = state.format[:state.nbytes] - return state -} - // printfArgType encodes the types of expressions a printf verb accepts. It is a bitmask. type printfArgType int @@ -810,79 +654,96 @@ var printVerbs = []printVerb{ {'X', sharpNumFlag, argRune | argInt | argString | argPointer | argFloat | argComplex}, } -// okPrintfArg compares the formatState to the arguments actually present, -// reporting any discrepancies it can discern. If the final argument is ellipsissed, -// there's little it can do for that. -func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, state *formatState) (ok bool) { +// okPrintfArg compares the operation to the arguments actually present, +// reporting any discrepancies it can discern, maxArgIndex was the index of the highest used index. +// If the final argument is ellipsissed, there's little it can do for that. +func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, maxArgIndex *int, firstArg int, name string, operation *fmtstr.Operation) (ok bool) { + verb := operation.Verb.Verb var v printVerb found := false // Linear scan is fast enough for a small list. for _, v = range printVerbs { - if v.verb == state.verb { + if v.verb == verb { found = true break } } - // Could current arg implement fmt.Formatter? + // Could verb's arg implement fmt.Formatter? // Skip check for the %w verb, which requires an error. formatter := false - if v.typ != argError && state.argNum < len(call.Args) { - if tv, ok := pass.TypesInfo.Types[call.Args[state.argNum]]; ok { + if v.typ != argError && operation.Verb.ArgIndex < len(call.Args) { + if tv, ok := pass.TypesInfo.Types[call.Args[operation.Verb.ArgIndex]]; ok { formatter = isFormatter(tv.Type) } } if !formatter { if !found { - pass.ReportRangef(call, "%s format %s has unknown verb %c", state.name, state.format, state.verb) + pass.ReportRangef(call, "%s format %s has unknown verb %c", name, operation.Text, verb) return false } - for _, flag := range state.flags { + for _, flag := range operation.Flags { // TODO: Disable complaint about '0' for Go 1.10. To be fixed properly in 1.11. // See issues 23598 and 23605. if flag == '0' { continue } if !strings.ContainsRune(v.flags, rune(flag)) { - pass.ReportRangef(call, "%s format %s has unrecognized flag %c", state.name, state.format, flag) + pass.ReportRangef(call, "%s format %s has unrecognized flag %c", name, operation.Text, flag) return false } } } - // Verb is good. If len(state.argNums)>trueArgs, we have something like %.*s and all - // but the final arg must be an integer. - trueArgs := 1 - if state.verb == '%' { - trueArgs = 0 + + var argIndexes []int + // First check for *. + if operation.Width.Dynamic != -1 { + argIndexes = append(argIndexes, operation.Width.Dynamic) + } + if operation.Prec.Dynamic != -1 { + argIndexes = append(argIndexes, operation.Prec.Dynamic) } - nargs := len(state.argNums) - for i := 0; i < nargs-trueArgs; i++ { - argNum := state.argNums[i] - if !argCanBeChecked(pass, call, i, state) { + // If len(argIndexes)>0, we have something like %.*s and all + // indexes in argIndexes must be an integer. + for _, argIndex := range argIndexes { + if !argCanBeChecked(pass, call, argIndex, firstArg, operation, name) { return } - arg := call.Args[argNum] + arg := call.Args[argIndex] if reason, ok := matchArgType(pass, argInt, arg); !ok { details := "" if reason != "" { details = " (" + reason + ")" } - pass.ReportRangef(call, "%s format %s uses non-int %s%s as argument of *", state.name, state.format, analysisutil.Format(pass.Fset, arg), details) + pass.ReportRangef(call, "%s format %s uses non-int %s%s as argument of *", name, operation.Text, analysisinternal.Format(pass.Fset, arg), details) return false } } - if state.verb == '%' || formatter { + // Collect to update maxArgNum in one loop. + if operation.Verb.ArgIndex != -1 && verb != '%' { + argIndexes = append(argIndexes, operation.Verb.ArgIndex) + } + for _, index := range argIndexes { + *maxArgIndex = max(*maxArgIndex, index) + } + + // Special case for '%', go will print "fmt.Printf("%10.2%%dhello", 4)" + // as "%4hello", discard any runes between the two '%'s, and treat the verb '%' + // as an ordinary rune, so early return to skip the type check. + if verb == '%' || formatter { return true } - argNum := state.argNums[len(state.argNums)-1] - if !argCanBeChecked(pass, call, len(state.argNums)-1, state) { + + // Now check verb's type. + verbArgIndex := operation.Verb.ArgIndex + if !argCanBeChecked(pass, call, verbArgIndex, firstArg, operation, name) { return false } - arg := call.Args[argNum] - if isFunctionValue(pass, arg) && state.verb != 'p' && state.verb != 'T' { - pass.ReportRangef(call, "%s format %s arg %s is a func value, not called", state.name, state.format, analysisutil.Format(pass.Fset, arg)) + arg := call.Args[verbArgIndex] + if isFunctionValue(pass, arg) && verb != 'p' && verb != 'T' { + pass.ReportRangef(call, "%s format %s arg %s is a func value, not called", name, operation.Text, analysisinternal.Format(pass.Fset, arg)) return false } if reason, ok := matchArgType(pass, v.typ, arg); !ok { @@ -894,12 +755,12 @@ func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, state *formatState) (o if reason != "" { details = " (" + reason + ")" } - pass.ReportRangef(call, "%s format %s has arg %s of wrong type %s%s", state.name, state.format, analysisutil.Format(pass.Fset, arg), typeString, details) + pass.ReportRangef(call, "%s format %s has arg %s of wrong type %s%s", name, operation.Text, analysisinternal.Format(pass.Fset, arg), typeString, details) return false } - if v.typ&argString != 0 && v.verb != 'T' && !bytes.Contains(state.flags, []byte{'#'}) { + if v.typ&argString != 0 && v.verb != 'T' && !strings.Contains(operation.Flags, "#") { if methodName, ok := recursiveStringer(pass, arg); ok { - pass.ReportRangef(call, "%s format %s with arg %s causes recursive %s method call", state.name, state.format, analysisutil.Format(pass.Fset, arg), methodName) + pass.ReportRangef(call, "%s format %s with arg %s causes recursive %s method call", name, operation.Text, analysisinternal.Format(pass.Fset, arg), methodName) return false } } @@ -983,25 +844,24 @@ func isFunctionValue(pass *analysis.Pass, e ast.Expr) bool { // argCanBeChecked reports whether the specified argument is statically present; // it may be beyond the list of arguments or in a terminal slice... argument, which // means we can't see it. -func argCanBeChecked(pass *analysis.Pass, call *ast.CallExpr, formatArg int, state *formatState) bool { - argNum := state.argNums[formatArg] - if argNum <= 0 { +func argCanBeChecked(pass *analysis.Pass, call *ast.CallExpr, argIndex, firstArg int, operation *fmtstr.Operation, name string) bool { + if argIndex <= 0 { // Shouldn't happen, so catch it with prejudice. - panic("negative arg num") + panic("negative argIndex") } - if argNum < len(call.Args)-1 { + if argIndex < len(call.Args)-1 { return true // Always OK. } if call.Ellipsis.IsValid() { return false // We just can't tell; there could be many more arguments. } - if argNum < len(call.Args) { + if argIndex < len(call.Args) { return true } // There are bad indexes in the format or there are fewer arguments than the format needs. // This is the argument number relative to the format: Printf("%s", "hi") will give 1 for the "hi". - arg := argNum - state.firstArg + 1 // People think of arguments as 1-indexed. - pass.ReportRangef(call, "%s format %s reads arg #%d, but call has %v", state.name, state.format, arg, count(len(call.Args)-state.firstArg, "arg")) + arg := argIndex - firstArg + 1 // People think of arguments as 1-indexed. + pass.ReportRangef(call, "%s format %s reads arg #%d, but call has %v", name, operation.Text, arg, count(len(call.Args)-firstArg, "arg")) return false } @@ -1018,7 +878,7 @@ const ( ) // checkPrint checks a call to an unformatted print routine such as Println. -func checkPrint(pass *analysis.Pass, call *ast.CallExpr, fn *types.Func) { +func checkPrint(pass *analysis.Pass, call *ast.CallExpr, name string) { firstArg := 0 typ := pass.TypesInfo.Types[call.Fun].Type if typ == nil { @@ -1052,7 +912,7 @@ func checkPrint(pass *analysis.Pass, call *ast.CallExpr, fn *types.Func) { if sel, ok := call.Args[0].(*ast.SelectorExpr); ok { if x, ok := sel.X.(*ast.Ident); ok { if x.Name == "os" && strings.HasPrefix(sel.Sel.Name, "Std") { - pass.ReportRangef(call, "%s does not take io.Writer but has first arg %s", fn.FullName(), analysisutil.Format(pass.Fset, call.Args[0])) + pass.ReportRangef(call, "%s does not take io.Writer but has first arg %s", name, analysisinternal.Format(pass.Fset, call.Args[0])) } } } @@ -1066,25 +926,25 @@ func checkPrint(pass *analysis.Pass, call *ast.CallExpr, fn *types.Func) { if strings.Contains(s, "%") { m := printFormatRE.FindStringSubmatch(s) if m != nil { - pass.ReportRangef(call, "%s call has possible Printf formatting directive %s", fn.FullName(), m[0]) + pass.ReportRangef(call, "%s call has possible Printf formatting directive %s", name, m[0]) } } } - if strings.HasSuffix(fn.Name(), "ln") { + if strings.HasSuffix(name, "ln") { // The last item, if a string, should not have a newline. arg = args[len(args)-1] if s, ok := stringConstantExpr(pass, arg); ok { if strings.HasSuffix(s, "\n") { - pass.ReportRangef(call, "%s arg list ends with redundant newline", fn.FullName()) + pass.ReportRangef(call, "%s arg list ends with redundant newline", name) } } } for _, arg := range args { if isFunctionValue(pass, arg) { - pass.ReportRangef(call, "%s arg %s is a func value, not called", fn.FullName(), analysisutil.Format(pass.Fset, arg)) + pass.ReportRangef(call, "%s arg %s is a func value, not called", name, analysisinternal.Format(pass.Fset, arg)) } if methodName, ok := recursiveStringer(pass, arg); ok { - pass.ReportRangef(call, "%s arg %s causes recursive call to %s method", fn.FullName(), analysisutil.Format(pass.Fset, arg), methodName) + pass.ReportRangef(call, "%s arg %s causes recursive call to %s method", name, analysisinternal.Format(pass.Fset, arg), methodName) } } } diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/shift/shift.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/shift/shift.go index 759ed0043ff17c..46b5f6d68c612a 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/shift/shift.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/shift/shift.go @@ -19,8 +19,8 @@ import ( "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" - "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" + "golang.org/x/tools/internal/analysisinternal" "golang.org/x/tools/internal/typeparams" ) @@ -123,7 +123,7 @@ func checkLongShift(pass *analysis.Pass, node ast.Node, x, y ast.Expr) { } } if amt >= minSize { - ident := analysisutil.Format(pass.Fset, x) + ident := analysisinternal.Format(pass.Fset, x) qualifier := "" if len(sizes) > 1 { qualifier = "may be " diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/sigchanyzer/sigchanyzer.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/sigchanyzer/sigchanyzer.go index 5f121f720d8315..78a2fa5ea3bd34 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/sigchanyzer/sigchanyzer.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/sigchanyzer/sigchanyzer.go @@ -8,6 +8,8 @@ package sigchanyzer import ( "bytes" + "slices" + _ "embed" "go/ast" "go/format" @@ -18,6 +20,7 @@ import ( "golang.org/x/tools/go/analysis/passes/inspect" "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" + "golang.org/x/tools/internal/analysisinternal" ) //go:embed doc.go @@ -32,8 +35,8 @@ var Analyzer = &analysis.Analyzer{ Run: run, } -func run(pass *analysis.Pass) (interface{}, error) { - if !analysisutil.Imports(pass.Pkg, "os/signal") { +func run(pass *analysis.Pass) (any, error) { + if !analysisinternal.Imports(pass.Pkg, "os/signal") { return nil, nil // doesn't directly import signal } @@ -69,7 +72,7 @@ func run(pass *analysis.Pass) (interface{}, error) { // mutating the AST. See https://golang.org/issue/46129. chanDeclCopy := &ast.CallExpr{} *chanDeclCopy = *chanDecl - chanDeclCopy.Args = append([]ast.Expr(nil), chanDecl.Args...) + chanDeclCopy.Args = slices.Clone(chanDecl.Args) chanDeclCopy.Args = append(chanDeclCopy.Args, &ast.BasicLit{ Kind: token.INT, Value: "1", diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/slog/slog.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/slog/slog.go index 0129102a33695b..c1ac960435d41f 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/slog/slog.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/slog/slog.go @@ -20,6 +20,7 @@ import ( "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" "golang.org/x/tools/go/types/typeutil" + "golang.org/x/tools/internal/analysisinternal" "golang.org/x/tools/internal/typesinternal" ) @@ -114,10 +115,10 @@ func run(pass *analysis.Pass) (any, error) { default: if unknownArg == nil { pass.ReportRangef(arg, "%s arg %q should be a string or a slog.Attr (possible missing key or value)", - shortName(fn), analysisutil.Format(pass.Fset, arg)) + shortName(fn), analysisinternal.Format(pass.Fset, arg)) } else { pass.ReportRangef(arg, "%s arg %q should probably be a string or a slog.Attr (previous arg %q cannot be a key)", - shortName(fn), analysisutil.Format(pass.Fset, arg), analysisutil.Format(pass.Fset, unknownArg)) + shortName(fn), analysisinternal.Format(pass.Fset, arg), analysisinternal.Format(pass.Fset, unknownArg)) } // Stop here so we report at most one missing key per call. return @@ -157,7 +158,7 @@ func run(pass *analysis.Pass) (any, error) { } func isAttr(t types.Type) bool { - return analysisutil.IsNamedType(t, "log/slog", "Attr") + return analysisinternal.IsTypeNamed(t, "log/slog", "Attr") } // shortName returns a name for the function that is shorter than FullName. diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stdversion/stdversion.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stdversion/stdversion.go index 75d8697759eb62..429125a8b7d428 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stdversion/stdversion.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stdversion/stdversion.go @@ -11,6 +11,7 @@ import ( "go/build" "go/types" "regexp" + "slices" "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" @@ -46,16 +47,14 @@ func run(pass *analysis.Pass) (any, error) { // Prior to go1.22, versions.FileVersion returns only the // toolchain version, which is of no use to us, so // disable this analyzer on earlier versions. - if !slicesContains(build.Default.ReleaseTags, "go1.22") { + if !slices.Contains(build.Default.ReleaseTags, "go1.22") { return nil, nil } // Don't report diagnostics for modules marked before go1.21, // since at that time the go directive wasn't clearly // specified as a toolchain requirement. - // - // TODO(adonovan): after go1.21, call GoVersion directly. - pkgVersion := any(pass.Pkg).(interface{ GoVersion() string }).GoVersion() + pkgVersion := pass.Pkg.GoVersion() if !versions.AtLeast(pkgVersion, "go1.21") { return nil, nil } @@ -88,7 +87,7 @@ func run(pass *analysis.Pass) (any, error) { inspect.Preorder(nodeFilter, func(n ast.Node) { switch n := n.(type) { case *ast.File: - if isGenerated(n) { + if ast.IsGenerated(n) { // Suppress diagnostics in generated files (such as cgo). fileVersion = "" } else { @@ -115,19 +114,6 @@ func run(pass *analysis.Pass) (any, error) { return nil, nil } -// Reduced from x/tools/gopls/internal/golang/util.go. Good enough for now. -// TODO(adonovan): use ast.IsGenerated in go1.21. -func isGenerated(f *ast.File) bool { - for _, group := range f.Comments { - for _, comment := range group.List { - if matched := generatedRx.MatchString(comment.Text); matched { - return true - } - } - } - return false -} - // Matches cgo generated comment as well as the proposed standard: // // https://golang.org/s/generatedcode @@ -147,13 +133,3 @@ func origin(obj types.Object) types.Object { } return obj } - -// TODO(adonovan): use go1.21 slices.Contains. -func slicesContains[S ~[]E, E comparable](slice S, x E) bool { - for _, elem := range slice { - if elem == x { - return true - } - } - return false -} diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stringintconv/string.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stringintconv/string.go index 108600a2baf1a8..f56e6ecaa299b6 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stringintconv/string.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stringintconv/string.go @@ -198,14 +198,14 @@ func run(pass *analysis.Pass) (interface{}, error) { // the type has methods, as some {String,GoString,Format} // may change the behavior of fmt.Sprint. if len(ttypes) == 1 && len(vtypes) == 1 && types.NewMethodSet(V0).Len() == 0 { - fmtName, importEdits := analysisinternal.AddImport(pass.TypesInfo, file, arg.Pos(), "fmt", "fmt") + _, prefix, importEdits := analysisinternal.AddImport(pass.TypesInfo, file, "fmt", "fmt", "Sprint", arg.Pos()) if types.Identical(T0, types.Typ[types.String]) { // string(x) -> fmt.Sprint(x) addFix("Format the number as a decimal", append(importEdits, analysis.TextEdit{ Pos: call.Fun.Pos(), End: call.Fun.End(), - NewText: []byte(fmtName + ".Sprint"), + NewText: []byte(prefix + "Sprint"), }), ) } else { @@ -214,7 +214,7 @@ func run(pass *analysis.Pass) (interface{}, error) { analysis.TextEdit{ Pos: call.Lparen + 1, End: call.Lparen + 1, - NewText: []byte(fmtName + ".Sprint("), + NewText: []byte(prefix + "Sprint("), }, analysis.TextEdit{ Pos: call.Rparen, diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/structtag/structtag.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/structtag/structtag.go index a0beb46bd143b6..4115ef769430b2 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/structtag/structtag.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/structtag/structtag.go @@ -89,7 +89,7 @@ var checkTagSpaces = map[string]bool{"json": true, "xml": true, "asn1": true} // checkCanonicalFieldTag checks a single struct field tag. func checkCanonicalFieldTag(pass *analysis.Pass, field *types.Var, tag string, seen *namesSeen) { switch pass.Pkg.Path() { - case "encoding/json", "encoding/xml": + case "encoding/json", "encoding/json/v2", "encoding/xml": // These packages know how to use their own APIs. // Sometimes they are testing what happens to incorrect programs. return diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/testinggoroutine.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/testinggoroutine.go index effcdc5700b16d..fef5a6014c41db 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/testinggoroutine.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/testinggoroutine.go @@ -16,6 +16,7 @@ import ( "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" "golang.org/x/tools/go/types/typeutil" + "golang.org/x/tools/internal/analysisinternal" ) //go:embed doc.go @@ -38,7 +39,7 @@ var Analyzer = &analysis.Analyzer{ func run(pass *analysis.Pass) (interface{}, error) { inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) - if !analysisutil.Imports(pass.Pkg, "testing") { + if !analysisinternal.Imports(pass.Pkg, "testing") { return nil, nil } diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/util.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/util.go index 8c7a51ca525dda..027c99e6b0f931 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/util.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/util.go @@ -36,6 +36,8 @@ func localFunctionDecls(info *types.Info, files []*ast.File) func(*types.Func) * // isMethodNamed returns true if f is a method defined // in package with the path pkgPath with a name in names. +// +// (Unlike [analysisinternal.IsMethodNamed], it ignores the receiver type name.) func isMethodNamed(f *types.Func, pkgPath string, names ...string) bool { if f == nil { return false diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/tests/tests.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/tests/tests.go index 36f2c43eb64d30..285b34218c3f16 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/tests/tests.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/tests/tests.go @@ -16,6 +16,7 @@ import ( "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/internal/analysisutil" + "golang.org/x/tools/internal/analysisinternal" ) //go:embed doc.go @@ -257,7 +258,7 @@ func isTestingType(typ types.Type, testingType string) bool { if !ok { return false } - return analysisutil.IsNamedType(ptr.Elem(), "testing", testingType) + return analysisinternal.IsTypeNamed(ptr.Elem(), "testing", testingType) } // Validate that fuzz target function's arguments are of accepted types. diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/timeformat/timeformat.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/timeformat/timeformat.go index 4a6c6b8bc6cc5c..4fdbb2b5415eff 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/timeformat/timeformat.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/timeformat/timeformat.go @@ -19,6 +19,7 @@ import ( "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" "golang.org/x/tools/go/types/typeutil" + "golang.org/x/tools/internal/analysisinternal" ) const badFormat = "2006-02-01" @@ -35,7 +36,7 @@ var Analyzer = &analysis.Analyzer{ Run: run, } -func run(pass *analysis.Pass) (interface{}, error) { +func run(pass *analysis.Pass) (any, error) { // Note: (time.Time).Format is a method and can be a typeutil.Callee // without directly importing "time". So we cannot just skip this package // when !analysisutil.Imports(pass.Pkg, "time"). @@ -48,11 +49,9 @@ func run(pass *analysis.Pass) (interface{}, error) { } inspect.Preorder(nodeFilter, func(n ast.Node) { call := n.(*ast.CallExpr) - fn, ok := typeutil.Callee(pass.TypesInfo, call).(*types.Func) - if !ok { - return - } - if !isTimeDotFormat(fn) && !isTimeDotParse(fn) { + obj := typeutil.Callee(pass.TypesInfo, call) + if !analysisinternal.IsMethodNamed(obj, "time", "Time", "Format") && + !analysisinternal.IsFunctionNamed(obj, "time", "Parse") { return } if len(call.Args) > 0 { @@ -87,19 +86,6 @@ func run(pass *analysis.Pass) (interface{}, error) { return nil, nil } -func isTimeDotFormat(f *types.Func) bool { - if f.Name() != "Format" || f.Pkg() == nil || f.Pkg().Path() != "time" { - return false - } - // Verify that the receiver is time.Time. - recv := f.Type().(*types.Signature).Recv() - return recv != nil && analysisutil.IsNamedType(recv.Type(), "time", "Time") -} - -func isTimeDotParse(f *types.Func) bool { - return analysisutil.IsFunctionNamed(f, "time", "Parse") -} - // badFormatAt return the start of a bad format in e or -1 if no bad format is found. func badFormatAt(info *types.Info, e ast.Expr) int { tv, ok := info.Types[e] diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go index a7889fa4590837..26e894bd4000eb 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go @@ -28,7 +28,7 @@ var Analyzer = &analysis.Analyzer{ Run: run, } -func run(pass *analysis.Pass) (interface{}, error) { +func run(pass *analysis.Pass) (any, error) { switch pass.Pkg.Path() { case "encoding/gob", "encoding/json", "encoding/xml", "encoding/asn1": // These packages know how to use their own APIs. diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unreachable/doc.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unreachable/doc.go index d17d0d9444e1f4..325a15358d5939 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unreachable/doc.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unreachable/doc.go @@ -9,6 +9,6 @@ // unreachable: check for unreachable code // // The unreachable analyzer finds statements that execution can never reach -// because they are preceded by an return statement, a call to panic, an +// because they are preceded by a return statement, a call to panic, an // infinite loop, or similar constructs. package unreachable diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/unsafeptr.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/unsafeptr.go index 272ae7fe045e3e..fb5b944faad08d 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/unsafeptr.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/unsafeptr.go @@ -16,6 +16,7 @@ import ( "golang.org/x/tools/go/analysis/passes/inspect" "golang.org/x/tools/go/analysis/passes/internal/analysisutil" "golang.org/x/tools/go/ast/inspector" + "golang.org/x/tools/internal/analysisinternal" ) //go:embed doc.go @@ -104,7 +105,7 @@ func isSafeUintptr(info *types.Info, x ast.Expr) bool { } switch sel.Sel.Name { case "Pointer", "UnsafeAddr": - if analysisutil.IsNamedType(info.Types[sel.X].Type, "reflect", "Value") { + if analysisinternal.IsTypeNamed(info.Types[sel.X].Type, "reflect", "Value") { return true } } @@ -152,5 +153,5 @@ func hasBasicType(info *types.Info, x ast.Expr, kind types.BasicKind) bool { // isReflectHeader reports whether t is reflect.SliceHeader or reflect.StringHeader. func isReflectHeader(t types.Type) bool { - return analysisutil.IsNamedType(t, "reflect", "SliceHeader", "StringHeader") + return analysisinternal.IsTypeNamed(t, "reflect", "SliceHeader", "StringHeader") } diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unusedresult/unusedresult.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unusedresult/unusedresult.go index c27d26dd6ec010..d7cc1e6ae2c7cf 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unusedresult/unusedresult.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unusedresult/unusedresult.go @@ -131,7 +131,7 @@ func run(pass *analysis.Pass) (interface{}, error) { // func() string var sigNoArgsStringResult = types.NewSignature(nil, nil, - types.NewTuple(types.NewVar(token.NoPos, nil, "", types.Typ[types.String])), + types.NewTuple(types.NewParam(token.NoPos, nil, "", types.Typ[types.String])), false) type stringSetFlag map[string]bool diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go index 1a9b3094e5e577..82c3db6a39db74 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go +++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go @@ -367,17 +367,26 @@ func run(fset *token.FileSet, cfg *Config, analyzers []*analysis.Analyzer) ([]re } pass := &analysis.Pass{ - Analyzer: a, - Fset: fset, - Files: files, - OtherFiles: cfg.NonGoFiles, - IgnoredFiles: cfg.IgnoredFiles, - Pkg: pkg, - TypesInfo: info, - TypesSizes: tc.Sizes, - TypeErrors: nil, // unitchecker doesn't RunDespiteErrors - ResultOf: inputs, - Report: func(d analysis.Diagnostic) { act.diagnostics = append(act.diagnostics, d) }, + Analyzer: a, + Fset: fset, + Files: files, + OtherFiles: cfg.NonGoFiles, + IgnoredFiles: cfg.IgnoredFiles, + Pkg: pkg, + TypesInfo: info, + TypesSizes: tc.Sizes, + TypeErrors: nil, // unitchecker doesn't RunDespiteErrors + ResultOf: inputs, + Report: func(d analysis.Diagnostic) { + // Unitchecker doesn't apply fixes, but it does report them in the JSON output. + if err := analysisinternal.ValidateFixes(fset, a, d.SuggestedFixes); err != nil { + // Since we have diagnostics, the exit code will be nonzero, + // so logging these errors is sufficient. + log.Println(err) + d.SuggestedFixes = nil + } + act.diagnostics = append(act.diagnostics, d) + }, ImportObjectFact: facts.ImportObjectFact, ExportObjectFact: facts.ExportObjectFact, AllObjectFacts: func() []analysis.ObjectFact { return facts.AllObjectFacts(factFilter) }, @@ -386,7 +395,7 @@ func run(fset *token.FileSet, cfg *Config, analyzers []*analysis.Analyzer) ([]re AllPackageFacts: func() []analysis.PackageFact { return facts.AllPackageFacts(factFilter) }, Module: module, } - pass.ReadFile = analysisinternal.MakeReadFile(pass) + pass.ReadFile = analysisinternal.CheckedReadFile(pass, os.ReadFile) t0 := time.Now() act.result, act.err = a.Run(pass) diff --git a/src/cmd/vendor/golang.org/x/tools/go/ast/inspector/inspector.go b/src/cmd/vendor/golang.org/x/tools/go/ast/inspector/inspector.go index 958cf38deb00a4..0d5050fe40510f 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/ast/inspector/inspector.go +++ b/src/cmd/vendor/golang.org/x/tools/go/ast/inspector/inspector.go @@ -36,6 +36,9 @@ package inspector import ( "go/ast" + _ "unsafe" + + "golang.org/x/tools/internal/astutil/edge" ) // An Inspector provides methods for inspecting @@ -44,6 +47,24 @@ type Inspector struct { events []event } +//go:linkname events +func events(in *Inspector) []event { return in.events } + +func packEdgeKindAndIndex(ek edge.Kind, index int) int32 { + return int32(uint32(index+1)<<7 | uint32(ek)) +} + +// unpackEdgeKindAndIndex unpacks the edge kind and edge index (within +// an []ast.Node slice) from the parent field of a pop event. +// +//go:linkname unpackEdgeKindAndIndex +func unpackEdgeKindAndIndex(x int32) (edge.Kind, int) { + // The "parent" field of a pop node holds the + // edge Kind in the lower 7 bits and the index+1 + // in the upper 25. + return edge.Kind(x & 0x7f), int(x>>7) - 1 +} + // New returns an Inspector for the specified syntax trees. func New(files []*ast.File) *Inspector { return &Inspector{traverse(files)} @@ -52,9 +73,10 @@ func New(files []*ast.File) *Inspector { // An event represents a push or a pop // of an ast.Node during a traversal. type event struct { - node ast.Node - typ uint64 // typeOf(node) on push event, or union of typ strictly between push and pop events on pop events - index int // index of corresponding push or pop event + node ast.Node + typ uint64 // typeOf(node) on push event, or union of typ strictly between push and pop events on pop events + index int32 // index of corresponding push or pop event + parent int32 // index of parent's push node (push nodes only), or packed edge kind/index (pop nodes only) } // TODO: Experiment with storing only the second word of event.node (unsafe.Pointer). @@ -83,7 +105,7 @@ func (in *Inspector) Preorder(types []ast.Node, f func(ast.Node)) { // }) mask := maskOf(types) - for i := 0; i < len(in.events); { + for i := int32(0); i < int32(len(in.events)); { ev := in.events[i] if ev.index > i { // push @@ -113,7 +135,7 @@ func (in *Inspector) Preorder(types []ast.Node, f func(ast.Node)) { // matches an element of the types slice. func (in *Inspector) Nodes(types []ast.Node, f func(n ast.Node, push bool) (proceed bool)) { mask := maskOf(types) - for i := 0; i < len(in.events); { + for i := int32(0); i < int32(len(in.events)); { ev := in.events[i] if ev.index > i { // push @@ -147,7 +169,7 @@ func (in *Inspector) Nodes(types []ast.Node, f func(n ast.Node, push bool) (proc func (in *Inspector) WithStack(types []ast.Node, f func(n ast.Node, push bool, stack []ast.Node) (proceed bool)) { mask := maskOf(types) var stack []ast.Node - for i := 0; i < len(in.events); { + for i := int32(0); i < int32(len(in.events)); { ev := in.events[i] if ev.index > i { // push @@ -189,43 +211,74 @@ func traverse(files []*ast.File) []event { extent += int(f.End() - f.Pos()) } // This estimate is based on the net/http package. - capacity := extent * 33 / 100 - if capacity > 1e6 { - capacity = 1e6 // impose some reasonable maximum + capacity := min(extent*33/100, 1e6) // impose some reasonable maximum (1M) + + v := &visitor{ + events: make([]event, 0, capacity), + stack: []item{{index: -1}}, // include an extra event so file nodes have a parent + } + for _, file := range files { + walk(v, edge.Invalid, -1, file) } - events := make([]event, 0, capacity) + return v.events +} - var stack []event - stack = append(stack, event{}) // include an extra event so file nodes have a parent - for _, f := range files { - ast.Inspect(f, func(n ast.Node) bool { - if n != nil { - // push - ev := event{ - node: n, - typ: 0, // temporarily used to accumulate type bits of subtree - index: len(events), // push event temporarily holds own index - } - stack = append(stack, ev) - events = append(events, ev) - } else { - // pop - top := len(stack) - 1 - ev := stack[top] - typ := typeOf(ev.node) - push := ev.index - parent := top - 1 - - events[push].typ = typ // set type of push - stack[parent].typ |= typ | ev.typ // parent's typ contains push and pop's typs. - events[push].index = len(events) // make push refer to pop - - stack = stack[:top] - events = append(events, ev) - } - return true - }) +type visitor struct { + events []event + stack []item +} + +type item struct { + index int32 // index of current node's push event + parentIndex int32 // index of parent node's push event + typAccum uint64 // accumulated type bits of current node's descendents + edgeKindAndIndex int32 // edge.Kind and index, bit packed +} + +func (v *visitor) push(ek edge.Kind, eindex int, node ast.Node) { + var ( + index = int32(len(v.events)) + parentIndex = v.stack[len(v.stack)-1].index + ) + v.events = append(v.events, event{ + node: node, + parent: parentIndex, + typ: typeOf(node), + index: 0, // (pop index is set later by visitor.pop) + }) + v.stack = append(v.stack, item{ + index: index, + parentIndex: parentIndex, + edgeKindAndIndex: packEdgeKindAndIndex(ek, eindex), + }) + + // 2B nodes ought to be enough for anyone! + if int32(len(v.events)) < 0 { + panic("event index exceeded int32") } - return events + // 32M elements in an []ast.Node ought to be enough for anyone! + if ek2, eindex2 := unpackEdgeKindAndIndex(packEdgeKindAndIndex(ek, eindex)); ek2 != ek || eindex2 != eindex { + panic("Node slice index exceeded uint25") + } +} + +func (v *visitor) pop(node ast.Node) { + top := len(v.stack) - 1 + current := v.stack[top] + + push := &v.events[current.index] + parent := &v.stack[top-1] + + push.index = int32(len(v.events)) // make push event refer to pop + parent.typAccum |= current.typAccum | push.typ // accumulate type bits into parent + + v.stack = v.stack[:top] + + v.events = append(v.events, event{ + node: node, + typ: current.typAccum, + index: current.index, + parent: current.edgeKindAndIndex, // see [unpackEdgeKindAndIndex] + }) } diff --git a/src/cmd/vendor/golang.org/x/tools/go/ast/inspector/iter.go b/src/cmd/vendor/golang.org/x/tools/go/ast/inspector/iter.go index b7e959114cb0b4..c576dc70ac7093 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/ast/inspector/iter.go +++ b/src/cmd/vendor/golang.org/x/tools/go/ast/inspector/iter.go @@ -26,7 +26,7 @@ func (in *Inspector) PreorderSeq(types ...ast.Node) iter.Seq[ast.Node] { return func(yield func(ast.Node) bool) { mask := maskOf(types) - for i := 0; i < len(in.events); { + for i := int32(0); i < int32(len(in.events)); { ev := in.events[i] if ev.index > i { // push @@ -63,7 +63,7 @@ func All[N interface { mask := typeOf((N)(nil)) return func(yield func(N) bool) { - for i := 0; i < len(in.events); { + for i := int32(0); i < int32(len(in.events)); { ev := in.events[i] if ev.index > i { // push diff --git a/src/cmd/vendor/golang.org/x/tools/go/ast/inspector/typeof.go b/src/cmd/vendor/golang.org/x/tools/go/ast/inspector/typeof.go index 2a872f89d47d23..97784484578d50 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/ast/inspector/typeof.go +++ b/src/cmd/vendor/golang.org/x/tools/go/ast/inspector/typeof.go @@ -12,6 +12,8 @@ package inspector import ( "go/ast" "math" + + _ "unsafe" ) const ( @@ -215,8 +217,9 @@ func typeOf(n ast.Node) uint64 { return 0 } +//go:linkname maskOf func maskOf(nodes []ast.Node) uint64 { - if nodes == nil { + if len(nodes) == 0 { return math.MaxUint64 // match all node types } var mask uint64 diff --git a/src/cmd/vendor/golang.org/x/tools/go/ast/inspector/walk.go b/src/cmd/vendor/golang.org/x/tools/go/ast/inspector/walk.go new file mode 100644 index 00000000000000..5a42174a0a0077 --- /dev/null +++ b/src/cmd/vendor/golang.org/x/tools/go/ast/inspector/walk.go @@ -0,0 +1,341 @@ +// Copyright 2025 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package inspector + +// This file is a fork of ast.Inspect to reduce unnecessary dynamic +// calls and to gather edge information. +// +// Consistency with the original is ensured by TestInspectAllNodes. + +import ( + "fmt" + "go/ast" + + "golang.org/x/tools/internal/astutil/edge" +) + +func walkList[N ast.Node](v *visitor, ek edge.Kind, list []N) { + for i, node := range list { + walk(v, ek, i, node) + } +} + +func walk(v *visitor, ek edge.Kind, index int, node ast.Node) { + v.push(ek, index, node) + + // walk children + // (the order of the cases matches the order + // of the corresponding node types in ast.go) + switch n := node.(type) { + // Comments and fields + case *ast.Comment: + // nothing to do + + case *ast.CommentGroup: + walkList(v, edge.CommentGroup_List, n.List) + + case *ast.Field: + if n.Doc != nil { + walk(v, edge.Field_Doc, -1, n.Doc) + } + walkList(v, edge.Field_Names, n.Names) + if n.Type != nil { + walk(v, edge.Field_Type, -1, n.Type) + } + if n.Tag != nil { + walk(v, edge.Field_Tag, -1, n.Tag) + } + if n.Comment != nil { + walk(v, edge.Field_Comment, -1, n.Comment) + } + + case *ast.FieldList: + walkList(v, edge.FieldList_List, n.List) + + // Expressions + case *ast.BadExpr, *ast.Ident, *ast.BasicLit: + // nothing to do + + case *ast.Ellipsis: + if n.Elt != nil { + walk(v, edge.Ellipsis_Elt, -1, n.Elt) + } + + case *ast.FuncLit: + walk(v, edge.FuncLit_Type, -1, n.Type) + walk(v, edge.FuncLit_Body, -1, n.Body) + + case *ast.CompositeLit: + if n.Type != nil { + walk(v, edge.CompositeLit_Type, -1, n.Type) + } + walkList(v, edge.CompositeLit_Elts, n.Elts) + + case *ast.ParenExpr: + walk(v, edge.ParenExpr_X, -1, n.X) + + case *ast.SelectorExpr: + walk(v, edge.SelectorExpr_X, -1, n.X) + walk(v, edge.SelectorExpr_Sel, -1, n.Sel) + + case *ast.IndexExpr: + walk(v, edge.IndexExpr_X, -1, n.X) + walk(v, edge.IndexExpr_Index, -1, n.Index) + + case *ast.IndexListExpr: + walk(v, edge.IndexListExpr_X, -1, n.X) + walkList(v, edge.IndexListExpr_Indices, n.Indices) + + case *ast.SliceExpr: + walk(v, edge.SliceExpr_X, -1, n.X) + if n.Low != nil { + walk(v, edge.SliceExpr_Low, -1, n.Low) + } + if n.High != nil { + walk(v, edge.SliceExpr_High, -1, n.High) + } + if n.Max != nil { + walk(v, edge.SliceExpr_Max, -1, n.Max) + } + + case *ast.TypeAssertExpr: + walk(v, edge.TypeAssertExpr_X, -1, n.X) + if n.Type != nil { + walk(v, edge.TypeAssertExpr_Type, -1, n.Type) + } + + case *ast.CallExpr: + walk(v, edge.CallExpr_Fun, -1, n.Fun) + walkList(v, edge.CallExpr_Args, n.Args) + + case *ast.StarExpr: + walk(v, edge.StarExpr_X, -1, n.X) + + case *ast.UnaryExpr: + walk(v, edge.UnaryExpr_X, -1, n.X) + + case *ast.BinaryExpr: + walk(v, edge.BinaryExpr_X, -1, n.X) + walk(v, edge.BinaryExpr_Y, -1, n.Y) + + case *ast.KeyValueExpr: + walk(v, edge.KeyValueExpr_Key, -1, n.Key) + walk(v, edge.KeyValueExpr_Value, -1, n.Value) + + // Types + case *ast.ArrayType: + if n.Len != nil { + walk(v, edge.ArrayType_Len, -1, n.Len) + } + walk(v, edge.ArrayType_Elt, -1, n.Elt) + + case *ast.StructType: + walk(v, edge.StructType_Fields, -1, n.Fields) + + case *ast.FuncType: + if n.TypeParams != nil { + walk(v, edge.FuncType_TypeParams, -1, n.TypeParams) + } + if n.Params != nil { + walk(v, edge.FuncType_Params, -1, n.Params) + } + if n.Results != nil { + walk(v, edge.FuncType_Results, -1, n.Results) + } + + case *ast.InterfaceType: + walk(v, edge.InterfaceType_Methods, -1, n.Methods) + + case *ast.MapType: + walk(v, edge.MapType_Key, -1, n.Key) + walk(v, edge.MapType_Value, -1, n.Value) + + case *ast.ChanType: + walk(v, edge.ChanType_Value, -1, n.Value) + + // Statements + case *ast.BadStmt: + // nothing to do + + case *ast.DeclStmt: + walk(v, edge.DeclStmt_Decl, -1, n.Decl) + + case *ast.EmptyStmt: + // nothing to do + + case *ast.LabeledStmt: + walk(v, edge.LabeledStmt_Label, -1, n.Label) + walk(v, edge.LabeledStmt_Stmt, -1, n.Stmt) + + case *ast.ExprStmt: + walk(v, edge.ExprStmt_X, -1, n.X) + + case *ast.SendStmt: + walk(v, edge.SendStmt_Chan, -1, n.Chan) + walk(v, edge.SendStmt_Value, -1, n.Value) + + case *ast.IncDecStmt: + walk(v, edge.IncDecStmt_X, -1, n.X) + + case *ast.AssignStmt: + walkList(v, edge.AssignStmt_Lhs, n.Lhs) + walkList(v, edge.AssignStmt_Rhs, n.Rhs) + + case *ast.GoStmt: + walk(v, edge.GoStmt_Call, -1, n.Call) + + case *ast.DeferStmt: + walk(v, edge.DeferStmt_Call, -1, n.Call) + + case *ast.ReturnStmt: + walkList(v, edge.ReturnStmt_Results, n.Results) + + case *ast.BranchStmt: + if n.Label != nil { + walk(v, edge.BranchStmt_Label, -1, n.Label) + } + + case *ast.BlockStmt: + walkList(v, edge.BlockStmt_List, n.List) + + case *ast.IfStmt: + if n.Init != nil { + walk(v, edge.IfStmt_Init, -1, n.Init) + } + walk(v, edge.IfStmt_Cond, -1, n.Cond) + walk(v, edge.IfStmt_Body, -1, n.Body) + if n.Else != nil { + walk(v, edge.IfStmt_Else, -1, n.Else) + } + + case *ast.CaseClause: + walkList(v, edge.CaseClause_List, n.List) + walkList(v, edge.CaseClause_Body, n.Body) + + case *ast.SwitchStmt: + if n.Init != nil { + walk(v, edge.SwitchStmt_Init, -1, n.Init) + } + if n.Tag != nil { + walk(v, edge.SwitchStmt_Tag, -1, n.Tag) + } + walk(v, edge.SwitchStmt_Body, -1, n.Body) + + case *ast.TypeSwitchStmt: + if n.Init != nil { + walk(v, edge.TypeSwitchStmt_Init, -1, n.Init) + } + walk(v, edge.TypeSwitchStmt_Assign, -1, n.Assign) + walk(v, edge.TypeSwitchStmt_Body, -1, n.Body) + + case *ast.CommClause: + if n.Comm != nil { + walk(v, edge.CommClause_Comm, -1, n.Comm) + } + walkList(v, edge.CommClause_Body, n.Body) + + case *ast.SelectStmt: + walk(v, edge.SelectStmt_Body, -1, n.Body) + + case *ast.ForStmt: + if n.Init != nil { + walk(v, edge.ForStmt_Init, -1, n.Init) + } + if n.Cond != nil { + walk(v, edge.ForStmt_Cond, -1, n.Cond) + } + if n.Post != nil { + walk(v, edge.ForStmt_Post, -1, n.Post) + } + walk(v, edge.ForStmt_Body, -1, n.Body) + + case *ast.RangeStmt: + if n.Key != nil { + walk(v, edge.RangeStmt_Key, -1, n.Key) + } + if n.Value != nil { + walk(v, edge.RangeStmt_Value, -1, n.Value) + } + walk(v, edge.RangeStmt_X, -1, n.X) + walk(v, edge.RangeStmt_Body, -1, n.Body) + + // Declarations + case *ast.ImportSpec: + if n.Doc != nil { + walk(v, edge.ImportSpec_Doc, -1, n.Doc) + } + if n.Name != nil { + walk(v, edge.ImportSpec_Name, -1, n.Name) + } + walk(v, edge.ImportSpec_Path, -1, n.Path) + if n.Comment != nil { + walk(v, edge.ImportSpec_Comment, -1, n.Comment) + } + + case *ast.ValueSpec: + if n.Doc != nil { + walk(v, edge.ValueSpec_Doc, -1, n.Doc) + } + walkList(v, edge.ValueSpec_Names, n.Names) + if n.Type != nil { + walk(v, edge.ValueSpec_Type, -1, n.Type) + } + walkList(v, edge.ValueSpec_Values, n.Values) + if n.Comment != nil { + walk(v, edge.ValueSpec_Comment, -1, n.Comment) + } + + case *ast.TypeSpec: + if n.Doc != nil { + walk(v, edge.TypeSpec_Doc, -1, n.Doc) + } + walk(v, edge.TypeSpec_Name, -1, n.Name) + if n.TypeParams != nil { + walk(v, edge.TypeSpec_TypeParams, -1, n.TypeParams) + } + walk(v, edge.TypeSpec_Type, -1, n.Type) + if n.Comment != nil { + walk(v, edge.TypeSpec_Comment, -1, n.Comment) + } + + case *ast.BadDecl: + // nothing to do + + case *ast.GenDecl: + if n.Doc != nil { + walk(v, edge.GenDecl_Doc, -1, n.Doc) + } + walkList(v, edge.GenDecl_Specs, n.Specs) + + case *ast.FuncDecl: + if n.Doc != nil { + walk(v, edge.FuncDecl_Doc, -1, n.Doc) + } + if n.Recv != nil { + walk(v, edge.FuncDecl_Recv, -1, n.Recv) + } + walk(v, edge.FuncDecl_Name, -1, n.Name) + walk(v, edge.FuncDecl_Type, -1, n.Type) + if n.Body != nil { + walk(v, edge.FuncDecl_Body, -1, n.Body) + } + + case *ast.File: + if n.Doc != nil { + walk(v, edge.File_Doc, -1, n.Doc) + } + walk(v, edge.File_Name, -1, n.Name) + walkList(v, edge.File_Decls, n.Decls) + // don't walk n.Comments - they have been + // visited already through the individual + // nodes + + default: + // (includes *ast.Package) + panic(fmt.Sprintf("Walk: unexpected node type %T", n)) + } + + v.pop(node) +} diff --git a/src/cmd/vendor/golang.org/x/tools/go/types/typeutil/map.go b/src/cmd/vendor/golang.org/x/tools/go/types/typeutil/map.go index 8d824f7140f456..b6d542c64ee64a 100644 --- a/src/cmd/vendor/golang.org/x/tools/go/types/typeutil/map.go +++ b/src/cmd/vendor/golang.org/x/tools/go/types/typeutil/map.go @@ -2,30 +2,35 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package typeutil defines various utilities for types, such as Map, -// a mapping from types.Type to any values. -package typeutil // import "golang.org/x/tools/go/types/typeutil" +// Package typeutil defines various utilities for types, such as [Map], +// a hash table that maps [types.Type] to any value. +package typeutil import ( "bytes" "fmt" "go/types" - "reflect" + "hash/maphash" + "unsafe" "golang.org/x/tools/internal/typeparams" ) // Map is a hash-table-based mapping from types (types.Type) to -// arbitrary any values. The concrete types that implement +// arbitrary values. The concrete types that implement // the Type interface are pointers. Since they are not canonicalized, // == cannot be used to check for equivalence, and thus we cannot // simply use a Go map. // // Just as with map[K]V, a nil *Map is a valid empty map. // -// Not thread-safe. +// Read-only map operations ([Map.At], [Map.Len], and so on) may +// safely be called concurrently. +// +// TODO(adonovan): deprecate in favor of https://go.dev/issues/69420 +// and 69559, if the latter proposals for a generic hash-map type and +// a types.Hash function are accepted. type Map struct { - hasher Hasher // shared by many Maps table map[uint32][]entry // maps hash to bucket; entry.key==nil means unused length int // number of map entries } @@ -36,35 +41,17 @@ type entry struct { value any } -// SetHasher sets the hasher used by Map. -// -// All Hashers are functionally equivalent but contain internal state -// used to cache the results of hashing previously seen types. -// -// A single Hasher created by MakeHasher() may be shared among many -// Maps. This is recommended if the instances have many keys in -// common, as it will amortize the cost of hash computation. -// -// A Hasher may grow without bound as new types are seen. Even when a -// type is deleted from the map, the Hasher never shrinks, since other -// types in the map may reference the deleted type indirectly. +// SetHasher has no effect. // -// Hashers are not thread-safe, and read-only operations such as -// Map.Lookup require updates to the hasher, so a full Mutex lock (not a -// read-lock) is require around all Map operations if a shared -// hasher is accessed from multiple threads. -// -// If SetHasher is not called, the Map will create a private hasher at -// the first call to Insert. -func (m *Map) SetHasher(hasher Hasher) { - m.hasher = hasher -} +// It is a relic of an optimization that is no longer profitable. Do +// not use [Hasher], [MakeHasher], or [SetHasher] in new code. +func (m *Map) SetHasher(Hasher) {} // Delete removes the entry with the given key, if any. // It returns true if the entry was found. func (m *Map) Delete(key types.Type) bool { if m != nil && m.table != nil { - hash := m.hasher.Hash(key) + hash := hash(key) bucket := m.table[hash] for i, e := range bucket { if e.key != nil && types.Identical(key, e.key) { @@ -83,7 +70,7 @@ func (m *Map) Delete(key types.Type) bool { // The result is nil if the entry is not present. func (m *Map) At(key types.Type) any { if m != nil && m.table != nil { - for _, e := range m.table[m.hasher.Hash(key)] { + for _, e := range m.table[hash(key)] { if e.key != nil && types.Identical(key, e.key) { return e.value } @@ -96,7 +83,7 @@ func (m *Map) At(key types.Type) any { // and returns the previous entry, if any. func (m *Map) Set(key types.Type, value any) (prev any) { if m.table != nil { - hash := m.hasher.Hash(key) + hash := hash(key) bucket := m.table[hash] var hole *entry for i, e := range bucket { @@ -115,10 +102,7 @@ func (m *Map) Set(key types.Type, value any) (prev any) { m.table[hash] = append(bucket, entry{key, value}) } } else { - if m.hasher.memo == nil { - m.hasher = MakeHasher() - } - hash := m.hasher.Hash(key) + hash := hash(key) m.table = map[uint32][]entry{hash: {entry{key, value}}} } @@ -195,53 +179,35 @@ func (m *Map) KeysString() string { return m.toString(false) } -//////////////////////////////////////////////////////////////////////// -// Hasher - -// A Hasher maps each type to its hash value. -// For efficiency, a hasher uses memoization; thus its memory -// footprint grows monotonically over time. -// Hashers are not thread-safe. -// Hashers have reference semantics. -// Call MakeHasher to create a Hasher. -type Hasher struct { - memo map[types.Type]uint32 - - // ptrMap records pointer identity. - ptrMap map[any]uint32 - - // sigTParams holds type parameters from the signature being hashed. - // Signatures are considered identical modulo renaming of type parameters, so - // within the scope of a signature type the identity of the signature's type - // parameters is just their index. - // - // Since the language does not currently support referring to uninstantiated - // generic types or functions, and instantiated signatures do not have type - // parameter lists, we should never encounter a second non-empty type - // parameter list when hashing a generic signature. - sigTParams *types.TypeParamList -} +// -- Hasher -- -// MakeHasher returns a new Hasher instance. -func MakeHasher() Hasher { - return Hasher{ - memo: make(map[types.Type]uint32), - ptrMap: make(map[any]uint32), - sigTParams: nil, - } +// hash returns the hash of type t. +// TODO(adonovan): replace by types.Hash when Go proposal #69420 is accepted. +func hash(t types.Type) uint32 { + return theHasher.Hash(t) } +// A Hasher provides a [Hasher.Hash] method to map a type to its hash value. +// Hashers are stateless, and all are equivalent. +type Hasher struct{} + +var theHasher Hasher + +// MakeHasher returns Hasher{}. +// Hashers are stateless; all are equivalent. +func MakeHasher() Hasher { return theHasher } + // Hash computes a hash value for the given type t such that // Identical(t, t') => Hash(t) == Hash(t'). func (h Hasher) Hash(t types.Type) uint32 { - hash, ok := h.memo[t] - if !ok { - hash = h.hashFor(t) - h.memo[t] = hash - } - return hash + return hasher{inGenericSig: false}.hash(t) } +// hasher holds the state of a single Hash traversal: whether we are +// inside the signature of a generic function; this is used to +// optimize [hasher.hashTypeParam]. +type hasher struct{ inGenericSig bool } + // hashString computes the Fowler–Noll–Vo hash of s. func hashString(s string) uint32 { var h uint32 @@ -252,21 +218,21 @@ func hashString(s string) uint32 { return h } -// hashFor computes the hash of t. -func (h Hasher) hashFor(t types.Type) uint32 { +// hash computes the hash of t. +func (h hasher) hash(t types.Type) uint32 { // See Identical for rationale. switch t := t.(type) { case *types.Basic: return uint32(t.Kind()) case *types.Alias: - return h.Hash(types.Unalias(t)) + return h.hash(types.Unalias(t)) case *types.Array: - return 9043 + 2*uint32(t.Len()) + 3*h.Hash(t.Elem()) + return 9043 + 2*uint32(t.Len()) + 3*h.hash(t.Elem()) case *types.Slice: - return 9049 + 2*h.Hash(t.Elem()) + return 9049 + 2*h.hash(t.Elem()) case *types.Struct: var hash uint32 = 9059 @@ -277,12 +243,12 @@ func (h Hasher) hashFor(t types.Type) uint32 { } hash += hashString(t.Tag(i)) hash += hashString(f.Name()) // (ignore f.Pkg) - hash += h.Hash(f.Type()) + hash += h.hash(f.Type()) } return hash case *types.Pointer: - return 9067 + 2*h.Hash(t.Elem()) + return 9067 + 2*h.hash(t.Elem()) case *types.Signature: var hash uint32 = 9091 @@ -290,33 +256,14 @@ func (h Hasher) hashFor(t types.Type) uint32 { hash *= 8863 } - // Use a separate hasher for types inside of the signature, where type - // parameter identity is modified to be (index, constraint). We must use a - // new memo for this hasher as type identity may be affected by this - // masking. For example, in func[T any](*T), the identity of *T depends on - // whether we are mapping the argument in isolation, or recursively as part - // of hashing the signature. - // - // We should never encounter a generic signature while hashing another - // generic signature, but defensively set sigTParams only if h.mask is - // unset. tparams := t.TypeParams() - if h.sigTParams == nil && tparams.Len() != 0 { - h = Hasher{ - // There may be something more efficient than discarding the existing - // memo, but it would require detecting whether types are 'tainted' by - // references to type parameters. - memo: make(map[types.Type]uint32), - // Re-using ptrMap ensures that pointer identity is preserved in this - // hasher. - ptrMap: h.ptrMap, - sigTParams: tparams, - } - } + if n := tparams.Len(); n > 0 { + h.inGenericSig = true // affects constraints, params, and results - for i := 0; i < tparams.Len(); i++ { - tparam := tparams.At(i) - hash += 7 * h.Hash(tparam.Constraint()) + for i := range n { + tparam := tparams.At(i) + hash += 7 * h.hash(tparam.Constraint()) + } } return hash + 3*h.hashTuple(t.Params()) + 5*h.hashTuple(t.Results()) @@ -350,17 +297,17 @@ func (h Hasher) hashFor(t types.Type) uint32 { return hash case *types.Map: - return 9109 + 2*h.Hash(t.Key()) + 3*h.Hash(t.Elem()) + return 9109 + 2*h.hash(t.Key()) + 3*h.hash(t.Elem()) case *types.Chan: - return 9127 + 2*uint32(t.Dir()) + 3*h.Hash(t.Elem()) + return 9127 + 2*uint32(t.Dir()) + 3*h.hash(t.Elem()) case *types.Named: - hash := h.hashPtr(t.Obj()) + hash := h.hashTypeName(t.Obj()) targs := t.TypeArgs() for i := 0; i < targs.Len(); i++ { targ := targs.At(i) - hash += 2 * h.Hash(targ) + hash += 2 * h.hash(targ) } return hash @@ -374,17 +321,17 @@ func (h Hasher) hashFor(t types.Type) uint32 { panic(fmt.Sprintf("%T: %v", t, t)) } -func (h Hasher) hashTuple(tuple *types.Tuple) uint32 { +func (h hasher) hashTuple(tuple *types.Tuple) uint32 { // See go/types.identicalTypes for rationale. n := tuple.Len() hash := 9137 + 2*uint32(n) - for i := 0; i < n; i++ { - hash += 3 * h.Hash(tuple.At(i).Type()) + for i := range n { + hash += 3 * h.hash(tuple.At(i).Type()) } return hash } -func (h Hasher) hashUnion(t *types.Union) uint32 { +func (h hasher) hashUnion(t *types.Union) uint32 { // Hash type restrictions. terms, err := typeparams.UnionTermSet(t) // if err != nil t has invalid type restrictions. Fall back on a non-zero @@ -395,11 +342,11 @@ func (h Hasher) hashUnion(t *types.Union) uint32 { return h.hashTermSet(terms) } -func (h Hasher) hashTermSet(terms []*types.Term) uint32 { +func (h hasher) hashTermSet(terms []*types.Term) uint32 { hash := 9157 + 2*uint32(len(terms)) for _, term := range terms { // term order is not significant. - termHash := h.Hash(term.Type()) + termHash := h.hash(term.Type()) if term.Tilde() { termHash *= 9161 } @@ -408,36 +355,47 @@ func (h Hasher) hashTermSet(terms []*types.Term) uint32 { return hash } -// hashTypeParam returns a hash of the type parameter t, with a hash value -// depending on whether t is contained in h.sigTParams. -// -// If h.sigTParams is set and contains t, then we are in the process of hashing -// a signature, and the hash value of t must depend only on t's index and -// constraint: signatures are considered identical modulo type parameter -// renaming. To avoid infinite recursion, we only hash the type parameter -// index, and rely on types.Identical to handle signatures where constraints -// are not identical. -// -// Otherwise the hash of t depends only on t's pointer identity. -func (h Hasher) hashTypeParam(t *types.TypeParam) uint32 { - if h.sigTParams != nil { - i := t.Index() - if i >= 0 && i < h.sigTParams.Len() && t == h.sigTParams.At(i) { - return 9173 + 3*uint32(i) - } +// hashTypeParam returns the hash of a type parameter. +func (h hasher) hashTypeParam(t *types.TypeParam) uint32 { + // Within the signature of a generic function, TypeParams are + // identical if they have the same index and constraint, so we + // hash them based on index. + // + // When we are outside a generic function, free TypeParams are + // identical iff they are the same object, so we can use a + // more discriminating hash consistent with object identity. + // This optimization saves [Map] about 4% when hashing all the + // types.Info.Types in the forward closure of net/http. + if !h.inGenericSig { + // Optimization: outside a generic function signature, + // use a more discrimating hash consistent with object identity. + return h.hashTypeName(t.Obj()) } - return h.hashPtr(t.Obj()) + return 9173 + 3*uint32(t.Index()) } -// hashPtr hashes the pointer identity of ptr. It uses h.ptrMap to ensure that -// pointers values are not dependent on the GC. -func (h Hasher) hashPtr(ptr any) uint32 { - if hash, ok := h.ptrMap[ptr]; ok { - return hash +var theSeed = maphash.MakeSeed() + +// hashTypeName hashes the pointer of tname. +func (hasher) hashTypeName(tname *types.TypeName) uint32 { + // Since types.Identical uses == to compare TypeNames, + // the Hash function uses maphash.Comparable. + // TODO(adonovan): or will, when it becomes available in go1.24. + // In the meantime we use the pointer's numeric value. + // + // hash := maphash.Comparable(theSeed, tname) + // + // (Another approach would be to hash the name and package + // path, and whether or not it is a package-level typename. It + // is rare for a package to define multiple local types with + // the same name.) + ptr := uintptr(unsafe.Pointer(tname)) + if unsafe.Sizeof(ptr) == 8 { + hash := uint64(ptr) + return uint32(hash ^ (hash >> 32)) + } else { + return uint32(ptr) } - hash := uint32(reflect.ValueOf(ptr).Pointer()) - h.ptrMap[ptr] = hash - return hash } // shallowHash computes a hash of t without looking at any of its @@ -454,7 +412,7 @@ func (h Hasher) hashPtr(ptr any) uint32 { // include m itself; there is no mention of the named type X that // might help us break the cycle. // (See comment in go/types.identical, case *Interface, for more.) -func (h Hasher) shallowHash(t types.Type) uint32 { +func (h hasher) shallowHash(t types.Type) uint32 { // t is the type of an interface method (Signature), // its params or results (Tuples), or their immediate // elements (mostly Slice, Pointer, Basic, Named), @@ -475,7 +433,7 @@ func (h Hasher) shallowHash(t types.Type) uint32 { case *types.Tuple: n := t.Len() hash := 9137 + 2*uint32(n) - for i := 0; i < n; i++ { + for i := range n { hash += 53471161 * h.shallowHash(t.At(i).Type()) } return hash @@ -508,10 +466,10 @@ func (h Hasher) shallowHash(t types.Type) uint32 { return 9127 case *types.Named: - return h.hashPtr(t.Obj()) + return h.hashTypeName(t.Obj()) case *types.TypeParam: - return h.hashPtr(t.Obj()) + return h.hashTypeParam(t) } panic(fmt.Sprintf("shallowHash: %T: %v", t, t)) } diff --git a/src/cmd/vendor/golang.org/x/tools/internal/analysisinternal/analysis.go b/src/cmd/vendor/golang.org/x/tools/internal/analysisinternal/analysis.go index fe67b0fa27a69f..d96d22982c5a72 100644 --- a/src/cmd/vendor/golang.org/x/tools/internal/analysisinternal/analysis.go +++ b/src/cmd/vendor/golang.org/x/tools/internal/analysisinternal/analysis.go @@ -8,15 +8,19 @@ package analysisinternal import ( "bytes" + "cmp" "fmt" "go/ast" + "go/printer" "go/scanner" "go/token" "go/types" - "os" pathpkg "path" + "slices" + "strings" "golang.org/x/tools/go/analysis" + "golang.org/x/tools/internal/typesinternal" ) func TypeErrorEndPos(fset *token.FileSet, src []byte, start token.Pos) token.Pos { @@ -65,90 +69,6 @@ func TypeErrorEndPos(fset *token.FileSet, src []byte, start token.Pos) token.Pos return end } -// StmtToInsertVarBefore returns the ast.Stmt before which we can -// safely insert a new var declaration, or nil if the path denotes a -// node outside any statement. -// -// Basic Example: -// -// z := 1 -// y := z + x -// -// If x is undeclared, then this function would return `y := z + x`, so that we -// can insert `x := ` on the line before `y := z + x`. -// -// If stmt example: -// -// if z == 1 { -// } else if z == y {} -// -// If y is undeclared, then this function would return `if z == 1 {`, because we cannot -// insert a statement between an if and an else if statement. As a result, we need to find -// the top of the if chain to insert `y := ` before. -func StmtToInsertVarBefore(path []ast.Node) ast.Stmt { - enclosingIndex := -1 - for i, p := range path { - if _, ok := p.(ast.Stmt); ok { - enclosingIndex = i - break - } - } - if enclosingIndex == -1 { - return nil // no enclosing statement: outside function - } - enclosingStmt := path[enclosingIndex] - switch enclosingStmt.(type) { - case *ast.IfStmt: - // The enclosingStmt is inside of the if declaration, - // We need to check if we are in an else-if stmt and - // get the base if statement. - // TODO(adonovan): for non-constants, it may be preferable - // to add the decl as the Init field of the innermost - // enclosing ast.IfStmt. - return baseIfStmt(path, enclosingIndex) - case *ast.CaseClause: - // Get the enclosing switch stmt if the enclosingStmt is - // inside of the case statement. - for i := enclosingIndex + 1; i < len(path); i++ { - if node, ok := path[i].(*ast.SwitchStmt); ok { - return node - } else if node, ok := path[i].(*ast.TypeSwitchStmt); ok { - return node - } - } - } - if len(path) <= enclosingIndex+1 { - return enclosingStmt.(ast.Stmt) - } - // Check if the enclosing statement is inside another node. - switch expr := path[enclosingIndex+1].(type) { - case *ast.IfStmt: - // Get the base if statement. - return baseIfStmt(path, enclosingIndex+1) - case *ast.ForStmt: - if expr.Init == enclosingStmt || expr.Post == enclosingStmt { - return expr - } - case *ast.SwitchStmt, *ast.TypeSwitchStmt: - return expr.(ast.Stmt) - } - return enclosingStmt.(ast.Stmt) -} - -// baseIfStmt walks up the if/else-if chain until we get to -// the top of the current if chain. -func baseIfStmt(path []ast.Node, index int) ast.Stmt { - stmt := path[index] - for i := index + 1; i < len(path); i++ { - if node, ok := path[i].(*ast.IfStmt); ok && node.Else == stmt { - stmt = node - continue - } - break - } - return stmt.(ast.Stmt) -} - // WalkASTWithParent walks the AST rooted at n. The semantics are // similar to ast.Inspect except it does not call f(nil). func WalkASTWithParent(n ast.Node, f func(n ast.Node, parent ast.Node) bool) { @@ -258,20 +178,25 @@ func equivalentTypes(want, got types.Type) bool { return types.AssignableTo(want, got) } -// MakeReadFile returns a simple implementation of the Pass.ReadFile function. -func MakeReadFile(pass *analysis.Pass) func(filename string) ([]byte, error) { +// A ReadFileFunc is a function that returns the +// contents of a file, such as [os.ReadFile]. +type ReadFileFunc = func(filename string) ([]byte, error) + +// CheckedReadFile returns a wrapper around a Pass.ReadFile +// function that performs the appropriate checks. +func CheckedReadFile(pass *analysis.Pass, readFile ReadFileFunc) ReadFileFunc { return func(filename string) ([]byte, error) { if err := CheckReadable(pass, filename); err != nil { return nil, err } - return os.ReadFile(filename) + return readFile(filename) } } // CheckReadable enforces the access policy defined by the ReadFile field of [analysis.Pass]. func CheckReadable(pass *analysis.Pass, filename string) error { - if slicesContains(pass.OtherFiles, filename) || - slicesContains(pass.IgnoredFiles, filename) { + if slices.Contains(pass.OtherFiles, filename) || + slices.Contains(pass.IgnoredFiles, filename) { return nil } for _, f := range pass.Files { @@ -282,24 +207,21 @@ func CheckReadable(pass *analysis.Pass, filename string) error { return fmt.Errorf("Pass.ReadFile: %s is not among OtherFiles, IgnoredFiles, or names of Files", filename) } -// TODO(adonovan): use go1.21 slices.Contains. -func slicesContains[S ~[]E, E comparable](slice S, x E) bool { - for _, elem := range slice { - if elem == x { - return true - } - } - return false -} - // AddImport checks whether this file already imports pkgpath and // that import is in scope at pos. If so, it returns the name under // which it was imported and a zero edit. Otherwise, it adds a new // import of pkgpath, using a name derived from the preferred name, -// and returns the chosen name along with the edit for the new import. +// and returns the chosen name, a prefix to be concatenated with member +// to form a qualified name, and the edit for the new import. +// +// In the special case that pkgpath is dot-imported then member, the +// identifer for which the import is being added, is consulted. If +// member is not shadowed at pos, AddImport returns (".", "", nil). +// (AddImport accepts the caller's implicit claim that the imported +// package declares member.) // // It does not mutate its arguments. -func AddImport(info *types.Info, file *ast.File, pos token.Pos, pkgpath, preferredName string) (name string, newImport []analysis.TextEdit) { +func AddImport(info *types.Info, file *ast.File, preferredName, pkgpath, member string, pos token.Pos) (name, prefix string, newImport []analysis.TextEdit) { // Find innermost enclosing lexical block. scope := info.Scopes[file].Innermost(pos) if scope == nil { @@ -309,10 +231,16 @@ func AddImport(info *types.Info, file *ast.File, pos token.Pos, pkgpath, preferr // Is there an existing import of this package? // If so, are we in its scope? (not shadowed) for _, spec := range file.Imports { - pkgname, ok := importedPkgName(info, spec) - if ok && pkgname.Imported().Path() == pkgpath { - if _, obj := scope.LookupParent(pkgname.Name(), pos); obj == pkgname { - return pkgname.Name(), nil + pkgname := info.PkgNameOf(spec) + if pkgname != nil && pkgname.Imported().Path() == pkgpath { + name = pkgname.Name() + if name == "." { + // The scope of ident must be the file scope. + if s, _ := scope.LookupParent(member, pos); s == info.Scopes[file] { + return name, "", nil + } + } else if _, obj := scope.LookupParent(name, pos); obj == pkgname { + return name, name + ".", nil } } } @@ -327,16 +255,16 @@ func AddImport(info *types.Info, file *ast.File, pos token.Pos, pkgpath, preferr newName = fmt.Sprintf("%s%d", preferredName, i) } - // For now, keep it real simple: create a new import - // declaration before the first existing declaration (which - // must exist), including its comments, and let goimports tidy it up. + // Create a new import declaration either before the first existing + // declaration (which must exist), including its comments; or + // inside the declaration, if it is an import group. // // Use a renaming import whenever the preferred name is not // available, or the chosen name does not match the last // segment of its path. - newText := fmt.Sprintf("import %q\n\n", pkgpath) + newText := fmt.Sprintf("%q", pkgpath) if newName != preferredName || newName != pathpkg.Base(pkgpath) { - newText = fmt.Sprintf("import %s %q\n\n", newName, pkgpath) + newText = fmt.Sprintf("%s %q", newName, pkgpath) } decl0 := file.Decls[0] var before ast.Node = decl0 @@ -350,22 +278,209 @@ func AddImport(info *types.Info, file *ast.File, pos token.Pos, pkgpath, preferr before = decl0.Doc } } - return newName, []analysis.TextEdit{{ - Pos: before.Pos(), - End: before.Pos(), + // If the first decl is an import group, add this new import at the end. + if gd, ok := before.(*ast.GenDecl); ok && gd.Tok == token.IMPORT && gd.Rparen.IsValid() { + pos = gd.Rparen + newText = "\t" + newText + "\n" + } else { + pos = before.Pos() + newText = "import " + newText + "\n\n" + } + return newName, newName + ".", []analysis.TextEdit{{ + Pos: pos, + End: pos, NewText: []byte(newText), }} } -// importedPkgName returns the PkgName object declared by an ImportSpec. -// TODO(adonovan): use go1.22's Info.PkgNameOf. -func importedPkgName(info *types.Info, imp *ast.ImportSpec) (*types.PkgName, bool) { - var obj types.Object - if imp.Name != nil { - obj = info.Defs[imp.Name] - } else { - obj = info.Implicits[imp] +// Format returns a string representation of the expression e. +func Format(fset *token.FileSet, e ast.Expr) string { + var buf strings.Builder + printer.Fprint(&buf, fset, e) // ignore errors + return buf.String() +} + +// Imports returns true if path is imported by pkg. +func Imports(pkg *types.Package, path string) bool { + for _, imp := range pkg.Imports() { + if imp.Path() == path { + return true + } + } + return false +} + +// IsTypeNamed reports whether t is (or is an alias for) a +// package-level defined type with the given package path and one of +// the given names. It returns false if t is nil. +// +// This function avoids allocating the concatenation of "pkg.Name", +// which is important for the performance of syntax matching. +func IsTypeNamed(t types.Type, pkgPath string, names ...string) bool { + if named, ok := types.Unalias(t).(*types.Named); ok { + tname := named.Obj() + return tname != nil && + typesinternal.IsPackageLevel(tname) && + tname.Pkg().Path() == pkgPath && + slices.Contains(names, tname.Name()) + } + return false +} + +// IsPointerToNamed reports whether t is (or is an alias for) a pointer to a +// package-level defined type with the given package path and one of the given +// names. It returns false if t is not a pointer type. +func IsPointerToNamed(t types.Type, pkgPath string, names ...string) bool { + r := typesinternal.Unpointer(t) + if r == t { + return false + } + return IsTypeNamed(r, pkgPath, names...) +} + +// IsFunctionNamed reports whether obj is a package-level function +// defined in the given package and has one of the given names. +// It returns false if obj is nil. +// +// This function avoids allocating the concatenation of "pkg.Name", +// which is important for the performance of syntax matching. +func IsFunctionNamed(obj types.Object, pkgPath string, names ...string) bool { + f, ok := obj.(*types.Func) + return ok && + typesinternal.IsPackageLevel(obj) && + f.Pkg().Path() == pkgPath && + f.Type().(*types.Signature).Recv() == nil && + slices.Contains(names, f.Name()) +} + +// IsMethodNamed reports whether obj is a method defined on a +// package-level type with the given package and type name, and has +// one of the given names. It returns false if obj is nil. +// +// This function avoids allocating the concatenation of "pkg.TypeName.Name", +// which is important for the performance of syntax matching. +func IsMethodNamed(obj types.Object, pkgPath string, typeName string, names ...string) bool { + if fn, ok := obj.(*types.Func); ok { + if recv := fn.Type().(*types.Signature).Recv(); recv != nil { + _, T := typesinternal.ReceiverNamed(recv) + return T != nil && + IsTypeNamed(T, pkgPath, typeName) && + slices.Contains(names, fn.Name()) + } + } + return false +} + +// ValidateFixes validates the set of fixes for a single diagnostic. +// Any error indicates a bug in the originating analyzer. +// +// It updates fixes so that fixes[*].End.IsValid(). +// +// It may be used as part of an analysis driver implementation. +func ValidateFixes(fset *token.FileSet, a *analysis.Analyzer, fixes []analysis.SuggestedFix) error { + fixMessages := make(map[string]bool) + for i := range fixes { + fix := &fixes[i] + if fixMessages[fix.Message] { + return fmt.Errorf("analyzer %q suggests two fixes with same Message (%s)", a.Name, fix.Message) + } + fixMessages[fix.Message] = true + if err := validateFix(fset, fix); err != nil { + return fmt.Errorf("analyzer %q suggests invalid fix (%s): %v", a.Name, fix.Message, err) + } + } + return nil +} + +// validateFix validates a single fix. +// Any error indicates a bug in the originating analyzer. +// +// It updates fix so that fix.End.IsValid(). +func validateFix(fset *token.FileSet, fix *analysis.SuggestedFix) error { + + // Stably sort edits by Pos. This ordering puts insertions + // (end = start) before deletions (end > start) at the same + // point, but uses a stable sort to preserve the order of + // multiple insertions at the same point. + slices.SortStableFunc(fix.TextEdits, func(x, y analysis.TextEdit) int { + if sign := cmp.Compare(x.Pos, y.Pos); sign != 0 { + return sign + } + return cmp.Compare(x.End, y.End) + }) + + var prev *analysis.TextEdit + for i := range fix.TextEdits { + edit := &fix.TextEdits[i] + + // Validate edit individually. + start := edit.Pos + file := fset.File(start) + if file == nil { + return fmt.Errorf("missing file info for pos (%v)", edit.Pos) + } + if end := edit.End; end.IsValid() { + if end < start { + return fmt.Errorf("pos (%v) > end (%v)", edit.Pos, edit.End) + } + endFile := fset.File(end) + if endFile == nil { + return fmt.Errorf("malformed end position %v", end) + } + if endFile != file { + return fmt.Errorf("edit spans files %v and %v", file.Name(), endFile.Name()) + } + } else { + edit.End = start // update the SuggestedFix + } + if eof := token.Pos(file.Base() + file.Size()); edit.End > eof { + return fmt.Errorf("end is (%v) beyond end of file (%v)", edit.End, eof) + } + + // Validate the sequence of edits: + // properly ordered, no overlapping deletions + if prev != nil && edit.Pos < prev.End { + xpos := fset.Position(prev.Pos) + xend := fset.Position(prev.End) + ypos := fset.Position(edit.Pos) + yend := fset.Position(edit.End) + return fmt.Errorf("overlapping edits to %s (%d:%d-%d:%d and %d:%d-%d:%d)", + xpos.Filename, + xpos.Line, xpos.Column, + xend.Line, xend.Column, + ypos.Line, ypos.Column, + yend.Line, yend.Column, + ) + } + prev = edit + } + + return nil +} + +// CanImport reports whether one package is allowed to import another. +// +// TODO(adonovan): allow customization of the accessibility relation +// (e.g. for Bazel). +func CanImport(from, to string) bool { + // TODO(adonovan): better segment hygiene. + if to == "internal" || strings.HasPrefix(to, "internal/") { + // Special case: only std packages may import internal/... + // We can't reliably know whether we're in std, so we + // use a heuristic on the first segment. + first, _, _ := strings.Cut(from, "/") + if strings.Contains(first, ".") { + return false // example.com/foo ∉ std + } + if first == "testdata" { + return false // testdata/foo ∉ std + } + } + if strings.HasSuffix(to, "/internal") { + return strings.HasPrefix(from, to[:len(to)-len("/internal")]) + } + if i := strings.LastIndex(to, "/internal/"); i >= 0 { + return strings.HasPrefix(from, to[:i]) } - pkgname, ok := obj.(*types.PkgName) - return pkgname, ok + return true } diff --git a/src/cmd/vendor/golang.org/x/tools/internal/astutil/edge/edge.go b/src/cmd/vendor/golang.org/x/tools/internal/astutil/edge/edge.go new file mode 100644 index 00000000000000..4f6ccfd6e5e293 --- /dev/null +++ b/src/cmd/vendor/golang.org/x/tools/internal/astutil/edge/edge.go @@ -0,0 +1,295 @@ +// Copyright 2025 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package edge defines identifiers for each field of an ast.Node +// struct type that refers to another Node. +package edge + +import ( + "fmt" + "go/ast" + "reflect" +) + +// A Kind describes a field of an ast.Node struct. +type Kind uint8 + +// String returns a description of the edge kind. +func (k Kind) String() string { + if k == Invalid { + return "" + } + info := fieldInfos[k] + return fmt.Sprintf("%v.%s", info.nodeType.Elem().Name(), info.name) +} + +// NodeType returns the pointer-to-struct type of the ast.Node implementation. +func (k Kind) NodeType() reflect.Type { return fieldInfos[k].nodeType } + +// FieldName returns the name of the field. +func (k Kind) FieldName() string { return fieldInfos[k].name } + +// FieldType returns the declared type of the field. +func (k Kind) FieldType() reflect.Type { return fieldInfos[k].fieldType } + +// Get returns the direct child of n identified by (k, idx). +// n's type must match k.NodeType(). +// idx must be a valid slice index, or -1 for a non-slice. +func (k Kind) Get(n ast.Node, idx int) ast.Node { + if k.NodeType() != reflect.TypeOf(n) { + panic(fmt.Sprintf("%v.Get(%T): invalid node type", k, n)) + } + v := reflect.ValueOf(n).Elem().Field(fieldInfos[k].index) + if idx != -1 { + v = v.Index(idx) // asserts valid index + } else { + // (The type assertion below asserts that v is not a slice.) + } + return v.Interface().(ast.Node) // may be nil +} + +const ( + Invalid Kind = iota // for nodes at the root of the traversal + + // Kinds are sorted alphabetically. + // Numbering is not stable. + // Each is named Type_Field, where Type is the + // ast.Node struct type and Field is the name of the field + + ArrayType_Elt + ArrayType_Len + AssignStmt_Lhs + AssignStmt_Rhs + BinaryExpr_X + BinaryExpr_Y + BlockStmt_List + BranchStmt_Label + CallExpr_Args + CallExpr_Fun + CaseClause_Body + CaseClause_List + ChanType_Value + CommClause_Body + CommClause_Comm + CommentGroup_List + CompositeLit_Elts + CompositeLit_Type + DeclStmt_Decl + DeferStmt_Call + Ellipsis_Elt + ExprStmt_X + FieldList_List + Field_Comment + Field_Doc + Field_Names + Field_Tag + Field_Type + File_Decls + File_Doc + File_Name + ForStmt_Body + ForStmt_Cond + ForStmt_Init + ForStmt_Post + FuncDecl_Body + FuncDecl_Doc + FuncDecl_Name + FuncDecl_Recv + FuncDecl_Type + FuncLit_Body + FuncLit_Type + FuncType_Params + FuncType_Results + FuncType_TypeParams + GenDecl_Doc + GenDecl_Specs + GoStmt_Call + IfStmt_Body + IfStmt_Cond + IfStmt_Else + IfStmt_Init + ImportSpec_Comment + ImportSpec_Doc + ImportSpec_Name + ImportSpec_Path + IncDecStmt_X + IndexExpr_Index + IndexExpr_X + IndexListExpr_Indices + IndexListExpr_X + InterfaceType_Methods + KeyValueExpr_Key + KeyValueExpr_Value + LabeledStmt_Label + LabeledStmt_Stmt + MapType_Key + MapType_Value + ParenExpr_X + RangeStmt_Body + RangeStmt_Key + RangeStmt_Value + RangeStmt_X + ReturnStmt_Results + SelectStmt_Body + SelectorExpr_Sel + SelectorExpr_X + SendStmt_Chan + SendStmt_Value + SliceExpr_High + SliceExpr_Low + SliceExpr_Max + SliceExpr_X + StarExpr_X + StructType_Fields + SwitchStmt_Body + SwitchStmt_Init + SwitchStmt_Tag + TypeAssertExpr_Type + TypeAssertExpr_X + TypeSpec_Comment + TypeSpec_Doc + TypeSpec_Name + TypeSpec_Type + TypeSpec_TypeParams + TypeSwitchStmt_Assign + TypeSwitchStmt_Body + TypeSwitchStmt_Init + UnaryExpr_X + ValueSpec_Comment + ValueSpec_Doc + ValueSpec_Names + ValueSpec_Type + ValueSpec_Values + + maxKind +) + +// Assert that the encoding fits in 7 bits, +// as the inspector relies on this. +// (We are currently at 104.) +var _ = [1 << 7]struct{}{}[maxKind] + +type fieldInfo struct { + nodeType reflect.Type // pointer-to-struct type of ast.Node implementation + name string + index int + fieldType reflect.Type +} + +func info[N ast.Node](fieldName string) fieldInfo { + nodePtrType := reflect.TypeFor[N]() + f, ok := nodePtrType.Elem().FieldByName(fieldName) + if !ok { + panic(fieldName) + } + return fieldInfo{nodePtrType, fieldName, f.Index[0], f.Type} +} + +var fieldInfos = [...]fieldInfo{ + Invalid: {}, + ArrayType_Elt: info[*ast.ArrayType]("Elt"), + ArrayType_Len: info[*ast.ArrayType]("Len"), + AssignStmt_Lhs: info[*ast.AssignStmt]("Lhs"), + AssignStmt_Rhs: info[*ast.AssignStmt]("Rhs"), + BinaryExpr_X: info[*ast.BinaryExpr]("X"), + BinaryExpr_Y: info[*ast.BinaryExpr]("Y"), + BlockStmt_List: info[*ast.BlockStmt]("List"), + BranchStmt_Label: info[*ast.BranchStmt]("Label"), + CallExpr_Args: info[*ast.CallExpr]("Args"), + CallExpr_Fun: info[*ast.CallExpr]("Fun"), + CaseClause_Body: info[*ast.CaseClause]("Body"), + CaseClause_List: info[*ast.CaseClause]("List"), + ChanType_Value: info[*ast.ChanType]("Value"), + CommClause_Body: info[*ast.CommClause]("Body"), + CommClause_Comm: info[*ast.CommClause]("Comm"), + CommentGroup_List: info[*ast.CommentGroup]("List"), + CompositeLit_Elts: info[*ast.CompositeLit]("Elts"), + CompositeLit_Type: info[*ast.CompositeLit]("Type"), + DeclStmt_Decl: info[*ast.DeclStmt]("Decl"), + DeferStmt_Call: info[*ast.DeferStmt]("Call"), + Ellipsis_Elt: info[*ast.Ellipsis]("Elt"), + ExprStmt_X: info[*ast.ExprStmt]("X"), + FieldList_List: info[*ast.FieldList]("List"), + Field_Comment: info[*ast.Field]("Comment"), + Field_Doc: info[*ast.Field]("Doc"), + Field_Names: info[*ast.Field]("Names"), + Field_Tag: info[*ast.Field]("Tag"), + Field_Type: info[*ast.Field]("Type"), + File_Decls: info[*ast.File]("Decls"), + File_Doc: info[*ast.File]("Doc"), + File_Name: info[*ast.File]("Name"), + ForStmt_Body: info[*ast.ForStmt]("Body"), + ForStmt_Cond: info[*ast.ForStmt]("Cond"), + ForStmt_Init: info[*ast.ForStmt]("Init"), + ForStmt_Post: info[*ast.ForStmt]("Post"), + FuncDecl_Body: info[*ast.FuncDecl]("Body"), + FuncDecl_Doc: info[*ast.FuncDecl]("Doc"), + FuncDecl_Name: info[*ast.FuncDecl]("Name"), + FuncDecl_Recv: info[*ast.FuncDecl]("Recv"), + FuncDecl_Type: info[*ast.FuncDecl]("Type"), + FuncLit_Body: info[*ast.FuncLit]("Body"), + FuncLit_Type: info[*ast.FuncLit]("Type"), + FuncType_Params: info[*ast.FuncType]("Params"), + FuncType_Results: info[*ast.FuncType]("Results"), + FuncType_TypeParams: info[*ast.FuncType]("TypeParams"), + GenDecl_Doc: info[*ast.GenDecl]("Doc"), + GenDecl_Specs: info[*ast.GenDecl]("Specs"), + GoStmt_Call: info[*ast.GoStmt]("Call"), + IfStmt_Body: info[*ast.IfStmt]("Body"), + IfStmt_Cond: info[*ast.IfStmt]("Cond"), + IfStmt_Else: info[*ast.IfStmt]("Else"), + IfStmt_Init: info[*ast.IfStmt]("Init"), + ImportSpec_Comment: info[*ast.ImportSpec]("Comment"), + ImportSpec_Doc: info[*ast.ImportSpec]("Doc"), + ImportSpec_Name: info[*ast.ImportSpec]("Name"), + ImportSpec_Path: info[*ast.ImportSpec]("Path"), + IncDecStmt_X: info[*ast.IncDecStmt]("X"), + IndexExpr_Index: info[*ast.IndexExpr]("Index"), + IndexExpr_X: info[*ast.IndexExpr]("X"), + IndexListExpr_Indices: info[*ast.IndexListExpr]("Indices"), + IndexListExpr_X: info[*ast.IndexListExpr]("X"), + InterfaceType_Methods: info[*ast.InterfaceType]("Methods"), + KeyValueExpr_Key: info[*ast.KeyValueExpr]("Key"), + KeyValueExpr_Value: info[*ast.KeyValueExpr]("Value"), + LabeledStmt_Label: info[*ast.LabeledStmt]("Label"), + LabeledStmt_Stmt: info[*ast.LabeledStmt]("Stmt"), + MapType_Key: info[*ast.MapType]("Key"), + MapType_Value: info[*ast.MapType]("Value"), + ParenExpr_X: info[*ast.ParenExpr]("X"), + RangeStmt_Body: info[*ast.RangeStmt]("Body"), + RangeStmt_Key: info[*ast.RangeStmt]("Key"), + RangeStmt_Value: info[*ast.RangeStmt]("Value"), + RangeStmt_X: info[*ast.RangeStmt]("X"), + ReturnStmt_Results: info[*ast.ReturnStmt]("Results"), + SelectStmt_Body: info[*ast.SelectStmt]("Body"), + SelectorExpr_Sel: info[*ast.SelectorExpr]("Sel"), + SelectorExpr_X: info[*ast.SelectorExpr]("X"), + SendStmt_Chan: info[*ast.SendStmt]("Chan"), + SendStmt_Value: info[*ast.SendStmt]("Value"), + SliceExpr_High: info[*ast.SliceExpr]("High"), + SliceExpr_Low: info[*ast.SliceExpr]("Low"), + SliceExpr_Max: info[*ast.SliceExpr]("Max"), + SliceExpr_X: info[*ast.SliceExpr]("X"), + StarExpr_X: info[*ast.StarExpr]("X"), + StructType_Fields: info[*ast.StructType]("Fields"), + SwitchStmt_Body: info[*ast.SwitchStmt]("Body"), + SwitchStmt_Init: info[*ast.SwitchStmt]("Init"), + SwitchStmt_Tag: info[*ast.SwitchStmt]("Tag"), + TypeAssertExpr_Type: info[*ast.TypeAssertExpr]("Type"), + TypeAssertExpr_X: info[*ast.TypeAssertExpr]("X"), + TypeSpec_Comment: info[*ast.TypeSpec]("Comment"), + TypeSpec_Doc: info[*ast.TypeSpec]("Doc"), + TypeSpec_Name: info[*ast.TypeSpec]("Name"), + TypeSpec_Type: info[*ast.TypeSpec]("Type"), + TypeSpec_TypeParams: info[*ast.TypeSpec]("TypeParams"), + TypeSwitchStmt_Assign: info[*ast.TypeSwitchStmt]("Assign"), + TypeSwitchStmt_Body: info[*ast.TypeSwitchStmt]("Body"), + TypeSwitchStmt_Init: info[*ast.TypeSwitchStmt]("Init"), + UnaryExpr_X: info[*ast.UnaryExpr]("X"), + ValueSpec_Comment: info[*ast.ValueSpec]("Comment"), + ValueSpec_Doc: info[*ast.ValueSpec]("Doc"), + ValueSpec_Names: info[*ast.ValueSpec]("Names"), + ValueSpec_Type: info[*ast.ValueSpec]("Type"), + ValueSpec_Values: info[*ast.ValueSpec]("Values"), +} diff --git a/src/cmd/vendor/golang.org/x/tools/internal/fmtstr/parse.go b/src/cmd/vendor/golang.org/x/tools/internal/fmtstr/parse.go new file mode 100644 index 00000000000000..9ab264f45d6d75 --- /dev/null +++ b/src/cmd/vendor/golang.org/x/tools/internal/fmtstr/parse.go @@ -0,0 +1,370 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package fmtstr defines a parser for format strings as used by [fmt.Printf]. +package fmtstr + +import ( + "fmt" + "strconv" + "strings" + "unicode/utf8" +) + +// Operation holds the parsed representation of a printf operation such as "%3.*[4]d". +// It is constructed by [Parse]. +type Operation struct { + Text string // full text of the operation, e.g. "%[2]*.3d" + Verb Verb // verb specifier, guaranteed to exist, e.g., 'd' in '%[1]d' + Range Range // the range of Text within the overall format string + Flags string // formatting flags, e.g. "-0" + Width Size // width specifier, e.g., '3' in '%3d' + Prec Size // precision specifier, e.g., '.4' in '%.4f' +} + +// Size describes an optional width or precision in a format operation. +// It may represent no value, a literal number, an asterisk, or an indexed asterisk. +type Size struct { + // At most one of these two fields is non-negative. + Fixed int // e.g. 4 from "%4d", otherwise -1 + Dynamic int // index of argument providing dynamic size (e.g. %*d or %[3]*d), otherwise -1 + + Index int // If the width or precision uses an indexed argument (e.g. 2 in %[2]*d), this is the index, otherwise -1 + Range Range // position of the size specifier within the operation +} + +// Verb represents the verb character of a format operation (e.g., 'd', 's', 'f'). +// It also includes positional information and any explicit argument indexing. +type Verb struct { + Verb rune + Range Range // positional range of the verb in the format string + Index int // index of an indexed argument, (e.g. 2 in %[2]d), otherwise -1 + ArgIndex int // argument index (0-based) associated with this verb, relative to CallExpr +} + +// byte offsets of format string +type Range struct { + Start, End int +} + +// Parse takes a format string and its index in the printf-like call, +// parses out all format operations, returns a slice of parsed +// [Operation] which describes flags, width, precision, verb, and argument indexing, +// or an error if parsing fails. +// +// All error messages are in predicate form ("call has a problem") +// so that they may be affixed into a subject ("log.Printf "). +// +// The flags will only be a subset of ['#', '0', '+', '-', ' ']. +// It does not perform any validation of verbs, nor the +// existence of corresponding arguments (obviously it can't). The provided format string may differ +// from the one in CallExpr, such as a concatenated string or a string +// referred to by the argument in the CallExpr. +func Parse(format string, idx int) ([]*Operation, error) { + if !strings.Contains(format, "%") { + return nil, fmt.Errorf("call has arguments but no formatting directives") + } + + firstArg := idx + 1 // Arguments are immediately after format string. + argNum := firstArg + var operations []*Operation + for i, w := 0, 0; i < len(format); i += w { + w = 1 + if format[i] != '%' { + continue + } + state, err := parseOperation(format[i:], firstArg, argNum) + if err != nil { + return nil, err + } + + state.operation.addOffset(i) + operations = append(operations, state.operation) + + w = len(state.operation.Text) + // Do not waste an argument for '%'. + if state.operation.Verb.Verb != '%' { + argNum = state.argNum + 1 + } + } + return operations, nil +} + +// Internal parsing state to operation. +type state struct { + operation *Operation + firstArg int // index of the first argument after the format string + argNum int // which argument we're expecting to format now + hasIndex bool // whether the argument is indexed + index int // the encountered index + indexPos int // the encountered index's offset + indexPending bool // whether we have an indexed argument that has not resolved + nbytes int // number of bytes of the format string consumed +} + +// parseOperation parses one format operation starting at the given substring `format`, +// which should begin with '%'. It returns a fully populated state or an error +// if the operation is malformed. The firstArg and argNum parameters help determine how +// arguments map to this operation. +// +// Parse sequence: '%' -> flags -> {[N]* or width} -> .{[N]* or precision} -> [N] -> verb. +func parseOperation(format string, firstArg, argNum int) (*state, error) { + state := &state{ + operation: &Operation{ + Text: format, + Width: Size{ + Fixed: -1, + Dynamic: -1, + Index: -1, + }, + Prec: Size{ + Fixed: -1, + Dynamic: -1, + Index: -1, + }, + }, + firstArg: firstArg, + argNum: argNum, + hasIndex: false, + index: 0, + indexPos: 0, + indexPending: false, + nbytes: len("%"), // There's guaranteed to be a percent sign. + } + // There may be flags. + state.parseFlags() + // There may be an index. + if err := state.parseIndex(); err != nil { + return nil, err + } + // There may be a width. + state.parseSize(Width) + // There may be a precision. + if err := state.parsePrecision(); err != nil { + return nil, err + } + // Now a verb, possibly prefixed by an index (which we may already have). + if !state.indexPending { + if err := state.parseIndex(); err != nil { + return nil, err + } + } + if state.nbytes == len(state.operation.Text) { + return nil, fmt.Errorf("format %s is missing verb at end of string", state.operation.Text) + } + verb, w := utf8.DecodeRuneInString(state.operation.Text[state.nbytes:]) + + // Ensure there must be a verb. + if state.indexPending { + state.operation.Verb = Verb{ + Verb: verb, + Range: Range{ + Start: state.indexPos, + End: state.nbytes + w, + }, + Index: state.index, + ArgIndex: state.argNum, + } + } else { + state.operation.Verb = Verb{ + Verb: verb, + Range: Range{ + Start: state.nbytes, + End: state.nbytes + w, + }, + Index: -1, + ArgIndex: state.argNum, + } + } + + state.nbytes += w + state.operation.Text = state.operation.Text[:state.nbytes] + return state, nil +} + +// addOffset adjusts the recorded positions in Verb, Width, Prec, and the +// operation's overall Range to be relative to the position in the full format string. +func (s *Operation) addOffset(parsedLen int) { + s.Verb.Range.Start += parsedLen + s.Verb.Range.End += parsedLen + + s.Range.Start = parsedLen + s.Range.End = s.Verb.Range.End + + // one of Fixed or Dynamic is non-negative means existence. + if s.Prec.Fixed != -1 || s.Prec.Dynamic != -1 { + s.Prec.Range.Start += parsedLen + s.Prec.Range.End += parsedLen + } + if s.Width.Fixed != -1 || s.Width.Dynamic != -1 { + s.Width.Range.Start += parsedLen + s.Width.Range.End += parsedLen + } +} + +// parseFlags accepts any printf flags. +func (s *state) parseFlags() { + s.operation.Flags = prefixOf(s.operation.Text[s.nbytes:], "#0+- ") + s.nbytes += len(s.operation.Flags) +} + +// prefixOf returns the prefix of s composed only of runes from the specified set. +func prefixOf(s, set string) string { + rest := strings.TrimLeft(s, set) + return s[:len(s)-len(rest)] +} + +// parseIndex parses an argument index of the form "[n]" that can appear +// in a printf operation (e.g., "%[2]d"). Returns an error if syntax is +// malformed or index is invalid. +func (s *state) parseIndex() error { + if s.nbytes == len(s.operation.Text) || s.operation.Text[s.nbytes] != '[' { + return nil + } + // Argument index present. + s.nbytes++ // skip '[' + start := s.nbytes + if num, ok := s.scanNum(); ok { + // Later consumed/stored by a '*' or verb. + s.index = num + s.indexPos = start - 1 + } + + ok := true + if s.nbytes == len(s.operation.Text) || s.nbytes == start || s.operation.Text[s.nbytes] != ']' { + ok = false // syntax error is either missing "]" or invalid index. + s.nbytes = strings.Index(s.operation.Text[start:], "]") + if s.nbytes < 0 { + return fmt.Errorf("format %s is missing closing ]", s.operation.Text) + } + s.nbytes = s.nbytes + start + } + arg32, err := strconv.ParseInt(s.operation.Text[start:s.nbytes], 10, 32) + if err != nil || !ok || arg32 <= 0 { + return fmt.Errorf("format has invalid argument index [%s]", s.operation.Text[start:s.nbytes]) + } + + s.nbytes++ // skip ']' + arg := int(arg32) + arg += s.firstArg - 1 // We want to zero-index the actual arguments. + s.argNum = arg + s.hasIndex = true + s.indexPending = true + return nil +} + +// scanNum advances through a decimal number if present, which represents a [Size] or [Index]. +func (s *state) scanNum() (int, bool) { + start := s.nbytes + for ; s.nbytes < len(s.operation.Text); s.nbytes++ { + c := s.operation.Text[s.nbytes] + if c < '0' || '9' < c { + if start < s.nbytes { + num, _ := strconv.ParseInt(s.operation.Text[start:s.nbytes], 10, 32) + return int(num), true + } else { + return 0, false + } + } + } + return 0, false +} + +type sizeType int + +const ( + Width sizeType = iota + Precision +) + +// parseSize parses a width or precision specifier. It handles literal numeric +// values (e.g., "%3d"), asterisk values (e.g., "%*d"), or indexed asterisk values (e.g., "%[2]*d"). +func (s *state) parseSize(kind sizeType) { + if s.nbytes < len(s.operation.Text) && s.operation.Text[s.nbytes] == '*' { + s.nbytes++ + if s.indexPending { + // Absorb it. + s.indexPending = false + size := Size{ + Fixed: -1, + Dynamic: s.argNum, + Index: s.index, + Range: Range{ + Start: s.indexPos, + End: s.nbytes, + }, + } + switch kind { + case Width: + s.operation.Width = size + case Precision: + // Include the leading '.'. + size.Range.Start -= len(".") + s.operation.Prec = size + default: + panic(kind) + } + } else { + // Non-indexed asterisk: "%*d". + size := Size{ + Dynamic: s.argNum, + Index: -1, + Fixed: -1, + Range: Range{ + Start: s.nbytes - 1, + End: s.nbytes, + }, + } + switch kind { + case Width: + s.operation.Width = size + case Precision: + // For precision, include the '.' in the range. + size.Range.Start -= 1 + s.operation.Prec = size + default: + panic(kind) + } + } + s.argNum++ + } else { // Literal number, e.g. "%10d" + start := s.nbytes + if num, ok := s.scanNum(); ok { + size := Size{ + Fixed: num, + Index: -1, + Dynamic: -1, + Range: Range{ + Start: start, + End: s.nbytes, + }, + } + switch kind { + case Width: + s.operation.Width = size + case Precision: + // Include the leading '.'. + size.Range.Start -= 1 + s.operation.Prec = size + default: + panic(kind) + } + } + } +} + +// parsePrecision checks if there's a precision specified after a '.' character. +// If found, it may also parse an index or an asterisk. Returns an error if any index +// parsing fails. +func (s *state) parsePrecision() error { + // If there's a period, there may be a precision. + if s.nbytes < len(s.operation.Text) && s.operation.Text[s.nbytes] == '.' { + s.nbytes++ + if err := s.parseIndex(); err != nil { + return err + } + s.parseSize(Precision) + } + return nil +} diff --git a/src/cmd/vendor/golang.org/x/tools/internal/stdlib/manifest.go b/src/cmd/vendor/golang.org/x/tools/internal/stdlib/manifest.go index cdaac9ab34df26..e7d0aee218648c 100644 --- a/src/cmd/vendor/golang.org/x/tools/internal/stdlib/manifest.go +++ b/src/cmd/vendor/golang.org/x/tools/internal/stdlib/manifest.go @@ -268,6 +268,8 @@ var PackageSymbols = map[string][]Symbol{ {"ErrTooLarge", Var, 0}, {"Fields", Func, 0}, {"FieldsFunc", Func, 0}, + {"FieldsFuncSeq", Func, 24}, + {"FieldsSeq", Func, 24}, {"HasPrefix", Func, 0}, {"HasSuffix", Func, 0}, {"Index", Func, 0}, @@ -280,6 +282,7 @@ var PackageSymbols = map[string][]Symbol{ {"LastIndexAny", Func, 0}, {"LastIndexByte", Func, 5}, {"LastIndexFunc", Func, 0}, + {"Lines", Func, 24}, {"Map", Func, 0}, {"MinRead", Const, 0}, {"NewBuffer", Func, 0}, @@ -293,7 +296,9 @@ var PackageSymbols = map[string][]Symbol{ {"Split", Func, 0}, {"SplitAfter", Func, 0}, {"SplitAfterN", Func, 0}, + {"SplitAfterSeq", Func, 24}, {"SplitN", Func, 0}, + {"SplitSeq", Func, 24}, {"Title", Func, 0}, {"ToLower", Func, 0}, {"ToLowerSpecial", Func, 0}, @@ -535,6 +540,7 @@ var PackageSymbols = map[string][]Symbol{ {"NewCTR", Func, 0}, {"NewGCM", Func, 2}, {"NewGCMWithNonceSize", Func, 5}, + {"NewGCMWithRandomNonce", Func, 24}, {"NewGCMWithTagSize", Func, 11}, {"NewOFB", Func, 0}, {"Stream", Type, 0}, @@ -673,6 +679,14 @@ var PackageSymbols = map[string][]Symbol{ {"Unmarshal", Func, 0}, {"UnmarshalCompressed", Func, 15}, }, + "crypto/fips140": { + {"Enabled", Func, 24}, + }, + "crypto/hkdf": { + {"Expand", Func, 24}, + {"Extract", Func, 24}, + {"Key", Func, 24}, + }, "crypto/hmac": { {"Equal", Func, 1}, {"New", Func, 0}, @@ -683,11 +697,43 @@ var PackageSymbols = map[string][]Symbol{ {"Size", Const, 0}, {"Sum", Func, 2}, }, + "crypto/mlkem": { + {"(*DecapsulationKey1024).Bytes", Method, 24}, + {"(*DecapsulationKey1024).Decapsulate", Method, 24}, + {"(*DecapsulationKey1024).EncapsulationKey", Method, 24}, + {"(*DecapsulationKey768).Bytes", Method, 24}, + {"(*DecapsulationKey768).Decapsulate", Method, 24}, + {"(*DecapsulationKey768).EncapsulationKey", Method, 24}, + {"(*EncapsulationKey1024).Bytes", Method, 24}, + {"(*EncapsulationKey1024).Encapsulate", Method, 24}, + {"(*EncapsulationKey768).Bytes", Method, 24}, + {"(*EncapsulationKey768).Encapsulate", Method, 24}, + {"CiphertextSize1024", Const, 24}, + {"CiphertextSize768", Const, 24}, + {"DecapsulationKey1024", Type, 24}, + {"DecapsulationKey768", Type, 24}, + {"EncapsulationKey1024", Type, 24}, + {"EncapsulationKey768", Type, 24}, + {"EncapsulationKeySize1024", Const, 24}, + {"EncapsulationKeySize768", Const, 24}, + {"GenerateKey1024", Func, 24}, + {"GenerateKey768", Func, 24}, + {"NewDecapsulationKey1024", Func, 24}, + {"NewDecapsulationKey768", Func, 24}, + {"NewEncapsulationKey1024", Func, 24}, + {"NewEncapsulationKey768", Func, 24}, + {"SeedSize", Const, 24}, + {"SharedKeySize", Const, 24}, + }, + "crypto/pbkdf2": { + {"Key", Func, 24}, + }, "crypto/rand": { {"Int", Func, 0}, {"Prime", Func, 0}, {"Read", Func, 0}, {"Reader", Var, 0}, + {"Text", Func, 24}, }, "crypto/rc4": { {"(*Cipher).Reset", Method, 0}, @@ -766,6 +812,39 @@ var PackageSymbols = map[string][]Symbol{ {"Sum224", Func, 2}, {"Sum256", Func, 2}, }, + "crypto/sha3": { + {"(*SHA3).AppendBinary", Method, 24}, + {"(*SHA3).BlockSize", Method, 24}, + {"(*SHA3).MarshalBinary", Method, 24}, + {"(*SHA3).Reset", Method, 24}, + {"(*SHA3).Size", Method, 24}, + {"(*SHA3).Sum", Method, 24}, + {"(*SHA3).UnmarshalBinary", Method, 24}, + {"(*SHA3).Write", Method, 24}, + {"(*SHAKE).AppendBinary", Method, 24}, + {"(*SHAKE).BlockSize", Method, 24}, + {"(*SHAKE).MarshalBinary", Method, 24}, + {"(*SHAKE).Read", Method, 24}, + {"(*SHAKE).Reset", Method, 24}, + {"(*SHAKE).UnmarshalBinary", Method, 24}, + {"(*SHAKE).Write", Method, 24}, + {"New224", Func, 24}, + {"New256", Func, 24}, + {"New384", Func, 24}, + {"New512", Func, 24}, + {"NewCSHAKE128", Func, 24}, + {"NewCSHAKE256", Func, 24}, + {"NewSHAKE128", Func, 24}, + {"NewSHAKE256", Func, 24}, + {"SHA3", Type, 24}, + {"SHAKE", Type, 24}, + {"Sum224", Func, 24}, + {"Sum256", Func, 24}, + {"Sum384", Func, 24}, + {"Sum512", Func, 24}, + {"SumSHAKE128", Func, 24}, + {"SumSHAKE256", Func, 24}, + }, "crypto/sha512": { {"BlockSize", Const, 0}, {"New", Func, 0}, @@ -788,6 +867,7 @@ var PackageSymbols = map[string][]Symbol{ {"ConstantTimeEq", Func, 0}, {"ConstantTimeLessOrEq", Func, 2}, {"ConstantTimeSelect", Func, 0}, + {"WithDataIndependentTiming", Func, 24}, {"XORBytes", Func, 20}, }, "crypto/tls": { @@ -864,6 +944,7 @@ var PackageSymbols = map[string][]Symbol{ {"ClientHelloInfo", Type, 4}, {"ClientHelloInfo.CipherSuites", Field, 4}, {"ClientHelloInfo.Conn", Field, 8}, + {"ClientHelloInfo.Extensions", Field, 24}, {"ClientHelloInfo.ServerName", Field, 4}, {"ClientHelloInfo.SignatureSchemes", Field, 8}, {"ClientHelloInfo.SupportedCurves", Field, 4}, @@ -881,6 +962,7 @@ var PackageSymbols = map[string][]Symbol{ {"Config.CurvePreferences", Field, 3}, {"Config.DynamicRecordSizingDisabled", Field, 7}, {"Config.EncryptedClientHelloConfigList", Field, 23}, + {"Config.EncryptedClientHelloKeys", Field, 24}, {"Config.EncryptedClientHelloRejectionVerify", Field, 23}, {"Config.GetCertificate", Field, 4}, {"Config.GetClientCertificate", Field, 8}, @@ -934,6 +1016,10 @@ var PackageSymbols = map[string][]Symbol{ {"ECHRejectionError", Type, 23}, {"ECHRejectionError.RetryConfigList", Field, 23}, {"Ed25519", Const, 13}, + {"EncryptedClientHelloKey", Type, 24}, + {"EncryptedClientHelloKey.Config", Field, 24}, + {"EncryptedClientHelloKey.PrivateKey", Field, 24}, + {"EncryptedClientHelloKey.SendAsRetry", Field, 24}, {"InsecureCipherSuites", Func, 14}, {"Listen", Func, 0}, {"LoadX509KeyPair", Func, 0}, @@ -1032,6 +1118,7 @@ var PackageSymbols = map[string][]Symbol{ {"VersionTLS12", Const, 2}, {"VersionTLS13", Const, 12}, {"X25519", Const, 8}, + {"X25519MLKEM768", Const, 24}, {"X509KeyPair", Func, 0}, }, "crypto/x509": { @@ -1056,6 +1143,8 @@ var PackageSymbols = map[string][]Symbol{ {"(ConstraintViolationError).Error", Method, 0}, {"(HostnameError).Error", Method, 0}, {"(InsecureAlgorithmError).Error", Method, 6}, + {"(OID).AppendBinary", Method, 24}, + {"(OID).AppendText", Method, 24}, {"(OID).Equal", Method, 22}, {"(OID).EqualASN1OID", Method, 22}, {"(OID).MarshalBinary", Method, 23}, @@ -1084,6 +1173,10 @@ var PackageSymbols = map[string][]Symbol{ {"Certificate.Extensions", Field, 2}, {"Certificate.ExtraExtensions", Field, 2}, {"Certificate.IPAddresses", Field, 1}, + {"Certificate.InhibitAnyPolicy", Field, 24}, + {"Certificate.InhibitAnyPolicyZero", Field, 24}, + {"Certificate.InhibitPolicyMapping", Field, 24}, + {"Certificate.InhibitPolicyMappingZero", Field, 24}, {"Certificate.IsCA", Field, 0}, {"Certificate.Issuer", Field, 0}, {"Certificate.IssuingCertificateURL", Field, 2}, @@ -1100,6 +1193,7 @@ var PackageSymbols = map[string][]Symbol{ {"Certificate.PermittedURIDomains", Field, 10}, {"Certificate.Policies", Field, 22}, {"Certificate.PolicyIdentifiers", Field, 0}, + {"Certificate.PolicyMappings", Field, 24}, {"Certificate.PublicKey", Field, 0}, {"Certificate.PublicKeyAlgorithm", Field, 0}, {"Certificate.Raw", Field, 0}, @@ -1107,6 +1201,8 @@ var PackageSymbols = map[string][]Symbol{ {"Certificate.RawSubject", Field, 0}, {"Certificate.RawSubjectPublicKeyInfo", Field, 0}, {"Certificate.RawTBSCertificate", Field, 0}, + {"Certificate.RequireExplicitPolicy", Field, 24}, + {"Certificate.RequireExplicitPolicyZero", Field, 24}, {"Certificate.SerialNumber", Field, 0}, {"Certificate.Signature", Field, 0}, {"Certificate.SignatureAlgorithm", Field, 0}, @@ -1198,6 +1294,7 @@ var PackageSymbols = map[string][]Symbol{ {"NameConstraintsWithoutSANs", Const, 10}, {"NameMismatch", Const, 8}, {"NewCertPool", Func, 0}, + {"NoValidChains", Const, 24}, {"NotAuthorizedToSign", Const, 0}, {"OID", Type, 22}, {"OIDFromInts", Func, 22}, @@ -1219,6 +1316,9 @@ var PackageSymbols = map[string][]Symbol{ {"ParsePKCS8PrivateKey", Func, 0}, {"ParsePKIXPublicKey", Func, 0}, {"ParseRevocationList", Func, 19}, + {"PolicyMapping", Type, 24}, + {"PolicyMapping.IssuerDomainPolicy", Field, 24}, + {"PolicyMapping.SubjectDomainPolicy", Field, 24}, {"PublicKeyAlgorithm", Type, 0}, {"PureEd25519", Const, 13}, {"RSA", Const, 0}, @@ -1265,6 +1365,7 @@ var PackageSymbols = map[string][]Symbol{ {"UnknownPublicKeyAlgorithm", Const, 0}, {"UnknownSignatureAlgorithm", Const, 0}, {"VerifyOptions", Type, 0}, + {"VerifyOptions.CertificatePolicies", Field, 24}, {"VerifyOptions.CurrentTime", Field, 0}, {"VerifyOptions.DNSName", Field, 0}, {"VerifyOptions.Intermediates", Field, 0}, @@ -1975,6 +2076,8 @@ var PackageSymbols = map[string][]Symbol{ {"(*File).DynString", Method, 1}, {"(*File).DynValue", Method, 21}, {"(*File).DynamicSymbols", Method, 4}, + {"(*File).DynamicVersionNeeds", Method, 24}, + {"(*File).DynamicVersions", Method, 24}, {"(*File).ImportedLibraries", Method, 0}, {"(*File).ImportedSymbols", Method, 0}, {"(*File).Section", Method, 0}, @@ -2048,6 +2151,8 @@ var PackageSymbols = map[string][]Symbol{ {"(Type).String", Method, 0}, {"(Version).GoString", Method, 0}, {"(Version).String", Method, 0}, + {"(VersionIndex).Index", Method, 24}, + {"(VersionIndex).IsHidden", Method, 24}, {"ARM_MAGIC_TRAMP_NUMBER", Const, 0}, {"COMPRESS_HIOS", Const, 6}, {"COMPRESS_HIPROC", Const, 6}, @@ -2240,6 +2345,19 @@ var PackageSymbols = map[string][]Symbol{ {"DynFlag", Type, 0}, {"DynFlag1", Type, 21}, {"DynTag", Type, 0}, + {"DynamicVersion", Type, 24}, + {"DynamicVersion.Deps", Field, 24}, + {"DynamicVersion.Flags", Field, 24}, + {"DynamicVersion.Index", Field, 24}, + {"DynamicVersion.Name", Field, 24}, + {"DynamicVersionDep", Type, 24}, + {"DynamicVersionDep.Dep", Field, 24}, + {"DynamicVersionDep.Flags", Field, 24}, + {"DynamicVersionDep.Index", Field, 24}, + {"DynamicVersionFlag", Type, 24}, + {"DynamicVersionNeed", Type, 24}, + {"DynamicVersionNeed.Name", Field, 24}, + {"DynamicVersionNeed.Needs", Field, 24}, {"EI_ABIVERSION", Const, 0}, {"EI_CLASS", Const, 0}, {"EI_DATA", Const, 0}, @@ -3718,6 +3836,7 @@ var PackageSymbols = map[string][]Symbol{ {"SymType", Type, 0}, {"SymVis", Type, 0}, {"Symbol", Type, 0}, + {"Symbol.HasVersion", Field, 24}, {"Symbol.Info", Field, 0}, {"Symbol.Library", Field, 13}, {"Symbol.Name", Field, 0}, @@ -3726,8 +3845,13 @@ var PackageSymbols = map[string][]Symbol{ {"Symbol.Size", Field, 0}, {"Symbol.Value", Field, 0}, {"Symbol.Version", Field, 13}, + {"Symbol.VersionIndex", Field, 24}, {"Type", Type, 0}, + {"VER_FLG_BASE", Const, 24}, + {"VER_FLG_INFO", Const, 24}, + {"VER_FLG_WEAK", Const, 24}, {"Version", Type, 0}, + {"VersionIndex", Type, 24}, }, "debug/gosym": { {"(*DecodingError).Error", Method, 0}, @@ -4453,8 +4577,10 @@ var PackageSymbols = map[string][]Symbol{ {"FS", Type, 16}, }, "encoding": { + {"BinaryAppender", Type, 24}, {"BinaryMarshaler", Type, 2}, {"BinaryUnmarshaler", Type, 2}, + {"TextAppender", Type, 24}, {"TextMarshaler", Type, 2}, {"TextUnmarshaler", Type, 2}, }, @@ -5984,13 +6110,16 @@ var PackageSymbols = map[string][]Symbol{ {"(*Interface).Complete", Method, 5}, {"(*Interface).Embedded", Method, 5}, {"(*Interface).EmbeddedType", Method, 11}, + {"(*Interface).EmbeddedTypes", Method, 24}, {"(*Interface).Empty", Method, 5}, {"(*Interface).ExplicitMethod", Method, 5}, + {"(*Interface).ExplicitMethods", Method, 24}, {"(*Interface).IsComparable", Method, 18}, {"(*Interface).IsImplicit", Method, 18}, {"(*Interface).IsMethodSet", Method, 18}, {"(*Interface).MarkImplicit", Method, 18}, {"(*Interface).Method", Method, 5}, + {"(*Interface).Methods", Method, 24}, {"(*Interface).NumEmbeddeds", Method, 5}, {"(*Interface).NumExplicitMethods", Method, 5}, {"(*Interface).NumMethods", Method, 5}, @@ -6011,9 +6140,11 @@ var PackageSymbols = map[string][]Symbol{ {"(*MethodSet).At", Method, 5}, {"(*MethodSet).Len", Method, 5}, {"(*MethodSet).Lookup", Method, 5}, + {"(*MethodSet).Methods", Method, 24}, {"(*MethodSet).String", Method, 5}, {"(*Named).AddMethod", Method, 5}, {"(*Named).Method", Method, 5}, + {"(*Named).Methods", Method, 24}, {"(*Named).NumMethods", Method, 5}, {"(*Named).Obj", Method, 5}, {"(*Named).Origin", Method, 18}, @@ -6054,6 +6185,7 @@ var PackageSymbols = map[string][]Symbol{ {"(*Pointer).String", Method, 5}, {"(*Pointer).Underlying", Method, 5}, {"(*Scope).Child", Method, 5}, + {"(*Scope).Children", Method, 24}, {"(*Scope).Contains", Method, 5}, {"(*Scope).End", Method, 5}, {"(*Scope).Innermost", Method, 5}, @@ -6089,6 +6221,7 @@ var PackageSymbols = map[string][]Symbol{ {"(*StdSizes).Offsetsof", Method, 5}, {"(*StdSizes).Sizeof", Method, 5}, {"(*Struct).Field", Method, 5}, + {"(*Struct).Fields", Method, 24}, {"(*Struct).NumFields", Method, 5}, {"(*Struct).String", Method, 5}, {"(*Struct).Tag", Method, 5}, @@ -6100,8 +6233,10 @@ var PackageSymbols = map[string][]Symbol{ {"(*Tuple).Len", Method, 5}, {"(*Tuple).String", Method, 5}, {"(*Tuple).Underlying", Method, 5}, + {"(*Tuple).Variables", Method, 24}, {"(*TypeList).At", Method, 18}, {"(*TypeList).Len", Method, 18}, + {"(*TypeList).Types", Method, 24}, {"(*TypeName).Exported", Method, 5}, {"(*TypeName).Id", Method, 5}, {"(*TypeName).IsAlias", Method, 9}, @@ -6119,9 +6254,11 @@ var PackageSymbols = map[string][]Symbol{ {"(*TypeParam).Underlying", Method, 18}, {"(*TypeParamList).At", Method, 18}, {"(*TypeParamList).Len", Method, 18}, + {"(*TypeParamList).TypeParams", Method, 24}, {"(*Union).Len", Method, 18}, {"(*Union).String", Method, 18}, {"(*Union).Term", Method, 18}, + {"(*Union).Terms", Method, 24}, {"(*Union).Underlying", Method, 18}, {"(*Var).Anonymous", Method, 5}, {"(*Var).Embedded", Method, 11}, @@ -6392,10 +6529,12 @@ var PackageSymbols = map[string][]Symbol{ {"(*Hash).WriteByte", Method, 14}, {"(*Hash).WriteString", Method, 14}, {"Bytes", Func, 19}, + {"Comparable", Func, 24}, {"Hash", Type, 14}, {"MakeSeed", Func, 14}, {"Seed", Type, 14}, {"String", Func, 19}, + {"WriteComparable", Func, 24}, }, "html": { {"EscapeString", Func, 0}, @@ -7082,6 +7221,7 @@ var PackageSymbols = map[string][]Symbol{ {"(*JSONHandler).WithGroup", Method, 21}, {"(*Level).UnmarshalJSON", Method, 21}, {"(*Level).UnmarshalText", Method, 21}, + {"(*LevelVar).AppendText", Method, 24}, {"(*LevelVar).Level", Method, 21}, {"(*LevelVar).MarshalText", Method, 21}, {"(*LevelVar).Set", Method, 21}, @@ -7110,6 +7250,7 @@ var PackageSymbols = map[string][]Symbol{ {"(Attr).Equal", Method, 21}, {"(Attr).String", Method, 21}, {"(Kind).String", Method, 21}, + {"(Level).AppendText", Method, 24}, {"(Level).Level", Method, 21}, {"(Level).MarshalJSON", Method, 21}, {"(Level).MarshalText", Method, 21}, @@ -7140,6 +7281,7 @@ var PackageSymbols = map[string][]Symbol{ {"Debug", Func, 21}, {"DebugContext", Func, 21}, {"Default", Func, 21}, + {"DiscardHandler", Var, 24}, {"Duration", Func, 21}, {"DurationValue", Func, 21}, {"Error", Func, 21}, @@ -7375,6 +7517,7 @@ var PackageSymbols = map[string][]Symbol{ {"(*Float).Acc", Method, 5}, {"(*Float).Add", Method, 5}, {"(*Float).Append", Method, 5}, + {"(*Float).AppendText", Method, 24}, {"(*Float).Cmp", Method, 5}, {"(*Float).Copy", Method, 5}, {"(*Float).Float32", Method, 5}, @@ -7421,6 +7564,7 @@ var PackageSymbols = map[string][]Symbol{ {"(*Int).And", Method, 0}, {"(*Int).AndNot", Method, 0}, {"(*Int).Append", Method, 6}, + {"(*Int).AppendText", Method, 24}, {"(*Int).Binomial", Method, 0}, {"(*Int).Bit", Method, 0}, {"(*Int).BitLen", Method, 0}, @@ -7477,6 +7621,7 @@ var PackageSymbols = map[string][]Symbol{ {"(*Int).Xor", Method, 0}, {"(*Rat).Abs", Method, 0}, {"(*Rat).Add", Method, 0}, + {"(*Rat).AppendText", Method, 24}, {"(*Rat).Cmp", Method, 0}, {"(*Rat).Denom", Method, 0}, {"(*Rat).Float32", Method, 4}, @@ -7659,11 +7804,13 @@ var PackageSymbols = map[string][]Symbol{ {"Zipf", Type, 0}, }, "math/rand/v2": { + {"(*ChaCha8).AppendBinary", Method, 24}, {"(*ChaCha8).MarshalBinary", Method, 22}, {"(*ChaCha8).Read", Method, 23}, {"(*ChaCha8).Seed", Method, 22}, {"(*ChaCha8).Uint64", Method, 22}, {"(*ChaCha8).UnmarshalBinary", Method, 22}, + {"(*PCG).AppendBinary", Method, 24}, {"(*PCG).MarshalBinary", Method, 22}, {"(*PCG).Seed", Method, 22}, {"(*PCG).Uint64", Method, 22}, @@ -7931,6 +8078,7 @@ var PackageSymbols = map[string][]Symbol{ {"(*UnixListener).SyscallConn", Method, 10}, {"(Flags).String", Method, 0}, {"(HardwareAddr).String", Method, 0}, + {"(IP).AppendText", Method, 24}, {"(IP).DefaultMask", Method, 0}, {"(IP).Equal", Method, 0}, {"(IP).IsGlobalUnicast", Method, 0}, @@ -8131,6 +8279,9 @@ var PackageSymbols = map[string][]Symbol{ {"(*MaxBytesError).Error", Method, 19}, {"(*ProtocolError).Error", Method, 0}, {"(*ProtocolError).Is", Method, 21}, + {"(*Protocols).SetHTTP1", Method, 24}, + {"(*Protocols).SetHTTP2", Method, 24}, + {"(*Protocols).SetUnencryptedHTTP2", Method, 24}, {"(*Request).AddCookie", Method, 0}, {"(*Request).BasicAuth", Method, 4}, {"(*Request).Clone", Method, 13}, @@ -8190,6 +8341,10 @@ var PackageSymbols = map[string][]Symbol{ {"(Header).Values", Method, 14}, {"(Header).Write", Method, 0}, {"(Header).WriteSubset", Method, 0}, + {"(Protocols).HTTP1", Method, 24}, + {"(Protocols).HTTP2", Method, 24}, + {"(Protocols).String", Method, 24}, + {"(Protocols).UnencryptedHTTP2", Method, 24}, {"AllowQuerySemicolons", Func, 17}, {"CanonicalHeaderKey", Func, 0}, {"Client", Type, 0}, @@ -8252,6 +8407,18 @@ var PackageSymbols = map[string][]Symbol{ {"FileSystem", Type, 0}, {"Flusher", Type, 0}, {"Get", Func, 0}, + {"HTTP2Config", Type, 24}, + {"HTTP2Config.CountError", Field, 24}, + {"HTTP2Config.MaxConcurrentStreams", Field, 24}, + {"HTTP2Config.MaxDecoderHeaderTableSize", Field, 24}, + {"HTTP2Config.MaxEncoderHeaderTableSize", Field, 24}, + {"HTTP2Config.MaxReadFrameSize", Field, 24}, + {"HTTP2Config.MaxReceiveBufferPerConnection", Field, 24}, + {"HTTP2Config.MaxReceiveBufferPerStream", Field, 24}, + {"HTTP2Config.PermitProhibitedCipherSuites", Field, 24}, + {"HTTP2Config.PingTimeout", Field, 24}, + {"HTTP2Config.SendPingTimeout", Field, 24}, + {"HTTP2Config.WriteByteTimeout", Field, 24}, {"Handle", Func, 0}, {"HandleFunc", Func, 0}, {"Handler", Type, 0}, @@ -8292,6 +8459,7 @@ var PackageSymbols = map[string][]Symbol{ {"PostForm", Func, 0}, {"ProtocolError", Type, 0}, {"ProtocolError.ErrorString", Field, 0}, + {"Protocols", Type, 24}, {"ProxyFromEnvironment", Func, 0}, {"ProxyURL", Func, 0}, {"PushOptions", Type, 8}, @@ -8361,9 +8529,11 @@ var PackageSymbols = map[string][]Symbol{ {"Server.ConnState", Field, 3}, {"Server.DisableGeneralOptionsHandler", Field, 20}, {"Server.ErrorLog", Field, 3}, + {"Server.HTTP2", Field, 24}, {"Server.Handler", Field, 0}, {"Server.IdleTimeout", Field, 8}, {"Server.MaxHeaderBytes", Field, 0}, + {"Server.Protocols", Field, 24}, {"Server.ReadHeaderTimeout", Field, 8}, {"Server.ReadTimeout", Field, 0}, {"Server.TLSConfig", Field, 0}, @@ -8453,12 +8623,14 @@ var PackageSymbols = map[string][]Symbol{ {"Transport.ExpectContinueTimeout", Field, 6}, {"Transport.ForceAttemptHTTP2", Field, 13}, {"Transport.GetProxyConnectHeader", Field, 16}, + {"Transport.HTTP2", Field, 24}, {"Transport.IdleConnTimeout", Field, 7}, {"Transport.MaxConnsPerHost", Field, 11}, {"Transport.MaxIdleConns", Field, 7}, {"Transport.MaxIdleConnsPerHost", Field, 0}, {"Transport.MaxResponseHeaderBytes", Field, 7}, {"Transport.OnProxyConnectResponse", Field, 20}, + {"Transport.Protocols", Field, 24}, {"Transport.Proxy", Field, 0}, {"Transport.ProxyConnectHeader", Field, 8}, {"Transport.ReadBufferSize", Field, 13}, @@ -8646,6 +8818,8 @@ var PackageSymbols = map[string][]Symbol{ {"(*AddrPort).UnmarshalText", Method, 18}, {"(*Prefix).UnmarshalBinary", Method, 18}, {"(*Prefix).UnmarshalText", Method, 18}, + {"(Addr).AppendBinary", Method, 24}, + {"(Addr).AppendText", Method, 24}, {"(Addr).AppendTo", Method, 18}, {"(Addr).As16", Method, 18}, {"(Addr).As4", Method, 18}, @@ -8676,6 +8850,8 @@ var PackageSymbols = map[string][]Symbol{ {"(Addr).WithZone", Method, 18}, {"(Addr).Zone", Method, 18}, {"(AddrPort).Addr", Method, 18}, + {"(AddrPort).AppendBinary", Method, 24}, + {"(AddrPort).AppendText", Method, 24}, {"(AddrPort).AppendTo", Method, 18}, {"(AddrPort).Compare", Method, 22}, {"(AddrPort).IsValid", Method, 18}, @@ -8684,6 +8860,8 @@ var PackageSymbols = map[string][]Symbol{ {"(AddrPort).Port", Method, 18}, {"(AddrPort).String", Method, 18}, {"(Prefix).Addr", Method, 18}, + {"(Prefix).AppendBinary", Method, 24}, + {"(Prefix).AppendText", Method, 24}, {"(Prefix).AppendTo", Method, 18}, {"(Prefix).Bits", Method, 18}, {"(Prefix).Contains", Method, 18}, @@ -8868,6 +9046,7 @@ var PackageSymbols = map[string][]Symbol{ {"(*Error).Temporary", Method, 6}, {"(*Error).Timeout", Method, 6}, {"(*Error).Unwrap", Method, 13}, + {"(*URL).AppendBinary", Method, 24}, {"(*URL).EscapedFragment", Method, 15}, {"(*URL).EscapedPath", Method, 5}, {"(*URL).Hostname", Method, 8}, @@ -8967,6 +9146,17 @@ var PackageSymbols = map[string][]Symbol{ {"(*ProcessState).SysUsage", Method, 0}, {"(*ProcessState).SystemTime", Method, 0}, {"(*ProcessState).UserTime", Method, 0}, + {"(*Root).Close", Method, 24}, + {"(*Root).Create", Method, 24}, + {"(*Root).FS", Method, 24}, + {"(*Root).Lstat", Method, 24}, + {"(*Root).Mkdir", Method, 24}, + {"(*Root).Name", Method, 24}, + {"(*Root).Open", Method, 24}, + {"(*Root).OpenFile", Method, 24}, + {"(*Root).OpenRoot", Method, 24}, + {"(*Root).Remove", Method, 24}, + {"(*Root).Stat", Method, 24}, {"(*SyscallError).Error", Method, 0}, {"(*SyscallError).Timeout", Method, 10}, {"(*SyscallError).Unwrap", Method, 13}, @@ -9060,6 +9250,8 @@ var PackageSymbols = map[string][]Symbol{ {"O_WRONLY", Const, 0}, {"Open", Func, 0}, {"OpenFile", Func, 0}, + {"OpenInRoot", Func, 24}, + {"OpenRoot", Func, 24}, {"PathError", Type, 0}, {"PathError.Err", Field, 0}, {"PathError.Op", Field, 0}, @@ -9081,6 +9273,7 @@ var PackageSymbols = map[string][]Symbol{ {"Remove", Func, 0}, {"RemoveAll", Func, 0}, {"Rename", Func, 0}, + {"Root", Type, 24}, {"SEEK_CUR", Const, 0}, {"SEEK_END", Const, 0}, {"SEEK_SET", Const, 0}, @@ -9422,6 +9615,7 @@ var PackageSymbols = map[string][]Symbol{ {"Zero", Func, 0}, }, "regexp": { + {"(*Regexp).AppendText", Method, 24}, {"(*Regexp).Copy", Method, 6}, {"(*Regexp).Expand", Method, 0}, {"(*Regexp).ExpandString", Method, 0}, @@ -9602,6 +9796,8 @@ var PackageSymbols = map[string][]Symbol{ {"(*StackRecord).Stack", Method, 0}, {"(*TypeAssertionError).Error", Method, 0}, {"(*TypeAssertionError).RuntimeError", Method, 0}, + {"(Cleanup).Stop", Method, 24}, + {"AddCleanup", Func, 24}, {"BlockProfile", Func, 1}, {"BlockProfileRecord", Type, 1}, {"BlockProfileRecord.Count", Field, 1}, @@ -9612,6 +9808,7 @@ var PackageSymbols = map[string][]Symbol{ {"Caller", Func, 0}, {"Callers", Func, 0}, {"CallersFrames", Func, 7}, + {"Cleanup", Type, 24}, {"Compiler", Const, 0}, {"Error", Type, 0}, {"Frame", Type, 7}, @@ -9974,6 +10171,8 @@ var PackageSymbols = map[string][]Symbol{ {"EqualFold", Func, 0}, {"Fields", Func, 0}, {"FieldsFunc", Func, 0}, + {"FieldsFuncSeq", Func, 24}, + {"FieldsSeq", Func, 24}, {"HasPrefix", Func, 0}, {"HasSuffix", Func, 0}, {"Index", Func, 0}, @@ -9986,6 +10185,7 @@ var PackageSymbols = map[string][]Symbol{ {"LastIndexAny", Func, 0}, {"LastIndexByte", Func, 5}, {"LastIndexFunc", Func, 0}, + {"Lines", Func, 24}, {"Map", Func, 0}, {"NewReader", Func, 0}, {"NewReplacer", Func, 0}, @@ -9997,7 +10197,9 @@ var PackageSymbols = map[string][]Symbol{ {"Split", Func, 0}, {"SplitAfter", Func, 0}, {"SplitAfterN", Func, 0}, + {"SplitAfterSeq", Func, 24}, {"SplitN", Func, 0}, + {"SplitSeq", Func, 24}, {"Title", Func, 0}, {"ToLower", Func, 0}, {"ToLowerSpecial", Func, 0}, @@ -16413,7 +16615,9 @@ var PackageSymbols = map[string][]Symbol{ {"ValueOf", Func, 0}, }, "testing": { + {"(*B).Chdir", Method, 24}, {"(*B).Cleanup", Method, 14}, + {"(*B).Context", Method, 24}, {"(*B).Elapsed", Method, 20}, {"(*B).Error", Method, 0}, {"(*B).Errorf", Method, 0}, @@ -16425,6 +16629,7 @@ var PackageSymbols = map[string][]Symbol{ {"(*B).Helper", Method, 9}, {"(*B).Log", Method, 0}, {"(*B).Logf", Method, 0}, + {"(*B).Loop", Method, 24}, {"(*B).Name", Method, 8}, {"(*B).ReportAllocs", Method, 1}, {"(*B).ReportMetric", Method, 13}, @@ -16442,7 +16647,9 @@ var PackageSymbols = map[string][]Symbol{ {"(*B).StopTimer", Method, 0}, {"(*B).TempDir", Method, 15}, {"(*F).Add", Method, 18}, + {"(*F).Chdir", Method, 24}, {"(*F).Cleanup", Method, 18}, + {"(*F).Context", Method, 24}, {"(*F).Error", Method, 18}, {"(*F).Errorf", Method, 18}, {"(*F).Fail", Method, 18}, @@ -16463,7 +16670,9 @@ var PackageSymbols = map[string][]Symbol{ {"(*F).TempDir", Method, 18}, {"(*M).Run", Method, 4}, {"(*PB).Next", Method, 3}, + {"(*T).Chdir", Method, 24}, {"(*T).Cleanup", Method, 14}, + {"(*T).Context", Method, 24}, {"(*T).Deadline", Method, 15}, {"(*T).Error", Method, 0}, {"(*T).Errorf", Method, 0}, @@ -16954,7 +17163,9 @@ var PackageSymbols = map[string][]Symbol{ {"(Time).Add", Method, 0}, {"(Time).AddDate", Method, 0}, {"(Time).After", Method, 0}, + {"(Time).AppendBinary", Method, 24}, {"(Time).AppendFormat", Method, 5}, + {"(Time).AppendText", Method, 24}, {"(Time).Before", Method, 0}, {"(Time).Clock", Method, 0}, {"(Time).Compare", Method, 20}, @@ -17428,4 +17639,9 @@ var PackageSymbols = map[string][]Symbol{ {"String", Func, 0}, {"StringData", Func, 0}, }, + "weak": { + {"(Pointer).Value", Method, 24}, + {"Make", Func, 24}, + {"Pointer", Type, 24}, + }, } diff --git a/src/cmd/vendor/golang.org/x/tools/internal/typeparams/common.go b/src/cmd/vendor/golang.org/x/tools/internal/typeparams/common.go index 0b84acc5c7fa43..cdae2b8e818485 100644 --- a/src/cmd/vendor/golang.org/x/tools/internal/typeparams/common.go +++ b/src/cmd/vendor/golang.org/x/tools/internal/typeparams/common.go @@ -66,75 +66,3 @@ func IsTypeParam(t types.Type) bool { _, ok := types.Unalias(t).(*types.TypeParam) return ok } - -// GenericAssignableTo is a generalization of types.AssignableTo that -// implements the following rule for uninstantiated generic types: -// -// If V and T are generic named types, then V is considered assignable to T if, -// for every possible instantiation of V[A_1, ..., A_N], the instantiation -// T[A_1, ..., A_N] is valid and V[A_1, ..., A_N] implements T[A_1, ..., A_N]. -// -// If T has structural constraints, they must be satisfied by V. -// -// For example, consider the following type declarations: -// -// type Interface[T any] interface { -// Accept(T) -// } -// -// type Container[T any] struct { -// Element T -// } -// -// func (c Container[T]) Accept(t T) { c.Element = t } -// -// In this case, GenericAssignableTo reports that instantiations of Container -// are assignable to the corresponding instantiation of Interface. -func GenericAssignableTo(ctxt *types.Context, V, T types.Type) bool { - V = types.Unalias(V) - T = types.Unalias(T) - - // If V and T are not both named, or do not have matching non-empty type - // parameter lists, fall back on types.AssignableTo. - - VN, Vnamed := V.(*types.Named) - TN, Tnamed := T.(*types.Named) - if !Vnamed || !Tnamed { - return types.AssignableTo(V, T) - } - - vtparams := VN.TypeParams() - ttparams := TN.TypeParams() - if vtparams.Len() == 0 || vtparams.Len() != ttparams.Len() || VN.TypeArgs().Len() != 0 || TN.TypeArgs().Len() != 0 { - return types.AssignableTo(V, T) - } - - // V and T have the same (non-zero) number of type params. Instantiate both - // with the type parameters of V. This must always succeed for V, and will - // succeed for T if and only if the type set of each type parameter of V is a - // subset of the type set of the corresponding type parameter of T, meaning - // that every instantiation of V corresponds to a valid instantiation of T. - - // Minor optimization: ensure we share a context across the two - // instantiations below. - if ctxt == nil { - ctxt = types.NewContext() - } - - var targs []types.Type - for i := 0; i < vtparams.Len(); i++ { - targs = append(targs, vtparams.At(i)) - } - - vinst, err := types.Instantiate(ctxt, V, targs, true) - if err != nil { - panic("type parameters should satisfy their own constraints") - } - - tinst, err := types.Instantiate(ctxt, T, targs, true) - if err != nil { - return false - } - - return types.AssignableTo(vinst, tinst) -} diff --git a/src/cmd/vendor/golang.org/x/tools/internal/typeparams/coretype.go b/src/cmd/vendor/golang.org/x/tools/internal/typeparams/coretype.go index 6e83c6fb1a2b08..27a2b179299681 100644 --- a/src/cmd/vendor/golang.org/x/tools/internal/typeparams/coretype.go +++ b/src/cmd/vendor/golang.org/x/tools/internal/typeparams/coretype.go @@ -109,8 +109,13 @@ func CoreType(T types.Type) types.Type { // // NormalTerms makes no guarantees about the order of terms, except that it // is deterministic. -func NormalTerms(typ types.Type) ([]*types.Term, error) { - switch typ := typ.Underlying().(type) { +func NormalTerms(T types.Type) ([]*types.Term, error) { + // typeSetOf(T) == typeSetOf(Unalias(T)) + typ := types.Unalias(T) + if named, ok := typ.(*types.Named); ok { + typ = named.Underlying() + } + switch typ := typ.(type) { case *types.TypeParam: return StructuralTerms(typ) case *types.Union: @@ -118,7 +123,7 @@ func NormalTerms(typ types.Type) ([]*types.Term, error) { case *types.Interface: return InterfaceTermSet(typ) default: - return []*types.Term{types.NewTerm(false, typ)}, nil + return []*types.Term{types.NewTerm(false, T)}, nil } } diff --git a/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/errorcode.go b/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/errorcode.go index 131caab2847ecf..235a6defc4c733 100644 --- a/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/errorcode.go +++ b/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/errorcode.go @@ -966,7 +966,7 @@ const ( // var _ = string(x) InvalidConversion - // InvalidUntypedConversion occurs when an there is no valid implicit + // InvalidUntypedConversion occurs when there is no valid implicit // conversion from an untyped value satisfying the type constraints of the // context in which it is used. // diff --git a/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/qualifier.go b/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/qualifier.go new file mode 100644 index 00000000000000..b64f714eb30f6e --- /dev/null +++ b/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/qualifier.go @@ -0,0 +1,46 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package typesinternal + +import ( + "go/ast" + "go/types" + "strconv" +) + +// FileQualifier returns a [types.Qualifier] function that qualifies +// imported symbols appropriately based on the import environment of a given +// file. +// If the same package is imported multiple times, the last appearance is +// recorded. +func FileQualifier(f *ast.File, pkg *types.Package) types.Qualifier { + // Construct mapping of import paths to their defined names. + // It is only necessary to look at renaming imports. + imports := make(map[string]string) + for _, imp := range f.Imports { + if imp.Name != nil && imp.Name.Name != "_" { + path, _ := strconv.Unquote(imp.Path.Value) + imports[path] = imp.Name.Name + } + } + + // Define qualifier to replace full package paths with names of the imports. + return func(p *types.Package) string { + if p == nil || p == pkg { + return "" + } + + if name, ok := imports[p.Path()]; ok { + if name == "." { + return "" + } else { + return name + } + } + + // If there is no local renaming, fall back to the package name. + return p.Name() + } +} diff --git a/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/recv.go b/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/recv.go index ba6f4f4ebd522f..8352ea761736a4 100644 --- a/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/recv.go +++ b/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/recv.go @@ -11,6 +11,9 @@ import ( // ReceiverNamed returns the named type (if any) associated with the // type of recv, which may be of the form N or *N, or aliases thereof. // It also reports whether a Pointer was present. +// +// The named result may be nil if recv is from a method on an +// anonymous interface or struct types or in ill-typed code. func ReceiverNamed(recv *types.Var) (isPtr bool, named *types.Named) { t := recv.Type() if ptr, ok := types.Unalias(t).(*types.Pointer); ok { diff --git a/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/types.go b/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/types.go index df3ea52125439c..34534879630c33 100644 --- a/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/types.go +++ b/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/types.go @@ -82,6 +82,7 @@ func NameRelativeTo(pkg *types.Package) types.Qualifier { type NamedOrAlias interface { types.Type Obj() *types.TypeName + // TODO(hxjiang): add method TypeArgs() *types.TypeList after stop supporting go1.22. } // TypeParams is a light shim around t.TypeParams(). @@ -119,3 +120,8 @@ func Origin(t NamedOrAlias) NamedOrAlias { } return t } + +// IsPackageLevel reports whether obj is a package-level symbol. +func IsPackageLevel(obj types.Object) bool { + return obj.Pkg() != nil && obj.Parent() == obj.Pkg().Scope() +} diff --git a/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/varkind.go b/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/varkind.go new file mode 100644 index 00000000000000..e5da0495111ba1 --- /dev/null +++ b/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/varkind.go @@ -0,0 +1,40 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package typesinternal + +// TODO(adonovan): when CL 645115 lands, define the go1.25 version of +// this API that actually does something. + +import "go/types" + +type VarKind uint8 + +const ( + _ VarKind = iota // (not meaningful) + PackageVar // a package-level variable + LocalVar // a local variable + RecvVar // a method receiver variable + ParamVar // a function parameter variable + ResultVar // a function result variable + FieldVar // a struct field +) + +func (kind VarKind) String() string { + return [...]string{ + 0: "VarKind(0)", + PackageVar: "PackageVar", + LocalVar: "LocalVar", + RecvVar: "RecvVar", + ParamVar: "ParamVar", + ResultVar: "ResultVar", + FieldVar: "FieldVar", + }[kind] +} + +// GetVarKind returns an invalid VarKind. +func GetVarKind(v *types.Var) VarKind { return 0 } + +// SetVarKind has no effect. +func SetVarKind(v *types.Var, kind VarKind) {} diff --git a/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/zerovalue.go b/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/zerovalue.go index 1066980649e091..d272949c177189 100644 --- a/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/zerovalue.go +++ b/src/cmd/vendor/golang.org/x/tools/internal/typesinternal/zerovalue.go @@ -9,62 +9,97 @@ import ( "go/ast" "go/token" "go/types" - "strconv" "strings" ) -// ZeroString returns the string representation of the "zero" value of the type t. +// ZeroString returns the string representation of the zero value for any type t. +// The boolean result indicates whether the type is or contains an invalid type +// or a non-basic (constraint) interface type. +// +// Even for invalid input types, ZeroString may return a partially correct +// string representation. The caller should use the returned isValid boolean +// to determine the validity of the expression. +// +// When assigning to a wider type (such as 'any'), it's the caller's +// responsibility to handle any necessary type conversions. +// // This string can be used on the right-hand side of an assignment where the // left-hand side has that explicit type. +// References to named types are qualified by an appropriate (optional) +// qualifier function. // Exception: This does not apply to tuples. Their string representation is // informational only and cannot be used in an assignment. -// When assigning to a wider type (such as 'any'), it's the caller's -// responsibility to handle any necessary type conversions. +// // See [ZeroExpr] for a variant that returns an [ast.Expr]. -func ZeroString(t types.Type, qf types.Qualifier) string { +func ZeroString(t types.Type, qual types.Qualifier) (_ string, isValid bool) { switch t := t.(type) { case *types.Basic: switch { case t.Info()&types.IsBoolean != 0: - return "false" + return "false", true case t.Info()&types.IsNumeric != 0: - return "0" + return "0", true case t.Info()&types.IsString != 0: - return `""` + return `""`, true case t.Kind() == types.UnsafePointer: fallthrough case t.Kind() == types.UntypedNil: - return "nil" + return "nil", true + case t.Kind() == types.Invalid: + return "invalid", false default: - panic(fmt.Sprint("ZeroString for unexpected type:", t)) + panic(fmt.Sprintf("ZeroString for unexpected type %v", t)) } - case *types.Pointer, *types.Slice, *types.Interface, *types.Chan, *types.Map, *types.Signature: - return "nil" + case *types.Pointer, *types.Slice, *types.Chan, *types.Map, *types.Signature: + return "nil", true + + case *types.Interface: + if !t.IsMethodSet() { + return "invalid", false + } + return "nil", true - case *types.Named, *types.Alias: + case *types.Named: switch under := t.Underlying().(type) { case *types.Struct, *types.Array: - return types.TypeString(t, qf) + "{}" + return types.TypeString(t, qual) + "{}", true + default: + return ZeroString(under, qual) + } + + case *types.Alias: + switch t.Underlying().(type) { + case *types.Struct, *types.Array: + return types.TypeString(t, qual) + "{}", true default: - return ZeroString(under, qf) + // A type parameter can have alias but alias type's underlying type + // can never be a type parameter. + // Use types.Unalias to preserve the info of type parameter instead + // of call Underlying() going right through and get the underlying + // type of the type parameter which is always an interface. + return ZeroString(types.Unalias(t), qual) } case *types.Array, *types.Struct: - return types.TypeString(t, qf) + "{}" + return types.TypeString(t, qual) + "{}", true case *types.TypeParam: // Assumes func new is not shadowed. - return "*new(" + types.TypeString(t, qf) + ")" + return "*new(" + types.TypeString(t, qual) + ")", true case *types.Tuple: // Tuples are not normal values. // We are currently format as "(t[0], ..., t[n])". Could be something else. + isValid := true components := make([]string, t.Len()) for i := 0; i < t.Len(); i++ { - components[i] = ZeroString(t.At(i).Type(), qf) + comp, ok := ZeroString(t.At(i).Type(), qual) + + components[i] = comp + isValid = isValid && ok } - return "(" + strings.Join(components, ", ") + ")" + return "(" + strings.Join(components, ", ") + ")", isValid case *types.Union: // Variables of these types cannot be created, so it makes @@ -76,45 +111,72 @@ func ZeroString(t types.Type, qf types.Qualifier) string { } } -// ZeroExpr returns the ast.Expr representation of the "zero" value of the type t. -// ZeroExpr is defined for types that are suitable for variables. -// It may panic for other types such as Tuple or Union. +// ZeroExpr returns the ast.Expr representation of the zero value for any type t. +// The boolean result indicates whether the type is or contains an invalid type +// or a non-basic (constraint) interface type. +// +// Even for invalid input types, ZeroExpr may return a partially correct ast.Expr +// representation. The caller should use the returned isValid boolean to determine +// the validity of the expression. +// +// This function is designed for types suitable for variables and should not be +// used with Tuple or Union types.References to named types are qualified by an +// appropriate (optional) qualifier function. +// // See [ZeroString] for a variant that returns a string. -func ZeroExpr(f *ast.File, pkg *types.Package, typ types.Type) ast.Expr { - switch t := typ.(type) { +func ZeroExpr(t types.Type, qual types.Qualifier) (_ ast.Expr, isValid bool) { + switch t := t.(type) { case *types.Basic: switch { case t.Info()&types.IsBoolean != 0: - return &ast.Ident{Name: "false"} + return &ast.Ident{Name: "false"}, true case t.Info()&types.IsNumeric != 0: - return &ast.BasicLit{Kind: token.INT, Value: "0"} + return &ast.BasicLit{Kind: token.INT, Value: "0"}, true case t.Info()&types.IsString != 0: - return &ast.BasicLit{Kind: token.STRING, Value: `""`} + return &ast.BasicLit{Kind: token.STRING, Value: `""`}, true case t.Kind() == types.UnsafePointer: fallthrough case t.Kind() == types.UntypedNil: - return ast.NewIdent("nil") + return ast.NewIdent("nil"), true + case t.Kind() == types.Invalid: + return &ast.BasicLit{Kind: token.STRING, Value: `"invalid"`}, false default: - panic(fmt.Sprint("ZeroExpr for unexpected type:", t)) + panic(fmt.Sprintf("ZeroExpr for unexpected type %v", t)) } - case *types.Pointer, *types.Slice, *types.Interface, *types.Chan, *types.Map, *types.Signature: - return ast.NewIdent("nil") + case *types.Pointer, *types.Slice, *types.Chan, *types.Map, *types.Signature: + return ast.NewIdent("nil"), true + + case *types.Interface: + if !t.IsMethodSet() { + return &ast.BasicLit{Kind: token.STRING, Value: `"invalid"`}, false + } + return ast.NewIdent("nil"), true - case *types.Named, *types.Alias: + case *types.Named: switch under := t.Underlying().(type) { case *types.Struct, *types.Array: return &ast.CompositeLit{ - Type: TypeExpr(f, pkg, typ), - } + Type: TypeExpr(t, qual), + }, true default: - return ZeroExpr(f, pkg, under) + return ZeroExpr(under, qual) + } + + case *types.Alias: + switch t.Underlying().(type) { + case *types.Struct, *types.Array: + return &ast.CompositeLit{ + Type: TypeExpr(t, qual), + }, true + default: + return ZeroExpr(types.Unalias(t), qual) } case *types.Array, *types.Struct: return &ast.CompositeLit{ - Type: TypeExpr(f, pkg, typ), - } + Type: TypeExpr(t, qual), + }, true case *types.TypeParam: return &ast.StarExpr{ // *new(T) @@ -125,7 +187,7 @@ func ZeroExpr(f *ast.File, pkg *types.Package, typ types.Type) ast.Expr { ast.NewIdent(t.Obj().Name()), }, }, - } + }, true case *types.Tuple: // Unlike ZeroString, there is no ast.Expr can express tuple by @@ -157,16 +219,14 @@ func IsZeroExpr(expr ast.Expr) bool { } // TypeExpr returns syntax for the specified type. References to named types -// from packages other than pkg are qualified by an appropriate package name, as -// defined by the import environment of file. +// are qualified by an appropriate (optional) qualifier function. // It may panic for types such as Tuple or Union. -func TypeExpr(f *ast.File, pkg *types.Package, typ types.Type) ast.Expr { - switch t := typ.(type) { +func TypeExpr(t types.Type, qual types.Qualifier) ast.Expr { + switch t := t.(type) { case *types.Basic: switch t.Kind() { case types.UnsafePointer: - // TODO(hxjiang): replace the implementation with types.Qualifier. - return &ast.SelectorExpr{X: ast.NewIdent("unsafe"), Sel: ast.NewIdent("Pointer")} + return &ast.SelectorExpr{X: ast.NewIdent(qual(types.NewPackage("unsafe", "unsafe"))), Sel: ast.NewIdent("Pointer")} default: return ast.NewIdent(t.Name()) } @@ -174,7 +234,7 @@ func TypeExpr(f *ast.File, pkg *types.Package, typ types.Type) ast.Expr { case *types.Pointer: return &ast.UnaryExpr{ Op: token.MUL, - X: TypeExpr(f, pkg, t.Elem()), + X: TypeExpr(t.Elem(), qual), } case *types.Array: @@ -183,18 +243,18 @@ func TypeExpr(f *ast.File, pkg *types.Package, typ types.Type) ast.Expr { Kind: token.INT, Value: fmt.Sprintf("%d", t.Len()), }, - Elt: TypeExpr(f, pkg, t.Elem()), + Elt: TypeExpr(t.Elem(), qual), } case *types.Slice: return &ast.ArrayType{ - Elt: TypeExpr(f, pkg, t.Elem()), + Elt: TypeExpr(t.Elem(), qual), } case *types.Map: return &ast.MapType{ - Key: TypeExpr(f, pkg, t.Key()), - Value: TypeExpr(f, pkg, t.Elem()), + Key: TypeExpr(t.Key(), qual), + Value: TypeExpr(t.Elem(), qual), } case *types.Chan: @@ -204,14 +264,14 @@ func TypeExpr(f *ast.File, pkg *types.Package, typ types.Type) ast.Expr { } return &ast.ChanType{ Dir: dir, - Value: TypeExpr(f, pkg, t.Elem()), + Value: TypeExpr(t.Elem(), qual), } case *types.Signature: var params []*ast.Field for i := 0; i < t.Params().Len(); i++ { params = append(params, &ast.Field{ - Type: TypeExpr(f, pkg, t.Params().At(i).Type()), + Type: TypeExpr(t.Params().At(i).Type(), qual), Names: []*ast.Ident{ { Name: t.Params().At(i).Name(), @@ -226,7 +286,7 @@ func TypeExpr(f *ast.File, pkg *types.Package, typ types.Type) ast.Expr { var returns []*ast.Field for i := 0; i < t.Results().Len(); i++ { returns = append(returns, &ast.Field{ - Type: TypeExpr(f, pkg, t.Results().At(i).Type()), + Type: TypeExpr(t.Results().At(i).Type(), qual), }) } return &ast.FuncType{ @@ -238,23 +298,9 @@ func TypeExpr(f *ast.File, pkg *types.Package, typ types.Type) ast.Expr { }, } - case interface{ Obj() *types.TypeName }: // *types.{Alias,Named,TypeParam} - switch t.Obj().Pkg() { - case pkg, nil: - return ast.NewIdent(t.Obj().Name()) - } - pkgName := t.Obj().Pkg().Name() - - // TODO(hxjiang): replace the implementation with types.Qualifier. - // If the file already imports the package under another name, use that. - for _, cand := range f.Imports { - if path, _ := strconv.Unquote(cand.Path.Value); path == t.Obj().Pkg().Path() { - if cand.Name != nil && cand.Name.Name != "" { - pkgName = cand.Name.Name - } - } - } - if pkgName == "." { + case *types.TypeParam: + pkgName := qual(t.Obj().Pkg()) + if pkgName == "" || t.Obj().Pkg() == nil { return ast.NewIdent(t.Obj().Name()) } return &ast.SelectorExpr{ @@ -262,6 +308,36 @@ func TypeExpr(f *ast.File, pkg *types.Package, typ types.Type) ast.Expr { Sel: ast.NewIdent(t.Obj().Name()), } + // types.TypeParam also implements interface NamedOrAlias. To differentiate, + // case TypeParam need to be present before case NamedOrAlias. + // TODO(hxjiang): remove this comment once TypeArgs() is added to interface + // NamedOrAlias. + case NamedOrAlias: + var expr ast.Expr = ast.NewIdent(t.Obj().Name()) + if pkgName := qual(t.Obj().Pkg()); pkgName != "." && pkgName != "" { + expr = &ast.SelectorExpr{ + X: ast.NewIdent(pkgName), + Sel: expr.(*ast.Ident), + } + } + + // TODO(hxjiang): call t.TypeArgs after adding method TypeArgs() to + // typesinternal.NamedOrAlias. + if hasTypeArgs, ok := t.(interface{ TypeArgs() *types.TypeList }); ok { + if typeArgs := hasTypeArgs.TypeArgs(); typeArgs != nil && typeArgs.Len() > 0 { + var indices []ast.Expr + for i := range typeArgs.Len() { + indices = append(indices, TypeExpr(typeArgs.At(i), qual)) + } + expr = &ast.IndexListExpr{ + X: expr, + Indices: indices, + } + } + } + + return expr + case *types.Struct: return ast.NewIdent(t.String()) @@ -269,9 +345,43 @@ func TypeExpr(f *ast.File, pkg *types.Package, typ types.Type) ast.Expr { return ast.NewIdent(t.String()) case *types.Union: - // TODO(hxjiang): handle the union through syntax (~A | ... | ~Z). - // Remove nil check when calling typesinternal.TypeExpr. - return nil + if t.Len() == 0 { + panic("Union type should have at least one term") + } + // Same as go/ast, the return expression will put last term in the + // Y field at topmost level of BinaryExpr. + // For union of type "float32 | float64 | int64", the structure looks + // similar to: + // { + // X: { + // X: float32, + // Op: | + // Y: float64, + // } + // Op: |, + // Y: int64, + // } + var union ast.Expr + for i := range t.Len() { + term := t.Term(i) + termExpr := TypeExpr(term.Type(), qual) + if term.Tilde() { + termExpr = &ast.UnaryExpr{ + Op: token.TILDE, + X: termExpr, + } + } + if i == 0 { + union = termExpr + } else { + union = &ast.BinaryExpr{ + X: union, + Op: token.OR, + Y: termExpr, + } + } + } + return union case *types.Tuple: panic("invalid input type types.Tuple") diff --git a/src/cmd/vendor/modules.txt b/src/cmd/vendor/modules.txt index 118646d75c4ccb..703d9364eac99f 100644 --- a/src/cmd/vendor/modules.txt +++ b/src/cmd/vendor/modules.txt @@ -16,7 +16,7 @@ github.com/google/pprof/third_party/svgpan # github.com/ianlancetaylor/demangle v0.0.0-20240912202439-0a2b6291aafd ## explicit; go 1.13 github.com/ianlancetaylor/demangle -# golang.org/x/arch v0.12.0 +# golang.org/x/arch v0.14.0 ## explicit; go 1.18 golang.org/x/arch/arm/armasm golang.org/x/arch/arm64/arm64asm @@ -25,10 +25,10 @@ golang.org/x/arch/ppc64/ppc64asm golang.org/x/arch/riscv64/riscv64asm golang.org/x/arch/s390x/s390xasm golang.org/x/arch/x86/x86asm -# golang.org/x/build v0.0.0-20241205234318-b850320af2a4 +# golang.org/x/build v0.0.0-20250211223606-a5e3f75caa63 ## explicit; go 1.22.0 golang.org/x/build/relnote -# golang.org/x/mod v0.22.0 +# golang.org/x/mod v0.23.0 ## explicit; go 1.22.0 golang.org/x/mod/internal/lazyregexp golang.org/x/mod/modfile @@ -39,16 +39,16 @@ golang.org/x/mod/sumdb/dirhash golang.org/x/mod/sumdb/note golang.org/x/mod/sumdb/tlog golang.org/x/mod/zip -# golang.org/x/sync v0.10.0 +# golang.org/x/sync v0.11.0 ## explicit; go 1.18 golang.org/x/sync/errgroup golang.org/x/sync/semaphore -# golang.org/x/sys v0.28.0 +# golang.org/x/sys v0.30.0 ## explicit; go 1.18 golang.org/x/sys/plan9 golang.org/x/sys/unix golang.org/x/sys/windows -# golang.org/x/telemetry v0.0.0-20241204182053-c0ac0e154df3 +# golang.org/x/telemetry v0.0.0-20250212145848-75305293b65a ## explicit; go 1.22.0 golang.org/x/telemetry golang.org/x/telemetry/counter @@ -60,10 +60,10 @@ golang.org/x/telemetry/internal/crashmonitor golang.org/x/telemetry/internal/mmap golang.org/x/telemetry/internal/telemetry golang.org/x/telemetry/internal/upload -# golang.org/x/term v0.27.0 +# golang.org/x/term v0.29.0 ## explicit; go 1.18 golang.org/x/term -# golang.org/x/text v0.21.0 +# golang.org/x/text v0.22.0 ## explicit; go 1.18 golang.org/x/text/cases golang.org/x/text/internal @@ -73,7 +73,7 @@ golang.org/x/text/internal/tag golang.org/x/text/language golang.org/x/text/transform golang.org/x/text/unicode/norm -# golang.org/x/tools v0.28.1-0.20250131145412-98746475647e +# golang.org/x/tools v0.30.1-0.20250212161021-f9aad7054b5f ## explicit; go 1.22.0 golang.org/x/tools/cmd/bisect golang.org/x/tools/cover @@ -122,8 +122,10 @@ golang.org/x/tools/go/types/objectpath golang.org/x/tools/go/types/typeutil golang.org/x/tools/internal/aliases golang.org/x/tools/internal/analysisinternal +golang.org/x/tools/internal/astutil/edge golang.org/x/tools/internal/bisect golang.org/x/tools/internal/facts +golang.org/x/tools/internal/fmtstr golang.org/x/tools/internal/stdlib golang.org/x/tools/internal/typeparams golang.org/x/tools/internal/typesinternal diff --git a/src/cmd/vet/testdata/print/print.go b/src/cmd/vet/testdata/print/print.go index a2ad0f1298aa79..fffe571163889f 100644 --- a/src/cmd/vet/testdata/print/print.go +++ b/src/cmd/vet/testdata/print/print.go @@ -200,8 +200,8 @@ func PrintfTests() { // Bad argument reorderings. Printf("%[xd", 3) // ERROR "Printf format %\[xd is missing closing \]" Printf("%[x]d x", 3) // ERROR "Printf format has invalid argument index \[x\]" - Printf("%[3]*s x", "hi", 2) // ERROR "Printf format has invalid argument index \[3\]" - _ = fmt.Sprintf("%[3]d x", 2) // ERROR "Sprintf format has invalid argument index \[3\]" + Printf("%[3]*s x", "hi", 2) // ERROR "Printf format %\[3\]\*s reads arg #3, but call has 2 args" + _ = fmt.Sprintf("%[3]d x", 2) // ERROR "Sprintf format %\[3\]d reads arg #3, but call has 1 arg" Printf("%[2]*.[1]*[3]d x", 2, "hi", 4) // ERROR "Printf format %\[2]\*\.\[1\]\*\[3\]d uses non-int \x22hi\x22 as argument of \*" Printf("%[0]s x", "arg1") // ERROR "Printf format has invalid argument index \[0\]" Printf("%[0]d x", 1) // ERROR "Printf format has invalid argument index \[0\]" diff --git a/src/go.mod b/src/go.mod index ccfdbd8ea22d77..4ccf4ff79eed2f 100644 --- a/src/go.mod +++ b/src/go.mod @@ -1,13 +1,13 @@ module std -go 1.24 +go 1.25 require ( - golang.org/x/crypto v0.30.0 - golang.org/x/net v0.32.1-0.20250121202134-9a960c88dd98 + golang.org/x/crypto v0.33.1-0.20250210163342-e47973b1c108 + golang.org/x/net v0.34.1-0.20250123000230-c72e89d6a9e4 ) require ( - golang.org/x/sys v0.28.0 // indirect - golang.org/x/text v0.21.0 // indirect + golang.org/x/sys v0.30.0 // indirect + golang.org/x/text v0.22.0 // indirect ) diff --git a/src/go.sum b/src/go.sum index 4d6a33e34a4e63..50dec70ed6e6f2 100644 --- a/src/go.sum +++ b/src/go.sum @@ -1,8 +1,8 @@ -golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY= -golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= -golang.org/x/net v0.32.1-0.20250121202134-9a960c88dd98 h1:36bTiCRO7f/J3t+LumnLTJDXqxsp1x6Q7754SsRD9u4= -golang.org/x/net v0.32.1-0.20250121202134-9a960c88dd98/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/crypto v0.33.1-0.20250210163342-e47973b1c108 h1:FwaGHNRX5GDt6vHr+Ly+yRTs0ADe4xTlGOzwaga4ZOs= +golang.org/x/crypto v0.33.1-0.20250210163342-e47973b1c108/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= +golang.org/x/net v0.34.1-0.20250123000230-c72e89d6a9e4 h1:guLo+MhruvDNVBe2ssFzu5BGn4pc0G1xx6TqTHK+MnE= +golang.org/x/net v0.34.1-0.20250123000230-c72e89d6a9e4/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go index 22f013f1d48407..81a8c4bc4dedbf 100644 --- a/src/net/http/h2_bundle.go +++ b/src/net/http/h2_bundle.go @@ -1085,7 +1085,7 @@ func http2configFromServer(h1 *Server, h2 *http2Server) http2http2Config { return conf } -// configFromServer merges configuration settings from h2 and h2.t1.HTTP2 +// configFromTransport merges configuration settings from h2 and h2.t1.HTTP2 // (the net/http Transport). func http2configFromTransport(h2 *http2Transport) http2http2Config { conf := http2http2Config{ @@ -1151,7 +1151,7 @@ func http2fillNetHTTPServerConfig(conf *http2http2Config, srv *Server) { http2fillNetHTTPConfig(conf, srv.HTTP2) } -// fillNetHTTPServerConfig sets fields in conf from tr.HTTP2. +// fillNetHTTPTransportConfig sets fields in conf from tr.HTTP2. func http2fillNetHTTPTransportConfig(conf *http2http2Config, tr *Transport) { http2fillNetHTTPConfig(conf, tr.HTTP2) } @@ -7797,6 +7797,7 @@ type http2ClientConn struct { doNotReuse bool // whether conn is marked to not be reused for any future requests closing bool closed bool + closedOnIdle bool // true if conn was closed for idleness seenSettings bool // true if we've seen a settings frame, false otherwise seenSettingsChan chan struct{} // closed when seenSettings is true or frame reading fails wantSettingsAck bool // we sent a SETTINGS frame and haven't heard back @@ -8512,10 +8513,12 @@ func (cc *http2ClientConn) idleStateLocked() (st http2clientConnIdleState) { // If this connection has never been used for a request and is closed, // then let it take a request (which will fail). + // If the conn was closed for idleness, we're racing the idle timer; + // don't try to use the conn. (Issue #70515.) // // This avoids a situation where an error early in a connection's lifetime // goes unreported. - if cc.nextStreamID == 1 && cc.streamsReserved == 0 && cc.closed { + if cc.nextStreamID == 1 && cc.streamsReserved == 0 && cc.closed && !cc.closedOnIdle { st.canTakeNewRequest = true } @@ -8578,6 +8581,7 @@ func (cc *http2ClientConn) closeIfIdle() { return } cc.closed = true + cc.closedOnIdle = true nextID := cc.nextStreamID // TODO: do clients send GOAWAY too? maybe? Just Close: cc.mu.Unlock() @@ -9869,9 +9873,12 @@ func (rl *http2clientConnReadLoop) cleanup() { // This avoids a situation where new connections are constantly created, // added to the pool, fail, and are removed from the pool, without any error // being surfaced to the user. - const unusedWaitTime = 5 * time.Second + unusedWaitTime := 5 * time.Second + if cc.idleTimeout > 0 && unusedWaitTime > cc.idleTimeout { + unusedWaitTime = cc.idleTimeout + } idleTime := cc.t.now().Sub(cc.lastActive) - if atomic.LoadUint32(&cc.atomicReused) == 0 && idleTime < unusedWaitTime { + if atomic.LoadUint32(&cc.atomicReused) == 0 && idleTime < unusedWaitTime && !cc.closedOnIdle { cc.idleTimer = cc.t.afterFunc(unusedWaitTime-idleTime, func() { cc.t.connPool().MarkDead(cc) }) diff --git a/src/vendor/golang.org/x/sys/cpu/cpu.go b/src/vendor/golang.org/x/sys/cpu/cpu.go index 02609d5b21d56a..9c105f23afcdc4 100644 --- a/src/vendor/golang.org/x/sys/cpu/cpu.go +++ b/src/vendor/golang.org/x/sys/cpu/cpu.go @@ -72,6 +72,9 @@ var X86 struct { HasSSSE3 bool // Supplemental streaming SIMD extension 3 HasSSE41 bool // Streaming SIMD extension 4 and 4.1 HasSSE42 bool // Streaming SIMD extension 4 and 4.2 + HasAVXIFMA bool // Advanced vector extension Integer Fused Multiply Add + HasAVXVNNI bool // Advanced vector extension Vector Neural Network Instructions + HasAVXVNNIInt8 bool // Advanced vector extension Vector Neural Network Int8 instructions _ CacheLinePad } diff --git a/src/vendor/golang.org/x/sys/cpu/cpu_x86.go b/src/vendor/golang.org/x/sys/cpu/cpu_x86.go index 600a6807861e7f..1e642f3304fa87 100644 --- a/src/vendor/golang.org/x/sys/cpu/cpu_x86.go +++ b/src/vendor/golang.org/x/sys/cpu/cpu_x86.go @@ -53,6 +53,9 @@ func initOptions() { {Name: "sse41", Feature: &X86.HasSSE41}, {Name: "sse42", Feature: &X86.HasSSE42}, {Name: "ssse3", Feature: &X86.HasSSSE3}, + {Name: "avxifma", Feature: &X86.HasAVXIFMA}, + {Name: "avxvnni", Feature: &X86.HasAVXVNNI}, + {Name: "avxvnniint8", Feature: &X86.HasAVXVNNIInt8}, // These capabilities should always be enabled on amd64: {Name: "sse2", Feature: &X86.HasSSE2, Required: runtime.GOARCH == "amd64"}, @@ -106,7 +109,7 @@ func archInit() { return } - _, ebx7, ecx7, edx7 := cpuid(7, 0) + eax7, ebx7, ecx7, edx7 := cpuid(7, 0) X86.HasBMI1 = isSet(3, ebx7) X86.HasAVX2 = isSet(5, ebx7) && osSupportsAVX X86.HasBMI2 = isSet(8, ebx7) @@ -134,14 +137,24 @@ func archInit() { X86.HasAVX512VAES = isSet(9, ecx7) X86.HasAVX512VBMI2 = isSet(6, ecx7) X86.HasAVX512BITALG = isSet(12, ecx7) - - eax71, _, _, _ := cpuid(7, 1) - X86.HasAVX512BF16 = isSet(5, eax71) } X86.HasAMXTile = isSet(24, edx7) X86.HasAMXInt8 = isSet(25, edx7) X86.HasAMXBF16 = isSet(22, edx7) + + // These features depend on the second level of extended features. + if eax7 >= 1 { + eax71, _, _, edx71 := cpuid(7, 1) + if X86.HasAVX512 { + X86.HasAVX512BF16 = isSet(5, eax71) + } + if X86.HasAVX { + X86.HasAVXIFMA = isSet(23, eax71) + X86.HasAVXVNNI = isSet(4, eax71) + X86.HasAVXVNNIInt8 = isSet(4, edx71) + } + } } func isSet(bitpos uint, value uint32) bool { diff --git a/src/vendor/modules.txt b/src/vendor/modules.txt index 45bf5af236cad6..5ffa43e85ef3ea 100644 --- a/src/vendor/modules.txt +++ b/src/vendor/modules.txt @@ -1,4 +1,4 @@ -# golang.org/x/crypto v0.30.0 +# golang.org/x/crypto v0.33.1-0.20250210163342-e47973b1c108 ## explicit; go 1.20 golang.org/x/crypto/chacha20 golang.org/x/crypto/chacha20poly1305 @@ -6,7 +6,7 @@ golang.org/x/crypto/cryptobyte golang.org/x/crypto/cryptobyte/asn1 golang.org/x/crypto/internal/alias golang.org/x/crypto/internal/poly1305 -# golang.org/x/net v0.32.1-0.20250121202134-9a960c88dd98 +# golang.org/x/net v0.34.1-0.20250123000230-c72e89d6a9e4 ## explicit; go 1.18 golang.org/x/net/dns/dnsmessage golang.org/x/net/http/httpguts @@ -15,10 +15,10 @@ golang.org/x/net/http2/hpack golang.org/x/net/idna golang.org/x/net/lif golang.org/x/net/nettest -# golang.org/x/sys v0.28.0 +# golang.org/x/sys v0.30.0 ## explicit; go 1.18 golang.org/x/sys/cpu -# golang.org/x/text v0.21.0 +# golang.org/x/text v0.22.0 ## explicit; go 1.18 golang.org/x/text/secure/bidirule golang.org/x/text/transform From 127288b4c6527e92ac788d32ece96ef67211b2c8 Mon Sep 17 00:00:00 2001 From: Michael Matloob Date: Mon, 10 Feb 2025 15:17:54 -0500 Subject: [PATCH 336/397] cmd/go: add errors obtaining c compiler version to cache key If there's an error getting the version of the c compiler, add the error to the input used to produce the cache key. In the case where we can't parse the version, the text of the output of the command is part of the error, so different unparseable versions will produce different cache keys. Before, we wouldn't add anything to the key when there was an error getting the version, so we wouldn't distinguish a missing compiler from one where we couldn't parse the version. Fixes #64589 Change-Id: I27f853e8ff40002e2f045b2210633b38f93d0130 Reviewed-on: https://go-review.googlesource.com/c/go/+/648196 LUCI-TryBot-Result: Go LUCI Reviewed-by: Sam Thanawalla Reviewed-by: Alan Donovan --- src/cmd/go/internal/work/exec.go | 6 ++ .../script/build_cc_cache_issue64589.txt | 100 ++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 src/cmd/go/testdata/script/build_cc_cache_issue64589.txt diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go index c79d6f73ef4a9d..8d47b8d5cfe3a5 100644 --- a/src/cmd/go/internal/work/exec.go +++ b/src/cmd/go/internal/work/exec.go @@ -301,12 +301,16 @@ func (b *Builder) buildActionID(a *Action) cache.ActionID { // compiler changes we rebuild the package. if ccID, _, err := b.gccToolID(ccExe[0], "c"); err == nil { fmt.Fprintf(h, "CC ID=%q\n", ccID) + } else { + fmt.Fprintf(h, "CC ID ERROR=%q\n", err) } if len(p.CXXFiles)+len(p.SwigCXXFiles) > 0 { cxxExe := b.cxxExe() fmt.Fprintf(h, "CXX=%q %q\n", cxxExe, cxxflags) if cxxID, _, err := b.gccToolID(cxxExe[0], "c++"); err == nil { fmt.Fprintf(h, "CXX ID=%q\n", cxxID) + } else { + fmt.Fprintf(h, "CXX ID ERROR=%q\n", err) } } if len(p.FFiles) > 0 { @@ -314,6 +318,8 @@ func (b *Builder) buildActionID(a *Action) cache.ActionID { fmt.Fprintf(h, "FC=%q %q\n", fcExe, fflags) if fcID, _, err := b.gccToolID(fcExe[0], "f95"); err == nil { fmt.Fprintf(h, "FC ID=%q\n", fcID) + } else { + fmt.Fprintf(h, "FC ID ERROR=%q\n", err) } } // TODO(rsc): Should we include the SWIG version? diff --git a/src/cmd/go/testdata/script/build_cc_cache_issue64589.txt b/src/cmd/go/testdata/script/build_cc_cache_issue64589.txt new file mode 100644 index 00000000000000..42ae91b196c2b6 --- /dev/null +++ b/src/cmd/go/testdata/script/build_cc_cache_issue64589.txt @@ -0,0 +1,100 @@ +# Regression test for https://go.dev/issue/64589: +# This test is very similar to build_cc_cache_issue64423. Issue #64423 +# was that we weren't properly parsing the versions output by the compiler. +# That test checked that we could parse the version and incorporate the +# version into the hash for the action id. This issue #64589 is that +# we treat all errors getting the version of the compiler the same, so +# we'd get the same action id for a missing compiler vs one whose +# version is unparseable. So the test now first does a run with a compiler +# that produces unparseable version output, and then runs it again with a missing +# compiler and ensures the command doesn't return the cached output for the +# first run when running the second run. + +[!cgo] skip +[short] skip 'builds and links a fake clang binary' +[!cc:clang] skip 'test is specific to clang version parsing' + +# Save the location of the real clang command for our fake one to use. +go run ./which clang +cp stdout $WORK/.realclang + +# Build a fake clang and ensure that it is the one in $PATH. +mkdir $WORK/bin +go build -o $WORK/bin/clang$GOEXE ./fakeclang +[!GOOS:plan9] env PATH=$WORK${/}bin +[GOOS:plan9] env path=$WORK${/}bin + +# Force CGO_ENABLED=1 so that the following commands should error +# out if the fake clang doesn't work. +env CGO_ENABLED=1 + +# The bug in https://go.dev/issue/64589 resulted in cache keys that +# didn't contain any information about the error getting the compiler version. +# Since the bug was in cache key computation, isolate the cache: +# if we change the way caching works, we want the test to fail +# instead of accidentally reusing the cached information from a +# previous test run. +env GOCACHE=$WORK${/}.cache +mkdir $GOCACHE + +go build -x runtime/cgo + + # Tell our fake clang to stop working. + # Previously, 'go build -x runtime/cgo' would continue to + # succeed because both the broken clang and the non-broken one + # resulted in a cache key with no clang version information. +env GO_BREAK_CLANG=1 +! go build -x runtime/cgo +stderr '# runtime/cgo\nGO_BREAK_CLANG is set' + +-- go.mod -- +module example/issue64589 +go 1.20 +-- which/main.go -- +package main + +import ( + "os" + "os/exec" +) + +func main() { + path, err := exec.LookPath(os.Args[1]) + if err != nil { + panic(err) + } + os.Stdout.WriteString(path) +} +-- fakeclang/main.go -- +package main + +import ( + "bytes" + "log" + "os" + "os/exec" + "path/filepath" + "slices" +) + +func main() { + if os.Getenv("GO_BREAK_CLANG") != "" { + os.Stderr.WriteString("GO_BREAK_CLANG is set\n") + os.Exit(1) + } + + b, err := os.ReadFile(filepath.Join(os.Getenv("WORK"), ".realclang")) + if err != nil { + log.Fatal(err) + } + if slices.Contains(os.Args, "-###") { // We are being run by gccToolID to determine the tool id used in the action id. + return // The important thing is that we don't print the string "version"! + } + clang := string(bytes.TrimSpace(b)) + cmd := exec.Command(clang, os.Args[1:]...) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + log.Fatal(err) + } +} From 024c900b43e4531576e726ef1cdb1cc119e64203 Mon Sep 17 00:00:00 2001 From: Sean Liao Date: Tue, 11 Feb 2025 16:30:22 +0000 Subject: [PATCH 337/397] cmd/go: clarify vcs suffix to repo mapping For #71635 Change-Id: I12ec2a810cfcaf2565b0d9c518b0921ec54e9f12 Reviewed-on: https://go-review.googlesource.com/c/go/+/648475 Reviewed-by: Michael Matloob Auto-Submit: Sam Thanawalla LUCI-TryBot-Result: Go LUCI Reviewed-by: Sam Thanawalla --- src/cmd/go/alldocs.go | 4 ++-- src/cmd/go/internal/help/helpdoc.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index fc85995373017d..6f0cb1b6981020 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -2924,12 +2924,12 @@ // import "example.org/user/foo.hg" // // denotes the root directory of the Mercurial repository at -// example.org/user/foo or foo.hg, and +// example.org/user/foo, and // // import "example.org/repo.git/foo/bar" // // denotes the foo/bar directory of the Git repository at -// example.org/repo or repo.git. +// example.org/repo. // // When a version control system supports multiple protocols, // each is tried in turn when downloading. For example, a Git diff --git a/src/cmd/go/internal/help/helpdoc.go b/src/cmd/go/internal/help/helpdoc.go index e96849521525d6..4adabfbbd4b491 100644 --- a/src/cmd/go/internal/help/helpdoc.go +++ b/src/cmd/go/internal/help/helpdoc.go @@ -214,12 +214,12 @@ For example, import "example.org/user/foo.hg" denotes the root directory of the Mercurial repository at -example.org/user/foo or foo.hg, and +example.org/user/foo, and import "example.org/repo.git/foo/bar" denotes the foo/bar directory of the Git repository at -example.org/repo or repo.git. +example.org/repo. When a version control system supports multiple protocols, each is tried in turn when downloading. For example, a Git From 6519aa955dd765072ac25881b127796d43de2b9a Mon Sep 17 00:00:00 2001 From: Alan Donovan Date: Wed, 4 Sep 2024 12:30:47 -0400 Subject: [PATCH 338/397] vet: add regression test for printf checker regression Updates golang/go#68796 Change-Id: I5bfa80216deff76fd9aabe9882f93fbfaebef957 Reviewed-on: https://go-review.googlesource.com/c/go/+/610737 Auto-Submit: Alan Donovan LUCI-TryBot-Result: Go LUCI Reviewed-by: Michael Matloob --- src/cmd/vet/testdata/print/print.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/cmd/vet/testdata/print/print.go b/src/cmd/vet/testdata/print/print.go index fffe571163889f..e00222c42b5aef 100644 --- a/src/cmd/vet/testdata/print/print.go +++ b/src/cmd/vet/testdata/print/print.go @@ -678,3 +678,12 @@ func PointersToCompoundTypes() { } fmt.Printf("%s\n", T1{&T2{"x"}}) // ERROR "Printf format %s has arg T1{&T2{.x.}} of wrong type .*print\.T1" } + +// Regression test for #68796: materialized aliases cause printf +// checker not to recognize "any" as identical to "interface{}". +func printfUsingAnyNotEmptyInterface(format string, args ...any) { + _ = fmt.Sprintf(format, args...) +} +func _() { + printfUsingAnyNotEmptyInterface("%s", 123) // ERROR "wrong type" +} From fc0049fb20fe5998232a365b5ee08d6730693f1b Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Thu, 6 Feb 2025 11:34:20 +0100 Subject: [PATCH 339/397] crypto/tls: document FIPS 140-3 mode behavior Change-Id: I6a6a465612cf76d148b9758ee3fcdc8606497830 Reviewed-on: https://go-review.googlesource.com/c/go/+/648835 Reviewed-by: Daniel McCarney LUCI-TryBot-Result: Go LUCI Auto-Submit: Filippo Valsorda Reviewed-by: Roland Shoemaker Reviewed-by: Ian Lance Taylor --- src/crypto/tls/tls.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/crypto/tls/tls.go b/src/crypto/tls/tls.go index f3089f0ed68dda..c64201abc1f406 100644 --- a/src/crypto/tls/tls.go +++ b/src/crypto/tls/tls.go @@ -4,6 +4,15 @@ // Package tls partially implements TLS 1.2, as specified in RFC 5246, // and TLS 1.3, as specified in RFC 8446. +// +// # FIPS 140-3 mode +// +// When the program is in [FIPS 140-3 mode], this package behaves as if +// only protocol versions, cipher suites, signature algorithms, and +// key exchange algorithms approved by NIST SP 800-52r2 are implemented. +// Others are silently ignored and not negotiated. +// +// [FIPS 140-3 mode]: https://go.dev/doc/security/fips140 package tls // BUG(agl): The crypto/tls package only implements some countermeasures From fb5f78a14f71f043604826067d1f224e1e90a2f5 Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Wed, 12 Feb 2025 09:23:14 -0800 Subject: [PATCH 340/397] internal/syscall: add cgo_import_dynamic for Fchmodat on AIX and Solaris For #67002 Change-Id: I1709fd51ba52c074501420943d311c785a49d851 Reviewed-on: https://go-review.googlesource.com/c/go/+/649015 LUCI-TryBot-Result: Go LUCI Auto-Submit: Damien Neil Reviewed-by: Ian Lance Taylor --- src/internal/syscall/unix/at_aix.go | 1 + src/internal/syscall/unix/at_solaris.go | 1 + 2 files changed, 2 insertions(+) diff --git a/src/internal/syscall/unix/at_aix.go b/src/internal/syscall/unix/at_aix.go index 5c2f00efe59cf3..e679efc34459d8 100644 --- a/src/internal/syscall/unix/at_aix.go +++ b/src/internal/syscall/unix/at_aix.go @@ -4,6 +4,7 @@ package unix +//go:cgo_import_dynamic libc_fchmodat fchmodat "libc.a/shr_64.o" //go:cgo_import_dynamic libc_fstatat fstatat "libc.a/shr_64.o" //go:cgo_import_dynamic libc_openat openat "libc.a/shr_64.o" //go:cgo_import_dynamic libc_unlinkat unlinkat "libc.a/shr_64.o" diff --git a/src/internal/syscall/unix/at_solaris.go b/src/internal/syscall/unix/at_solaris.go index fa65d9e8d95990..a4910f1003aaae 100644 --- a/src/internal/syscall/unix/at_solaris.go +++ b/src/internal/syscall/unix/at_solaris.go @@ -13,6 +13,7 @@ func syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err func rawSyscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) //go:cgo_import_dynamic libc_faccessat faccessat "libc.so" +//go:cgo_import_dynamic libc_fchmodat fchmodat "libc.so" //go:cgo_import_dynamic libc_fstatat fstatat "libc.so" //go:cgo_import_dynamic libc_openat openat "libc.so" //go:cgo_import_dynamic libc_unlinkat unlinkat "libc.so" From 679cd8e7798db593d0973519f6d3ee7ea7659142 Mon Sep 17 00:00:00 2001 From: Mateusz Poliwczak Date: Wed, 12 Feb 2025 07:16:32 +0000 Subject: [PATCH 341/397] reflect, internal/abi: speed up TypeFor[T] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit goos: linux goarch: amd64 pkg: reflect cpu: AMD Ryzen 5 4600G with Radeon Graphics │ /tmp/before │ /tmp/after │ │ sec/op │ sec/op vs base │ TypeForString-12 2.091n ± 1% 1.174n ± 1% -43.84% (p=0.000 n=20) TypeForError-12 7.5810n ± 3% 0.9372n ± 1% -87.64% (p=0.000 n=20) Change-Id: I22022f99b2dd2029f02d9ed8477b209adf7e9496 GitHub-Last-Rev: 64d2ac5bb2f3b2a659663832a4641ff4fc83bddd GitHub-Pull-Request: golang/go#71654 Reviewed-on: https://go-review.googlesource.com/c/go/+/648395 LUCI-TryBot-Result: Go LUCI Reviewed-by: Ian Lance Taylor Reviewed-by: Cherry Mui Auto-Submit: Ian Lance Taylor --- src/internal/abi/type.go | 6 +----- src/reflect/type.go | 14 +++++--------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/src/internal/abi/type.go b/src/internal/abi/type.go index 1c1793fcf5ba37..4671b0da2848f3 100644 --- a/src/internal/abi/type.go +++ b/src/internal/abi/type.go @@ -187,11 +187,7 @@ func TypeOf(a any) *Type { // TypeFor returns the abi.Type for a type parameter. func TypeFor[T any]() *Type { - var v T - if t := TypeOf(v); t != nil { - return t // optimize for T being a non-interface kind - } - return TypeOf((*T)(nil)).Elem() // only for an interface kind + return (*PtrType)(unsafe.Pointer(TypeOf((*T)(nil)))).Elem } func (t *Type) Kind() Kind { return t.Kind_ & KindMask } diff --git a/src/reflect/type.go b/src/reflect/type.go index 0e41a6db992e1c..e5ee7f90d0202c 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -1303,6 +1303,11 @@ func TypeOf(i any) Type { return toType(abi.TypeOf(i)) } +// TypeFor returns the [Type] that represents the type argument T. +func TypeFor[T any]() Type { + return toType(abi.TypeFor[T]()) +} + // rtypeOf directly extracts the *rtype of the provided value. func rtypeOf(i any) *abi.Type { return abi.TypeOf(i) @@ -2850,12 +2855,3 @@ func addTypeBits(bv *bitVector, offset uintptr, t *abi.Type) { } } } - -// TypeFor returns the [Type] that represents the type argument T. -func TypeFor[T any]() Type { - var v T - if t := TypeOf(v); t != nil { - return t // optimize for T being a non-interface kind - } - return TypeOf((*T)(nil)).Elem() // only for an interface kind -} From f2cadb6b2e589247be6730e8cb13c23d88450fbf Mon Sep 17 00:00:00 2001 From: Dmitri Shuralyov Date: Tue, 11 Feb 2025 18:08:32 -0500 Subject: [PATCH 342/397] cmd/pprof: update vendored github.com/google/pprof [generated] Pull in the latest published version of github.com/google/pprof as part of the continuous process of keeping Go's dependencies up to date. For #36905. [git-generate] cd src/cmd go get github.com/google/pprof@v0.0.0-20250208200701-d0013a598941 go mod tidy go mod vendor Change-Id: I87e5621286d3db85f358fb86875aaf65bd7811a9 Reviewed-on: https://go-review.googlesource.com/c/go/+/648916 Auto-Submit: Dmitri Shuralyov LUCI-TryBot-Result: Go LUCI Reviewed-by: Cherry Mui Reviewed-by: Dmitri Shuralyov --- src/cmd/go.mod | 2 +- src/cmd/go.sum | 4 +-- .../pprof/internal/driver/html/stacks.js | 4 ++- .../google/pprof/internal/report/report.go | 33 +++++++++++-------- .../pprof/internal/symbolizer/symbolizer.go | 14 ++++++++ src/cmd/vendor/modules.txt | 2 +- 6 files changed, 41 insertions(+), 18 deletions(-) diff --git a/src/cmd/go.mod b/src/cmd/go.mod index 5f4e4186160dd1..99c4046490c7d0 100644 --- a/src/cmd/go.mod +++ b/src/cmd/go.mod @@ -3,7 +3,7 @@ module cmd go 1.25 require ( - github.com/google/pprof v0.0.0-20241101162523-b92577c0c142 + github.com/google/pprof v0.0.0-20250208200701-d0013a598941 golang.org/x/arch v0.14.0 golang.org/x/build v0.0.0-20250211223606-a5e3f75caa63 golang.org/x/mod v0.23.0 diff --git a/src/cmd/go.sum b/src/cmd/go.sum index 75299131f6a996..78f797c648efe4 100644 --- a/src/cmd/go.sum +++ b/src/cmd/go.sum @@ -1,7 +1,7 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/pprof v0.0.0-20241101162523-b92577c0c142 h1:sAGdeJj0bnMgUNVeUpp6AYlVdCt3/GdI3pGRqsNSQLs= -github.com/google/pprof v0.0.0-20241101162523-b92577c0c142/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/pprof v0.0.0-20250208200701-d0013a598941 h1:43XjGa6toxLpeksjcxs1jIoIyr+vUfOqY2c6HB4bpoc= +github.com/google/pprof v0.0.0-20250208200701-d0013a598941/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/ianlancetaylor/demangle v0.0.0-20240912202439-0a2b6291aafd h1:EVX1s+XNss9jkRW9K6XGJn2jL2lB1h5H804oKPsxOec= github.com/ianlancetaylor/demangle v0.0.0-20240912202439-0a2b6291aafd/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw= github.com/yuin/goldmark v1.6.0 h1:boZcn2GTjpsynOsC0iJHnBWa4Bi0qzfJjthwauItG68= diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/html/stacks.js b/src/cmd/vendor/github.com/google/pprof/internal/driver/html/stacks.js index 484c2d75908a4d..7db06996da499c 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/driver/html/stacks.js +++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/html/stacks.js @@ -135,7 +135,9 @@ function stackViewer(stacks, nodes) { } // Update params to include src. - let v = pprofQuoteMeta(stacks.Sources[src].FullName); + // When `pprof` is invoked with `-lines`, FullName will be suffixed with `:`, + // which we need to remove. + let v = pprofQuoteMeta(stacks.Sources[src].FullName.replace(/:[0-9]+$/, '')); if (param != 'f' && param != 'sf') { // old f,sf values are overwritten // Add new source to current parameter value. const old = params.get(param); diff --git a/src/cmd/vendor/github.com/google/pprof/internal/report/report.go b/src/cmd/vendor/github.com/google/pprof/internal/report/report.go index 8e73f179ecd09b..9d52872b7d4383 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/report/report.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/report/report.go @@ -699,13 +699,17 @@ func printTags(w io.Writer, rpt *Report) error { p := rpt.prof o := rpt.options - formatTag := func(v int64, key string) string { - return measurement.ScaledLabel(v, key, o.OutputUnit) + formatTag := func(v int64, unit string) string { + return measurement.ScaledLabel(v, unit, o.OutputUnit) } - // Hashtable to keep accumulate tags as key,value,count. + // Accumulate tags as key,value,count. tagMap := make(map[string]map[string]int64) + // Note that we assume single value per tag per sample. Multiple values are + // encodable in the format but are discouraged. + tagTotalMap := make(map[string]int64) for _, s := range p.Sample { + sampleValue := o.SampleValue(s.Value) for key, vals := range s.Label { for _, val := range vals { valueMap, ok := tagMap[key] @@ -713,7 +717,8 @@ func printTags(w io.Writer, rpt *Report) error { valueMap = make(map[string]int64) tagMap[key] = valueMap } - valueMap[val] += o.SampleValue(s.Value) + valueMap[val] += sampleValue + tagTotalMap[key] += sampleValue } } for key, vals := range s.NumLabel { @@ -725,7 +730,8 @@ func printTags(w io.Writer, rpt *Report) error { valueMap = make(map[string]int64) tagMap[key] = valueMap } - valueMap[val] += o.SampleValue(s.Value) + valueMap[val] += sampleValue + tagTotalMap[key] += sampleValue } } } @@ -736,22 +742,23 @@ func printTags(w io.Writer, rpt *Report) error { } tabw := tabwriter.NewWriter(w, 0, 0, 1, ' ', tabwriter.AlignRight) for _, tagKey := range graph.SortTags(tagKeys, true) { - var total int64 key := tagKey.Name tags := make([]*graph.Tag, 0, len(tagMap[key])) for t, c := range tagMap[key] { - total += c tags = append(tags, &graph.Tag{Name: t, Flat: c}) } - f, u := measurement.Scale(total, o.SampleUnit, o.OutputUnit) - fmt.Fprintf(tabw, "%s:\t Total %.1f%s\n", key, f, u) + tagTotal, profileTotal := tagTotalMap[key], rpt.Total() + if profileTotal > 0 { + fmt.Fprintf(tabw, "%s:\t Total %s of %s (%s)\n", key, rpt.formatValue(tagTotal), rpt.formatValue(profileTotal), measurement.Percentage(tagTotal, profileTotal)) + } else { + fmt.Fprintf(tabw, "%s:\t Total %s of %s\n", key, rpt.formatValue(tagTotal), rpt.formatValue(profileTotal)) + } for _, t := range graph.SortTags(tags, true) { - f, u := measurement.Scale(t.FlatValue(), o.SampleUnit, o.OutputUnit) - if total > 0 { - fmt.Fprintf(tabw, " \t%.1f%s (%s):\t %s\n", f, u, measurement.Percentage(t.FlatValue(), total), t.Name) + if profileTotal > 0 { + fmt.Fprintf(tabw, " \t%s (%s):\t %s\n", rpt.formatValue(t.FlatValue()), measurement.Percentage(t.FlatValue(), profileTotal), t.Name) } else { - fmt.Fprintf(tabw, " \t%.1f%s:\t %s\n", f, u, t.Name) + fmt.Fprintf(tabw, " \t%s:\t %s\n", rpt.formatValue(t.FlatValue()), t.Name) } } fmt.Fprintln(tabw) diff --git a/src/cmd/vendor/github.com/google/pprof/internal/symbolizer/symbolizer.go b/src/cmd/vendor/github.com/google/pprof/internal/symbolizer/symbolizer.go index 0d451364619381..95c15b136655c7 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/symbolizer/symbolizer.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/symbolizer/symbolizer.go @@ -257,6 +257,10 @@ func Demangle(prof *profile.Profile, force bool, demanglerMode string) { } options := demanglerModeToOptions(demanglerMode) + // Bail out fast to avoid any parsing, if we really don't want any demangling. + if len(options) == 0 { + return + } for _, fn := range prof.Function { demangleSingleFunction(fn, options) } @@ -288,6 +292,16 @@ func demangleSingleFunction(fn *profile.Function, options []demangle.Option) { fn.Name = demangled return } + + // OSX has all the symbols prefixed with extra '_' so lets try + // once more without it + if strings.HasPrefix(fn.SystemName, "_") { + if demangled := demangle.Filter(fn.SystemName[1:], o...); demangled != fn.SystemName { + fn.Name = demangled + return + } + } + // Could not demangle. Apply heuristics in case the name is // already demangled. name := fn.SystemName diff --git a/src/cmd/vendor/modules.txt b/src/cmd/vendor/modules.txt index 703d9364eac99f..24a3c19576bc28 100644 --- a/src/cmd/vendor/modules.txt +++ b/src/cmd/vendor/modules.txt @@ -1,4 +1,4 @@ -# github.com/google/pprof v0.0.0-20241101162523-b92577c0c142 +# github.com/google/pprof v0.0.0-20250208200701-d0013a598941 ## explicit; go 1.22 github.com/google/pprof/driver github.com/google/pprof/internal/binutils From 3902e9ef4e4543c6ac7371174a122ca090af971a Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Wed, 12 Feb 2025 15:24:10 -0800 Subject: [PATCH 343/397] internal/abi: remove go122 flag We no longer need this flag in case we need to rollback. Change-Id: Id8b8f76380237f2d80a14037e88df4917c843f03 Reviewed-on: https://go-review.googlesource.com/c/go/+/649095 Reviewed-by: Michael Stapelberg LUCI-TryBot-Result: Go LUCI Reviewed-by: Keith Randall Auto-Submit: Keith Randall --- src/internal/abi/switch.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/internal/abi/switch.go b/src/internal/abi/switch.go index 9669fe51d5aa75..df6f99c945910f 100644 --- a/src/internal/abi/switch.go +++ b/src/internal/abi/switch.go @@ -27,12 +27,7 @@ type InterfaceSwitchCacheEntry struct { Itab uintptr } -const go122InterfaceSwitchCache = true - func UseInterfaceSwitchCache(goarch string) bool { - if !go122InterfaceSwitchCache { - return false - } // We need an atomic load instruction to make the cache multithreaded-safe. // (AtomicLoadPtr needs to be implemented in cmd/compile/internal/ssa/_gen/ARCH.rules.) switch goarch { From 3e0f9e3973f6190cb63c511175e169543a466fe6 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Mon, 27 Jan 2025 13:02:27 +0100 Subject: [PATCH 344/397] crypto/internal/fips140test: add functional tests Running TestIntegrityCheckFailure|TestCASTFailures|TestFIPS140 with -v and the appropriate GOFIPS140 environment variables will produce logs sufficient for the functional testing session of the FIPS 140-3 validation. The tests can also be cross-compiled with -c and executed on the target. Change-Id: I6a6a465606518923d3f288e030c0f1b977aa6415 Reviewed-on: https://go-review.googlesource.com/c/go/+/648816 Reviewed-by: Ian Lance Taylor Reviewed-by: Daniel McCarney LUCI-TryBot-Result: Go LUCI Auto-Submit: Filippo Valsorda Reviewed-by: Roland Shoemaker --- src/crypto/internal/fips140test/check_test.go | 60 ++- src/crypto/internal/fips140test/fips_test.go | 407 ++++++++++++++++++ .../internal/fips140test/nistec_test.go | 7 - .../internal/fips140test/sshkdf_test.go | 27 +- 4 files changed, 465 insertions(+), 36 deletions(-) diff --git a/src/crypto/internal/fips140test/check_test.go b/src/crypto/internal/fips140test/check_test.go index 6b0cd3f39e1695..3c594bdb338b0e 100644 --- a/src/crypto/internal/fips140test/check_test.go +++ b/src/crypto/internal/fips140test/check_test.go @@ -5,6 +5,7 @@ package fipstest import ( + "bytes" "crypto/internal/fips140" . "crypto/internal/fips140/check" "crypto/internal/fips140/check/checktest" @@ -13,14 +14,14 @@ import ( "internal/godebug" "internal/testenv" "os" + "path/filepath" + "runtime" "testing" "unicode" "unsafe" ) -const enableFIPSTest = true - -func TestFIPSCheckVerify(t *testing.T) { +func TestIntegrityCheck(t *testing.T) { if Verified { t.Logf("verified") return @@ -30,15 +31,11 @@ func TestFIPSCheckVerify(t *testing.T) { t.Fatalf("GODEBUG=fips140=on but verification did not run") } - if !enableFIPSTest { - return - } - if err := fips140.Supported(); err != nil { t.Skipf("skipping: %v", err) } - cmd := testenv.Command(t, os.Args[0], "-test.v", "-test.run=TestFIPSCheck") + cmd := testenv.Command(t, os.Args[0], "-test.v", "-test.run=TestIntegrityCheck") cmd.Env = append(cmd.Environ(), "GODEBUG=fips140=on") out, err := cmd.CombinedOutput() if err != nil { @@ -47,11 +44,52 @@ func TestFIPSCheckVerify(t *testing.T) { t.Logf("exec'ed GODEBUG=fips140=on and succeeded:\n%s", out) } -func TestFIPSCheckInfo(t *testing.T) { - if !enableFIPSTest { - return +func TestIntegrityCheckFailure(t *testing.T) { + moduleStatus(t) + testenv.MustHaveExec(t) + if err := fips140.Supported(); err != nil { + t.Skipf("skipping: %v", err) + } + + bin, err := os.ReadFile(os.Args[0]) + if err != nil { + t.Fatal(err) } + // Replace the expected module checksum with a different value. + bin = bytes.ReplaceAll(bin, Linkinfo.Sum[:], bytes.Repeat([]byte("X"), len(Linkinfo.Sum))) + + binPath := filepath.Join(t.TempDir(), "fips140test.exe") + if err := os.WriteFile(binPath, bin, 0o755); err != nil { + t.Fatal(err) + } + + if runtime.GOOS == "darwin" { + // Regenerate the macOS ad-hoc code signature. + cmd := testenv.Command(t, "codesign", "-s", "-", "-f", binPath) + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("codesign failed: %v\n%s", err, out) + } + } + + t.Logf("running modified binary...") + cmd := testenv.Command(t, binPath, "-test.v", "-test.run=TestIntegrityCheck$") + cmd.Env = append(cmd.Environ(), "GODEBUG=fips140=on") + out, err := cmd.CombinedOutput() + t.Logf("%s", out) + if err == nil { + t.Errorf("modified binary did not fail as expected") + } + if !bytes.Contains(out, []byte("fips140: verification mismatch")) { + t.Errorf("modified binary did not fail with expected message") + } + if bytes.Contains(out, []byte("verified")) { + t.Errorf("modified binary did not exit") + } +} + +func TestIntegrityCheckInfo(t *testing.T) { if err := fips140.Supported(); err != nil { t.Skipf("skipping: %v", err) } diff --git a/src/crypto/internal/fips140test/fips_test.go b/src/crypto/internal/fips140test/fips_test.go index 8da5278050ba6c..1dd8aa21a9628d 100644 --- a/src/crypto/internal/fips140test/fips_test.go +++ b/src/crypto/internal/fips140test/fips_test.go @@ -9,14 +9,421 @@ // to either minimize, skip, or remove them. Finally, the module needs to avoid // importing internal packages like testenv and cryptotest to avoid locking in // their APIs. +// +// Also, this package includes the ACVP and functional testing harnesses. package fipstest import ( + "bytes" + "crypto/internal/boring" + "crypto/internal/fips140" + "crypto/internal/fips140/aes" + "crypto/internal/fips140/aes/gcm" + "crypto/internal/fips140/check" + "crypto/internal/fips140/drbg" + "crypto/internal/fips140/ecdh" + "crypto/internal/fips140/ecdsa" + "crypto/internal/fips140/ed25519" + "crypto/internal/fips140/hkdf" + "crypto/internal/fips140/hmac" + "crypto/internal/fips140/mlkem" + "crypto/internal/fips140/pbkdf2" + "crypto/internal/fips140/rsa" + "crypto/internal/fips140/sha256" + "crypto/internal/fips140/sha3" + "crypto/internal/fips140/sha512" + "crypto/internal/fips140/tls12" + "crypto/internal/fips140/tls13" + "crypto/rand" "encoding/hex" "strings" "testing" ) +func moduleStatus(t *testing.T) { + if fips140.Enabled { + t.Log("FIPS 140-3 mode enabled") + } else { + t.Log("FIPS 140-3 mode not enabled") + } + + t.Logf("Module name: %s", fips140.Name()) + t.Logf("Module version: %s", fips140.Version()) + + if check.Verified { + t.Log("FIPS 140-3 integrity self-check succeeded") + } else { + t.Log("FIPS 140-3 integrity self-check not succeeded") + } +} + +func TestFIPS140(t *testing.T) { + moduleStatus(t) + if boring.Enabled { + t.Skip("Go+BoringCrypto shims prevent the service indicator from being set") + } + + aesKey := make([]byte, 128/8) + aesIV := make([]byte, aes.BlockSize) + plaintext := []byte("Go Cryptographic Module TestFIPS140 plaintext...") + plaintextSHA256 := decodeHex(t, "06b2614e2ef315832b23f5d0ff70294d8ddd3889527dfbe75707fe41da929325") + aesBlock, err := aes.New(aesKey) + fatalIfErr(t, err) + + t.Run("AES-CTR", func(t *testing.T) { + ensureServiceIndicator(t) + ctr := aes.NewCTR(aesBlock, aesIV) + ciphertext := make([]byte, len(plaintext)) + ctr.XORKeyStream(ciphertext, plaintext) + t.Logf("AES-CTR ciphertext: %x", ciphertext) + out := make([]byte, len(plaintext)) + ctr = aes.NewCTR(aesBlock, aesIV) + ctr.XORKeyStream(out, ciphertext) + t.Logf("AES-CTR decrypted plaintext: %s", out) + if !bytes.Equal(plaintext, out) { + t.Errorf("AES-CTR round trip failed") + } + }) + + t.Run("AES-CBC", func(t *testing.T) { + ensureServiceIndicator(t) + cbcEnc := aes.NewCBCEncrypter(aesBlock, [16]byte(aesIV)) + ciphertext := make([]byte, len(plaintext)) + cbcEnc.CryptBlocks(ciphertext, plaintext) + t.Logf("AES-CBC ciphertext: %x", ciphertext) + cbcDec := aes.NewCBCDecrypter(aesBlock, [16]byte(aesIV)) + out := make([]byte, len(plaintext)) + cbcDec.CryptBlocks(out, ciphertext) + t.Logf("AES-CBC decrypted plaintext: %s", out) + if !bytes.Equal(plaintext, out) { + t.Errorf("AES-CBC round trip failed") + } + }) + + t.Run("AES-GCM", func(t *testing.T) { + ensureServiceIndicator(t) + g, err := gcm.New(aesBlock, 12, 16) + fatalIfErr(t, err) + nonce := make([]byte, 12) + ciphertext := make([]byte, len(plaintext)+g.Overhead()) + gcm.SealWithRandomNonce(g, nonce, ciphertext, plaintext, nil) + t.Logf("AES-GCM ciphertext: %x", ciphertext) + out, err := g.Open(nil, nonce, ciphertext, nil) + fatalIfErr(t, err) + t.Logf("AES-GCM decrypted plaintext: %s", out) + if !bytes.Equal(plaintext, out) { + t.Errorf("AES-GCM round trip failed") + } + }) + + t.Run("Counter KDF", func(t *testing.T) { + ensureServiceIndicator(t) + k := gcm.NewCounterKDF(aesBlock) + context := [12]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12} + key := k.DeriveKey(0x01, context) + t.Logf("Counter KDF key: %x", key) + }) + + t.Run("KAS-ECC-SSC ephemeralUnified", func(t *testing.T) { + ensureServiceIndicator(t) + k, err := ecdh.GenerateKey(ecdh.P256(), rand.Reader) + fatalIfErr(t, err) + pk := k.PublicKey() + shared, err := ecdh.ECDH(ecdh.P256(), k, pk) + fatalIfErr(t, err) + t.Logf("KAS-ECC-SSC shared secret: %x", shared) + }) + + t.Run("ECDSA KeyGen, SigGen, SigVer", func(t *testing.T) { + ensureServiceIndicator(t) + k, err := ecdsa.GenerateKey(ecdsa.P256(), rand.Reader) + fatalIfErr(t, err) + + sig, err := ecdsa.Sign(ecdsa.P256(), sha256.New, k, rand.Reader, plaintextSHA256) + fatalIfErr(t, err) + t.Logf("ECDSA signature: %x", sig) + err = ecdsa.Verify(ecdsa.P256(), k.PublicKey(), plaintextSHA256, sig) + if err != nil { + t.Errorf("ECDSA signature verification failed") + } + + sig, err = ecdsa.SignDeterministic(ecdsa.P256(), sha256.New, k, plaintextSHA256) + fatalIfErr(t, err) + t.Logf("ECDSA deterministic signature: %x", sig) + err = ecdsa.Verify(ecdsa.P256(), k.PublicKey(), plaintextSHA256, sig) + if err != nil { + t.Errorf("ECDSA deterministic signature verification failed") + } + }) + + t.Run("EDDSA KeyGen, SigGen, SigVer", func(t *testing.T) { + ensureServiceIndicator(t) + k, err := ed25519.GenerateKey() + fatalIfErr(t, err) + + sig := ed25519.Sign(k, plaintext) + t.Logf("EDDSA signature: %x", sig) + + pk, err := ed25519.NewPublicKey(k.PublicKey()) + fatalIfErr(t, err) + err = ed25519.Verify(pk, plaintext, sig) + if err != nil { + t.Errorf("EDDSA signature verification failed") + } + }) + + t.Run("ctrDRBG", func(t *testing.T) { + ensureServiceIndicator(t) + r := drbg.NewCounter((*[48]byte)(plaintext)) + r.Reseed((*[48]byte)(plaintext), (*[48]byte)(plaintext)) + out := make([]byte, 16) + r.Generate(out, (*[48]byte)(plaintext)) + t.Logf("ctrDRBG output: %x", out) + }) + + t.Run("HMAC", func(t *testing.T) { + ensureServiceIndicator(t) + h := hmac.New(sha256.New, plaintext) + h.Write(plaintext) + out := h.Sum(nil) + t.Logf("HMAC output: %x", out) + }) + + t.Run("ML-KEM KeyGen, Encap, Decap", func(t *testing.T) { + ensureServiceIndicator(t) + k, err := mlkem.GenerateKey768() + fatalIfErr(t, err) + + ss, c := k.EncapsulationKey().Encapsulate() + t.Logf("ML-KEM encapsulation: %x", c) + + ss2, err := k.Decapsulate(c) + fatalIfErr(t, err) + t.Logf("ML-KEM shared secret: %x", ss) + if !bytes.Equal(ss, ss2) { + t.Errorf("ML-KEM round trip failed") + } + }) + + var rsaKey *rsa.PrivateKey + t.Run("RSA KeyGen", func(t *testing.T) { + ensureServiceIndicator(t) + var err error + rsaKey, err = rsa.GenerateKey(rand.Reader, 2048) + fatalIfErr(t, err) + t.Log("RSA key generated") + }) + + t.Run("RSA SigGen, SigVer PKCS 1.5", func(t *testing.T) { + ensureServiceIndicator(t) + sig, err := rsa.SignPKCS1v15(rsaKey, "SHA-256", plaintextSHA256) + fatalIfErr(t, err) + t.Logf("RSA PKCS1v15 signature: %x", sig) + + err = rsa.VerifyPKCS1v15(rsaKey.PublicKey(), "SHA-256", plaintextSHA256, sig) + fatalIfErr(t, err) + }) + + t.Run("RSA SigGen, SigVer PSS", func(t *testing.T) { + ensureServiceIndicator(t) + sig, err := rsa.SignPSS(rand.Reader, rsaKey, sha256.New(), plaintextSHA256, 16) + fatalIfErr(t, err) + t.Logf("RSA PSS signature: %x", sig) + + err = rsa.VerifyPSS(rsaKey.PublicKey(), sha256.New(), plaintextSHA256, sig) + fatalIfErr(t, err) + }) + + t.Run("KTS IFC OAEP", func(t *testing.T) { + ensureServiceIndicator(t) + c, err := rsa.EncryptOAEP(sha256.New(), sha256.New(), rand.Reader, rsaKey.PublicKey(), plaintextSHA256, nil) + fatalIfErr(t, err) + t.Logf("RSA OAEP ciphertext: %x", c) + + out, err := rsa.DecryptOAEP(sha256.New(), sha256.New(), rsaKey, c, nil) + fatalIfErr(t, err) + t.Logf("RSA OAEP decrypted plaintext: %x", out) + if !bytes.Equal(plaintextSHA256, out) { + t.Errorf("RSA OAEP round trip failed") + } + }) + + t.Run("SHA2-224", func(t *testing.T) { + ensureServiceIndicator(t) + h := sha256.New224() + h.Write(plaintext) + out := h.Sum(nil) + t.Logf("SHA2-224 output: %x", out) + }) + + t.Run("SHA2-256", func(t *testing.T) { + ensureServiceIndicator(t) + h := sha256.New() + h.Write(plaintext) + out := h.Sum(nil) + t.Logf("SHA2-256 output: %x", out) + }) + + t.Run("SHA2-384", func(t *testing.T) { + ensureServiceIndicator(t) + h := sha512.New384() + h.Write(plaintext) + out := h.Sum(nil) + t.Logf("SHA2-384 output: %x", out) + }) + + t.Run("SHA2-512", func(t *testing.T) { + ensureServiceIndicator(t) + h := sha512.New() + h.Write(plaintext) + out := h.Sum(nil) + t.Logf("SHA2-512 output: %x", out) + }) + + t.Run("SHA2-512/224", func(t *testing.T) { + ensureServiceIndicator(t) + h := sha512.New512_224() + h.Write(plaintext) + out := h.Sum(nil) + t.Logf("SHA2-512/224 output: %x", out) + }) + + t.Run("SHA2-512/256", func(t *testing.T) { + ensureServiceIndicator(t) + h := sha512.New512_256() + h.Write(plaintext) + out := h.Sum(nil) + t.Logf("SHA2-512/256 output: %x", out) + }) + + t.Run("SHA3-224", func(t *testing.T) { + ensureServiceIndicator(t) + h := sha3.New224() + h.Write(plaintext) + out := h.Sum(nil) + t.Logf("SHA3-224 output: %x", out) + }) + + t.Run("SHA3-256", func(t *testing.T) { + ensureServiceIndicator(t) + h := sha3.New256() + h.Write(plaintext) + out := h.Sum(nil) + t.Logf("SHA3-256 output: %x", out) + }) + + t.Run("SHA3-384", func(t *testing.T) { + ensureServiceIndicator(t) + h := sha3.New384() + h.Write(plaintext) + out := h.Sum(nil) + t.Logf("SHA3-384 output: %x", out) + }) + + t.Run("SHA3-512", func(t *testing.T) { + ensureServiceIndicator(t) + h := sha3.New512() + h.Write(plaintext) + out := h.Sum(nil) + t.Logf("SHA3-512 output: %x", out) + }) + + t.Run("SHAKE-128", func(t *testing.T) { + ensureServiceIndicator(t) + h := sha3.NewShake128() + h.Write(plaintext) + out := make([]byte, 16) + h.Read(out) + t.Logf("SHAKE-128 output: %x", out) + }) + + t.Run("SHAKE-256", func(t *testing.T) { + ensureServiceIndicator(t) + h := sha3.NewShake256() + h.Write(plaintext) + out := make([]byte, 16) + h.Read(out) + t.Logf("SHAKE-256 output: %x", out) + }) + + t.Run("cSHAKE-128", func(t *testing.T) { + ensureServiceIndicator(t) + h := sha3.NewCShake128(nil, []byte("test")) + h.Write(plaintext) + out := make([]byte, 16) + h.Read(out) + t.Logf("cSHAKE-128 output: %x", out) + }) + + t.Run("cSHAKE-256", func(t *testing.T) { + ensureServiceIndicator(t) + h := sha3.NewCShake256(nil, []byte("test")) + h.Write(plaintext) + out := make([]byte, 16) + h.Read(out) + t.Logf("cSHAKE-256 output: %x", out) + }) + + t.Run("KDA HKDF", func(t *testing.T) { + ensureServiceIndicator(t) + key := hkdf.Key(sha256.New, plaintextSHA256, []byte("salt"), "info", 16) + t.Logf("HKDF key: %x", key) + }) + + t.Run("KDA OneStepNoCounter", func(t *testing.T) { + ensureServiceIndicator(t) + key := hkdf.Extract(sha256.New, plaintextSHA256, []byte("salt")) + t.Logf("KDA OneStepNoCounter key: %x", key) + }) + + t.Run("Feedback KDF", func(t *testing.T) { + ensureServiceIndicator(t) + key := hkdf.Expand(sha256.New, plaintextSHA256, "info", 16) + t.Logf("Feedback KDF key: %x", key) + }) + + t.Run("PBKDF", func(t *testing.T) { + ensureServiceIndicator(t) + key, err := pbkdf2.Key(sha256.New, "password", plaintextSHA256, 2, 16) + fatalIfErr(t, err) + t.Logf("PBKDF key: %x", key) + }) + + t.Run("KDF TLS v1.2 CVL", func(t *testing.T) { + ensureServiceIndicator(t) + key := tls12.MasterSecret(sha256.New, plaintextSHA256, []byte("test")) + t.Logf("TLS v1.2 CVL Master Secret: %x", key) + }) + + t.Run("KDF TLS v1.3 CVL", func(t *testing.T) { + ensureServiceIndicator(t) + es := tls13.NewEarlySecret(sha256.New, plaintextSHA256) + hs := es.HandshakeSecret(plaintextSHA256) + ms := hs.MasterSecret() + client := ms.ClientApplicationTrafficSecret(sha256.New()) + server := ms.ServerApplicationTrafficSecret(sha256.New()) + t.Logf("TLS v1.3 CVL Application Traffic Secrets: client %x, server %x", client, server) + }) +} + +func ensureServiceIndicator(t *testing.T) { + fips140.ResetServiceIndicator() + t.Cleanup(func() { + if fips140.ServiceIndicator() { + t.Logf("Service indicator is set") + } else { + t.Errorf("Service indicator is not set") + } + }) +} + +func fatalIfErr(t *testing.T, err error) { + t.Helper() + if err != nil { + t.Fatal(err) + } +} + func decodeHex(t *testing.T, s string) []byte { t.Helper() s = strings.ReplaceAll(s, " ", "") diff --git a/src/crypto/internal/fips140test/nistec_test.go b/src/crypto/internal/fips140test/nistec_test.go index 3849add7004e2a..3b3de2bc2cb1f6 100644 --- a/src/crypto/internal/fips140test/nistec_test.go +++ b/src/crypto/internal/fips140test/nistec_test.go @@ -251,10 +251,3 @@ func testScalarMult[P nistPoint[P]](t *testing.T, newPoint func() P, c elliptic. }) } } - -func fatalIfErr(t *testing.T, err error) { - t.Helper() - if err != nil { - t.Fatal(err) - } -} diff --git a/src/crypto/internal/fips140test/sshkdf_test.go b/src/crypto/internal/fips140test/sshkdf_test.go index 91135205de9bd5..3538af8469bee8 100644 --- a/src/crypto/internal/fips140test/sshkdf_test.go +++ b/src/crypto/internal/fips140test/sshkdf_test.go @@ -8,23 +8,22 @@ import ( "bytes" "crypto/internal/fips140/ssh" "crypto/sha256" - "encoding/hex" "testing" ) func TestSSHACVPVector(t *testing.T) { // https://github.com/usnistgov/ACVP-Server/blob/3a7333f638/gen-val/json-files/kdf-components-ssh-1.0/prompt.json#L910-L915 - K := fromHex("0000010100E534CD9780786AF19994DD68C3FD7FE1E1F77C3938B2005C49B080CF88A63A44079774A36F23BA4D73470CB318C30524854D2F36BAB9A45AD73DBB3BC5DD39A547F62BC921052E102E37F3DD0CD79A04EB46ACC14B823B326096A89E33E8846624188BB3C8F16B320E7BB8F5EB05F080DCEE244A445DBED3A9F3BA8C373D8BE62CDFE2FC5876F30F90F01F0A55E5251B23E0DBBFCFB1450715E329BB00FB222E850DDB11201460B8AEF3FC8965D3B6D3AFBB885A6C11F308F10211B82EA2028C7A84DD0BB8D5D6AC3A48D0C2B93609269C585E03889DB3621993E7F7C09A007FB6B5C06FFA532B0DBF11F71F740D9CD8FAD2532E21B9423BF3D85EE4E396BE32") - H := fromHex("8FB22F0864960DA5679FD377248E41C2D0390E5AB3BB7955A3B6C588FB75B20D") - sessionID := fromHex("269A512E7B560E13396E0F3F56BDA730E23EE122EE6D59C91C58FB07872BCCCC") + K := decodeHex(t, "0000010100E534CD9780786AF19994DD68C3FD7FE1E1F77C3938B2005C49B080CF88A63A44079774A36F23BA4D73470CB318C30524854D2F36BAB9A45AD73DBB3BC5DD39A547F62BC921052E102E37F3DD0CD79A04EB46ACC14B823B326096A89E33E8846624188BB3C8F16B320E7BB8F5EB05F080DCEE244A445DBED3A9F3BA8C373D8BE62CDFE2FC5876F30F90F01F0A55E5251B23E0DBBFCFB1450715E329BB00FB222E850DDB11201460B8AEF3FC8965D3B6D3AFBB885A6C11F308F10211B82EA2028C7A84DD0BB8D5D6AC3A48D0C2B93609269C585E03889DB3621993E7F7C09A007FB6B5C06FFA532B0DBF11F71F740D9CD8FAD2532E21B9423BF3D85EE4E396BE32") + H := decodeHex(t, "8FB22F0864960DA5679FD377248E41C2D0390E5AB3BB7955A3B6C588FB75B20D") + sessionID := decodeHex(t, "269A512E7B560E13396E0F3F56BDA730E23EE122EE6D59C91C58FB07872BCCCC") // https://github.com/usnistgov/ACVP-Server/blob/3a7333f638/gen-val/json-files/kdf-components-ssh-1.0/expectedResults.json#L1306-L1314 - initialIVClient := fromHex("82321D9FE2ACD958D3F55F4D3FF5C79D") - initialIVServer := fromHex("03F336F61311770BD5346B41E04CDB1F") - encryptionKeyClient := fromHex("20E55008D0120C400F42E5D2E148AB75") - encryptionKeyServer := fromHex("8BF4DEBEC96F4ADBBE5BB43828D56E6D") - integrityKeyClient := fromHex("15F53BCCE2645D0AD1C539C09BF9054AA3A4B10B71E96B9E3A15672405341BB5") - integrityKeyServer := fromHex("00BB773FD63AC7B7281A7B54C130CCAD363EE8928104E67CA5A3211EE3BBAB93") + initialIVClient := decodeHex(t, "82321D9FE2ACD958D3F55F4D3FF5C79D") + initialIVServer := decodeHex(t, "03F336F61311770BD5346B41E04CDB1F") + encryptionKeyClient := decodeHex(t, "20E55008D0120C400F42E5D2E148AB75") + encryptionKeyServer := decodeHex(t, "8BF4DEBEC96F4ADBBE5BB43828D56E6D") + integrityKeyClient := decodeHex(t, "15F53BCCE2645D0AD1C539C09BF9054AA3A4B10B71E96B9E3A15672405341BB5") + integrityKeyServer := decodeHex(t, "00BB773FD63AC7B7281A7B54C130CCAD363EE8928104E67CA5A3211EE3BBAB93") gotIVClient, gotKeyClient, gotIntegrityClient := ssh.Keys( sha256.New, ssh.ClientKeys, K, H, sessionID, 16, 16, 32) @@ -50,11 +49,3 @@ func TestSSHACVPVector(t *testing.T) { t.Errorf("got integrity key server %x, want %x", gotIntegrityServer, integrityKeyServer) } } - -func fromHex(s string) []byte { - b, err := hex.DecodeString(s) - if err != nil { - panic(err) - } - return b -} From 19f779dd4f44d12070d4302b72d6e0e93ab939f9 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Mon, 27 Jan 2025 13:02:27 +0100 Subject: [PATCH 345/397] crypto/internal/fips140test: make TestCASTFailures standalone We want it to work even when fips140test.test is cross-compiled and moved to a different machine. Also, make it log more. Change-Id: I6a6a46566712f05f6b551ecde75672baf2c0fc6b Reviewed-on: https://go-review.googlesource.com/c/go/+/644644 Reviewed-by: Ian Lance Taylor Reviewed-by: Roland Shoemaker Reviewed-by: Daniel McCarney LUCI-TryBot-Result: Go LUCI Auto-Submit: Filippo Valsorda --- src/crypto/internal/fips140test/cast_test.go | 65 +++++++++++++++----- 1 file changed, 49 insertions(+), 16 deletions(-) diff --git a/src/crypto/internal/fips140test/cast_test.go b/src/crypto/internal/fips140test/cast_test.go index b2aee15eab70f5..41122f339d1831 100644 --- a/src/crypto/internal/fips140test/cast_test.go +++ b/src/crypto/internal/fips140test/cast_test.go @@ -13,6 +13,7 @@ import ( "io/fs" "os" "regexp" + "slices" "strings" "testing" @@ -34,7 +35,35 @@ import ( _ "crypto/internal/fips140/tls13" ) -func findAllCASTs(t *testing.T) map[string]struct{} { +var allCASTs = []string{ + "AES-CBC", + "CTR_DRBG", + "CounterKDF", + "DetECDSA P-256 SHA2-512 sign", + "ECDH PCT", + "ECDSA P-256 SHA2-512 sign and verify", + "ECDSA PCT", + "Ed25519 sign and verify", + "Ed25519 sign and verify PCT", + "HKDF-SHA2-256", + "HMAC-SHA2-256", + "KAS-ECC-SSC P-256", + "ML-KEM PCT", + "ML-KEM PCT", + "ML-KEM PCT", + "ML-KEM PCT", + "ML-KEM-768", + "PBKDF2", + "RSA sign and verify PCT", + "RSASSA-PKCS-v1.5 2048-bit sign and verify", + "SHA2-256", + "SHA2-512", + "TLSv1.2-SHA2-256", + "TLSv1.3-SHA2-256", + "cSHAKE128", +} + +func TestAllCASTs(t *testing.T) { testenv.MustHaveSource(t) // Ask "go list" for the location of the crypto/internal/fips140 tree, as it @@ -48,7 +77,7 @@ func findAllCASTs(t *testing.T) map[string]struct{} { t.Logf("FIPS module directory: %s", fipsDir) // Find all invocations of fips140.CAST or fips140.PCT. - allCASTs := make(map[string]struct{}) + var foundCASTs []string castRe := regexp.MustCompile(`fips140\.(CAST|PCT)\("([^"]+)"`) if err := fs.WalkDir(os.DirFS(fipsDir), ".", func(path string, d fs.DirEntry, err error) error { if err != nil { @@ -62,14 +91,17 @@ func findAllCASTs(t *testing.T) map[string]struct{} { return err } for _, m := range castRe.FindAllSubmatch(data, -1) { - allCASTs[string(m[2])] = struct{}{} + foundCASTs = append(foundCASTs, string(m[2])) } return nil }); err != nil { t.Fatalf("WalkDir: %v", err) } - return allCASTs + slices.Sort(foundCASTs) + if !slices.Equal(foundCASTs, allCASTs) { + t.Errorf("AllCASTs is out of date. Found CASTs: %#v", foundCASTs) + } } // TestConditionals causes the conditional CASTs and PCTs to be invoked. @@ -127,28 +159,29 @@ UjmopwKBgAqB2KYYMUqAOvYcBnEfLDmyZv9BTVNHbR2lKkMYqv5LlvDaBxVfilE0 } func TestCASTFailures(t *testing.T) { + moduleStatus(t) testenv.MustHaveExec(t) - allCASTs := findAllCASTs(t) - if len(allCASTs) == 0 { - t.Fatal("no CASTs found") - } - - for name := range allCASTs { + for _, name := range allCASTs { t.Run(name, func(t *testing.T) { - t.Parallel() + // Don't parallelize if running in verbose mode, to produce a less + // confusing recoding for the validation lab. + if !testing.Verbose() { + t.Parallel() + } + t.Logf("CAST/PCT succeeded: %s", name) + t.Logf("Testing CAST/PCT failure...") cmd := testenv.Command(t, testenv.Executable(t), "-test.run=TestConditionals", "-test.v") - cmd = testenv.CleanCmdEnv(cmd) cmd.Env = append(cmd.Env, fmt.Sprintf("GODEBUG=failfipscast=%s,fips140=on", name)) out, err := cmd.CombinedOutput() + t.Logf("%s", out) if err == nil { - t.Error(err) - } else { - t.Logf("CAST/PCT %s failed and caused the program to exit or the test to fail", name) - t.Logf("%s", out) + t.Fatal("Test did not fail as expected") } if strings.Contains(string(out), "completed successfully") { t.Errorf("CAST/PCT %s failure did not stop the program", name) + } else { + t.Logf("CAST/PCT %s failed as expected and caused the program to exit", name) } }) } From 4ffa9a8305ddca86813cda356ddf1529b8054601 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Wed, 5 Feb 2025 13:51:26 +0100 Subject: [PATCH 346/397] crypto/internal/fips140test: support disabling PAA/PAI FIPS 140-3 testing requires testing the module both with and without platform hardware acceleration. Change-Id: I6a6a4656faad883062d64bc8e2363d4c59bd8cce Reviewed-on: https://go-review.googlesource.com/c/go/+/648817 Auto-Submit: Filippo Valsorda Reviewed-by: Daniel McCarney Reviewed-by: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Reviewed-by: Roland Shoemaker --- src/crypto/internal/fips140test/acvp_test.go | 8 ++++++++ src/crypto/internal/fips140test/fips_test.go | 6 ++++++ src/crypto/internal/impl/impl.go | 14 ++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/src/crypto/internal/fips140test/acvp_test.go b/src/crypto/internal/fips140test/acvp_test.go index f25f3d4f0f7cbe..a0ad7b27df1226 100644 --- a/src/crypto/internal/fips140test/acvp_test.go +++ b/src/crypto/internal/fips140test/acvp_test.go @@ -44,6 +44,7 @@ import ( "crypto/internal/fips140/subtle" "crypto/internal/fips140/tls12" "crypto/internal/fips140/tls13" + "crypto/internal/impl" "crypto/rand" _ "embed" "encoding/binary" @@ -58,7 +59,14 @@ import ( "testing" ) +var noPAAPAI = os.Getenv("GONOPAAPAI") == "1" + func TestMain(m *testing.M) { + if noPAAPAI { + for _, p := range impl.Packages() { + impl.Select(p, "") + } + } if os.Getenv("ACVP_WRAPPER") == "1" { wrapperMain() } else { diff --git a/src/crypto/internal/fips140test/fips_test.go b/src/crypto/internal/fips140test/fips_test.go index 1dd8aa21a9628d..81ccd0cf7fdd1d 100644 --- a/src/crypto/internal/fips140test/fips_test.go +++ b/src/crypto/internal/fips140test/fips_test.go @@ -50,6 +50,12 @@ func moduleStatus(t *testing.T) { t.Logf("Module name: %s", fips140.Name()) t.Logf("Module version: %s", fips140.Version()) + if noPAAPAI { + t.Log("PAA/PAI disabled") + } else { + t.Log("PAA/PAI enabled") + } + if check.Verified { t.Log("FIPS 140-3 integrity self-check succeeded") } else { diff --git a/src/crypto/internal/impl/impl.go b/src/crypto/internal/impl/impl.go index 524db45d749f79..193839f1f197ee 100644 --- a/src/crypto/internal/impl/impl.go +++ b/src/crypto/internal/impl/impl.go @@ -38,6 +38,20 @@ func Register(pkg, name string, available *bool) { }) } +// Packages returns the list of all packages for which alternative +// implementations are registered. +func Packages() []string { + var pkgs []string + seen := make(map[string]bool) + for _, i := range allImplementations { + if !seen[i.Package] { + pkgs = append(pkgs, i.Package) + seen[i.Package] = true + } + } + return pkgs +} + // List returns the names of all alternative implementations registered for the // given package, whether available or not. The implicit base implementation is // not included. From 8659ad904966dfe809925c980ac11e7f98ac61aa Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Thu, 6 Feb 2025 11:34:48 +0100 Subject: [PATCH 347/397] crypto/internal/fips140test: require FIPS 140 mode for the ACVP wrapper Change-Id: I6a6a46565c14cf1d924a8fcfbf6752e9646ec63d Reviewed-on: https://go-review.googlesource.com/c/go/+/648818 Reviewed-by: Daniel McCarney LUCI-TryBot-Result: Go LUCI Reviewed-by: Roland Shoemaker Auto-Submit: Filippo Valsorda Reviewed-by: Ian Lance Taylor --- src/crypto/internal/fips140test/acvp_test.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/crypto/internal/fips140test/acvp_test.go b/src/crypto/internal/fips140test/acvp_test.go index a0ad7b27df1226..119fdefc64a4bf 100644 --- a/src/crypto/internal/fips140test/acvp_test.go +++ b/src/crypto/internal/fips140test/acvp_test.go @@ -75,6 +75,10 @@ func TestMain(m *testing.M) { } func wrapperMain() { + if !fips140.Enabled { + fmt.Fprintln(os.Stderr, "ACVP wrapper must be run with GODEBUG=fips140=on") + os.Exit(2) + } if err := processingLoop(bufio.NewReader(os.Stdin), os.Stdout); err != nil { fmt.Fprintf(os.Stderr, "processing error: %v\n", err) os.Exit(1) @@ -2129,6 +2133,7 @@ func TestACVP(t *testing.T) { cmd = testenv.Command(t, goTool, args...) cmd.Dir = dataDir cmd.Env = append(os.Environ(), "ACVP_WRAPPER=1") + cmd.Env = append(os.Environ(), "GODEBUG=fips140=on") output, err := cmd.CombinedOutput() if err != nil { t.Fatalf("failed to run acvp tests: %s\n%s", err, string(output)) From 1eb4c0dcb125d27e1a4296ae136f75ac08c3b9c5 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Wed, 12 Feb 2025 12:37:52 +0100 Subject: [PATCH 348/397] cmd/dist: test GOFIPS140=latest rather than just the GODEBUG GOFIPS140=latest turns on the GODEBUG by default, and it's otherwise untested. Change-Id: I6a6a4656ff7ad313ce2c61ee4144ad2858bd148c Reviewed-on: https://go-review.googlesource.com/c/go/+/648819 LUCI-TryBot-Result: Go LUCI Auto-Submit: Filippo Valsorda Reviewed-by: Ian Lance Taylor Reviewed-by: Daniel McCarney Reviewed-by: Roland Shoemaker --- src/cmd/dist/test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index 005e1da86a1dc2..b137c7db7990bd 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -712,9 +712,9 @@ func (t *tester) registerTests() { // Check that all crypto packages compile (and test correctly, in longmode) with fips. if t.fipsSupported() { // Test standard crypto packages with fips140=on. - t.registerTest("GODEBUG=fips140=on go test crypto/...", &goTest{ + t.registerTest("GOFIPS140=latest go test crypto/...", &goTest{ variant: "gofips140", - env: []string{"GODEBUG=fips140=on"}, + env: []string{"GOFIPS140=latest"}, pkg: "crypto/...", }) From c4136a433c28eb12abad777f8e74087ecf6e21f4 Mon Sep 17 00:00:00 2001 From: Sean Liao Date: Fri, 12 Jul 2024 20:56:19 +0100 Subject: [PATCH 349/397] runtime/debug: document DefaultGODEBUG as a BuildSetting Fixes #66465 Change-Id: I60c017ddba29fa5b452b665d8521cd6c8e20438c Reviewed-on: https://go-review.googlesource.com/c/go/+/597979 LUCI-TryBot-Result: Go LUCI Reviewed-by: Jorropo Auto-Submit: Ian Lance Taylor Reviewed-by: qiu laidongfeng2 <2645477756@qq.com> Reviewed-by: Ian Lance Taylor Reviewed-by: Dmitri Shuralyov --- src/runtime/debug/mod.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/runtime/debug/mod.go b/src/runtime/debug/mod.go index 53bbf1d8470568..3eab08744f5c29 100644 --- a/src/runtime/debug/mod.go +++ b/src/runtime/debug/mod.go @@ -77,6 +77,7 @@ type Module struct { // - CGO_CPPFLAGS: the effective CGO_CPPFLAGS environment variable // - CGO_CXXFLAGS: the effective CGO_CXXFLAGS environment variable // - CGO_LDFLAGS: the effective CGO_LDFLAGS environment variable +// - DefaultGODEBUG: the effective GODEBUG settings // - GOARCH: the architecture target // - GOAMD64/GOARM/GO386/etc: the architecture feature level for GOARCH // - GOOS: the operating system target From f91ac1b61eb7c18773ff01be58a39f49de436585 Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Thu, 13 Feb 2025 10:31:53 -0500 Subject: [PATCH 350/397] crypto/internal/fips140test: fix TestACVP env vars Fix TestACVP environment construction to include both ACVP_WRAPPER and GODEBUG. Previously we were accidentally overwriting the cmd.Env, stomping the ACVP_WRAPPER env var and replacing it with just the GODEBUG env var. This in turn makes the tests start to fail when the test binary subprocess is invoked without knowing it's fulfilling the role of the wrapper, and not the test driver. Change-Id: Ie6ee30c8b93b2051a671e12aaa63d2116c5eb8c8 Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest Reviewed-on: https://go-review.googlesource.com/c/go/+/649016 LUCI-TryBot-Result: Go LUCI Reviewed-by: Dmitri Shuralyov Reviewed-by: Cherry Mui Reviewed-by: Filippo Valsorda Auto-Submit: Filippo Valsorda --- src/crypto/internal/fips140test/acvp_test.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/crypto/internal/fips140test/acvp_test.go b/src/crypto/internal/fips140test/acvp_test.go index 119fdefc64a4bf..ddb234bab655e1 100644 --- a/src/crypto/internal/fips140test/acvp_test.go +++ b/src/crypto/internal/fips140test/acvp_test.go @@ -2132,8 +2132,10 @@ func TestACVP(t *testing.T) { } cmd = testenv.Command(t, goTool, args...) cmd.Dir = dataDir - cmd.Env = append(os.Environ(), "ACVP_WRAPPER=1") - cmd.Env = append(os.Environ(), "GODEBUG=fips140=on") + cmd.Env = append(os.Environ(), + "ACVP_WRAPPER=1", + "GODEBUG=fips140=on", + ) output, err := cmd.CombinedOutput() if err != nil { t.Fatalf("failed to run acvp tests: %s\n%s", err, string(output)) From fdaac84480b02e600660d0ca7c15339138807107 Mon Sep 17 00:00:00 2001 From: Carlos Amedee Date: Mon, 23 Dec 2024 11:27:20 -0500 Subject: [PATCH 351/397] os: use AddCleanup to close files This changes the finalizer mechanism used to close files from runtime.SetFinalizer to runtime.AddCleanup. Updates #70907 Change-Id: I47582b81b0ed69609dd9dac158ec7bb8819c8c77 Reviewed-on: https://go-review.googlesource.com/c/go/+/638555 Reviewed-by: Michael Pratt Auto-Submit: Carlos Amedee LUCI-TryBot-Result: Go LUCI --- src/os/file_plan9.go | 16 +++++++++------- src/os/file_unix.go | 21 ++++++++++++--------- src/os/file_windows.go | 16 +++++++++------- src/os/root_openat.go | 13 ++++++++----- src/os/root_unix.go | 2 +- src/os/root_windows.go | 2 +- 6 files changed, 40 insertions(+), 30 deletions(-) diff --git a/src/os/file_plan9.go b/src/os/file_plan9.go index c123fe696191dd..f74dbf20c49df7 100644 --- a/src/os/file_plan9.go +++ b/src/os/file_plan9.go @@ -23,7 +23,7 @@ func fixLongPath(path string) string { // file is the real representation of *File. // The extra level of indirection ensures that no clients of os -// can overwrite this data, which could cause the finalizer +// can overwrite this data, which could cause the cleanup // to close the wrong file descriptor. type file struct { fdmu poll.FDMutex @@ -31,13 +31,14 @@ type file struct { name string dirinfo atomic.Pointer[dirInfo] // nil unless directory being read appendMode bool // whether file is opened for appending + cleanup runtime.Cleanup // cleanup closes the file when no longer referenced } // Fd returns the integer Plan 9 file descriptor referencing the open file. // If f is closed, the file descriptor becomes invalid. -// If f is garbage collected, a finalizer may close the file descriptor, -// making it invalid; see [runtime.SetFinalizer] for more information on when -// a finalizer might be run. On Unix systems this will cause the [File.SetDeadline] +// If f is garbage collected, a cleanup may close the file descriptor, +// making it invalid; see [runtime.AddCleanup] for more information on when +// a cleanup might be run. On Unix systems this will cause the [File.SetDeadline] // methods to stop working. // // As an alternative, see the f.SyscallConn method. @@ -57,7 +58,7 @@ func NewFile(fd uintptr, name string) *File { return nil } f := &File{&file{fd: fdi, name: name}} - runtime.SetFinalizer(f.file, (*file).close) + f.cleanup = runtime.AddCleanup(f, func(f *file) { f.close() }, f.file) return f } @@ -168,8 +169,9 @@ func (file *file) close() error { err := file.decref() - // no need for a finalizer anymore - runtime.SetFinalizer(file, nil) + // There is no need for a cleanup at this point. File must be alive at the point + // where cleanup.stop is called. + file.cleanup.Stop() return err } diff --git a/src/os/file_unix.go b/src/os/file_unix.go index b5c0baf3ab7f18..5e9239edc56e40 100644 --- a/src/os/file_unix.go +++ b/src/os/file_unix.go @@ -54,7 +54,7 @@ func rename(oldname, newname string) error { // file is the real representation of *File. // The extra level of indirection ensures that no clients of os -// can overwrite this data, which could cause the finalizer +// can overwrite this data, which could cause the cleanup // to close the wrong file descriptor. type file struct { pfd poll.FD @@ -63,17 +63,18 @@ type file struct { nonblock bool // whether we set nonblocking mode stdoutOrErr bool // whether this is stdout or stderr appendMode bool // whether file is opened for appending + cleanup runtime.Cleanup // cleanup closes the file when no longer referenced } // Fd returns the integer Unix file descriptor referencing the open file. // If f is closed, the file descriptor becomes invalid. -// If f is garbage collected, a finalizer may close the file descriptor, -// making it invalid; see [runtime.SetFinalizer] for more information on when -// a finalizer might be run. On Unix systems this will cause the [File.SetDeadline] +// If f is garbage collected, a cleanup may close the file descriptor, +// making it invalid; see [runtime.AddCleanup] for more information on when +// a cleanup might be run. On Unix systems this will cause the [File.SetDeadline] // methods to stop working. // Because file descriptors can be reused, the returned file descriptor may -// only be closed through the [File.Close] method of f, or by its finalizer during -// garbage collection. Otherwise, during garbage collection the finalizer +// only be closed through the [File.Close] method of f, or by its cleanup during +// garbage collection. Otherwise, during garbage collection the cleanup // may close an unrelated file descriptor with the same (reused) number. // // As an alternative, see the f.SyscallConn method. @@ -240,7 +241,8 @@ func newFile(fd int, name string, kind newFileKind, nonBlocking bool) *File { } } - runtime.SetFinalizer(f.file, (*file).close) + // Close the file when the File is not live. + f.cleanup = runtime.AddCleanup(f, func(f *file) { f.close() }, f.file) return f } @@ -337,8 +339,9 @@ func (file *file) close() error { err = &PathError{Op: "close", Path: file.name, Err: e} } - // no need for a finalizer anymore - runtime.SetFinalizer(file, nil) + // There is no need for a cleanup at this point. File must be alive at the point + // where cleanup.stop is called. + file.cleanup.Stop() return err } diff --git a/src/os/file_windows.go b/src/os/file_windows.go index 2160f1e6ffda70..2da924fe437db4 100644 --- a/src/os/file_windows.go +++ b/src/os/file_windows.go @@ -22,20 +22,21 @@ const _UTIME_OMIT = -1 // file is the real representation of *File. // The extra level of indirection ensures that no clients of os -// can overwrite this data, which could cause the finalizer +// can overwrite this data, which could cause the cleanup // to close the wrong file descriptor. type file struct { pfd poll.FD name string dirinfo atomic.Pointer[dirInfo] // nil unless directory being read appendMode bool // whether file is opened for appending + cleanup runtime.Cleanup // cleanup closes the file when no longer referenced } // Fd returns the Windows handle referencing the open file. // If f is closed, the file descriptor becomes invalid. -// If f is garbage collected, a finalizer may close the file descriptor, -// making it invalid; see [runtime.SetFinalizer] for more information on when -// a finalizer might be run. On Unix systems this will cause the [File.SetDeadline] +// If f is garbage collected, a cleanup may close the file descriptor, +// making it invalid; see [runtime.AddCleanup] for more information on when +// a cleanup might be run. On Unix systems this will cause the [File.SetDeadline] // methods to stop working. func (file *File) Fd() uintptr { if file == nil { @@ -65,7 +66,7 @@ func newFile(h syscall.Handle, name string, kind string) *File { }, name: name, }} - runtime.SetFinalizer(f.file, (*file).close) + f.cleanup = runtime.AddCleanup(f, func(f *file) { f.close() }, f.file) // Ignore initialization errors. // Assume any problems will show up in later I/O. @@ -129,8 +130,9 @@ func (file *file) close() error { err = &PathError{Op: "close", Path: file.name, Err: e} } - // no need for a finalizer anymore - runtime.SetFinalizer(file, nil) + // There is no need for a cleanup at this point. File must be alive at the point + // where cleanup.stop is called. + file.cleanup.Stop() return err } diff --git a/src/os/root_openat.go b/src/os/root_openat.go index 97e389db8d2352..5038c822f59a38 100644 --- a/src/os/root_openat.go +++ b/src/os/root_openat.go @@ -21,10 +21,11 @@ type root struct { // refs is incremented while an operation is using fd. // closed is set when Close is called. // fd is closed when closed is true and refs is 0. - mu sync.Mutex - fd sysfdType - refs int // number of active operations - closed bool // set when closed + mu sync.Mutex + fd sysfdType + refs int // number of active operations + closed bool // set when closed + cleanup runtime.Cleanup // cleanup closes the file when no longer referenced } func (r *root) Close() error { @@ -34,7 +35,9 @@ func (r *root) Close() error { syscall.Close(r.fd) } r.closed = true - runtime.SetFinalizer(r, nil) // no need for a finalizer any more + // There is no need for a cleanup at this point. Root must be alive at the point + // where cleanup.stop is called. + r.cleanup.Stop() return nil } diff --git a/src/os/root_unix.go b/src/os/root_unix.go index 31773ef6817b92..06da8da15ec0d2 100644 --- a/src/os/root_unix.go +++ b/src/os/root_unix.go @@ -52,7 +52,7 @@ func newRoot(fd int, name string) (*Root, error) { fd: fd, name: name, }} - runtime.SetFinalizer(r.root, (*root).Close) + r.root.cleanup = runtime.AddCleanup(r, func(f *root) { f.Close() }, r.root) return r, nil } diff --git a/src/os/root_windows.go b/src/os/root_windows.go index ba809bd6e0ba94..9b57d5648e6956 100644 --- a/src/os/root_windows.go +++ b/src/os/root_windows.go @@ -109,7 +109,7 @@ func newRoot(fd syscall.Handle, name string) (*Root, error) { fd: fd, name: name, }} - runtime.SetFinalizer(r.root, (*root).Close) + r.root.cleanup = runtime.AddCleanup(r, func(f *root) { f.Close() }, r.root) return r, nil } From f7becfc7f1e514ee658eae3997ae09cab9edb123 Mon Sep 17 00:00:00 2001 From: Mateusz Poliwczak Date: Sat, 14 Dec 2024 11:03:27 +0000 Subject: [PATCH 352/397] go/types: use documented version of gotypesalias GODEBUG This way the code would panic, in case it does not exist. Change-Id: I95de7460c0386afdc5d3f6a847e9fcbd22446010 GitHub-Last-Rev: 9ae0502a091feed45169f5c1a7e2761f8ffa2841 GitHub-Pull-Request: golang/go#70845 Reviewed-on: https://go-review.googlesource.com/c/go/+/636097 LUCI-TryBot-Result: Go LUCI Reviewed-by: Alan Donovan Reviewed-by: Cherry Mui --- src/go/types/eval_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/go/types/eval_test.go b/src/go/types/eval_test.go index 49d901f6924b69..f7f0da0db95737 100644 --- a/src/go/types/eval_test.go +++ b/src/go/types/eval_test.go @@ -208,7 +208,7 @@ func TestEvalPos(t *testing.T) { } // gotypesalias controls the use of Alias types. -var gotypesalias = godebug.New("#gotypesalias") +var gotypesalias = godebug.New("gotypesalias") // split splits string s at the first occurrence of s, trimming spaces. func split(s, sep string) (string, string) { From e4b12eb8af28d3f505a5487b76dbfd4b1a37c0da Mon Sep 17 00:00:00 2001 From: Carlos Amedee Date: Mon, 23 Dec 2024 11:34:03 -0500 Subject: [PATCH 353/397] io: use runtime.AddCleanup instead of runtime.SetFinalizer Replace the usage of runtime.SetFinalizer with runtime.AddCleanup. Updates #70907 Change-Id: Id604ca44ea67dcf8f87797e27347c6f4e9ad0b86 Reviewed-on: https://go-review.googlesource.com/c/go/+/638556 Reviewed-by: Michael Pratt Auto-Submit: Carlos Amedee TryBot-Bypass: Carlos Amedee --- src/io/multi_test.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/io/multi_test.go b/src/io/multi_test.go index 7a24a8afc5a419..934a6ec785fda4 100644 --- a/src/io/multi_test.go +++ b/src/io/multi_test.go @@ -332,9 +332,7 @@ func TestMultiReaderFreesExhaustedReaders(t *testing.T) { buf1 := bytes.NewReader([]byte("foo")) buf2 := bytes.NewReader([]byte("bar")) mr = MultiReader(buf1, buf2) - runtime.SetFinalizer(buf1, func(*bytes.Reader) { - close(closed) - }) + runtime.AddCleanup(buf1, func(ch chan struct{}) { close(ch) }, closed) }() buf := make([]byte, 4) From aa8d4df9d9b8659abc7bdc1485c11db515ed1479 Mon Sep 17 00:00:00 2001 From: Mateusz Poliwczak Date: Tue, 24 Dec 2024 07:23:13 +0000 Subject: [PATCH 354/397] go/types: propagate *ast.LabeledStmt in blockBranches properly Fixes #70974 Change-Id: I330c0ae53dcbcdb173ab514ee94f2ca53944df09 GitHub-Last-Rev: 7c2b740da6d6e94ac8787f04ad8942f3776ac56c GitHub-Pull-Request: golang/go#70976 Reviewed-on: https://go-review.googlesource.com/c/go/+/638257 Reviewed-by: Michael Knyszek Auto-Submit: Alan Donovan LUCI-TryBot-Result: Go LUCI Commit-Queue: Alan Donovan Reviewed-by: Alan Donovan --- src/cmd/compile/internal/types2/labels.go | 14 +++++----- src/go/types/labels.go | 22 +++++++-------- .../types/testdata/check/doubled_labels.go | 26 ++++++++++++++++++ .../types/testdata/check/issue70974.go | 27 +++++++++++++++++++ 4 files changed, 71 insertions(+), 18 deletions(-) create mode 100644 src/internal/types/testdata/check/doubled_labels.go create mode 100644 src/internal/types/testdata/check/issue70974.go diff --git a/src/cmd/compile/internal/types2/labels.go b/src/cmd/compile/internal/types2/labels.go index e44b7c7f70f3cd..6a6f64b4b8a7b2 100644 --- a/src/cmd/compile/internal/types2/labels.go +++ b/src/cmd/compile/internal/types2/labels.go @@ -112,8 +112,8 @@ func (check *Checker) blockBranches(all *Scope, parent *block, lstmt *syntax.Lab return varDeclPos.IsKnown() && slices.Contains(badJumps, jmp) } - var stmtBranches func(syntax.Stmt) - stmtBranches = func(s syntax.Stmt) { + var stmtBranches func(*syntax.LabeledStmt, syntax.Stmt) + stmtBranches = func(lstmt *syntax.LabeledStmt, s syntax.Stmt) { switch s := s.(type) { case *syntax.DeclStmt: for _, d := range s.DeclList { @@ -163,7 +163,7 @@ func (check *Checker) blockBranches(all *Scope, parent *block, lstmt *syntax.Lab fwdJumps = fwdJumps[:i] lstmt = s } - stmtBranches(s.Stmt) + stmtBranches(lstmt, s.Stmt) case *syntax.BranchStmt: if s.Label == nil { @@ -232,9 +232,9 @@ func (check *Checker) blockBranches(all *Scope, parent *block, lstmt *syntax.Lab fwdJumps = append(fwdJumps, check.blockBranches(all, b, lstmt, s.List)...) case *syntax.IfStmt: - stmtBranches(s.Then) + stmtBranches(lstmt, s.Then) if s.Else != nil { - stmtBranches(s.Else) + stmtBranches(lstmt, s.Else) } case *syntax.SwitchStmt: @@ -250,12 +250,12 @@ func (check *Checker) blockBranches(all *Scope, parent *block, lstmt *syntax.Lab } case *syntax.ForStmt: - stmtBranches(s.Body) + stmtBranches(lstmt, s.Body) } } for _, s := range list { - stmtBranches(s) + stmtBranches(nil, s) } return fwdJumps diff --git a/src/go/types/labels.go b/src/go/types/labels.go index 97b753581aedd9..7b6324880af6c0 100644 --- a/src/go/types/labels.go +++ b/src/go/types/labels.go @@ -119,8 +119,8 @@ func (check *Checker) blockBranches(all *Scope, parent *block, lstmt *ast.Labele fwdJumps = append(fwdJumps, check.blockBranches(all, b, lstmt, list)...) } - var stmtBranches func(ast.Stmt) - stmtBranches = func(s ast.Stmt) { + var stmtBranches func(*ast.LabeledStmt, ast.Stmt) + stmtBranches = func(lstmt *ast.LabeledStmt, s ast.Stmt) { switch s := s.(type) { case *ast.DeclStmt: if d, _ := s.Decl.(*ast.GenDecl); d != nil && d.Tok == token.VAR { @@ -168,7 +168,7 @@ func (check *Checker) blockBranches(all *Scope, parent *block, lstmt *ast.Labele fwdJumps = fwdJumps[:i] lstmt = s } - stmtBranches(s.Stmt) + stmtBranches(lstmt, s.Stmt) case *ast.BranchStmt: if s.Label == nil { @@ -235,36 +235,36 @@ func (check *Checker) blockBranches(all *Scope, parent *block, lstmt *ast.Labele blockBranches(lstmt, s.List) case *ast.IfStmt: - stmtBranches(s.Body) + stmtBranches(lstmt, s.Body) if s.Else != nil { - stmtBranches(s.Else) + stmtBranches(lstmt, s.Else) } case *ast.CaseClause: blockBranches(nil, s.Body) case *ast.SwitchStmt: - stmtBranches(s.Body) + stmtBranches(lstmt, s.Body) case *ast.TypeSwitchStmt: - stmtBranches(s.Body) + stmtBranches(lstmt, s.Body) case *ast.CommClause: blockBranches(nil, s.Body) case *ast.SelectStmt: - stmtBranches(s.Body) + stmtBranches(lstmt, s.Body) case *ast.ForStmt: - stmtBranches(s.Body) + stmtBranches(lstmt, s.Body) case *ast.RangeStmt: - stmtBranches(s.Body) + stmtBranches(lstmt, s.Body) } } for _, s := range list { - stmtBranches(s) + stmtBranches(nil, s) } return fwdJumps diff --git a/src/internal/types/testdata/check/doubled_labels.go b/src/internal/types/testdata/check/doubled_labels.go new file mode 100644 index 00000000000000..f3de27020ba35b --- /dev/null +++ b/src/internal/types/testdata/check/doubled_labels.go @@ -0,0 +1,26 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +func _() { +outer: +inner: + for { + continue inner + break inner + } + goto outer +} + +func _() { +outer: +inner: + for { + continue inner + continue outer /* ERROR "invalid continue label outer" */ + break outer /* ERROR "invalid break label outer" */ + } + goto outer +} diff --git a/src/internal/types/testdata/check/issue70974.go b/src/internal/types/testdata/check/issue70974.go new file mode 100644 index 00000000000000..59b11653cee18f --- /dev/null +++ b/src/internal/types/testdata/check/issue70974.go @@ -0,0 +1,27 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +func _() { +outer: + for { + break outer + } + + for { + break outer /* ERROR "invalid break label outer" */ + } +} + +func _() { +outer: + for { + continue outer + } + + for { + continue outer /* ERROR "invalid continue label outer" */ + } +} From 769274bf14f318f186ae1f89fd0fccb18241aaee Mon Sep 17 00:00:00 2001 From: Sam Thanawalla Date: Mon, 10 Feb 2025 21:06:02 +0000 Subject: [PATCH 355/397] cmd/go: do not apply kill timeout to go test with -bench The testing package already does this. go test should do the same thing. Fixes: #69181 Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest,gotip-windows-amd64-longtest Change-Id: I942bd09c5832b48d498a2eb1f1500e1d294d0a2c Reviewed-on: https://go-review.googlesource.com/c/go/+/648236 LUCI-TryBot-Result: Go LUCI Reviewed-by: Michael Matloob --- src/cmd/go/internal/test/test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/go/internal/test/test.go b/src/cmd/go/internal/test/test.go index 28ab6a09355020..2ee2aa6f415d5c 100644 --- a/src/cmd/go/internal/test/test.go +++ b/src/cmd/go/internal/test/test.go @@ -802,9 +802,9 @@ func runTest(ctx context.Context, cmd *base.Command, args []string) { // to that timeout plus one minute. This is a backup alarm in case // the test wedges with a goroutine spinning and its background // timer does not get a chance to fire. - // Don't set this if fuzzing, since it should be able to run + // Don't set this if fuzzing or benchmarking, since it should be able to run // indefinitely. - if testTimeout > 0 && testFuzz == "" { + if testTimeout > 0 && testFuzz == "" && testBench == "" { // The WaitDelay for the test process depends on both the OS I/O and // scheduling overhead and the amount of I/O generated by the test just // before it exits. We set the minimum at 5 seconds to account for the OS From ca4649747a0057ea59c34c4126ab3eed6086dd88 Mon Sep 17 00:00:00 2001 From: Paul Murphy Date: Wed, 12 Feb 2025 08:45:34 -0600 Subject: [PATCH 356/397] runtime: fix usleep on s390x/linux The timespec argument takes the remainder in nanoseconds, not microseconds. Convert the remaining time to nsec. Fixes #71714 Change-Id: I36cbbe3a088830c5e3afcc9516ef42e96ee21268 Reviewed-on: https://go-review.googlesource.com/c/go/+/648915 TryBot-Result: Gopher Robot Reviewed-by: Mauri de Souza Meneguzzo Reviewed-by: Axel Busch Run-TryBot: Paul Murphy Reviewed-by: Cherry Mui Reviewed-by: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Reviewed-by: Vishwanatha HD --- src/runtime/sys_linux_s390x.s | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/runtime/sys_linux_s390x.s b/src/runtime/sys_linux_s390x.s index 7da4a5272991d4..2f9d4beda82f64 100644 --- a/src/runtime/sys_linux_s390x.s +++ b/src/runtime/sys_linux_s390x.s @@ -112,9 +112,10 @@ TEXT runtime·usleep(SB),NOSPLIT,$16-4 MOVW $1000000, R3 DIVD R3, R2 MOVD R2, 8(R15) - MOVW $1000, R3 - MULLD R2, R3 + MULLD R2, R3 // Convert sec to usec and subtract SUB R3, R4 + MOVW $1000, R3 + MULLD R3, R4 // Convert remaining usec into nsec. MOVD R4, 16(R15) // nanosleep(&ts, 0) From a7e331e67105f1a8cc0236b7f3b1e6a3570dda27 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Thu, 13 Feb 2025 08:04:03 -0800 Subject: [PATCH 357/397] cmd/compile: implement signed loads from read-only memory In addition to unsigned loads which already exist. This helps code that does switches on strings to constant-fold the switch away when the string being switched on is constant. Fixes #71699 Change-Id: If3051af0f7255d2a573da6f96b153a987a7f159d Reviewed-on: https://go-review.googlesource.com/c/go/+/649295 LUCI-TryBot-Result: Go LUCI Reviewed-by: Cuong Manh Le Reviewed-by: Dmitri Shuralyov Reviewed-by: Keith Randall Auto-Submit: Keith Randall --- src/cmd/compile/internal/ssa/_gen/386.rules | 2 + src/cmd/compile/internal/ssa/_gen/AMD64.rules | 7 ++- src/cmd/compile/internal/ssa/_gen/AMD64Ops.go | 2 +- src/cmd/compile/internal/ssa/_gen/ARM.rules | 2 + src/cmd/compile/internal/ssa/_gen/ARM64.rules | 3 + .../compile/internal/ssa/_gen/MIPS64.rules | 9 ++- src/cmd/compile/internal/ssa/_gen/Wasm.rules | 3 + src/cmd/compile/internal/ssa/rewrite386.go | 26 +++++++++ src/cmd/compile/internal/ssa/rewriteAMD64.go | 49 +++++++++++++++- src/cmd/compile/internal/ssa/rewriteARM.go | 28 +++++++++ src/cmd/compile/internal/ssa/rewriteARM64.go | 39 +++++++++++++ src/cmd/compile/internal/ssa/rewriteMIPS64.go | 51 ++++++++++++++-- src/cmd/compile/internal/ssa/rewriteWasm.go | 58 +++++++++++++++++++ test/codegen/switch.go | 14 +++++ 14 files changed, 279 insertions(+), 14 deletions(-) diff --git a/src/cmd/compile/internal/ssa/_gen/386.rules b/src/cmd/compile/internal/ssa/_gen/386.rules index 67cfa3460aa3e1..216f5c2e2e79eb 100644 --- a/src/cmd/compile/internal/ssa/_gen/386.rules +++ b/src/cmd/compile/internal/ssa/_gen/386.rules @@ -940,3 +940,5 @@ (MOVBload [off] {sym} (SB) _) && symIsRO(sym) => (MOVLconst [int32(read8(sym, int64(off)))]) (MOVWload [off] {sym} (SB) _) && symIsRO(sym) => (MOVLconst [int32(read16(sym, int64(off), config.ctxt.Arch.ByteOrder))]) (MOVLload [off] {sym} (SB) _) && symIsRO(sym) => (MOVLconst [int32(read32(sym, int64(off), config.ctxt.Arch.ByteOrder))]) +(MOVBLSXload [off] {sym} (SB) _) && symIsRO(sym) => (MOVLconst [int32(int8(read8(sym, int64(off))))]) +(MOVWLSXload [off] {sym} (SB) _) && symIsRO(sym) => (MOVLconst [int32(int16(read16(sym, int64(off), config.ctxt.Arch.ByteOrder)))]) diff --git a/src/cmd/compile/internal/ssa/_gen/AMD64.rules b/src/cmd/compile/internal/ssa/_gen/AMD64.rules index ba7f181f5e4909..0e429b5be74dcb 100644 --- a/src/cmd/compile/internal/ssa/_gen/AMD64.rules +++ b/src/cmd/compile/internal/ssa/_gen/AMD64.rules @@ -1648,8 +1648,13 @@ (MOVBload [off] {sym} (SB) _) && symIsRO(sym) => (MOVLconst [int32(read8(sym, int64(off)))]) (MOVWload [off] {sym} (SB) _) && symIsRO(sym) => (MOVLconst [int32(read16(sym, int64(off), config.ctxt.Arch.ByteOrder))]) -(MOVLload [off] {sym} (SB) _) && symIsRO(sym) => (MOVQconst [int64(read32(sym, int64(off), config.ctxt.Arch.ByteOrder))]) +(MOVLload [off] {sym} (SB) _) && symIsRO(sym) => (MOVLconst [int32(read32(sym, int64(off), config.ctxt.Arch.ByteOrder))]) (MOVQload [off] {sym} (SB) _) && symIsRO(sym) => (MOVQconst [int64(read64(sym, int64(off), config.ctxt.Arch.ByteOrder))]) +(MOVBQSXload [off] {sym} (SB) _) && symIsRO(sym) => (MOVQconst [int64(int8(read8(sym, int64(off))))]) +(MOVWQSXload [off] {sym} (SB) _) && symIsRO(sym) => (MOVQconst [int64(int16(read16(sym, int64(off), config.ctxt.Arch.ByteOrder)))]) +(MOVLQSXload [off] {sym} (SB) _) && symIsRO(sym) => (MOVQconst [int64(int32(read32(sym, int64(off), config.ctxt.Arch.ByteOrder)))]) + + (MOVOstore [dstOff] {dstSym} ptr (MOVOload [srcOff] {srcSym} (SB) _) mem) && symIsRO(srcSym) => (MOVQstore [dstOff+8] {dstSym} ptr (MOVQconst [int64(read64(srcSym, int64(srcOff)+8, config.ctxt.Arch.ByteOrder))]) (MOVQstore [dstOff] {dstSym} ptr (MOVQconst [int64(read64(srcSym, int64(srcOff), config.ctxt.Arch.ByteOrder))]) mem)) diff --git a/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go b/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go index 7be70c77372403..53df7af3059a52 100644 --- a/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go +++ b/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go @@ -758,7 +758,7 @@ func init() { {name: "MOVLQSX", argLength: 1, reg: gp11, asm: "MOVLQSX"}, // sign extend arg0 from int32 to int64 {name: "MOVLQZX", argLength: 1, reg: gp11, asm: "MOVL"}, // zero extend arg0 from int32 to int64 - {name: "MOVLconst", reg: gp01, asm: "MOVL", typ: "UInt32", aux: "Int32", rematerializeable: true}, // 32 low bits of auxint + {name: "MOVLconst", reg: gp01, asm: "MOVL", typ: "UInt32", aux: "Int32", rematerializeable: true}, // 32 low bits of auxint (upper 32 are zeroed) {name: "MOVQconst", reg: gp01, asm: "MOVQ", typ: "UInt64", aux: "Int64", rematerializeable: true}, // auxint {name: "CVTTSD2SL", argLength: 1, reg: fpgp, asm: "CVTTSD2SL"}, // convert float64 to int32 diff --git a/src/cmd/compile/internal/ssa/_gen/ARM.rules b/src/cmd/compile/internal/ssa/_gen/ARM.rules index 9cdb5d8ad541c9..a3bb2c312f9c16 100644 --- a/src/cmd/compile/internal/ssa/_gen/ARM.rules +++ b/src/cmd/compile/internal/ssa/_gen/ARM.rules @@ -1473,3 +1473,5 @@ (MOVBUload [off] {sym} (SB) _) && symIsRO(sym) => (MOVWconst [int32(read8(sym, int64(off)))]) (MOVHUload [off] {sym} (SB) _) && symIsRO(sym) => (MOVWconst [int32(read16(sym, int64(off), config.ctxt.Arch.ByteOrder))]) (MOVWload [off] {sym} (SB) _) && symIsRO(sym) => (MOVWconst [int32(read32(sym, int64(off), config.ctxt.Arch.ByteOrder))]) +(MOVBload [off] {sym} (SB) _) && symIsRO(sym) => (MOVWconst [int32(int8(read8(sym, int64(off))))]) +(MOVHload [off] {sym} (SB) _) && symIsRO(sym) => (MOVWconst [int32(int16(read16(sym, int64(off), config.ctxt.Arch.ByteOrder)))]) diff --git a/src/cmd/compile/internal/ssa/_gen/ARM64.rules b/src/cmd/compile/internal/ssa/_gen/ARM64.rules index 6652d2ec014c26..3696e17d9ce957 100644 --- a/src/cmd/compile/internal/ssa/_gen/ARM64.rules +++ b/src/cmd/compile/internal/ssa/_gen/ARM64.rules @@ -1940,6 +1940,9 @@ (MOVHUload [off] {sym} (SB) _) && symIsRO(sym) => (MOVDconst [int64(read16(sym, int64(off), config.ctxt.Arch.ByteOrder))]) (MOVWUload [off] {sym} (SB) _) && symIsRO(sym) => (MOVDconst [int64(read32(sym, int64(off), config.ctxt.Arch.ByteOrder))]) (MOVDload [off] {sym} (SB) _) && symIsRO(sym) => (MOVDconst [int64(read64(sym, int64(off), config.ctxt.Arch.ByteOrder))]) +(MOVBload [off] {sym} (SB) _) && symIsRO(sym) => (MOVDconst [int64(int8(read8(sym, int64(off))))]) +(MOVHload [off] {sym} (SB) _) && symIsRO(sym) => (MOVDconst [int64(int16(read16(sym, int64(off), config.ctxt.Arch.ByteOrder)))]) +(MOVWload [off] {sym} (SB) _) && symIsRO(sym) => (MOVDconst [int64(int32(read32(sym, int64(off), config.ctxt.Arch.ByteOrder)))]) // Prefetch instructions (aux is option: 0 - PLDL1KEEP; 1 - PLDL1STRM) (PrefetchCache addr mem) => (PRFM [0] addr mem) diff --git a/src/cmd/compile/internal/ssa/_gen/MIPS64.rules b/src/cmd/compile/internal/ssa/_gen/MIPS64.rules index 8aed350039ab7e..cc3985ecdd0a6f 100644 --- a/src/cmd/compile/internal/ssa/_gen/MIPS64.rules +++ b/src/cmd/compile/internal/ssa/_gen/MIPS64.rules @@ -811,7 +811,10 @@ (SGTU x x) => (MOVVconst [0]) // fold readonly sym load -(MOVBload [off] {sym} (SB) _) && symIsRO(sym) => (MOVVconst [int64(read8(sym, int64(off)))]) -(MOVHload [off] {sym} (SB) _) && symIsRO(sym) => (MOVVconst [int64(read16(sym, int64(off), config.ctxt.Arch.ByteOrder))]) -(MOVWload [off] {sym} (SB) _) && symIsRO(sym) => (MOVVconst [int64(read32(sym, int64(off), config.ctxt.Arch.ByteOrder))]) +(MOVBUload [off] {sym} (SB) _) && symIsRO(sym) => (MOVVconst [int64(read8(sym, int64(off)))]) +(MOVHUload [off] {sym} (SB) _) && symIsRO(sym) => (MOVVconst [int64(read16(sym, int64(off), config.ctxt.Arch.ByteOrder))]) +(MOVWUload [off] {sym} (SB) _) && symIsRO(sym) => (MOVVconst [int64(read32(sym, int64(off), config.ctxt.Arch.ByteOrder))]) (MOVVload [off] {sym} (SB) _) && symIsRO(sym) => (MOVVconst [int64(read64(sym, int64(off), config.ctxt.Arch.ByteOrder))]) +(MOVBload [off] {sym} (SB) _) && symIsRO(sym) => (MOVVconst [int64(int8(read8(sym, int64(off))))]) +(MOVHload [off] {sym} (SB) _) && symIsRO(sym) => (MOVVconst [int64(int16(read16(sym, int64(off), config.ctxt.Arch.ByteOrder)))]) +(MOVWload [off] {sym} (SB) _) && symIsRO(sym) => (MOVVconst [int64(int32(read32(sym, int64(off), config.ctxt.Arch.ByteOrder)))]) diff --git a/src/cmd/compile/internal/ssa/_gen/Wasm.rules b/src/cmd/compile/internal/ssa/_gen/Wasm.rules index 91a9fc5e4a9772..08cadabe0ea4c2 100644 --- a/src/cmd/compile/internal/ssa/_gen/Wasm.rules +++ b/src/cmd/compile/internal/ssa/_gen/Wasm.rules @@ -395,3 +395,6 @@ (I64Load32U [off] (LoweredAddr {sym} [off2] (SB)) _) && symIsRO(sym) && isU32Bit(off+int64(off2)) => (I64Const [int64(read32(sym, off+int64(off2), config.ctxt.Arch.ByteOrder))]) (I64Load16U [off] (LoweredAddr {sym} [off2] (SB)) _) && symIsRO(sym) && isU32Bit(off+int64(off2)) => (I64Const [int64(read16(sym, off+int64(off2), config.ctxt.Arch.ByteOrder))]) (I64Load8U [off] (LoweredAddr {sym} [off2] (SB)) _) && symIsRO(sym) && isU32Bit(off+int64(off2)) => (I64Const [int64(read8(sym, off+int64(off2)))]) +(I64Load32S [off] (LoweredAddr {sym} [off2] (SB)) _) && symIsRO(sym) && isU32Bit(off+int64(off2)) => (I64Const [int64(int32(read32(sym, off+int64(off2), config.ctxt.Arch.ByteOrder)))]) +(I64Load16S [off] (LoweredAddr {sym} [off2] (SB)) _) && symIsRO(sym) && isU32Bit(off+int64(off2)) => (I64Const [int64(int16(read16(sym, off+int64(off2), config.ctxt.Arch.ByteOrder)))]) +(I64Load8S [off] (LoweredAddr {sym} [off2] (SB)) _) && symIsRO(sym) && isU32Bit(off+int64(off2)) => (I64Const [int64(int8(read8(sym, off+int64(off2))))]) diff --git a/src/cmd/compile/internal/ssa/rewrite386.go b/src/cmd/compile/internal/ssa/rewrite386.go index 9f1645f8c33dcc..dbc1335fcdc338 100644 --- a/src/cmd/compile/internal/ssa/rewrite386.go +++ b/src/cmd/compile/internal/ssa/rewrite386.go @@ -3491,6 +3491,19 @@ func rewriteValue386_Op386MOVBLSXload(v *Value) bool { v.AddArg2(base, mem) return true } + // match: (MOVBLSXload [off] {sym} (SB) _) + // cond: symIsRO(sym) + // result: (MOVLconst [int32(int8(read8(sym, int64(off))))]) + for { + off := auxIntToInt32(v.AuxInt) + sym := auxToSym(v.Aux) + if v_0.Op != OpSB || !(symIsRO(sym)) { + break + } + v.reset(Op386MOVLconst) + v.AuxInt = int32ToAuxInt(int32(int8(read8(sym, int64(off))))) + return true + } return false } func rewriteValue386_Op386MOVBLZX(v *Value) bool { @@ -4672,6 +4685,19 @@ func rewriteValue386_Op386MOVWLSXload(v *Value) bool { v.AddArg2(base, mem) return true } + // match: (MOVWLSXload [off] {sym} (SB) _) + // cond: symIsRO(sym) + // result: (MOVLconst [int32(int16(read16(sym, int64(off), config.ctxt.Arch.ByteOrder)))]) + for { + off := auxIntToInt32(v.AuxInt) + sym := auxToSym(v.Aux) + if v_0.Op != OpSB || !(symIsRO(sym)) { + break + } + v.reset(Op386MOVLconst) + v.AuxInt = int32ToAuxInt(int32(int16(read16(sym, int64(off), config.ctxt.Arch.ByteOrder)))) + return true + } return false } func rewriteValue386_Op386MOVWLZX(v *Value) bool { diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go index 28041ea76d1953..9ea1114d45e9b0 100644 --- a/src/cmd/compile/internal/ssa/rewriteAMD64.go +++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go @@ -9668,6 +9668,19 @@ func rewriteValueAMD64_OpAMD64MOVBQSXload(v *Value) bool { v.AddArg2(base, mem) return true } + // match: (MOVBQSXload [off] {sym} (SB) _) + // cond: symIsRO(sym) + // result: (MOVQconst [int64(int8(read8(sym, int64(off))))]) + for { + off := auxIntToInt32(v.AuxInt) + sym := auxToSym(v.Aux) + if v_0.Op != OpSB || !(symIsRO(sym)) { + break + } + v.reset(OpAMD64MOVQconst) + v.AuxInt = int64ToAuxInt(int64(int8(read8(sym, int64(off))))) + return true + } return false } func rewriteValueAMD64_OpAMD64MOVBQZX(v *Value) bool { @@ -10412,6 +10425,8 @@ func rewriteValueAMD64_OpAMD64MOVLQSX(v *Value) bool { func rewriteValueAMD64_OpAMD64MOVLQSXload(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] + b := v.Block + config := b.Func.Config // match: (MOVLQSXload [off] {sym} ptr (MOVLstore [off2] {sym2} ptr2 x _)) // cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) // result: (MOVLQSX x) @@ -10455,6 +10470,19 @@ func rewriteValueAMD64_OpAMD64MOVLQSXload(v *Value) bool { v.AddArg2(base, mem) return true } + // match: (MOVLQSXload [off] {sym} (SB) _) + // cond: symIsRO(sym) + // result: (MOVQconst [int64(int32(read32(sym, int64(off), config.ctxt.Arch.ByteOrder)))]) + for { + off := auxIntToInt32(v.AuxInt) + sym := auxToSym(v.Aux) + if v_0.Op != OpSB || !(symIsRO(sym)) { + break + } + v.reset(OpAMD64MOVQconst) + v.AuxInt = int64ToAuxInt(int64(int32(read32(sym, int64(off), config.ctxt.Arch.ByteOrder)))) + return true + } return false } func rewriteValueAMD64_OpAMD64MOVLQZX(v *Value) bool { @@ -10742,15 +10770,15 @@ func rewriteValueAMD64_OpAMD64MOVLload(v *Value) bool { } // match: (MOVLload [off] {sym} (SB) _) // cond: symIsRO(sym) - // result: (MOVQconst [int64(read32(sym, int64(off), config.ctxt.Arch.ByteOrder))]) + // result: (MOVLconst [int32(read32(sym, int64(off), config.ctxt.Arch.ByteOrder))]) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) if v_0.Op != OpSB || !(symIsRO(sym)) { break } - v.reset(OpAMD64MOVQconst) - v.AuxInt = int64ToAuxInt(int64(read32(sym, int64(off), config.ctxt.Arch.ByteOrder))) + v.reset(OpAMD64MOVLconst) + v.AuxInt = int32ToAuxInt(int32(read32(sym, int64(off), config.ctxt.Arch.ByteOrder))) return true } return false @@ -12792,6 +12820,8 @@ func rewriteValueAMD64_OpAMD64MOVWQSX(v *Value) bool { func rewriteValueAMD64_OpAMD64MOVWQSXload(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] + b := v.Block + config := b.Func.Config // match: (MOVWQSXload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) // cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) // result: (MOVWQSX x) @@ -12835,6 +12865,19 @@ func rewriteValueAMD64_OpAMD64MOVWQSXload(v *Value) bool { v.AddArg2(base, mem) return true } + // match: (MOVWQSXload [off] {sym} (SB) _) + // cond: symIsRO(sym) + // result: (MOVQconst [int64(int16(read16(sym, int64(off), config.ctxt.Arch.ByteOrder)))]) + for { + off := auxIntToInt32(v.AuxInt) + sym := auxToSym(v.Aux) + if v_0.Op != OpSB || !(symIsRO(sym)) { + break + } + v.reset(OpAMD64MOVQconst) + v.AuxInt = int64ToAuxInt(int64(int16(read16(sym, int64(off), config.ctxt.Arch.ByteOrder)))) + return true + } return false } func rewriteValueAMD64_OpAMD64MOVWQZX(v *Value) bool { diff --git a/src/cmd/compile/internal/ssa/rewriteARM.go b/src/cmd/compile/internal/ssa/rewriteARM.go index 09be5ccf685b61..8dfa9ab6d6f20a 100644 --- a/src/cmd/compile/internal/ssa/rewriteARM.go +++ b/src/cmd/compile/internal/ssa/rewriteARM.go @@ -4863,6 +4863,19 @@ func rewriteValueARM_OpARMMOVBload(v *Value) bool { v.AddArg3(ptr, idx, mem) return true } + // match: (MOVBload [off] {sym} (SB) _) + // cond: symIsRO(sym) + // result: (MOVWconst [int32(int8(read8(sym, int64(off))))]) + for { + off := auxIntToInt32(v.AuxInt) + sym := auxToSym(v.Aux) + if v_0.Op != OpSB || !(symIsRO(sym)) { + break + } + v.reset(OpARMMOVWconst) + v.AuxInt = int32ToAuxInt(int32(int8(read8(sym, int64(off))))) + return true + } return false } func rewriteValueARM_OpARMMOVBloadidx(v *Value) bool { @@ -5700,6 +5713,8 @@ func rewriteValueARM_OpARMMOVHUreg(v *Value) bool { func rewriteValueARM_OpARMMOVHload(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] + b := v.Block + config := b.Func.Config // match: (MOVHload [off1] {sym} (ADDconst [off2] ptr) mem) // result: (MOVHload [off1+off2] {sym} ptr mem) for { @@ -5798,6 +5813,19 @@ func rewriteValueARM_OpARMMOVHload(v *Value) bool { v.AddArg3(ptr, idx, mem) return true } + // match: (MOVHload [off] {sym} (SB) _) + // cond: symIsRO(sym) + // result: (MOVWconst [int32(int16(read16(sym, int64(off), config.ctxt.Arch.ByteOrder)))]) + for { + off := auxIntToInt32(v.AuxInt) + sym := auxToSym(v.Aux) + if v_0.Op != OpSB || !(symIsRO(sym)) { + break + } + v.reset(OpARMMOVWconst) + v.AuxInt = int32ToAuxInt(int32(int16(read16(sym, int64(off), config.ctxt.Arch.ByteOrder)))) + return true + } return false } func rewriteValueARM_OpARMMOVHloadidx(v *Value) bool { diff --git a/src/cmd/compile/internal/ssa/rewriteARM64.go b/src/cmd/compile/internal/ssa/rewriteARM64.go index 6fabb77c0d804a..def0003764d3c5 100644 --- a/src/cmd/compile/internal/ssa/rewriteARM64.go +++ b/src/cmd/compile/internal/ssa/rewriteARM64.go @@ -8718,6 +8718,19 @@ func rewriteValueARM64_OpARM64MOVBload(v *Value) bool { v.AuxInt = int64ToAuxInt(0) return true } + // match: (MOVBload [off] {sym} (SB) _) + // cond: symIsRO(sym) + // result: (MOVDconst [int64(int8(read8(sym, int64(off))))]) + for { + off := auxIntToInt32(v.AuxInt) + sym := auxToSym(v.Aux) + if v_0.Op != OpSB || !(symIsRO(sym)) { + break + } + v.reset(OpARM64MOVDconst) + v.AuxInt = int64ToAuxInt(int64(int8(read8(sym, int64(off))))) + return true + } return false } func rewriteValueARM64_OpARM64MOVBloadidx(v *Value) bool { @@ -10563,6 +10576,19 @@ func rewriteValueARM64_OpARM64MOVHload(v *Value) bool { v.AuxInt = int64ToAuxInt(0) return true } + // match: (MOVHload [off] {sym} (SB) _) + // cond: symIsRO(sym) + // result: (MOVDconst [int64(int16(read16(sym, int64(off), config.ctxt.Arch.ByteOrder)))]) + for { + off := auxIntToInt32(v.AuxInt) + sym := auxToSym(v.Aux) + if v_0.Op != OpSB || !(symIsRO(sym)) { + break + } + v.reset(OpARM64MOVDconst) + v.AuxInt = int64ToAuxInt(int64(int16(read16(sym, int64(off), config.ctxt.Arch.ByteOrder)))) + return true + } return false } func rewriteValueARM64_OpARM64MOVHloadidx(v *Value) bool { @@ -11978,6 +12004,19 @@ func rewriteValueARM64_OpARM64MOVWload(v *Value) bool { v.AuxInt = int64ToAuxInt(0) return true } + // match: (MOVWload [off] {sym} (SB) _) + // cond: symIsRO(sym) + // result: (MOVDconst [int64(int32(read32(sym, int64(off), config.ctxt.Arch.ByteOrder)))]) + for { + off := auxIntToInt32(v.AuxInt) + sym := auxToSym(v.Aux) + if v_0.Op != OpSB || !(symIsRO(sym)) { + break + } + v.reset(OpARM64MOVDconst) + v.AuxInt = int64ToAuxInt(int64(int32(read32(sym, int64(off), config.ctxt.Arch.ByteOrder)))) + return true + } return false } func rewriteValueARM64_OpARM64MOVWloadidx(v *Value) bool { diff --git a/src/cmd/compile/internal/ssa/rewriteMIPS64.go b/src/cmd/compile/internal/ssa/rewriteMIPS64.go index bad8016cb4b04a..b82f027a5a801a 100644 --- a/src/cmd/compile/internal/ssa/rewriteMIPS64.go +++ b/src/cmd/compile/internal/ssa/rewriteMIPS64.go @@ -2802,6 +2802,19 @@ func rewriteValueMIPS64_OpMIPS64MOVBUload(v *Value) bool { v.AddArg2(ptr, mem) return true } + // match: (MOVBUload [off] {sym} (SB) _) + // cond: symIsRO(sym) + // result: (MOVVconst [int64(read8(sym, int64(off)))]) + for { + off := auxIntToInt32(v.AuxInt) + sym := auxToSym(v.Aux) + if v_0.Op != OpSB || !(symIsRO(sym)) { + break + } + v.reset(OpMIPS64MOVVconst) + v.AuxInt = int64ToAuxInt(int64(read8(sym, int64(off)))) + return true + } return false } func rewriteValueMIPS64_OpMIPS64MOVBUreg(v *Value) bool { @@ -2891,7 +2904,7 @@ func rewriteValueMIPS64_OpMIPS64MOVBload(v *Value) bool { } // match: (MOVBload [off] {sym} (SB) _) // cond: symIsRO(sym) - // result: (MOVVconst [int64(read8(sym, int64(off)))]) + // result: (MOVVconst [int64(int8(read8(sym, int64(off))))]) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -2899,7 +2912,7 @@ func rewriteValueMIPS64_OpMIPS64MOVBload(v *Value) bool { break } v.reset(OpMIPS64MOVVconst) - v.AuxInt = int64ToAuxInt(int64(read8(sym, int64(off)))) + v.AuxInt = int64ToAuxInt(int64(int8(read8(sym, int64(off))))) return true } return false @@ -3484,6 +3497,19 @@ func rewriteValueMIPS64_OpMIPS64MOVHUload(v *Value) bool { v.AddArg2(ptr, mem) return true } + // match: (MOVHUload [off] {sym} (SB) _) + // cond: symIsRO(sym) + // result: (MOVVconst [int64(read16(sym, int64(off), config.ctxt.Arch.ByteOrder))]) + for { + off := auxIntToInt32(v.AuxInt) + sym := auxToSym(v.Aux) + if v_0.Op != OpSB || !(symIsRO(sym)) { + break + } + v.reset(OpMIPS64MOVVconst) + v.AuxInt = int64ToAuxInt(int64(read16(sym, int64(off), config.ctxt.Arch.ByteOrder))) + return true + } return false } func rewriteValueMIPS64_OpMIPS64MOVHUreg(v *Value) bool { @@ -3595,7 +3621,7 @@ func rewriteValueMIPS64_OpMIPS64MOVHload(v *Value) bool { } // match: (MOVHload [off] {sym} (SB) _) // cond: symIsRO(sym) - // result: (MOVVconst [int64(read16(sym, int64(off), config.ctxt.Arch.ByteOrder))]) + // result: (MOVVconst [int64(int16(read16(sym, int64(off), config.ctxt.Arch.ByteOrder)))]) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -3603,7 +3629,7 @@ func rewriteValueMIPS64_OpMIPS64MOVHload(v *Value) bool { break } v.reset(OpMIPS64MOVVconst) - v.AuxInt = int64ToAuxInt(int64(read16(sym, int64(off), config.ctxt.Arch.ByteOrder))) + v.AuxInt = int64ToAuxInt(int64(int16(read16(sym, int64(off), config.ctxt.Arch.ByteOrder)))) return true } return false @@ -4202,6 +4228,19 @@ func rewriteValueMIPS64_OpMIPS64MOVWUload(v *Value) bool { v.AddArg2(ptr, mem) return true } + // match: (MOVWUload [off] {sym} (SB) _) + // cond: symIsRO(sym) + // result: (MOVVconst [int64(read32(sym, int64(off), config.ctxt.Arch.ByteOrder))]) + for { + off := auxIntToInt32(v.AuxInt) + sym := auxToSym(v.Aux) + if v_0.Op != OpSB || !(symIsRO(sym)) { + break + } + v.reset(OpMIPS64MOVVconst) + v.AuxInt = int64ToAuxInt(int64(read32(sym, int64(off), config.ctxt.Arch.ByteOrder))) + return true + } return false } func rewriteValueMIPS64_OpMIPS64MOVWUreg(v *Value) bool { @@ -4335,7 +4374,7 @@ func rewriteValueMIPS64_OpMIPS64MOVWload(v *Value) bool { } // match: (MOVWload [off] {sym} (SB) _) // cond: symIsRO(sym) - // result: (MOVVconst [int64(read32(sym, int64(off), config.ctxt.Arch.ByteOrder))]) + // result: (MOVVconst [int64(int32(read32(sym, int64(off), config.ctxt.Arch.ByteOrder)))]) for { off := auxIntToInt32(v.AuxInt) sym := auxToSym(v.Aux) @@ -4343,7 +4382,7 @@ func rewriteValueMIPS64_OpMIPS64MOVWload(v *Value) bool { break } v.reset(OpMIPS64MOVVconst) - v.AuxInt = int64ToAuxInt(int64(read32(sym, int64(off), config.ctxt.Arch.ByteOrder))) + v.AuxInt = int64ToAuxInt(int64(int32(read32(sym, int64(off), config.ctxt.Arch.ByteOrder)))) return true } return false diff --git a/src/cmd/compile/internal/ssa/rewriteWasm.go b/src/cmd/compile/internal/ssa/rewriteWasm.go index 6f83aea13afc5a..e0d753185f6649 100644 --- a/src/cmd/compile/internal/ssa/rewriteWasm.go +++ b/src/cmd/compile/internal/ssa/rewriteWasm.go @@ -3899,6 +3899,8 @@ func rewriteValueWasm_OpWasmI64Load(v *Value) bool { func rewriteValueWasm_OpWasmI64Load16S(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] + b := v.Block + config := b.Func.Config // match: (I64Load16S [off] (I64AddConst [off2] ptr) mem) // cond: isU32Bit(off+off2) // result: (I64Load16S [off+off2] ptr mem) @@ -3918,6 +3920,24 @@ func rewriteValueWasm_OpWasmI64Load16S(v *Value) bool { v.AddArg2(ptr, mem) return true } + // match: (I64Load16S [off] (LoweredAddr {sym} [off2] (SB)) _) + // cond: symIsRO(sym) && isU32Bit(off+int64(off2)) + // result: (I64Const [int64(int16(read16(sym, off+int64(off2), config.ctxt.Arch.ByteOrder)))]) + for { + off := auxIntToInt64(v.AuxInt) + if v_0.Op != OpWasmLoweredAddr { + break + } + off2 := auxIntToInt32(v_0.AuxInt) + sym := auxToSym(v_0.Aux) + v_0_0 := v_0.Args[0] + if v_0_0.Op != OpSB || !(symIsRO(sym) && isU32Bit(off+int64(off2))) { + break + } + v.reset(OpWasmI64Const) + v.AuxInt = int64ToAuxInt(int64(int16(read16(sym, off+int64(off2), config.ctxt.Arch.ByteOrder)))) + return true + } return false } func rewriteValueWasm_OpWasmI64Load16U(v *Value) bool { @@ -3967,6 +3987,8 @@ func rewriteValueWasm_OpWasmI64Load16U(v *Value) bool { func rewriteValueWasm_OpWasmI64Load32S(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] + b := v.Block + config := b.Func.Config // match: (I64Load32S [off] (I64AddConst [off2] ptr) mem) // cond: isU32Bit(off+off2) // result: (I64Load32S [off+off2] ptr mem) @@ -3986,6 +4008,24 @@ func rewriteValueWasm_OpWasmI64Load32S(v *Value) bool { v.AddArg2(ptr, mem) return true } + // match: (I64Load32S [off] (LoweredAddr {sym} [off2] (SB)) _) + // cond: symIsRO(sym) && isU32Bit(off+int64(off2)) + // result: (I64Const [int64(int32(read32(sym, off+int64(off2), config.ctxt.Arch.ByteOrder)))]) + for { + off := auxIntToInt64(v.AuxInt) + if v_0.Op != OpWasmLoweredAddr { + break + } + off2 := auxIntToInt32(v_0.AuxInt) + sym := auxToSym(v_0.Aux) + v_0_0 := v_0.Args[0] + if v_0_0.Op != OpSB || !(symIsRO(sym) && isU32Bit(off+int64(off2))) { + break + } + v.reset(OpWasmI64Const) + v.AuxInt = int64ToAuxInt(int64(int32(read32(sym, off+int64(off2), config.ctxt.Arch.ByteOrder)))) + return true + } return false } func rewriteValueWasm_OpWasmI64Load32U(v *Value) bool { @@ -4054,6 +4094,24 @@ func rewriteValueWasm_OpWasmI64Load8S(v *Value) bool { v.AddArg2(ptr, mem) return true } + // match: (I64Load8S [off] (LoweredAddr {sym} [off2] (SB)) _) + // cond: symIsRO(sym) && isU32Bit(off+int64(off2)) + // result: (I64Const [int64(int8(read8(sym, off+int64(off2))))]) + for { + off := auxIntToInt64(v.AuxInt) + if v_0.Op != OpWasmLoweredAddr { + break + } + off2 := auxIntToInt32(v_0.AuxInt) + sym := auxToSym(v_0.Aux) + v_0_0 := v_0.Args[0] + if v_0_0.Op != OpSB || !(symIsRO(sym) && isU32Bit(off+int64(off2))) { + break + } + v.reset(OpWasmI64Const) + v.AuxInt = int64ToAuxInt(int64(int8(read8(sym, off+int64(off2))))) + return true + } return false } func rewriteValueWasm_OpWasmI64Load8U(v *Value) bool { diff --git a/test/codegen/switch.go b/test/codegen/switch.go index 980ea7056192f3..509343110a32db 100644 --- a/test/codegen/switch.go +++ b/test/codegen/switch.go @@ -183,3 +183,17 @@ func interfaceConv(x IJ) I { // arm64:`CALL\truntime.typeAssert`,`LDAR`,`MOVWU\t16\(R0\)`,`MOVD\t\(R.*\)\(R.*\)` return x } + +// Make sure we can constant fold after inlining. See issue 71699. +func stringSwitchInlineable(s string) { + switch s { + case "foo", "bar", "baz", "goo": + default: + println("no") + } +} +func stringSwitch() { + // amd64:-"CMP",-"CALL" + // arm64:-"CMP",-"CALL" + stringSwitchInlineable("foo") +} From eab8e987c067ca91ad4ed79b384d8a33494bbf39 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 7 Jan 2025 11:28:44 -0500 Subject: [PATCH 358/397] cmd: use cmd/internal/hash.New32 and Sum32 only Do not use New16, New20, Sum16, Sum20 anymore. As of CL 641096, these are just wrappers around New32 and Sum32. Change call sites to use them directly. Change-Id: Icea91a77449f6839b903894997057ba404bd04e0 Reviewed-on: https://go-review.googlesource.com/c/go/+/641076 LUCI-TryBot-Result: Go LUCI Reviewed-by: Keith Randall Reviewed-by: Cherry Mui Auto-Submit: Russ Cox Reviewed-by: Keith Randall --- src/cmd/cgo/main.go | 2 +- src/cmd/compile/internal/liveness/plive.go | 2 +- src/cmd/compile/internal/types/fmt.go | 4 +- src/cmd/internal/hash/hash.go | 59 +++------------------- src/cmd/internal/obj/objfile.go | 2 +- src/cmd/internal/obj/sym.go | 2 +- src/cmd/link/internal/ld/elf.go | 4 +- src/cmd/link/internal/ld/lib.go | 4 +- src/cmd/objdump/objdump_test.go | 4 +- 9 files changed, 20 insertions(+), 63 deletions(-) diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go index 939e282ff069ed..77beb0992cf74f 100644 --- a/src/cmd/cgo/main.go +++ b/src/cmd/cgo/main.go @@ -390,7 +390,7 @@ func main() { // We already put _cgo_ at the beginning, so the main // concern is other cgo wrappers for the same functions. // Use the beginning of the 16 bytes hash of the input to disambiguate. - h := hash.New16() + h := hash.New32() io.WriteString(h, *importPath) var once sync.Once var wg sync.WaitGroup diff --git a/src/cmd/compile/internal/liveness/plive.go b/src/cmd/compile/internal/liveness/plive.go index ac0c2dff0a96c2..6c97858cf6efbb 100644 --- a/src/cmd/compile/internal/liveness/plive.go +++ b/src/cmd/compile/internal/liveness/plive.go @@ -981,7 +981,7 @@ func (lv *Liveness) enableClobber() { // Clobber only functions where the hash of the function name matches a pattern. // Useful for binary searching for a miscompiled function. hstr := "" - for _, b := range hash.Sum20([]byte(lv.f.Name)) { + for _, b := range hash.Sum32([]byte(lv.f.Name)) { hstr += fmt.Sprintf("%08b", b) } if !strings.HasSuffix(hstr, h) { diff --git a/src/cmd/compile/internal/types/fmt.go b/src/cmd/compile/internal/types/fmt.go index 0dba510ac44e20..139defafe20b4c 100644 --- a/src/cmd/compile/internal/types/fmt.go +++ b/src/cmd/compile/internal/types/fmt.go @@ -646,7 +646,7 @@ func SplitVargenSuffix(name string) (base, suffix string) { func TypeHash(t *Type) uint32 { p := t.LinkString() - // Using 16 bytes hash is overkill, but reduces accidental collisions. - h := hash.Sum16([]byte(p)) + // Using a cryptographic hash is overkill but minimizes accidental collisions. + h := hash.Sum32([]byte(p)) return binary.LittleEndian.Uint32(h[:4]) } diff --git a/src/cmd/internal/hash/hash.go b/src/cmd/internal/hash/hash.go index a37368f50e74b9..cdb24a2645ccd5 100644 --- a/src/cmd/internal/hash/hash.go +++ b/src/cmd/internal/hash/hash.go @@ -5,69 +5,26 @@ // Package hash implements hash functions used in the compiler toolchain. package hash -// TODO(rsc): Delete the 16 and 20 forms and use 32 at all call sites. - import ( "crypto/sha256" "hash" ) -const ( - // Size32 is the size of the 32-byte hash checksum. - Size32 = 32 - // Size20 is the size of the 20-byte hash checksum. - Size20 = 20 - // Size16 is the size of the 16-byte hash checksum. - Size16 = 16 -) - -type shortHash struct { - hash.Hash - n int -} +// Size32 is the size of the 32-byte hash functions [New32] and [Sum32]. +const Size32 = 32 -func (h *shortHash) Sum(b []byte) []byte { - old := b - sum := h.Hash.Sum(b) - return sum[:len(old)+h.n] -} - -// New32 returns a new [hash.Hash] computing the 32 bytes hash checksum. +// New32 returns a new [hash.Hash] computing the 32-byte hash checksum. +// Note that New32 and [Sum32] compute different hashes. func New32() hash.Hash { h := sha256.New() _, _ = h.Write([]byte{1}) // make this hash different from sha256 return h } -// New20 returns a new [hash.Hash] computing the 20 bytes hash checksum. -func New20() hash.Hash { - return &shortHash{New32(), 20} -} - -// New16 returns a new [hash.Hash] computing the 16 bytes hash checksum. -func New16() hash.Hash { - return &shortHash{New32(), 16} -} - -// Sum32 returns the 32 bytes checksum of the data. -func Sum32(data []byte) [Size32]byte { +// Sum32 returns a 32-byte checksum of the data. +// Note that Sum32 and [New32] compute different hashes. +func Sum32(data []byte) [32]byte { sum := sha256.Sum256(data) - sum[0] ^= 1 // make this hash different from sha256 + sum[0] ^= 0xff // make this hash different from sha256 return sum } - -// Sum20 returns the 20 bytes checksum of the data. -func Sum20(data []byte) [Size20]byte { - sum := Sum32(data) - var short [Size20]byte - copy(short[:], sum[4:]) - return short -} - -// Sum16 returns the 16 bytes checksum of the data. -func Sum16(data []byte) [Size16]byte { - sum := Sum32(data) - var short [Size16]byte - copy(short[:], sum[8:]) - return short -} diff --git a/src/cmd/internal/obj/objfile.go b/src/cmd/internal/obj/objfile.go index bc22765abcd91a..3299fbf4e6e1b0 100644 --- a/src/cmd/internal/obj/objfile.go +++ b/src/cmd/internal/obj/objfile.go @@ -494,7 +494,7 @@ func contentHash64(s *LSym) goobj.Hash64Type { // For now, we assume there is no circular dependencies among // hashed symbols. func (w *writer) contentHash(s *LSym) goobj.HashType { - h := hash.New20() + h := hash.New32() var tmp [14]byte // Include the size of the symbol in the hash. diff --git a/src/cmd/internal/obj/sym.go b/src/cmd/internal/obj/sym.go index 887257905035fb..08c50ec72b6a5c 100644 --- a/src/cmd/internal/obj/sym.go +++ b/src/cmd/internal/obj/sym.go @@ -216,7 +216,7 @@ func (ctxt *Link) Int128Sym(hi, lo int64) *LSym { // GCLocalsSym generates a content-addressable sym containing data. func (ctxt *Link) GCLocalsSym(data []byte) *LSym { - sum := hash.Sum16(data) + sum := hash.Sum32(data) str := base64.StdEncoding.EncodeToString(sum[:16]) return ctxt.LookupInit(fmt.Sprintf("gclocals·%s", str), func(lsym *LSym) { lsym.P = data diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go index e6a525198fae25..6ff1d943833783 100644 --- a/src/cmd/link/internal/ld/elf.go +++ b/src/cmd/link/internal/ld/elf.go @@ -1690,11 +1690,11 @@ func (ctxt *Link) doelf() { sb.SetType(sym.SRODATA) ldr.SetAttrSpecial(s, true) sb.SetReachable(true) - sb.SetSize(hash.Size20) + sb.SetSize(hash.Size32) slices.SortFunc(ctxt.Library, func(a, b *sym.Library) int { return strings.Compare(a.Pkg, b.Pkg) }) - h := hash.New20() + h := hash.New32() for _, l := range ctxt.Library { h.Write(l.Fingerprint[:]) } diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index 2d8f964f3594c6..b114ca2a3d4115 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -1022,7 +1022,7 @@ func typeSymbolMangle(name string) string { return name } if isType { - hb := hash.Sum20([]byte(name[5:])) + hb := hash.Sum32([]byte(name[5:])) prefix := "type:" if name[5] == '.' { prefix = "type:." @@ -1035,7 +1035,7 @@ func typeSymbolMangle(name string) string { if j == -1 || j <= i { j = len(name) } - hb := hash.Sum20([]byte(name[i+1 : j])) + hb := hash.Sum32([]byte(name[i+1 : j])) return name[:i+1] + base64.StdEncoding.EncodeToString(hb[:6]) + name[j:] } diff --git a/src/cmd/objdump/objdump_test.go b/src/cmd/objdump/objdump_test.go index 0f3a183c612d1c..0d6f608a3f8313 100644 --- a/src/cmd/objdump/objdump_test.go +++ b/src/cmd/objdump/objdump_test.go @@ -134,9 +134,9 @@ func testDisasm(t *testing.T, srcfname string, printCode bool, printGnuAsm bool, goarch = f[1] } - hash := hash.Sum16([]byte(fmt.Sprintf("%v-%v-%v-%v", srcfname, flags, printCode, printGnuAsm))) + hash := hash.Sum32([]byte(fmt.Sprintf("%v-%v-%v-%v", srcfname, flags, printCode, printGnuAsm))) tmp := t.TempDir() - hello := filepath.Join(tmp, fmt.Sprintf("hello-%x.exe", hash)) + hello := filepath.Join(tmp, fmt.Sprintf("hello-%x.exe", hash[:16])) args := []string{"build", "-o", hello} args = append(args, flags...) args = append(args, srcfname) From 43b7e670401401b2e7536b4931df8b29a25994c7 Mon Sep 17 00:00:00 2001 From: Jakub Ciolek Date: Sun, 2 Feb 2025 23:42:43 +0100 Subject: [PATCH 359/397] cmd/compile: lower x*z + y to FMA if FMA enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is a generic opcode for FMA, but we don't use it in rewrite rules. This is maybe because some archs, like WASM and MIPS don't have a late lowering rule for it. Fixes #71204 Intel Alder Lake 12600k (GOAMD64=v3): math: name old time/op new time/op delta Acos-16 4.58ns ± 0% 3.36ns ± 0% -26.68% (p=0.008 n=5+5) Acosh-16 8.04ns ± 1% 6.44ns ± 0% -19.95% (p=0.008 n=5+5) Asin-16 4.28ns ± 0% 3.32ns ± 0% -22.24% (p=0.008 n=5+5) Asinh-16 9.92ns ± 0% 8.62ns ± 0% -13.13% (p=0.008 n=5+5) Atan-16 2.31ns ± 0% 1.84ns ± 0% -20.02% (p=0.008 n=5+5) Atanh-16 7.79ns ± 0% 7.03ns ± 0% -9.67% (p=0.008 n=5+5) Atan2-16 3.93ns ± 0% 3.52ns ± 0% -10.35% (p=0.000 n=5+4) Cbrt-16 4.62ns ± 0% 4.41ns ± 0% -4.57% (p=0.016 n=4+5) Ceil-16 0.14ns ± 1% 0.14ns ± 2% ~ (p=0.103 n=5+5) Copysign-16 0.33ns ± 0% 0.33ns ± 0% +0.03% (p=0.029 n=4+4) Cos-16 4.87ns ± 0% 4.75ns ± 0% -2.44% (p=0.016 n=5+4) Cosh-16 4.86ns ± 0% 4.86ns ± 0% ~ (p=0.317 n=5+5) Erf-16 2.71ns ± 0% 2.25ns ± 0% -16.69% (p=0.008 n=5+5) Erfc-16 3.06ns ± 0% 2.67ns ± 0% -13.00% (p=0.016 n=5+4) Erfinv-16 3.88ns ± 0% 2.84ns ± 3% -26.83% (p=0.008 n=5+5) Erfcinv-16 4.08ns ± 0% 3.01ns ± 1% -26.27% (p=0.008 n=5+5) Exp-16 3.29ns ± 0% 3.37ns ± 2% +2.64% (p=0.016 n=4+5) ExpGo-16 8.44ns ± 0% 7.48ns ± 1% -11.37% (p=0.008 n=5+5) Expm1-16 4.46ns ± 0% 3.69ns ± 2% -17.26% (p=0.016 n=4+5) Exp2-16 8.20ns ± 0% 7.39ns ± 2% -9.94% (p=0.008 n=5+5) Exp2Go-16 8.26ns ± 0% 7.23ns ± 0% -12.49% (p=0.016 n=4+5) Abs-16 0.26ns ± 3% 0.22ns ± 1% -16.34% (p=0.008 n=5+5) Dim-16 0.38ns ± 1% 0.40ns ± 2% +5.02% (p=0.008 n=5+5) Floor-16 0.11ns ± 1% 0.17ns ± 4% +54.99% (p=0.008 n=5+5) Max-16 1.24ns ± 0% 1.24ns ± 0% ~ (p=0.619 n=5+5) Min-16 1.24ns ± 0% 1.24ns ± 0% ~ (p=0.484 n=5+5) Mod-16 13.4ns ± 1% 12.8ns ± 0% -4.21% (p=0.016 n=5+4) Frexp-16 1.70ns ± 0% 1.71ns ± 0% +0.46% (p=0.008 n=5+5) Gamma-16 3.97ns ± 0% 3.97ns ± 0% ~ (p=0.643 n=5+5) Hypot-16 2.11ns ± 0% 2.11ns ± 0% ~ (p=0.762 n=5+5) HypotGo-16 2.48ns ± 4% 2.26ns ± 0% -8.94% (p=0.008 n=5+5) Ilogb-16 1.67ns ± 0% 1.67ns ± 0% -0.07% (p=0.048 n=5+5) J0-16 19.8ns ± 0% 19.3ns ± 0% ~ (p=0.079 n=4+5) J1-16 19.4ns ± 0% 18.9ns ± 0% -2.63% (p=0.000 n=5+4) Jn-16 41.5ns ± 0% 40.6ns ± 0% -2.32% (p=0.016 n=4+5) Ldexp-16 2.26ns ± 0% 2.26ns ± 0% ~ (p=0.683 n=5+5) Lgamma-16 4.40ns ± 0% 4.21ns ± 0% -4.21% (p=0.008 n=5+5) Log-16 4.05ns ± 0% 4.05ns ± 0% ~ (all equal) Logb-16 1.69ns ± 0% 1.69ns ± 0% ~ (p=0.429 n=5+5) Log1p-16 5.00ns ± 0% 3.99ns ± 0% -20.14% (p=0.008 n=5+5) Log10-16 4.22ns ± 0% 4.21ns ± 0% -0.15% (p=0.008 n=5+5) Log2-16 2.27ns ± 0% 2.25ns ± 0% -0.94% (p=0.008 n=5+5) Modf-16 1.44ns ± 0% 1.44ns ± 0% ~ (p=0.492 n=5+5) Nextafter32-16 2.09ns ± 0% 2.09ns ± 0% ~ (p=0.079 n=4+5) Nextafter64-16 2.09ns ± 0% 2.09ns ± 0% ~ (p=0.095 n=4+5) PowInt-16 10.8ns ± 0% 10.8ns ± 0% ~ (all equal) PowFrac-16 25.3ns ± 0% 25.3ns ± 0% -0.09% (p=0.000 n=5+4) Pow10Pos-16 0.52ns ± 1% 0.52ns ± 0% ~ (p=0.810 n=5+5) Pow10Neg-16 0.82ns ± 0% 0.82ns ± 0% ~ (p=0.381 n=5+5) Round-16 0.93ns ± 0% 0.93ns ± 0% ~ (p=0.056 n=5+5) RoundToEven-16 1.64ns ± 0% 1.64ns ± 0% ~ (all equal) Remainder-16 12.4ns ± 2% 12.0ns ± 0% -3.27% (p=0.008 n=5+5) Signbit-16 0.37ns ± 0% 0.37ns ± 0% -0.19% (p=0.008 n=5+5) Sin-16 4.04ns ± 0% 3.92ns ± 0% -3.13% (p=0.000 n=4+5) Sincos-16 5.99ns ± 0% 5.80ns ± 0% -3.03% (p=0.008 n=5+5) Sinh-16 5.22ns ± 0% 5.22ns ± 0% ~ (p=0.651 n=5+4) SqrtIndirect-16 0.41ns ± 0% 0.41ns ± 0% ~ (p=0.333 n=4+5) SqrtLatency-16 2.66ns ± 0% 2.66ns ± 0% ~ (p=0.079 n=4+5) SqrtIndirectLatency-16 2.66ns ± 0% 2.66ns ± 0% ~ (p=1.000 n=5+5) SqrtGoLatency-16 30.1ns ± 0% 28.6ns ± 1% -4.84% (p=0.008 n=5+5) SqrtPrime-16 645ns ± 0% 645ns ± 0% ~ (p=0.095 n=5+4) Tan-16 4.21ns ± 0% 4.09ns ± 0% -2.76% (p=0.029 n=4+4) Tanh-16 5.36ns ± 0% 5.36ns ± 0% ~ (p=0.444 n=5+5) Trunc-16 0.12ns ± 6% 0.11ns ± 1% -6.79% (p=0.008 n=5+5) Y0-16 19.2ns ± 0% 18.7ns ± 0% -2.52% (p=0.000 n=5+4) Y1-16 19.1ns ± 0% 18.4ns ± 0% ~ (p=0.079 n=4+5) Yn-16 40.7ns ± 0% 39.5ns ± 0% -2.82% (p=0.008 n=5+5) Float64bits-16 0.21ns ± 0% 0.21ns ± 0% ~ (p=0.603 n=5+5) Float64frombits-16 0.21ns ± 0% 0.21ns ± 0% ~ (p=0.984 n=4+5) Float32bits-16 0.21ns ± 0% 0.21ns ± 0% ~ (p=0.778 n=4+5) Float32frombits-16 0.21ns ± 0% 0.20ns ± 0% ~ (p=0.397 n=5+5) FMA-16 0.82ns ± 0% 0.82ns ± 0% +0.02% (p=0.029 n=4+4) [Geo mean] 2.87ns 2.74ns -4.61% math/cmplx: name old time/op new time/op delta Abs-16 2.07ns ± 0% 2.05ns ± 0% -0.70% (p=0.016 n=5+4) Acos-16 36.5ns ± 0% 35.7ns ± 0% -2.33% (p=0.029 n=4+4) Acosh-16 37.0ns ± 0% 36.2ns ± 0% -2.20% (p=0.008 n=5+5) Asin-16 36.5ns ± 0% 35.7ns ± 0% -2.29% (p=0.008 n=5+5) Asinh-16 33.5ns ± 0% 31.6ns ± 0% -5.51% (p=0.008 n=5+5) Atan-16 15.5ns ± 0% 13.9ns ± 0% -10.61% (p=0.008 n=5+5) Atanh-16 15.0ns ± 0% 13.6ns ± 0% -9.73% (p=0.008 n=5+5) Conj-16 0.11ns ± 5% 0.11ns ± 1% ~ (p=0.421 n=5+5) Cos-16 12.3ns ± 0% 12.2ns ± 0% -0.60% (p=0.000 n=4+5) Cosh-16 12.1ns ± 0% 12.0ns ± 0% ~ (p=0.079 n=4+5) Exp-16 10.0ns ± 0% 9.8ns ± 0% -1.77% (p=0.008 n=5+5) Log-16 14.5ns ± 0% 13.7ns ± 0% -5.67% (p=0.008 n=5+5) Log10-16 14.5ns ± 0% 13.7ns ± 0% -5.55% (p=0.000 n=5+4) Phase-16 5.11ns ± 0% 4.25ns ± 0% -16.90% (p=0.008 n=5+5) Polar-16 7.12ns ± 0% 6.35ns ± 0% -10.90% (p=0.008 n=5+5) Pow-16 64.3ns ± 0% 63.7ns ± 0% -0.97% (p=0.008 n=5+5) Rect-16 5.74ns ± 0% 5.58ns ± 0% -2.73% (p=0.016 n=4+5) Sin-16 12.2ns ± 0% 12.2ns ± 0% -0.54% (p=0.000 n=4+5) Sinh-16 12.1ns ± 0% 12.0ns ± 0% -0.58% (p=0.000 n=5+4) Sqrt-16 5.30ns ± 0% 5.18ns ± 0% -2.36% (p=0.008 n=5+5) Tan-16 22.7ns ± 0% 22.6ns ± 0% -0.33% (p=0.008 n=5+5) Tanh-16 21.2ns ± 0% 20.9ns ± 0% -1.32% (p=0.008 n=5+5) [Geo mean] 11.3ns 10.8ns -3.97% Change-Id: Idcc4b357ba68477929c126289e5095b27a827b1b Reviewed-on: https://go-review.googlesource.com/c/go/+/646335 LUCI-TryBot-Result: Go LUCI Auto-Submit: Keith Randall Reviewed-by: Keith Randall Reviewed-by: Dmitri Shuralyov Reviewed-by: Keith Randall --- src/cmd/compile/internal/amd64/ssa.go | 4 +- src/cmd/compile/internal/ssa/_gen/AMD64.rules | 5 +- src/cmd/compile/internal/ssa/_gen/AMD64Ops.go | 10 +++- src/cmd/compile/internal/ssa/opGen.go | 47 +++++++++++++++++++ src/cmd/compile/internal/ssa/rewriteAMD64.go | 44 ++++++++++++++++- test/codegen/floats.go | 2 + test/codegen/math.go | 6 ++- 7 files changed, 110 insertions(+), 8 deletions(-) diff --git a/src/cmd/compile/internal/amd64/ssa.go b/src/cmd/compile/internal/amd64/ssa.go index 493369af51ce15..9eef71f760357a 100644 --- a/src/cmd/compile/internal/amd64/ssa.go +++ b/src/cmd/compile/internal/amd64/ssa.go @@ -202,7 +202,7 @@ func getgFromTLS(s *ssagen.State, r int16) { func ssaGenValue(s *ssagen.State, v *ssa.Value) { switch v.Op { - case ssa.OpAMD64VFMADD231SD: + case ssa.OpAMD64VFMADD231SD, ssa.OpAMD64VFMADD231SS: p := s.Prog(v.Op.Asm()) p.From = obj.Addr{Type: obj.TYPE_REG, Reg: v.Args[2].Reg()} p.To = obj.Addr{Type: obj.TYPE_REG, Reg: v.Reg()} @@ -1170,6 +1170,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { case ssa.OpAMD64BSFL, ssa.OpAMD64BSRL, ssa.OpAMD64SQRTSD, ssa.OpAMD64SQRTSS: p.To.Reg = v.Reg() } + case ssa.OpAMD64LoweredRound32F, ssa.OpAMD64LoweredRound64F: + // input is already rounded case ssa.OpAMD64ROUNDSD: p := s.Prog(v.Op.Asm()) val := v.AuxInt diff --git a/src/cmd/compile/internal/ssa/_gen/AMD64.rules b/src/cmd/compile/internal/ssa/_gen/AMD64.rules index 0e429b5be74dcb..9177067e522206 100644 --- a/src/cmd/compile/internal/ssa/_gen/AMD64.rules +++ b/src/cmd/compile/internal/ssa/_gen/AMD64.rules @@ -170,7 +170,7 @@ (Cvt32Fto64F ...) => (CVTSS2SD ...) (Cvt64Fto32F ...) => (CVTSD2SS ...) -(Round(32|64)F ...) => (Copy ...) +(Round(32|64)F ...) => (LoweredRound(32|64)F ...) // Floating-point min is tricky, as the hardware op isn't right for various special // cases (-0 and NaN). We use two hardware ops organized just right to make the @@ -1589,6 +1589,9 @@ (MULSDload x [off] {sym} ptr (MOVQstore [off] {sym} ptr y _)) => (MULSD x (MOVQi2f y)) (MULSSload x [off] {sym} ptr (MOVLstore [off] {sym} ptr y _)) => (MULSS x (MOVLi2f y)) +// Detect FMA +(ADDS(S|D) (MULS(S|D) x y) z) && buildcfg.GOAMD64 >= 3 && z.Block.Func.useFMA(v) => (VFMADD231S(S|D) z x y) + // Redirect stores to use the other register set. (MOVQstore [off] {sym} ptr (MOVQf2i val) mem) => (MOVSDstore [off] {sym} ptr val mem) (MOVLstore [off] {sym} ptr (MOVLf2i val) mem) => (MOVSSstore [off] {sym} ptr val mem) diff --git a/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go b/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go index 53df7af3059a52..1cce32eba32523 100644 --- a/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go +++ b/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go @@ -692,9 +692,15 @@ func init() { // ROUNDSD instruction is only guaraneteed to be available if GOAMD64>=v2. // For GOAMD64=v3. + // x==S for float32, x==D for float64 + // arg0 + arg1*arg2, with no intermediate rounding. + {name: "VFMADD231SS", argLength: 3, reg: fp31, resultInArg0: true, asm: "VFMADD231SS"}, {name: "VFMADD231SD", argLength: 3, reg: fp31, resultInArg0: true, asm: "VFMADD231SD"}, // Note that these operations don't exactly match the semantics of Go's diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index 13ec9dc9e3fc3a..f4f648c53b5fa6 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -924,6 +924,9 @@ const ( OpAMD64SQRTSD OpAMD64SQRTSS OpAMD64ROUNDSD + OpAMD64LoweredRound32F + OpAMD64LoweredRound64F + OpAMD64VFMADD231SS OpAMD64VFMADD231SD OpAMD64MINSD OpAMD64MINSS @@ -12060,6 +12063,50 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "LoweredRound32F", + argLen: 1, + resultInArg0: true, + zeroWidth: true, + reg: regInfo{ + inputs: []inputInfo{ + {0, 2147418112}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 + }, + outputs: []outputInfo{ + {0, 2147418112}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 + }, + }, + }, + { + name: "LoweredRound64F", + argLen: 1, + resultInArg0: true, + zeroWidth: true, + reg: regInfo{ + inputs: []inputInfo{ + {0, 2147418112}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 + }, + outputs: []outputInfo{ + {0, 2147418112}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 + }, + }, + }, + { + name: "VFMADD231SS", + argLen: 3, + resultInArg0: true, + asm: x86.AVFMADD231SS, + reg: regInfo{ + inputs: []inputInfo{ + {0, 2147418112}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 + {1, 2147418112}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 + {2, 2147418112}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 + }, + outputs: []outputInfo{ + {0, 2147418112}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 + }, + }, + }, { name: "VFMADD231SD", argLen: 3, diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go index 9ea1114d45e9b0..63376dcb76f2d9 100644 --- a/src/cmd/compile/internal/ssa/rewriteAMD64.go +++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go @@ -1007,10 +1007,10 @@ func rewriteValueAMD64(v *Value) bool { v.Op = OpAMD64ROLB return true case OpRound32F: - v.Op = OpCopy + v.Op = OpAMD64LoweredRound32F return true case OpRound64F: - v.Op = OpCopy + v.Op = OpAMD64LoweredRound64F return true case OpRoundToEven: return rewriteValueAMD64_OpRoundToEven(v) @@ -2430,6 +2430,26 @@ func rewriteValueAMD64_OpAMD64ADDSD(v *Value) bool { } break } + // match: (ADDSD (MULSD x y) z) + // cond: buildcfg.GOAMD64 >= 3 && z.Block.Func.useFMA(v) + // result: (VFMADD231SD z x y) + for { + for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { + if v_0.Op != OpAMD64MULSD { + continue + } + y := v_0.Args[1] + x := v_0.Args[0] + z := v_1 + if !(buildcfg.GOAMD64 >= 3 && z.Block.Func.useFMA(v)) { + continue + } + v.reset(OpAMD64VFMADD231SD) + v.AddArg3(z, x, y) + return true + } + break + } return false } func rewriteValueAMD64_OpAMD64ADDSDload(v *Value) bool { @@ -2533,6 +2553,26 @@ func rewriteValueAMD64_OpAMD64ADDSS(v *Value) bool { } break } + // match: (ADDSS (MULSS x y) z) + // cond: buildcfg.GOAMD64 >= 3 && z.Block.Func.useFMA(v) + // result: (VFMADD231SS z x y) + for { + for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { + if v_0.Op != OpAMD64MULSS { + continue + } + y := v_0.Args[1] + x := v_0.Args[0] + z := v_1 + if !(buildcfg.GOAMD64 >= 3 && z.Block.Func.useFMA(v)) { + continue + } + v.reset(OpAMD64VFMADD231SS) + v.AddArg3(z, x, y) + return true + } + break + } return false } func rewriteValueAMD64_OpAMD64ADDSSload(v *Value) bool { diff --git a/test/codegen/floats.go b/test/codegen/floats.go index 1b85eba35249c9..2a5cf3995781e6 100644 --- a/test/codegen/floats.go +++ b/test/codegen/floats.go @@ -74,6 +74,7 @@ func FusedAdd32(x, y, z float32) float32 { // arm64:"FMADDS" // loong64:"FMADDF\t" // riscv64:"FMADDS\t" + // amd64/v3:"VFMADD231SS\t" return x*y + z } @@ -98,6 +99,7 @@ func FusedAdd64(x, y, z float64) float64 { // arm64:"FMADDD" // loong64:"FMADDD\t" // riscv64:"FMADDD\t" + // amd64/v3:"VFMADD231SD\t" return x*y + z } diff --git a/test/codegen/math.go b/test/codegen/math.go index 4ce5fa419d2b79..87d9cd7b2715ba 100644 --- a/test/codegen/math.go +++ b/test/codegen/math.go @@ -240,10 +240,11 @@ func nanGenerate64() float64 { // amd64:"DIVSD" z0 := zero / zero - // amd64:"MULSD" + // amd64/v1,amd64/v2:"MULSD" z1 := zero * inf // amd64:"SQRTSD" z2 := math.Sqrt(negone) + // amd64/v3:"VFMADD231SD" return z0 + z1 + z2 } @@ -254,7 +255,8 @@ func nanGenerate32() float32 { // amd64:"DIVSS" z0 := zero / zero - // amd64:"MULSS" + // amd64/v1,amd64/v2:"MULSS" z1 := zero * inf + // amd64/v3:"VFMADD231SS" return z0 + z1 } From 89c2f282dc84a9b3842dca375a4635305c86ad9b Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Mon, 6 Jan 2025 15:28:22 -0800 Subject: [PATCH 360/397] cmd/compile: move []byte->string map key optimization to ssa If we call slicebytetostring immediately (with no intervening writes) before calling map access or delete functions with the resulting string as the key, then we can just use the ptr/len of the slicebytetostring argument as the key. This avoids an allocation. Fixes #44898 Update #71132 There's old code in cmd/compile/internal/walk/order.go that handles some of these cases. 1. m[string(b)] 2. s := string(b); m[s] 3. m[[2]string{string(b1),string(b2)}] The old code handled cases 1&3. The new code handles cases 1&2. We'll leave the old code around to keep 3 working, although it seems not terribly common. Case 2 happens particularly after inlining, so it is pretty common. Change-Id: I8913226ca79d2c65f4e2bd69a38ac8c976a57e43 Reviewed-on: https://go-review.googlesource.com/c/go/+/640656 Reviewed-by: Keith Randall Reviewed-by: Michael Pratt LUCI-TryBot-Result: Go LUCI --- .../compile/internal/ssa/_gen/generic.rules | 19 ++++++++++ src/cmd/compile/internal/ssa/rewrite.go | 8 +++++ .../compile/internal/ssa/rewritegeneric.go | 36 +++++++++++++++++++ src/cmd/compile/internal/walk/order.go | 8 +++++ test/codegen/maps.go | 22 ++++++++++++ 5 files changed, 93 insertions(+) diff --git a/src/cmd/compile/internal/ssa/_gen/generic.rules b/src/cmd/compile/internal/ssa/_gen/generic.rules index 9188eff2ecc448..0339370517ca83 100644 --- a/src/cmd/compile/internal/ssa/_gen/generic.rules +++ b/src/cmd/compile/internal/ssa/_gen/generic.rules @@ -2795,3 +2795,22 @@ && isDirectIface(itab) && clobber(v) => (MakeResult (EqPtr x y) mem) + +// If we use the result of slicebytetostring in a map lookup operation, +// then we don't need to actually do the []byte->string conversion. +// We can just use the ptr/len of the byte slice directly as a (temporary) string. +// +// Note that this does not handle some obscure cases like +// m[[2]string{string(b1), string(b2)}]. There is code in ../walk/order.go +// which handles some of those cases. +(StaticLECall {f} [argsize] typ_ map_ key:(SelectN [0] sbts:(StaticLECall {g} _ ptr len mem)) m:(SelectN [1] sbts)) + && (isSameCall(f, "runtime.mapaccess1_faststr") + || isSameCall(f, "runtime.mapaccess2_faststr") + || isSameCall(f, "runtime.mapdelete_faststr")) + && isSameCall(g, "runtime.slicebytetostring") + && key.Uses == 1 + && sbts.Uses == 2 + && resetCopy(m, mem) + && clobber(sbts) + && clobber(key) +=> (StaticLECall {f} [argsize] typ_ map_ (StringMake ptr len) mem) diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go index 383cb23dae4982..71f8e9045cecab 100644 --- a/src/cmd/compile/internal/ssa/rewrite.go +++ b/src/cmd/compile/internal/ssa/rewrite.go @@ -964,6 +964,14 @@ func clobber(vv ...*Value) bool { return true } +// resetCopy resets v to be a copy of arg. +// Always returns true. +func resetCopy(v *Value, arg *Value) bool { + v.reset(OpCopy) + v.AddArg(arg) + return true +} + // clobberIfDead resets v when use count is 1. Returns true. // clobberIfDead is used by rewrite rules to decrement // use counts of v's args when v is dead and never used. diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go index b3161ad50d4448..d0b6e0b1001d04 100644 --- a/src/cmd/compile/internal/ssa/rewritegeneric.go +++ b/src/cmd/compile/internal/ssa/rewritegeneric.go @@ -30350,6 +30350,42 @@ func rewriteValuegeneric_OpStaticLECall(v *Value) bool { v.AddArg2(v0, mem) return true } + // match: (StaticLECall {f} [argsize] typ_ map_ key:(SelectN [0] sbts:(StaticLECall {g} _ ptr len mem)) m:(SelectN [1] sbts)) + // cond: (isSameCall(f, "runtime.mapaccess1_faststr") || isSameCall(f, "runtime.mapaccess2_faststr") || isSameCall(f, "runtime.mapdelete_faststr")) && isSameCall(g, "runtime.slicebytetostring") && key.Uses == 1 && sbts.Uses == 2 && resetCopy(m, mem) && clobber(sbts) && clobber(key) + // result: (StaticLECall {f} [argsize] typ_ map_ (StringMake ptr len) mem) + for { + if len(v.Args) != 4 { + break + } + argsize := auxIntToInt32(v.AuxInt) + f := auxToCall(v.Aux) + _ = v.Args[3] + typ_ := v.Args[0] + map_ := v.Args[1] + key := v.Args[2] + if key.Op != OpSelectN || auxIntToInt64(key.AuxInt) != 0 { + break + } + sbts := key.Args[0] + if sbts.Op != OpStaticLECall || len(sbts.Args) != 4 { + break + } + g := auxToCall(sbts.Aux) + mem := sbts.Args[3] + ptr := sbts.Args[1] + len := sbts.Args[2] + m := v.Args[3] + if m.Op != OpSelectN || auxIntToInt64(m.AuxInt) != 1 || sbts != m.Args[0] || !((isSameCall(f, "runtime.mapaccess1_faststr") || isSameCall(f, "runtime.mapaccess2_faststr") || isSameCall(f, "runtime.mapdelete_faststr")) && isSameCall(g, "runtime.slicebytetostring") && key.Uses == 1 && sbts.Uses == 2 && resetCopy(m, mem) && clobber(sbts) && clobber(key)) { + break + } + v.reset(OpStaticLECall) + v.AuxInt = int32ToAuxInt(argsize) + v.Aux = callToAux(f) + v0 := b.NewValue0(v.Pos, OpStringMake, typ.String) + v0.AddArg2(ptr, len) + v.AddArg4(typ_, map_, v0, mem) + return true + } return false } func rewriteValuegeneric_OpStore(v *Value) bool { diff --git a/src/cmd/compile/internal/walk/order.go b/src/cmd/compile/internal/walk/order.go index 858fc706ab9783..8967b7dbba4840 100644 --- a/src/cmd/compile/internal/walk/order.go +++ b/src/cmd/compile/internal/walk/order.go @@ -334,6 +334,14 @@ func (o *orderState) mapKeyTemp(outerPos src.XPos, t *types.Type, n ir.Node) ir. // It would be nice to handle these generally, but because // []byte keys are not allowed in maps, the use of string(k) // comes up in important cases in practice. See issue 3512. +// +// Note that this code does not handle the case: +// +// s := string(k) +// x = m[s] +// +// Cases like this are handled during SSA, search for slicebytetostring +// in ../ssa/_gen/generic.rules. func mapKeyReplaceStrConv(n ir.Node) bool { var replaced bool switch n.Op() { diff --git a/test/codegen/maps.go b/test/codegen/maps.go index c4aed3354514f6..860b2c2cbd23cd 100644 --- a/test/codegen/maps.go +++ b/test/codegen/maps.go @@ -66,6 +66,28 @@ func LookupStringConversionKeyedArrayLit(m map[[2]string]int, bytes []byte) int return m[[2]string{0: string(bytes)}] } +func LookupStringConversion1(m map[string]int, bytes []byte) int { + // amd64:-`.*runtime\.slicebytetostring\(` + s := string(bytes) + return m[s] +} +func LookupStringConversion2(m *map[string]int, bytes []byte) int { + // amd64:-`.*runtime\.slicebytetostring\(` + s := string(bytes) + return (*m)[s] +} +func LookupStringConversion3(m map[string]int, bytes []byte) (int, bool) { + // amd64:-`.*runtime\.slicebytetostring\(` + s := string(bytes) + r, ok := m[s] + return r, ok +} +func DeleteStringConversion(m map[string]int, bytes []byte) { + // amd64:-`.*runtime\.slicebytetostring\(` + s := string(bytes) + delete(m, s) +} + // ------------------- // // Map Clear // // ------------------- // From 0044bc614af52d3f9acdd4db18e053e635c25ccd Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 11 Feb 2025 12:56:27 -0800 Subject: [PATCH 361/397] os: consolidate and clarify File.Fd docs Change-Id: Id062b969fe7d6908a0797b36a4a379e4d46ba557 Reviewed-on: https://go-review.googlesource.com/c/go/+/648516 LUCI-TryBot-Result: Go LUCI Auto-Submit: Ian Lance Taylor Reviewed-by: Ian Lance Taylor Reviewed-by: Damien Neil --- src/os/file.go | 17 +++++++++++++++++ src/os/file_plan9.go | 37 +++++++++++++++---------------------- src/os/file_unix.go | 15 ++------------- src/os/file_windows.go | 9 ++------- src/os/stat_plan9.go | 2 +- 5 files changed, 37 insertions(+), 43 deletions(-) diff --git a/src/os/file.go b/src/os/file.go index 1d4382e4861f6a..32ff6be7be2538 100644 --- a/src/os/file.go +++ b/src/os/file.go @@ -685,6 +685,23 @@ func (f *File) SyscallConn() (syscall.RawConn, error) { return newRawConn(f) } +// Fd returns the system file descriptor or handle referencing the open file. +// If f is closed, the descriptor becomes invalid. +// If f is garbage collected, a cleanup may close the descriptor, +// making it invalid; see [runtime.AddCleanup] for more information on when +// a cleanup might be run. +// +// Do not close the returned descriptor; that could cause a later +// close of f to close an unrelated descriptor. +// +// On Unix systems this will cause the [File.SetDeadline] +// methods to stop working. +// +// For most uses prefer the f.SyscallConn method. +func (f *File) Fd() uintptr { + return f.fd() +} + // DirFS returns a file system (an fs.FS) for the tree of files rooted at the directory dir. // // Note that DirFS("/prefix") only guarantees that the Open calls it makes to the diff --git a/src/os/file_plan9.go b/src/os/file_plan9.go index f74dbf20c49df7..73df3b086dc3d7 100644 --- a/src/os/file_plan9.go +++ b/src/os/file_plan9.go @@ -27,26 +27,19 @@ func fixLongPath(path string) string { // to close the wrong file descriptor. type file struct { fdmu poll.FDMutex - fd int + sysfd int name string dirinfo atomic.Pointer[dirInfo] // nil unless directory being read appendMode bool // whether file is opened for appending cleanup runtime.Cleanup // cleanup closes the file when no longer referenced } -// Fd returns the integer Plan 9 file descriptor referencing the open file. -// If f is closed, the file descriptor becomes invalid. -// If f is garbage collected, a cleanup may close the file descriptor, -// making it invalid; see [runtime.AddCleanup] for more information on when -// a cleanup might be run. On Unix systems this will cause the [File.SetDeadline] -// methods to stop working. -// -// As an alternative, see the f.SyscallConn method. -func (f *File) Fd() uintptr { +// fd is the Plan 9 implementation of Fd. +func (f *File) fd() uintptr { if f == nil { return ^(uintptr(0)) } - return uintptr(f.fd) + return uintptr(f.sysfd) } // NewFile returns a new File with the given file descriptor and @@ -57,7 +50,7 @@ func NewFile(fd uintptr, name string) *File { if fdi < 0 { return nil } - f := &File{&file{fd: fdi, name: name}} + f := &File{&file{sysfd: fdi, name: name}} f.cleanup = runtime.AddCleanup(f, func(f *file) { f.close() }, f.file) return f } @@ -180,7 +173,7 @@ func (file *file) close() error { // and writeUnlock methods. func (file *file) destroy() error { var err error - if e := syscall.Close(file.fd); e != nil { + if e := syscall.Close(file.sysfd); e != nil { err = &PathError{Op: "close", Path: file.name, Err: e} } return err @@ -222,7 +215,7 @@ func (f *File) Truncate(size int64) error { } defer f.decref() - if err = syscall.Fwstat(f.fd, buf[:n]); err != nil { + if err = syscall.Fwstat(f.sysfd, buf[:n]); err != nil { return &PathError{Op: "truncate", Path: f.name, Err: err} } return nil @@ -254,7 +247,7 @@ func (f *File) chmod(mode FileMode) error { } defer f.decref() - if err = syscall.Fwstat(f.fd, buf[:n]); err != nil { + if err = syscall.Fwstat(f.sysfd, buf[:n]); err != nil { return &PathError{Op: "chmod", Path: f.name, Err: err} } return nil @@ -281,7 +274,7 @@ func (f *File) Sync() error { } defer f.decref() - if err = syscall.Fwstat(f.fd, buf[:n]); err != nil { + if err = syscall.Fwstat(f.sysfd, buf[:n]); err != nil { return &PathError{Op: "sync", Path: f.name, Err: err} } return nil @@ -294,7 +287,7 @@ func (f *File) read(b []byte) (n int, err error) { return 0, err } defer f.readUnlock() - n, e := fixCount(syscall.Read(f.fd, b)) + n, e := fixCount(syscall.Read(f.sysfd, b)) if n == 0 && len(b) > 0 && e == nil { return 0, io.EOF } @@ -309,7 +302,7 @@ func (f *File) pread(b []byte, off int64) (n int, err error) { return 0, err } defer f.readUnlock() - n, e := fixCount(syscall.Pread(f.fd, b, off)) + n, e := fixCount(syscall.Pread(f.sysfd, b, off)) if n == 0 && len(b) > 0 && e == nil { return 0, io.EOF } @@ -328,7 +321,7 @@ func (f *File) write(b []byte) (n int, err error) { if len(b) == 0 { return 0, nil } - return fixCount(syscall.Write(f.fd, b)) + return fixCount(syscall.Write(f.sysfd, b)) } // pwrite writes len(b) bytes to the File starting at byte offset off. @@ -343,7 +336,7 @@ func (f *File) pwrite(b []byte, off int64) (n int, err error) { if len(b) == 0 { return 0, nil } - return fixCount(syscall.Pwrite(f.fd, b, off)) + return fixCount(syscall.Pwrite(f.sysfd, b, off)) } // seek sets the offset for the next Read or Write on file to offset, interpreted @@ -358,7 +351,7 @@ func (f *File) seek(offset int64, whence int) (ret int64, err error) { // Free cached dirinfo, so we allocate a new one if we // access this file as a directory again. See #35767 and #37161. f.dirinfo.Store(nil) - return syscall.Seek(f.fd, offset, whence) + return syscall.Seek(f.sysfd, offset, whence) } // Truncate changes the size of the named file. @@ -555,7 +548,7 @@ func (f *File) Chdir() error { return err } defer f.decref() - if e := syscall.Fchdir(f.fd); e != nil { + if e := syscall.Fchdir(f.sysfd); e != nil { return &PathError{Op: "chdir", Path: f.name, Err: e} } return nil diff --git a/src/os/file_unix.go b/src/os/file_unix.go index 5e9239edc56e40..bb99b5279de53b 100644 --- a/src/os/file_unix.go +++ b/src/os/file_unix.go @@ -66,19 +66,8 @@ type file struct { cleanup runtime.Cleanup // cleanup closes the file when no longer referenced } -// Fd returns the integer Unix file descriptor referencing the open file. -// If f is closed, the file descriptor becomes invalid. -// If f is garbage collected, a cleanup may close the file descriptor, -// making it invalid; see [runtime.AddCleanup] for more information on when -// a cleanup might be run. On Unix systems this will cause the [File.SetDeadline] -// methods to stop working. -// Because file descriptors can be reused, the returned file descriptor may -// only be closed through the [File.Close] method of f, or by its cleanup during -// garbage collection. Otherwise, during garbage collection the cleanup -// may close an unrelated file descriptor with the same (reused) number. -// -// As an alternative, see the f.SyscallConn method. -func (f *File) Fd() uintptr { +// fd is the Unix implementation of Fd. +func (f *File) fd() uintptr { if f == nil { return ^(uintptr(0)) } diff --git a/src/os/file_windows.go b/src/os/file_windows.go index 2da924fe437db4..c209a9f003b39b 100644 --- a/src/os/file_windows.go +++ b/src/os/file_windows.go @@ -32,13 +32,8 @@ type file struct { cleanup runtime.Cleanup // cleanup closes the file when no longer referenced } -// Fd returns the Windows handle referencing the open file. -// If f is closed, the file descriptor becomes invalid. -// If f is garbage collected, a cleanup may close the file descriptor, -// making it invalid; see [runtime.AddCleanup] for more information on when -// a cleanup might be run. On Unix systems this will cause the [File.SetDeadline] -// methods to stop working. -func (file *File) Fd() uintptr { +// fd is the Windows implementation of Fd. +func (file *File) fd() uintptr { if file == nil { return uintptr(syscall.InvalidHandle) } diff --git a/src/os/stat_plan9.go b/src/os/stat_plan9.go index a5e9901379aeac..e9fba17e9d1b51 100644 --- a/src/os/stat_plan9.go +++ b/src/os/stat_plan9.go @@ -59,7 +59,7 @@ func dirstat(arg any) (*syscall.Dir, error) { if err := a.incref("fstat"); err != nil { return nil, err } - n, err = syscall.Fstat(a.fd, buf) + n, err = syscall.Fstat(a.sysfd, buf) a.decref() case string: name = a From eab3c1e697189ddded55a5ac14d8b29d35145419 Mon Sep 17 00:00:00 2001 From: Jes Cok Date: Thu, 13 Feb 2025 16:02:20 +0000 Subject: [PATCH 362/397] os: explicitly return nil for {rootChmod,rootMkdir,rootRemove} in root_openat.go It is consistent with same functions in root_noopenat.go. Change-Id: I81415fd3922101499fcbbdec97e315add0671acb GitHub-Last-Rev: 3444e8546ee1877feb644202ad2b05379b4b7e74 GitHub-Pull-Request: golang/go#71715 Reviewed-on: https://go-review.googlesource.com/c/go/+/649235 Reviewed-by: Ian Lance Taylor Reviewed-by: Damien Neil Auto-Submit: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI --- src/os/root_openat.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/os/root_openat.go b/src/os/root_openat.go index 5038c822f59a38..d98d2e36752f4b 100644 --- a/src/os/root_openat.go +++ b/src/os/root_openat.go @@ -74,7 +74,7 @@ func rootChmod(r *Root, name string, mode FileMode) error { if err != nil { return &PathError{Op: "chmodat", Path: name, Err: err} } - return err + return nil } func rootMkdir(r *Root, name string, perm FileMode) error { @@ -84,7 +84,7 @@ func rootMkdir(r *Root, name string, perm FileMode) error { if err != nil { return &PathError{Op: "mkdirat", Path: name, Err: err} } - return err + return nil } func rootRemove(r *Root, name string) error { @@ -94,7 +94,7 @@ func rootRemove(r *Root, name string) error { if err != nil { return &PathError{Op: "removeat", Path: name, Err: err} } - return err + return nil } // doInRoot performs an operation on a path in a Root. From 0b88a878798de21c79cbe0e499402a008df0c4bb Mon Sep 17 00:00:00 2001 From: "khr@golang.org" Date: Sun, 17 Nov 2024 16:42:37 -0800 Subject: [PATCH 363/397] cmd/compile: add variants of LDP/STP for arm64 load/store combining These will be used in a subsequent CL. Change-Id: I96562668da502e5cb41096c9831c59292644be72 Reviewed-on: https://go-review.googlesource.com/c/go/+/629255 Reviewed-by: Cherry Mui Reviewed-by: Keith Randall LUCI-TryBot-Result: Go LUCI --- src/cmd/compile/internal/arm64/ssa.go | 4 +- src/cmd/compile/internal/ssa/_gen/ARM64Ops.go | 67 ++++++---- src/cmd/compile/internal/ssa/opGen.go | 126 ++++++++++++++++-- 3 files changed, 160 insertions(+), 37 deletions(-) diff --git a/src/cmd/compile/internal/arm64/ssa.go b/src/cmd/compile/internal/arm64/ssa.go index adcabb1b954aeb..7bf8051bef5e7b 100644 --- a/src/cmd/compile/internal/arm64/ssa.go +++ b/src/cmd/compile/internal/arm64/ssa.go @@ -516,7 +516,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { ssagen.AddAux(&p.From, v) p.To.Type = obj.TYPE_REG p.To.Reg = v.Reg() - case ssa.OpARM64LDP: + case ssa.OpARM64LDP, ssa.OpARM64LDPW, ssa.OpARM64FLDPD, ssa.OpARM64FLDPS: p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_MEM p.From.Reg = v.Args[0].Reg() @@ -583,7 +583,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.To = genIndexedOperand(v.Op, v.Args[0].Reg(), v.Args[1].Reg()) p.From.Type = obj.TYPE_REG p.From.Reg = v.Args[2].Reg() - case ssa.OpARM64STP: + case ssa.OpARM64STP, ssa.OpARM64STPW, ssa.OpARM64FSTPD, ssa.OpARM64FSTPS: p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_REGREG p.From.Reg = v.Args[1].Reg() diff --git a/src/cmd/compile/internal/ssa/_gen/ARM64Ops.go b/src/cmd/compile/internal/ssa/_gen/ARM64Ops.go index c9cb62cd17cee2..4c4e610dba9413 100644 --- a/src/cmd/compile/internal/ssa/_gen/ARM64Ops.go +++ b/src/cmd/compile/internal/ssa/_gen/ARM64Ops.go @@ -169,9 +169,11 @@ func init() { fp2flags = regInfo{inputs: []regMask{fp, fp}} fp1flags = regInfo{inputs: []regMask{fp}} fpload = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{fp}} + fpload2 = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{fp, fp}} fp2load = regInfo{inputs: []regMask{gpspsbg, gpg}, outputs: []regMask{fp}} fpstore = regInfo{inputs: []regMask{gpspsbg, fp}} - fpstore2 = regInfo{inputs: []regMask{gpspsbg, gpg, fp}} + fpstoreidx = regInfo{inputs: []regMask{gpspsbg, gpg, fp}} + fpstore2 = regInfo{inputs: []regMask{gpspsbg, fp, fp}} readflags = regInfo{inputs: nil, outputs: []regMask{gp}} prefreg = regInfo{inputs: []regMask{gpspsbg}} ) @@ -369,16 +371,26 @@ func init() { {name: "MOVDaddr", argLength: 1, reg: regInfo{inputs: []regMask{buildReg("SP") | buildReg("SB")}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVD", rematerializeable: true, symEffect: "Addr"}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB - {name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. - {name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. - {name: "MOVHload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVH", typ: "Int16", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. - {name: "MOVHUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVHU", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. - {name: "MOVWload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVW", typ: "Int32", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. - {name: "MOVWUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVWU", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. - {name: "MOVDload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVD", typ: "UInt64", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. - {name: "LDP", argLength: 2, reg: gpload2, aux: "SymOff", asm: "LDP", typ: "(UInt64,UInt64)", faultOnNilArg0: true, symEffect: "Read"}, // load from ptr = arg0 + auxInt + aux, returns the tuple <*(*uint64)ptr, *(*uint64)(ptr+8)>. arg1=mem. - {name: "FMOVSload", argLength: 2, reg: fpload, aux: "SymOff", asm: "FMOVS", typ: "Float32", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. - {name: "FMOVDload", argLength: 2, reg: fpload, aux: "SymOff", asm: "FMOVD", typ: "Float64", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. + {name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. + {name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. + {name: "MOVHload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVH", typ: "Int16", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. + {name: "MOVHUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVHU", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. + {name: "MOVWload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVW", typ: "Int32", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. + {name: "MOVWUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVWU", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. + {name: "MOVDload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVD", typ: "UInt64", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. + {name: "FMOVSload", argLength: 2, reg: fpload, aux: "SymOff", asm: "FMOVS", typ: "Float32", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. + {name: "FMOVDload", argLength: 2, reg: fpload, aux: "SymOff", asm: "FMOVD", typ: "Float64", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. + + // LDP instructions load the contents of two adjacent locations in memory into registers. + // Address to start loading is addr = arg0 + auxInt + aux. + // x := *(*T)(addr) + // y := *(*T)(addr+sizeof(T)) + // arg1=mem + // Returns the tuple . + {name: "LDP", argLength: 2, reg: gpload2, aux: "SymOff", asm: "LDP", typ: "(UInt64,UInt64)", faultOnNilArg0: true, symEffect: "Read"}, // T=int64 (gp reg destination) + {name: "LDPW", argLength: 2, reg: gpload2, aux: "SymOff", asm: "LDPW", typ: "(UInt32,UInt32)", faultOnNilArg0: true, symEffect: "Read"}, // T=int32 (gp reg destination) ??? extension + {name: "FLDPD", argLength: 2, reg: fpload2, aux: "SymOff", asm: "FLDPD", typ: "(Float64,Float64)", faultOnNilArg0: true, symEffect: "Read"}, // T=float64 (fp reg destination) + {name: "FLDPS", argLength: 2, reg: fpload2, aux: "SymOff", asm: "FLDPS", typ: "(Float32,Float32)", faultOnNilArg0: true, symEffect: "Read"}, // T=float32 (fp reg destination) // register indexed load {name: "MOVDloadidx", argLength: 3, reg: gp2load, asm: "MOVD", typ: "UInt64"}, // load 64-bit dword from arg0 + arg1, arg2 = mem. @@ -404,24 +416,33 @@ func init() { {name: "MOVHstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 2 bytes of arg1 to arg0 + auxInt + aux. arg2=mem. {name: "MOVWstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVW", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes of arg1 to arg0 + auxInt + aux. arg2=mem. {name: "MOVDstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVD", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of arg1 to arg0 + auxInt + aux. arg2=mem. - {name: "STP", argLength: 4, reg: gpstore2, aux: "SymOff", asm: "STP", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 16 bytes of arg1 and arg2 to arg0 + auxInt + aux. arg3=mem. {name: "FMOVSstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "FMOVS", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes of arg1 to arg0 + auxInt + aux. arg2=mem. {name: "FMOVDstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "FMOVD", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of arg1 to arg0 + auxInt + aux. arg2=mem. + // STP instructions store the contents of two registers to adjacent locations in memory. + // Address to start storing is addr = arg0 + auxInt + aux. + // *(*T)(addr) = arg1 + // *(*T)(addr+sizeof(T)) = arg2 + // arg3=mem. Returns mem. + {name: "STP", argLength: 4, reg: gpstore2, aux: "SymOff", asm: "STP", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // T=int64 (gp reg source) + {name: "STPW", argLength: 4, reg: gpstore2, aux: "SymOff", asm: "STPW", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // T=int32 (gp reg source) + {name: "FSTPD", argLength: 4, reg: fpstore2, aux: "SymOff", asm: "FSTPD", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // T=float64 (fp reg source) + {name: "FSTPS", argLength: 4, reg: fpstore2, aux: "SymOff", asm: "FSTPS", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // T=float32 (fp reg source) + // register indexed store - {name: "MOVBstoreidx", argLength: 4, reg: gpstore2, asm: "MOVB", typ: "Mem"}, // store 1 byte of arg2 to arg0 + arg1, arg3 = mem. - {name: "MOVHstoreidx", argLength: 4, reg: gpstore2, asm: "MOVH", typ: "Mem"}, // store 2 bytes of arg2 to arg0 + arg1, arg3 = mem. - {name: "MOVWstoreidx", argLength: 4, reg: gpstore2, asm: "MOVW", typ: "Mem"}, // store 4 bytes of arg2 to arg0 + arg1, arg3 = mem. - {name: "MOVDstoreidx", argLength: 4, reg: gpstore2, asm: "MOVD", typ: "Mem"}, // store 8 bytes of arg2 to arg0 + arg1, arg3 = mem. - {name: "FMOVSstoreidx", argLength: 4, reg: fpstore2, asm: "FMOVS", typ: "Mem"}, // store 32-bit float of arg2 to arg0 + arg1, arg3=mem. - {name: "FMOVDstoreidx", argLength: 4, reg: fpstore2, asm: "FMOVD", typ: "Mem"}, // store 64-bit float of arg2 to arg0 + arg1, arg3=mem. + {name: "MOVBstoreidx", argLength: 4, reg: gpstore2, asm: "MOVB", typ: "Mem"}, // store 1 byte of arg2 to arg0 + arg1, arg3 = mem. + {name: "MOVHstoreidx", argLength: 4, reg: gpstore2, asm: "MOVH", typ: "Mem"}, // store 2 bytes of arg2 to arg0 + arg1, arg3 = mem. + {name: "MOVWstoreidx", argLength: 4, reg: gpstore2, asm: "MOVW", typ: "Mem"}, // store 4 bytes of arg2 to arg0 + arg1, arg3 = mem. + {name: "MOVDstoreidx", argLength: 4, reg: gpstore2, asm: "MOVD", typ: "Mem"}, // store 8 bytes of arg2 to arg0 + arg1, arg3 = mem. + {name: "FMOVSstoreidx", argLength: 4, reg: fpstoreidx, asm: "FMOVS", typ: "Mem"}, // store 32-bit float of arg2 to arg0 + arg1, arg3=mem. + {name: "FMOVDstoreidx", argLength: 4, reg: fpstoreidx, asm: "FMOVD", typ: "Mem"}, // store 64-bit float of arg2 to arg0 + arg1, arg3=mem. // shifted register indexed store - {name: "MOVHstoreidx2", argLength: 4, reg: gpstore2, asm: "MOVH", typ: "Mem"}, // store 2 bytes of arg2 to arg0 + arg1*2, arg3 = mem. - {name: "MOVWstoreidx4", argLength: 4, reg: gpstore2, asm: "MOVW", typ: "Mem"}, // store 4 bytes of arg2 to arg0 + arg1*4, arg3 = mem. - {name: "MOVDstoreidx8", argLength: 4, reg: gpstore2, asm: "MOVD", typ: "Mem"}, // store 8 bytes of arg2 to arg0 + arg1*8, arg3 = mem. - {name: "FMOVSstoreidx4", argLength: 4, reg: fpstore2, asm: "FMOVS", typ: "Mem"}, // store 32-bit float of arg2 to arg0 + arg1*4, arg3=mem. - {name: "FMOVDstoreidx8", argLength: 4, reg: fpstore2, asm: "FMOVD", typ: "Mem"}, // store 64-bit float of arg2 to arg0 + arg1*8, arg3=mem. + {name: "MOVHstoreidx2", argLength: 4, reg: gpstore2, asm: "MOVH", typ: "Mem"}, // store 2 bytes of arg2 to arg0 + arg1*2, arg3 = mem. + {name: "MOVWstoreidx4", argLength: 4, reg: gpstore2, asm: "MOVW", typ: "Mem"}, // store 4 bytes of arg2 to arg0 + arg1*4, arg3 = mem. + {name: "MOVDstoreidx8", argLength: 4, reg: gpstore2, asm: "MOVD", typ: "Mem"}, // store 8 bytes of arg2 to arg0 + arg1*8, arg3 = mem. + {name: "FMOVSstoreidx4", argLength: 4, reg: fpstoreidx, asm: "FMOVS", typ: "Mem"}, // store 32-bit float of arg2 to arg0 + arg1*4, arg3=mem. + {name: "FMOVDstoreidx8", argLength: 4, reg: fpstoreidx, asm: "FMOVD", typ: "Mem"}, // store 64-bit float of arg2 to arg0 + arg1*8, arg3=mem. {name: "MOVBstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 1 byte of zero to arg0 + auxInt + aux. arg1=mem. {name: "MOVHstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 2 bytes of zero to arg0 + auxInt + aux. arg1=mem. diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index f4f648c53b5fa6..19a748eb08f548 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -1603,9 +1603,12 @@ const ( OpARM64MOVWload OpARM64MOVWUload OpARM64MOVDload - OpARM64LDP OpARM64FMOVSload OpARM64FMOVDload + OpARM64LDP + OpARM64LDPW + OpARM64FLDPD + OpARM64FLDPS OpARM64MOVDloadidx OpARM64MOVWloadidx OpARM64MOVWUloadidx @@ -1626,9 +1629,12 @@ const ( OpARM64MOVHstore OpARM64MOVWstore OpARM64MOVDstore - OpARM64STP OpARM64FMOVSstore OpARM64FMOVDstore + OpARM64STP + OpARM64STPW + OpARM64FSTPD + OpARM64FSTPS OpARM64MOVBstoreidx OpARM64MOVHstoreidx OpARM64MOVWstoreidx @@ -21592,6 +21598,38 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "FMOVSload", + auxType: auxSymOff, + argLen: 2, + faultOnNilArg0: true, + symEffect: SymRead, + asm: arm64.AFMOVS, + reg: regInfo{ + inputs: []inputInfo{ + {0, 9223372038733561855}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB + }, + outputs: []outputInfo{ + {0, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + }, + }, + }, + { + name: "FMOVDload", + auxType: auxSymOff, + argLen: 2, + faultOnNilArg0: true, + symEffect: SymRead, + asm: arm64.AFMOVD, + reg: regInfo{ + inputs: []inputInfo{ + {0, 9223372038733561855}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB + }, + outputs: []outputInfo{ + {0, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + }, + }, + }, { name: "LDP", auxType: auxSymOff, @@ -21610,34 +21648,53 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "FMOVSload", + name: "LDPW", auxType: auxSymOff, argLen: 2, faultOnNilArg0: true, symEffect: SymRead, - asm: arm64.AFMOVS, + asm: arm64.ALDPW, + reg: regInfo{ + inputs: []inputInfo{ + {0, 9223372038733561855}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB + }, + outputs: []outputInfo{ + {0, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 + {1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 + }, + }, + }, + { + name: "FLDPD", + auxType: auxSymOff, + argLen: 2, + faultOnNilArg0: true, + symEffect: SymRead, + asm: arm64.AFLDPD, reg: regInfo{ inputs: []inputInfo{ {0, 9223372038733561855}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB }, outputs: []outputInfo{ {0, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + {1, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 }, }, }, { - name: "FMOVDload", + name: "FLDPS", auxType: auxSymOff, argLen: 2, faultOnNilArg0: true, symEffect: SymRead, - asm: arm64.AFMOVD, + asm: arm64.AFLDPS, reg: regInfo{ inputs: []inputInfo{ {0, 9223372038733561855}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB }, outputs: []outputInfo{ {0, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + {1, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 }, }, }, @@ -21921,6 +21978,34 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "FMOVSstore", + auxType: auxSymOff, + argLen: 3, + faultOnNilArg0: true, + symEffect: SymWrite, + asm: arm64.AFMOVS, + reg: regInfo{ + inputs: []inputInfo{ + {0, 9223372038733561855}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB + {1, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + }, + }, + }, + { + name: "FMOVDstore", + auxType: auxSymOff, + argLen: 3, + faultOnNilArg0: true, + symEffect: SymWrite, + asm: arm64.AFMOVD, + reg: regInfo{ + inputs: []inputInfo{ + {0, 9223372038733561855}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB + {1, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + }, + }, + }, { name: "STP", auxType: auxSymOff, @@ -21937,30 +22022,47 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "FMOVSstore", + name: "STPW", auxType: auxSymOff, - argLen: 3, + argLen: 4, faultOnNilArg0: true, symEffect: SymWrite, - asm: arm64.AFMOVS, + asm: arm64.ASTPW, + reg: regInfo{ + inputs: []inputInfo{ + {1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 + {2, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 + {0, 9223372038733561855}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB + }, + }, + }, + { + name: "FSTPD", + auxType: auxSymOff, + argLen: 4, + faultOnNilArg0: true, + symEffect: SymWrite, + asm: arm64.AFSTPD, reg: regInfo{ inputs: []inputInfo{ {0, 9223372038733561855}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB {1, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + {2, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 }, }, }, { - name: "FMOVDstore", + name: "FSTPS", auxType: auxSymOff, - argLen: 3, + argLen: 4, faultOnNilArg0: true, symEffect: SymWrite, - asm: arm64.AFMOVD, + asm: arm64.AFSTPS, reg: regInfo{ inputs: []inputInfo{ {0, 9223372038733561855}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB {1, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + {2, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 }, }, }, From 20d7c57422143d07f5ef85d674687dbc0a4871ce Mon Sep 17 00:00:00 2001 From: "khr@golang.org" Date: Sun, 17 Nov 2024 12:07:34 -0800 Subject: [PATCH 364/397] cmd/compile: pair loads and stores on arm64 Look for possible paired load/store operations on arm64. I don't expect this would be a lot faster, but it will save binary space, and indirectly through the icache at least a bit of time. Change-Id: I4dd73b0e6329c4659b7453998f9b75320fcf380b Reviewed-on: https://go-review.googlesource.com/c/go/+/629256 LUCI-TryBot-Result: Go LUCI Reviewed-by: David Chase Auto-Submit: Keith Randall Reviewed-by: Keith Randall --- src/cmd/compile/internal/ssa/compile.go | 1 + src/cmd/compile/internal/ssa/pair.go | 357 ++++++++++++++++++++++++ test/codegen/memcombine.go | 94 +++++++ test/tighten.go | 16 +- 4 files changed, 463 insertions(+), 5 deletions(-) create mode 100644 src/cmd/compile/internal/ssa/pair.go diff --git a/src/cmd/compile/internal/ssa/compile.go b/src/cmd/compile/internal/ssa/compile.go index 3f46599a3e5756..634a6f68642e71 100644 --- a/src/cmd/compile/internal/ssa/compile.go +++ b/src/cmd/compile/internal/ssa/compile.go @@ -488,6 +488,7 @@ var passes = [...]pass{ {name: "lower", fn: lower, required: true}, {name: "addressing modes", fn: addressingModes, required: false}, {name: "late lower", fn: lateLower, required: true}, + {name: "pair", fn: pair}, {name: "lowered deadcode for cse", fn: deadcode}, // deadcode immediately before CSE avoids CSE making dead values live again {name: "lowered cse", fn: cse}, {name: "elim unread autos", fn: elimUnreadAutos}, diff --git a/src/cmd/compile/internal/ssa/pair.go b/src/cmd/compile/internal/ssa/pair.go new file mode 100644 index 00000000000000..5af9b0cb1b6d66 --- /dev/null +++ b/src/cmd/compile/internal/ssa/pair.go @@ -0,0 +1,357 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssa + +import ( + "cmd/compile/internal/ir" + "cmd/compile/internal/types" + "slices" +) + +// The pair pass finds memory operations that can be paired up +// into single 2-register memory instructions. +func pair(f *Func) { + // Only arm64 for now. This pass is fairly arch-specific. + switch f.Config.arch { + case "arm64": + default: + return + } + pairLoads(f) + pairStores(f) +} + +type pairableLoadInfo struct { + width int64 // width of one element in the pair, in bytes + pair Op +} + +// All pairableLoad ops must take 2 arguments, a pointer and a memory. +// They must also take an offset in Aux/AuxInt. +var pairableLoads = map[Op]pairableLoadInfo{ + OpARM64MOVDload: {8, OpARM64LDP}, + OpARM64MOVWload: {4, OpARM64LDPW}, + OpARM64FMOVDload: {8, OpARM64FLDPD}, + OpARM64FMOVSload: {4, OpARM64FLDPS}, +} + +type pairableStoreInfo struct { + width int64 // width of one element in the pair, in bytes + pair Op +} + +// All pairableStore keys must take 3 arguments, a pointer, a value, and a memory. +// All pairableStore values must take 4 arguments, a pointer, 2 values, and a memory. +// They must also take an offset in Aux/AuxInt. +var pairableStores = map[Op]pairableStoreInfo{ + OpARM64MOVDstore: {8, OpARM64STP}, + OpARM64MOVWstore: {4, OpARM64STPW}, + OpARM64FMOVDstore: {8, OpARM64FSTPD}, + OpARM64FMOVSstore: {4, OpARM64FSTPS}, + // TODO: storezero variants. +} + +// offsetOk returns true if a pair instruction should be used +// for the offset Aux+off, when the data width (of the +// unpaired instructions) is width. +// This function is best-effort. The compiled function must +// still work if offsetOk always returns true. +// TODO: this is currently arm64-specific. +func offsetOk(aux Aux, off, width int64) bool { + if true { + // Seems to generate slightly smaller code if we just + // always allow this rewrite. + // + // Without pairing, we have 2 load instructions, like: + // LDR 88(R0), R1 + // LDR 96(R0), R2 + // with pairing we have, best case: + // LDP 88(R0), R1, R2 + // but maybe we need an adjuster if out of range or unaligned: + // ADD R0, $88, R27 + // LDP (R27), R1, R2 + // Even with the adjuster, it is at least no worse. + // + // A similar situation occurs when accessing globals. + // Two loads from globals requires 4 instructions, + // two ADRP and two LDR. With pairing, we need + // ADRP+ADD+LDP, three instructions. + // + // With pairing, it looks like the critical path might + // be a little bit longer. But it should never be more + // instructions. + // TODO: see if that longer critical path causes any + // regressions. + return true + } + if aux != nil { + if _, ok := aux.(*ir.Name); !ok { + // Offset is probably too big (globals). + return false + } + // We let *ir.Names pass here, as + // they are probably small offsets from SP. + // There's no guarantee that we're in range + // in that case though (we don't know the + // stack frame size yet), so the assembler + // might need to issue fixup instructions. + // Assume some small frame size. + if off >= 0 { + off += 120 + } + // TODO: figure out how often this helps vs. hurts. + } + switch width { + case 4: + if off >= -256 && off <= 252 && off%4 == 0 { + return true + } + case 8: + if off >= -512 && off <= 504 && off%8 == 0 { + return true + } + } + return false +} + +func pairLoads(f *Func) { + var loads []*Value + + // Registry of aux values for sorting. + auxIDs := map[Aux]int{} + auxID := func(aux Aux) int { + id, ok := auxIDs[aux] + if !ok { + id = len(auxIDs) + auxIDs[aux] = id + } + return id + } + + for _, b := range f.Blocks { + // Find loads. + loads = loads[:0] + clear(auxIDs) + for _, v := range b.Values { + info := pairableLoads[v.Op] + if info.width == 0 { + continue // not pairable + } + if !offsetOk(v.Aux, v.AuxInt, info.width) { + continue // not advisable + } + loads = append(loads, v) + } + if len(loads) < 2 { + continue + } + + // Sort to put pairable loads together. + slices.SortFunc(loads, func(x, y *Value) int { + // First sort by op, ptr, and memory arg. + if x.Op != y.Op { + return int(x.Op - y.Op) + } + if x.Args[0].ID != y.Args[0].ID { + return int(x.Args[0].ID - y.Args[0].ID) + } + if x.Args[1].ID != y.Args[1].ID { + return int(x.Args[1].ID - y.Args[1].ID) + } + // Then sort by aux. (nil first, then by aux ID) + if x.Aux != nil { + if y.Aux == nil { + return 1 + } + a, b := auxID(x.Aux), auxID(y.Aux) + if a != b { + return a - b + } + } else if y.Aux != nil { + return -1 + } + // Then sort by offset, low to high. + return int(x.AuxInt - y.AuxInt) + }) + + // Look for pairable loads. + for i := 0; i < len(loads)-1; i++ { + x := loads[i] + y := loads[i+1] + if x.Op != y.Op || x.Args[0] != y.Args[0] || x.Args[1] != y.Args[1] { + continue + } + if x.Aux != y.Aux { + continue + } + if x.AuxInt+pairableLoads[x.Op].width != y.AuxInt { + continue + } + + // Commit point. + + // Make the 2-register load. + load := b.NewValue2IA(x.Pos, pairableLoads[x.Op].pair, types.NewTuple(x.Type, y.Type), x.AuxInt, x.Aux, x.Args[0], x.Args[1]) + + // Modify x to be (Select0 load). Similar for y. + x.reset(OpSelect0) + x.SetArgs1(load) + y.reset(OpSelect1) + y.SetArgs1(load) + + i++ // Skip y next time around the loop. + } + } +} + +func pairStores(f *Func) { + last := f.Cache.allocBoolSlice(f.NumValues()) + defer f.Cache.freeBoolSlice(last) + + // prevStore returns the previous store in the + // same block, or nil if there are none. + prevStore := func(v *Value) *Value { + if v.Op == OpInitMem || v.Op == OpPhi { + return nil + } + m := v.MemoryArg() + if m.Block != v.Block { + return nil + } + return m + } + + for _, b := range f.Blocks { + // Find last store in block, so we can + // walk the stores last to first. + // Last to first helps ensure that the rewrites we + // perform do not get in the way of subsequent rewrites. + for _, v := range b.Values { + if v.Type.IsMemory() { + last[v.ID] = true + } + } + for _, v := range b.Values { + if v.Type.IsMemory() { + if m := prevStore(v); m != nil { + last[m.ID] = false + } + } + } + var lastMem *Value + for _, v := range b.Values { + if last[v.ID] { + lastMem = v + break + } + } + + // Check all stores, from last to first. + memCheck: + for v := lastMem; v != nil; v = prevStore(v) { + info := pairableStores[v.Op] + if info.width == 0 { + continue // Not pairable. + } + if !offsetOk(v.Aux, v.AuxInt, info.width) { + continue // Not advisable to pair. + } + ptr := v.Args[0] + val := v.Args[1] + mem := v.Args[2] + off := v.AuxInt + aux := v.Aux + + // Look for earlier store we can combine with. + lowerOk := true + higherOk := true + count := 10 // max lookback distance + for w := prevStore(v); w != nil; w = prevStore(w) { + if w.Uses != 1 { + // We can't combine stores if the earlier + // store has any use besides the next one + // in the store chain. + // (Unless we could check the aliasing of + // all those other uses.) + continue memCheck + } + if w.Op == v.Op && + w.Args[0] == ptr && + w.Aux == aux && + (lowerOk && w.AuxInt == off-info.width || higherOk && w.AuxInt == off+info.width) { + // This op is mergeable with v. + + // Commit point. + + // ptr val1 val2 mem + args := []*Value{ptr, val, w.Args[1], mem} + if w.AuxInt == off-info.width { + args[1], args[2] = args[2], args[1] + off -= info.width + } + v.reset(info.pair) + v.AddArgs(args...) + v.Aux = aux + v.AuxInt = off + v.Pos = w.Pos // take position of earlier of the two stores (TODO: not really working?) + + // Make w just a memory copy. + wmem := w.MemoryArg() + w.reset(OpCopy) + w.SetArgs1(wmem) + continue memCheck + } + if count--; count == 0 { + // Only look back so far. + // This keeps us in O(n) territory, and it + // also prevents us from keeping values + // in registers for too long (and thus + // needing to spill them). + continue memCheck + } + // We're now looking at a store w which is currently + // between the store v that we're intending to merge into, + // and the store we'll eventually find to merge with it. + // Make sure this store doesn't alias with the one + // we'll be moving. + var width int64 + switch w.Op { + case OpARM64MOVDstore, OpARM64MOVDstorezero, OpARM64FMOVDstore: + width = 8 + case OpARM64MOVWstore, OpARM64MOVWstorezero, OpARM64FMOVSstore: + width = 4 + case OpARM64MOVHstore, OpARM64MOVHstorezero: + width = 2 + case OpARM64MOVBstore, OpARM64MOVBstorezero: + width = 1 + case OpCopy: + continue // this was a store we merged earlier + default: + // Can't reorder with any other memory operations. + // (atomics, calls, ...) + continue memCheck + } + + // We only allow reordering with respect to other + // writes to the same pointer and aux, so we can + // compute the exact the aliasing relationship. + if w.Args[0] != ptr || w.Aux != aux { + continue memCheck + } + if overlap(w.AuxInt, width, off-info.width, info.width) { + // Aliases with slot before v's location. + lowerOk = false + } + if overlap(w.AuxInt, width, off+info.width, info.width) { + // Aliases with slot after v's location. + higherOk = false + } + if !higherOk && !lowerOk { + continue memCheck + } + } + } + } +} diff --git a/test/codegen/memcombine.go b/test/codegen/memcombine.go index e1cae0e46983e6..2a9cc68ab0e441 100644 --- a/test/codegen/memcombine.go +++ b/test/codegen/memcombine.go @@ -899,9 +899,11 @@ func store32le(p *struct{ a, b uint32 }, x uint64) { p.b = uint32(x >> 32) } func store32be(p *struct{ a, b uint32 }, x uint64) { + // arm64:"STPW" // ppc64:"MOVD",-"MOVW",-"SRD" // s390x:"MOVD",-"MOVW",-"SRD" p.a = uint32(x >> 32) + // arm64:-"STPW" // ppc64:-"MOVW",-"SRD" // s390x:-"MOVW",-"SRD" p.b = uint32(x) @@ -970,3 +972,95 @@ func issue70300Reverse(v uint64) (b [8]byte) { b[0] = byte(v) return b } + +// --------------------------------- // +// Arm64 double-register loads // +// --------------------------------- // + +func dwloadI64(p *struct{ a, b int64 }) int64 { + // arm64:"LDP\t" + return p.a + p.b +} +func dwloadI32(p *struct{ a, b int32 }) int32 { + // arm64:"LDPW\t" + return p.a + p.b +} +func dwloadF64(p *struct{ a, b float64 }) float64 { + // arm64:"FLDPD\t" + return p.a + p.b +} +func dwloadF32(p *struct{ a, b float32 }) float32 { + // arm64:"FLDPS\t" + return p.a + p.b +} + +func dwloadBig(p *struct{ a, b, c, d, e, f int64 }) int64 { + // arm64:"LDP\t\\(", "LDP\t16", "LDP\t32" + return p.c + p.f + p.a + p.e + p.d + p.b +} + +func dwloadArg(a [2]int64) int64 { + // arm64:"LDP\t" + return a[0] + a[1] +} + +// ---------------------------------- // +// Arm64 double-register stores // +// ---------------------------------- // + +func dwstoreI64(p *struct{ a, b int64 }, x, y int64) { + // arm64:"STP\t" + p.a = x + p.b = y +} +func dwstoreI32(p *struct{ a, b int32 }, x, y int32) { + // arm64:"STPW\t" + p.a = x + p.b = y +} +func dwstoreF64(p *struct{ a, b float64 }, x, y float64) { + // arm64:"FSTPD\t" + p.a = x + p.b = y +} +func dwstoreF32(p *struct{ a, b float32 }, x, y float32) { + // arm64:"FSTPS\t" + p.a = x + p.b = y +} + +func dwstoreBig(p *struct{ a, b, c, d, e, f int64 }, a, b, c, d, e, f int64) { + // This is not perfect. We merge b+a, then d+e, then c and f have no pair. + p.c = c + p.f = f + // arm64:`STP\s\(R[0-9]+, R[0-9]+\), \(R[0-9]+\)` + p.a = a + // arm64:`STP\s\(R[0-9]+, R[0-9]+\), 24\(R[0-9]+\)` + p.e = e + p.d = d + p.b = b +} + +func dwstoreRet() [2]int { + // arm64:"STP\t" + return [2]int{5, 6} +} + +func dwstoreLocal(i int) int64 { + var a [2]int64 + a[0] = 5 + // arm64:"STP\t" + a[1] = 6 + return a[i] +} + +func dwstoreOrder(p *struct { + a, b int64 + c, d, e, f bool +}, a, b int64) { + // arm64:"STP\t" + p.a = a + p.c = true + p.e = true + p.b = b +} diff --git a/test/tighten.go b/test/tighten.go index 92ed2492b26e74..d85dfecbb0237e 100644 --- a/test/tighten.go +++ b/test/tighten.go @@ -9,14 +9,20 @@ package main var ( - e any - ts uint16 + ga, gb, gc, gd int ) func moveValuesWithMemoryArg(len int) { for n := 0; n < len; n++ { - // Load of e.data is lowed as a MOVDload op, which has a memory - // argument. It's moved near where it's used. - _ = e != ts // ERROR "MOVDload is moved$" "MOVDaddr is moved$" + // Loads of b and d can be delayed until inside the outer "if". + a := ga + b := gb // ERROR "MOVDload is moved$" + c := gc + d := gd // ERROR "MOVDload is moved$" + if a == c { + if b == d { + return + } + } } } From a0029e95e5d6f15cab70e533d447c75aa4211636 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Sat, 23 Nov 2024 10:58:47 -0800 Subject: [PATCH 365/397] cmd/compile: regalloc: handle desired registers of 2-output insns Particularly with 2-word load instructions, this becomes important. Classic example is: func f(p *string) string { return *p } We want the two loads to put the return values directly into the two ABI return registers. At this point in the stack, cmd/go is 1.1% smaller. Change-Id: I51fd1710238e81d15aab2bfb816d73c8e7c207b1 Reviewed-on: https://go-review.googlesource.com/c/go/+/631137 Reviewed-by: David Chase Reviewed-by: Keith Randall LUCI-TryBot-Result: Go LUCI --- src/cmd/compile/internal/ssa/regalloc.go | 21 ++++++++++++++++++++- test/codegen/memcombine.go | 10 ++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go index 08ce0d16a63bba..1b7bcb2b1d4c8f 100644 --- a/src/cmd/compile/internal/ssa/regalloc.go +++ b/src/cmd/compile/internal/ssa/regalloc.go @@ -930,6 +930,7 @@ func (s *regAllocState) regalloc(f *Func) { // Data structure used for computing desired registers. var desired desiredState + desiredSecondReg := map[ID][4]register{} // desired register allocation for 2nd part of a tuple // Desired registers for inputs & outputs for each instruction in the block. type dentry struct { @@ -949,6 +950,7 @@ func (s *regAllocState) regalloc(f *Func) { s.curBlock = b s.startRegsMask = 0 s.usedSinceBlockStart = 0 + clear(desiredSecondReg) // Initialize regValLiveSet and uses fields for this block. // Walk backwards through the block doing liveness analysis. @@ -1346,6 +1348,11 @@ func (s *regAllocState) regalloc(f *Func) { } dinfo[i].in[j] = desired.get(a.ID) } + if v.Op == OpSelect1 && prefs[0] != noRegister { + // Save desired registers of select1 for + // use by the tuple generating instruction. + desiredSecondReg[v.Args[0].ID] = prefs + } } // Process all the non-phi values. @@ -1748,6 +1755,17 @@ func (s *regAllocState) regalloc(f *Func) { } } } + if out.idx == 1 { + if prefs, ok := desiredSecondReg[v.ID]; ok { + for _, r := range prefs { + if r != noRegister && (mask&^s.used)>>r&1 != 0 { + // Desired register is allowed and unused. + mask = regMask(1) << r + break + } + } + } + } // Avoid registers we're saving for other values. if mask&^desired.avoid&^s.nospill&^s.used != 0 { mask &^= desired.avoid @@ -2874,7 +2892,8 @@ type desiredStateEntry struct { // Registers it would like to be in, in priority order. // Unused slots are filled with noRegister. // For opcodes that return tuples, we track desired registers only - // for the first element of the tuple. + // for the first element of the tuple (see desiredSecondReg for + // tracking the desired register for second part of a tuple). regs [4]register } diff --git a/test/codegen/memcombine.go b/test/codegen/memcombine.go index 2a9cc68ab0e441..9345391b61928f 100644 --- a/test/codegen/memcombine.go +++ b/test/codegen/memcombine.go @@ -1004,6 +1004,16 @@ func dwloadArg(a [2]int64) int64 { return a[0] + a[1] } +func dwloadResult1(p *string) string { + // arm64:"LDP\t\\(R0\\), \\(R0, R1\\)" + return *p +} + +func dwloadResult2(p *[2]int64) (int64, int64) { + // arm64:"LDP\t\\(R0\\), \\(R1, R0\\)" + return p[1], p[0] +} + // ---------------------------------- // // Arm64 double-register stores // // ---------------------------------- // From 187fd2698d2f9fc2fc52aa7d4c0922552f848e98 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Sat, 23 Nov 2024 17:35:02 -0800 Subject: [PATCH 366/397] cmd/compile: make write barrier code amenable to paired loads/stores It currently isn't because it does load/store/load/store/... Rework to do overwrite processing in pairs so it is instead load/load/store/store/... Change-Id: If7be629bc4048da5f2386dafb8f05759b79e9e2b Reviewed-on: https://go-review.googlesource.com/c/go/+/631495 Reviewed-by: David Chase Reviewed-by: Keith Randall LUCI-TryBot-Result: Go LUCI --- src/cmd/compile/internal/ssa/writebarrier.go | 49 ++++++++++++++------ test/codegen/writebarrier.go | 13 ++++++ 2 files changed, 47 insertions(+), 15 deletions(-) diff --git a/src/cmd/compile/internal/ssa/writebarrier.go b/src/cmd/compile/internal/ssa/writebarrier.go index 71acefbf8ae526..bf04f1b5c228d5 100644 --- a/src/cmd/compile/internal/ssa/writebarrier.go +++ b/src/cmd/compile/internal/ssa/writebarrier.go @@ -376,21 +376,6 @@ func writebarrier(f *Func) { // For each write barrier store, append write barrier code to bThen. memThen := mem - var curCall *Value - var curPtr *Value - addEntry := func(pos src.XPos, v *Value) { - if curCall == nil || curCall.AuxInt == maxEntries { - t := types.NewTuple(types.Types[types.TUINTPTR].PtrTo(), types.TypeMem) - curCall = bThen.NewValue1(pos, OpWB, t, memThen) - curPtr = bThen.NewValue1(pos, OpSelect0, types.Types[types.TUINTPTR].PtrTo(), curCall) - memThen = bThen.NewValue1(pos, OpSelect1, types.TypeMem, curCall) - } - // Store value in write buffer - num := curCall.AuxInt - curCall.AuxInt = num + 1 - wbuf := bThen.NewValue1I(pos, OpOffPtr, types.Types[types.TUINTPTR].PtrTo(), num*f.Config.PtrSize, curPtr) - memThen = bThen.NewValue3A(pos, OpStore, types.TypeMem, types.Types[types.TUINTPTR], wbuf, v, memThen) - } // Note: we can issue the write barrier code in any order. In particular, // it doesn't matter if they are in a different order *even if* they end @@ -410,6 +395,38 @@ func writebarrier(f *Func) { dsts := sset2 dsts.clear() + // Buffer up entries that we need to put in the write barrier buffer. + type write struct { + ptr *Value // value to put in write barrier buffer + pos src.XPos // location to use for the write + } + var writeStore [maxEntries]write + writes := writeStore[:0] + + flush := func() { + if len(writes) == 0 { + return + } + // Issue a call to get a write barrier buffer. + t := types.NewTuple(types.Types[types.TUINTPTR].PtrTo(), types.TypeMem) + call := bThen.NewValue1I(pos, OpWB, t, int64(len(writes)), memThen) + curPtr := bThen.NewValue1(pos, OpSelect0, types.Types[types.TUINTPTR].PtrTo(), call) + memThen = bThen.NewValue1(pos, OpSelect1, types.TypeMem, call) + // Write each pending pointer to a slot in the buffer. + for i, write := range writes { + wbuf := bThen.NewValue1I(write.pos, OpOffPtr, types.Types[types.TUINTPTR].PtrTo(), int64(i)*f.Config.PtrSize, curPtr) + memThen = bThen.NewValue3A(write.pos, OpStore, types.TypeMem, types.Types[types.TUINTPTR], wbuf, write.ptr, memThen) + } + writes = writes[:0] + } + addEntry := func(pos src.XPos, ptr *Value) { + writes = append(writes, write{ptr: ptr, pos: pos}) + if len(writes) == maxEntries { + flush() + } + } + + // Find all the pointers we need to write to the buffer. for _, w := range stores { if w.Op != OpStoreWB { continue @@ -437,7 +454,9 @@ func writebarrier(f *Func) { f.fe.Func().SetWBPos(pos) nWBops-- } + flush() + // Now do the rare cases, Zeros and Moves. for _, w := range stores { pos := w.Pos switch w.Op { diff --git a/test/codegen/writebarrier.go b/test/codegen/writebarrier.go index e2b1399399b020..c3c39c58f7901c 100644 --- a/test/codegen/writebarrier.go +++ b/test/codegen/writebarrier.go @@ -88,3 +88,16 @@ func issue71228(dst *S, ptr *int) { //amd64:`.*runtime[.]wbMove` *dst = *sp } + +func writeDouble(p *[2]*int, x, y *int) { + // arm64: `LDP\s`, `STP\s\(R[0-9]+, R[0-9]+\), \(`, + p[0] = x + // arm64: `STP\s\(R[0-9]+, R[0-9]+\), 16\(`, + p[1] = y +} + +func writeDoubleNil(p *[2]*int) { + // arm64: `LDP\s`, `STP\s\(R[0-9]+, R[0-9]+\),`, `STP\s\(ZR, ZR\),` + p[0] = nil + p[1] = nil +} From 807a51b391c8a8d949d6fa00c26953ba0f8ae267 Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Mon, 10 Feb 2025 15:35:17 -0800 Subject: [PATCH 367/397] os: add Root.Chown For #67002 Change-Id: I546537618cbe32217fa72264d49db2b1a1d3b6db Reviewed-on: https://go-review.googlesource.com/c/go/+/648295 LUCI-TryBot-Result: Go LUCI Auto-Submit: Damien Neil Reviewed-by: Ian Lance Taylor --- api/next/67002.txt | 1 + doc/next/6-stdlib/99-minor/os/67002.md | 1 + src/internal/syscall/unix/asm_darwin.s | 1 + src/internal/syscall/unix/asm_openbsd.s | 2 + src/internal/syscall/unix/at.go | 18 ++++ src/internal/syscall/unix/at_aix.go | 1 + src/internal/syscall/unix/at_darwin.go | 22 +++++ src/internal/syscall/unix/at_libc.go | 22 ++++- src/internal/syscall/unix/at_openbsd.go | 22 +++++ src/internal/syscall/unix/at_solaris.go | 1 + .../syscall/unix/at_sysnum_dragonfly.go | 1 + .../syscall/unix/at_sysnum_freebsd.go | 1 + src/internal/syscall/unix/at_sysnum_linux.go | 1 + src/internal/syscall/unix/at_sysnum_netbsd.go | 1 + src/internal/syscall/unix/at_wasip1.go | 5 ++ src/os/root.go | 6 ++ src/os/root_noopenat.go | 10 +++ src/os/root_openat.go | 10 +++ src/os/root_unix.go | 8 ++ src/os/root_unix_test.go | 87 +++++++++++++++++++ src/os/root_windows.go | 4 + 21 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 src/os/root_unix_test.go diff --git a/api/next/67002.txt b/api/next/67002.txt index 06119c0e754589..216d3a3afeb606 100644 --- a/api/next/67002.txt +++ b/api/next/67002.txt @@ -1 +1,2 @@ pkg os, method (*Root) Chmod(string, fs.FileMode) error #67002 +pkg os, method (*Root) Chown(string, int, int) error #67002 diff --git a/doc/next/6-stdlib/99-minor/os/67002.md b/doc/next/6-stdlib/99-minor/os/67002.md index a0751c30e2fec3..04ff6d5de0fec0 100644 --- a/doc/next/6-stdlib/99-minor/os/67002.md +++ b/doc/next/6-stdlib/99-minor/os/67002.md @@ -1,3 +1,4 @@ The [os.Root] type supports the following additional methods: * [os.Root.Chmod] + * [os.Root.Chown] diff --git a/src/internal/syscall/unix/asm_darwin.s b/src/internal/syscall/unix/asm_darwin.s index de6e01ee4a4fe3..0f28cd1e393bc7 100644 --- a/src/internal/syscall/unix/asm_darwin.s +++ b/src/internal/syscall/unix/asm_darwin.s @@ -26,3 +26,4 @@ TEXT ·libc_faccessat_trampoline(SB),NOSPLIT,$0-0; JMP libc_faccessat(SB) TEXT ·libc_readlinkat_trampoline(SB),NOSPLIT,$0-0; JMP libc_readlinkat(SB) TEXT ·libc_mkdirat_trampoline(SB),NOSPLIT,$0-0; JMP libc_mkdirat(SB) TEXT ·libc_fchmodat_trampoline(SB),NOSPLIT,$0-0; JMP libc_fchmodat(SB) +TEXT ·libc_fchownat_trampoline(SB),NOSPLIT,$0-0; JMP libc_fchownat(SB) diff --git a/src/internal/syscall/unix/asm_openbsd.s b/src/internal/syscall/unix/asm_openbsd.s index 306ef4664d57d8..b804a52714c3b4 100644 --- a/src/internal/syscall/unix/asm_openbsd.s +++ b/src/internal/syscall/unix/asm_openbsd.s @@ -16,3 +16,5 @@ TEXT ·libc_mkdirat_trampoline(SB),NOSPLIT,$0-0 JMP libc_mkdirat(SB) TEXT ·libc_fchmodat_trampoline(SB),NOSPLIT,$0-0 JMP libc_fchmodat(SB) +TEXT ·libc_fchownat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_fchownat(SB) diff --git a/src/internal/syscall/unix/at.go b/src/internal/syscall/unix/at.go index 2a29dd6a5a3ac7..794f8ace14f20d 100644 --- a/src/internal/syscall/unix/at.go +++ b/src/internal/syscall/unix/at.go @@ -96,3 +96,21 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) error { } return nil } + +func Fchownat(dirfd int, path string, uid, gid int, flags int) error { + p, err := syscall.BytePtrFromString(path) + if err != nil { + return err + } + _, _, errno := syscall.Syscall6(fchownatTrap, + uintptr(dirfd), + uintptr(unsafe.Pointer(p)), + uintptr(uid), + uintptr(gid), + uintptr(flags), + 0) + if errno != 0 { + return errno + } + return nil +} diff --git a/src/internal/syscall/unix/at_aix.go b/src/internal/syscall/unix/at_aix.go index e679efc34459d8..aa188cdb76f6bf 100644 --- a/src/internal/syscall/unix/at_aix.go +++ b/src/internal/syscall/unix/at_aix.go @@ -5,6 +5,7 @@ package unix //go:cgo_import_dynamic libc_fchmodat fchmodat "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_fchownat fchownat "libc.a/shr_64.o" //go:cgo_import_dynamic libc_fstatat fstatat "libc.a/shr_64.o" //go:cgo_import_dynamic libc_openat openat "libc.a/shr_64.o" //go:cgo_import_dynamic libc_unlinkat unlinkat "libc.a/shr_64.o" diff --git a/src/internal/syscall/unix/at_darwin.go b/src/internal/syscall/unix/at_darwin.go index 759b0943f558c3..75d7b455691859 100644 --- a/src/internal/syscall/unix/at_darwin.go +++ b/src/internal/syscall/unix/at_darwin.go @@ -80,3 +80,25 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) error { } return nil } + +func libc_fchownat_trampoline() + +//go:cgo_import_dynamic libc_fchownat fchownat "/usr/lib/libSystem.B.dylib" + +func Fchownat(dirfd int, path string, uid, gid int, flags int) error { + p, err := syscall.BytePtrFromString(path) + if err != nil { + return err + } + _, _, errno := syscall_syscall6(abi.FuncPCABI0(libc_fchownat_trampoline), + uintptr(dirfd), + uintptr(unsafe.Pointer(p)), + uintptr(uid), + uintptr(gid), + uintptr(flags), + 0) + if errno != 0 { + return errno + } + return nil +} diff --git a/src/internal/syscall/unix/at_libc.go b/src/internal/syscall/unix/at_libc.go index f88e09d31db417..137e0e093651ed 100644 --- a/src/internal/syscall/unix/at_libc.go +++ b/src/internal/syscall/unix/at_libc.go @@ -17,6 +17,7 @@ import ( //go:linkname procReadlinkat libc_readlinkat //go:linkname procMkdirat libc_mkdirat //go:linkname procFchmodat libc_fchmodat +//go:linkname procFchownat libc_chownat var ( procFstatat, @@ -24,7 +25,8 @@ var ( procUnlinkat, procReadlinkat, procMkdirat, - procFchmodat uintptr + procFchmodat, + procFchownat uintptr ) func Unlinkat(dirfd int, path string, flags int) error { @@ -126,3 +128,21 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) error { } return nil } + +func Fchownat(dirfd int, path string, uid, gid int, flags int) error { + p, err := syscall.BytePtrFromString(path) + if err != nil { + return err + } + _, _, errno := syscall6(uintptr(unsafe.Pointer(&procFchownat)), 4, + uintptr(dirfd), + uintptr(unsafe.Pointer(p)), + uintptr(uid), + uintptr(gid), + uintptr(flags), + 0) + if errno != 0 { + return errno + } + return nil +} diff --git a/src/internal/syscall/unix/at_openbsd.go b/src/internal/syscall/unix/at_openbsd.go index 26ca70322b7f15..771cb063e0cf40 100644 --- a/src/internal/syscall/unix/at_openbsd.go +++ b/src/internal/syscall/unix/at_openbsd.go @@ -71,3 +71,25 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) error { } return nil } + +//go:cgo_import_dynamic libc_fchownat fchownat "libc.so" + +func libc_fchownat_trampoline() + +func Fchownat(dirfd int, path string, uid, gid int, flags int) error { + p, err := syscall.BytePtrFromString(path) + if err != nil { + return err + } + _, _, errno := syscall_syscall6(abi.FuncPCABI0(libc_fchmodat_trampoline), + uintptr(dirfd), + uintptr(unsafe.Pointer(p)), + uintptr(uid), + uintptr(gid), + uintptr(flags), + 0) + if errno != 0 { + return errno + } + return nil +} diff --git a/src/internal/syscall/unix/at_solaris.go b/src/internal/syscall/unix/at_solaris.go index a4910f1003aaae..f84e8e35daa11c 100644 --- a/src/internal/syscall/unix/at_solaris.go +++ b/src/internal/syscall/unix/at_solaris.go @@ -14,6 +14,7 @@ func rawSyscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, e //go:cgo_import_dynamic libc_faccessat faccessat "libc.so" //go:cgo_import_dynamic libc_fchmodat fchmodat "libc.so" +//go:cgo_import_dynamic libc_fchownat fchownat "libc.so" //go:cgo_import_dynamic libc_fstatat fstatat "libc.so" //go:cgo_import_dynamic libc_openat openat "libc.so" //go:cgo_import_dynamic libc_unlinkat unlinkat "libc.so" diff --git a/src/internal/syscall/unix/at_sysnum_dragonfly.go b/src/internal/syscall/unix/at_sysnum_dragonfly.go index 84c60c47b8ac5c..1e89e97f388077 100644 --- a/src/internal/syscall/unix/at_sysnum_dragonfly.go +++ b/src/internal/syscall/unix/at_sysnum_dragonfly.go @@ -13,6 +13,7 @@ const ( readlinkatTrap uintptr = syscall.SYS_READLINKAT mkdiratTrap uintptr = syscall.SYS_MKDIRAT fchmodatTrap uintptr = syscall.SYS_FCHMODAT + fchownatTrap uintptr = syscall.SYS_FCHOWNAT AT_EACCESS = 0x4 AT_FDCWD = 0xfffafdcd diff --git a/src/internal/syscall/unix/at_sysnum_freebsd.go b/src/internal/syscall/unix/at_sysnum_freebsd.go index 22ff4e7e895c58..59a8c2ce5a21c1 100644 --- a/src/internal/syscall/unix/at_sysnum_freebsd.go +++ b/src/internal/syscall/unix/at_sysnum_freebsd.go @@ -20,4 +20,5 @@ const ( readlinkatTrap uintptr = syscall.SYS_READLINKAT mkdiratTrap uintptr = syscall.SYS_MKDIRAT fchmodatTrap uintptr = syscall.SYS_FCHMODAT + fchownatTrap uintptr = syscall.SYS_FCHOWNAT ) diff --git a/src/internal/syscall/unix/at_sysnum_linux.go b/src/internal/syscall/unix/at_sysnum_linux.go index 8fba319cab7dbd..35cc4307e92f3d 100644 --- a/src/internal/syscall/unix/at_sysnum_linux.go +++ b/src/internal/syscall/unix/at_sysnum_linux.go @@ -12,6 +12,7 @@ const ( readlinkatTrap uintptr = syscall.SYS_READLINKAT mkdiratTrap uintptr = syscall.SYS_MKDIRAT fchmodatTrap uintptr = syscall.SYS_FCHMODAT + fchownatTrap uintptr = syscall.SYS_FCHOWNAT ) const ( diff --git a/src/internal/syscall/unix/at_sysnum_netbsd.go b/src/internal/syscall/unix/at_sysnum_netbsd.go index f2b7a4f9ebfe8a..bb946b6581d253 100644 --- a/src/internal/syscall/unix/at_sysnum_netbsd.go +++ b/src/internal/syscall/unix/at_sysnum_netbsd.go @@ -13,6 +13,7 @@ const ( readlinkatTrap uintptr = syscall.SYS_READLINKAT mkdiratTrap uintptr = syscall.SYS_MKDIRAT fchmodatTrap uintptr = syscall.SYS_FCHMODAT + fchownatTrap uintptr = syscall.SYS_FCHOWNAT ) const ( diff --git a/src/internal/syscall/unix/at_wasip1.go b/src/internal/syscall/unix/at_wasip1.go index 7289317110f855..3fdc95436c2dc1 100644 --- a/src/internal/syscall/unix/at_wasip1.go +++ b/src/internal/syscall/unix/at_wasip1.go @@ -106,6 +106,11 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) error { return syscall.ENOSYS } +func Fchownat(dirfd int, path string, uid, gid int, flags int) error { + // WASI preview 1 doesn't support changing file ownership. + return syscall.ENOSYS +} + //go:wasmimport wasi_snapshot_preview1 path_create_directory //go:noescape func path_create_directory(fd int32, path *byte, pathLen size) syscall.Errno diff --git a/src/os/root.go b/src/os/root.go index cd26144ab7410f..fd3b603ed83805 100644 --- a/src/os/root.go +++ b/src/os/root.go @@ -151,6 +151,12 @@ func (r *Root) Mkdir(name string, perm FileMode) error { return rootMkdir(r, name, perm) } +// Chown changes the numeric uid and gid of the named file in the root. +// See [Chown] for more details. +func (r *Root) Chown(name string, uid, gid int) error { + return rootChown(r, name, uid, gid) +} + // Remove removes the named file or (empty) directory in the root. // See [Remove] for more details. func (r *Root) Remove(name string) error { diff --git a/src/os/root_noopenat.go b/src/os/root_noopenat.go index 819486f289f397..919e78c777825d 100644 --- a/src/os/root_noopenat.go +++ b/src/os/root_noopenat.go @@ -105,6 +105,16 @@ func rootChmod(r *Root, name string, mode FileMode) error { return nil } +func rootChown(r *Root, name string, uid, gid int) error { + if err := checkPathEscapes(r, name); err != nil { + return &PathError{Op: "chownat", Path: name, Err: err} + } + if err := Chown(joinPath(r.root.name, name), uid, gid); err != nil { + return &PathError{Op: "chownat", Path: name, Err: underlyingError(err)} + } + return nil +} + func rootMkdir(r *Root, name string, perm FileMode) error { if err := checkPathEscapes(r, name); err != nil { return &PathError{Op: "mkdirat", Path: name, Err: err} diff --git a/src/os/root_openat.go b/src/os/root_openat.go index d98d2e36752f4b..65d3eacf4df98b 100644 --- a/src/os/root_openat.go +++ b/src/os/root_openat.go @@ -77,6 +77,16 @@ func rootChmod(r *Root, name string, mode FileMode) error { return nil } +func rootChown(r *Root, name string, uid, gid int) error { + _, err := doInRoot(r, name, func(parent sysfdType, name string) (struct{}, error) { + return struct{}{}, chownat(parent, name, uid, gid) + }) + if err != nil { + return &PathError{Op: "chownat", Path: name, Err: err} + } + return err +} + func rootMkdir(r *Root, name string, perm FileMode) error { _, err := doInRoot(r, name, func(parent sysfdType, name string) (struct{}, error) { return struct{}{}, mkdirat(parent, name, perm) diff --git a/src/os/root_unix.go b/src/os/root_unix.go index 06da8da15ec0d2..76d6b74eb7364b 100644 --- a/src/os/root_unix.go +++ b/src/os/root_unix.go @@ -157,6 +157,14 @@ func chmodat(parent int, name string, mode FileMode) error { }) } +func chownat(parent int, name string, uid, gid int) error { + return afterResolvingSymlink(parent, name, func() error { + return ignoringEINTR(func() error { + return unix.Fchownat(parent, name, uid, gid, unix.AT_SYMLINK_NOFOLLOW) + }) + }) +} + func mkdirat(fd int, name string, perm FileMode) error { return ignoringEINTR(func() error { return unix.Mkdirat(fd, name, syscallMode(perm)) diff --git a/src/os/root_unix_test.go b/src/os/root_unix_test.go new file mode 100644 index 00000000000000..280efc68751ed3 --- /dev/null +++ b/src/os/root_unix_test.go @@ -0,0 +1,87 @@ +// Copyright 2025 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. + +//go:build unix || (js && wasm) || wasip1 + +package os_test + +import ( + "fmt" + "os" + "runtime" + "syscall" + "testing" +) + +func TestRootChown(t *testing.T) { + if runtime.GOOS == "wasip1" { + t.Skip("Chown not supported on " + runtime.GOOS) + } + + // Look up the current default uid/gid. + f := newFile(t) + dir, err := f.Stat() + if err != nil { + t.Fatal(err) + } + sys := dir.Sys().(*syscall.Stat_t) + + groups, err := os.Getgroups() + if err != nil { + t.Fatalf("getgroups: %v", err) + } + groups = append(groups, os.Getgid()) + for _, test := range rootTestCases { + test.run(t, func(t *testing.T, target string, root *os.Root) { + if target != "" { + if err := os.WriteFile(target, nil, 0o666); err != nil { + t.Fatal(err) + } + } + for _, gid := range groups { + err := root.Chown(test.open, -1, gid) + if errEndsTest(t, err, test.wantError, "root.Chown(%q, -1, %v)", test.open, gid) { + return + } + checkUidGid(t, target, int(sys.Uid), gid) + } + }) + } +} + +func TestRootConsistencyChown(t *testing.T) { + if runtime.GOOS == "wasip1" { + t.Skip("Chown not supported on " + runtime.GOOS) + } + groups, err := os.Getgroups() + if err != nil { + t.Fatalf("getgroups: %v", err) + } + var gid int + if len(groups) == 0 { + gid = os.Getgid() + } else { + gid = groups[0] + } + for _, test := range rootConsistencyTestCases { + test.run(t, func(t *testing.T, path string, r *os.Root) (string, error) { + chown := os.Chown + lstat := os.Lstat + if r != nil { + chown = r.Chown + lstat = r.Lstat + } + err := chown(path, -1, gid) + if err != nil { + return "", err + } + fi, err := lstat(path) + if err != nil { + return "", err + } + sys := fi.Sys().(*syscall.Stat_t) + return fmt.Sprintf("%v %v", sys.Uid, sys.Gid), nil + }) + } +} diff --git a/src/os/root_windows.go b/src/os/root_windows.go index 9b57d5648e6956..4f391cb2a7d9fd 100644 --- a/src/os/root_windows.go +++ b/src/os/root_windows.go @@ -276,6 +276,10 @@ func chmodat(parent syscall.Handle, name string, mode FileMode) error { return windows.SetFileInformationByHandle(h, windows.FileBasicInfo, unsafe.Pointer(&fbi), uint32(unsafe.Sizeof(fbi))) } +func chownat(parent syscall.Handle, name string, uid, gid int) error { + return syscall.EWINDOWS // matches syscall.Chown +} + func mkdirat(dirfd syscall.Handle, name string, perm FileMode) error { return windows.Mkdirat(dirfd, name, syscallMode(perm)) } From 5ff7a634e19a3e8e8a24bbdb948de19695234943 Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Thu, 13 Feb 2025 14:38:09 -0800 Subject: [PATCH 368/397] net/http, net/http/internal/httpcommon: add httpcommon package The golang.org/x/net/internal/httpcommon package is a new package containing internal functions common to the HTTP/2 and HTTP/3 implementations. Update to golang.org/x/net@v0.35.1-0.20250213222735-884432780bfd, which includes the httpcommon package. Since net/http can't depend on a x/net/internal package, add net/http/internal/httpcommon which bundles the x/net package. Change-Id: Iba6c4be7b3e2d9a9d79c4b5153497b0e04b4497b Reviewed-on: https://go-review.googlesource.com/c/go/+/649296 Reviewed-by: Dmitri Shuralyov Auto-Submit: Damien Neil LUCI-TryBot-Result: Go LUCI Reviewed-by: Dmitri Shuralyov --- src/go.mod | 2 +- src/go.sum | 4 +- src/go/build/deps_test.go | 1 + src/net/http/h2_bundle.go | 453 ++------------- src/net/http/http.go | 2 +- src/net/http/http_test.go | 4 +- .../http/internal/httpcommon/httpcommon.go | 532 ++++++++++++++++++ src/vendor/modules.txt | 2 +- 8 files changed, 574 insertions(+), 426 deletions(-) create mode 100644 src/net/http/internal/httpcommon/httpcommon.go diff --git a/src/go.mod b/src/go.mod index 4ccf4ff79eed2f..c0bbca7e29bcc4 100644 --- a/src/go.mod +++ b/src/go.mod @@ -4,7 +4,7 @@ go 1.25 require ( golang.org/x/crypto v0.33.1-0.20250210163342-e47973b1c108 - golang.org/x/net v0.34.1-0.20250123000230-c72e89d6a9e4 + golang.org/x/net v0.35.1-0.20250213222735-884432780bfd ) require ( diff --git a/src/go.sum b/src/go.sum index 50dec70ed6e6f2..61223c0bbb6ee0 100644 --- a/src/go.sum +++ b/src/go.sum @@ -1,7 +1,7 @@ golang.org/x/crypto v0.33.1-0.20250210163342-e47973b1c108 h1:FwaGHNRX5GDt6vHr+Ly+yRTs0ADe4xTlGOzwaga4ZOs= golang.org/x/crypto v0.33.1-0.20250210163342-e47973b1c108/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= -golang.org/x/net v0.34.1-0.20250123000230-c72e89d6a9e4 h1:guLo+MhruvDNVBe2ssFzu5BGn4pc0G1xx6TqTHK+MnE= -golang.org/x/net v0.34.1-0.20250123000230-c72e89d6a9e4/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= +golang.org/x/net v0.35.1-0.20250213222735-884432780bfd h1:NtufTkm/X6BNpniJAbESf1Mvax5jGy+/oP53IEn5RiA= +golang.org/x/net v0.35.1-0.20250213222735-884432780bfd/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index 29773486dd8176..580500c033e1fc 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -614,6 +614,7 @@ var depsRules = ` net/http/httptrace, mime/multipart, log + < net/http/internal/httpcommon < net/http; # HTTP-aware packages diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go index 81a8c4bc4dedbf..9933c413ac84d4 100644 --- a/src/net/http/h2_bundle.go +++ b/src/net/http/h2_bundle.go @@ -1,7 +1,7 @@ //go:build !nethttpomithttp2 // Code generated by golang.org/x/tools/cmd/bundle. DO NOT EDIT. -// $ bundle -o=h2_bundle.go -prefix=http2 -tags=!nethttpomithttp2 golang.org/x/net/http2 +// $ bundle -o=h2_bundle.go -prefix=http2 -tags=!nethttpomithttp2 -import=golang.org/x/net/internal/httpcommon=net/http/internal/httpcommon golang.org/x/net/http2 // Package http2 implements the HTTP/2 protocol. // @@ -40,6 +40,7 @@ import ( mathrand "math/rand" "net" "net/http/httptrace" + "net/http/internal/httpcommon" "net/textproto" "net/url" "os" @@ -3413,101 +3414,6 @@ func http2cutoff64(base int) uint64 { return (1<<64-1)/uint64(base) + 1 } -var ( - http2commonBuildOnce sync.Once - http2commonLowerHeader map[string]string // Go-Canonical-Case -> lower-case - http2commonCanonHeader map[string]string // lower-case -> Go-Canonical-Case -) - -func http2buildCommonHeaderMapsOnce() { - http2commonBuildOnce.Do(http2buildCommonHeaderMaps) -} - -func http2buildCommonHeaderMaps() { - common := []string{ - "accept", - "accept-charset", - "accept-encoding", - "accept-language", - "accept-ranges", - "age", - "access-control-allow-credentials", - "access-control-allow-headers", - "access-control-allow-methods", - "access-control-allow-origin", - "access-control-expose-headers", - "access-control-max-age", - "access-control-request-headers", - "access-control-request-method", - "allow", - "authorization", - "cache-control", - "content-disposition", - "content-encoding", - "content-language", - "content-length", - "content-location", - "content-range", - "content-type", - "cookie", - "date", - "etag", - "expect", - "expires", - "from", - "host", - "if-match", - "if-modified-since", - "if-none-match", - "if-unmodified-since", - "last-modified", - "link", - "location", - "max-forwards", - "origin", - "proxy-authenticate", - "proxy-authorization", - "range", - "referer", - "refresh", - "retry-after", - "server", - "set-cookie", - "strict-transport-security", - "trailer", - "transfer-encoding", - "user-agent", - "vary", - "via", - "www-authenticate", - "x-forwarded-for", - "x-forwarded-proto", - } - http2commonLowerHeader = make(map[string]string, len(common)) - http2commonCanonHeader = make(map[string]string, len(common)) - for _, v := range common { - chk := CanonicalHeaderKey(v) - http2commonLowerHeader[chk] = v - http2commonCanonHeader[v] = chk - } -} - -func http2lowerHeader(v string) (lower string, ascii bool) { - http2buildCommonHeaderMapsOnce() - if s, ok := http2commonLowerHeader[v]; ok { - return s, true - } - return http2asciiToLower(v) -} - -func http2canonicalHeader(v string) string { - http2buildCommonHeaderMapsOnce() - if s, ok := http2commonCanonHeader[v]; ok { - return s - } - return CanonicalHeaderKey(v) -} - var ( http2VerboseLogs bool http2logFrameWrites bool @@ -3894,23 +3800,6 @@ func (s *http2sorter) SortStrings(ss []string) { s.v = save } -// validPseudoPath reports whether v is a valid :path pseudo-header -// value. It must be either: -// -// - a non-empty string starting with '/' -// - the string '*', for OPTIONS requests. -// -// For now this is only used a quick check for deciding when to clean -// up Opaque URLs before sending requests from the Transport. -// See golang.org/issue/16847 -// -// We used to enforce that the path also didn't start with "//", but -// Google's GFE accepts such paths and Chrome sends them, so ignore -// that part of the spec. See golang.org/issue/19103. -func http2validPseudoPath(v string) bool { - return (len(v) > 0 && v[0] == '/') || v == "*" -} - // incomparable is a zero-width, non-comparable type. Adding it to a struct // makes that struct also non-comparable, and generally doesn't add // any size (as long as it's first). @@ -4863,8 +4752,7 @@ const http2maxCachedCanonicalHeadersKeysSize = 2048 func (sc *http2serverConn) canonicalHeader(v string) string { sc.serveG.check() - http2buildCommonHeaderMapsOnce() - cv, ok := http2commonCanonHeader[v] + cv, ok := httpcommon.CachedCanonicalHeader(v) if ok { return cv } @@ -8698,23 +8586,6 @@ func (cc *http2ClientConn) closeForLostPing() { // exported. At least they'll be DeepEqual for h1-vs-h2 comparisons tests. var http2errRequestCanceled = errors.New("net/http: request canceled") -func http2commaSeparatedTrailers(req *Request) (string, error) { - keys := make([]string, 0, len(req.Trailer)) - for k := range req.Trailer { - k = http2canonicalHeader(k) - switch k { - case "Transfer-Encoding", "Trailer", "Content-Length": - return "", fmt.Errorf("invalid Trailer key %q", k) - } - keys = append(keys, k) - } - if len(keys) > 0 { - sort.Strings(keys) - return strings.Join(keys, ","), nil - } - return "", nil -} - func (cc *http2ClientConn) responseHeaderTimeout() time.Duration { if cc.t.t1 != nil { return cc.t.t1.ResponseHeaderTimeout @@ -8726,22 +8597,6 @@ func (cc *http2ClientConn) responseHeaderTimeout() time.Duration { return 0 } -// checkConnHeaders checks whether req has any invalid connection-level headers. -// per RFC 7540 section 8.1.2.2: Connection-Specific Header Fields. -// Certain headers are special-cased as okay but not transmitted later. -func http2checkConnHeaders(req *Request) error { - if v := req.Header.Get("Upgrade"); v != "" { - return fmt.Errorf("http2: invalid Upgrade request header: %q", req.Header["Upgrade"]) - } - if vv := req.Header["Transfer-Encoding"]; len(vv) > 0 && (len(vv) > 1 || vv[0] != "" && vv[0] != "chunked") { - return fmt.Errorf("http2: invalid Transfer-Encoding request header: %q", vv) - } - if vv := req.Header["Connection"]; len(vv) > 0 && (len(vv) > 1 || vv[0] != "" && !http2asciiEqualFold(vv[0], "close") && !http2asciiEqualFold(vv[0], "keep-alive")) { - return fmt.Errorf("http2: invalid Connection request header: %q", vv) - } - return nil -} - // actualContentLength returns a sanitized version of // req.ContentLength, where 0 actually means zero (not unknown) and -1 // means unknown. @@ -8787,25 +8642,7 @@ func (cc *http2ClientConn) roundTrip(req *Request, streamf func(*http2clientStre donec: make(chan struct{}), } - // TODO(bradfitz): this is a copy of the logic in net/http. Unify somewhere? - if !cc.t.disableCompression() && - req.Header.Get("Accept-Encoding") == "" && - req.Header.Get("Range") == "" && - !cs.isHead { - // Request gzip only, not deflate. Deflate is ambiguous and - // not as universally supported anyway. - // See: https://zlib.net/zlib_faq.html#faq39 - // - // Note that we don't request this for HEAD requests, - // due to a bug in nginx: - // http://trac.nginx.org/nginx/ticket/358 - // https://golang.org/issue/5522 - // - // We don't request gzip if the request is for a range, since - // auto-decoding a portion of a gzipped document will just fail - // anyway. See https://golang.org/issue/8923 - cs.requestedGzip = true - } + cs.requestedGzip = httpcommon.IsRequestGzip(req.Method, req.Header, cc.t.disableCompression()) go cs.doRequest(req, streamf) @@ -8919,10 +8756,6 @@ func (cs *http2clientStream) writeRequest(req *Request, streamf func(*http2clien cc := cs.cc ctx := cs.ctx - if err := http2checkConnHeaders(req); err != nil { - return err - } - // wait for setting frames to be received, a server can change this value later, // but we just wait for the first settings frame var isExtendedConnect bool @@ -9086,26 +8919,39 @@ func (cs *http2clientStream) encodeAndWriteHeaders(req *Request) error { // we send: HEADERS{1}, CONTINUATION{0,} + DATA{0,} (DATA is // sent by writeRequestBody below, along with any Trailers, // again in form HEADERS{1}, CONTINUATION{0,}) - trailers, err := http2commaSeparatedTrailers(req) - if err != nil { - return err - } - hasTrailers := trailers != "" - contentLen := http2actualContentLength(req) - hasBody := contentLen != 0 - hdrs, err := cc.encodeHeaders(req, cs.requestedGzip, trailers, contentLen) + cc.hbuf.Reset() + res, err := http2encodeRequestHeaders(req, cs.requestedGzip, cc.peerMaxHeaderListSize, func(name, value string) { + cc.writeHeader(name, value) + }) if err != nil { - return err + return fmt.Errorf("http2: %w", err) } + hdrs := cc.hbuf.Bytes() // Write the request. - endStream := !hasBody && !hasTrailers + endStream := !res.HasBody && !res.HasTrailers cs.sentHeaders = true err = cc.writeHeaders(cs.ID, endStream, int(cc.maxFrameSize), hdrs) http2traceWroteHeaders(cs.trace) return err } +func http2encodeRequestHeaders(req *Request, addGzipHeader bool, peerMaxHeaderListSize uint64, headerf func(name, value string)) (httpcommon.EncodeHeadersResult, error) { + return httpcommon.EncodeHeaders(req.Context(), httpcommon.EncodeHeadersParam{ + Request: httpcommon.Request{ + Header: req.Header, + Trailer: req.Trailer, + URL: req.URL, + Host: req.Host, + Method: req.Method, + ActualContentLength: http2actualContentLength(req), + }, + AddGzipHeader: addGzipHeader, + PeerMaxHeaderListSize: peerMaxHeaderListSize, + DefaultUserAgent: http2defaultUserAgent, + }, headerf) +} + // cleanupWriteRequest performs post-request tasks. // // If err (the result of writeRequest) is non-nil and the stream is not closed, @@ -9494,229 +9340,6 @@ func (cs *http2clientStream) awaitFlowControl(maxBytes int) (taken int32, err er } } -func http2validateHeaders(hdrs Header) string { - for k, vv := range hdrs { - if !httpguts.ValidHeaderFieldName(k) && k != ":protocol" { - return fmt.Sprintf("name %q", k) - } - for _, v := range vv { - if !httpguts.ValidHeaderFieldValue(v) { - // Don't include the value in the error, - // because it may be sensitive. - return fmt.Sprintf("value for header %q", k) - } - } - } - return "" -} - -var http2errNilRequestURL = errors.New("http2: Request.URI is nil") - -// requires cc.wmu be held. -func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trailers string, contentLength int64) ([]byte, error) { - cc.hbuf.Reset() - if req.URL == nil { - return nil, http2errNilRequestURL - } - - host := req.Host - if host == "" { - host = req.URL.Host - } - host, err := httpguts.PunycodeHostPort(host) - if err != nil { - return nil, err - } - if !httpguts.ValidHostHeader(host) { - return nil, errors.New("http2: invalid Host header") - } - - // isNormalConnect is true if this is a non-extended CONNECT request. - isNormalConnect := false - protocol := req.Header.Get(":protocol") - if req.Method == "CONNECT" && protocol == "" { - isNormalConnect = true - } else if protocol != "" && req.Method != "CONNECT" { - return nil, errors.New("http2: invalid :protocol header in non-CONNECT request") - } - - var path string - if !isNormalConnect { - path = req.URL.RequestURI() - if !http2validPseudoPath(path) { - orig := path - path = strings.TrimPrefix(path, req.URL.Scheme+"://"+host) - if !http2validPseudoPath(path) { - if req.URL.Opaque != "" { - return nil, fmt.Errorf("invalid request :path %q from URL.Opaque = %q", orig, req.URL.Opaque) - } else { - return nil, fmt.Errorf("invalid request :path %q", orig) - } - } - } - } - - // Check for any invalid headers+trailers and return an error before we - // potentially pollute our hpack state. (We want to be able to - // continue to reuse the hpack encoder for future requests) - if err := http2validateHeaders(req.Header); err != "" { - return nil, fmt.Errorf("invalid HTTP header %s", err) - } - if err := http2validateHeaders(req.Trailer); err != "" { - return nil, fmt.Errorf("invalid HTTP trailer %s", err) - } - - enumerateHeaders := func(f func(name, value string)) { - // 8.1.2.3 Request Pseudo-Header Fields - // The :path pseudo-header field includes the path and query parts of the - // target URI (the path-absolute production and optionally a '?' character - // followed by the query production, see Sections 3.3 and 3.4 of - // [RFC3986]). - f(":authority", host) - m := req.Method - if m == "" { - m = MethodGet - } - f(":method", m) - if !isNormalConnect { - f(":path", path) - f(":scheme", req.URL.Scheme) - } - if protocol != "" { - f(":protocol", protocol) - } - if trailers != "" { - f("trailer", trailers) - } - - var didUA bool - for k, vv := range req.Header { - if http2asciiEqualFold(k, "host") || http2asciiEqualFold(k, "content-length") { - // Host is :authority, already sent. - // Content-Length is automatic, set below. - continue - } else if http2asciiEqualFold(k, "connection") || - http2asciiEqualFold(k, "proxy-connection") || - http2asciiEqualFold(k, "transfer-encoding") || - http2asciiEqualFold(k, "upgrade") || - http2asciiEqualFold(k, "keep-alive") { - // Per 8.1.2.2 Connection-Specific Header - // Fields, don't send connection-specific - // fields. We have already checked if any - // are error-worthy so just ignore the rest. - continue - } else if http2asciiEqualFold(k, "user-agent") { - // Match Go's http1 behavior: at most one - // User-Agent. If set to nil or empty string, - // then omit it. Otherwise if not mentioned, - // include the default (below). - didUA = true - if len(vv) < 1 { - continue - } - vv = vv[:1] - if vv[0] == "" { - continue - } - } else if http2asciiEqualFold(k, "cookie") { - // Per 8.1.2.5 To allow for better compression efficiency, the - // Cookie header field MAY be split into separate header fields, - // each with one or more cookie-pairs. - for _, v := range vv { - for { - p := strings.IndexByte(v, ';') - if p < 0 { - break - } - f("cookie", v[:p]) - p++ - // strip space after semicolon if any. - for p+1 <= len(v) && v[p] == ' ' { - p++ - } - v = v[p:] - } - if len(v) > 0 { - f("cookie", v) - } - } - continue - } else if k == ":protocol" { - // :protocol pseudo-header was already sent above. - continue - } - - for _, v := range vv { - f(k, v) - } - } - if http2shouldSendReqContentLength(req.Method, contentLength) { - f("content-length", strconv.FormatInt(contentLength, 10)) - } - if addGzipHeader { - f("accept-encoding", "gzip") - } - if !didUA { - f("user-agent", http2defaultUserAgent) - } - } - - // Do a first pass over the headers counting bytes to ensure - // we don't exceed cc.peerMaxHeaderListSize. This is done as a - // separate pass before encoding the headers to prevent - // modifying the hpack state. - hlSize := uint64(0) - enumerateHeaders(func(name, value string) { - hf := hpack.HeaderField{Name: name, Value: value} - hlSize += uint64(hf.Size()) - }) - - if hlSize > cc.peerMaxHeaderListSize { - return nil, http2errRequestHeaderListSize - } - - trace := httptrace.ContextClientTrace(req.Context()) - traceHeaders := http2traceHasWroteHeaderField(trace) - - // Header list size is ok. Write the headers. - enumerateHeaders(func(name, value string) { - name, ascii := http2lowerHeader(name) - if !ascii { - // Skip writing invalid headers. Per RFC 7540, Section 8.1.2, header - // field names have to be ASCII characters (just as in HTTP/1.x). - return - } - cc.writeHeader(name, value) - if traceHeaders { - http2traceWroteHeaderField(trace, name, value) - } - }) - - return cc.hbuf.Bytes(), nil -} - -// shouldSendReqContentLength reports whether the http2.Transport should send -// a "content-length" request header. This logic is basically a copy of the net/http -// transferWriter.shouldSendContentLength. -// The contentLength is the corrected contentLength (so 0 means actually 0, not unknown). -// -1 means unknown. -func http2shouldSendReqContentLength(method string, contentLength int64) bool { - if contentLength > 0 { - return true - } - if contentLength < 0 { - return false - } - // For zero bodies, whether we send a content-length depends on the method. - // It also kinda doesn't matter for http2 either way, with END_STREAM. - switch method { - case "POST", "PUT", "PATCH": - return true - default: - return false - } -} - // requires cc.wmu be held. func (cc *http2ClientConn) encodeTrailers(trailer Header) ([]byte, error) { cc.hbuf.Reset() @@ -9733,7 +9356,7 @@ func (cc *http2ClientConn) encodeTrailers(trailer Header) ([]byte, error) { } for k, vv := range trailer { - lowKey, ascii := http2lowerHeader(k) + lowKey, ascii := httpcommon.LowerHeader(k) if !ascii { // Skip writing invalid headers. Per RFC 7540, Section 8.1.2, header // field names have to be ASCII characters (just as in HTTP/1.x). @@ -10088,7 +9711,7 @@ func (rl *http2clientConnReadLoop) handleResponse(cs *http2clientStream, f *http Status: status + " " + StatusText(statusCode), } for _, hf := range regularFields { - key := http2canonicalHeader(hf.Name) + key := httpcommon.CanonicalHeader(hf.Name) if key == "Trailer" { t := res.Trailer if t == nil { @@ -10096,7 +9719,7 @@ func (rl *http2clientConnReadLoop) handleResponse(cs *http2clientStream, f *http res.Trailer = t } http2foreachHeaderElement(hf.Value, func(v string) { - t[http2canonicalHeader(v)] = nil + t[httpcommon.CanonicalHeader(v)] = nil }) } else { vv := header[key] @@ -10220,7 +9843,7 @@ func (rl *http2clientConnReadLoop) processTrailers(cs *http2clientStream, f *htt trailer := make(Header) for _, hf := range f.RegularFields() { - key := http2canonicalHeader(hf.Name) + key := httpcommon.CanonicalHeader(hf.Name) trailer[key] = append(trailer[key], hf.Value) } cs.trailer = trailer @@ -10766,7 +10389,7 @@ func (cc *http2ClientConn) writeStreamReset(streamID uint32, code http2ErrCode, var ( http2errResponseHeaderListSize = errors.New("http2: response header list larger than advertised limit") - http2errRequestHeaderListSize = errors.New("http2: request header list larger than peer's advertised limit") + http2errRequestHeaderListSize = httpcommon.ErrRequestHeaderListSize ) func (cc *http2ClientConn) logf(format string, args ...interface{}) { @@ -10953,16 +10576,6 @@ func http2traceFirstResponseByte(trace *httptrace.ClientTrace) { } } -func http2traceHasWroteHeaderField(trace *httptrace.ClientTrace) bool { - return trace != nil && trace.WroteHeaderField != nil -} - -func http2traceWroteHeaderField(trace *httptrace.ClientTrace, k, v string) { - if trace != nil && trace.WroteHeaderField != nil { - trace.WroteHeaderField(k, []string{v}) - } -} - func http2traceGot1xxResponseFunc(trace *httptrace.ClientTrace) func(int, textproto.MIMEHeader) error { if trace != nil { return trace.Got1xxResponse @@ -11345,7 +10958,7 @@ func http2encodeHeaders(enc *hpack.Encoder, h Header, keys []string) { } for _, k := range keys { vv := h[k] - k, ascii := http2lowerHeader(k) + k, ascii := httpcommon.LowerHeader(k) if !ascii { // Skip writing invalid headers. Per RFC 7540, Section 8.1.2, header // field names have to be ASCII characters (just as in HTTP/1.x). diff --git a/src/net/http/http.go b/src/net/http/http.go index 32ff7e2008a845..e1e9eea0cefe93 100644 --- a/src/net/http/http.go +++ b/src/net/http/http.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:generate bundle -o=h2_bundle.go -prefix=http2 -tags=!nethttpomithttp2 golang.org/x/net/http2 +//go:generate bundle -o=h2_bundle.go -prefix=http2 -tags=!nethttpomithttp2 -import=golang.org/x/net/internal/httpcommon=net/http/internal/httpcommon golang.org/x/net/http2 package http diff --git a/src/net/http/http_test.go b/src/net/http/http_test.go index 5aba3ed5a6e536..c12bbedac986db 100644 --- a/src/net/http/http_test.go +++ b/src/net/http/http_test.go @@ -164,7 +164,9 @@ func TestNoUnicodeStrings(t *testing.T) { } if !strings.HasSuffix(path, ".go") || strings.HasSuffix(path, "_test.go") || - path == "h2_bundle.go" || d.IsDir() { + path == "h2_bundle.go" || + path == "internal/httpcommon/httpcommon.go" || + d.IsDir() { return nil } diff --git a/src/net/http/internal/httpcommon/httpcommon.go b/src/net/http/internal/httpcommon/httpcommon.go new file mode 100644 index 00000000000000..c9f17785726f98 --- /dev/null +++ b/src/net/http/internal/httpcommon/httpcommon.go @@ -0,0 +1,532 @@ +// Code generated by golang.org/x/tools/cmd/bundle. DO NOT EDIT. +//go:generate bundle -prefix= -o=httpcommon.go golang.org/x/net/internal/httpcommon + +package httpcommon + +import ( + "context" + "errors" + "fmt" + "net/http/httptrace" + "net/textproto" + "net/url" + "sort" + "strconv" + "strings" + "sync" + + "golang.org/x/net/http/httpguts" + "golang.org/x/net/http2/hpack" +) + +// The HTTP protocols are defined in terms of ASCII, not Unicode. This file +// contains helper functions which may use Unicode-aware functions which would +// otherwise be unsafe and could introduce vulnerabilities if used improperly. + +// asciiEqualFold is strings.EqualFold, ASCII only. It reports whether s and t +// are equal, ASCII-case-insensitively. +func asciiEqualFold(s, t string) bool { + if len(s) != len(t) { + return false + } + for i := 0; i < len(s); i++ { + if lower(s[i]) != lower(t[i]) { + return false + } + } + return true +} + +// lower returns the ASCII lowercase version of b. +func lower(b byte) byte { + if 'A' <= b && b <= 'Z' { + return b + ('a' - 'A') + } + return b +} + +// isASCIIPrint returns whether s is ASCII and printable according to +// https://tools.ietf.org/html/rfc20#section-4.2. +func isASCIIPrint(s string) bool { + for i := 0; i < len(s); i++ { + if s[i] < ' ' || s[i] > '~' { + return false + } + } + return true +} + +// asciiToLower returns the lowercase version of s if s is ASCII and printable, +// and whether or not it was. +func asciiToLower(s string) (lower string, ok bool) { + if !isASCIIPrint(s) { + return "", false + } + return strings.ToLower(s), true +} + +var ( + commonBuildOnce sync.Once + commonLowerHeader map[string]string // Go-Canonical-Case -> lower-case + commonCanonHeader map[string]string // lower-case -> Go-Canonical-Case +) + +func buildCommonHeaderMapsOnce() { + commonBuildOnce.Do(buildCommonHeaderMaps) +} + +func buildCommonHeaderMaps() { + common := []string{ + "accept", + "accept-charset", + "accept-encoding", + "accept-language", + "accept-ranges", + "age", + "access-control-allow-credentials", + "access-control-allow-headers", + "access-control-allow-methods", + "access-control-allow-origin", + "access-control-expose-headers", + "access-control-max-age", + "access-control-request-headers", + "access-control-request-method", + "allow", + "authorization", + "cache-control", + "content-disposition", + "content-encoding", + "content-language", + "content-length", + "content-location", + "content-range", + "content-type", + "cookie", + "date", + "etag", + "expect", + "expires", + "from", + "host", + "if-match", + "if-modified-since", + "if-none-match", + "if-unmodified-since", + "last-modified", + "link", + "location", + "max-forwards", + "origin", + "proxy-authenticate", + "proxy-authorization", + "range", + "referer", + "refresh", + "retry-after", + "server", + "set-cookie", + "strict-transport-security", + "trailer", + "transfer-encoding", + "user-agent", + "vary", + "via", + "www-authenticate", + "x-forwarded-for", + "x-forwarded-proto", + } + commonLowerHeader = make(map[string]string, len(common)) + commonCanonHeader = make(map[string]string, len(common)) + for _, v := range common { + chk := textproto.CanonicalMIMEHeaderKey(v) + commonLowerHeader[chk] = v + commonCanonHeader[v] = chk + } +} + +// LowerHeader returns the lowercase form of a header name, +// used on the wire for HTTP/2 and HTTP/3 requests. +func LowerHeader(v string) (lower string, ascii bool) { + buildCommonHeaderMapsOnce() + if s, ok := commonLowerHeader[v]; ok { + return s, true + } + return asciiToLower(v) +} + +// CanonicalHeader canonicalizes a header name. (For example, "host" becomes "Host".) +func CanonicalHeader(v string) string { + buildCommonHeaderMapsOnce() + if s, ok := commonCanonHeader[v]; ok { + return s + } + return textproto.CanonicalMIMEHeaderKey(v) +} + +// CachedCanonicalHeader returns the canonical form of a well-known header name. +func CachedCanonicalHeader(v string) (string, bool) { + buildCommonHeaderMapsOnce() + s, ok := commonCanonHeader[v] + return s, ok +} + +var ( + ErrRequestHeaderListSize = errors.New("request header list larger than peer's advertised limit") +) + +// Request is a subset of http.Request. +// It'd be simpler to pass an *http.Request, of course, but we can't depend on net/http +// without creating a dependency cycle. +type Request struct { + URL *url.URL + Method string + Host string + Header map[string][]string + Trailer map[string][]string + ActualContentLength int64 // 0 means 0, -1 means unknown +} + +// EncodeHeadersParam is parameters to EncodeHeaders. +type EncodeHeadersParam struct { + Request Request + + // AddGzipHeader indicates that an "accept-encoding: gzip" header should be + // added to the request. + AddGzipHeader bool + + // PeerMaxHeaderListSize, when non-zero, is the peer's MAX_HEADER_LIST_SIZE setting. + PeerMaxHeaderListSize uint64 + + // DefaultUserAgent is the User-Agent header to send when the request + // neither contains a User-Agent nor disables it. + DefaultUserAgent string +} + +// EncodeHeadersParam is the result of EncodeHeaders. +type EncodeHeadersResult struct { + HasBody bool + HasTrailers bool +} + +// EncodeHeaders constructs request headers common to HTTP/2 and HTTP/3. +// It validates a request and calls headerf with each pseudo-header and header +// for the request. +// The headerf function is called with the validated, canonicalized header name. +func EncodeHeaders(ctx context.Context, param EncodeHeadersParam, headerf func(name, value string)) (res EncodeHeadersResult, _ error) { + req := param.Request + + // Check for invalid connection-level headers. + if err := checkConnHeaders(req.Header); err != nil { + return res, err + } + + if req.URL == nil { + return res, errors.New("Request.URL is nil") + } + + host := req.Host + if host == "" { + host = req.URL.Host + } + host, err := httpguts.PunycodeHostPort(host) + if err != nil { + return res, err + } + if !httpguts.ValidHostHeader(host) { + return res, errors.New("invalid Host header") + } + + // isNormalConnect is true if this is a non-extended CONNECT request. + isNormalConnect := false + var protocol string + if vv := req.Header[":protocol"]; len(vv) > 0 { + protocol = vv[0] + } + if req.Method == "CONNECT" && protocol == "" { + isNormalConnect = true + } else if protocol != "" && req.Method != "CONNECT" { + return res, errors.New("invalid :protocol header in non-CONNECT request") + } + + // Validate the path, except for non-extended CONNECT requests which have no path. + var path string + if !isNormalConnect { + path = req.URL.RequestURI() + if !validPseudoPath(path) { + orig := path + path = strings.TrimPrefix(path, req.URL.Scheme+"://"+host) + if !validPseudoPath(path) { + if req.URL.Opaque != "" { + return res, fmt.Errorf("invalid request :path %q from URL.Opaque = %q", orig, req.URL.Opaque) + } else { + return res, fmt.Errorf("invalid request :path %q", orig) + } + } + } + } + + // Check for any invalid headers+trailers and return an error before we + // potentially pollute our hpack state. (We want to be able to + // continue to reuse the hpack encoder for future requests) + if err := validateHeaders(req.Header); err != "" { + return res, fmt.Errorf("invalid HTTP header %s", err) + } + if err := validateHeaders(req.Trailer); err != "" { + return res, fmt.Errorf("invalid HTTP trailer %s", err) + } + + trailers, err := commaSeparatedTrailers(req.Trailer) + if err != nil { + return res, err + } + + enumerateHeaders := func(f func(name, value string)) { + // 8.1.2.3 Request Pseudo-Header Fields + // The :path pseudo-header field includes the path and query parts of the + // target URI (the path-absolute production and optionally a '?' character + // followed by the query production, see Sections 3.3 and 3.4 of + // [RFC3986]). + f(":authority", host) + m := req.Method + if m == "" { + m = "GET" + } + f(":method", m) + if !isNormalConnect { + f(":path", path) + f(":scheme", req.URL.Scheme) + } + if protocol != "" { + f(":protocol", protocol) + } + if trailers != "" { + f("trailer", trailers) + } + + var didUA bool + for k, vv := range req.Header { + if asciiEqualFold(k, "host") || asciiEqualFold(k, "content-length") { + // Host is :authority, already sent. + // Content-Length is automatic, set below. + continue + } else if asciiEqualFold(k, "connection") || + asciiEqualFold(k, "proxy-connection") || + asciiEqualFold(k, "transfer-encoding") || + asciiEqualFold(k, "upgrade") || + asciiEqualFold(k, "keep-alive") { + // Per 8.1.2.2 Connection-Specific Header + // Fields, don't send connection-specific + // fields. We have already checked if any + // are error-worthy so just ignore the rest. + continue + } else if asciiEqualFold(k, "user-agent") { + // Match Go's http1 behavior: at most one + // User-Agent. If set to nil or empty string, + // then omit it. Otherwise if not mentioned, + // include the default (below). + didUA = true + if len(vv) < 1 { + continue + } + vv = vv[:1] + if vv[0] == "" { + continue + } + } else if asciiEqualFold(k, "cookie") { + // Per 8.1.2.5 To allow for better compression efficiency, the + // Cookie header field MAY be split into separate header fields, + // each with one or more cookie-pairs. + for _, v := range vv { + for { + p := strings.IndexByte(v, ';') + if p < 0 { + break + } + f("cookie", v[:p]) + p++ + // strip space after semicolon if any. + for p+1 <= len(v) && v[p] == ' ' { + p++ + } + v = v[p:] + } + if len(v) > 0 { + f("cookie", v) + } + } + continue + } else if k == ":protocol" { + // :protocol pseudo-header was already sent above. + continue + } + + for _, v := range vv { + f(k, v) + } + } + if shouldSendReqContentLength(req.Method, req.ActualContentLength) { + f("content-length", strconv.FormatInt(req.ActualContentLength, 10)) + } + if param.AddGzipHeader { + f("accept-encoding", "gzip") + } + if !didUA { + f("user-agent", param.DefaultUserAgent) + } + } + + // Do a first pass over the headers counting bytes to ensure + // we don't exceed cc.peerMaxHeaderListSize. This is done as a + // separate pass before encoding the headers to prevent + // modifying the hpack state. + if param.PeerMaxHeaderListSize > 0 { + hlSize := uint64(0) + enumerateHeaders(func(name, value string) { + hf := hpack.HeaderField{Name: name, Value: value} + hlSize += uint64(hf.Size()) + }) + + if hlSize > param.PeerMaxHeaderListSize { + return res, ErrRequestHeaderListSize + } + } + + trace := httptrace.ContextClientTrace(ctx) + + // Header list size is ok. Write the headers. + enumerateHeaders(func(name, value string) { + name, ascii := LowerHeader(name) + if !ascii { + // Skip writing invalid headers. Per RFC 7540, Section 8.1.2, header + // field names have to be ASCII characters (just as in HTTP/1.x). + return + } + + headerf(name, value) + + if trace != nil && trace.WroteHeaderField != nil { + trace.WroteHeaderField(name, []string{value}) + } + }) + + res.HasBody = req.ActualContentLength != 0 + res.HasTrailers = trailers != "" + return res, nil +} + +// IsRequestGzip reports whether we should add an Accept-Encoding: gzip header +// for a request. +func IsRequestGzip(method string, header map[string][]string, disableCompression bool) bool { + // TODO(bradfitz): this is a copy of the logic in net/http. Unify somewhere? + if !disableCompression && + len(header["Accept-Encoding"]) == 0 && + len(header["Range"]) == 0 && + method != "HEAD" { + // Request gzip only, not deflate. Deflate is ambiguous and + // not as universally supported anyway. + // See: https://zlib.net/zlib_faq.html#faq39 + // + // Note that we don't request this for HEAD requests, + // due to a bug in nginx: + // http://trac.nginx.org/nginx/ticket/358 + // https://golang.org/issue/5522 + // + // We don't request gzip if the request is for a range, since + // auto-decoding a portion of a gzipped document will just fail + // anyway. See https://golang.org/issue/8923 + return true + } + return false +} + +// checkConnHeaders checks whether req has any invalid connection-level headers. +// +// https://www.rfc-editor.org/rfc/rfc9114.html#section-4.2-3 +// https://www.rfc-editor.org/rfc/rfc9113.html#section-8.2.2-1 +// +// Certain headers are special-cased as okay but not transmitted later. +// For example, we allow "Transfer-Encoding: chunked", but drop the header when encoding. +func checkConnHeaders(h map[string][]string) error { + if vv := h["Upgrade"]; len(vv) > 0 && (vv[0] != "" && vv[0] != "chunked") { + return fmt.Errorf("invalid Upgrade request header: %q", vv) + } + if vv := h["Transfer-Encoding"]; len(vv) > 0 && (len(vv) > 1 || vv[0] != "" && vv[0] != "chunked") { + return fmt.Errorf("invalid Transfer-Encoding request header: %q", vv) + } + if vv := h["Connection"]; len(vv) > 0 && (len(vv) > 1 || vv[0] != "" && !asciiEqualFold(vv[0], "close") && !asciiEqualFold(vv[0], "keep-alive")) { + return fmt.Errorf("invalid Connection request header: %q", vv) + } + return nil +} + +func commaSeparatedTrailers(trailer map[string][]string) (string, error) { + keys := make([]string, 0, len(trailer)) + for k := range trailer { + k = CanonicalHeader(k) + switch k { + case "Transfer-Encoding", "Trailer", "Content-Length": + return "", fmt.Errorf("invalid Trailer key %q", k) + } + keys = append(keys, k) + } + if len(keys) > 0 { + sort.Strings(keys) + return strings.Join(keys, ","), nil + } + return "", nil +} + +// validPseudoPath reports whether v is a valid :path pseudo-header +// value. It must be either: +// +// - a non-empty string starting with '/' +// - the string '*', for OPTIONS requests. +// +// For now this is only used a quick check for deciding when to clean +// up Opaque URLs before sending requests from the Transport. +// See golang.org/issue/16847 +// +// We used to enforce that the path also didn't start with "//", but +// Google's GFE accepts such paths and Chrome sends them, so ignore +// that part of the spec. See golang.org/issue/19103. +func validPseudoPath(v string) bool { + return (len(v) > 0 && v[0] == '/') || v == "*" +} + +func validateHeaders(hdrs map[string][]string) string { + for k, vv := range hdrs { + if !httpguts.ValidHeaderFieldName(k) && k != ":protocol" { + return fmt.Sprintf("name %q", k) + } + for _, v := range vv { + if !httpguts.ValidHeaderFieldValue(v) { + // Don't include the value in the error, + // because it may be sensitive. + return fmt.Sprintf("value for header %q", k) + } + } + } + return "" +} + +// shouldSendReqContentLength reports whether we should send +// a "content-length" request header. This logic is basically a copy of the net/http +// transferWriter.shouldSendContentLength. +// The contentLength is the corrected contentLength (so 0 means actually 0, not unknown). +// -1 means unknown. +func shouldSendReqContentLength(method string, contentLength int64) bool { + if contentLength > 0 { + return true + } + if contentLength < 0 { + return false + } + // For zero bodies, whether we send a content-length depends on the method. + // It also kinda doesn't matter for http2 either way, with END_STREAM. + switch method { + case "POST", "PUT", "PATCH": + return true + default: + return false + } +} diff --git a/src/vendor/modules.txt b/src/vendor/modules.txt index 5ffa43e85ef3ea..791a7d8e874bae 100644 --- a/src/vendor/modules.txt +++ b/src/vendor/modules.txt @@ -6,7 +6,7 @@ golang.org/x/crypto/cryptobyte golang.org/x/crypto/cryptobyte/asn1 golang.org/x/crypto/internal/alias golang.org/x/crypto/internal/poly1305 -# golang.org/x/net v0.34.1-0.20250123000230-c72e89d6a9e4 +# golang.org/x/net v0.35.1-0.20250213222735-884432780bfd ## explicit; go 1.18 golang.org/x/net/dns/dnsmessage golang.org/x/net/http/httpguts From 371ee1469cf30ecdbc8d1b55cf307a310ff3d630 Mon Sep 17 00:00:00 2001 From: Meng Zhuo Date: Thu, 12 Sep 2024 20:03:59 +0800 Subject: [PATCH 369/397] cmd/link,cmd/internal: add R_GOT_PCREL_ITYPE_RELOC for riscv64 This CL adds new relocation type for riscv64: R_GOT_PCREL_ITYPE_RELOC which generate an AUIPC + I-type pair with relocation type of GOT_HI20 and PCREL_LO12_I. According to RISCV elf psabi doc, medium position independent code model, the GNU as example is: ``` # Calculate address of non-local symbol .Ltmp3: aupipc a0, %got_pcrel_hi(symbol) ld a0, %pcrel_lo(.Ltmp3)(a0) ``` Change-Id: I719dd05e009ca2d9291f0689b346c059f9c56918 Reviewed-on: https://go-review.googlesource.com/c/go/+/612635 Reviewed-by: Dmitri Shuralyov Reviewed-by: Joel Sing Reviewed-by: Cherry Mui LUCI-TryBot-Result: Go LUCI --- src/cmd/internal/obj/riscv/cpu.go | 5 ++ src/cmd/internal/obj/riscv/obj.go | 9 ++- src/cmd/internal/objabi/reloctype.go | 4 ++ src/cmd/internal/objabi/reloctype_string.go | 61 +++++++++++---------- src/cmd/link/internal/riscv64/asm.go | 19 +++++-- 5 files changed, 62 insertions(+), 36 deletions(-) diff --git a/src/cmd/internal/obj/riscv/cpu.go b/src/cmd/internal/obj/riscv/cpu.go index 69a85166968648..2b75ed38a62611 100644 --- a/src/cmd/internal/obj/riscv/cpu.go +++ b/src/cmd/internal/obj/riscv/cpu.go @@ -317,6 +317,11 @@ const ( // it is the first instruction in an AUIPC + S-type pair that needs a // R_RISCV_PCREL_STYPE relocation. NEED_PCREL_STYPE_RELOC + + // NEED_GOT_PCREL_ITYPE_RELOC is set on AUIPC instructions to indicate that + // it is the first instruction in an AUIPC + I-type pair that needs a + // R_RISCV_GOT_PCREL_ITYPE relocation. + NEED_GOT_PCREL_ITYPE_RELOC ) // RISC-V mnemonics, as defined in the "opcodes" and "opcodes-pseudo" files diff --git a/src/cmd/internal/obj/riscv/obj.go b/src/cmd/internal/obj/riscv/obj.go index 381dc085608644..54c34af2f4a97c 100644 --- a/src/cmd/internal/obj/riscv/obj.go +++ b/src/cmd/internal/obj/riscv/obj.go @@ -215,11 +215,15 @@ func markRelocs(p *obj.Prog) { switch p.From.Name { case obj.NAME_EXTERN, obj.NAME_STATIC: p.Mark |= NEED_PCREL_ITYPE_RELOC + case obj.NAME_GOTREF: + p.Mark |= NEED_GOT_PCREL_ITYPE_RELOC } case p.From.Type == obj.TYPE_MEM && p.To.Type == obj.TYPE_REG: switch p.From.Name { case obj.NAME_EXTERN, obj.NAME_STATIC: p.Mark |= NEED_PCREL_ITYPE_RELOC + case obj.NAME_GOTREF: + p.Mark |= NEED_GOT_PCREL_ITYPE_RELOC } case p.From.Type == obj.TYPE_REG && p.To.Type == obj.TYPE_MEM: switch p.To.Name { @@ -2203,7 +2207,7 @@ func instructionsForMOV(p *obj.Prog) []*instruction { // MOV c(Rs), Rd -> L $c, Rs, Rd inss = instructionsForLoad(p, movToLoad(p.As), addrToReg(p.From)) - case obj.NAME_EXTERN, obj.NAME_STATIC: + case obj.NAME_EXTERN, obj.NAME_STATIC, obj.NAME_GOTREF: if p.From.Sym.Type == objabi.STLSBSS { return instructionsForTLSLoad(p) } @@ -2631,6 +2635,9 @@ func assemble(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { } else if p.Mark&NEED_PCREL_STYPE_RELOC == NEED_PCREL_STYPE_RELOC { rt = objabi.R_RISCV_PCREL_STYPE addr = &p.To + } else if p.Mark&NEED_GOT_PCREL_ITYPE_RELOC == NEED_GOT_PCREL_ITYPE_RELOC { + rt = objabi.R_RISCV_GOT_PCREL_ITYPE + addr = &p.From } else { break } diff --git a/src/cmd/internal/objabi/reloctype.go b/src/cmd/internal/objabi/reloctype.go index 9106b085ea7d02..8e9bee508224b2 100644 --- a/src/cmd/internal/objabi/reloctype.go +++ b/src/cmd/internal/objabi/reloctype.go @@ -291,6 +291,10 @@ const ( // address. R_RISCV_GOT_HI20 + // R_RISCV_GOT_PCREL_ITYPE resolves a 32-bit PC-relative GOT entry + // address for an AUIPC + I-type instruction pair. + R_RISCV_GOT_PCREL_ITYPE + // R_RISCV_PCREL_HI20 resolves the high 20 bits of a 32-bit PC-relative // address. R_RISCV_PCREL_HI20 diff --git a/src/cmd/internal/objabi/reloctype_string.go b/src/cmd/internal/objabi/reloctype_string.go index fd0e401db1e277..2d8a9554eb5c94 100644 --- a/src/cmd/internal/objabi/reloctype_string.go +++ b/src/cmd/internal/objabi/reloctype_string.go @@ -75,39 +75,40 @@ func _() { _ = x[R_RISCV_TLS_IE-65] _ = x[R_RISCV_TLS_LE-66] _ = x[R_RISCV_GOT_HI20-67] - _ = x[R_RISCV_PCREL_HI20-68] - _ = x[R_RISCV_PCREL_LO12_I-69] - _ = x[R_RISCV_PCREL_LO12_S-70] - _ = x[R_RISCV_BRANCH-71] - _ = x[R_RISCV_RVC_BRANCH-72] - _ = x[R_RISCV_RVC_JUMP-73] - _ = x[R_PCRELDBL-74] - _ = x[R_LOONG64_ADDR_HI-75] - _ = x[R_LOONG64_ADDR_LO-76] - _ = x[R_LOONG64_TLS_LE_HI-77] - _ = x[R_LOONG64_TLS_LE_LO-78] - _ = x[R_CALLLOONG64-79] - _ = x[R_LOONG64_TLS_IE_HI-80] - _ = x[R_LOONG64_TLS_IE_LO-81] - _ = x[R_LOONG64_GOT_HI-82] - _ = x[R_LOONG64_GOT_LO-83] - _ = x[R_LOONG64_ADD64-84] - _ = x[R_LOONG64_SUB64-85] - _ = x[R_JMP16LOONG64-86] - _ = x[R_JMP21LOONG64-87] - _ = x[R_JMPLOONG64-88] - _ = x[R_ADDRMIPSU-89] - _ = x[R_ADDRMIPSTLS-90] - _ = x[R_ADDRCUOFF-91] - _ = x[R_WASMIMPORT-92] - _ = x[R_XCOFFREF-93] - _ = x[R_PEIMAGEOFF-94] - _ = x[R_INITORDER-95] + _ = x[R_RISCV_GOT_PCREL_ITYPE-68] + _ = x[R_RISCV_PCREL_HI20-69] + _ = x[R_RISCV_PCREL_LO12_I-70] + _ = x[R_RISCV_PCREL_LO12_S-71] + _ = x[R_RISCV_BRANCH-72] + _ = x[R_RISCV_RVC_BRANCH-73] + _ = x[R_RISCV_RVC_JUMP-74] + _ = x[R_PCRELDBL-75] + _ = x[R_LOONG64_ADDR_HI-76] + _ = x[R_LOONG64_ADDR_LO-77] + _ = x[R_LOONG64_TLS_LE_HI-78] + _ = x[R_LOONG64_TLS_LE_LO-79] + _ = x[R_CALLLOONG64-80] + _ = x[R_LOONG64_TLS_IE_HI-81] + _ = x[R_LOONG64_TLS_IE_LO-82] + _ = x[R_LOONG64_GOT_HI-83] + _ = x[R_LOONG64_GOT_LO-84] + _ = x[R_LOONG64_ADD64-85] + _ = x[R_LOONG64_SUB64-86] + _ = x[R_JMP16LOONG64-87] + _ = x[R_JMP21LOONG64-88] + _ = x[R_JMPLOONG64-89] + _ = x[R_ADDRMIPSU-90] + _ = x[R_ADDRMIPSTLS-91] + _ = x[R_ADDRCUOFF-92] + _ = x[R_WASMIMPORT-93] + _ = x[R_XCOFFREF-94] + _ = x[R_PEIMAGEOFF-95] + _ = x[R_INITORDER-96] } -const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_USEIFACER_USEIFACEMETHODR_USENAMEDMETHODR_METHODOFFR_KEEPR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_DWARFFILEREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_ARM64_GOTR_ARM64_PCRELR_ARM64_PCREL_LDST8R_ARM64_PCREL_LDST16R_ARM64_PCREL_LDST32R_ARM64_PCREL_LDST64R_ARM64_LDST8R_ARM64_LDST16R_ARM64_LDST32R_ARM64_LDST64R_ARM64_LDST128R_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_POWER_TLS_IE_PCREL34R_POWER_TLS_LE_TPREL34R_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_GOT_PCREL34R_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_ADDRPOWER_D34R_ADDRPOWER_PCREL34R_RISCV_JALR_RISCV_JAL_TRAMPR_RISCV_CALLR_RISCV_PCREL_ITYPER_RISCV_PCREL_STYPER_RISCV_TLS_IER_RISCV_TLS_LER_RISCV_GOT_HI20R_RISCV_PCREL_HI20R_RISCV_PCREL_LO12_IR_RISCV_PCREL_LO12_SR_RISCV_BRANCHR_RISCV_RVC_BRANCHR_RISCV_RVC_JUMPR_PCRELDBLR_LOONG64_ADDR_HIR_LOONG64_ADDR_LOR_LOONG64_TLS_LE_HIR_LOONG64_TLS_LE_LOR_CALLLOONG64R_LOONG64_TLS_IE_HIR_LOONG64_TLS_IE_LOR_LOONG64_GOT_HIR_LOONG64_GOT_LOR_LOONG64_ADD64R_LOONG64_SUB64R_JMP16LOONG64R_JMP21LOONG64R_JMPLOONG64R_ADDRMIPSUR_ADDRMIPSTLSR_ADDRCUOFFR_WASMIMPORTR_XCOFFREFR_PEIMAGEOFFR_INITORDER" +const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_USEIFACER_USEIFACEMETHODR_USENAMEDMETHODR_METHODOFFR_KEEPR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_DWARFFILEREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_ARM64_GOTR_ARM64_PCRELR_ARM64_PCREL_LDST8R_ARM64_PCREL_LDST16R_ARM64_PCREL_LDST32R_ARM64_PCREL_LDST64R_ARM64_LDST8R_ARM64_LDST16R_ARM64_LDST32R_ARM64_LDST64R_ARM64_LDST128R_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_POWER_TLS_IE_PCREL34R_POWER_TLS_LE_TPREL34R_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_GOT_PCREL34R_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_ADDRPOWER_D34R_ADDRPOWER_PCREL34R_RISCV_JALR_RISCV_JAL_TRAMPR_RISCV_CALLR_RISCV_PCREL_ITYPER_RISCV_PCREL_STYPER_RISCV_TLS_IER_RISCV_TLS_LER_RISCV_GOT_HI20R_RISCV_GOT_PCREL_ITYPER_RISCV_PCREL_HI20R_RISCV_PCREL_LO12_IR_RISCV_PCREL_LO12_SR_RISCV_BRANCHR_RISCV_RVC_BRANCHR_RISCV_RVC_JUMPR_PCRELDBLR_LOONG64_ADDR_HIR_LOONG64_ADDR_LOR_LOONG64_TLS_LE_HIR_LOONG64_TLS_LE_LOR_CALLLOONG64R_LOONG64_TLS_IE_HIR_LOONG64_TLS_IE_LOR_LOONG64_GOT_HIR_LOONG64_GOT_LOR_LOONG64_ADD64R_LOONG64_SUB64R_JMP16LOONG64R_JMP21LOONG64R_JMPLOONG64R_ADDRMIPSUR_ADDRMIPSTLSR_ADDRCUOFFR_WASMIMPORTR_XCOFFREFR_PEIMAGEOFFR_INITORDER" -var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 53, 59, 68, 79, 88, 99, 109, 116, 123, 131, 139, 147, 153, 159, 165, 175, 184, 194, 210, 226, 237, 243, 254, 264, 273, 286, 300, 314, 328, 344, 355, 368, 387, 407, 427, 447, 460, 474, 488, 502, 517, 531, 545, 556, 578, 600, 614, 629, 652, 669, 687, 708, 723, 742, 753, 770, 782, 801, 820, 834, 848, 864, 882, 902, 922, 936, 954, 970, 980, 997, 1014, 1033, 1052, 1065, 1084, 1103, 1119, 1135, 1150, 1165, 1179, 1193, 1205, 1216, 1229, 1240, 1252, 1262, 1274, 1285} +var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 53, 59, 68, 79, 88, 99, 109, 116, 123, 131, 139, 147, 153, 159, 165, 175, 184, 194, 210, 226, 237, 243, 254, 264, 273, 286, 300, 314, 328, 344, 355, 368, 387, 407, 427, 447, 460, 474, 488, 502, 517, 531, 545, 556, 578, 600, 614, 629, 652, 669, 687, 708, 723, 742, 753, 770, 782, 801, 820, 834, 848, 864, 887, 905, 925, 945, 959, 977, 993, 1003, 1020, 1037, 1056, 1075, 1088, 1107, 1126, 1142, 1158, 1173, 1188, 1202, 1216, 1228, 1239, 1252, 1263, 1275, 1285, 1297, 1308} func (i RelocType) String() string { i -= 1 diff --git a/src/cmd/link/internal/riscv64/asm.go b/src/cmd/link/internal/riscv64/asm.go index a3f50dc54fe22d..8e5d5be41ec0dd 100644 --- a/src/cmd/link/internal/riscv64/asm.go +++ b/src/cmd/link/internal/riscv64/asm.go @@ -170,8 +170,11 @@ func genSymsLate(ctxt *ld.Link, ldr *loader.Loader) { relocs := ldr.Relocs(s) for ri := 0; ri < relocs.Count(); ri++ { r := relocs.At(ri) - if r.Type() != objabi.R_RISCV_CALL && r.Type() != objabi.R_RISCV_PCREL_ITYPE && - r.Type() != objabi.R_RISCV_PCREL_STYPE && r.Type() != objabi.R_RISCV_TLS_IE { + if r.Type() != objabi.R_RISCV_CALL && + r.Type() != objabi.R_RISCV_PCREL_ITYPE && + r.Type() != objabi.R_RISCV_PCREL_STYPE && + r.Type() != objabi.R_RISCV_TLS_IE && + r.Type() != objabi.R_RISCV_GOT_PCREL_ITYPE { continue } if r.Off() == 0 && ldr.SymType(s).IsText() { @@ -233,7 +236,11 @@ func elfreloc1(ctxt *ld.Link, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, out.Write64(uint64(elf.R_RISCV_JAL) | uint64(elfsym)<<32) out.Write64(uint64(r.Xadd)) - case objabi.R_RISCV_CALL, objabi.R_RISCV_PCREL_ITYPE, objabi.R_RISCV_PCREL_STYPE, objabi.R_RISCV_TLS_IE: + case objabi.R_RISCV_CALL, + objabi.R_RISCV_PCREL_ITYPE, + objabi.R_RISCV_PCREL_STYPE, + objabi.R_RISCV_TLS_IE, + objabi.R_RISCV_GOT_PCREL_ITYPE: // Find the text symbol for the AUIPC instruction targeted // by this relocation. relocs := ldr.Relocs(s) @@ -262,6 +269,8 @@ func elfreloc1(ctxt *ld.Link, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, hiRel, loRel = elf.R_RISCV_PCREL_HI20, elf.R_RISCV_PCREL_LO12_S case objabi.R_RISCV_TLS_IE: hiRel, loRel = elf.R_RISCV_TLS_GOT_HI20, elf.R_RISCV_PCREL_LO12_I + case objabi.R_RISCV_GOT_PCREL_ITYPE: + hiRel, loRel = elf.R_RISCV_GOT_HI20, elf.R_RISCV_PCREL_LO12_I } out.Write64(uint64(sectoff)) out.Write64(uint64(hiRel) | uint64(elfsym)<<32) @@ -426,7 +435,7 @@ func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loade case objabi.R_RISCV_JAL, objabi.R_RISCV_JAL_TRAMP: return val, 1, true - case objabi.R_RISCV_CALL, objabi.R_RISCV_PCREL_ITYPE, objabi.R_RISCV_PCREL_STYPE, objabi.R_RISCV_TLS_IE, objabi.R_RISCV_TLS_LE: + case objabi.R_RISCV_CALL, objabi.R_RISCV_PCREL_ITYPE, objabi.R_RISCV_PCREL_STYPE, objabi.R_RISCV_TLS_IE, objabi.R_RISCV_TLS_LE, objabi.R_RISCV_GOT_PCREL_ITYPE: return val, 2, true } @@ -626,7 +635,7 @@ func extreloc(target *ld.Target, ldr *loader.Loader, r loader.Reloc, s loader.Sy case objabi.R_RISCV_JAL, objabi.R_RISCV_JAL_TRAMP: return ld.ExtrelocSimple(ldr, r), true - case objabi.R_RISCV_CALL, objabi.R_RISCV_PCREL_ITYPE, objabi.R_RISCV_PCREL_STYPE, objabi.R_RISCV_TLS_IE, objabi.R_RISCV_TLS_LE: + case objabi.R_RISCV_CALL, objabi.R_RISCV_PCREL_ITYPE, objabi.R_RISCV_PCREL_STYPE, objabi.R_RISCV_TLS_IE, objabi.R_RISCV_TLS_LE, objabi.R_RISCV_GOT_PCREL_ITYPE: return ld.ExtrelocViaOuterSym(ldr, r, s), true } return loader.ExtReloc{}, false From baeab452d1a00c139a5096b796d7b1780ad80f1d Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 20 Nov 2024 11:01:27 -0500 Subject: [PATCH 370/397] testing: panic in AllocsPerRun if parallel tests are running If other tests are running, AllocsPerRun's result will be inherently flaky. Saw this with CL 630136 and #70327. Proposed in #70464. Fixes #70464. Change-Id: I190afdf26bc31299f6e5e8665b4fb420ffd554ee Reviewed-on: https://go-review.googlesource.com/c/go/+/630137 Auto-Submit: Russ Cox LUCI-TryBot-Result: Go LUCI Reviewed-by: Ian Lance Taylor --- src/testing/allocs.go | 3 +++ src/testing/testing.go | 12 +++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/testing/allocs.go b/src/testing/allocs.go index 1eeb2d4802c31c..8161fad06fb9ea 100644 --- a/src/testing/allocs.go +++ b/src/testing/allocs.go @@ -18,6 +18,9 @@ import ( // AllocsPerRun sets GOMAXPROCS to 1 during its measurement and will restore // it before returning. func AllocsPerRun(runs int, f func()) (avg float64) { + if parallelStart.Load() != parallelStop.Load() { + panic("testing: AllocsPerRun called during parallel test") + } defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1)) // Warm up the function diff --git a/src/testing/testing.go b/src/testing/testing.go index aefcb84fc8de20..8b0915a0ef7901 100644 --- a/src/testing/testing.go +++ b/src/testing/testing.go @@ -424,6 +424,11 @@ import ( var initRan bool +var ( + parallelStart atomic.Int64 // number of parallel tests started + parallelStop atomic.Int64 // number of parallel tests stopped +) + // Init registers testing flags. These flags are automatically registered by // the "go test" command before running test functions, so Init is only needed // when calling functions such as Benchmark without using "go test". @@ -1536,7 +1541,6 @@ func (t *T) Parallel() { if t.denyParallel { panic(parallelConflict) } - t.isParallel = true if t.parent.barrier == nil { // T.Parallel has no effect when fuzzing. // Multiple processes may run in parallel, but only one input can run at a @@ -1544,6 +1548,8 @@ func (t *T) Parallel() { return } + t.isParallel = true + // We don't want to include the time we spend waiting for serial tests // in the test duration. Record the elapsed time thus far and reset the // timer afterwards. @@ -1572,6 +1578,7 @@ func (t *T) Parallel() { t.signal <- true // Release calling test. <-t.parent.barrier // Wait for the parent test to complete. t.tstate.waitParallel() + parallelStart.Add(1) if t.chatty != nil { t.chatty.Updatef(t.name, "=== CONT %s\n", t.name) @@ -1707,6 +1714,9 @@ func tRunner(t *T, fn func(t *T)) { panic(err) } running.Delete(t.name) + if t.isParallel { + parallelStop.Add(1) + } t.signal <- signal }() From b16c04f43993436f24b1e4155a4652193eb1b90c Mon Sep 17 00:00:00 2001 From: qiulaidongfeng <2645477756@qq.com> Date: Thu, 13 Feb 2025 00:41:13 +0800 Subject: [PATCH 371/397] cmd/dist: use slices.Index Change-Id: Ifcab176faa2ac55e60576cf6acd96a18d0e860ab Reviewed-on: https://go-review.googlesource.com/c/go/+/648859 Reviewed-by: Dmitri Shuralyov Reviewed-by: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Auto-Submit: Ian Lance Taylor --- src/cmd/dist/build.go | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go index 1f467647f56143..4fcc508f8ed48e 100644 --- a/src/cmd/dist/build.go +++ b/src/cmd/dist/build.go @@ -16,6 +16,7 @@ import ( "os/exec" "path/filepath" "regexp" + "slices" "sort" "strconv" "strings" @@ -104,16 +105,6 @@ var okgoos = []string{ "aix", } -// find reports the first index of p in l[0:n], or else -1. -func find(p string, l []string) int { - for i, s := range l { - if p == s { - return i - } - } - return -1 -} - // xinit handles initialization of the various global state, like goroot and goarch. func xinit() { b := os.Getenv("GOROOT") @@ -134,7 +125,7 @@ func xinit() { b = gohostos } goos = b - if find(goos, okgoos) < 0 { + if slices.Index(okgoos, goos) < 0 { fatalf("unknown $GOOS %s", goos) } @@ -202,7 +193,7 @@ func xinit() { if b != "" { gohostarch = b } - if find(gohostarch, okgoarch) < 0 { + if slices.Index(okgoarch, gohostarch) < 0 { fatalf("unknown $GOHOSTARCH %s", gohostarch) } @@ -211,7 +202,7 @@ func xinit() { b = gohostarch } goarch = b - if find(goarch, okgoarch) < 0 { + if slices.Index(okgoarch, goarch) < 0 { fatalf("unknown $GOARCH %s", goarch) } From c8545439b596ffc88d09b9f6970fefdf69fcfc5d Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Sun, 24 Nov 2024 12:39:20 +1100 Subject: [PATCH 372/397] cmd/asm,cmd/internal/obj/riscv: implement vector configuration setting instructions Implement vector configuration setting instructions (VSETVLI, VSETIVLI, VSETL). These allow the vector length (vl) and vector type (vtype) CSRs to be configured via a single instruction. Unfortunately each instruction has its own dedicated encoding. In the case of VSETVLI/VSETIVLI, the vector type is specified via a series of special operands, which specify the selected element width (E8, E16, E32, E64), the vector register group multiplier (M1, M2, M4, M8, MF2, MF4, MF8), the vector tail policy (TU, TA) and vector mask policy (MU, MA). Note that the order of these special operands matches non-Go assemblers. Partially based on work by Pengcheng Wang . Cq-Include-Trybots: luci.golang.try:gotip-linux-riscv64 Change-Id: I431f59c1e048a3e84754f0643a963da473a741fe Reviewed-on: https://go-review.googlesource.com/c/go/+/631936 Reviewed-by: Mark Ryan Reviewed-by: Meng Zhuo Reviewed-by: Cherry Mui LUCI-TryBot-Result: Go LUCI Reviewed-by: Dmitri Shuralyov --- src/cmd/asm/internal/arch/arm64.go | 6 +- src/cmd/asm/internal/arch/riscv64.go | 35 +++- src/cmd/asm/internal/asm/asm.go | 21 +++ src/cmd/asm/internal/asm/parse.go | 16 +- src/cmd/asm/internal/asm/testdata/riscv64.s | 24 +++ .../asm/internal/asm/testdata/riscv64error.s | 4 + src/cmd/internal/obj/arm64/a.out.go | 4 +- src/cmd/internal/obj/link.go | 3 +- src/cmd/internal/obj/riscv/cpu.go | 71 +++++++++ src/cmd/internal/obj/riscv/list.go | 9 ++ src/cmd/internal/obj/riscv/obj.go | 149 ++++++++++++++++-- src/cmd/internal/obj/util.go | 7 + 12 files changed, 325 insertions(+), 24 deletions(-) diff --git a/src/cmd/asm/internal/arch/arm64.go b/src/cmd/asm/internal/arch/arm64.go index e63601de6476f0..87ccb8c0409313 100644 --- a/src/cmd/asm/internal/arch/arm64.go +++ b/src/cmd/asm/internal/arch/arm64.go @@ -59,10 +59,10 @@ func jumpArm64(word string) bool { var arm64SpecialOperand map[string]arm64.SpecialOperand -// GetARM64SpecialOperand returns the internal representation of a special operand. -func GetARM64SpecialOperand(name string) arm64.SpecialOperand { +// ARM64SpecialOperand returns the internal representation of a special operand. +func ARM64SpecialOperand(name string) arm64.SpecialOperand { if arm64SpecialOperand == nil { - // Generate the mapping automatically when the first time the function is called. + // Generate mapping when function is first called. arm64SpecialOperand = map[string]arm64.SpecialOperand{} for opd := arm64.SPOP_BEGIN; opd < arm64.SPOP_END; opd++ { arm64SpecialOperand[opd.String()] = opd diff --git a/src/cmd/asm/internal/arch/riscv64.go b/src/cmd/asm/internal/arch/riscv64.go index 27a66c5e637bb7..69e060a865ed7b 100644 --- a/src/cmd/asm/internal/arch/riscv64.go +++ b/src/cmd/asm/internal/arch/riscv64.go @@ -13,9 +13,8 @@ import ( "cmd/internal/obj/riscv" ) -// IsRISCV64AMO reports whether the op (as defined by a riscv.A* -// constant) is one of the AMO instructions that requires special -// handling. +// IsRISCV64AMO reports whether op is an AMO instruction that requires +// special handling. func IsRISCV64AMO(op obj.As) bool { switch op { case riscv.ASCW, riscv.ASCD, riscv.AAMOSWAPW, riscv.AAMOSWAPD, riscv.AAMOADDW, riscv.AAMOADDD, @@ -26,3 +25,33 @@ func IsRISCV64AMO(op obj.As) bool { } return false } + +// IsRISCV64VTypeI reports whether op is a vtype immediate instruction that +// requires special handling. +func IsRISCV64VTypeI(op obj.As) bool { + return op == riscv.AVSETVLI || op == riscv.AVSETIVLI +} + +var riscv64SpecialOperand map[string]riscv.SpecialOperand + +// RISCV64SpecialOperand returns the internal representation of a special operand. +func RISCV64SpecialOperand(name string) riscv.SpecialOperand { + if riscv64SpecialOperand == nil { + // Generate mapping when function is first called. + riscv64SpecialOperand = map[string]riscv.SpecialOperand{} + for opd := riscv.SPOP_BEGIN; opd < riscv.SPOP_END; opd++ { + riscv64SpecialOperand[opd.String()] = opd + } + } + if opd, ok := riscv64SpecialOperand[name]; ok { + return opd + } + return riscv.SPOP_END +} + +// RISCV64ValidateVectorType reports whether the given configuration is a +// valid vector type. +func RISCV64ValidateVectorType(vsew, vlmul, vtail, vmask int64) error { + _, err := riscv.EncodeVectorType(vsew, vlmul, vtail, vmask) + return err +} diff --git a/src/cmd/asm/internal/asm/asm.go b/src/cmd/asm/internal/asm/asm.go index 9fc7fa559816cb..a1f6a73d708103 100644 --- a/src/cmd/asm/internal/asm/asm.go +++ b/src/cmd/asm/internal/asm/asm.go @@ -915,6 +915,19 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) { prog.To = a[5] break } + if p.arch.Family == sys.RISCV64 && arch.IsRISCV64VTypeI(op) { + prog.From = a[0] + vsew := p.getSpecial(prog, op, &a[1]) + vlmul := p.getSpecial(prog, op, &a[2]) + vtail := p.getSpecial(prog, op, &a[3]) + vmask := p.getSpecial(prog, op, &a[4]) + if err := arch.RISCV64ValidateVectorType(vsew, vlmul, vtail, vmask); err != nil { + p.errorf("invalid vtype: %v", err) + } + prog.AddRestSourceArgs([]obj.Addr{a[1], a[2], a[3], a[4]}) + prog.To = a[5] + break + } fallthrough default: p.errorf("can't handle %s instruction with %d operands", op, len(a)) @@ -965,3 +978,11 @@ func (p *Parser) getRegister(prog *obj.Prog, op obj.As, addr *obj.Addr) int16 { } return addr.Reg } + +// getSpecial checks that addr represents a special operand and returns its value. +func (p *Parser) getSpecial(prog *obj.Prog, op obj.As, addr *obj.Addr) int64 { + if addr.Type != obj.TYPE_SPECIAL || addr.Name != 0 || addr.Reg != 0 || addr.Index != 0 { + p.errorf("%s: expected special operand; found %s", op, obj.Dconv(prog, addr)) + } + return addr.Offset +} diff --git a/src/cmd/asm/internal/asm/parse.go b/src/cmd/asm/internal/asm/parse.go index 638f4e2fc4e7fe..8f8f6dcc346a44 100644 --- a/src/cmd/asm/internal/asm/parse.go +++ b/src/cmd/asm/internal/asm/parse.go @@ -21,6 +21,7 @@ import ( "cmd/asm/internal/lex" "cmd/internal/obj" "cmd/internal/obj/arm64" + "cmd/internal/obj/riscv" "cmd/internal/obj/x86" "cmd/internal/objabi" "cmd/internal/src" @@ -398,16 +399,21 @@ func (p *Parser) operand(a *obj.Addr) { tok := p.next() name := tok.String() if tok.ScanToken == scanner.Ident && !p.atStartOfRegister(name) { + // See if this is an architecture specific special operand. switch p.arch.Family { case sys.ARM64: - // arm64 special operands. - if opd := arch.GetARM64SpecialOperand(name); opd != arm64.SPOP_END { + if opd := arch.ARM64SpecialOperand(name); opd != arm64.SPOP_END { a.Type = obj.TYPE_SPECIAL a.Offset = int64(opd) - break } - fallthrough - default: + case sys.RISCV64: + if opd := arch.RISCV64SpecialOperand(name); opd != riscv.SPOP_END { + a.Type = obj.TYPE_SPECIAL + a.Offset = int64(opd) + } + } + + if a.Type != obj.TYPE_SPECIAL { // We have a symbol. Parse $sym±offset(symkind) p.symbolReference(a, p.qualifySymbol(name), prefix) } diff --git a/src/cmd/asm/internal/asm/testdata/riscv64.s b/src/cmd/asm/internal/asm/testdata/riscv64.s index 9ab4e066bee481..cbe99ba3485e7a 100644 --- a/src/cmd/asm/internal/asm/testdata/riscv64.s +++ b/src/cmd/asm/internal/asm/testdata/riscv64.s @@ -424,6 +424,30 @@ start: BSET $63, X9 // 9394f42b BSETI $1, X10, X11 // 93151528 + // + // "V" Standard Extension for Vector Operations, Version 1.0 + // + + // 31.6: Configuration Setting Instructions + VSETVLI X10, E8, M1, TU, MU, X12 // 57760500 + VSETVLI X10, E16, M1, TU, MU, X12 // 57768500 + VSETVLI X10, E32, M1, TU, MU, X12 // 57760501 + VSETVLI X10, E64, M1, TU, MU, X12 // 57768501 + VSETVLI X10, E32, M1, TU, MA, X12 // 57760509 + VSETVLI X10, E32, M1, TA, MA, X12 // 5776050d + VSETVLI X10, E32, M2, TA, MA, X12 // 5776150d + VSETVLI X10, E32, M4, TA, MA, X12 // 5776250d + VSETVLI X10, E32, M8, TA, MA, X12 // 5776350d + VSETVLI X10, E32, MF2, TA, MA, X12 // 5776550d + VSETVLI X10, E32, MF4, TA, MA, X12 // 5776650d + VSETVLI X10, E32, MF8, TA, MA, X12 // 5776750d + VSETVLI X10, E32, M1, TA, MA, X12 // 5776050d + VSETVLI $15, E32, M1, TA, MA, X12 // 57f607cd + VSETIVLI $0, E32, M1, TA, MA, X12 // 577600cd + VSETIVLI $15, E32, M1, TA, MA, X12 // 57f607cd + VSETIVLI $31, E32, M1, TA, MA, X12 // 57f60fcd + VSETVL X10, X11, X12 // 57f6a580 + // // Privileged ISA // diff --git a/src/cmd/asm/internal/asm/testdata/riscv64error.s b/src/cmd/asm/internal/asm/testdata/riscv64error.s index 0b0184aaa7e1ed..a90f22af9f40b8 100644 --- a/src/cmd/asm/internal/asm/testdata/riscv64error.s +++ b/src/cmd/asm/internal/asm/testdata/riscv64error.s @@ -46,4 +46,8 @@ TEXT errors(SB),$0 SRLI $1, X5, F1 // ERROR "expected integer register in rd position but got non-integer register F1" SRLI $1, F1, X5 // ERROR "expected integer register in rs1 position but got non-integer register F1" FNES F1, (X5) // ERROR "needs an integer register output" + VSETVLI $32, E16, M1, TU, MU, X12 // ERROR "must be in range [0, 31] (5 bits)" + VSETVLI $-1, E32, M2, TA, MA, X12 // ERROR "must be in range [0, 31] (5 bits)" + VSETIVLI X10, E32, M2, TA, MA, X12 // ERROR "expected immediate value" + VSETVL X10, X11 // ERROR "expected integer register in rs1 position" RET diff --git a/src/cmd/internal/obj/arm64/a.out.go b/src/cmd/internal/obj/arm64/a.out.go index ad00e4842cdfc6..de04a242803df9 100644 --- a/src/cmd/internal/obj/arm64/a.out.go +++ b/src/cmd/internal/obj/arm64/a.out.go @@ -1055,8 +1055,8 @@ type SpecialOperand int const ( // PRFM - SPOP_PLDL1KEEP SpecialOperand = iota // must be the first one - SPOP_BEGIN SpecialOperand = iota - 1 // set as the lower bound + SPOP_PLDL1KEEP SpecialOperand = obj.SpecialOperandARM64Base + iota // must be the first one + SPOP_BEGIN SpecialOperand = obj.SpecialOperandARM64Base + iota - 1 // set as the lower bound SPOP_PLDL1STRM SPOP_PLDL2KEEP SPOP_PLDL2STRM diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go index 6d6a5fd44df1a5..dbd66714d269fe 100644 --- a/src/cmd/internal/obj/link.go +++ b/src/cmd/internal/obj/link.go @@ -98,7 +98,8 @@ import ( // val = string // // -// Special symbolic constants for ARM64, such as conditional flags, tlbi_op and so on. +// Special symbolic constants for ARM64 (such as conditional flags, tlbi_op and so on) +// and RISCV64 (such as names for vector configuration instruction arguments). // Encoding: // type = TYPE_SPECIAL // offset = The constant value corresponding to this symbol diff --git a/src/cmd/internal/obj/riscv/cpu.go b/src/cmd/internal/obj/riscv/cpu.go index 2b75ed38a62611..143164ac411139 100644 --- a/src/cmd/internal/obj/riscv/cpu.go +++ b/src/cmd/internal/obj/riscv/cpu.go @@ -1227,6 +1227,77 @@ const ( RM_RMM // Round to Nearest, ties to Max Magnitude ) +type SpecialOperand int + +const ( + SPOP_BEGIN SpecialOperand = obj.SpecialOperandRISCVBase + + // Vector mask policy. + SPOP_MA SpecialOperand = obj.SpecialOperandRISCVBase + iota - 1 + SPOP_MU + + // Vector tail policy. + SPOP_TA + SPOP_TU + + // Vector register group multiplier (VLMUL). + SPOP_M1 + SPOP_M2 + SPOP_M4 + SPOP_M8 + SPOP_MF2 + SPOP_MF4 + SPOP_MF8 + + // Vector selected element width (VSEW). + SPOP_E8 + SPOP_E16 + SPOP_E32 + SPOP_E64 + + SPOP_END +) + +var specialOperands = map[SpecialOperand]struct { + encoding uint32 + name string +}{ + SPOP_MA: {encoding: 1, name: "MA"}, + SPOP_MU: {encoding: 0, name: "MU"}, + + SPOP_TA: {encoding: 1, name: "TA"}, + SPOP_TU: {encoding: 0, name: "TU"}, + + SPOP_M1: {encoding: 0, name: "M1"}, + SPOP_M2: {encoding: 1, name: "M2"}, + SPOP_M4: {encoding: 2, name: "M4"}, + SPOP_M8: {encoding: 3, name: "M8"}, + SPOP_MF2: {encoding: 5, name: "MF2"}, + SPOP_MF4: {encoding: 6, name: "MF4"}, + SPOP_MF8: {encoding: 7, name: "MF8"}, + + SPOP_E8: {encoding: 0, name: "E8"}, + SPOP_E16: {encoding: 1, name: "E16"}, + SPOP_E32: {encoding: 2, name: "E32"}, + SPOP_E64: {encoding: 3, name: "E64"}, +} + +func (so SpecialOperand) encode() uint32 { + op, ok := specialOperands[so] + if ok { + return op.encoding + } + return 0 +} + +func (so SpecialOperand) String() string { + op, ok := specialOperands[so] + if ok { + return op.name + } + return "" +} + // All unary instructions which write to their arguments (as opposed to reading // from them) go here. The assembly parser uses this information to populate // its AST in a semantically reasonable way. diff --git a/src/cmd/internal/obj/riscv/list.go b/src/cmd/internal/obj/riscv/list.go index c5b7e807199264..8eb97a476dc774 100644 --- a/src/cmd/internal/obj/riscv/list.go +++ b/src/cmd/internal/obj/riscv/list.go @@ -14,6 +14,7 @@ func init() { obj.RegisterRegister(obj.RBaseRISCV, REG_END, RegName) obj.RegisterOpcode(obj.ABaseRISCV, Anames) obj.RegisterOpSuffix("riscv64", opSuffixString) + obj.RegisterSpecialOperands(int64(SPOP_BEGIN), int64(SPOP_END), specialOperandConv) } func RegName(r int) string { @@ -49,3 +50,11 @@ func opSuffixString(s uint8) string { } return fmt.Sprintf(".%s", ss) } + +func specialOperandConv(a int64) string { + spc := SpecialOperand(a) + if spc >= SPOP_BEGIN && spc < SPOP_END { + return spc.String() + } + return "SPC_??" +} diff --git a/src/cmd/internal/obj/riscv/obj.go b/src/cmd/internal/obj/riscv/obj.go index 54c34af2f4a97c..c6f66d0195df4b 100644 --- a/src/cmd/internal/obj/riscv/obj.go +++ b/src/cmd/internal/obj/riscv/obj.go @@ -1042,27 +1042,35 @@ func immEven(x int64) error { return nil } -// immIFits checks whether the immediate value x fits in nbits bits -// as a signed integer. If it does not, an error is returned. -func immIFits(x int64, nbits uint) error { - nbits-- - min := int64(-1) << nbits - max := int64(1)< max { if nbits <= 16 { - return fmt.Errorf("signed immediate %d must be in range [%d, %d] (%d bits)", x, min, max, nbits) + return fmt.Errorf("%s immediate %d must be in range [%d, %d] (%d bits)", label, x, min, max, nbits) } - return fmt.Errorf("signed immediate %#x must be in range [%#x, %#x] (%d bits)", x, min, max, nbits) + return fmt.Errorf("%s immediate %#x must be in range [%#x, %#x] (%d bits)", label, x, min, max, nbits) } return nil } +// immIFits checks whether the immediate value x fits in nbits bits +// as a signed integer. If it does not, an error is returned. +func immIFits(x int64, nbits uint) error { + return immFits(x, nbits, true) +} + // immI extracts the signed integer of the specified size from an immediate. func immI(as obj.As, imm int64, nbits uint) uint32 { if err := immIFits(imm, nbits); err != nil { panic(fmt.Sprintf("%v: %v", as, err)) } - return uint32(imm) + return uint32(imm) & ((1 << nbits) - 1) } func wantImmI(ctxt *obj.Link, ins *instruction, imm int64, nbits uint) { @@ -1071,6 +1079,26 @@ func wantImmI(ctxt *obj.Link, ins *instruction, imm int64, nbits uint) { } } +// immUFits checks whether the immediate value x fits in nbits bits +// as an unsigned integer. If it does not, an error is returned. +func immUFits(x int64, nbits uint) error { + return immFits(x, nbits, false) +} + +// immU extracts the unsigned integer of the specified size from an immediate. +func immU(as obj.As, imm int64, nbits uint) uint32 { + if err := immUFits(imm, nbits); err != nil { + panic(fmt.Sprintf("%v: %v", as, err)) + } + return uint32(imm) & ((1 << nbits) - 1) +} + +func wantImmU(ctxt *obj.Link, ins *instruction, imm int64, nbits uint) { + if err := immUFits(imm, nbits); err != nil { + ctxt.Diag("%v: %v", ins, err) + } +} + func wantReg(ctxt *obj.Link, ins *instruction, pos string, descr string, r, min, max uint32) { if r < min || r > max { var suffix string @@ -1227,6 +1255,29 @@ func validateJ(ctxt *obj.Link, ins *instruction) { wantNoneReg(ctxt, ins, "rs3", ins.rs3) } +func validateVsetvli(ctxt *obj.Link, ins *instruction) { + wantImmU(ctxt, ins, ins.imm, 11) + wantIntReg(ctxt, ins, "rd", ins.rd) + wantIntReg(ctxt, ins, "rs1", ins.rs1) + wantNoneReg(ctxt, ins, "rs2", ins.rs2) + wantNoneReg(ctxt, ins, "rs3", ins.rs3) +} + +func validateVsetivli(ctxt *obj.Link, ins *instruction) { + wantImmU(ctxt, ins, ins.imm, 10) + wantIntReg(ctxt, ins, "rd", ins.rd) + wantImmU(ctxt, ins, int64(ins.rs1), 5) + wantNoneReg(ctxt, ins, "rs2", ins.rs2) + wantNoneReg(ctxt, ins, "rs3", ins.rs3) +} + +func validateVsetvl(ctxt *obj.Link, ins *instruction) { + wantIntReg(ctxt, ins, "rd", ins.rd) + wantIntReg(ctxt, ins, "rs1", ins.rs1) + wantIntReg(ctxt, ins, "rs2", ins.rs2) + wantNoneReg(ctxt, ins, "rs3", ins.rs3) +} + func validateRaw(ctxt *obj.Link, ins *instruction) { // Treat the raw value specially as a 32-bit unsigned integer. // Nobody wants to enter negative machine code. @@ -1415,6 +1466,29 @@ func encodeCJImmediate(imm uint32) uint32 { return bits << 2 } +func encodeVset(as obj.As, rs1, rs2, rd uint32) uint32 { + enc := encode(as) + if enc == nil { + panic("encodeVset: could not encode instruction") + } + return enc.funct7<<25 | rs2<<20 | rs1<<15 | enc.funct3<<12 | rd<<7 | enc.opcode +} + +func encodeVsetvli(ins *instruction) uint32 { + vtype := immU(ins.as, ins.imm, 11) + return encodeVset(ins.as, regI(ins.rs1), vtype, regI(ins.rd)) +} + +func encodeVsetivli(ins *instruction) uint32 { + vtype := immU(ins.as, ins.imm, 10) + avl := immU(ins.as, int64(ins.rs1), 5) + return encodeVset(ins.as, avl, vtype, regI(ins.rd)) +} + +func encodeVsetvl(ins *instruction) uint32 { + return encodeVset(ins.as, regI(ins.rs1), regI(ins.rs2), regI(ins.rd)) +} + func encodeRawIns(ins *instruction) uint32 { // Treat the raw value specially as a 32-bit unsigned integer. // Nobody wants to enter negative machine code. @@ -1485,6 +1559,27 @@ func EncodeUImmediate(imm int64) (int64, error) { return imm << 12, nil } +func EncodeVectorType(vsew, vlmul, vtail, vmask int64) (int64, error) { + vsewSO := SpecialOperand(vsew) + if vsewSO < SPOP_E8 || vsewSO > SPOP_E64 { + return -1, fmt.Errorf("invalid vector selected element width %q", vsewSO) + } + vlmulSO := SpecialOperand(vlmul) + if vlmulSO < SPOP_M1 || vlmulSO > SPOP_MF8 { + return -1, fmt.Errorf("invalid vector register group multiplier %q", vlmulSO) + } + vtailSO := SpecialOperand(vtail) + if vtailSO != SPOP_TA && vtailSO != SPOP_TU { + return -1, fmt.Errorf("invalid vector tail policy %q", vtailSO) + } + vmaskSO := SpecialOperand(vmask) + if vmaskSO != SPOP_MA && vmaskSO != SPOP_MU { + return -1, fmt.Errorf("invalid vector mask policy %q", vmaskSO) + } + vtype := vmaskSO.encode()<<7 | vtailSO.encode()<<6 | vsewSO.encode()<<3 | vlmulSO.encode() + return int64(vtype), nil +} + type encoding struct { encode func(*instruction) uint32 // encode returns the machine code for an instruction validate func(*obj.Link, *instruction) // validate validates an instruction @@ -1522,6 +1617,11 @@ var ( uEncoding = encoding{encode: encodeU, validate: validateU, length: 4} jEncoding = encoding{encode: encodeJ, validate: validateJ, length: 4} + // Encodings for vector configuration setting instruction. + vsetvliEncoding = encoding{encode: encodeVsetvli, validate: validateVsetvli, length: 4} + vsetivliEncoding = encoding{encode: encodeVsetivli, validate: validateVsetivli, length: 4} + vsetvlEncoding = encoding{encode: encodeVsetvl, validate: validateVsetvl, length: 4} + // rawEncoding encodes a raw instruction byte sequence. rawEncoding = encoding{encode: encodeRawIns, validate: validateRaw, length: 4} @@ -1788,6 +1888,15 @@ var instructions = [ALAST & obj.AMask]instructionData{ ABSET & obj.AMask: {enc: rIIIEncoding, immForm: ABSETI, ternary: true}, ABSETI & obj.AMask: {enc: iIIEncoding, ternary: true}, + // + // "V" Standard Extension for Vector Operations, Version 1.0 + // + + // 31.6. Vector Configuration-Setting Instructions + AVSETVLI & obj.AMask: {enc: vsetvliEncoding, immForm: AVSETIVLI}, + AVSETIVLI & obj.AMask: {enc: vsetivliEncoding}, + AVSETVL & obj.AMask: {enc: vsetvlEncoding}, + // // Privileged ISA // @@ -2345,7 +2454,12 @@ func instructionsForProg(p *obj.Prog) []*instruction { ins := instructionForProg(p) inss := []*instruction{ins} - if len(p.RestArgs) > 1 { + if ins.as == AVSETVLI || ins.as == AVSETIVLI { + if len(p.RestArgs) != 4 { + p.Ctxt.Diag("incorrect number of arguments for instruction") + return nil + } + } else if len(p.RestArgs) > 1 { p.Ctxt.Diag("too many source registers") return nil } @@ -2583,6 +2697,21 @@ func instructionsForProg(p *obj.Prog) []*instruction { // XNOR -> (NOT (XOR x y)) ins.as = AXOR inss = append(inss, &instruction{as: AXORI, rs1: ins.rd, rs2: obj.REG_NONE, rd: ins.rd, imm: -1}) + + case AVSETVLI, AVSETIVLI: + ins.rs1, ins.rs2 = ins.rs2, obj.REG_NONE + vtype, err := EncodeVectorType(p.RestArgs[0].Offset, p.RestArgs[1].Offset, p.RestArgs[2].Offset, p.RestArgs[3].Offset) + if err != nil { + p.Ctxt.Diag("%v: %v", p, err) + } + ins.imm = int64(vtype) + if ins.as == AVSETIVLI { + if p.From.Type != obj.TYPE_CONST { + p.Ctxt.Diag("%v: expected immediate value", p) + } + ins.rs1 = uint32(p.From.Offset) + } + } for _, ins := range inss { diff --git a/src/cmd/internal/obj/util.go b/src/cmd/internal/obj/util.go index 26de22122a6269..7d87bff94918b4 100644 --- a/src/cmd/internal/obj/util.go +++ b/src/cmd/internal/obj/util.go @@ -591,6 +591,13 @@ type spcSet struct { var spcSpace []spcSet +// Each architecture is allotted a distinct subspace: [Lo, Hi) for declaring its +// arch-specific special operands. +const ( + SpecialOperandARM64Base = 0 << 16 + SpecialOperandRISCVBase = 1 << 16 +) + // RegisterSpecialOperands binds a pretty-printer (SPCconv) for special // operand numbers to a given special operand number range. Lo is inclusive, // hi is exclusive (valid special operands are lo through hi-1). From 954e2c0b062d21f4914f04f0eb1aa7c5197ee92c Mon Sep 17 00:00:00 2001 From: Carlos Amedee Date: Mon, 6 Jan 2025 12:59:07 -0500 Subject: [PATCH 373/397] sync: use runtime.AddCleanup instead of runtime.SetFinalizer This changes the use of finalizers to the cleanup implementation in tests. Updates #70907 Change-Id: I7d7289999a83fa53f538698f34294f7d9651c921 Reviewed-on: https://go-review.googlesource.com/c/go/+/640735 Reviewed-by: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI --- src/sync/map_test.go | 10 ++++------ src/sync/oncefunc_test.go | 4 +--- src/sync/pool_test.go | 10 ++++------ 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/sync/map_test.go b/src/sync/map_test.go index f12c43a28fc95f..05c81354c87b67 100644 --- a/src/sync/map_test.go +++ b/src/sync/map_test.go @@ -225,15 +225,13 @@ func TestIssue40999(t *testing.T) { // add an initial entry to bias len(m.dirty) above the miss count. m.Store(nil, struct{}{}) - var finalized uint32 + var cleanedUp uint32 - // Set finalizers that count for collected keys. A non-zero count + // Add cleanups that count for collected keys. A non-zero count // indicates that keys have not been leaked. - for atomic.LoadUint32(&finalized) == 0 { + for atomic.LoadUint32(&cleanedUp) == 0 { p := new(int) - runtime.SetFinalizer(p, func(*int) { - atomic.AddUint32(&finalized, 1) - }) + runtime.AddCleanup(p, func(c *uint32) { atomic.AddUint32(c, 1) }, &cleanedUp) m.Store(p, struct{}{}) m.Delete(p) runtime.GC() diff --git a/src/sync/oncefunc_test.go b/src/sync/oncefunc_test.go index 5f0d5640631dd0..daf094571f054b 100644 --- a/src/sync/oncefunc_test.go +++ b/src/sync/oncefunc_test.go @@ -203,9 +203,7 @@ func TestOnceXGC(t *testing.T) { t.Run(n, func(t *testing.T) { buf := make([]byte, 1024) var gc atomic.Bool - runtime.SetFinalizer(&buf[0], func(_ *byte) { - gc.Store(true) - }) + runtime.AddCleanup(&buf[0], func(g *atomic.Bool) { g.Store(true) }, &gc) f := fn(buf) gcwaitfin() if gc.Load() != false { diff --git a/src/sync/pool_test.go b/src/sync/pool_test.go index b6ee983c2989b2..286dcacf3ecc84 100644 --- a/src/sync/pool_test.go +++ b/src/sync/pool_test.go @@ -109,12 +109,10 @@ loop: if try == 1 && testing.Short() { break } - var fin, fin1 uint32 + var cln, cln1 uint32 for i := 0; i < N; i++ { v := new(string) - runtime.SetFinalizer(v, func(vv *string) { - atomic.AddUint32(&fin, 1) - }) + runtime.AddCleanup(v, func(f *uint32) { atomic.AddUint32(f, 1) }, &cln) p.Put(v) } if drain { @@ -126,11 +124,11 @@ loop: runtime.GC() time.Sleep(time.Duration(i*100+10) * time.Millisecond) // 1 pointer can remain on stack or elsewhere - if fin1 = atomic.LoadUint32(&fin); fin1 >= N-1 { + if cln1 = atomic.LoadUint32(&cln); cln1 >= N-1 { continue loop } } - t.Fatalf("only %v out of %v resources are finalized on try %v", fin1, N, try) + t.Fatalf("only %v out of %v resources are cleaned up on try %v", cln1, N, try) } } From a8487dadeb6057418ee29b3ec8d2f1af0c91a42e Mon Sep 17 00:00:00 2001 From: Carlos Amedee Date: Mon, 6 Jan 2025 13:15:51 -0500 Subject: [PATCH 374/397] cmd/go: use runtime.AddCleanup instead of runtime.SetFinalizer Replace the usage of runtime.SetFinalizer with runtime.AddCleanup. This changes a test and how when the Go command panics when a file is left locked. Updates #70907 Change-Id: I8d8c56d16486728f9bd4b910b81796ae506bda74 Reviewed-on: https://go-review.googlesource.com/c/go/+/640736 Reviewed-by: Sam Thanawalla LUCI-TryBot-Result: Go LUCI --- src/cmd/go/internal/base/limit.go | 8 ++------ src/cmd/go/internal/lockedfile/lockedfile.go | 12 +++++++----- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/cmd/go/internal/base/limit.go b/src/cmd/go/internal/base/limit.go index b4160bde021c0d..4317432527a433 100644 --- a/src/cmd/go/internal/base/limit.go +++ b/src/cmd/go/internal/base/limit.go @@ -52,7 +52,7 @@ func AcquireNet() (release func(), err error) { } checker := new(netTokenChecker) - runtime.SetFinalizer(checker, (*netTokenChecker).panicUnreleased) + cleanup := runtime.AddCleanup(checker, func(_ int) { panic("internal error: net token acquired but not released") }, 0) return func() { if checker.released { @@ -62,7 +62,7 @@ func AcquireNet() (release func(), err error) { if hasToken { <-netLimitSem } - runtime.SetFinalizer(checker, nil) + cleanup.Stop() }, nil } @@ -78,7 +78,3 @@ type netTokenChecker struct { // “tiny allocator”. unusedAvoidTinyAllocator string } - -func (c *netTokenChecker) panicUnreleased() { - panic("internal error: net token acquired but not released") -} diff --git a/src/cmd/go/internal/lockedfile/lockedfile.go b/src/cmd/go/internal/lockedfile/lockedfile.go index 82e1a89675e704..8bd2ffbe8f7860 100644 --- a/src/cmd/go/internal/lockedfile/lockedfile.go +++ b/src/cmd/go/internal/lockedfile/lockedfile.go @@ -24,6 +24,8 @@ import ( type File struct { osFile closed bool + // cleanup panics when the file is no longer referenced and it has not been closed. + cleanup runtime.Cleanup } // osFile embeds a *os.File while keeping the pointer itself unexported. @@ -48,11 +50,11 @@ func OpenFile(name string, flag int, perm fs.FileMode) (*File, error) { // Although the operating system will drop locks for open files when the go // command exits, we want to hold locks for as little time as possible, and we // especially don't want to leave a file locked after we're done with it. Our - // Close method is what releases the locks, so use a finalizer to report + // Close method is what releases the locks, so use a cleanup to report // missing Close calls on a best-effort basis. - runtime.SetFinalizer(f, func(f *File) { - panic(fmt.Sprintf("lockedfile.File %s became unreachable without a call to Close", f.Name())) - }) + f.cleanup = runtime.AddCleanup(f, func(fileName string) { + panic(fmt.Sprintf("lockedfile.File %s became unreachable without a call to Close", fileName)) + }, f.Name()) return f, nil } @@ -91,7 +93,7 @@ func (f *File) Close() error { f.closed = true err := closeFile(f.osFile.File) - runtime.SetFinalizer(f, nil) + f.cleanup.Stop() return err } From c0d96f30e88b7ed541830a9d5a172f199d05399c Mon Sep 17 00:00:00 2001 From: Dmitri Shuralyov Date: Thu, 13 Feb 2025 19:15:49 -0500 Subject: [PATCH 375/397] net/http: unskip TestDisableContentLength/h2 h2_bundle.go has been updated. Change-Id: I055b8db9aab964621c980e4731011c89f7694405 Reviewed-on: https://go-review.googlesource.com/c/go/+/649496 Reviewed-by: Dmitri Shuralyov Reviewed-by: Damien Neil LUCI-TryBot-Result: Go LUCI Auto-Submit: Dmitri Shuralyov --- src/net/http/serve_test.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/net/http/serve_test.go b/src/net/http/serve_test.go index e551732016e81e..89fcbd1329b1f5 100644 --- a/src/net/http/serve_test.go +++ b/src/net/http/serve_test.go @@ -7128,10 +7128,6 @@ func testHeadBody(t *testing.T, mode testMode, chunked bool, method string) { // or disabled when the header is set to nil. func TestDisableContentLength(t *testing.T) { run(t, testDisableContentLength) } func testDisableContentLength(t *testing.T, mode testMode) { - if mode == http2Mode { - t.Skip("skipping until h2_bundle.go is updated; see https://go-review.googlesource.com/c/net/+/471535") - } - noCL := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) { w.Header()["Content-Length"] = nil // disable the default Content-Length response fmt.Fprintf(w, "OK") From 242ef7cb05a6d406912389b6b3b6ad3bda1f7484 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Sat, 28 Dec 2024 22:32:59 +0100 Subject: [PATCH 376/397] crypto/rsa: normalize GenerateKey benchmark MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Benchmarking key generation is a pain. The number of random candidates explored before finding a prime varies greatly, and on top of that some rejections happen in the trial divisions step and some in the Miller-Rabin step. However, we can calculate on average how many candidates we should reject before finding a prime, and of those how many should be divisible by small primes. (And even the number of multiplications in a Miller-Rabin iteration.) The new checked in sequence of candidates is normalized to represent the average case. It doesn't normalize the runtime of GCD, but running the benchmark with 20 different randomly generated "average cases" produces very consistent results, so it must not matter much. goos: darwin goarch: arm64 pkg: crypto/rsa cpu: Apple M2 │ regen.txt │ │ sec/op │ GenerateKey/2048-8 136.4m ± 0% Changed slightly the excess masking in keygen.go to make it easier to feed fixed candidates. This might also make it easier to share test vectors in the future. Change-Id: I66696c693f35da7bda27db537aa3bf3b991e970e Reviewed-on: https://go-review.googlesource.com/c/go/+/639335 Auto-Submit: Filippo Valsorda Reviewed-by: Daniel McCarney Reviewed-by: Roland Shoemaker Reviewed-by: Russ Cox LUCI-TryBot-Result: Go LUCI --- src/crypto/internal/fips140/rsa/keygen.go | 17 +- src/crypto/rsa/rsa_test.go | 59 +- src/crypto/rsa/testdata/keygen2048.txt | 719 ++++++++++++++++++++++ 3 files changed, 781 insertions(+), 14 deletions(-) create mode 100644 src/crypto/rsa/testdata/keygen2048.txt diff --git a/src/crypto/internal/fips140/rsa/keygen.go b/src/crypto/internal/fips140/rsa/keygen.go index 658eb9ab2458aa..c8314e78df663d 100644 --- a/src/crypto/internal/fips140/rsa/keygen.go +++ b/src/crypto/internal/fips140/rsa/keygen.go @@ -167,15 +167,17 @@ func randomPrime(rand io.Reader, bits int) ([]byte, error) { if err := drbg.ReadWithReader(rand, b); err != nil { return nil, err } - if excess := len(b)*8 - bits; excess != 0 { - b[0] >>= excess - } + // Clear the most significant bits to reach the desired size. We use a + // mask rather than right-shifting b[0] to make it easier to inject test + // candidates, which can be represented as simple big-endian integers. + excess := len(b)*8 - bits + b[0] &= 0b1111_1111 >> excess // Don't let the value be too small: set the most significant two bits. // Setting the top two bits, rather than just the top bit, means that // when two of these values are multiplied together, the result isn't // ever one bit short. - if excess := len(b)*8 - bits; excess < 7 { + if excess < 7 { b[0] |= 0b1100_0000 >> excess } else { b[0] |= 0b0000_0001 @@ -270,9 +272,8 @@ func isPrime(w []byte) bool { b := make([]byte, (bits+7)/8) for { drbg.Read(b) - if excess := len(b)*8 - bits; excess != 0 { - b[0] >>= excess - } + excess := len(b)*8 - bits + b[0] &= 0b1111_1111 >> excess result, err := millerRabinIteration(mr, b) if err != nil { // b was rejected. @@ -295,6 +296,8 @@ func isPrime(w []byte) bool { // // Higher values cause fewer Miller-Rabin tests of composites (nothing can help // with the final test on the actual prime) but make InverseVarTime take longer. +// There are diminishing returns: including the 75th prime would increase the +// success rate of trial division by 0.05%. var productOfPrimes = []byte{ 0x10, 0x6a, 0xa9, 0xfb, 0x76, 0x46, 0xfa, 0x6e, 0xb0, 0x81, 0x3c, 0x28, 0xc5, 0xd5, 0xf0, 0x9f, 0x07, 0x7e, 0xc3, 0xba, 0x23, 0x8b, 0xfb, 0x99, 0xc1, 0xb6, 0x31, 0xa2, 0x03, 0xe8, 0x11, 0x87, diff --git a/src/crypto/rsa/rsa_test.go b/src/crypto/rsa/rsa_test.go index 73b0c3749eedb2..9e4478f9705f85 100644 --- a/src/crypto/rsa/rsa_test.go +++ b/src/crypto/rsa/rsa_test.go @@ -16,10 +16,13 @@ import ( "crypto/sha256" "crypto/sha512" "crypto/x509" + "encoding/hex" "encoding/pem" "flag" "fmt" + "io" "math/big" + "os" "strings" "testing" ) @@ -762,28 +765,70 @@ func BenchmarkVerifyPSS(b *testing.B) { }) } -func BenchmarkGenerateKey(b *testing.B) { +func BenchmarkParsePKCS8PrivateKey(b *testing.B) { b.Run("2048", func(b *testing.B) { + p, _ := pem.Decode([]byte(test2048KeyPEM)) + b.ResetTimer() for i := 0; i < b.N; i++ { - if _, err := GenerateKey(rand.Reader, 2048); err != nil { + if _, err := x509.ParsePKCS8PrivateKey(p.Bytes); err != nil { b.Fatal(err) } } }) } -func BenchmarkParsePKCS8PrivateKey(b *testing.B) { +func BenchmarkGenerateKey(b *testing.B) { b.Run("2048", func(b *testing.B) { - p, _ := pem.Decode([]byte(test2048KeyPEM)) - b.ResetTimer() - for i := 0; i < b.N; i++ { - if _, err := x509.ParsePKCS8PrivateKey(p.Bytes); err != nil { + primes, err := os.ReadFile("testdata/keygen2048.txt") + if err != nil { + b.Fatal(err) + } + for b.Loop() { + r := &testPrimeReader{primes: string(primes)} + if _, err := GenerateKey(r, 2048); err != nil { b.Fatal(err) } } }) } +// testPrimeReader feeds prime candidates from a text file, +// one per line in hex, to GenerateKey. +type testPrimeReader struct { + primes string +} + +func (r *testPrimeReader) Read(p []byte) (n int, err error) { + // Neutralize randutil.MaybeReadByte. + // + // DO NOT COPY this. We *will* break you. We can do this because we're + // in the standard library, and can update this along with the + // GenerateKey implementation if necessary. + // + // You have been warned. + if len(p) == 1 { + return 1, nil + } + + var line string + for line == "" || line[0] == '#' { + var ok bool + line, r.primes, ok = strings.Cut(r.primes, "\n") + if !ok { + return 0, io.EOF + } + } + b, err := hex.DecodeString(line) + if err != nil { + return 0, err + } + if len(p) != len(b) { + return 0, fmt.Errorf("unexpected read length: %d", len(p)) + } + copy(p, b) + return len(p), nil +} + type testEncryptOAEPMessage struct { in []byte seed []byte diff --git a/src/crypto/rsa/testdata/keygen2048.txt b/src/crypto/rsa/testdata/keygen2048.txt new file mode 100644 index 00000000000000..31854020d75b01 --- /dev/null +++ b/src/crypto/rsa/testdata/keygen2048.txt @@ -0,0 +1,719 @@ +# Prime candidates for RSA 2048 key generation, one per line, in big endian hex. +# This file contains two primes, one of which is at the end of the file. +# The totients of the primes are coprime with 65537. +# +# The number of composites, the distribution of their small divisors, and the +# number of trailing zeros are all chosen to be representative of the expected +# average key generation run, to provide a useful benchmark target. +# +# https://c2sp.org/CCTV/keygen#rsa-key-generation-benchmark +# https://words.filippo.io/rsa-keygen-bench/ + +c3280c027a24d6e2277d1227e4531c1ee765bda9d304bfe7a59519bf2686fd5435c5e5a1200b74cba47c49f444e89b0e0991d05824119ee9dee73e4bd6ce3e93a10604239677fd0b735438b2360d0da9e6e929e1c564df0f0287eb0804cb9dba824a53156098ce8c8efdb8197d12ac040baef4e90710670aa7a33d9a0cd0c62d +d658a5dea2c73517326aba6bddc24b677d47178dc77dd584160827702d203908c504bcb305309c6ced76c7bb2f891bd99119e95bd3d90b1c25c00808c10f94e5ee29aa84d066baf7a17250328286a74173cee433292afec2e3707790d1d590b0ae8d667614a8ec33ed8cd9344dae48dff98631c7e609b7c63c4bb1a5dcdcfdb5 +e5ce50dd929f658d7285fa47a175298c0657dfcc98620e92772c6ed6134ba24d7703ce31d6a2e20e82b95be2a72f3818f7f2bad597bed7a8b5c6c3cf408fb49aa70c003182583a95b9c615ffff31343060c98b1058423387f52e3a7992a29b5b494a49256a7dccb25874f9109d7124ddb2c3e6f4430243439b605ba67a1c2f8d +d01fc442afdb8bd631d93d4531bb16f4f9c3bc710f6546c248f809987cb7878e8ab9dec73b7d3d823563e4df53e41830b16d25eb96985f393c17906caa24d5a8a8123439ecea4d34d7b28bc4f16bcdcbf1f2d3a8d53b5c26cb2d217c04a12f3a436510031901bb1af9c5530402384ca801dff5ab6ea922be78857d0290ae11bd +c0047306b9a1a51226ae3d77981ef08f43783f5ae6534ef5783e0044518e53a7c778759f88378970c1ac71e3a57a6f0839e45036d3dd180a713d962f701b139af22c8fe07ae2105c1b56efe0cdb4ef36e94d9b398570db68efe873ccac75186357ffdb5f9e10470e62efd78b09ae76508ddef6c43faeff84cbf8ceef9138e035 +fdac5080d27a1a4213ee721dc344e16b5e8e6bb790e1bb8dc965a2e76b2311889fbaa9967b57d323aaf13e2960dedac6ac719a1a85a6817262703606b176bf3675922502040273ce256939000801cd1dd8888251c14b6223dd572d4c9efee5b522b2a06b0ccb34d302524eacf1f9183350c90adf8f5ccdaf708937f25677817d +c4876a812cbb5fdb31dd80e04656a0bd3e131a2d2eed4b29420f373e9e4ac61a0d0a023713c030bcef917c146647f97aa9937626f251f1fe2eb4106f3eeecb6b8c2346ddc9bd88740e2115b23b72d2d4a4ece93f96ec34b983c61cce8c33bb650107859190c2bfb24b326a534aa0f44fc2210601f39c82b344e184632d825315 +ecfd96ea0fdf3cd7072d6db2d9ae052f50a16b948838353f9d566c383309fcc1e43d3a0ed9cdb9c9d4b0d8552053a1c2561c7df175bae082128c3d380a60c8c578b51049928d0669bc2f20256b80b089f217f390c80252c49038bd1f2f89b265d49b935c5d621a7f9e6b41e8c7c5e454c5b539f90bfd2e5e09ff19ae280c92b5 +d934a84e3d322798b83c86259f93f06f9545a2d5cb911ce4ee19fa887e433baaf6cd3c66285626dc09669b4b2209926193af341683629bc8575f0d3cdff3b558566733aa3e256f4363f4eb4005caf7cef91d2653e20f7b2c35a74411dd73e8be0d1193f0bdfef5f39b680d069d64b3c49de3d31e91e19015b3e14e24884010d5 +dd1f0316593bb2e1df22f1fd618d56e7c4f28d6a85501ce14e262dd316acfdc67d17caaa3d7fbb730c885ef394050eb80ce597cde2510153e67d99ab8c463f6b8d3aa607e49d8303318f9c379df7f48454b9b1093ff29f0a6e78f586d00f26912b2f27db810b96c956586ebafcbee500a701f74cdc42201aabc2c5a1977671ed +e1eda3a00453828b2060ac037e3fdc546a019c30d7ef08c51ec722ef98313148b08583fc495746ab3e6a46efb4f4342013ef44da8821adcde73bfc873b7a521dee1e9cccf3f169e78fba89963a4561fc507c5333befa509cd910ed26e45c62a2a3e0df1d961042e6f38474a99c9c5b366d0a6d81c41774d1ffc4117cb9f000bd +f04402a78861bdb7100df31330193151688bd1c4ecbff887c1e484d67ec705cc62013d49f1b92fef400d5530202dcb4145828a9f657d2a1c454dafcb3b36a1664027ff703d78fbf4712fc6248308b56ca80bd10b19263df5194a74278269b61f5199390d4f77a9934cb88272681a77682dca4af9cdbcf376ab7660b9f3e6007d +faba6e112b7f349d92bba5f80de2437ad692922a33efed347579eb7be667b1df09a2dcdfac534fee0fbd4fef0838a74006dbcba62b8ce6cc0e6d1e1035effa096085716e4761083728f923525c9ac4339d15cbce8164d2abacaf1e134802e28733d1f7e7327f7430f4386102915f02b9c435b7a4f8a0433062973356490c999d +cd1d62358df14d823c9aaef80de713db2bff6dc3f15da163f981601b2096cbbc04ee12767937ff5f7218b758defc27912cbcfd8a7bdffa48e1c5d4accd21ded2cbb99f053103555cd78e9cbe0ce6e89db7fea4718b326f266c62ca997c1102ad9c04a3296405d2f9b8ed4a0e799e4818eba66247c25da68955f03f076dd7f735 +e4ce1badc198ea490b37dc7c04e6748904868129bb8cd4a7638f5cd9b7cc5e7f6f92639faa0bd755c6b84bb8c8361c5869b248ec443b24a81e5a9abf94309653f9777dca00aed9fcecc21dad79f9aa5b1a720d3800728a452d5a4fd4dcf156c20fcbba7e0a10c5c3cc63bd6e24fa63b248ed1a9b24205a801be3c1cb74be2bed +e6212b34639e14987d4820c32930bb2a72ec98670dd8269ffb85583f86be8152b6421798e6f11f64c410966f5fc85074b932944675c1d2e67ef1e831f15cec8dd2b8f7635e84c1624cc830fcf3ce1df011dcf133bb636e2a5c92789bf6e824a0a84c9311d0903af0ccc2ee417400538b745190546f97abb03461efcd924af65d +e64458a6209dfa4288e20607c5efa3ef0023005dd04286bd9d97e835e6316c8b76a6cd471d74d30fae6f84a0605135d85d5b626a9bda82ff24c1245428be2ab06ed0fe994f6bd4189e5620d88dfafb454dcee861b2cdf7362bbc4d2adafd606c17088f190e6bd14d57b51fcb1068b13cef8c454e138694f06138dc7b082dcdad +c0896f1090bcc0994a8888a71d7aa6a484d4a02312a2fffa805bce038a98064f054e097488c9e2e3f8daed458cca270761d07daeab428591d6bc30debf0548949ab2c89b2a4950241f78798100efe858b7667842410091764b6f62061c22e1b2f923de098547632f81525ed7696808097d20c7703b6ae01e11c094aee01a39cd +fe882662e021d8b4329b80e6caacc66174c483c453881389de36331a81b229c8404b4916a8103139fb125289a3746e3ef11370b6453b170635b727e88f3ba7ff760db3d69b87a6613f41a6a0d2af65326b109d6b4fb940b3dd20f1920bf40b88bd6027a11e9bd7e6e1508ca1c45d5011e084085aba7898c439aa9fff2466cf75 +e87cb70f7bba008257d76ae1b6629a6a21d12158eef819d8422a8b4f18830d426d784ee64d204fbbe3d21fc6bcfcb946a08b72e92132563de4f52c7e6682785408b0f612d7a461f413b68a186c637872a6207aaeb3774d302053375b1ea36bc63a968eccbb6034d408d4fd82c93810bd50990d28b5ca037fb541cc0402770a65 +c59ce336ad22514ff1bfcb64706d7812f8fb592fada9adac89b7b4bc74cc100bb7d41f6448a4fe8e8c54ad3eb9f643ff62240f1f24e4f7869c4de12cc7530f8856f5abbbc098a09a0b6f98dbf008ee586eed521b608302c49ff5450117babdcc89c1e1868503557696b7ea13ac4587d1535982cd0d88aac6161bbd3338877785 +d8f6e37189f694e33286bf6489fa969c0b82e21fa3a7fcdd142070bcc05a43b89b55163db9077a3576cb8917c30a3a66a04262e6d065cd5e74a6064de059c502c768edc7e33647f66ab6fd024d3c900b552dfb6c2d6aa21b6c1b569ae31bd75b2bc4d968ae9c49009c770f57d121a9c3ff0ed376f424891e734456bf605a943d +dd66fb98c6b659ed158375316e61785260961deda5c7cd3a620c21da10382f4aa97d02c1107bfa0589fe6362bb883f48dd5ece326f3c7cbc28d91ab7d1fa8ea1a0df6704bf3dfe9b1f053e4e307d5bed6bb7576254a8188f1d60d91963dcc2db5f7723ebfba4adcef5c5de4e56484306da72669305e167fd2224e678edb0c5a5 +c5a1245c78e99291db45c225773d2141b204c9c8627dd8120c4cc331a67c0b2c118e20dd7805436b4f05b36ad6b1d20b128286976e8f61772f2635ff88fb1c1f6ac2f390175eb9f4f556babe6aa1b2be9683ed442261a79789b10c5ab0f91eef7cc7d6b99d0fccf0d8a9780e540a3ece093ce6dcbfe8e62bce995c23ff201c65 +cb8ca7cd1d043349c6b244ea7f7766f717daf97fe5db079c9f94c0a30ee9b7fd6999728fa22802ac02c7e3228b53030956d3a7c6c148620461adc434388eb9b90ddc84bfd6032069a425521548c2cb78b4683c80d2c48c6df5e831fc23731957d490193f15607c396f62ad650c4266b8bd46b0127001b7d36b97e3b0f76ad735 +e89e37f2ae5007402036195b40ebd882f60756b616a827a3267a701cb12a7000723ba42eda4619989a8d080a444e5a8a8d4fd1a635279297f420e20d9e2587391613c9c35c0e4f6135f5c3abed32fe28783e05a2e0253e7bc351e20c4ddb399aa24ebd971fcf9db2263b0d01b628e87650d14cafe341f881b010089052bde375 +ecc17a8b65380f0203aad09dc6fb76d31fbf9d75a2e342a6b8bbd80585f649d1c1fb6ab5db10e2c15353c9baf32730ea797c9743a8e64e5ec31dfd776b0a25b2b80b68ecd612211b90233f2662381eba397fe5b2bd2cf330c1c7a3abaeca21a13ee088a8e24175022df26221de4cbe1357ae6cb0c93e973779c5b23c8707759d +cc377422aa2d5b267df8adeb9e774012bd8ab7e86855deb61466882d7ee02a749426d242d3329ed6a0b98ce56caff22b2a2ec5c1d7565bc7ac1062b3c9bb887184d690a4c39987e706c9b0360a9195bae763ecd9cb4863b7020972aea212df48374bac14101073af8169f8113debe9480af26dbe534ff7ebc078a84fea0452dd +f6b8e7c33db4bf1106731a54905cc34ebb8235ef9c8196ae9a43afc58f9fc478cf45924130526d2b3721cd9e5397665159d9e978676ac5663838bee9db236e389ff21786737b78abb5c34dd44f878a6a8f38b4f9017a8429e0ff7efc7e95783d532681bbb652222e604492e5e9cae70acff964a27274e30f3544758a60603c85 +f45323a64eb82a494ddf732502daf879938c2000b2f68690b013cb3a40d7459d850c41c829fb0d830a8a8ce53e43040c0e2de84e36c8adcf8b2935fc4d603d5065b7530baa21f3fc8566d13f6840dc0000e0531819c833ddb9db52257b1b18d815adf7f2cc1a74a8a2417db14f3578582987324ea66a85d6877e2803df34976d +c4b49ac4794fcad37ffeddf43b27b0f95d504ebd8faec1640fb3d1ec3ecf0d5f433e53f62b436a17436104fd1368903e38a10e173267b2105bfe5f64be5c275f3e1574cd2bc46435b004c158df4eb0ea47d3244a16e2d4eb49b68f06212c3753ba6acb74e59ad0154509ad46491b167f68c118f2ab8ea351f22cf23946b98545 +d9966e5ef2c98ed3ab7665493cb3b29e0b55e4f3593218417dc012d0cb6293a3ec9440f2959f3990afd04def8fd14e016d949c0ae116900fbd3e810addc5545db1285f73927c7828eac881a6bb5c25410ed7a9b28e9bc3a6e96f1a239dfbe2e9db90df2cc1bd832293f06e30b4cebf795945b717ec0d273364fd603a2db06b5d +e0fcd8c3c66391647f3cad90bc667361230cd0907a4f95d63b85dd7ce259952784a2facfd8a707dd58c5a66f1f3f238fd55f6c39a615547448d01ed27c046357edf1c7c8efb17e529a9a28b63e83aa0d203cc687cbfe19201388ca4edfc302fa04e11dca78907ee5401bca9b9ad1650ae8dcd63921aacd3afafe39cc9fc0e18d +c2e60320538adaf01aad0431695c391db850f09bdcd1d7711224ff6117e966c3ff1df74fe32210f805dfe5b9ede44b3f5b4398ba09f41712a0acfd17d3f29d901531870079a2106331127a4ee083b348ae34eb10be594f24f320315535cdaaf40ae6c0a3ed762e5f4f77aa6ccd01a1a8a471e2790210485bfb2179f1b214157d +cf2bea1f18b8b7c173139634d3a75be5b16cb92c08fd01189a75d214a0467380b64eaadc717871926d76a3dbf60c488cb1555eccdf749bb161c6f55bf68c6bce9e89ca4d4165cfeea41e5d7ca0bec8b5e32fe8a4f433a0b94e34949dd60f3a73e108ab3ed1cca9f1bca7a28f111ed8ca5b88253df61d7921d1e53de8839cd4d5 +d846b3f003220a8c32229f05a7cbca5fa373ac6d5b6dc3cc2bca8f0c1ed73092087cff694c43ef25b00e16b3327127259e48c51ac271faf2c6c8d4745f07a08b4df84aeaa95d0a73ede4eb50264198625f39917ca61787e8441f579e75a370a11b51db89851783daf44cc88142af0c558f346ee033317235085a2cd185e0e5cd +c82518eb29d04d44fc4d8ed9cdf5252652db5214be69172f58ebba11ecf8ccbdc76e45054484b270b559aed27f66c97f105b997e83f969d2b8045fc5c4795a0f14aa2f26d66a376245ecc3ba39dfa105044754ca7ed6b96722963168f565f192e40fa1f0bd4c875d325394eb72c13f53af85814aed81db2ccdc76feb4bdfcacd +cd174cce3c2a5a2aa08ed861ad64fb0c6a03407ee93ed2343676f1cafc25193af66589d891a1aac648b4d309b047ff6b116dc7bd974acde138cb95c4d7ee95737aad0742aa8d1a9e1781b7cf2a6f09495eb22d2767412a6743f2d80dbe8ec2b07ff4ea528c13e66a6f90385975f8d441aba9c0db2085b7714e07636914878655 +fdd7dbf9cec219fc1c59527f14b95b1094107a0173afd4435582319719f86d300c59fe8e676e29c4b90953208683694ac537b1bada7696767e0fb69893c102da2ad292318a8c06623844d2baf98ce5cbb8f5f4aac2b8adf1ba6cfb0b0238816d76f48671a0bd1aa42ebddcb5ca36bdc6b163f2fdf808ab06ce8129c88a34a29d +fa040fe20e7648d5452eb22d0449d909131d8aca9afb85d969c029525f06d97c719b5427f767b0c64374a0e85059287903827bf981af82b073909ecc277085e1bd489d8416f5e78584565fac47a39551991fcd6850d3705948630b4777eab04ec4d8211bc174b4f52a02aaf3176817c461aa64c0cc6f8caa83c2dae9785413f5 +eda819394c12ddfad1c5195f590389019ccebdceb5d22bdf8f0b8039f339cfa920726ae970d02788062f05e3f94601f6cc73caa1385d12e26842e8658c4feb352a77fe30cbe16475919ed604306151ff9519500547f02c5baf6d0ffc28c145eb09b64b6513bcc006cffa11b1ce9550eaaca8b52abab2731f0a87c2cb3838bbfd +e0a102fad6c51e75f45f919ff5c994fbedbc2decb9be980fb643c5dc4e8d7715642daa68e907ef73d50f48d9b22f9dd269b587edb7daf5086bf9d524de5b0ced07ec6ddcdbb6a7b80a2811a041b43d80ef92d80d26f626712921b2f454b16f9ce469979f9020058df410a8c0fa58f79a1ab8909258d136ea7565cce3db5583b5 +e29cac64588f2d390d569480051aa315a28651b17b5debe2f11937c590f7a6acf553bfd700d56ca0e9557e0002f8078e5c459dcd68621a7684938324207e686d5641210d9c25030892671e28dddbbfb8a5592162a9988e6201916cde8d4c19469edcbf2d539c9d13225ed75642edaf5a5a41f70498f6ad7bcce75521c56ec055 +c8f655d328cd97dddb6eb73dae1c513547e1f9eb924c9d3ab85c12e93f55e7585bd78605483a941d93c951ecb7703f70acfd134898f2d8c3b2eb852694feb12a536b68b1b31df677bcbc1818d00cec3ec77c69dfba074b773458fb688d166147942c76d2e90fe3bf6b1c63062bfa85591216a3a9a1fa89762c1c9d0941c1c5f5 +e4e8eb15317afd379b4739eef0e964d365f45e52838aae4c04671bc51ab06aa583fe7efa805f3beba9bd6c94d9cf1c4816d1d30a6cd0603d8e9e08d367125e6d70b3d1f4bac36d2d81442136d06bdb68618a895ecf5a45d27c9bab3f5302bf93c770680fb74d79fc3ebb0cb23c70a2c798b30e4341bfeb0ae224d9adee129aad +e9b15d8bc80ca4b280c5ff6ee0c92de7efe5d70c356855de5e23fbc6d7c3fbb9ebb2018cc8d3c82ec24ea057005aeb8504d68579c13aaa90adcb5719b8cc633e19ff70ed00f5ea38230eee0fb6c0185ad5a946798b8477e5e0a40961891ca48da0e92db23ee17549212cb337094a9074759544226d88b6a4ad0795f97adad15d +d7a679cb982749b84280e8e68593a578b1df3c3f3cea32c5f85cb8ad9e916a2e46804709b7d13ba3fedafcd5363eed258513077f8618c187a5ead4d80e365afd07ca9b94790e9ff312b7fbfa363571cbed16f7ecbc4958c56d8d2834a80841d55d200fbdd68d6f2edfd53ad9bd98b87467bb33f75fbf679805c691892180f6b5 +cc223cfc403e44f7b1b6b1b4923f5e601174288ebb449c591c7acd53629fd1d54e713a06f3f0c5bae6e0ec6c60f63a39628ad674607ebde06ded53451758cd3f46a2804625ccb5c6b4b8d3387863ff0f191f241ebc76ef2c002ae25415844b968887f5afc058a8a84a73c00708956bb108e22afc824481bc5f635ceb5b612df5 +c8cebb9900596d86f78b675e0b9b6e2efa078d5338e2e8c411b686eaf9fdf2009b0ddc390a54f9ed042363a55faaf61b1db8f81138701bec4ed242a96116111baa7a3a1a58f290ead2dfac414451ca6349b40a006cdaf8a7279413b774da1ec860e60d4cf8bd496c4daf6d67a071672b5813ed77e8cdc39463bbe9e833fc80b5 +ff877d7617c7692de75b95c6aa2b938e06917fe3964679d4d99909571a4aea438d5d9d749ea1cfe9edc3ea5ecaeb2cbf67df63e1d77f2e99841d52401fab7dc8dc8e7db0bb4bab56c2a738c0567fdd9e1d5cad05f143d9a208f1d3c261e2ea1fafb523e45b7ba00d3aa14f8d0ea6843f978289988325b778a74a503afc03dc75 +cdcbd7112b042912bd54805d11c334564f5b49da681c0300afbbf0657f50655b73775b8494160160c721758f848b8f5fdce80accbff0a819779a3ea8a081d2c8204e1ffe325bb2bb20646a3e99e0afb359fac49747724d30fb2861d4fa3576e157ea7ca9a5f8acf8d978a680cf20eac31c46ce888214306d279257c61372182d +cc8bfc877a0f189775fd8663bdda40e940dede0b46a834cb46e57e08ee7ee103275eda18677b67a7d15aefb25311e15bbb8320c72794426976af19f61709b596318d6a181afdbdce9f663e48da148de140c099b10cd8ad5c56befe57b612a3543ca80ae0b1828da26f30498d4b685d3a3bf0d9821aee4eeff19dcd095312861d +f57c84d6f79dabd40b86d9abb9b211355dee5a80404a0858450122d5c9b7f8850aa9399fbe271fd3d551b3fc5cb1f965e9f7ef04d725f8be2fa1473bd2925541b006934939bbb4cc6a061b12c9c4b2b6c3e72c05c9ec303ed089e71cc33b7954004cf5ea29c43dc207da28ce80feb805c804a371adde587970c4a6eb4c1b04c5 +d1be804b2c5442d6f2b8a6410d7b499e8a992a72fa4d532f9715f3c24abc6be301d5eeb7156d8b2010b0b61978ae0bc4205b3b9fff4d0bcc9842d43ee99b56d741d7c06b70b9928f9455802e6b714d01622ad14112f78ced761f10393fdba4e27626638c5b578da4db161f3e4d52edd897cf0dca2c83f1bca4422af1325fc82d +c3e6cc9373a12a14d3916be237b0b016fe7f240c9e7c631e50d2078d63552a898c781d5c1d23d4a4d4881ec211af661527fac39d5937e9f84bdb8182e69fce9a2a31618480bc538cc14e3d778cb0b7b3ba5ff2e4ca04282bda5df1333ed840e437b2ba8daa1679b4288f95ea19b5051ee77fc0dffbeed396df58796803b7eb95 +d36abf4625822935c2e14f94141ac1ab6a700f62010d9d5fb56ec9d582fe5e8ccbbace8496b16c215575df4692fdb5e5603cf0ca4680d9cc2e9440896221c86c0d3d7a96dba443d2eb651e95326d2663d8777c724c8b75be3e3b2319b23ee3561748560be33e8e4fafe01b40490732ff991a7c0f971672fa60f7adb59ecc3475 +ed3d82f546fb076502e0f5c4db6089fd203a6f8cfb7a3000e8c0d98ca15fdc784c4ffe0331bbf753663f7754c52886c6175465114a0d009829843629dea455d6ca5e940d88e1fbddab15ba018ae467a7bb2ac7fd9df12707611134a10e6b008f52bb0d2c3889a9b6dd8695fb7287bd2644d38094222df4b6e0a3799d95a32cd5 +e9faa255b3a1b7a6514cf14b7a62fa3ef57c1e7c62943aabc0ae690ed22c656d7477e17a42bd104e4243909576d03f93805c50873b8af7b6ad4a67350842c84ef4fff257d7c7b21dea8a907bf2be9bfa7261dcb50cb6d80ac1ee9e045027d0d6c4760541cbec65db502eac75e340555b2607779fbd4550218c0b8f8303692e5d +c3995bb359e84240b30d6927e9999a3c8c31577b42dbd527dea888466f209724156f57b3392566ea36066eb321924d8bdc5868c6a3fd546c413f31a3a85e8cde6977c4253af146c8acdafd179a5f0356d6219f3db83d565ce1c1286b5083b9226c982641ffbd5cf76738eac94b55ff7ff37817afc68761499762525ac97d8b05 +df98867af5ade57a001271bed2114f69b037ce084870e224d7b0b0e1af1f911bd91e50cfb6017706bf027c0031ebf403420690dd73ea6b862ad2340a1281063a52c647e793d852ee7d610de95d8eb418c9d091e8651f8a9f4c2becd70ee006abdd439e38a773373ed57210044143472bac3ab9d587b84ea9d166f61b9c91c1ad +d799dc56a7286200cfc1959e434161e67551f5b74a92e515466ab1332df4332b9e07af5803cfdd4aea7e6b76f24049cf402fabbdb4529c180d63b1fba3badb09b23eae4bc8784baf2487236b94684663e3bde39acd41c875ebdf1e5143a55fd15be61b2991bc24f9fed25d9779c75176f597755f6f0d2a95211f4756c1516fb5 +c6310962a28f5ef6bbae4ad219aaed7a5fd3021b64ef4f92b3c0ecd605cad3a9f97c8a8019724432318b1e65452a95b3e8a91d2fcd4a0a72fe084cee5c526b4ffb8ce02e2a394fc1dd4c4781aa06be5c2e55ed015c15c4f4b7c408af2ecabaa3b2909b427960571eb7cbbd9bb18a9751b6a92935d41e9f7176c97b64ed55354d +e5192872a3d1e009df8a07cfb29361e86c95183d9702d02d257bb5bbec7830e44f14ca100ba2a59fb3dec712ff6c274f592a45daac1e5c2b4e31b737ff1a57ac338e4e3fac6dac68671e3b7a6d5ee21cfd8604c04bed23a45c00ea0b7d0d1f122af3229ca667ee8808f86fe2e740c016729ca1082873f71ec822f145d9b76aa5 +e44d270ef565b5e7e27244463c6ff3bfaca373f5248970a917e3c76f80f274f328793273323bcc30f8779dfa3454787931c7f7a21ebf41b8532b8d7dc86c1f67edd627e7425aa3b86b3f865c848a8c5941ee098caa2f307436e886983552c6aef44c25d65186e1d0ca31d32a9f784a7e9d42d704c331cb4bf2815c084b356315 +e0edc4ddc48bfbd3d7509a7a9aac58c5538218b81f4c3eaab6fa616954c1d19458271a91925dd6a2da62cf33fc137687c3027fbd671d8c272d4d74e4afd343530e9a62a90de771d7340cb3acaf85444c3a861b7f73f0f1194d9f1bc72482b7926348d41ddc5d74286349cd7570fcff35521f0747ec8d3cee3d6ffafd61402c4d +cd5729475237d63b4dba8e30ebb93d68a0a867e2e4b7d624117adb20708c61102b0ddd4fc2c14001ec81fa9638f6bab94afd4ed51b3dc669ed3aa800b6b9c52a396f93a24b0715dbe17a1a8ed2d773c373570a415647794b28a9e4fd450a6a3f4e6af36dbf31201f194ccd6b09905982e01d5e56a743f4507645b84a28435b75 +f629fb24dc8ead8c4fd6b2a95c080d547d158c17f19ab53deb4eefe36857a5a1ade5fa87db6928a3b0b1cf9dad51819d93f4ae71d3881a26e54cbb10216a63687f2a6dee8ef58cf6d8602b8b394e6b9495874b8f92aa88e2edd842ca9174290c411f7e582ec2a691968ccec291d849d3f2d0834aae803b77839bcdf42f3bc97d +f8b09d6e5cee1df04800701b4583c8b963e34224d6c9566bfd83b11afe5d8b1b26255918ea42df2c389f5c355476ae841391282399de66a055d02bcf1cc71e1b22d1903e4dcbe0bdeb478a9949690cd694fb86ba6d7e83ed73e7a739486d5219cdb38a7781a5144476f01818db6abd1d73be57b0355231f24ea0154c20f5050d +f4163ed4e0ddf79fd97c43604c8e7b0ee09580b62166b6735c55ff4fd849c938716c0d129f5874dbe070724a0e4186a9a196677e1a7c52b9f34a117d51fb97281446ff7f3336b225ed287e4dd82b84c024e88047292d18e061dee2f7a9ec5a8f81a7717071a2f86bd53b80f68243bdf19e446232951265c065a60fdd487b7c3d +e1145d235521795fbcecf10eb4ca8a29cbeebad436d82540ab3eac21b46f46891772b08a7e69b1ea1c504047b0f584b47c600e18a6d7511715048c4e68a6c54e1af0ded19d84c83f84aadc1bf6ba030f2f80afe29adb094eb68a76e8cc9c8caa95e51c11fc590c90aa86945456b72324cf7035d13e4a1ea7f39cd265964e2ac5 +f0f245183e09ce283c77f3e17e0cb4ceebf99c23e4433a1241a68829f0709cd929068f8984b0bef578198ac06f3a3a753697695447d0a675d7a897ead5a99ddc0a444b4e6eb568932886ae1cc3a67647a248a3ac95e941517da3a20e9bb301102bf28d812434358035901eb99568b8982ef9a76cea58e874c686b9d1bb7e6cb5 +ea13168958667f214be4cf775d29789ca2851c20360aa05e76b5caa7d1ea4e6208ebaaef15dc9eb2b0cf54a9211bc0d615c72d251f361f861d0edfcdacc8c8a71cdcde40baa97d8febb5220fc253b53759b208a6905e00ee4970334270777dccfef096274fffe21699a37a187d4e771dc33d21c8a39e479b1ae4e820561aa5c5 +e666c27528aeebef0bcabad66873b3b44385315ec52177a68d6ad4fe86eb0307ec0aee39d7e671e8dfe432e31ae226cd99e3c3af73b9740de75674621abe63a510b264c2d6597e0963be2257130cdc4c510ac5001370b22d7edb060619dc525380b97787853a80f51492e7d75285a106d4b1f386593b4a8deb46baac39acb12d +dcb4379101c0d50c12a85f4efa5e8d5a3765de6f646060458db7469cd2fe0ebf620d38c64b0a6720080df8859ac74d3a5209e9a59e1c2437860b58a0ff8d88c279b164ff5f817612475cab07c966b275647cc3b765347c21b431a690765afa60f0158da8101214f28d034318a86bf9b592cef2abaae616017e2d5a046edb752d +ea5dab735eb313fae23a38a2aa217c62cd7d67a00a5a56fea73ad5ddd38c4668ad89a4cab1f94f3aeaa1ae7edb27518026e41111b513a74a4d88b3ee9df0bcd991e8adabe8ad233b0fc0bff82d0c87f010314e8a069af98b2d6aa922a8e7792e8a07fd61da0f8325fad04daedde33ad9558e193eeea4bf35a73ad21995f02c55 +c189d07afc0ff09ed9fa600f2b16bc6ade9a253420079dcdc5107946ab42e42a00b2728b4baa608f6ae6376b2c7eab0b15824efc1f9c5eb320f42c837524bc9979322fb29458d40dd65c5c1e629170827876dbf1f37e774d71225ac3a548f4e8126add70d76d6bc802f84484aa402a0dd379f7ea2c9a9d5488bf26c38b46267d +d74d8e36181e5ac15aa040c54bf8e64386aad135468efbcc1cb17c9db0da80a233ee78cbb83c8411c7632955e1e5c151b5631d1bc32683975c9db251e3c8eb3336e7bd888c9607795e040b1eeb85a59180371f7089f9f19e66073a32af1d9c23004cb656eb37955b4672ba85fd707934d0018202d02af9a292fdc537d9335add +eeedecf01b04430f99072f20643d57b88bc4b3d1ab69ae1db4b1867ba7ed56d50fd9ec9f06be6acc702b2ca193147343483c83f77894d98af2f36e6695505ac43c9cce9a6fecc94fcecaa89360bf407b28b6332db5dc5449ea9c68b227ff1abe73a612e4df4632a5d8dff54d721671ceb603ce0750e2ee8ffa2f7b82b3faa015 +db4ffa9ff038ad29458284e3137601bca912bc18344cba7385c3fc73d2d072fbd0942fcd9048321d37ad8c7c1cac6b431c87624639859685302dc830d671e7189a64d3fea5461dacc06ea617a037af08845f86b2907fa3bf7d2308806694c44ef29002a735b58802200391c3a2ab88ac9cf8ec437fb8068902160534788ad4d5 +f49318745e60ce9c01a772f6c051f1b9fd0c1218ef56a442ab235d6e7c6eddd21a564b22f1d587222bc4fd062e668d24b17802da698e2364720a7c1675fb7982972f7cb583eb4deac0baa2d74ebe3759517e9823bbe50bcc3bd94d7b175928f268d95e68e734c6a7e7c9e14b52afc3d2745b4af669f1bf436793cb08a1d5acad +d2fb4ef724dbf7fcddd0ba8686c697f5c64a869c70efc258cfcbecb68e0bd27c5269018b957604f4adc46124e28078a40b410d2b6fedae4f91892d172204327cb4e71f9c6f89b2d2b23f1c40b7389205471358e89db6851829f9b9fdf6f7736dad4ccec19830e38f4f5f4dc5ea9ddf3e26cce3cadc2cfb30752682e4a829ab75 +d5daa77d5cf5869c9c83f3048a11ad7cb39aa6ab44b353c9b7d5a4121aba52954fef42bbd60d475f361af181322f0919b9b1d82339dffb7eb74cd800e1ed8f71aacc66b6fa67613e82e40f522e662fc27604e129ca42c311e4994711e143459d21c89e07a7d14c02a85abbdbf2e32f9b559d9f24a27a98b2521d39acd6c690b5 +eafcb4e1299d16e398fa574e354d79cdb9625797688faefaac2d4a29b23ef552823c7e19d22fef28e2c1a24c6bfa374063ee99fb069b97f8bc472af6d69ced556f13efea086266bdff71c1b4da8e4b3f85e1a72fcf562a70f198c7608328c9277d85247311acc83a98866a521b7fb9aa0a7f4043109746274b624d8dbefd4745 +c7e8eb5f561d14193634b83e7944b8149e67f8bef30702c3a04acff906d4481134d4755317cfbdc39043dfa9d7b4c0f98e5b01a4f50ef49c7d17ad7c4164d1bd9a504de03bd419b33980cb0d0938f0e6aef5a7e69c1da4a31b4e8398eb00208f0175bd1c4f46e4496580dfc26bd9ed2715a9672e144e07e49f44e91f68a0b8bd +f08ec66071a5b495fa35b81ebc06eaf3fcfeacb3fd78b753e5de57cdeee8be92bb77db13d1b62490f29e6c1821e54cd30d83b54cd9e9eefc349c7cb4333b67e692fd459ed9f2591166693dda538bc39084ddf85014a38b4df0e88350ced2cceab85fc2be8b14888889f7c2d5e9683674f40610855d77ea09f89d705ca753702d +c2140c54f9dbf6e1f412a27fb4d6c11b58434a1ece009dd1dd820ef05f59dc0da64f05d96be8b9d2b27c6f9f5e49cbccba9b16fe1babf5eee02fe432ad86c04182371d3514a36f416197b9524203c2919b2c79ad55467ecaa56095e3048830b63ccec9efe120272b6ed318804cdad84a62f99bb63464981f552c655babf51435 +d4b69020109685911be78c377d4bd7fec5443a91ea13266a0c8286b0f1289b6df4b3d451ae92c5dfc1c60c9ef38a381ec9257b65f984e1e364e6c060198f3e0823405aa93abd8ddb7daddbd1e467df6b7b749fb31e4edf88fef8d222de401a42bc180fc5c5dda9d7a494c8c88359072381727a59a3ee715035441595e622edc5 +d2b5c8d40f92c7f7af2933c5e7a120977d26637932c98ab9b034c53074ea38ed1279e7e71b062b8d140e3d499f96a2cf696980043611ce272475099dff5002bde2c6f9c936b4764e0adaeb84ac9554f81b8de3e195a56d9314660d6ec76438d6ed9c8a84a2cd1d08c50ca5d12392df85ccf70467ea0407a3985dbbee5293ce7d +d2cccb950749662ae7599688015675cbbbcf7966a03d22dc8af81f4258a1b78e9b9d7bf8b5d6983256a98af801721a139df8cfdcd29e576af1634a7c682e016acdb7a510d058d4514be5b50e733cb9d30c7b0bb33ea184a00f8b3871c72ae3bbb37d9238e2988fbbbce08c2d4a065d0c63e80c7cf40f15535eb55e4f50d360b5 +e81853fbc8f1fd6896a47a6e80539439cd9645e8b0ded1f5c554cf853e617bc0b411d15ca04bb9b22fabd4aa2226df4c119d59ce36ab116166dcaf03129c94f7db155e8638c8d309bfcd64fab7c77e6a35b3d2668a40f02618820f51a5ff241c8887066a45ff2fd930e1d5a6a18e9e9351adfa05dd462dc7c9382fc7494b54b5 +de9f654dde79f9170defd2ad8386a4ab535889fcefc088eeb1addf4aa45a01a0a4d583e40109a9637aaa8c7fcd5314570bef2ff3b8958e80f2fc146c71b3fd79ccd4d06d0a7be94eac5ccb5fd44695df6d78ee4dc7a9a6c51852b95219b9b296a10d5ddffb8f38ac5034351565caadc01881d3575709a0e9e818151852816bed +f89cae294cee1cceaf47188aaacab9ef8e42b584dc85456f370aa6d729e28d018da252093e35c555f242c44c40e1e531dc1f1fb4fc955ef4dcbb13a340adf0c7101e1afd8d11cc65993fe209ea8886855c132b6fc257e4190356375cb8bc004598415f51cf5d952707e42ac26c85c184990906c26f9215b9353a22cb82e2acbd +fa89c077b8fd463079fbb1c9c89b2891e6afc11380297be421cb5a7ff390385686879041f70358f1db73ebc8df6a494393f0303e5c560a3fa2aba714395a20398aa953dca5fde0d901e1bb617790e1f0094203b5b1ab164d86783955e5826fc803cb72c3c6bc77ee9477d3eb7df476e6df97a4b20e59facf160c2ad0f35beb95 +ebfc6e1f84e61274faaf64e51d06e188c3efad1947ba41027041b56e3a1c80dd71281759d7a75ec704e22d9e205673ad6a38f0fa0d936cac6e3c2754b1f0f12946f4ac36f3248880e2d7f57635e80cc27c12b8016864d02a04e5236f537eba37f7d4fc5b46af2d042702110c9f1ece18d74879f776e3b21bf76adcc8617e8fed +de9ad428d3d9b64ed58c7b59ae9fce61cb2c5ec3f95b5955341f67ce61c0db17394fbe596b5ed306a293c2ec9591b5f5bcea5b396bddbbf56f435edc1b4484de6310975688210197160c945b7ee3ebf6b7c9848318be0e45899d364fc67d4ffea82479fd5f672f8df5f89ba157ff7ce6953e9ecc685b5f50f629de639f372a7d +c87d59cbe55203e3b5ea1bee1489173612a0e52d9c366a7e09a0575b0e79ff5d07f3adcc468018a2ca24b974025d2b26220c2a110537de158dcdaf860e8e7e1685e47f8327ce81ad8244385c88c477add2c8b997b3014ffa32a952e179acebd87fa545e91d5a56d4a16e41e50ed5e3d5dbbbd7be870944b2984afc2d57607db5 +d82c4ed9f5670b8b68d2ad054794f78a0b3fdb32e88db4f72f75033983bd1884fa8bf5b3a1427805b2f4d4787b6a1547876a01c8a9c2c74799d5f7c6e0f0482967c02db243be59c78e4fa4f5a34e4895a07ffcca0ec3bd5f24048d10ec4e1bec3945d7280d8144b5672a76746f6c15e42970eb55c840687a915a464cf4b4795d +d500a754e5fad4d58a926c0d18159eade6b51ec72a6445cb782a9954c54176bd7d70d3a60fe5279757a739e6062eb9cfa83e3520e1964f59def2d9808b32da1468af321ba7be5a3bc619b5c75c636efaa86d360e8fa0675f3dcdc4438c417bb51902c9d3565e37c799fab1b94f17854ca143533795ebbcc614bca54f36959c4d +d4d9363f9db9a5e0bc14649810f5c435a731f6a3fffe42b24d8df6a6eedd5ad0562f17be5db9950d46407bb9dbba9f9a3ae29fe3cd6f8d04595ea26849bd35d49ee0e8359c47cf5776b51567c82ac6cef6bec5fc4e1d5f5e712a1a9e8b449e6a577a4104b385bbefeab0fa580ad8b5fe8712779b5391635f8fec655c59d656f5 +cfbd0ea0320f61a647b842dee1bddc13ec5de423c1be6fc590c31e8069884a5f87c37d7e0a2a2ac6fb34188f91bcba00e2b87b65002e2ee25461c2e2ed35a09d7914fd0779d3bb46748a530ace5c5006e200301b9e26d3d7738668b0b1fe5602b7579b7b4a904117010957e55daaba9baed75af81537ddff4d20f16351786c1d +d8c02acc14cc767fa7b05c3a06207d5c861262b850ba868193d9f82b7aec7d9cb656175af823171ae4c0776319a067daf1c7ff913432f4d0133c2b75076e800d6de11debcaf71f6113679e4bc16ee76a3de6b191f6d3cad0f9d2ec82cf415c8412fb2213f0ef13a67d3898ae4ae1166d439c9cf4b9e20f2c2df83319e042c3e5 +e09ab5e7d7b2e37af36a0efa852cf2dd2d0c3356d28a81a8d860745806998293b9c337c88bdcc1c20b41d26f50ce1db86a67c5b08d5bc7caf5082b1f6b9732f8fd6e362d6fc9f3c7dea1babd701a97b41c901320e21cad45dfacfbffd70f2d7484c2df74903b13cceb7c16a3b694c1f3e598185fdcc2fc57e2c6e5a37eb84dbd +e5f48e4163389097f7f2557916abcd1f9312212df0707edef38698f90010aa7b700da25b6c8d3b514d6446b4e91db6f8c17eae2819104f969f30a07e9112ca1ec98ac4461dccaf667a48a552a51a5eb1acbd7a75f0538ff2eb6d8bd2c3b320fccec7a318731274edb1a09b6116eae22be0f3fdc914e462d2575cca09f0ae3365 +e402a052a7a9b2cfa8242c5d82973bae666edb84875b46fc25f708d2b102ec88ffc81e775dd01ff7f80f86974fc5c628e3857827466858b6a8cf5b1609beb4ac5a2c295ea1f07b678a4c5f4c9a9279b91cd314b6bba8ea68243beba2754d4be2159ccc1937d8a65d79934e78fb70c26ef9aeb114cec8aea0c82cb5ede771f8bd +c71fff2a5b3ff0e26dc3822532912b9853215321f7c64f7d9c185021164778ccd16d948dc71373d5ada2dee3e8dc0f9c4504d013d5222e2a04b3c566c31959ca85aadb18a843de651a1280f28c3b171495cd3748d24b21e1d5c05bfabf7a718c88a6af4d4eba69abb4eb558c15ec988708d0e10131e8c7d0d11ea6c64423eb3d +d7cbf7cc537909068a0722855a09cf12b51530e87916e6c89696ae56e23e6fae0788e2bf78c6547bd121e333c76ea86ab23d732b793a2c402799162c44ce27951c1ea985ffcffd7b0f94242b295bdbaf3b8b7082066757d7d9b8c38e4134fb6006fcd89a00e4ecb97da349e5f9f93950e973ce136e0c5b07c4bb1e79fbca0485 +d864ee108f8b62a1d71199d384358b2db77aa201c67689fb2c3034e3eb7fae2fab138756a59809d330e55bd15f41451b1d106a25db63d9df8ddbe26798c03062f0f7dd8e1f1ae43fbec8ac08f919f348090a6b74abed675d9f55028fd9ac991a32ef3b12678d3bf7f6e63705cfde4ca9f0fa864f693e635502ff578828bfb70d +df728818bc24b802d4928b3fed26c687bf8d4da2af081b0a5b7e8408d0e1e2de2afd236decc06e8b58d43e064765535741273691c905a083424bf82ab2ae83563a7c00d43814220569aa54615e7205551bb79fcf36af9ea8c30799bc37e9ecdecb90355a92e5d9d62328059eea240b67e36573b51d11c9df248190839afccfcd +d740d1962a65467ddaafb33dcec0247d6a0d3815d7a4b1f3da3e8ed0ca75e19dc02b16a71dba5fa28d09f38ac61352e0a870f8bfa094b459f5bea40cf42fbb17567211fb0af831b0c2112154762650da96d76b73b58c460f837ab8f8918a2a081f7a04716d85a87f4676404b03b467781ace02ec88ec890464c13688dee050ad +e1762495c9983ae9e73ed7458e667553ad221d6e6b675764f89331005ce0186c6d308d3ef1f911244bf4ce0d588505f7b5559bbee448d8373c51c8ea98ed1f3b3d112f4fed7d560db106c96c5fcb6687779ec1f6f472a6703a70cbfd2d31d607ed5e2149d19204ccae35988684b60c54292091c6510e23e36653d3925b14b525 +f311353a315073e78a275aaabf28914051637a5cb165eb300498365c72c6d1e67bd2510916b31ad0518c52e79e19915d9a361624d4aae90e852ae780c1d43edcea4c27304fbc9c120fff5566e361d9d696c99fd01a09580526292e5f626a8318a6af6f34665971dffba3f676d64b4a9e3cd8d6601de4f049c54e6a69f4fb0d35 +c610a2f93bb2952f6173ffc5cfbac1fcb866c4a61d2d7ce84932b63e5d1cd84ff22f00bc64bcc134e012d0e960c022c20fd406e8b1ed4c50f74a684e081a347e8dd8530f8e4c8bce1eac6532738d067e04d30b74f594ceeba4fdc49c3bc92e5c002b63798edc61b7cfc4a83c8d8e264c094f4d68b81d3be22db9d1d63049989d +dc83d0f2c3f7f9c7fe861259e876a071245fff737b963c686b45d421f094e61df3659c9de88d764072995971fbc688f03c5ba77170ed1786b9aa91b312cc008a9d46cbf48328dcf7a8a3ea5a172b88e16a6de0635770f3cbc47fae8904dec0f998fd814a7415e9f8601938cfd23f38aa9c0972c5712651834a23627676d6d98d +f8a26d32aa3c0a5a555fd3d63856e2dd04a1621e7caa100d3d775c67d864a6f7fca4f0564f5866cea4b6ae6597c9e81c7a67ebc8e7cfead05a511bbe1aa998630e763e4bae47d05c98b6242b32511260fa834b5912970b94ddd996bb712d361c2ed4117a6a7e53543b9b8911eacccfcb4d58d7d4b60d8f4b261b0a426125619d +da00566848c01f70b68f38c714ef36b49121604e951988e32e30b0649b15e5732918c5c7d830bc081a2b1bb3a16340e9fe8e6b4683734fff68c018e85f58f1ff30b54cb047e6abf634efcbdf080f6438e4817fdcc4c10f3003d8528502704c09e99b6a65ce88c100164e9931f4ba544c3deb5690357a0bf5f1cd9b5c6f5f9bed +fa5a96c584235b346dfa9355e3fef370e71edbc85826c3c202b460fe60c72a460c1d0aa5a4668ee910e8058c6ddc20e1f30f5b6a369cc5e2e262001388fecdfb030a01dfcc830f8095e808c439e32c1c22666b81f5c061ee279069c67efa9f905ecd04261da47539e10d1545d76f602acc4eed83275755523d8107dced594d8d +c9c78f76f133f80c60cb1ad3413b7c40afa5da7859ca268b899a75ed06f09d85dc62d054d50d9b2f060f1930bd150e6b0c7e71a2bf0fcf3d02c7425ed17a0b3673d3f4f9437c8375302c8c5f35d8409bccf4eec3438d7d0aab52c25be9706fd376d91cf1e2cd43ba19a07b76dabdeeb2650115499630fd7458aa2d42e128051d +f05036e195b7ff5750867782fe51d704d8717cb0c9ee23d598fa0d2d7db8f1105685495cb095a05a9557ca4dc8fd7948dcf362715637bfb171e5038217469bb646029155af6e83821d82d50a4c8064a2496778e8c073fca484d2d2367c52bf39cdd98f1f2bff5c2362f79ccf871a70db99a404d33b1fe6615d9dcf64b2b2286d +e6389326de9873443429aa1213f8f39322c4dec5f62d5b4fb938db5ef185adcdb29f5d4acaa7b784fbf9abadac995e43b5298c2a06f34c681e08e29d100f240676c8d798b141335afa8fa06e8e102edcd542318dfa190c981be80058855125b1e1bc4e860864a6b2daad46293d166e5ac6d33634e6157731aab64406aa198775 +e28708b6c2ef0e6eb7854970f88cf767a58ef73422bacbe3c74e208b22133ba36ba266c56ed44893fddc0ab3037933fd4d174d9de58fa00fc1a239cf44fd3f53775df9b04aff3c3daef9955480fb6b01374499d0b263952c3759f292455f720274fd892755a58d6cccfed87fe7dd9edc9c75a554cd1921b7eab0acd38836558d +cfe5a09a3363e7fcbb97280be6f5bcef49295b3a2b724d8f11e5eadc42e0f58370fcaee7ce6024972e66fa40afaa26c4762281dce1744664aceb4a80bd356a282d42dcb3e8f3ab25ff9c98d7a06e41db8b1ffa1ce4b878b18c9b06bfdb14a0170af5d2895a125314e2f36b8d3b75e5b6af12b1c7ae99e87ff942bf5723993ea5 +dba8a5680de66065714e55eec51efe354ea04fb3e796023739930227f513f003a03d8d0b70280da58867a8cbc25bec56be3ee98c251185d0182c656246380d6088ba4f37b6440eb8c1646d448e34909e17b4c51ec5696058b87ea9182b509a963e5b2f6b6c1ed0b70c99ad3635338b956951c47fedba1f39681e05cd7bd8d7b5 +cec8ffc8e7c03f70b83775d4a2d3eb6c2949fa9b9deef69c1a698d1ea5aa1e090e7a7a35ccc51b160a94a997409ebd82043b0a6ac7461556118b61305ba9006887d4c0b603ac1649e489380ffa7f4972e8fddaa959811aff55e70e34674a5281525b9ae0750aa69d531d73a8ef7e8aabfe373d66a752877a428fca260093cb3d +d90b40ff3961fdc0b9bd0890d9d6ce6f58f45720b6e46c97ebd876e248a054027c40fa9a1a6b123f1d119ffac30f60a836b558bae286b768926d82ba6bdc5c6c115e76975cd2e9f282e165e434229083fc57f2a025e8de756b01ce83f011e7ac82a0c4a995a6efe6878f2ec937b2b642cac433fadbe6bc05d4d94cf1621b9de5 +c51983be4bf08d37e6bbcfcaea856bb66581438a118537014b3812b01cd7b482b8192d03c21c3e15dc61dda8e729353ac22791ecf4d197ddc7d57b1063ff80e0c6dc6570a2088f670f2a401bad33baec2490941b68c72f2c99f3f9ffae478e3f253c4bc2a5d5df040155da0a484421a0aa061fcc12b5178ca4cbc5494383e0bd +eae065f0dd770e127b9747e3f5d89d33c7094ac37ba2ccbc63dfd7d4f2f208d6500ea8e38d6072e6716a4899dbcbccaf0b72b8812e34a699c6605ec008d8eb58a27ca1e1ab0500bce2dd236af669c53469d658cb7681355d172b65f496871b04d16b83c512858b70f4fbbf9557d51397278b13a922031160c1131b10c3c32b55 +d7543c8648c0a7230ec35252d0e9f4ab6d281cae438670a969728f53b5867fc7120110a1be83d4d4a7f95bae092b85bb37adb630db5524747db6bc3f350fda33ea8539e14b31425e3b099b241439efedc44f0c99a1975b6f545dafb4edaea8c395d00c9dd613a1cbf80d755df8a2d614ec5e5e83562d28a6e739b2bebe3c6c8d +ce98fe4c3e7791ddefcd1b9d35275bd2c1f98500ca0e533aa6fdd1752162852a212a60d1278677fc4b2bc2a32a7e67518c1e8f98fffd3e3bbdee1e4999b36f31cafb59ad586796fa40e5d5f96233dd3e8dd5380dbedba349d529d5ffc763f091fb1a1fdc5b012de244fe3517dee4bbb53a5e89717491a689caacee4a21ccf8a5 +e44142ef41cd39b3bec3bc40d7b8979cb700ee9ff6316feeba9c64ea173ea3af565bb7525929f247e13c5e8d7dee841be0f2752a20c1ccaa019dfc26feedd45fbc601cae0f2b6f170be95216ec176ad746df2b1cb3b49d8ceb9ffdb48de1aaa1ca1fc7cdd7cd6f1ad7392f3a1ed5536a82db646c4c029d10c2545d8655697a25 +d24c24ef31e65a1cbb3418e1a091398c92ad8fe1022a13e90d232aeec05e2021651a774d3bf5700139dfc523b4980e9f287d7f2dc5271db70dcf5e3ae6b12b15e057674a13e5c106975d0b98da8edc756c3a038c95d8bac78a0bd9d59b64a5d65ba3d2eba47a729570b9943a74f1d6838f97a461921854c45f0a55afce001865 +f53009a9c7023f570bb32b16c64df08b5e473ad7a4695479ff799aaadcfe15336c2c41d2d9b4436eab9c51a3f8b46f82f151d10d01e7c23f1d2413e166243a60c30aa686a9d79fd7a06694b56e62eab2e9a38334c95cba056a7e354c9efa052fc5abca6113608bea0654857f608366e3637a46ac63da1ac9bcec8575ba391f7d +effdf430fe6cf83e9ab57fa9af31038676bd7efb035fbd4929e305c88c2e86a9d7fc7d1984255b400a4e3ba69b9c039aea84c3bfc539954ea966b174c7e904968cc3594e62caa9d495b379c69f4be4dab289f9560bb82d86d093dc07c828adeeac564c3afc43a91799e74746b6034937f25a7ffd47a2e95f5efcf216fd6e30f5 +fd312c2d37a7f9bc5747c85cce2bb9b3f11faee8eb0cf9eabb5e2b985b6d79c0be0542b83f730f9b0a7d844c96641ca2c646ab162af73ece2b3dd2b5920746083e48e9bc2aeed08b73129d75aa20118a1ec0f4373403c5a82fc1be24a2d53ae8e127bff6fb842d9365746325e1ff6b825bca1b10bcc44fcb7753cd93b4e7da4d +e19bae43e71c102ec61906cfbe7a1c50ff4f517f9500a647a3d138517eaa32df011a944bcb30fb399844cb8b24c4af8e33d893e002efe6d9513e8279a08e2f0d6343387e181cd287459605999280c964b8e4d1eba55c5476dee6970c4405a9872451bdd013ed58cac1d619b88300e50f83922038a96dac937799bc86de1d8fdd +e45af63733bea0ce335617f63969fef91160902dd6ee6208183a5bb57d91d5ea2a1180b90c5b154f7aefcb4ad2b2229455bc2c4c6abf9bdefce1ab45d2692964779cb7461b85c2c81c6e09eab23eeb00a0aa6bff717d3dcdac23d7a1f8fb1dde321227538cb0a22439b81706dcde9aa697694e421d6ac4cec47f7d585eb1b5e5 +c02e43d1b9223510d290d7eb00a1e7836ae45a4930970651850804396627c634be76b272642b4f9eb9732f3f91635761b708cf52d797fabea83cd640f2e4cc85dcf358ad9f58573ce0a663e3a4dc4b35b3a9e4cba2af9eb34886bd67e09249cae43c1c99419fec69368e7be280d31df88022a062eca2915007d3eec666a19555 +d01d138ec72d3cc8be8a256213d130ddc88ac122f45ce1b8816a6bd828a4881daea455646f470dc5af804ca7e8bfe83944e59f3e625c1de06f86fe8867e50444ce019ed0bbf82a020139bd0bf8a4b0558182d5867c07b1081fd831326e7241908c9c83e459459721c5dfbcc85ab9a4bab4c729f30ccf9031ffc7204264c6468d +fd3915bebfdf090a857dba66cd39ad8c087cd94fbd3127cda816cff9764c6b402f3995f642d85bd820961960188619a4c1b3ba044bbd95ce38aa1c9c53a72d2da6cf8098b63e9e98f8f7293999cf7f061cd8d38b8062bba16dc9a8d1a499a02746478c5b670394e855fedb6e315ee1261fd8f18e40ff50d3821f6d9a5add7a2d +f5ac41e9861e7b80125fcc26557f0fa67cc1d1e2d1afff1bb0dd9e19287ff65b21a276021d0ab8958abe508879f38e91b46414c99fad0b6d301bef9dc68540cc0678adde95b7cbd238840ebfd274d4b0853323f19c625c2996bfc1740e88a5d098c7c9d4659321d5f6d04b5d4bc4eeec9e6aa598b4538cf876d5a475f90b142d +d58d247519881bc39adb7e9ccd1b8ab178c43b5858852d84b0f80f071559af43997a191d1f17ecd5ab37e78beb22d954dc469e7d6b457dffc05f0b908cc526c50e36c484bfdd037a8bd59afe13066cd2c93dbaeda276da3cc8a1404ecdeeef6624494decaca9bc2052ad9d5f1a699d739e2f5972e68002fdc38b850e77a56515 +c6877d5d0212ca82b394c8ab47464c59483bf1868ccb2cb1661545659a65eac46aee551b09f1e465b3169d2eb90ed643143e982d394e9dfdccab3a5917ea2b4e631a828aac0caa24bf3324b1de5484844f176975d93bc5a3b4d457dcd39d0aaa5d29ebb4207e03009ac30160faa29795e9f95338614bed64634c1572bb91ba2d +eb4a8bc143dd915e59c99a1469225be57b152e6fb804e948e7acfb6b36b10eabe0383aff8f9fccd65ea336b6c1427fe88bfb88d4b1265842375c8be6db4620eea2b45c9cbcad7db53470e1df13cbc19017951cfb693c4deaeb932450ade0b22fb5f8189ab090278ee1d28504a5483976d28955adbcc71fc18e6544433ff5c035 +d4a71ec4350f51d22b5546c6d7d6d07f1160b41866101ad847c412c39c84ff052d78cd5e2084c4e6e6f85889eb8e3084a6b0a60d9088b42ceeadb7a0bbb9366d5bbf89814c1b7a4045761d0b16778b0b1e9a8ba1b5a6d1139e52019978ff31ad93963f75ed98ba544ba7805437177876b37f2b7560314af5511c2cb43d8fabe5 +e5a5b5a02380762d273a3d808abf781b6409955e69ee510137bed632f18843deebd4d7f81f45913f57b7f1681cc9731eee76ba99f5fd0da8b2b2bacb15dd9ca9df53b5e758f0b8ce323ca7131d1cf675823ebceadf9f9a816eea392adb963557e28c29d966dc24c29147d59afb9db9561aa9cf200ea3a7ef284dbdb9c4b43d75 +e2399769327dd44829b3915999a66e29d023b82e52606001bf07cf1de15b2cb2685431a0167845fbcd06b8e7cfb6ba78dd8aed5edb44bc7c4935e5feb2ab44c1a35bf97dd24967b21b725a39260b32fede553f678c4cf07b0d4a1f23dcf34a75f49f0bc5b10ea517df13cc57aa11d89c00b23142d07ca274238c3dea132e0545 +d08343b82cda4e6743a5750db867698a28d55d3bf763b12b20b5096979be7a8d82dacb50c9cac513d3bf35adf608b1001723cadcec167ed6400014afea8aeac3f4f9e30e8ee46d740ff202c6236a8a85d75b618d291a081e5e145a07174bf2b3099f140cdd5c656670b5ad209b82a6d751a85a91da8c871ed3843647fa5962b5 +f19d08d244ae38b667a3eafc49ecc02c57ed3765a9b6f5e6df373dcaa34d184727e1e7e2d67f2463945ff05b4cdd28251e02fb979b08cf4110cdb4fa5349e74572bbbc661079a631e1fd4978942b7acc46888865b2fc5304d959f9c389eec03bca5a67b8eb9c85fdf381eccae9235e11aa4cb3bd670ef4d0a695a60c9f345bc5 +ea9733f219602bd2f8b57835c0260e5729c33d805e92768558b76ed0c434c1941ea514a0f636bbe6a62a954ff288d61a617958157231b0e51df8e585dac28cfb49260908c10a561c47cfeb6765a383f28e8a2640301e99ff6f22ad8b310938fe9bdfb1dbc1f977936d31ca524228e047b9771d73bf7f1274dd4c8d3c1d8d725d +ccdc84ffdee0c939b3428220f15ffc02333ba05373bf34461403d5087462ca6e33716806c61f68722dc19016bb168f10c0564a6838ba72e90db7a7e53561ef725a4b2d2fd46642b478c7431c0ef4f867ac42ad9adb88c4cb3c49556d4bcd48c553240099f27d91176bef4260e76b33ea684330384d997d8d863c199e5d2fa12d +fc8dbe56db6199481e0e7b536a7b11d1dfc6725f8c9904d20c26ad95f95c45558e2d4925215493052c3a1922d0746777fec9b10564a2a9352fe6367a089545f54cf1ac34204f683907c4c43faf300e42d21a07cbbd91dc6a2e7ec1182a4d43573b71b1a6e6889b24610e873fabaa71f25224eaeba4c431bcb20e196ec7ca2dfd +f8d0fbe2244f8917d1f3a0f276062d4f55386a924b2c43c027155a604e2b13d97c8c02cbf081b36a7014139626a553ba32b44aaab79b4b32206233256c8e7e4c8084bbff1e98e877a42d39b9ae2a27fbb89a374d1ed342864c4de01c15bf7832c1f1a7e367899e7cda988aaa46e8dd199de7bf596312febcb8ee78fb167cd6ad +f521cf6c8ee30acf897098cc12b22b02fb9413ba7b453b09ee30c1a9054ce49913b0be04caec5215668251b09db8beb273ef6cb98a7d832a8262c9fe0008652000dfa184f138b6087d79ddf3addb92a7b5af54f143eef7e3fa9e1e136add0c4259306dc3853b3cb9f55b341389609adc23ab0774ea48f0cd95ff9cd243e12b85 +e9f9e5446698aea25c754a3a109bf6a98d19b9d8b70254afa85c6c5bab62d1ab9db2a5901b8310fbdf00851bc1d57c6f5e5af582f4bfe3a67a961398f259a08f176c1062cac3b919cea6616b1f35319b844cf9a97a47eb166aa5f470b7a5bbeee6b051f69181f9c8d75ab71118f6459f1ba6c49b41f555f3c36ff562f8734fed +cf0da6581432e2b9bd38e4bb9d6497e3e09ddc23915531002cb1006271692ae28bbca7051ead4ebc16471028679b7454879400ba245cb4af1d7b4f5c41ba8278c6450a58f22dca5df7ebe945e67834012d064645dbfef5084f2567abb2a13944ea141e50fa4ed460295d90ef40d0bf5b0a1b2af8e8c4e9d52e34c2f707b2d675 +fc98b4b70d654a1aa86a64aa10a13db39bcb025a0c9dbf572dc1df22ebe96f155df7a1d624e85387e90cf6c763a32bd955dfa0ed99f37ad71aac4f8570d7a0ccf881b6cc4fcb91a62e1cd60488048294fe2dba071bca8689ca63e07771537c7e36deb5f0205a58d041fe6102e81918aeda2b9752b0d136efd49b71a98c7cdd7d +cbfc166895123f56dd9f5f4844b8a1f566082862f6a7cd0b425e1e90f92e129d64217e3f755923ce47572e2e8b1297aedcf3044c263feec5517caef9657698c3b75d6b257ac61dd60da87aca05da46a840c661963f423b5c76e5812741d54a1793f1e16f1d134d3196cfa670ee8d62a691214648cdef7d12db935da44787aa45 +d258d504c6f3d59ccd8dca3ce517279a027fe433d71e16f389852e341deba5eb2c94dcf8714687e7b6a6322ad390adf5e08942568c02a5e586d49011458f2c823d54a859a03e82410dd602ab3b5ad526e77f54b735065fdcdfe6c1657e31878e6d15689b23e1e079175ff683ac53a611a74032269477b5ea00e2a087cfcf2e4d +f611da44eccba932fc27d436d8ee762e3757744e1b2f0edaf8a7c63afe45675a19f695cb1fbb547ab2e3e5d00c804d8efaaea6f60ae35a5e338e5a648927bbf1fb7242898b376e0f66670ae2c0f16d75fe9279dc97015822725d617d09909d04bb4c48d097defeb5c9de928b0747715637dde13b23a37f97483bd87cee7a9f05 +f748f838957c169a4bcd35da0205727f4e036733a6ba5200cdf695c7a46124b6cb39b876354253d7394f9e3460ae9175e82da7771c9a0b2c812d442e66fc49f2c0ef5c4de0175bc32ecf2a072bdc852aac303923d40e0853e0774c7cc7d3eb6ac6bbc63bcefea3da62aee1d630acf23ca7eb4d0923451d19eb2638abb4dc26bd +eae5a4efe1e981d4ed08ae37b694f24b0e6c16c6991f3d88265accfc88803fd7a51498d9f6cfe2bfa5bd4948ef82ecb87da6b1221495cb117f0a5312284ff3678ed7d640ef2ed7b19e348e7a0bd694dc28196781d2475c45d6252ea2ccb443e1860df490867eb607127e2472c222d7bb36abf85aeaede667decae255dc43348d +e8a6152e7462c848d36f38e356c47d268b763542a5665465e4fc00c57a391bf5a735b808af29b9ba29144e93828a9f10df2aa2a198a767aab846614035963d7175d320e7aca496a8e57784857dcc10b571823526bbae7fa16102b1fe174ee3719b0e9f0b1578bfebbc7b77dd3658ade9d1bd6cad35bde306c01f9a43dd168425 +dce3db498d870b98be37fd5908c1a3f9b80372540bb627ab5f3860fdae340512b848d888d31943c45da506683ed373f9dfb078ad441c4a3445bc0b6c290ac4a53fdd53d758503684628ad1722d5d27d306cf22767c3ccb82d6be665622a6c1614e78e4079b3d537276b4ed16dcb2daf1ae2fd3b7301830ca7f18ee10d5578c65 +dc0262673ff106b22fd8f7b0e954504681bff6492f0d76c4813a8beff028377a21696e04a1875ba357e5a21ef720b22c6da618375d5dbb40677629e5d1f197ef880297cfc735eb7c16b1480e7fc437883118c2a17ff7a9adf24415c6fa80c2540756e73c3cb313a1b7fcb58f4ccdd2f481a528ef30c413594146d86e508c596d +c31f4efa0071274e62c6ad18672d29e8d0a34ddd87332c090b19c48140e531ae99fb16c0e66ef1e9258d417dec22be932eee3e8e2d2d1e32f83714f815903b348a52cc583c6376384b81520427f7ec1a93174885da96c8fe5b6f4d2023936fbd216b67f8e0314b6555c38d245acd5aeb83d7b05359f54171f356a9dab4b07715 +cfdcc840aaf8bdd98c4274ace9f46d8036df8ebbf027c22c22887f7804c93d6dc578659abd3d28a6a5f8ad889645c7e2b56057a3666467734183fa59e703fadd01cc2b08909f76a39d06eb3c06975e9b57f67c3517478af4a4457604962eb656920bb228633040bded473f06f055a46045ac54c2c63d109b515e360e5095613d +cd789dbf2f41a8cae05aadf109ead16729ca86da3a303d3b4ac05ccbf016a4f09e18226a6fbd0698c2f9d52fb37baa4b2427278fbe50d64c791a0ecdec22a1b97294f8a21807d82ec09ab91bd3fafc1a79b9e7da27cc7448813975a165ea18771367896046eb9924b358263c279fed1baf36be8bd82ce49de66a304a7807a505 +fb5fcf913fd6acb1fe6a6fa1cfe623631b3eacb0fb1af53b822a2ffb0bbee8cf544bea5ff17cfe897148470a928fa9290b35a487b8db43e2aedf67efe174b71409c8b15e769bff98888f2a69b3fe93d6e958cc0b185ea58ec5ebda005219446eb55d0736ad2ad32cf4cd580e60d25e26f1e792e637c3ac528fbdf1501cd3851d +d7216df66b03f51eaabd1e945db039ee72fbef1ea3f79846d46ab083ca02d74d7068054ac05d5ee5b90ba84c81f9cad3a969945f7d4ba547c8cdf42de47f95542f886d33f1a6ce7172db2fa72b5daac85462027c9d0aa1ed855b7dc1aad537935f30469beaccd3248dc1b8399f8cf627fa548b03a01c33e9d1238681574d937d +c28409f6abdb5ea38bc20f01eec110058cb90a07c1063f69ce8170cf8879ef8679b25965f2c985371fb7b40a2298e8cf61aefc062090ed32dd7477a99f775e39bbbeeb243b4c2b90d1c6bee88647e595e390e3a0a3d2a2890fc1e5fbc1299d63583170fd614ebaaefaf08e9ad323342c9acdf0dbfe2150f89eca4402499ca4f5 +f135258dfa7b82b185b48a111e343b46830ba562a63f53e1ef0a0cedce0d8b6e3e9323c3cceecd577d859f5659e6365085036ca7f15e75fb2fdb5f8d0819c8454f948309b2571237dfa5d08275182d55786efa8a274c5ac6641563bbf115ecf4f8cdf24b5bde89b90490c72a67fd5ff2f61d92015d4d53b5af3c48aee33838dd +dd23c15c71c7be2ed8d55fc98cb7b00269a3ca2f93ce801013fc77b7aab1917bfab2133dea01e0581ffc8481218eb7097f5ceb0167c1f223c387088f2c2d108b06d2bd1ff68e4255f4cf5508a067fa895fa27d9739bf7be72e661fa69163638a04766d8f9d07fabdcf010cf02f421ba893c7ced966627b5c6739bd2e70613fdd +f542781d273191506f5b5db33aae73a25facdde2967d84f1ea53e0fa98d43fbbec42401cbe771f71e1d1a0d8f48680739fbefc1f701546e856cb7bdd57c65f96aa4d686b9af695aac3b6ae92742d8ade5f6f4574aa60773b6c01f533dccc720d9ba285c04013a627fc0a7fb26f0ea48482e94d0f89437ad9a531cba372233145 +ee4e65895d9283d8717a958c088cf3bdb836ed38f4c6eaa9b9051739a1de986781e90ffd268674aceab08e95b2d0d7505619b9fad815876972f3391ce66b8645370c4050cbb8084f97c4eb7ee7dd85d5eeb8cc4eeb6917984a8bcf36f2539fbad5618b6a80e1409e48cdbab7bfef14d628d1028169fb6787b98a38920a558115 +f34ea6ca038a7aeed8f446b56b1ea9a175e082f8a03e0b764bef95a9e255a27454d4018f697c91f76a588e31dae7a9f9eb18925aeb19ddfcfb0b5cf6cfe253c643f3bf541015b3a0fede9629638c49c81650b8ee9cbe1026e04886a689e0033980a3c364069dc03dba3154da56807b325ddd96412960c64e915a5fba57e657f5 +faea3f46d8d6236c5257177d6f27bd2ff7a2312d54512c5cdedaa96effe4810c216e39075136577c91b2e0022f32ab111acb05f8a9b051c9d11fba8fb708b1e8b8154d8f3d6566a52efbfc0d8414b1162b435bd6b409382e1b34fb3d92615b887be1ad050578978012aaa5192a8cc4612d29bda58989bc50b837592ec327318d +c8094fb8e642491e29d3cfb5f0b214255838b38635f637dc8fff89ecfceed440300a2cd3553633d927d88145109973923a89b427cfa4634f77372938355217dbe7c19ef20121b4e213ec86a790ba4e867dd45fe83fa0a51cfb28fcbef983ff0c3c4a3e8dacbd3eb5a8e2b46a571e000435e7d871e8f932d4b56a808ed9a4dabd +c4f4ebe55a4f83579e37ba2779811b10775250d36bb5876ca8cfa896c53c8ff65be9689fd68a8a39281d053e740bebea27fd781f0b3ab5be3f40308d6998cc5a95f1d5cc095e7896825c6e0504139cc5f2438ae85a048daf28a1698538bcab8231a8bf449b1e1815b442be1eb1abd9019d0058b18e118256be7a70293e133b3d +f712ecdb5544ce9d3c146f317d4850dfe9bfa1b45a9d4d19dc9ab459c592274c282edcb33ad398aeb22e6e41b72670a0a4b0373c73c829570a0acb8caf1c7034d46e849a6be96db32e2f99bf0e0382920b6503a8bdc7acaa801c69ac6f0192b9c8293c7bb79f3c5ca82bb3452b3a314419e0b53f72867048710a7e02f4aea76d +fdabbf57b9d9a703eb7f9d698055cac6e6a541a1878222839a7813b84d7cfb75a25eca26df09d2cd42099ebc2269e7ddc60612f5e3fbcfb152036ed3cb83c56a552aff9ebb00a356705f3a4ce9100a805b9ea0527065b48ad0f6655f342fecc35aae1a715a3e00fd02bf177d352923117599d3ff30828a0c57fa650116df7075 +dce3548054466fabb408c58cab550ebfd604967bc785844da99e08a5e03fcc84a973288fcc3cfdcadf7e3d7f0a13d1146189713658c1c32a43eba7a84e7742c1c988acd1aea84acd4ba0dc7d87e3711933289c2effcdde2570684cf3adff3b54f15350ed40af0a1bf0aec47d77148e1937c9762abdf9c7820bb2626d4a6ba985 +f086ad1a65ac4b2afd897d1bb7895ec8ab5477b96d4fe6b06128515843c5584f5b8d3f4b5ae3deecd0719d3a772df47b37a8d938710edc57d5bfce58b7e415b4c57f623f5e50d456736667180b0a08cf0372f696d65f013cdd7a1a2e4dcbdeeb0bb1584ac7383da048cd518ecd9a3b5e7c896311abe96793041de812366fd6cd +c95ea65ce5be0a626740d2fbbd4df61913a5eb682419831b9709912d2d2176ae51f8d23b685eaa15eaa4fe76859ad148f6a2407b1d4461bda13a8ed337e9646259be2000010b2ccabc5b81151f7c59766898659d80144f36c4f4d2dddfb3b72d9c96b1e59e6767b64e046bd6ea612fe45434b68cc7b71bfe3b1936d2873aae2d +e50160abeb3931d7740cb48a3aa0681453c31eb3983a7cabf94cb581ed81ea7b1cca9c2157d562e63cd30e572e25f56aeb3102ebbf7e9e86e1c70da9d7119e7917536b375527fc6ecb2266c1264df2823355c8a7f3201ee8bfff6a1886b5bbd4b05dc78a7425d6236800732d0b7875b59417f0ef62641fb1a48f9b2f4ea92dfd +e4d5215833bed28784a0ad5dd2869b97ae32d0f6ca5f4333e5df45a4135ae61576a83161d03229ad935812fbee75d4f8b5e9e9444a25332855af2265c9107c24a048caee053ddd72b0d3adf16ee669f8f8cf1ae84a65fb947f0843ccf76ac641ff1ac98464cd36d80b243c2ec15cb8a6fad3e45435e503d4144892ebf74774ad +efe9f954c6f3a607b54fd893c9ca2fda5df4614d830053248900f58fd3ecdcc1ad994c55b1739b476ac8bb6d19aac6cfcf987f2fee4d0187461318e6a10fdf3b5936013bd11c582c49f2ad1d09d1ee9460183f45a22aa42c02bc940be4170fbf8e205c87e8c64943b840562ec7db4ae337b1f0f977fde638d8dcea9dbd9f5cb5 +cc4937af80e67e580d30ee54f7948481213053a49c27dc0dfdbdbc5afe79b50f103492daad1cad29667f5b45f3983311f4a3d769fa7e3493e5fd8f9584a3942191104198de7a77e978671a2af406ba6accf1e8ff883166e29ddb00823cd1d4d6689d287bf7d0d511735609668557beafec9d6546bdc3fb631c474eec3e2f26c5 +f935bebb45a3b09d044ee922c36f6a0066e8668b4717c5f21cbc18a36d311caef071995cebb139b39c5077ff3bd5a527f858c545349bf3f50dc0323bd71835e1685a913f98d314c85ec1312ed0ba310187148ae6988497e508e00c0ef1bc72023c91ec8ed528ddf1ec8edce3ead3e88a05a51bb7ebdc1fac29cf596cbaa49c55 +fc26c66972bc7b013f0b879557e341a1ab9b05fba4a5580e9607358674359856e13a1439756614bd6600202cd18f932f737e839fda6427945750345f7070a1e317d391816d58e1500d96188087174df8970cbf8c7c4359da09a143084871079cfe68f5b6470e9eb6b8508ee4b8baa271fd1993203b0f71d074c3bea1b31cd1dd +cee883ffeb32eae7594cfbc23d3cbd5b37c72da6dd7d3d5bfb286f7dbe460ac3b6043f78cadf14715b656dfa92d421958c8acfb43194078759c058565ca181b32c327b94a9086011b5952ebedc80d0e8ad8e66f84ea9d9677e19c2424e122f3c8d987072322f24c5de5ca61b5abc7f0aeffa26972a7a2d241defbaf7af8ede45 +d01046b4fe46abf9b099573273cf61303301689d00de860f94acaa64838d76f25365bed14039eb287e24ddc34a07c183f6a2a81392fba7d6e1d4e0602932ae13339de5a788900a96d58fa25042c7568fbf8939ab65a5e47320b03ddb72091895056d659677ad22ba1ce6088ad515247327ceb49fc5e223d3e828050c5ee8a155 +d1f9a4c8b9d2d6c6ae0d928fd5c2c6fbc78d056c6804223788fbf1f9990298a9fb0ac57d85dfe1d1590c617212d717b292e2dff15279b973f03eca220b76c5cb1b699b49221e91a88b0619384df979f21ef63a5b72ed20c533388ba23d96b6d852490c5837955aed263f56eb862bdb50cbda07c65417b25864bedb6cc6cc39cd +c477431e31e33ad6357203152d48df7537ee7d4343dde4580bfce608d0b07725edbf7e16d5a6ad8ddd79ebff06905225322e7ecf86cf2e9d6cc141caeccdbe4c24babad2da9eb6f696620f056a42579cb5218c1acaccce5a1b3a76dc4110acd74829a31d373825e31cfec03a58102044845d8997b9ed93bd1e5ea96e081d1015 +c29d8fc580e7ce4685181a7c43c82620a6eadff437952b73b655b0683283561f067583447debd62a16b7e55b8dd6d4d2f61a99165006d04576025129c027f2af7dd2d88d7f1faec453d96bb34ad50c4a1726406f2cd50cd45c6cb670cc97d6a0809b556cee10c08759b9b36344aa8627ffb9c67b159664678ebe6b131e124f75 +d64fc2f28b0bbbe44bd528770722849281433f156ca40cc2722d4bc18df19e48181cc7bb7265a68407c8048e95f0aa88706bba6d9b7bc9e78d54b4ac028a96b99813e514dfc032f436ee7d284ca3d4403ba94ca5a93707a20fbc72d0897d3fffbce43e252a7d3e53ab66993cb2e1fa02120c4897dbe444441a63e2f7bcde3a2d +ce6dc18edb75b0a352738d0292c22d924c813c1a9abddc00cdf4592879b566e30d9e98277f96410b2db488a96262e32fc1d104e776db8a10a931f98524fc7fda19b3867910614835fca01a02241ad34dd02719ff37e980df15c16ad99b1321ca7c375eee6569894fa9a07e9f4d7b0b49de1586d2b2243b2c50981d8d1e76ffc5 +c7a9dca1332f1c903d260c67444f62c9cf1d8b53e283199bb0c2eb84a72dc800557709e0d77cbb5ba76b01176406814073b633bd56af3bfc89b8d499480cef7e7355dc78cc58a8a9f11f8221ca79cbf32a25c75f393cf8dce9d45218b1280595f2f496539b6ba9e3972c08c7b9d0732fe9488754a6f4555cabc331dc634dc0b5 +d652d68072085772edc617f0114a69dfec0cf4bd7f7cd50160d9d8852e3672e013522075e2a0fea5f6c0418cb61941ef1ac6bfe3021d68f710a723fff5f423509f75a4b8094dc4f753c791120148ae4d0ae44bb09d09529cc6d29388a5e90cb5df5a3c23ca6f559c72255f8f1db04eb00fa36143a95b8e43bd71172d9363387d +d34134232eb029ceed44cce495cccd5bb84406f5dc027b2901cb3b57f201a619828bb4dd7331f393430a9e1a2c0ba039c4cd8895d5c1c554ec9b48ec5c1ba98d29fb53cbcea1a479afa55f1fc5f00c1d086441af41a833bef4758b7c65c9dd8c2b34cc1fc63c8d558f72d9736c858cf6e182fd4140036e9b590958f580787abd +d95d11a752f12c2d04e41d0bd2813dbea2272e49cd943c72993e38a88f32448105e1cb3816daae65d7486f69b6f7a6f28eef4a5cd5e4ad28b47246895f5b79ad4aa4a73b0328cbdd1999876ed8908d5192ba68bc0a446919081b64bb91b299c021cf2f9609503fa802d86545a831e39a8c4cc775362f73a3c6d1214ebf7c7bfd +e59903fd4b578592a5d6d706264846e17127732a16af4104235850e06e78f22d900d8d427d30b4d6c74dd4d1f90e0abf1ff0f17cc8cfcc9dbf910f90a0518364634fca337aab25faffabec1a7af9f4154e10434acdb0b5d1ee705c198d0f2bca3ae5b32b15b91883e87ece116d6b0bb1afa564d3846715a8b3eb0521ee3bea5d +e90a1f94595c3a7bd75b90b5b6cb021e32090affb36bc094470886dad266cca4c057e48480d92be364d02961b7c88992dd3010fa94f8189be92241beb96bc3a2b0b97e3b0a88060b0e2f17bf0458b64ba357f89a33c6e5c0f0b0905f9eaa1ea5e5d492e4c54c5c4fcbdcc41d546809acdc26e5bb46b53ed95e548ae261db0f15 +c0bf25c067104f867cc0f8e86553c2d46c9dec62a16c5472fc88261d0c557109575afd749dc3cf060b31fe5c25255db5c5b428b46d23c5972e0e3c1897b97876ce743da8ad0ea9ad00a10d0f6b211ef125cf861b17b9ca21bcfced9aef4392c9728cee93b61a02a6725b3fe92804742231a2589a93bb115299cbe571e8188485 +fce11de71e18c85d152046211cf5d57be81b26abf687d094816d5b1bc16e7f446f7f4bd6164db6c7d0f60ad9ee7fcef172517188f1221cff8231936541baad418aa310896ccb0e76986ac6975bf6b5884234e6bf8c719874f6ff1d7b98665396bea1a58d4e413768285d8d1db16dd496b051f3f9e8015ec280eefb911480cb85 +d71ea7196f642b90f8ea627a8f941655f6472d7fc02f4ec24c55cc79f95d661183121e7324628325bd52f33e2f1bc1a14310d7f49930462feee1ce1dcb787af70374a29a7152eca3bfef0138e11e85394335ef7f8b9ac51a0314fdc795791c9ca0b5958c381148b12af682ea6ff5f731d6b3b83cd0cdad9ca4f9d4829575d94d +d7fdca776293f33e09c416d2c1ba70f00f7b47dc1ca6a2c8ac6ccfc9f1fd1e88344f75316a99be099789591600ae779a4c78d4c12f4a0e97388fbd6ca63f437fe1def8f31671ec27f6f9bceec8405932c15da2fe3ffe66c6dc3bd0aeac146867790adc61bfab3da2a0d358594746debd018d2b7d58dbca16f4851269bc806cb5 +ce72cddb8418186abd586c8fa62dfaf121e804090937c323ddfeb139dfed9e570b26e2e28e69ca08ba5515556959b451092c83fa5648fa769122987313415e14bc664402854134518f131f58db527d163db3cd13062a9af658357801535ed5bdf24f97ff18cc824ec9af6dad9a2d3921faf7d84218d1f513ad262f64dd86cadd +d5066137aa3101b001a99b1ee411dc57a6c5ba33dee3279e85d2c62510306a69c924835e21e6541d5c2fa3f74ea4e908024bd299c5f8e6049720e1cacb935f8adab9b4a3e78f83555ea835574122c2cfc9b1c2d14d0e4e56e021e06614d5e76628982cec22995458e6482f7ced45f757716620d27a53935386ecec12b9bc73d5 +dd62d314161fb6c7fbd6942123a8e321835e19c5b3bd6f067dd713106c83a04903508862541e1687d6147954334f2315595e41d307cc17c47a85fb0016fd987c2b6273aef981780aabdb54e6f8eaf269f97af56b8190fa2ae67af1a3a60eb924f0e00e9f0e5345ee4ffa94d10a1058f5b364234e6838e2832c787b673be173cd +e2b1d31e084c148363d4a41c685f15ca460e1ccabfd25dc20b9c51844c17c281fe72c76d2b6d4a093108d5cc88f0d196d24baf65c90af95a905afa7794d9ba873c1fd79fda78b878ee970c8a7a3f434ca44cd35965415b35ebff7c635a5ac74a4500738c86f52db8a7f7c82c4544766bc726f4f2b2a4c02419430bba3cdaaecd +c227213c7f588e4bbcfd2dbf3ac650c6610f03e4c4313ddaf02791a75ae396a25c62089e11e47326e585ba8c5c8e6aa20ac1dc690f32d600c162ea086f5eccff3029d1bc2f590194b7980379680edcdc6f21505ee678057c36245c400277140541d12346f067bc77354fa2abe8dcc26a2df51f0e9b5d05f604e179529d2d226d +c90dde4f6f6f00220fbe1efa9accd0d33f47c2c7f25844d4a3d58964d1a01eb63cf695b4415864b11d25c69cc231cbe4c1b8e8c47bb49715fce7769b865db47c8242882c528765534521de678c800469937a2857ace52f3bfc74aeecdae1b82588c7a3ce44b656bc274ee80c0926985ef828e5d7083486b3df38359285cb8dfd +c3e5c636529c8c0c7a842c434708663d186b95f8cc1a69eb7d39c7e008cd1e192defd05ce9fac89e93e57e64b99ca4801e83e7fffb7f0d5a46505d4d5522ca84f00e05b2e895706ee703b63b897775f5950c8bc5d7e2557d617b55eba35ec36743a198b4cf239d95b9efe62f4c40a8b3930eeb82d07c186d1c3935d3a2229515 +c8b525c6c1d8ae599b7f7841cb55d4ea2af528a77ee21d840b45d644104eff3cf467ea7bf0f0e0bbdc5a81cc4606907712d1235fe3f33551ebd11f6dd54ec3a42d3b6569224d0579bf587cfdba19a2fdd8bc8e30229e0d11cd7536aac5dec9475fee801900f6462114c0b148bfb210c7a27f9b027f1886abe00674fce8ff761d +f59a9242b778b65b309b619dfd19a877bb25a168bf0c323c54b03e3635eb31d5345030dfa96130b157c10b8c8d78f4733c0610f4130e99279840966b0115b31066f6eab749fb930fb844b50265d36d04873a3ab0197893cc62b6703d61e397c8aa3660dd3cadff9e020621b8b90b441ac368f773f94d2d2d4d35afb9ec12a14d +c9d9ec80523510681280ca314ff905ea6256ca3ac6225e478705a662319ec8365c36282f1db47774d85f00cfb3d66aa68cb60a9af761924829e992f0e5058488bfae552fa0c8d847bb4546dd71502d63db7a2b713122455d47912ac37b89d071b272b99af36df64f66f803d3ef980784b0da7ecfa117f75ef52430896f15c3b5 +e979ad6a662fd41f6dbb5ee0d3a8f7a928ae0f0940dc3982ea5a1168a46f5910ccf0d5606193eafda19ae97c5aff2b903b0e3a89eb3c879ce0e13cdf43a2a177c8104d7fc121bb9406a826900da82ad4352f4899d04af3f57a225c86c20a175a96f941c2c5eab721db904330d6bceb8d6a7a913461e389158708c9b7b83d8ecd +ce2c29c73a1a121454c12d84784165325ab05dca980a0390a3cf0af78409cce3e67ab9df103543babc0e35149a0b8b9c677f9c71d37a59eb27811eeca31ff7d568430a434a1c03720541cb69a21947e378d14711f17efcab348fee297e53f169fd5ab195b4be24bcc8c68a9bc00b273aa10a01dad64117cb7615b5fd88d0df75 +c3ec5ee6e08a212829db60b82d68c90e4dce2c6c419dfd7402a1a4ead2c4d7d864d45e72a2b4f41a09a569e4863b2c78c60d071188d927f608f1b2c623aa23b63d8ecc23e253b3c995c85416dc4ee57ff0a63e2e8884f191feb8f16bbb578b5054182b3edd779a0163a873685b927b7d375495571fafb20f420f8ab95c0d0555 +f389ef5bdad020e5dd82a2e0f9dcd3b40fe30af45ac437a727047a934137920df2cde3dd6097bec3a2cf142955651661fbe04cabc3a19ce2d882d9e17a8c18046f598216e3b975f297819bbeab264676e4ca1acd202eed2eb7bea7812238b33988ad4c980dfb1eebc643b5a7b9312969f4adf746844e9d714b2180e6fb19a69d +cb8caf76e9203122c7f3cfccc7d2924ec29cd53ddc0709ee0902237d445c2cec1ca337b1e1ab7b6cb63cc7f5f11e50ae8ceeae9dfe11299c39390db51e8a4186e69a74d0775bdb38d1c2c5f8024ad1810e298285393293d3118edaac82a5d8914c5dff163610db4bc4c09486eaad877840c3ddd16c9098f107aa7614499ecb95 +ca106a4be4fb9b3c203254f44debc87417b64ab4c774f972f12cd1b3adb1c5c0c760e68cb145fbd02c7b682f451ce467f17a0f07b5394e7db5fe209d972e3fd2cb92b583b6446740fdf38e292d18b4818e824f645f86a20eabe722c0f693984b58be5e29a56a40ff2589ef5713b5ab2d7ac803b72936011dd436cd1db6e2d6ad +c69e4a726bdf444c038ae2f146b35ac11f03127abd71686cdf8da7219ec3cc89fcd1eb4a6c83bc6eca90373c8b998be6a05858e52a370b184b3d1a2f4a280f847eb5c252c351f52151e13a83dd7aaa2eceea9361071b13037cb9197d8f7c4055ce4955df497258815f59f2a436392a4c6f97166882189926575682fa328ac98d +f6a6bf9a76484194e7e94c0624ce91045be44e04c8c25bde647d421e6266694a4fcb384699cb98cab4d5e3498edba6c581e868258af1b628557561fb9c5e5e23cfc9effdf4f46a788587a1422a4817152b28d67c7888c9543673c2d8eb3a5a51ee01ff2021d7e9f9eaace73873bcd189f84704f2bd9ad5c38cae6e188a3e4ca5 +d4aeb7fa7499ce369691bf04ffeb312ee235060d0a7d96e2bf6398985cf0b55bed0b8b34a53346adb47826e71b7ba2490af72f9d92a33054e1ad8e203233e356f5de9874525de52e74960948dc6a2dc8c9d1671b463a167ac5c889d5cdc6fb6a087b9949f3a3a4c15e1828979e9bd566f502bf9d12e4735dd1b51ab9ef7dc97d +e1324d35af63b7c5475c19d4642a776c82b69d3dad74278afd80ae38969d6e010f0f78c7a17dbbc505afdb00f05c0371a8b100acbaf7b69b4cbd46cde9cb11ca43d36ecc1d109aac95a7d6abd11f088787d9d8ada4412fdc06c030339a10e1459939bced6b5b872dfbb08e33f0c427fb94e0245613f0b697f483674af9f46395 +e4e6640df3213f25799c6aa0c723c17cb67d707261f3ef74f95bdee8d2acc59af18233286136a9d86610421205424d27f21aaf838b7ee361176c0c89fea4e1b79ee48ea438944746d527b1adacdea3dfefe2dfc5de313876f211cd3f7e3543a5cfa7f07624e913f65c506af956011b854549b6b956c951a803eeaaf6f08e9bc5 +c3c8a60114d2f5d38e14c79b803d2d7af36e285daa5654da567e6feaabaf74d6165304d53bc465c0c72b3f9f7961a996e77e066f37eab45808ef5fc1bbb87cb252307b88eda73baa461b3ac1cc44c37af966ec17755fa66040bd340f2a77a8158c247638008673fd3cf4f98ed552ebdd52b61932b540db5ba90b939f2dd9a585 +e18fab58b61a8b6b28e6626cb74cbf9b1753e51ee3a8093b9283cefe7dd576f2043192fb59a472bb89454b2712ff6bbfd390dff0ae2ecddbdefb80aabe82500c6e4d35fb99b79c6f17adaaae7ef87443189916566d755e8f2f9726bc7f3b1d8253a98877bb5e20d2e8bffff9445cd8cc56af3425ae0901f98494678adfe82e45 +dee8564ce74a01b800b97ef020ae40870571f9d4a4488f9e11bd5ee1acb37310843f065d3b50a5e695104bd7f7fa7b5ece9c5a930c81bdea0c7a140e7e107b6a31597dac446b1a10a8030c9f2de9eb5552b796635e92ec9d98dbd311bb4d18e641d294fdb9dbe3816657cf9980b9fe4bcdd0c1015bcc2053dd1b267ee26b40e5 +e67803f44dfe83b81f73a9b99ef69b758f15a3d108f7eee2ab55e9222ddb611e65de2862bf867fafbf04af4e33e80c922296baf1039d4f76afe2537f988d17e16013cd22dc33e6f9ac8ba04f6f166c44666d572e2515db1de362dd2d45662f5c87b148faa1bef73aeb27fd75123faa6c0ba4aa27dac96c8c08207deec65d32b5 +cf02e0be2c3370c707986317d450090c72ae8e1d3b2f6601a0b2fd62eb7531bf9b883fca519362541d176388699f2ea0434920f11c08d418701bfd0fcac8cd6b23b123551d37d53333d361c5135761f4edf669939f5e9c932525314e623356c155570a6d253f78d6dc0ba1865d94383239921a3b2bedfde0181581dc5b822a7d +df15be4ca79a4659366701c3d33bb1b31a337733b1c5bf32944f501316101d9aa23b0c5426e90b9ce7abb5a489d24900e4004512e51ac7af4aef6a3a6845cc1d82bc4c905d1afede8a0d20f7f38bbd83e9d63eae6dd7d8d69c480661d802890fffc1dddc682fe03ed0241c130e8b2d00a6f8f5f2c99b27c852d6b652a2e8039d +c8c4b2c92bf417257ca6a493b1dfb3acf2d57e49f97a873ae34727d2977d4fc339d36017b08cfdfa4a6a544088ee3034d96eb9c050857eb914a2aebb5acfdf6632361e9604a52559a831db5013fca0eb9381b6c40e421064e45c534f7a0028a3333066491e7e1b35cf6aa82389e47306c7773b745221141744d723c85ea2cc75 +e2acbe5b77c2da5bf137081388a217e53e6212e847903fc2263f6c099a7ffabe54e8c200be0f8c35685088f32d6f4e7067d36913854c064773b4fd6dfd0aa7b56eae581a5c2ad01f25b155bbc88845c005fdcadda96dfc95b821e15889899d2c6a9c35bf5da5ad1c886dd62c25753853fb6c1453f558f40171c33d73ae410975 +f1e94067ccb4c0d8465a57da3e31f3d0a77070bb82f7253a2cc410b8b53b12df6fce41c457e3cf25a86fead441f3019b0220f9b62740dae8a20620843536b0643ded83f214ac93216c93e747b6a74762798038236778fb0e8fb2dfdc90002995a129ed27eaf8fbbee89bd0ddb60f56d30a5778078d4d61dd36ce12afec488bfd +e3e06839335402cc2a140f9b3da84df94187bfe716eb31e4523ae2cafeefffebf62af5e16a379c3184afba15da90895581eca9c4f87f4d671d72c384121a7999200c986b33cf89692d70d171eab1ae7bec2773f243339ece696183d76f6f7b4038e5bd5bb801f7c4c9feb25f3a492f5073efb161564193abe2be7f59f2e1950d +e6eead8428cce555091e3adf44d15d2e312fd5692cd4078930f4820d2cf47c5a040164967b629b0ba1b2d06e16935671f608e1b0d972d070b9006c0a8eb248094b9afbf778c89cfb1f80606ac5413e2e6597065eb0bb0869ee40fca0cabe995b4f6626e6b89eaaea90f5f48004233e845e291386f3d298b46dd5260f618f0f4d +f1985216060ba19e8e0b77afb6f04ec35a7c7cee04f9df6a306b4da8d76ca5c92cbcc7a728bb22ad5b24e6d1eb1f7305fb8a7b41b747747503d0198c38df69bad6c6aab06d55adc79537c6d8e606620b545864e3394dc5c0d1916346cc01988649d186c48dcd1937d21834eb194ed3ef03f2d114770632f4d37a14516cca2bed +f9c9f2bd2342e3c4dbc5894122166fa39625cf16ffcbc84a71ae8145fd6a66e1dcedeb7e6f264209f0c877393f21862d81d2c759546f0fdf8c41708d5362a4f8b6111a3a7f732af1d187ae1ad693117b0d5dabb08f64f9c256153b160d4a957433a7bd780e9956d7e175f15ecc79c03d3fb0698238426c07337202a32771ec4d +cb2d386ba2cde8f38438f2774b54f75a9be753407727da7eddb882beaa0fcb6225d1095a980ef842d06a3847fe772d745b2e615a9720f608fea86281a9e041c38628b4335ae93b446f19a495878d350f9664e3d4b80b153e67a7d1aaa73728477889de9cbb6de0bb7a9537d7327c49c5a99bea50c96c9d53eeeb576010979d0d +e1045e327e0b645b22b8703682d618317e0b96aaf79a8378e6e670c56c6c0075941a48d4301dbf66968588f76b064fcf34a323846b09ec18be65c744d4b3b86583991b8facf99a247fc84078c53a2a0889b573c247b354ddc50be0ed49291762334bb34f5cda0bcea7ce61087bbd967df9c2790f901e9c135847bdf766e3c0d5 +d17d7c04e0e73f0af70e8a681fe57336d20b1132167808e6799fcad00617671dfe513c63c38a1ac28b390a16649574cbe7090d09aea1e9cbb4542ee30532098c4e0f5243491def547f771a6da3d741aec52e6e346d8018ba95d2ed500f0ce37a723d3f99bd8d1f0abdb72af353569817a815f95054ed2bb94a30b96e2e83cc05 +f521ce6d6aa5622862e18019c1b08b71d313a12bbe15f27f6d68cb14e31dd1eae4f1b5b5c85655e685e1885edf7548bab4f9284804cca5a874ba1750a79765e6d74e6024239431045519a5a5a6f9326c5d2bf59711e52785d17cab0ac6c2bc8858fe335e2bd6e0a54a39fce1668c382a3d8f79a48d5bb0ce7bb448f0f46d265d +d27b0a46e492d31872b6d2670921afb3c11964a113bc425a2116008cda9bdee4f2e1f008a96942089755c1a90a80f62c18b3ddec2f22a38971b63f3d9e23af975a8c51357699f7b11598ea7b877e6f0901215d2e8df364ef1ab0106eb0706df83285bf3015f12ca98688c8d919aba4d630516b1211f8d6d8f71cd99d0c599cc5 +ef72eecba638aa1f75b33a9d91981f780b7f5e39371e020c8e468cf72069891f8bddce8eb86075dd459de98a0cd65af719afaee5553fc68b00f8dbf87e33a620bb767d8740b69f45406bc8c3992525c94b3feff1a7d3cd91be83d24d767ef4836d01c62c74ff946ab61c5e5d0964d63c5c42ea56411364d7fc4a4b3dfbc8e495 +dae2195ea4ffc79e7a0b70fbae8d74cf51cfaefa30d15c0e9a054276037a4504ad5efdb692ff97f0c456c3fc66f21f71563aed455a1555fed1d8f7fdfb14a126fd475e582e187e1a8875e25f7959111afe8f141b0bcf641367f672d024a286766d902d7b48de1e40f4943a07adc20866cf2034d32881ff1756ef2a7470886c45 +c393aa8773a783ff411304ad3000ab42d9dcf488f3c4d6098f49db82b339ac6942288861268dbc76afd12c5f9adf3f61ac685d5ddcd80c8a3b639fa59e6a11c425cb4f90b01070ecf9810e5468e8fb2131c807d72dc96528fe3379995c383c36efe88d7f1bf4706fc64f775c4fa9dbaa738ccad52004540d134b51f912436d35 +fe6c3ab23ca3b1624a56147831d8ce58edc77ae99d6db6f17f889bb19f8b87ec488ecc4d4370a26978a553b5769f5803bf3b14893ef6f779dcd4a2a0a6821ad61e63a4c8a41a58ad3c1c5c62e72f524cb63992cf6100b8e7e8a1f9666d932f4f29724a3645cd20727a615161a08af2689749bcc601f37912971778b7d738c62d +f87d31fbc3fe86c9f4e6f2d6e66044b0b3cb461ec9b00c52747b9b7cbd1bef105ab9cfca392e807db5ff40103aad29641f1d0408eb4df587c8c44ff78729db10fcd76f56a475b3f16bd28a7497a939ae2afb8ac23a1e89ac29836dd5bfef509f23796a4038c899bc0ae2428cc3fc34564f4a6841ae920a50f838000039751d8d +dcdeec99b18f7d837ff301714ac199acb2d8c3e73065562d6635f6644a72693bb098d56865fbcb921eaa8c417719c634b7606cc0628e740f051677c920fe386d546aacf0de236bacc0fe221275566ad92250387c10cffd555d554fedf9ad3f7c4b6cda017a7e0b8040505483cc64285305438da2d50442295e4d535a8f9be7e5 +e786b2c5dc7d1439be99339d198b15b98cfc3f718adcc65bef4fbb86be6dc7bae3dd12734960659f4ae9ad6a45c66e0eaa6efac0edf6c0ba72910e1910e9056031b3f6c58538c0b24d5c325d7c1d50a78479f7c7f3e9cef501171ccf45f455e71e91b6f49f4362d0fbf8d8855da8574d888fe26398160323a45668f8ae62e9e5 +d960b0d7131cc252542f29a686a2e1b9b61bc5ed2da6208a6a13b461b4cd6606505b4d5e640dea6e11afcfc5caaee218e78d2026a5b44bdbf3c8a77f789ea841f52dcf2fb86b0078bc643341856b1d2fe18441247e58d03065f96d10e85620a24adfaab437b5ce2044f900239d868abfd09ea56434986a2a3da0e34fa1f59f85 +e9f06ff9af989968099c7585ee539702a91b9966cc1c0f6fb7c7a20f32f37b12697f6afbf0b27e16187893bd40cc24f53aa4265c2195a0f08ddc17f755c4e3c76a79d1153e6a2d99bb9ced184b4f031e7dffff14ccea6b87a30dba589ea8f65970af537297e40c17a94a4aa4504f03efbdaf05b38e6015a1102235897b4bfcdd +d76a70ac8966f4c7f4c87b96879541d573b2806996fb6a8a2054d8b56fa5a19e318631afa4e83b18aeeba714eb1670d95dee8760b9ed0f5ff17b8bb75540b5011405ae8a2da96d87cfab2626983de17a890e424a25b41401b990127d0cc6b1bd786cb2786fbe8080eb18e98558894c3fe383c7bcfe897bf98dfe95521fc12e7d +f7bd785aafaf4f2bdafbf38235f1e4c730e9ab5dc4fa3cdc9b9ca90b06dd9bf8f382ed58c7b0e34cd51c2cfe7b59345aa10839f3345cdab897ab7f553673e0bbf69ef0577ffa2b758fd2a6decb7a24d9818227aade82801f62c453b95e3087d8992b435e50e01f83a4833967a8b75ce37a760fbb6cae3e99bf89130e1736755d +cf26ba352f678c227c25e5147ea8de4bfc4310d388530d9bd3d0dbe0e9254fea8483ae00f5f0ec81dec0e42f5d1bf948b8519ce593737e318925de8c00c0214247abfcdbbc77df57d750b3a9c160b39ad9260297f7fc67ea2043d190bf0765a4fab4c7e6edfc3f08a26311de00e47b879b338097574e4a377e2387ee9c525085 +c6064c4add843be7a9bcf2582ced8aeb459ba930241002cf0325da5a2d2e1b5921479e50b688b069fb82929469ffedfa5a1180f7a9a6168168a64ef917c909a7f4ede94357203f1113d0c6d2376a5e39d37482511a67ffb65832a4daaed93f86ee9739b42c62368eeec1434d6c42a1fe53c5068bbd3ff89549029410740cc23d +ed15402f355404533c4592b42d93de22ac89ea83acdd01bc6b742ce77761a4743fdf9a069965a7d19e86218f8976580be43e4a1d978e0722668b060f95c0365fd9c84f732ea445436040c8ded47a88ed05172d17b46e92d26ad56afc99d0ae216003413458b2718cc194e559c4f141e593996bd9888d57781b5aa33ff1b44e95 +e83a24b27cc273db2414f5adc3d70f5b9926dedf39b4118298c908a26fdc0817341485b2c847ee98ad34afd0a316d32c03c455474f73261bd3231e08c09de84c051d1efdcfac30ebe0da967755db47b13928966f6d0cf348e24f6831a30942c3b971e74fd33a1c6a0997a4db9eb486aff9da54af901149106b991566d025ed3d +c76da67e64ab8b60d859753dd47d501e96d45772eb72cfe226dfd6a52d026034f4ac2cd8f4113ca8cb31b830eec8037f94e62273653608152de1fb580f247e919aa25dd58540902ecb868f5e25ab6deac6caa4dcd48dc9f35cf1939f1f22369f98e50463fbe9e368dff83cf27847e2ae45433c747e848d995fd26d68c9fa541d +fcc228f8f74fcc29e4d70f6e437d258e34a9db8d1af38d951eca478a66e56a776423b54d636b7537f46e6b1ed1d8e19eb03c865dcdd1090db77c1da5a695569f4f0b85d554ab61c8f65d04627da559d43f5b44962d38bf3ee742b9bcfa2db3e9120223b31617a631b80b1bec2cd7d1837e452d6307c4c1c7340193075fb2b8f5 +e076473f86fbe36192153f0864ea831bf5d4dd8cde7ed5d7ac0dcedc4cd36e10edabaf12ac16e9978c12c60506de560c18e3cc85ef2f5563bcd434f7c16413470f9dadc62f92b5b01328bafd9d7a2e5e11db723a8002eabc1d116593ff975a3076c679e3b56734873d51ef99fff20a2f9bf4f06665e5e84852f7ccd830004785 +cf9e7ba49264fc3070173fce670ff6ff6f11935237a557b68fadce974bfdec70b65822bf865394873da79de16f4e506d244477ec4ccdd1851e2cd2713a0075835fa59acbbee79d2439e4d1656328f339be18605976317882fba6b83dd21fee67c38217132eb115801ef009558886804327c446ba577dc93a92ad71b2888b825d +e8ac898dec76b876eaca1dd3d5b73ecc8a0c06e04c15608b1cf9cd20917d3d72135dcb29e03c59dffce2c2e77d345c8232c32ed8f5ee58d08ce2396d4866b3b09611f9d7e71a3eccdf46e17d84c53edc861575242f6301802fd237359ee6961bc32ae74fe34cf64bc0513cf9635d4f046d229550674dea3dfb7e7dd7a5a4441d +dead27581a5bdfc0ae2111f2bbd3a2c6c0bb996dffa395b4b52b9c30cded05e6a363d314ee9ff024651dffa44aa3ff0beaeb736b1688d9d40fe3e0fef53d4ba6c78446306d6ab6d014af2381df992a526ed354aba7f3fc20e1edbca83012e40566e121801018ee1ef32ee9687ae896b9aa2f3ba935f199c5eeb7953a5eed518d +ff751130a3aa372c26cad01df7083187cf5f6b1604a98f63687846634c3a6676515b839e49454eb344eb894dd4d9b7ac4de7bd8b8de3aaa103b45124e2477e17c0a44bb32f4afeb2522391fce1ba6f89f5596ab338a8cfb1b64848d517b96b5daa4c164ca5275ad8adbef3fba0f0115303162690de9f75aeaef3cb2a831c98cd +dc93f8f672332db4d675cf638d5c3a9b9ab7e28c011802aa30ad61846ee175916a5a9daa13ce7db426209cb409fec83f26f9f4a653a1bfa1c3e4de7318bfd51c182177bcce23e120c601d67f21b948060fb521f1a9cf4a5ff5a260af17dfceca586674084a012c3156e3c59b346707d6511b7f4cb668fad7e517e247750b98e5 +c82bf0ea27c2be5b5b90850621a508016f821cec4da9dabc473fbcbf0cff53e3c13fa3ceea1c851f638ca622d30dcee8519b30e54bfe7f2021dfe08c56a03323453436007a1a0d5058661d0e83ae6e746e27a2db8bc0390eb94a45fb9b3b6ff21f0874805b748eece85a21675b1bf0f87393eb64fb480e776f209dcdc288218d +cb01ab004a455102d265024066c28efbf293b3b0b8c5b97a2adafa84c2f0ee25c567d46dcdc4efae7039917277646f2baaf507ff8bed41e88aedadec96a4cad46b77af2c7ad24bad0cee415ef7fe59c5459fce5334537265db060fa1fef9526d21d4dc4a932c3d27f018b988c51fcc54b3d45757aa1e782e43f46e6630ab7525 +c8fb98ad46a049845c83dccb2c7e31b8b16ea956b9b7f30422ff2f53da87733b60c801751ab394d86449a8270f0df4fd25193d886b8ec7c2f2a4649f2fc39640e8634155ecc8a1a191f2688c1f5adb42843c9d7c73f7379082ba202d30b8ef70a397a35d26e9b5e49d4e3cd87dd6b051a642efcbef58b9b5cd05f349fa724ea5 +e154fd4f5be7bfbeced17aa18baba53f19837f0c7964be61154aa49c6521c9f38d7619877850275b9573cea6e4114fbafd3db7ccf9bd2ee023821042a5e6d8b242f9f62a7bb601d1118573a628bdf8500cec45235d7fec639b5795af057c863f1838fa15eb25ede388c5f7ef53eb9143aac8aca8d19efa3dca4bda97feec5e1d +cdeb910095d2e9345ccc30254efc1fa238ce11958ed30d24617110b02c18136b832293835d0963910d43d8247b9a7b19c49fb479b1717f4ac7b55a2888144aa4fa7360f9847fdacafc98097e7f0b3468eaf0ae8966fb279f1def69640794a221123168a021f85d8d79ea5b1702c4123369d598a4801eaa973dee2741d915e6ad +f8438935ba59e7c95287e5c2ef5d2950e736f74e6fd622f034c28beb3184cd9c0f62cae993bd4c1fcce3ddd5dd0b8eefe9fde9165211685907b55f96833ec32b3398a4377786ffc5b3b1222345b488662802bf89ed7a5b55edc639b9f941292336c51874ca037d33cbe951cfdbbe876f5fc995075cc4ba44e3f6cbdfcc59deed +f37918b706b8ceba15db3e18cde5d888270e3e01c5d5d10b5606f74047587671ed3c5dd0cabaacc3091a82786dc9c17956eaa129196d8b007b4f1540c520fa8c75990c7b63603a56a3200a1ce9379fb536cc2216c87d850085145e230c959f1ded675adcd029fd57e32c762de466b9921470b357ad945d12871bd9a3f25ebcd5 +c5d4d9b311fcc1f9d2d2dbfedc09c347d5d793746335a7f8db899cb6cea019cc66bb50afda64b84c2cf10ea5b72669c598924b1c9735c7ba423bf07c06158372f514e687f5284979231805874905cba2bce044615ebafeb93ceb672b6527c20f48b2917b1593c1788506b75df278881fc77a7c0606093bf65c15156daa594d95 +e63759f9d2559b33c4620d6c598532593b957d232b873ea35125cf190a1fb78f3a959a100d4892ce47b87c84748e1a5b232cdeb3e404fd6cbf19069f2c8de134458854ed4e07d95131af6c441305ec7a70a96058a2882af2a342a626430725a2adb448b7bde4f4adc0bb275e33b44a97d2e9329194f1c815ff57428a1e2cfdbd +fb6dd7d761b3a07b56cee7abf128faabe4ffe20dea8169b2cf74d3dbffb159d3e085cafa59b779433e89eca22895833c491d2409b1403a4d6d437c405848627065dfb0a67ebda9458e474abc9aad869ffef2399abba08185eba0f7ed58822224a981e28b0e7314770357de626418235987b194e8fd6dcfdd03194be656fd60cd +c204ef8a6c39a3f23133957bce1fae1158b587cbbd73797bbbd6e37aa86d747d0c8793ca59b658e9095602aa882f34cdb9a9d290ceaafd9d2116a15f6cceec75b0a150cd215d2e9b993c5ed17fc829be4126afcc9d85851e5d366d18b47fe90edb38e72262dbcac4bb701128c8a2d942b0f110c41d352578c323c1cd7f8ca99d +efdaab310cd92e5a7dd0dd4f5d387921fe5e18b9358d1f8d4178e7522f2aa1936f9bdd5de36ed955530c65f059aff8d177da54b57281266f188309a037533d346788175022f8a4995692294dc2a09b7ae1e79394b8cd9c69033ef8d4d07506fd0dc14967649456b8afbcf480bbbf1c6bb7d2bb0809c88c0f8934fe89b572d9ad +e3f62e0b73cb17ec33426c5a4ba8f4292e03e677f5d1617d938e93e54304f7819a3921ce0df73423902947ea2b4dd162517380dd48ce63f30e8b7df9d7194e75564e72b6809056d6db1bfa62b3dca60f7a017291f8742477efc7eae8c9e7627843726fa4a9fe78dddba02d9814844c6e8c54febd3e2158971fd4779f725f68ed +c3c9197fd49de1a9aaf1ba03302a0849278a6bb8460afaf38952d542cf7afe6f8c1fc40b7240ded7a7ffcb5b23e4a5b1507ff7400db4d19fe433524474e21f9673c88c098f9d033c191809e20617dfd5f92cbcba5c8dcfd6652551945d1eda48f6dcddd16ffc05dbe4e3cdb163de9eac0726b7dd8ca388adbe54858471319325 +dc87423787fb3776d3a38c010062304d7fe6f8e4bc5fe8e66201d9bfd724b601c5184ac3267ddc8cddf3880542fb91ac077cfd2b7a07b49b90a550f8445c1c68c084a77321c0d03d005c0e666a9ef3709c1708e8d5f5f2d82f0ec81a2de2fec456b22ddc5243b2ab19f64a74bba5fa6c2a091258c5916c2c49d2ea7f0a5d084d +d0012d2f905082a4516b64dbadf6a52659fb6065fa31f6678c00941eaff3d1e2423a57d9450fb53dbc956536eb00844326cbba017727d3703cb3d83d7e30510a25a0e3a030e4083c747a9a33cd8d8ad28d2b249ead1286cf1de4015c6022248801fcac6320d2b3aa398b7c4ece75a6a9d9fc19d460c657b9d9aad6bf7501a5d5 +cfa3a9a0b42aee7cbf76b882f2ef49bbb53f2eca837a6660714545c6a5988a819a82b3ff72f96c828f385b34fad06e52fbfc3dcc6e43ee9dafbefbff3f5111fbaf795e0675047a21a64c717b725d027b1df53e680d49e2a0fa68975b8d616790535e6da217b58ee3135043b13f96d9d9f14ceba25c80e698a8b6e79247aefa45 +deccd1e4355492e13408d4a9ef52ede6f736c3bb92c85bf76f264a053308a228a547fcc55b2b18c52615030aa71bc0118f259e8638656f0f912352d44ea4964ee652ad4a277d02a96cc6128655cd3caa276eb2622de7a6dac84bda2300ba6ed68d5883db8f45d88feaf67fd7af568c09dad637d46cca9dd7164913bc21dead4d +f05f8e610335c370350f81e7d3b8681bda7c0e51293550553b028ae6937115061873b575b342c8e0eb16e4a94a7263d405fee689dab1e304651abbf9dcaad9cdc3e0b78a78d8d08ac7bb3bdd54bce8609b4a741d10540e88402f74fd20a931b098f83e08efbf73ea2cd91adf599a06e3181f369cae318a388bad70258959e5fd +f40bd808d8983b526dd32870db7481b0026292b56b3fb937f2ca04a20063470f46f6903dc5c323dde933fc6df412d04d326dd3f2c3c63cabf2796b3a414d953f2e164fb4d7120cfb555ab5499f097ece48afe978a71c8a43deaecd680f181087b380da2186afe81e60470daba27cdda8f72c1e2013743ebb8c7c7836ba0d9a8d +e0a5aa6ff2ed1f0a13e9f226b1d3e1daa1dff2a82fbc24c57f4364ffb58fa6dfc3c146aa2a0c86fbddcfa6255398f4d5309e5116b1e05e044ad396c780312b36c56065218bad573ad88fe687502ff51a6490c10b3afc0db2faed8d282fd91f6245ef83361aee9485da9d7cfc4ef91c9d98d6ae5cf383d8513621290f3dc4d42d +ddecac7bf804349baad7591ee4130b79bc255a87ce3b3af695c7ead8676ddf607832ea50bf24952f57c1e19ace029361d94e6891aed1dc095d784e4147422676e52967436cc963af0914f335a7282cd7b73188996c01113d78ff465b609608faf2d1356ec58044f8b9261cd09cb3b8449805ff34abdd257479dfb7e699b9d485 +ed3e5e09d1a52ce643f484d223b312b47511c0b5fda60bf8081b69a6470f94713661b098f744fd144c1807d7bcb30117813d4d6f506d232c216cd0cf81edb59180ba2bf74ddec8f7fc1bc720059253b36ddb4758fd39986a097cd636c80acd11529b24e9dec6d803e87cf990cd6add1c6d5f16cffd74896811d05d324bff511d +f70b3ad2f71f7561b3afb043fd85a7f703416a0571aaeba91b098d198af0d19675245b53c0b9839b8a3fd4ef37b95d2361809cf72f0d057654ce018c9e9c9222419e636ad7b7b28ab9d0deeecc369869be70a511c15fd40e8e9c35858e04db42e6d08614d2e98754d85206ecce8121305400c3a7eb1be090406449bb100efbb5 +c3cf52f73bb03e184af1ee941c56e4e3e4280b78e2d7b3e9beef82f896fa241d58b5a260b8289708c88ffad26a3e907da16bdea925de7c61de15b0330f717b05693423ed0979130ddc3771d424839262f4135e270b396a899e40ca2f799a7ffee07e65ed428b4a5069987e010754b3455456c28183c46ec789095938d17be055 +c7e0b0844d2d1a7a638dd86b30ad2bd20caad56264c4ebd10566d876097c09785110d4238146ee0a1a219c9247a61b4e39fd342546946af09b9820bcebef102efd8be1b51902acaaa5509869b9ebc5510aa656261313b7ec6facc4eacadef66e758d976ebd613a1b42f0ee54a1fce38fd0096887427f61e007f9386f576b9dcd +d4149cbd1f05bec65413f244f06bcd0ee3405e734d57cd023569e58f8da93fda5dd2cd38c2ad1ce0ba131e9fe0d5c3e898699493276431ace3adeef0d8d74c0197144540adca344003f77a92dbd168e0320adfde66701df5c71bf439413a61693ff137447fde0cdba216e33c78b73e1c6ed6fc813b541041728688edf87dfe95 +dedd0cbbba3cf035e2aaf743b0328e04709b0a27089553039a37c46fc62664f4c3d68115e470517aa546cf3126a2771812ce0c0c2631f435f25966ca88e37eb49faeb9d345618de4403aaf0f7af33c5044e806f423b0eb9180f6ec797dd4374a08d3ef625377787203c5267c8f9014d32b575d124047da743681ad677303334d +fc1208a5ba359665264d35fc6bdc4b23a187ab3fd587a2cab5a3911b708c68dddd57cb150ae32cb3262393e24df810c38329a679bb452ab0eb7a70f7e679285f75b83dcf470390537e02cc0c83cdc6b45c0773589b43b144797ddb6336a8103365d09dbb1b5edc2e5d568079234cf7bec794e952b8f29944ad66e049d2c632f5 +dddfbe3908d0c1ab4ba1c000a2a154671f440d059da2d700a6eb8a46f43c8dd870f352b74e7c96aa4d12e7c7ad5793d3adfbaf242d1b48b32f7f51743f6222ad8f7b7dc663b7e43dbc4a07ad3be5694744e9971d156afaf090053fc24a26df63a664728c0c844b95fd2b46afb22f4d8c6e97b63bb0974bffc3bd146ebddd1fd5 +e0efae147c20338a15d2fb5a5196b402cb9536cdefadde4cc9427f5308a7693768461575c1bceab20e9e28af8f5ba5fd2c981065650f4adf4de6a460c29c395130007d623ca2409a9badd4e3bc00a1188fe3a19005eae44cd36c201126ce72e229b277b220959b76ca71005bb246bab998937818c238e8dd778b0058c28a7af5 +eeda184c6f8397794c654db95158c29a0957b5d273d1d44432e2d212e358592226a00b284670c7182cd64899398bb9f19e4b987ba7ab08fa09d8fb41504bfaca985f1da13792f5b44066c36d0036aa4d48b35ebb6ea6cc173928ab9cfeaf22a37b540b39f7cadbd66e91fccfeb084d2009e3eb3e57885cfd00ffc0ffcc8b2695 +d85227d4f2889dd7f1e39c15060490dd7bc2ccd84f4f22179c74f9240670b68a3a0a2ca2bcaf3ab7512597db68d794f20313ab1966704897b32fd993cc8a656467c66dfb00d50991c01ca979cc35ab7aa0ca463b31829a852f51ece4076fb8fab7d395445897004d3f4d6fe07cb4f9fa7d6bfda3bef6c1d0c4169339da897575 +fa6393cb5800304597bcf745fca14d20d93de2c1f99f3909511dd8b9ba76072e55aca206b562721095499a302f2c77f7ed31dfd4b5011156ffa6e9f96b45bfa1aa698a863d342561b2aace1414171e8280d01e902eea9b2c476465628168592550ba5204609a5b7026d86e85b660739beb085c29f7d9114df91bbd25d59a5175 +e2b832d391a032e7fad9bfd592bd8dd27676e2d64a7f237b75c3d33e6a58adb73cc536681969d88e768ea287064d87de15f93dfafbe1cf0fbf80403793b739ce6aba95b73312b419e31613c2cdbafa65f34393b14ca52ef3ad565e5ab28e4b12bc38199250162992cd29ee558f2fc41f448ffdff6d34e3e259a413b22b7dc405 +f9b8c2242b699145f93f38e0d537eea01e147321aa2780c0017dcf4db6d2b6157964c62c5ee1f16630e3c0c5dfbd2d79fc68153875f2d5231f64537876d7a2d353cd70802c227655d7afd42dd94ccd79dd123f86de8a524c96daacf0365d4bfcb3b255e4598fc119938b151fc7ebd4b6fe6188298ab65853acaedc18f1f580d5 +ceaf59a8150e25e680974300c03087e734c24de34a838035f6af22283da5bcd9c8c76f20a049d26c85efe92928ed12d2c8533d139a867b380697afde7376c8f78593e5b264b224777d525d4d0a62b39d4fee7c4c57d1b133bf181f7c5b3805b727ba0630cf28d48d50e55a05c6735bdd9e90e4b98767aacd8cca543d92239cdd +ff090e80f5837f43f9f393a2cbbb87657185cd70b0b7c7ad681480aa48e8f5d69773316c3d6a9d9af1c8a3ce9aed950484a5a77849076650d573de967a3e9eeff5f70c3230014e39b1b8ac200b8618c201d83893185c07e75befc0ab6791cec4f0523382b1047bd40296642135d9498715f516693c624c0ddfe0bc67506a59fd +ee12ade07eb483a078532f5940b71a9c71b2310d2d49b56df3b7d2394f75d1495be2ccac175a52b9228440dcdfae49759e38b5af2de3563230cb19c06acd0570fa3635548770ded37e0b0f42293e978d1ee0b26b8c105c78e3ae12de17f389eee748aa8acf91814043342df26391c9d9e90dd117198e65ecf9c1d1f5216dc9b5 +f33b2b58ee5e248e076301e4d4b77ab9c9d702924f95f13b486e272da16fc9f57fba60091c79a83169fc8f08082875e12acfde59d10c8ce9944bbe8e8876b31645e074d501c146c651fba3ace691ebc0eb18c57fe7abb0b1efa3b5a497ee7899ef95aadd867f9a988cc28d9d01a163ee0dce6782ae0a45409b6a104da6805865 +c15736b1ca11e133c090d5a065b53cd82e2979f44cb93bba041735f4fd339955f1e9f2a753f7100c8aa7d0df40b908a74a4419999c0f4736021aa171c3bdb5974aea4ba1db3ede0b9ec3ee0eee5789dc24a6ae4bda8c5559b148648b55e3a6e2412970d9c2b0fe767fad196b130fc88ef383f5511000af8b3f74c2cacf165b1d +f16569ecf0eaba1f622c8caf1632b24735afd2684f3a7ac86d8ec679c6b7fe9212ef216d37c210d3ca5849c167ce063d006551d85e2d40fcc12265a14467d8d36a67a9972b7b72ff814f90bdb473f0c8618a22023e80e66d6e0df8e466ea995fef20d4127fc3d690e803e4ff62ac8f88f7b384a7a219fa8b116269152c2f8d25 +e70c3cb7b95c703d9f9e4e5b9dd6260f3a4cd3deecb2b7632652a013158fbf0f5e4b76287410cb20b627737fbf7fa92f85081a13a00a3fc59daca503576d8b449b600f6d9c57dbb7c674309bb1c4af7fcddd90085b68713ec20c766c442a0ef136731101bcc6b1b9633ca344a590ec7b1ca611c6b39c161a4b8b3016ee7c615d +e94d5b4afc86cef446b4a4b0004e08f5b9b94923f907fb015e4959406d03a8acc13a51d825b3930d5166ae0054622aff440eb6f2550d51e7ddcc88dff5dc3a8f8120cf6c4a2f3e01902bd8d86c28df484e5b776d31d149a47a5cc842220a608eb0ffa175eee3eb3280ef12c5b2a05025537abe234717f6e2aa849e675fd4aab5 +f8d4915ed06d22f36675aa84359e1a877b369a6e556371b59690ced0f4d592860a78c49c6bdc8e7ea1a1bd1109dd8878d53bec463b3ea10801181ddd6257daf65aec29f188a706f0039003f436a2086922c7c1de0f251d6749855b0348df64308e0a0ca1fd0b7723dd4f35956662fe0aafd3d420ab19c5487756eedf86cf84ad +f35dc4c3be8a22c7466e1d8e9b44adf3e91601eede366fb9658446491715ea34524d76d8660ddf95f6c512b34d52c3cc4e6bed657cb6e40347d9cc46dc5404cc2e54dd8a370041ff1651e20a8084e45b7b73334ae12c19b5885fc8c626e9937dda3c673365f1c3fd785738c20c5723eb16e604f2a94c4ef966f577262c9e5575 +f265c490a6cd394199083e842612145ae5576ab26719701f92d9e084075d66f4f8eac3a6375abfdfe3197a79d45d30e1a6b05b2f09c5d884d495b1deeaaf3b5fae36541290093078308f0e003b9b271de921051bd13216bc16c996c1d73b3563a4a1e4c71bfb1ec962b10efddbf17c69b77621390a9922d63952cdd4b203a2b5 +f5727c0c1826e112487441c855f1225f8096dd90d13f152a49a737445d03c78115f963f88446f2c7a3335a371ad886150694cc476a0ae0ffc5adcc6368190813938f0744baf6e4def9a211afbcb3cd176166f3ffb23a48a793aaffa08384979d4482435d3126a5ede1665beae8426e0d0c12ad3c0077dbabca8d55ee87b8c5c5 +d793b9f288bd065b38d4e80160a7680af407bea4c05b90f40eaa8736a6a9bf41b2206f663b24205115c953f68cf2be1a2bc7073e17d8ebbf6897c0caa9480192c014f15a9ccf024caa11ef56fc35ca06870d8b86c41baa2fdf6ca00475dc3091d50fa452021e66db6cd58e8002c37b7b43975f23373ec4840ddf8c5afe3882bd +ef2744764125c14bd0109d542b600ff2c445c3496a21409b7ecb9dc0aee0667b564ed41d819537fdbdcd4781121e20c151cdb342facfb9ceb1fa39542b953d5db58ccd7bd5ad36e0252dede437fbe819312c6ebb9745bb0ffdd84f99b34ef0d323b89f12abcbc2e90649ca09372e226ee7009d2600109967ca0b55315062aa9d +cf3cba2e0eec4502ab476834d2ed47764c44d45c750ac23115f49c52ae41ca82f36930c92e424b8daedccbe1cd905068e43ff1dae15093217de2e42eaee6f113ede1e967677bf41b8de614329b9853d7725da58134bcbe055a73827bae503b15f7e1487e453b9252c34006e20127fbfbfe2a4c3d74ce558bfc1734e4728edb7d +c9f921d0852f020ba370b4f2d58dac49176eda353b7db9dcecfd73c1465d8c7a1f4dbede864d6fe320d8e5a2386cbda7ee51d9a0efa099b99b1128cc0ce959a1938fbb85ac4c0306068ccbaea4bac0f7ffb2adecf215237e23e7397b949bfa852c38ef97d40071780b379ef1747ef0be6ac7951f1499ae383c43b86cd34658dd +e49e960ab120ed0d6f3c980febfb5cedc0076a4f3ae7f3b5e2cf9f9ca783a390fd77b674d6c73a9ded0fc3f6dbb1bc91242780ba1f4edcd8098f207aec2ff3bacc6694b6bcb94efef3df81a99c4db1d89a7d3981671d0f2f62a4b1900c0bca3aa690171d04a927183d381e6c67fcd7147660dd43a554aeeeb737f3a5cbf1d635 +f2f9ec42a76b676a5951bf735c3398d8bfde2ef02cf24200b6270745316de9fd949c489fe43f1b4b6212903931e29bfaaf77fc0ec9b0dfc7177dc23fcca35f2a0cdaf82d8fe53c792854322f98c538b968efd86d805ba173e23dac68c2cd0e56796959a5ce5bcd195f89a45ab5e371b0d76b92b348c5e461fab00570740a2355 +fb2cc865e608517979f6f4ee62be241fa5a43f326ceac1cd90e6389bf8046a03bf5bece2b7d3772dc0babcbfeed93c86e5f712350bf429410509a680e4ae335a0893463c423e84cd4ec649bccb376d84b67699f84c8a7471ee4ebf7b5341495be4aade3f16181e21ea1624aa8fa48f266e3f358c5527e89cc2973d9d02b08d85 +eb853c389114d97737af83290fbfa382ac883d68dc89c47e38b5b252a23a61a29a5709aa98333c9f0868f72a3ea5999f4d7a853dd8f3ed18e1acbc0215c97ea23e2154343338d3451d4c5f656eec491f9c2f2c02d69d760be048ab96937bc9a6bd60709066bada1dd197c0c028d87367e0c02fc4a8f19468734a96f3a94eac0d +c70e66e78b8c832a330525acf00fb556c3fb9902e879952ba4f5ef4238248b61d9bd5a15f9346dc23b3cf6b961ffcffd853fc2ae240d50b53b4bcfd7f9c6cfcebbf84714dec1d15d3904b8eb506a8a7f5d5d9313d195ed2655474e1e54d1ae6311721475de884b5118accd509d9f734ffb051f9eed141c22a16a68c96a9fb24d +e9ea13afcfa9ec4b657cade8c373d20c2c13b4e76ac74d00aab43922bce4fd990127ef8e6d65fd099cc55cfc42bd19b9ade8fa71eab087b3231da53ea39ff01b2e8114a74f108757abdc22cb06fcb60a159dfd15ff52d1234f8bde2f8849a78ae24a1091793c69b1ae9807e065c70692cf7278ce739787daef86864762f7bc1d +c886f6a02b642d27c8606a4d933e9ffc1af53449324d5da647a427dfe244ae2b2b2cfadaab181298b07dc90c1fe6a900f1aa078edd86fcfb3b9ca8a6ac2d18248c25afaa1ca9bb3d391b15d277a2733f88df7eaad52d50449f085a1f0ea81948a38a7798193a52619428ad1cec3c7426d922f0dd8dd38234a82346d59e7a4c75 +f648344d2a961d9585105006b9db58df1a1c0bc7bcf2a7d46a5147a92a333ce3de0e8d2faf815738dedff3d6773ffa6134635601f9f4e491a184577b224f377c8580eeb35cbf8ecd1f069d825af966fd84cff6f2332e0fcf3c3f605d3b6fb6cae295c2f55c10d46328f8f8bd29d6489bce95ae1455771b0cc1c807bd74c1bd15 +c79a37d4b999e7348b78d0fa08b7a7dd53ac0b4beaf0c3ac6b001cbef235b42385075e0c81afb247df1d0b733894caa9dab15083c2fecf9d93706d1e060c143a5e1d2c865ea9f55acf25998ac3965dfa5b1ac476a9a6d559866c7e6b31cf78289a276bfae51a0479f899d25b9e08631f17719a5505f418a381def0a772b12c7d +d88b9c146f4e0199fb750c6666498bc1166178fc39169ebb5326f517181830778015833a4d98de263316f84c6af44fe81c6d12369e9f77ffc56f9d5e64f612bdb96e7440f84bc7f473a5f31684a1b32ab72595b58dbedac75f6d1808977ce2428f8a2ea87e3a50aa20748b0fdb93af66ee8489b00de02a62eeb1283154c8040d +e615ba364ffafd0b9d68d3a9de8600f09d08ef321235bbbf4a96aa37f64062b87e8959dbc99a9cc3a43b2829daa490a156e5a347f380b2cc88c2fb01847fb15982903f64c5eb91bc2c632500cc55534469709234c3f75a6a483b122c98f2ef0b43835d68b96284d81161f9dd7ea5f3317da0b8d6d945e8ca1ee2c36fc53b9125 +dd10b88f1b2bffabd48f5372f2087f5042668ca3035dd58325855d8030d3c2889de3d01c4c29309b4af3ee4478de119663358c4cd43bfde822ca3d43d85eb6a9df6702eba7b55321745f8364cf6a6f025bc7cd0efd724f8bc57858035318cba6f0752a04e784ea9b87bbe4c7b6989e66dc214b2038eda8c74866131cccb81955 +d1b0fab56306f78133d466ee8ef5f25e03743ce6f9f0cb3be4daba3b6d38d9d92f3eb55cc4e5f0efbe568da82df2d4a7e2488709ea08e71ad8d6c223d19292d283f77b7d226717363d4472e57c067790c8fb7beaeba402585796df83e7918f88a58698fbc428a2cbac30f09e647b2a36332d006bf1f3cad6e3a3b31bd88a270d +ffea786a2f25d52829f186a0f33580fbc345298a69401f144fddb4706962a2d17281ffd9ece1088b4a0ef43f186a6061785abbf876e79add9354da10ece0764c68a15c60afc504996564a7bff20623197d2e7e92e94d2b1716e15b5fba48f42afa481535f5c861001f7ef481434c7a3f144e5839313c3730f5c8dfd8413abc25 +c423dddf756797d8d1f4c3d65a1870332e1e0f38393ca7d1a1682b68570473ecb473195464fc3d5088e64e04196e83ad79ac888ff490f7ea240d2e56295adf29d069856fd7635069c9964941d2bdc3a171a9e56a67f1722ff9b3dd6493de3aa153db2a8abb97d67f7b8952c4224aa4b2be97616d53b3eee164128caf710ba65d +c9674f220b3a2c58df851f2603bfe4c908e2945bdf89df61d2ba9094e4cce5591c943cf2ab2a40ee664723961a0f353c0bdc5b85088e45d12a7d28336557eaa8224b843882b0dbcc3bdbd766fc2becf05348f2bfc85c4cd472a7bc264bd91ddbeafc8df06e53823d06ef34565439b13d76678ce32684f99ebf039b1aa422af1d +e78177a16356284b786a93ce78a6765e11053d69177d7aacdc500a5eef65cd61a77fc39b07e164684361a378bcd99862ed041a28e9f8ac7da2331907bac701652ac3d1a618d76f6d68781c82df15bb465205c6f4dfb1d7e42f1c2997ea578a37e229a6b8b8318a758ff684d58257ad18e955bcd99872bb3df226674858b68435 +c42eac8e41f303ad0083c1a790c6c79d0aaffc394020cb344fe105a9cc4190170b0fb5fbd81c77edabc17fc7c261a5561f34edcda4688369ec781ef4d486c99af5debded2faf3fa8e96d33999da49bab75e89fadd3cbb8ffbc2fb0f8481370080c35dd6aa0e88aac0d8955c5395b6655cb8bd34417f0686b03dfb332b7b39f95 +fcac3e16eef5fc593642ce3bc0f7dcfa5d3203afdf4d914725d22449eff9c53a56ec94c030cb793c870b78787baec6f8ba18c6e0ab83cc082db8f1d80a5ef4f19f4f775d0581b2c50928aa9bb552c7fbcfc26ca785df3580e53c649690cbbef9d3e9b168ba18ed4ae9144813c09c9212df7a25971e0cf39d16d0ba3c31bea345 +fe925c06ec7371c2e002573af3bc6bdd0db363dfce1fd3e1ab46a53e9a85aca5c41a00a91294bc02b8f672bb001c81f29a04d560dcc1c83a7e379be2e6863a97bf82dbaf58794885d0a5a08344d313a5966a667a7c9149147b90e02e043e8474d8097940d6208da26f7ba17dbb94ed8ea730610a27a6d19db0e852f25d3788d5 +c1552629fa38301034c6cf7b05e27566ba9f370474bd4efeff1448d83d288144dc5a088de234b311c8f9182c4496ebcdc279e299a654a4fbd5ce9d212f4af82a6f4cef9bc22b4e2f05beb2820843d69b1e245da30f501aea1f9c2f498240ca5895939c97bd50593b019e1b05a0d1d5b3acdce7848aa111626851878d2dd3d0cd +e74a8165276844b8154a45f81e0dc7dcfa55d19fe3af14a87ef0c39ae2f952ceb9370a1ccafb78ecaf7278b4470dfa26cea6e901ec0159f3a3d68ab0022c8c2c118511dc681e00fbe2a03cf9431e6ceec99f76799053f1cafac04e94895ecbb46e760d058ec20bd9823ef56d4f47bc67c4fa449c3b795a37f0997e34932c359d +c8326eb60037bf4345b9da19d4a4b0aaa618fce1b1b636d983ec5ca5e7ef9a48295d6fd5d2805d38e311b974f69a5dcca40db2db8dfff01c563bdcf623ce76a3c304dcb8e21df3a5ebd78abdb4883482ef0e99b3ddf998812075be2bbb73e53bc69f93c0c925ef9574c42e660d94375ab0451557934b5d93e9ab5c0160a57b9d +e325d4d545d0c461d1e6cb5c5c88b2fe5a6498a5f4f33c3ebc4251f700840fc0ce8e6b2c5aa4ebfe0d47aa64704656425bdba03ab530ad347e3868af9d32e743c085e48550e64a8846eb6b3e6b57e23c641105153807a22c7b929461c47b98b9980965529fc562c0c40389545d9c93520839165dc9f5df9519812ad49f344c7d +ef6fa5cdd389e45b4a5d2773bcf6c52799445e1a00b80e0af49bf59ff9dcc0b719973775ea3309190f9ed31d59c1e04cc2fc46b5807d51bc4b72e86845de6b39c85c809db14229905bc93c986047f127e7d2ae02184b34b7af72ff1bad7fd0ae398e631e095dfc480592517459b551829f814e989caf154ca40e57084b0b19a5 +f554cd79a676ea46712f4e3d592ad62c12f6f5699ecf30f65046de91c2e47eacdfba5ea7d691802a9a57111070daeefafd93a3efbf7a483f58fbe8bb3e38a20de9c438f227710407c9ea34d6cf304ba18e94f8cd18112bfca6bf7256c02c53446a67a66b5d8ef28f02a52d90304db070aaed34d746906e75aed077ed397f5ea5 +cb4b1fd5fd6ea096c48409dcffe3103a32309bb2ca283475ddfebdfc6d3f21d1a0aaf28c63af15fb94217210d76078e43495bfbdc8ac4a0ca483a4a84fce13c3f24ed69d1225225fa3a39df9327dac09030bdb3191354307db701183acabe5b9f4049a98084711d65b76657bf957ab0e1d51d18debeb386a4a4692ee4b10894d +d729e6b7386227bb2cbda5260a2d6d3c26127d5afb20f93086e44d3a2b180fec7ec80d0e6941b1e32d4a65441504557af88198fed0f8713c7ca89f095e1f3ec17174c6e138367f247ddce75ccb9cff48fb13a62f5feea30dc6dab7d12ed70a5779e4b890200c28171b83ac8a348f4e15027e34a89dddd727846edc880fe8a6bd +d74900ff226b5a70acc71f89a6b928ef282d39e17ca9cd334c4262c44837259ac948b9487ce4be7336b9829b9f48382baec51e5456be045920ed2d32b28b744716617e83003843611e42ae9183cfe86c0b51e514200504dde737f86e70c006b996d2d10ca9c33f733dc29497633364674de14e2256fe2b4658755a48226ee91d +cfeb9020e28f7ac0276b098df6fdd9322178b14087b45b09f0894fe673d6f13b51937a0fb6f4f68ad54bbee4831218ba5923d60ca33ea79c5b4304e773fb91d2026b00a773aca6b9d05de79140afdc7f2f4a160665f9e65398967f2cedc78edbcf8f1c1b9b0a6eb2d9eb43b52e58cb7ab716ec235e78106843cdc5e21b37679d +e280bbcced0e16442aecdb68961f53ef97afdfc030a2606d54e2b5610d3ad6f44165cc2c9500a49b539565f24bbecec5b6bbfc8185c815b00ce24bbe6f61032d30d611ed5b78f8adc5c2c45f82deea75aab6c64514e0cb3602a2b612beff2c102c888df5764e1a7df70794472f86a114ad17107a259535f07d27cf18c9434a75 +f719d169442d84d3858146d5690a18c28e1783be909379827ef36bbbeb72cbd71cd66568f2a015c3b4bdfdd2940fd751af4fc370dc2df02d2e836c9e6c27ddf866b646bc05046aa4a3ec49281d9f03a56897b625d9d884ac02e87bab4cb8e9d875f41895a1dbbd77d77c18e67f55961888aa672edff49c0ba6750d0c97c659c5 +c5188adf4708b4c4e8b5da09939f8241abfbb4735ce569ea05fbb948d34ed13408a68032adc0cc381858a100c202975c05f64d5f240364fc699b4b0d7170dd6b6722f46ca9f464da1eb915176cb62ae58ede202dec980925d9a4c72d55d4a1a617c6b3cef3500ea5695276f3c64610703544fbf32b9cff064b12f959473b5d95 +f848376b6da6b8c4a5a6cd5c091f87aa6861d5f074c4656f1d436fe455e222c778f2f9de22e40cf831e9f2978177ee80e29291ffb6728c7c2317b55e91d9a5ba92e2097a9a18fa975b51feb8c9e720faf8b1595f0c6ec30432660744178ced85ee4caab23727e83f094ece52a12ff9bb473e7c1767ca9d4e5bef3b2774be0895 +de46df8ca7a7d1bdeffd0154a914705de0689253f377ba9d71d0fbb4ef39f37fa76585e83f3f0efe5dbd96d916bc6ce65b5f9e9854740e60e06cbff56b74b00d5c1381c45002372995dd149a0c6e17904b356a6b4991dad55880e146b2fe6d2f5a7923b3ff93d1efd5d832f0bfb3f99d5aaccd7a33159ac6cccfe8d2646033f5 +c05cfce36415e5e276a06631d8bd157702acfed8578334c7a8834404723300d6eff52261007b514cd9d8af7eb18458149a71727b5e6834f019910b098a56be457fef0a1242dfea95d6d9185067e7b1bfce3d398373225669aaf922a8c7f556549f050a0e32ec7d4dd8b60aa9f5ac5136e07e87d33d10b41c51344e7c310ff445 +de846c4c59e11179be5e1532e39df29bf5418a0482318bd8a2e86b85f9f550578ca39d42f4fecb8d449346946d0ef2ea58976a392d5597fa171f2cb0b89339ca30a711c02625232f71caae3e51fc42354307508263028f3008b579180acdb4be0f8871ae4beaacb30776a1889117239af7a523d35477a0a97f1ad09462e9349d +df12c209beed0ea2f3642937597f2552dad5e523e29d3ceefa2a6497562ae2d165fa88a412de4a3b9c60c066c57647dba4b62daaecc6472e8a5494a40cd795008c917af115502cf37bcc20869dcc291de45bb0bf3afd9868949e3419c7f573e88bc04ec813c0efb58b7e8a5993de4ce67a8b75efe0ffb0b019e52e3cae42a27d +cc50771c1648fee05dd7f2b11aeca10f9c98fa92fa549e7d58c9addbde156a9da1479fb99802524f074c666e1c5073896613a3887fb9596e963564f423179d93b8f01e4ea28aa4a0cbfb816cea5093a9514ba234d882587a11005bc9b9f78afefa418ff26c7d9955eb50610f9b334f223a7e3279f879e645a700430897ad4225 +eec6db480d9fa186cbdb38ce166dcb9fbde5378b3b7c02e8cb9b0408cce03f5345a115c1578ba63ada5a63f3a67ccdeff0091f145c20550b6d0681d7b15d85a9127e3609ddacd1fb051958b0f0ec9684cc64d2a489144c6baabf7d54b87208d2a5c90b3103b390be118a3857a6cd8f81bd58ec78874d5376efb3f64639e1af45 +f9f7bf19e35163b79760af714be892589c1ff3a4e640d2a95614e5bc1fb99f9e02780df153bf12b2612c3bac9b8207c69c576011db501a4e667a289f8bf1956f600453ce00b57da6b79d143d69c31bf44ee4bef65a6b0a5c4f054e92c82b2aae00c569be359f40bc67b221edec8a21cf1d5fa2a734dd486c9da49af2e6cc2b85 +c55325a6adf5dbecac33ab7115fbc5502f1af5fa3c39e2785f736003f3f02cd12c172700b8063eb97c7467294ec30a80b523398090f6a6536156e53e9c2f0504fb2a75b2aaa3d989baf6aaf7a9a3f9a80e3ac23b3a05204cec1b1d31f0879e9d3d0a4229fd2af6809d142bc8a9d697b7e04a8f03881c01c46caad405dbcd7625 +e55ec0d6b7f1a14eeb398b7504ed6feda7f2e8f79ef3d1ccc0e193311ff39b73cd7afa873e4e03ee95ad3a8d1f1dc8e1999dd2263bed74c6c46cd061eac4544fc8dd67483a9b15d998128346228151d049077f83a7d950a058c5a6b89953694fa226dd1822c8196ddc75911604330cdc09e5c259ca8b081c14a448e9d1fc47ad +e05c896d23616319b2041fdeea81b8da5077aa68a6a586e0fbc189aecf29c432e46e1e37e515db6e2674837a469bb3f44f7572ffb8abb225291430ca44c7eef9e79a7269209362a7f60c014fa5568a98949809cc93fde3ec99ed034dc7134e0d2e8f28f7ef38ded6a1fae3bcb147de54228dd91f7d88844f31c59882bb435595 +ea2513a18692955aa60455f8fe637f48cfcb64f497063a5cad9f7419a1396c992a9a8e9a55615488b374242caf05a80edf2d871e6c65206a1a27566728af9e4f7581eb1741c0e88622d14a9d3c840ed68cb2146d22995532b820771773b2c416a853946fff2a41136de6205c149e3789e394d75ebaaa9846af47867bff3ac0c5 +dd99490b49bdd7f025fe2ccf451f8b25718d1992339c0a1c62169eb3da2d137db4c8709ea60eca1e590da4d20f737ad582c937ccf364f10c593e9c336859fa403de6f7a5b8de16a41b5d49eafd98a94a8a6b3218ac696e236e46307e20a1929c5bd114516e6b6a6f4466b217dbe03de266e7342bdc3384a34f13116c57d1dc7d +d6366000987a0bc50a837241f9c5bccad07a851d10fd8ae8d9bfec1bdf8acf86ab98b885d16e89827d0ed7522a3e2aaf5fdc2d46e2fe3bde43bd3b8fcfe77de4f4ecf80d6489f12807d57a4ec43deb0307b94ac5e610a29c75810a56b207c2ac8747c5f40b6b112f98c0ad59b6c382fd610818630967bf9d8061cce453086f2d +dbaf7fa3ce31316be0fbfbd2f5439fba81d440719459e61d5cd52d6708e3bdb1c51322f33133b2c6f8addaa143ebf380b46d958723fa9cbd0a470fa1ec34bd5d2417380d5700827259bf7d058306b766d600fcb63eca7519ddea51e7e170521dc2ac5b5df245e5dfc19a3c0b7599cc80d920ee5ff31ffaf3585c7c5791c741c5 +f81d4e3e2ee193d38eb2025316be6b7f65bb6625666079abc6e0c7b7f3258ea7c95c53769112d9f83846dddbfaca860519fb3f17e1d1eda1c88e6df313682f2d8bd6018692865ce0e413c72b1882e315494992173477e759ed05766fdd9769c69f852af3dd385aa9d39cea626b372157ed825bd88df7258a1aaa78a0ffef69f5 +ee3fcccabd80601f017d6b760e12f14cfdc876c8e0190550d32c1f1eb6049f5edd356396314b8914a84f6178f62751e8c31fa5bea13d4f76f79c446bdd45a66a71b310a4ec1c85677288ba0ce73861a4bd40cb96cc896dd839227b2b53a358baa8cf0e70995cd7f66819c00a7f7811502d81f8aaa7a90d0851313f08b63e07a5 +e7bc5d453f823ac26bb071e138eadad94528a689566eab8884aeca68a4128603b771b3fbcdefa6645f3e16163a4b2347b7a63d36aff89e97f5b40894d7cbda43f0dec94040067e88d1c2627245462fdfaa061ced0ac4e9743140c1680b07c107e1493a2800f8abc75e403c4ac5289b59559a9fb25e0051ff614fe3c6314f911d +c6757706c39d581ffb923998c8d11656c261d23f529f1ea3dd5b91482fbc1b5d9d0fafe22b0ae8f7caaac98dfbd4fbad7f31ee044a8d467b590c3166abf56a5e3aea37ca2daf4c1a6815f4a503a7b1b55a3fbcf14f84ffb867cf9f3f546b02009de6d3ccfd76b691e5293240c342550ee13a4141a693071b629fd3770a01371d +cce03e4ce3bdb4c846c1044eacd7a400cea051d22c7eaaa0cb1494e2c35a282b87e0157bb72708a21b88297be011ebe06b2a93c28d1edf61821cb7ad6edd14ea4693821c1fedee39da6bc86cf65c31b949984db16ce23fa23b0d4f9c7d73bef86969173b7ff988854cdcf7a23c9b2e3ae8bab8860d85a5ff004349f3b74b4dcd +f3ce37a66647d5ebd8781e14c54b25e738ab57df1393db7bf1e71b0e5c2cff7e1c9aee1228c2047979a6073326c56e969577f196e58264cc3e95addddc871beb8c7facf010236594f33644576934e024a3194f7c168268b64f7082ee9cb96cdf6bd834899523841ffa8694eaaca9c2dc48a53e02199259c77294e2063664fcdd +dd5df28cf7821595a31fd36906f6802b3b402bbb1ad9870cf92b64acd08c8a2045a4ab03ef7cd607a15d27925b3974ea3a1f453c5d59c744343e7686a62737af11557bdc6862eff77c9341c988696938874064dc0b0e1212e6e460651c05edb595d849a974cdb58c498be6e75a8ee339004f121c4ed81b50e88bb8d7cc87620d +d56377fdba499c3acb75cc81353de33f5f626e85d74b9f72fdc0a265b19a7f4b34295a3aa78073097ad62d38575693cd8bc5c6306286891d201e5958c686ae7776a2b3d7d9352fa536f415a71565ca2a1637ce6c1c6dcd3219852a87e865d5d4e018269a20a10b4391cfe8216d2d8712174e1c6bd2d3a369dd005c913fb1d9ed +c24d97dece5958111a0a0d8538d1c15e282f21681a47f5c66035267a89e57d21287000214b069c5acb3ddf99e9ad4d18c02b675ec1b634394901796507a740c818b8859e6e74bdbcd433a236c7ab511131eba2d27414502507cbba401311e9153a615db6fa904d54d415d99970eaf7aaf3a265efdd2021b560eea01b40c1a0cd +c65535ed408e69a5928bb27267ae53024e6ea2a32867212a914b9447d07fa6b725e4337bee9b7b7ff99e065248848111b08d4bd028533cc9420e54801ae0b8536ff3659f34eb9062f1469d6dbd22596ebf993f89e35cd4366fb3de63886192030c477ccddaa8cfd1944ed3aa2288d61d7f931e42cfe939cde98d42bb92c48865 +ca8d20c285a7f844aaac144079b0e9ee4c92e160aff97d298959514223f85d94658219eb8a0740c7c1b59395ff6e57c0b9688e8a843d9f75974f5fab5dcda5a0ebf44dc271c22f0138f1268de1fabd7088f34f181c20c58479fd5f73b36c36b9c77d1a02c3c999298470dbd1a4edc324e3478220ecc4e11d3cc350fbf20ac525 +cb1f812e799aefea75f7ff591654d77fd43706de79eacd8f4972e4a10d433c74f66fb644c7a53b09ab8611daaec1b8b158995d1162f5cd66468d3627638694f0144500412822685b72e9cc4d0f0310cbdf9422943be40f675255cd36a624dab1635e6257ea937ec0a9c2218b3458b9f807bf604639bd3f2c7ea9df24bf7f9755 +c9041cd6b43bf14ef4fe6cd495f876bf7a3da054e826570bedca2593b715c5e6f02f5ad5703196ab717ddfdd926dc5ae1f4eb49f054b8078da6fcb41c8d828833418c883451e944bc1f62a02e87423aeb84f52a6806d6fcabf42ec19ba3e023c216d57215c3c7d475065320677210d19f1806d08fd6a3502f8e157c8ffc7ec8d +c5961a4910ba30ef276b27337bc4adcf01c74a83189305f7be816887901c6eec46d204e813e3d4fe85e812639403102dc00a8e2d54c858e54d69eb45076ec46b826c9f6d9eb862a5dcf168fc71c84b1ae6a58677fb16eb1b11f37e0844a84b8b0bd06c33ed5b1d61b0855cf220429803872218f736089e7f0627927c01891b5d +dcbeda335b757bf79323762fbb7b849545bb717052586afa644c0788e300c07b3ef64437ee07a0b181c83cbecdb49b91c4020215fd88302a232c8ac46a0fc1c1a2fc8b45b66f8e8ee21135b1f186f1faab41ece733401d92ec4cca066d6a6490d721152b5547bac7cc4f1027ee7c6edfdcd8ed22d04586fd159cff4ce970b245 +cf4169d4412da9494e211cbf5d25ebee47e7e48409e3b9d76b4bc6da0f91836fbd40b4ede0c50d05a63d6184c9495dbb608d3e57117d086d30e35b121acedc64dc75c5f7c760cf9d1a455f171a2fa9864f404f7188604a92301b5fad6d5544de323a74888906b6177dba5a643ac784ee4eefe15d6833aeeee55cc9a0f6d699b5 +ee2113d74d47670f7313c08e615fecd2777ccbf355bc125ab0bc48151947af19b99f2cda5a815d5c44046e74199595989d1ff84205a8a2c976f9e09ff0361a62c27b3575d1a53f3d3c9c2681fd9528a71e22bb630f9ff2b9ca1a77c54ccfd699595d97becb8764cad0383aaaf908368acc311b43980cf902885d0cb13eaff335 +dff036be4f36093f2e20781547235c6b88f82401795e0cb513d74e9618236af81d9daccda3da9c4a5272d2e10e49a776c7baf5f2aa40fa61e1003df52d603a6abc2484eb807588826d5027f5529fe01b6651a71dfb1ed23990c7ad12a6902c71282e9083fd6d33a36919e51b00d10a47582a9dac65b9d192269000c3bbdd6cfd +dc0d7122b50d0b27327606cef7fb6380d0e7f7297f5076c4b4de8cd76ef629745d2bf9bee4e2b1fd8f37a1cb11758e98d2f2e54583de2a3c0c339a8bc8d013d48d5c76297e12e18d03aaa6f242defd98b145f5bc37224c0f94f895132b6791392e7d598e0b39c2f9badf8631f19325fcac3b8f8ddc655914ec249cfd9e0d0e15 +ebb816b31744578bbb9b10c8c0217de1c20b0ef86b5bc6da94f5708d0140618a56699792225b3adf6e9a02b68422ac0b9f8bc5f676944b4bc3382059dcb33b5343e2bcceb340ef9faed9044814c41de3cf862e07a2bf936a6e8176bc8217e24169f9fbaf8c09b321e349f4d2364d9e37096ef8f62e0c0ed640adbff7bf7b0135 +c68591f3244def5bd01eb6f7a257842fff85f59e2243377e0d265f1f1b90e478b563d5085d1982d96ab881793e195a168c468b50c2c16388107761bad1278db7529d207c5a41ce77bf1cd4a5f6b16cc97b5186f821b15311a07ac6ef0df2994372f2f52c3803ccdad0da78ea6e7527502970e09dd1ae7ef8e99b872beb9f8045 +f6b4a1c781d759e5f4a13973e003264c365893c9f181e5410af0820d57ad417039913bcabe466e43e7e4d66d79fc564a627d3bcde846d5ac6658ae09444050515953337a9398bb1ceefea37c72c67f09cc0ce3f1a4091f52834003c3f180ac340819a4fa0e9fbe074f9d0187392ecbcd024f0a90649759ac83fdf7e77593934d +f6e7675f852d318d6b402d410762978cca8588326d5bbf84ac86160e03c426d90ce167b041d255993eadeccf331e7d0cb57fb25878da293cf2b9fead61e9e080f2488d98e96179693f4492cfb4b6df7b24446687e1b880356779fe408b09c07ae59fe64cd4bdb209dd93e37d6064f6ebd7f0b5d3316e77c916e515d608096fbd +d9cc77a38c2e2c6ada42e24580e3a801b85020808778cf7956f90cda127aef2416e931aef46688ec937d9d57401820292f1b7ef0b956a9ffedfb4fc5c04f9e582fb527d7e09d68ae5cfe1d99b47b603302a89fb5b933e18e4f0a1fdbe591974537f59ff2ac171bedc72ae00100bdc4891441c2767fd70cc9917234cb6f7910cd +f29f0718f61441e6a7fa1968060a4624c4e038995140029615e447a2ceaadf4faf0b650a448fdeaf4d2bd8a3467fbfbf1d413dac1706b7d4d345daad253a8e47bda4215bb71898c7b4859dfdf9011f4f14b76be402efcc22a3f65895847aa866ecd65492a53e7b024513878f197e23d16b6753655c7f2f67d1d5a4df6112e87d +c38400b70f59f672e31bafa81bc5da25f9eb83c2892534d863325df19d0cb4d161db7d52e5d96ca6d4884cbdd47f8f95a7f59f087933df4c687cff3c1c09c527e559a50674edad1f798b233b3a9e6bd0f1d2e14933ca7d27910e4cec9022fe6713b6d774f624968cb2f8a146c5aaf48df2a44171e90c98aaffc5b45cdd0f5295 +dbfdf8391f3f46855b0effd42884211a069a720eea40b4045e05b3f7b89350b3baa9349542f5dd48e6c6675799ad85b7ba29c0d7163f9ecc8a5f945e9ab62cbb3c05f018e07bd736b3d245c168ed0e7c565fa8df0dbf75649acc4a078f625cbe24d7d102bfeb66971d97774e5a2a686b7484260e762c2cbe8218412b255cbc4d +ff1044955a4a46fe88719b98b4fbef3610210a11a00f28779409e52a898a2a62d383379e3892ecbd5594fbc4c54d363f2030ac48f0cf8031904c598d494776c399cfeb0be3b0b376519e82981cd88d0dbb656ea1896aafc998a00c33a7e8e619fd64838b70bbde315812ed2084ac77af17a5c5737cbdd211a0559f178cbc796d +dffea7b7cc8dd939086609c14c85234851f74699f5df1de82d8f9052f8d29c4e2f5af05fcf1e0111d0da7d216ce76366684271c14e56a56efa08592f7c0aac245aa1d4a0acf19f921884f50cc320fcc76f1cd094692634e3bd5142cb588e62687705b236927f77e4097724c5936523fdf6633a934efa57ecc0bbb109e4301575 +fc7089d2a8cfc5cce0d344cd5ef8b83274f0e49f7a805299bf8adab3e89a074d9daa62f7ae3b8127b628a11044a511061ab08e7751e9603750dc5a5f46a46735b5901c118a2a839d1232d2cbb429c0a7588847daf657f367560e30412e984028bba9616754eb2f2dbfaa3ee4550ee81898d933eb5c4339c1f126bf9286e7721d +fad5e667ecc443e6caacb6ca76599adaeae84cbcb83d0713eb84f13dc7fdf4f0d208ffe47ea4a1d67375df6a08cf13067fb8bce071c39a5a75e94363964125cdc689e499394d3c7d6f0ca6238668024221f82817d132e981c72075db853262cefa4bbebef031efa99dc6ef5384cf942c6ecf0746825c9ceec4cc699f2d4181e5 +fd1b4d7018b7346ea508723e0a7d3960a8828e7789230e1cc749340be4c93b4f424f598b1acf0d16dc515cd6ffb9739c5d52d6e8e9e570c355a0dafef9dd7d61071b0b4ad1f9189df4284308d74c34eb8dcc2d9b9d8fe66fa96b0b221881dde85a8583145463d45d7e1abf1278da2ea8050db5173deb108d12c70528d9c4745d +d58a4da763089093120a6a32735137d1ada1a5ee779329ee0c3c04036ad92f36ac3d4ece8e47e6f3ed86ffd47e96e36c245141e64bc20a825657fe0eb15ca4dd9456e59f6769fb3545f5cfdab573f9ac9ff9ad1dc55f012589cc6c58025df387e050d52ad8946f9618fbce898b651c8fc155827229a779a6876e92dfb484ca65 +c9086f19fcd869343b4a3c21ddfc79caf54d812e21049ee968aecbdbf22ca5f4e211ac94595b28f9f8a3f7f21d5a7c95bbb92a5baa0906ab3ed98694a9a3e40dba216006180c472e993fb1674cbb02c5dff2e77d2f9d03323bb0addddb2ed040c1c55599377d7e98cb0386cb2f95b8f57182ec2b982cac39f01243bc0ad89565 +f461eb483e0ab79a1a6d670c7613f6b04b6f3c2ab1bf12bf20d108f8c9234e1fdbd4502bf829be59b4ae68bb90fbdd6d5b19c5b84a3a512190adb31df2a4e29b5fe4991ebb00532365ffcbf462be7af9267e06c252ff251093bb6a442e1c88a0936aeedd25d99513be8af23447eecb1dcb06ff24ad868e44f53c790feaf4ffe5 +cf62f209d35a652c0f29f916da23634d32148391c06f3e9691d24758b87fa9dded4cd75928a2c4f3a097a0debfcb6928405e50f4508e16482c30f4a6401e1d32517991d3e13acba0397fd02483705d3500f81cfbfac3c4fe75d755999a9a6587b1ffd34f71a8ee827372616aaba8d7e44532c639c104993815efdf23b86387ed +c355f05e36c6438f1fd6ea0613892c3b71931a3af6738797cfc8fba634d62c69b1a803f4e779e3581b1b834fd9ab5f6424cd08f5bf242f71435944a2c31fa93bfc8ff5baaf40f5e378962fa3c10cdd5a1bc8dc0a0ee910d6d7182f5bef59bdc4ebea9f46108f0c78192b6cb94d8e259be4667c7ff4b8b48f51fdd34600fbd7ad +e9704819bdae06326676d9c36cee870a503273e9e450594b52a16ad584504f09fd19177569de2e3c2889d461257b6e69d323ddc6534a672a999118967bf283b012fdf87d9301c37cbffbf49eee882aac5dd871bc137396e9a184f1f11105cfb6b88fb8665a861f0894ea4270fd93130a382b938c9218143345e3f7fc6d24bd3d +f935d2e497d834233aac83a32151b1f19adeddcfbe5145a882e0faa6a53324dd21c79e5677eadcfe93628a58f70bb18d004fae06197b01293b3d09fdb4b7aa0ffbf7059c62185fc4a30cb957fdc13062583c3ed2f4e4588a7d63056e7c2adf47f6467697c6ce15cb542e92edbe132c1d40fd56aa4de0b107e3ff1582e5c0e475 +d51a8b2cf9408add3bc549a140310d4c8df4d2bc68ec35306ea146b90c2d19197afbf54891a240bdd1057f3d8238578ea1eb2e7c0b54676e4b53549fa074bdbcbe794d9084810ab6e0b4827c739e845912f54839c37031482e5953f04ca7b5c39d28c7d97646508675386085a3b59b011ee2b8aea1f46c052753376fe5e027dd +f7048051b96422dd7f07e4fe6f1b70b95aa981f6136cf00e05f8bd1c90d54e425bfecfdf1c5522ac89b10419f898bc1c0616ee8bc703c0dbe4835ed1f56ae159685535960e386e662ea504c7b9bdb1ae7a0cd46e79eaf6e72e5aa60cb58e1c91bec7258677438198287296625f65c8e77db2c44da948d8a2f523b1e65e1f08e5 +ef81839f7627a4798900fdaef895cd619689724ce0b8b3af8b12711a1b7c4b89cba3957f176d4a74668a7e7eaee137f9fb144c96355e1cc7170c107f513a2a09d3b053c8b1b6fc9134c084e5540b2f698190d43b9a1bbc0d0cb77d3c526a95eb5115281fb66c3e3c569460d701393a91e41a1c27be304c6d4d352864736f791d +d06d19436af8376073fbf7527fc3ef4b54e6f6d7323cb3fb4de5547ca75c7aa5a975665c9eb6408447eeed168c75a94c24bb7ea1047517a2991d204a10fe798d24e57d0d907080935492fe3571aa8a97533d0f836ac2037023d22ff0674954a43f144d5ea0755cd6b5a64a5f9da16966c1a40f757081a59b51ae50371ccbc14d +c91f81ae46dbaa65df1a6a5e5ad6e663575559384d94123b2b25c73b67e9d80a56c1e7e503906b87d04534b8d1e0ee788e45458558b4aebdfcd4054871c00ed3f1913e25c154619b787d62fa362c92242189f3b12ffb89ec239c20fb9852900cb73c5b6aa681165f6692321078aceb4da6d8c6753038a624a65048a60903e72d +e2b88ee5f593780e9536660e1e277047f5f00f2507c30923f76355443a88bd194546598aeba7d8a594c461973c066c9f1b72514ba669678a85b5706637ae059459d99a4d9e1bf1a95988226df3fbd51b0c08bf65ea092870f902d734f2326c1c82b28e32154b7044be05a11d4ff9505e8b22e991bdcd295fed0d7d520ef59aa5 +c51bae95613c3cb9ced85c822f9f63284b4f69cd5806e5f17e0691fa5531d3a83361e042b796f53667517851bf533915ade6100c5e35e571fe62186af6a2f6b111f7b006ba1d2dfbe15177f0df69bf48e59bb15c38c3e5f2adc861b99c3ec18e86cc2ef60765a1bea21c66a4a93f5ca5c824a33e3df049e2294a851e607d98f5 +d44dd9aa118e09e71722661f274ecbe1dea8195148b3be5788e0581a67b10c54fd565b1206442dd2e6ab50d0acd466d4190fa2b435c93e6b3599f38ab8ac197a97c1b6eb85ece86f6ffbbdca079f844b9e7aced5a1362415d7952785bc3d7f7759cc23fe28b1e7004ccc809956462a5291d03ea4db7ad19c160121bf81b6ab95 +ef78419ec73c3b5c017aad711d0cb29aede2c53c6849a804fcfdd1e4e8a32d26e5d024f3f621e0053c03fbe25ef5becb19acefe10688585b80d1504f0084ff606d37b8c630e73f15736dda94e82eac69d73b1fd69ac9c0af1343dee6b43f512d93654a9559331b93ab76767e5437d42e8866b68140b1c7e8a8de2ec92b96d175 +e0b9a8df9507d8acbc32c9782d83d3a67e5e9601c155794bfe29e065a4f3bfd5c923001a143473e1cbd5d9820b73bcc1014bb1a7381ea8402a01734683529b599b19505d9bb7eb270c9b64a57b98f97554ff8380f79653ab19bac8ba59bc057463c497239831384ce93c4da48c0ec1fe94403ee965f3856425a082d5bb9d158d +c88f3d02089a37c3ef9de421da396c22884f1934cccbf6a603eb689c1d6d503cb9af8f153dc2f2b4a57d4e3731fd0ac69bfed081027d0be77f299903ec52846ee784024559b5d13ef76dfa4b365d08a6fecb2fe5621dabd3963a3ff799f1e95466633169ad5c5ea044286baf5fb3a19a2a7147affcdda544c1061da877b978f5 +fe6cb780781593d1e777f946121b55f15059ab69f8c1ded35a09e6c29dc4ed637bf0dd3e11a7c056af7c7fed27e98bd80a5fa2ea7665a82b8381261c7e764f02fd5f605c7b8059161cb1a1e11f7632c90d417b460e32b3ace20a6948168ff52dd64f5c17a412b7fa72674baf8c1e24ea62a8319b3533c4dd04b840083179627d +e14376d91a06128b4239141f7d4b1a16847d475a02660e0304396ca40ad93b994c6d501db2cc180f466437841e76f798ceb5e7523ac41b4237064b2b31245df30dbcb6a076cca82de707e1b45c8892556f9fce262ef24169cdd7539c8ec04f497f5c4b28262a2622a650648ad9d4ae5e1945a443562a8de81518b22c42bb3285 +dd6496c4c984f5305b5d7e114dc2184f75ed627180145f331049bbb0f15e14ad2fa74ba7540206b61ce364bd191230ae6ff2d8c25d378d6ff9e8d08e4972a015b917b43ecd734d6defd9961cfe7ba50b916294c9e0cc686c7a496eb5f44c98c44ab974af71be0aa50f5f47cb902a6cc004289ee1e882f9a71bd63ca3d1160c6d +cbdab7643480f2ce10c7f4f3effa1491d7eaf45109b5e7e188cd5d8cc3d6f17b220d774844d4d130edd0ace88a8758d951187405c4dc67dad60c15eb7a2b7695393459db06832e96bb017623dc617c0b916484542633c5c68c0bb44ebe306d9ab1d7e33fd50e328cea3f256393a822dedc68c8af63388462b1e5b2ad9b72cfed +db561231fa1ec28360b09c579bb5cf6d4a8038139fff0994a34e325ede4ba9e41cc65eb04294490880891eb4a624cdc25777e8ae54cc65642e3e986d25f0d1d68450df0bbf52f2b0ee5da9769b6872b39abbe87dd4ebcf56f16c4f8c59f7b27d49e84676ee28980a68fbac057e0bbf69a5414859aac4eb110e18102e4d356d0d +d13ae235284d459e4228f01ab6c8b9ca0df6eb563c83471c32d272e8bc5708f1dbb853d4a225d019b0d63d244a79bdd9cf83152b5c568a5cb378ae601cd96864cd2fb65a1adf1e0fc8cef28c367f44705ab153b86018287fc73892221877eb2f544da6bd09ad2d9eb5285978a49fb3536b8ad70cb0b5dd96577b4d284ac5c1d5 +ccbbb29d9ee1e4f113219a526ca77d70a7b00fd13f9ae423d287c8fec3fc4d128a3f29110b87933f86849161f57c1b72c9309fdcd52390535eedc3b18e61acb6e904aeb4eda536a74f53fd02c9fa903f2f60532baa57c26755168b02db0c3cd311fea7b833ef308be69e8e4408c23eab0ccd3222231a17b74438a8a937746e15 +ffefc0562538685dbfb1e3184c5c855dd0a04bc340374386134f756fcd52deaf24010cd012ea90306be7c11128326b8e940a441ffe90c81c7096e11431482a8cc42576034034403b8a5691d28538833f17313e610558be716afed80807ee29d20b309106c06edd2e7cb06f905af6fcbcb5ffd41f36acf88170330394db4504bd +e3081868e6bfd443207bc3b51e53884770f6dfc227f5c4ad5aac48192c838b7d53b753365313afe4082f5763d93a9362f362434df93b06490bc0df7ed1a3e69811fd8e2f2daf8093ed7a3c55744a8e2243eff50570aeb50180d9cad962af13522d80e562dd549840102e4af3b654f62b29a8a035d59e04277e3b8204989feabd +dd467258d247ee309beefa0333ad4bfd4acffff39ddbc44e6cff2492c65f2a9cbbeb33b915141d7361e579ca387ef3e55105b39db94a006dc92f55d104b29b2d9cc52342e58ac426c5bea0c600845091de3ec35bff5ff3e181c8c13c763ed8ea37d5abf8b39f4583034cf575000216c48d56338650cb39a4e1806c7dcd5b3d15 +eaa24e93d42d27e4bb64120d554c2ee11a095f0f9ff153b835c94e9a2133812d5ef3a22be995af15f6b12b7288c048a6fba834f4698e77259b5a1cdaa740d550383c2c0be7fdaec742ba71148a08d4934bc8e719edc0fe65c32ebeaec3221f7566b9f8f4dc076a0eff4a35f675852a26e46914c5bc2f1012c8dce0f5f6b71cfd +d1ef6b9fe5c0ce5ea98ee2851163b31dcbe3626f2c61e0343c3518d407aa23e14c1d9fb268c844608dc939434e54a5c20f2604c1ddb5fe4f5e71956a4114021758963fab0f569d82a333be13da8f80abc81693de7fe55bec0c53bb6f2a92f9ec80ca756367aa767b39d5b28fa21a232e9f524a2b08586e3e2630c073710083f5 +d0898926fb912d9a6a570a895aedba60ef0f47192b21b7ec097f40cfa4eb92ddb3af30bb55a8dc66a74a68fcc908f19abcd9951f06bd9ea57d91221135c90bbd191b53c03296b8e5127978ab4a7538b3f1a975448474b2895e24eb45ad71bfb24de5b98cc1858a25d1d41a0ae575b05db820aebbfe82a1b7f362509731780fc5 +c77eec2c2dc7baa150df52db49a9f9d624da0cdfd2f20ae97d27e948321afc76aa9e3453dea6d7decc72c8d67da56f57de1874149066b20726ec74b2dbd109bec0fa05c735bcff108ba3e966f00f6a5bfe868c5b74a7983bb0d3310b80b6d745b7a288a73ee40951329aeb18f1b5054a4148a89c7cb34b0f5693ad7e7f29577d +fc417d0a6a65e7a90ca52a82a7ab97069e9845a248fde683451ae12c6fc24391063da1dfdd12adbf2f6de878a47ac0954c8bd6a13129ba1aecdc535a16feb591ede4a8dcd5b0aa9d40129dbaf29879af5debb7fac908565977889ea4857c27b6fcebd8f0cec0fe5ebf1b0f389205ad4976726aaab02045cecb7f3440231f98ad +d3339da1f1643b18af3aa714ab2fef6e2f229821d1e9100261f4f696b972af044ee21a2c0f3f3f0cb69cfbbe06409057a02e6129a3e6ddadefa12639ca150eb9ddb0a2e4a0b5697e4160de6d885061d71cc5ad6a19c7e002078e8ead1348a3017758cf3cad68d70865ade96f3334d708a34d5931ed105cefe0544e78a4388805 +e9065eb79ee92dc6837b8aa61f7e99541dc966151f34dc0b97506a5666090d58c815490a4170097a4b5158aff94a69eea153561c7e332b387c42f3563ae81591e908b0e2f4449c943e7586bb4aee61c31d9640f440d08fc1bca84f8575e097817984e803705a513ac3c852b702d7675d5782e365eb76995d1ce292194039370d +cb211ab2c89539b83d3b4f8ef0edc2e2a061dff45c19b8e25c9905049323f59e42108359467529f94df66006d2b9409f1add75c7be360e29805570161d3660c96038c49bf576dd84f6f9b12aae23cc8bd268ee48c29b5fd3c13c939308214c759c7afeb89465b1bea95c292a0481cad727acf3020a44cd639740be98cac94515 +d5963124a849989d338e6ee7ffaa24830b21fb0b32e6313e3ea77abe09b62ea4bb29a31c7df9c38fdaa25f5ed00abeceeac3c79b0c33dbf19380a9a88cd6cfd09e5bcccdbdd644ba3e018893800a910f2e99beaa7efdf3358ce600d20be8020dc4168647e9a530ff61673bac47ed53c63b39e9964bc542b797de0a7517edc385 +dda885206c316fb8493450432e705e2f202dd4d5a35f86bf6332df0d50729aa3f86bb71ef78d7af36940a1add9f8679f0b8b67e828755191f76ff74e1b0530a9a2fca1120b32f28c3e73a9e51f9ac3be261c91919d936c66e2da8ef0b23db3c9a6b2c3e1d71fc634319e99e758513396352fbc9c978c3e8746e9dc6e943655fd +f0b6bd708eeb9a153389eb769fb6b140127f876b4116fc7f72dfe4e3137951dbe9190d6f76916dfb8dcbe8c8ed02848386d8d43298bfc1d6d6daf773156bac1cb2463ed1232902643bb090eb604c812de60c1515482bb3217660e11eaab25865f375d9fb7a5257c80bb5019056e233bace203cb691fa15831ae1302901a7e8fd +e6e9ede06461fff5f9fa150353b9604229649e454bc1adba9d30d58fae3f9bbd45b45c4a257e71163c9399a1888741cfed9ff01ab8167381e6f16e6e16cc2aad73f6c8c30d1d0be9eceaff662984aff469d85cbe852086beec64a5c7a2448720b384b79d046f4c41408402621d2a676aed29d24eaa99088d126e947f9e240475 +e99b898150f7a8a2d907745b3cf293f2484957a448f480fa2fa9d1069ac64ee0b34fc1816558093e14d8675e12dc416732f6102ec9cff519315806c2d75bf4870a2aeb20abc04717a8246b3ca56ace5db90fc60b820b72876d92a6a4ee263050d4a529ad29d87f626f5e9c4385ceca30076eab6340e31adb05490e3fd0228ac5 +c2a9ae48163c80e187b63785aee50b61cf8cafa1f41355a404b3bdcdb1468318ed913fb4294b51e7301d92f1970dc01e4320fea142e29cc8c10d083a6b6523829a13a762fc6681ef0622ed11d81108fa814b989eb435dbee63e025f9196761850054ed2148c07387a5f8f20f6623f6531b4cbea6ad00e8398c3460edd9c3b48d +d5b9d5961ae8595d6f90402dd03cd9af9194ccdb9c30db8df9e4e3951108f739a6b095eaf6be0a44e681aae508aea83ce5aa3875f72821a8ce50086c91f08a731de573e52ba0a592b5f8e3d92200aa1b742f1c19533a4c321873ad2c4b5f5f24b2f6d0ae92a09108735c0a8795b476b92a55bb65a86fb142318f63bedd26cfc5 +fc0e95da298f47b4c5c200cb2cf6c8250297a1cce4de3a070884413f6403d2410277f934161acf154e2c2987279f1b8a1db936ab1232dcf00e02926a218388f972f4fd47a2299af22b9e15b9909154c0b615929f13fd058f331bd1d3f61291373027c965cf07ccbe762fa5249855ebbd897dff7c802bd81a7f89e5408b4a0a05 +fbb36d7d5e2598ffbd50b3ab673e91ceb8f99f6eb46a756396bd2189905426d492acc0eff5245cf16231795c3e3e88bb11b2f66c7c5995130f7679072addf04f7cbd9059755ec8c3163ee8390bcc1023aea55b16f85972c178c46600a5bd20c8aabeb7cfdc9731acb2068ab311b1665771d4b19a8d782fde357d9db1e6828095 +cf448a3d3b21c41ba1aee82c0d424c2ff6d5afa1bc2fa3c82483c0b60ca0ff0fb579cf87cde23daf83b1077f1333aa5f51dd14ef5d3c276cda122df9e79e4156e16f97279b054fda035f0292e0098ec65d9ef02f2c6076016969d58e1f9fb671e356a956eaef3b449088b2eb8443df2cdd4fb09874f6614328c41e5ac0b67e05 +d3f9360e3d6ea978fc7d18f492ac4696929fdec822744c17ed262748e6bac0547633d89bb9c4b34bbd385253f170f262a22ec37d0f68fec97a193b23d73a649177864d08504e9f952c5d52d831b0fb7a2444db147c2f1c4d5d359deaa19b5b335b968d713cedc0d02dd7f08537bf3f51e17ccc440336a242195c239f5e558945 +c72746e4ec4cfc545d4cd3642a4775a04fa97b2e502f52783f56f90e7549b82655053833afbee2472fa7fce36161b90b8463c22511122e63f9416e075517e917b475d6c7c66bb61dfb1a82391929213e05127a704dc4355b563ba246819c48bb8ca27cecb6633aa89d8114e8c23cdb470cec30ead9f9e815809e7cd5bdc51f0d +d2e429c50f73236e0eacf38428572263d1e37d3ca438d9a4738660097c26f9fb7f4c5a28cfa789465a5961c8a81eb6ec5ccecafe1022fbb5bb1c7bccd93be66f1058ce0fbe48c50d961744f507cf4236b4cf5aac01159c634d831941072e0ee1509c78bec8a8d8867273a5d59cc772343c9afdb86e6a50a8cb3bf1e65be1f405 +e0c9f261bcee9f861d84c726717f65582c17a3db29d18e1a5e4b3e5cdf7cb850de9e9cd663c2a83a5ea9282e255c6003b77eaa0cffcbf0ea1d01c3b9eb52aa0358cdb52ef08af713e077a7e4afe78323ad1e0e911209d3e9eb23cf1b4f9fba7952f697e057a2ef7905bd6988c7c669c317dfc2e5f960eb1b5c645e1ae9b6bf0d +c62c8b51ad3c9e9acdd33a4f4ea308e6cd444a539af5cda31c40a39769d2bafbb632f60272615ff1d5829849ee087f0351f7ea347fa6984532dc286ff1932871c7d11dfc6050a02633b3782c2a0c2ceb219628f6a638d14d8e438908ddaf6c623bb4c69a4a5cd313cc8d17126bba96e6ec92e501d8e81b836653152b3c3a9ead +eb161956621add40a0cc0ca3f3bc9a60f2b0f6a2274f4038213e3f0d288dcc5066ab3813fb42687196ab29d76f1cbfb0b0be7cb9606207a7732817a49230b60b9de7fb8e77a20815b83f84850dc0586025e12223f82823d6daa6efb34b8213c2c439628e81850110815d225305e84165f1502239ea79544d7dc322e69aedf2a5 +c9b557ebd4b4ded4aaa97bf4db989dcbca6a741d59cca239ad8b0121c35508f33a321a1fbb9123d9ba370ab69c70a4032f34c32af2d6a54d7e312840171ac11cd663b5ad8df1d7bf6f9bf972155509c2beeb1c65a0a7b85a857a66bfcca4a62cdb4156a460e2d6274e8589ad83431f824eb51b3f06522e52f7c2d3e93c541b9d +f17c93e94c7ab2f777f518ed702a02b4b527c8d21226a7941559475beba02d7e8271bd3b79b78ef5256b094610e4345fe43802210d2e9d072201436933fcf3243323b7b708f93ef223f2eee56023307c0206979876772ff1c302d9684def77c5c37beac1ba407f1c92f23df7e380c4b3dad03b333f145293737e48c6e4c29d2d +d677d7f7b547fe2d6e89c506500885bb6000af7b109349faf06cd588a829ff62b5e5f72da766cb26f49c41e40fd743f03b887998ab0dc0d691fc16073066e3a7d3bb562d25a109ef7228849be098bc41a94d1635d61d0c07de82649b597eb53384b4008cbfc981cd2ad32ce65fcae288c6b57e8410ea504e68d169e3a93ad3ad +d2738f6224131eaa57bac0cb592b5888cf9ab32c5ca3ac603f00dcb7523bc766033cca5ed14e1e85acb26e537b1506bd9ede1169b6771cab017e4b65fa473290a2786ddb0c065dd9e13d3fc3274c280f7cb99f143a3e2f3e66d3d259c9100c7852aafe78aa36b33545241a422734d1cf216c45a1316b7f5280656a768e8a5f45 +ec9e5721d7fa361c5555ae29c7c53c91735b9b9cf971dfa5359f7a7684ef737018b70235d9f856766fe15c87829fc13a0cb22afecb906af9a3d098673154121ae0556e17e94b05784ba4c3b7c0adcbbe8c595c4cab7c82c4c8dfa9f79c15123af3d9c0862dd46244ee60cce7861bcbecf41e1b1d39a708135bf042615adf3b5d +e61ca49b6676e6a5a59d07f5fc51b85ece0a7ab69f0a851f71688f3aca1bbd19b4cb9144869f8827dca9cbfffc59e57cd8729bbd313b8c1713598a584bd9d2f4027c6f88e24bea6738d07b5adbf8c0f38785aa33b6666664607acc77f4f3fbd350d0bb51da7d2693f1fb35d0c61c269ee5f50414b1a4441f72d97d429a6f4845 +f1ba2f7d8f063535c811c0b268d314f93340ea7c3d418928cd5016a2e8224ada2b4228959e6abe7c5c3c9e2472a5cf5ec6d21b7449af0bfcb00331dc64c03be20d75f7b29d2d47642792bc9acdf2f1647ad453fb3e63301385dadc8472048fc73a32e7d3fb6283994a322f7ff6cb8a419886c2c0f700ae704f34647a97daa8dd +ebf53f293fae2b16f3d0a34227556cc536f7f83542a627b250a4b6e8e41fe8a7a68fb9beeef8ed233bed0ed4419eb832a6e698d0ff6b7fb95617e2ccce0561a2b0f124b15bea9b59aaf86ec04374d7942bc6a7e0167e5eeb360fd6002fca0dfc7935a8ba069d47b74821777900ed205980e1b8182792dabeb5858e8e2f0c35d5 +c6894fe616cebe6bd407afcfd26e4ff2ce32f253bf530de41ecb645f181806cc3d592a18024d67ddfc1779788b80dea06c7c4c29ce0294a1dcdc76a30f173daa97c55a9f34aa0cb8f5d848a5f2f706cef4eb515397d4eb38d493a3df2b582d7644c3902b780c93f0c5ded25c50fdcaef8358139741af17241ff861f19a5cda05 +c044d81f9543061edcaac544ecff31ceeaccac638f14129d9df54c34891a9c2482766445a37e405493467ed188b570ed1e8450e6750873170f4ee3c9c29a519b0f17bb935cc74fa6cfa583f6891cd935cb8868068b5d76975074ca7d4c6f2cc0156a93e25c5eeb03d5fd6d7858b599f15fd8ab9e6b5dc22ad1a302f96775cdd5 +d9ac0da9f7b0cefde928331c9edd485728a4e4238bcd2c4df7c1ceef777df025a6c94c27ccdd49476ebfdf8dae75603fafb4563ebb956a6b73b381dec4d414d6031d3db06360ee425b7f104e14b993acf1594695500c2ef559bf9f569e3e33232c5333814d1060c696b2c0c58ffff825cd92ad1c29bdd4e0ae4b711639bb6ac5 +f2a92c73a5decd8e1e36eb832029d8828ff031b759d366267cfba24e35f01b45c637d7727322e60c27d55e65871362410c3a783decca9e65e821d5a21cdb8c5d97e13cc11aea383fa8f26b602e3a9d895ac042df6c2bf9d42bbfa6d11959cd9b9ea9d5202a857ae0b3c04b7097428f3291a50e86d07085e24b061972a0fafd45 +cabbe2b78d742f7d8fafcfc03d8d1c5464c5379c6a34514b255add1babd0fbb955b3280f9c9b9ee22a6139fdaccb09f1bef5f64058b9cb24aaa23b4bf88a7f34e3601ebfcd12ebd497a70c673c58b303e960be452f19b397b91e2aac835c7cc395ca2b0484272d9cea2476be8febfde504fc9cc392ae1cb89e464fa226f3eb55 +d9f356c3beb34dd9d2577d5cfc5dd9d7571cf90dfa1302ebb0bcfc194de5185237457e7324033655050e22b976a45fc5d54b5b22c0d50ac7762b6d812c5f32d682624b07e71eaf335c85205606475cf9206fef4c5a65e1c90cf4bfa74a136f592878410aa2784d0b30373067c2bb529ebd24f1c50e941137d244b83d903f586d +f2d4f9085480253f2946c7f41189ad8351cb734f6219905cb6f75537d6b505a49c350b5af52386bc59bb946ae662690fc349e18d31f70084b72d981fe557a70b2ebeebdb16a25d63dd93bfe9ac1c2a919ceb92081d7f47f5db53f9a66e5907c83201e41028544d14b1524516fdfdc1effb6741d79621ec127545ab4113d12b65 +ebdedff63552b39b84b4435c4825a88b523de9c880e30afbac8922f6a296e00ff02296fe3b66583c7848daee7b2fb7acea9144d7a5d3b7d2ca7c5e109584d08426069bf599fe097272e0dbe536caf767f0520b25ea5f678a255d3efff629aca6435a296f7cf6d29bb4c37372701c37ea7a952d483dd0d54c45ce6e7fe61e1d45 +f8932edaad8028dfdc82072d6ad44c32ef59fd388b6573848eef6239700a431e11ecffd167470a2d4d05f2e6522d69009b6883f55baac1b894039b13b98d6b5ea25bdf219c36040964551842c564b8d13ebd4b729d8156636bb7fc0a7965462b5b3c80786ec10827533be07445a6f66e54ade6155bd008f710e8dbe69cdc6365 +d143338d085ed0955e617ac2758b534a1fa75838e0f10bdf4192142c3c47180ccbcda159813a69c9f6db92a9278285315df6b65757d42a2a1555bd4ba3477dc65a9acad854a6fe0b76089ee6d7b76143fa08a67a9e98927fca7212ec94488318b291858f4fac01171bf595626dce76ef81ac84cd58602a43770a71945e41f20d +c7ff71337de97e9bcf2e125b1731a7ff3c139e4e999a9992c4d9b4893f4756d94507a366a6d8d435b5f4b8618a36cefbedecd4fb9d2c2441dc47b085b89686de53d9a1a7e673546e94db1315bc8369e3866965f55200390575a1dbc4e1e8b06d800068254a21d54c6d79bed40e25b625f6a2fe012635c1c7fee7f60e49582015 +f40213d83153dcb0b019d5ced1f4b3e944881f6638c5f325d8ed05a4c8ca5a6ce38815f336610ba4ca4c7337f15ccea090478c97f8db9231ba73af7689434fbc6ec171944dd77908cd0d329a306957079b6401f0f34738791093d71fbbe9f7af7e6945f7a0c8806abc31f6cffce47c9d539f3f4cb9fce3b0ca54d1177285f145 +efb3b6ac061fcd4bb6411ab78ee10cca7c14b5b9dbd07109d1f6e03b5ef11f4726a88f89a5e79e66a11d59e2ebd426b3f21b34e25602adddcdc87753702b1e4b852a565525559281d32a753e363a98723f365c479dc9f1dea8311d723dc016e811e0d8e918b63c3e6c3e17f4c9a765fec6c563fc1ab1ccd5c916273da3a0ba1d +d0b8a638098319ed6f0c0bc2c0e23c36b000059c0883a8fcdfe9357f4541cfa6f06d0355b0092107459a752b040722356d7f95320d7206deeee6dca587a60acc2c64d8b63067ca8ac10d221a6ae7311a083d62d180f9524cfbb7f5b3fe71f0e82bcc29b64d55872eb03b816af1d23a54d6fc4e395764d0dbdad63e494b16b5b5 +ed0752e6c489b4e37b27a1a90073f5958a7eb7dc6be8c5fbabae963784ea0993152cb9b8e0c9555fde1cda14f4e377611e66a7e7f50166a6eb0e37286a08584d931f47eb66dbb234c7e10a5080ad84edf57765b0e2c32eae6c725cd95932e94f1475a1241d1e3f8b5f11c0ad8f399332a0c1f0a54f48f81455920ce94a3d18f5 +f2164f284acd56b67aaf1b0cd0e733709c7ada139cdd348c91eeb742303f96ea21d3f4b423326ba8cd95fd1c36d5f99966e1dfb075fb13ffae9b2a37db11824a6e184980ff63322a336cbe1cedb8c748349dea7673689c4b34be89d065441eed9b010c540826a2079346eb90d80bb219c973718670ff8803afe28feab3019a0d +f9a00b6f7d7638db994b087390ba2b91cca6a3c30682898efd42f300aa20116e0bad9392294b06fee445d694bc8a5d93e4bffd7f4deef45660d39148230b955b0157bf62255e31861f9ee002e78c300a8d93c11f3d3d7bdfeefdc87231c9001fb7cd41387153dcc91f8a1a1663718494d9d6c866af82c0df6b796943ddce0f1d +d77482d83a5059204beacc0c1dea0a87347b5dc9e5dd04148a9339067121e4be8d8f3bd13a0780e6efdcc077be7f1281df3994031ce308a1bac1024144dde9e3587984dc76b919e941abe1b9e6a6c83076389e05b209966b698942f02e83861a30349797354f02d3a7d1fc0797a38e4ca94aab692e9d242f8d11d8e9ceb36e65 +f36609d7add6e2e5af768e8806280de76a92799a44ba2317d16b35d8120480ab7beb4550c706984300fce781bcfaaa7f34f4b8313ba9e350e35136e7dfe060191dffc4f60803f87a23e70e78ad4067a6ca1ceec7605ec4224d9e4056322fa932fc8d86c3eba6904028ff1391918c0628f23425369788e6f15c5237f3e945748d +f76aca3ae95e24732d780671dae23eb76e95320b999bc3087b9fd5b47ed48ac45f276df913fa29ebc0f267c5d6149f5ef3e995252ab855a75ff13294cae22463caad196c29593233bd345c470f48ec0a33855caf026b02c7e9be7585e6a2620ac8071712520903ba6ed56af7633e08de22b65c24260996b905bc7b17305b6315 +ee47144c7cc79048da2e5c7ca377d6bf54373b0235788f6515a4d05d76427797e8ee951f3880d80105a8b9a5e584a09d7a278f9927737c3cb3e65b00d166696d1e299a81d0b63b3d16c2e80ef0769ef0d49219b97d88772147bf19c8e0e2354dfe0753613ffdf82ca10b79a606969a7d10ba6ef12d41cc9ef7a0ab41a60aee05 +c7512a6fc248a703f04a4628a04c5f42925d0b3a0bbd26671ca332a46ed23a23552581ca3b14fb93c50f2b34f27a4ce81b7b32469a30a02044b08e1d8c76d48da3058e821978bce032f5f8cc59d85d30ed8f8cec79c716aaa577e1c0f61afba873d6f8709695f4bbd22241886fd684db8f7371947330c16dc5cf588393011035 +f3965870c5a0eb8f3f06393b00ff005947a4c93ca91234a60e0acd6174533882abc26e4c4660f194a8851b59029bc31ee4e696fa1fa59e7c88ea0a2b91960d4146ad140286b1f3d3727d0f67b29394d00a604e65e4240b9c93c735f665e1cfdc69cd48a2dac10a6c7b5140d8a57ad1841d99ac5631fceaaddd8d6578b4ea8ead +c108f896edb6a310f4b3acf52348f351a213a75eadbee769f484a220fee6d32fa5ef491f9d39d964015a4eb6f741abd14914cf03ef05f039b0eb0361c1dad1836dbaa575b6b9cf69d3d39c15f3fb5e1c5ec54a80e49636096ab75916e269b1a15cfc5cd374a064a3251b5d6cd6de2aa65aed83cf68d4dbe1ab9682e98bad22ed +c47513e74cbb89be9ce2f69b924430b0f84c0bf6b99414e7db74ac0db1d31100d5f06bf3310e11d1feee623c4998d40dddb72481c45eb87ef0e78b71b85aa1bc121613106dd4fc055a456dfc0a708c5c13337214aec0bff64bce84a49751451ae207b393b2299713cb705bbe69b11b3dde3f818d3fbd8293b501d027b2c2cd7d +e7c4a401decffc41ac44a48dbd92dad6142e816439b07a93c64b0b3eb772d278aac72a5583b93be6d23c85c91a22478b7ae1e9544b05747d5003809f17f89593153595cc572f9ed5815302e80c5eca2a360f030ad556787222cacad104d6c20514be1ff92047b6d194c5706c95e1c5719d25fdfa818198879d9192405b546945 +cf1924b43aa3edd753df6dbe5eb4453194ad50937d6072f449185a6f704dff7f70a28e317e0c5e8c8d67164e83df9ef57eb748b38c4a08248d56e7ec06caf4c47ef7bf09d291fe57c9b0093bbbd36c323f383170e4d1430012eadebd912ec07c507f2b91de125d7711869e7311a98f4a3e63c37cbf770fbb8f965c8d8f337135 +f8aafc8ab799051e91d03ebc27f3126b952aefbdeeec0957c60335325694fcab82a7b5ae5807699479851cc4c5c50610fceec008da4a5591a5065379db44cc33e3d8d654442cf7d8867973a5b7a967df6005192305bbbd556ceb2f51bd80115ca86fd299b9c01e51e6f7467f1dd6decda49ae2211fbc8c1764cdac271290316d +dce1b066d202d9d4ec6be321dbe4a0f27be678cbd16d30bdbf55877c70d7ef875fc895611b7c5988e1d2c5311b4885b3a8845186ac8117c17d9302b66fd1de0855058eae06c04a1d6ed84facea5d5cbb88cf5a8e7790aea33619a681858cfed59a7cb1db54f2d865c71556d4b9cdbd8539015f00e264c0bc4e4570eada2444c5 +e9b694930c95ec62abdba4da1bf14713c02cda478d380e6c4cf3e3a046fad0807211fd0c7f1f0511a28c83cdfbc56f48abe9daaf48b10433989ceb489aada52f35d23aa25b8ca027f1fcdc8457afc56b177aeb04bcab67146ebe9b2ab1e8000a8468f112c07db377bffeb6ad81084001819a8e1bf7360126e344105eaa6c22ad +f2b747825bea0eb69671e2ec7894a0445206269d9b04a1fbf7253ef4a69c05a9ed168408962ac47d852c85cf863534d3ae082e2fe90a9daeab63a37dace95513525731ec16f629465b9f7f05449722fa06c66e6c8b8a909344cf2d4036b5bcf044fd7dcbc50eb53cf2a1246bcb564f8286dbd4c6e8ca155152fdd1b1627b71c5 +e1e43a3d617669dff0cd6d191f3c92516435c17e5b3d8ecdcb57182b7c8529d7def527c14f660d63e61bf30b953f187ef06e378b2139ad0f30f4dc6193a3df84eb265f4578dde745ef8fa1f10a3b7b920bfad2a113452a222b8434d4000d53e52d8e00c3a59f9d7e4514ed175101559c636e90a1daa5d7094db4c529a0964145 +f1fdc775e8fc8246bb2da1d922e140782d2f4ffe317226701bcdd3bbe97efb8197f2a4c3b9e59d8d489eec1eef8bb2e39466a9800b5b112d6d8cd8c55eef993a6cc13a8f9fd23ff53cc12de466e24a033674cfcebe7baf90c3c3f1fc366f3c463fccc4c02dd074b1e5f83423e4e26fba1d35d6b90f22f0369e4fa35b4b46fc0d +ff0bc4dabe703216d2597fec46f08827f09d8277baecd636cb7e63c08004849a4baa21ded34362a871db6afed09e0acfc73cb36220bc5ed0489b022e1e2491eafb0f44c96bc7581ea02d841179f4079370b4dc576357723496fe7e0217dc8773fbdd09b562146613fddc8b38ebf33e283b9f3f5bd17bad87b60d34a191b9cd45 +e4d00abe3070d6233ad696bba8c4ec62f9d3b372a799303bdc4bda030d78db01cdba42919778bc3ff5703fb14798ed26c182cd29852d2488a9f72ecb2e95a7241df1f8f3372ee7990460bdab916884e47ba8ebbbd5eb010bd36b267fc0be5075dfaa772853187e02bcaa6664dc3e98cb1744a47b15e6a92352377ffd5a7b277d +dfcc6a945099cc5fc8a3c59d70e46e29acfade7843ca12f82715f5eeb8975a379afce84de3cfc32840391464413667d6c6427ce85d26fd9a737c5aebf4caa6d1419c2f52f661eaa3a05642d575f855a1650924a0b9adf410402a27f2d896907cc674c16c04c36a385b951d885608cda14a16d6905de193f7e9afaace19a26f25 +f756cf4396de4683afb81f0b1be7b72fe5304e807c430bd35dc598846a3c78a0546154c4798a43c15916f1ff06467bc4d108ea1a339f561d728c1a4e0900fb7f22da26729f5f4093ed53e44696955ff94c2211359aab0d7771a327c69ee934f31db90b4bb6c85c805abbde0feb40f6c26f9d14a496589ba1e42bf86dba5ca025 +cd3ec9b8f738386ad4b07a2411e57ecd743b145b6e865b28bb78e053be310aa7d4ec30e375ba5d2be7cc03719984c05ad512d0bd1f1e41237c1205db19f933c4c3f28135a7935b38e8bae7bcc5bb3fc8810e59a1438286b17189b6feb5dccf584b883a42c14127dcfca06e4c7a0249ff4bcd28c78b7a0b4f608de3a4fb13713d +d1c3b913cc9a0dc1c63b5da8442cb55e508a9fb81fa5538bcda09696fe73fddcdeb2b9766a60c6fe13b6b5ba25cd99414a29bcf87bea3225dcb90c9e5c05e45c982c60e36af6630d023809d0c9c68d7ec1d78088722be1dc45204a02be07f7a33f3688aa0efdd486de336a6fe9d40b24ae560ee94329995c67dc43c999eb584d +e6906f19fbe0a7b73a6602c14cb916c205e117d109800b7dd3c3c0947c65a58cb7933544b2d9fe95defc58fc514c3b7b7e661549223c407a66d8293d895ed71224dcc7c9928867c0179719421ccf1432f01481e76c79ae0c5d5b9b5c4c43d9a903df053da80aa6a2297e7727f8d263f18052bbb4691e7bc2679a4ed9b1655485 +ffaaceb134150a10384cf039e8ad64bff0d2f34e26d5f69ff0440b0d27f9964fffbdfe722279ab31e4ec029394f692dcf8701edaba8b577d0ab28e217e60e2ae885ca72b41624ea3c0793eb388e7c1d513d4c0169606a9d030cc397e8dc3cf0e59dabae23c06de3651ebe395159554f0b6b861bb22c7b0bae083936ca238f43d +e1353b6edcca52bb2e5f4856c771853d534cb7be128ad0a62fff102cc1ea0c83f143afecdc865fc72b1294a940ad4cb7a0316c255f87ba7dc848e7a6a81cf339d085d64002815434431a53c2754e59a8b9cbe97f9cb4321cd60ac9fdd828ae9ded8954efb7287dc088212f66037e5fb80de89a60a5c5daecc91c371295a2214d +e2f3e64e2b74da49aa0993acf7fbdc551d092a9bb47b9c9d5243af4bf4ca6c0e0fb7b7cb743acc4199b9829b6eb893818bd6f60c40f88095efbed69aeaa877fd59e9780d68e2ae38e5389334db71722adcb041d4bd31b009d7ea342e2964a31ce795dbb22b62a6aba4e50edd711db57d3573d96f6d40a5a0eebf5f7fc041e665 +f05bc3e8dd7a81fd90afff645e6f99124219ef8358f125b4deee68652446147c2af8a6eaa2527d9a62755f5c663b936792d052ade822b93f2aa328cedebc9fd32b787a5ac88cc439294672ef61fabb0aacb5a8a33073a6bf8665cededa4fdf80364e9a38c4f2c4a348cae5c7e29bee6c49655dc6a705c3881c7e408aa5385725 +c0d865f35d27caebe727aa38ddd5f74bfa94d6a194d92123ce6a2d939bc9208d4cb9222de08b0515bbad5ced083ff087e516d2e6c3b37755311d233c6cd1b4e7273cc800e5704ffdd28edb92b781143f1f3d259a1524a2762e4d6ec13c7918f54766e63f62305b5180d904a7a648ddf18ac448592855575a0ef5797cf47f893d +f032c386d6dfdbdfd28ac2006ace6ab1591adc464269b33f27ac5138ba399226c151e9e59894d48b0e94ef366884457baa930075b179c7bfb61cd1a452b9149e9fb18dc937df8756d55b3c8f4c2b5419cf54854d3df18df3769eb6b7f0926764952ef7f453b460941cde1b868be3ec8cd6aa333b3a8b45bfdfdadc3bdb59b3d5 +da1915e7c7e36ac52d28383cbc60036ef18185dc10eb99a72cd55b819cf5640bc3ed899ae849a9e033634c9ae84e8ee24359c2502e11ffe142748238a2e57fa08c46b43ea52742eac29564b598f32da59ae9fbcdb34fdc30d3e1fbf3b08d0076344c8eca5646bdfd787868b27fc615a93de698497580586f41cee473f9309425 +cd2946b5bc0b7e1289bb27fb6e81afbf0fef4300f5d0317445419bf9aaf4835b9e6d4c6c10ea746406e45942bd697a8147887900bb31d42e18cbf29bba283786526823540d959252f74a3a6ea9d5561f66e9ac0cadc457e46126fd3b99dee5e4252449c4121722b19bd01d7eb6811f705487ed1d4416a274798b05d5fbac5955 +ce5a745d1e79d7b335d7c88377b1c692ab802a6665bde0af07b37d70e982e0c1af32125c8af9c9cfe22e872bb4e3a71ddc49d07ee17db5bf045995f3b6f4d79da9271d51b89bb13f23592cb57ed01eba6c40949a967adb0f8e3606782e9866322f3477043ec8b65d6718bea34aa025e8f08eb0a8468050274a99bd7f05711ad5 +ff5d660485911741bf3cc5f0c060444c1c847a17c2d7b68b40b644d944310ae3a4dbe878131bc6685242ecc37912cfa7cdc6f4611f7b9873ea0e75c59cb7da908d5c1d503a1720f67bbd2a15f3b035b4e89f39383da64eff98f34bce4f3ad3a91556c39986ef56e94cb7442df4f2687fa2dc965011cf0314f9fd0a4e99f8a82d +d92d8e5d030306cbb0b4e7145a8a4e0636282a5d7f29816cc37366e95d5a9f51415539448edbc6903b07f0d81b84d5a8a33c90f7b9e4e7df1e10bffd107dec6d9362dc86513051ed064f8ff64f156903d0a96fde60811447570cecef2a77cfbb9ea1e3e43ea5d703d39fdf0e3720338f7eb201641fd0c63249d97bb34227ad75 +e046388255096cdd05bcbd3153f97722a6a7841b7c49f9c13542713b5909ec25cc2da599b1025e224b26930b5aabd4bd2e554ba3bfebd531c9586f38d317df4b6c6382b67c99bbca920e7592fdde8934cd38c07d3710be51e1ea08766709a2d63a8562a079ba6116265431cebf8cca528fd82fc77f0a2de81f6e8296fe0715b5 +f5ac18e52f951d10be9300cc6f88abb46f237d7c0bdeb4a088e9352d8fcf1dc59c5b54751bf27b2136eb9e7703d70e4287e5cbd5d07848ec3bb116d977938bfbe288d85e98b68cc1c00a15383cd01f6324f0d78b44500bbe68b27b32e19778a165352214eaa2156780deeec3274ece0ddc7f93fe11401bd49e915ccb664a3f55 +ebb41e1f5442da75e42bf4b8d1dbaec10e59b71b126a5825f03707a9608512ea068436c3afa102a4d2044ea7e6a15e70d5726d8f68f9bdc79f09abc5a2df6946088467b35085fb626a1be703441ccf627eb9b3f56e07d932e8c4b1ad3b2ff399de007cbf72017d819c4ec8ba10daeb75ee00c74bdfc11ccab597352a145c88c5 +f695a2a2b05e885de58d21acc17e7d0acec99cc82a40a0e65277cbbb12698e1101b7d0e30828a9cef39a3661e2533399a754cc67f4f927e084d0c6e756f0daa1e53f1656d637a795972a3d9e65b8e76d5a9556bbecf8243b6f5c56858a0b5187248630a6ede79b202ed70111da94a25f8e95abec93672f1650e9f94ad8e8dea5 +fb1965abe9d6b95979793175667a8174540dd9106ca08aa16da6ee91438ddb51ac0be3f88ac43b3ff3b3a8fc72ea00d669ca2424040f995a63c21fdd6806883e36bf88f7cde516afc79cd2ab91a030c9fcdf8f043cdd33e448178a37f5a5c75fa3eecdf93c24b97a75a09b07d8b6cab8d81338e1155a31305e60bc7bac49a9b5 +d08191f8d2eccdf966eea365f8eff23790b197673dfaf8727de20239e5e64acaeda10dbb9d662df04056a6d7dccb35b4eb78187ffd9b7625baaa1cfdcfa7801a19e63f5353407f5628f10f1dec5c8a02b5cd51cdaa3320ece9daa1af982899280d6942fd90388b819c3f3550974814fd336785889f966a751754054d31eca70d +cb6ae70226b42cdceeace435730d84c2e0a62021315a08f8c91746c6eb4ceb5705bc1344ca936d225d6a8adb1fd6f9ce2249a16bfffb77655d314ea4daabc1a90be9641b787847430f03f1f13b2ad301d8007749a0333ec9fbc233d7adc597331614e7789e0665676aa1eb02aa6fa1846e1570332943f304f96f4a9d467e4885 +e91ae993af41925b63076c8d6f97c71f54802d64ebaa90385676474c25c360084080594c4ec8fa2db7436a7b18b55af2c7902c4cadc0474a7fbc2e82783af9bc87eb88792a0a4241c4b99383585225f1ef1c7e46bbb32c8ed90e83cd2395688821610194e6bdb38d6fbf53870ac9c20df991227c598b300eb7955f7a44d6abdd +c865501f45da50c7061abf8421dae04745125764a6fbad33fef595783dd8676bad62c7ef7853e4b75f4b5aab8bab93b43999a425a83f7176199aada5347567b70d514d2c984bab627c8a3db82f29a0ce1f7d70c1b0de249689c7c59e279ab94c5dbe149125f79196660813b7ebcce27044e8429afd6be018c70a49cce6d76d9d +dd8abe13a5ea14ffd8ff45ab9a3a35b90e6bc79c018fd1a1005cfb7c721601ece24f2078b2289a6afd9bc3d2c63a7e5c7623051bc4ddc8bd9aabc48b7b5d2b5ca86fbfa6b8c980b37e7d46bab3734887543934bdb0a75eff82bf238999a51cc1ad0595805dc27068f8d23af344e022a916bd2012fc7038f547f92d97f76112c5 +ec32ef777c9318c52ea24f7dbd1f323cdfbc1fc91f8ef39248190d4944d320ac758fffcd5a7ac3df78761b1a27cc90da44882672496ded73f2998e4884a86ec264a2f368a6adcc210bb28a9ff66358f15c5e531044a71a7515e7c17d00758b289ab786acf07860e0de22deb357fd45d2f1bc289277456cd028da8cac1f0252e5 +e1e11019dfb7beb92187a908847bfa04cc987466e9f709f3fca57d32699d961cd6630a147ddfa228c30e5c5b6e75d9badf16bcc6edb5284edb255c64c6af7f977c4ccc5893a10b621c98a77eef18882a25852b4667dc6cb03a09a2dda391fff31548f4abaa33ea5903ac891d907fd2e2f56706ffe4bf6eee1e01cefe431e956d +fa197e6f7fda770e2db0630a8d13e4ff7154557470fab3723ef0c7af17974bbeabfa5fd67234c92790f3806e65cc938925aea2eaf11a27535053781166b8c5e9b8edb8071eb0dc434a49bd78b4d36557421f0778c122716598ae748051d2496c518c3fe07fa70731bb34186e6c26c1fbf3f927cfe3a6338386aae4f109df3ced +ee1d856fb6c508481be35e01355c6c32f4fd918834444c48f7dde2b60216389ccf46a42e5961cc40e6cda7b5ba2235669c466d6f14950055c84b339ca92693243b9b7e02a3c105cd6a25ac002d3c6182e90661a913ced8678c231e4105163118c2e719c5d5fd8665981d7c842c282944b81bd482cd9c4f1879442994c62d38ed +cd1e3cd21cb756d928c0f53688aac4c03ff7e71ef20dcd4798159fd8af9a105e5424a23c800a70de73cb5b22ba328dd799c85ddbd20c62bcb4b028ee1476dccc6eb26b932c12dd584f8fb6d70f4046a001e72161db28e2fc76cd5317edb4b35f7c878637b7a2f1788395fd5c019a0033c7c9caaeab1700d89deff335f5f65dcd +c6c7888d3182c721e7989d341dffd18da609b2578e48825acf5d541e54475631b5de037f8323981a7d6ed462c6add59fdc2bf323c9d1c502afd881d817b6a9acc6682cd5d1eb0f7d7cc607580703e3bafdedef36b7af7afedad4262cec7a345748b237804f6012f860dd71a25340d5674d1e599a4dd41b990f7d504195f7b0ed +da9a9b87449827f325fcb2c03bb69a87074b2b97434e03efffa97e3198e3e720d806fd0f5767c29340fd2b8d8a7b2a1df39327de79d848d600b78cc4be447c6110cb060281b891b6811ee411a92ac23b1b19b224669ca3512f85b6e69aca9405ebaf5fcda241ca7ffbf7cc1dd8984a2670b696d5d15aa3846d919552208f889d +d2fad86c78c301373441fb2ca6b8dbe2bd3088ae6f9351df1659f2a7491a203aba7ae0cd4c7c9747cffdba58b901680df5eba4a2dc9311f25fd1b48f4464b55b239e5f6fd26bed5a636b73ffb1df7fb7160d065492c6f2f8db8682aaff9d4b5e9969f0817bcd123be3bf3a2e1de81cee2b0fd7bcddc7fe6c652e6e7e9e3ce07d +fdafb1e55ea0bc6bb0bacc5cf0c617b39f41ad7a2c7f760b26e963b03b1cff39a7a00ece74c36d6a964919430b0cd5f2f84c86595fb34f6c3be57ac13a985083f312d61784d966f82c28a68f4f810c2c7b27d492355f88cd9b47baed0bf6fddf5009ce95576c7b6d8a718de2444b7263ac4a1bb627fe66fa797ab27aebc9121d +ce606360ad461a06a31c1995ab7d67944dec0459c06c95b0f736020864d80511bc41e62f6e58274a3a1f11d372e0f39aa23141979028173f1778eb015c84ac3a9ba7aa492bd589b16a2fcd50288d5e34609aa84a0796fc6165a0684e7f12acd722be221b226a83c9565c54eb1df3dac8d987df544fc177b9981e617e3c160d0d +e0f7089df05ba237db3b1c45bc21d66c29ccb507e9daf95001c416827fbb671390c97df7b83788e2569a5c5fbfb6843cc695f239f5a1e95303dc43eb5b6af0f1c68ab9e90bcfd516e6d6b6ee40d4f9ba37b6c048525c80283488d70250c5cf99c971e66bfecf91de978dbfcb7c6ae04cb05ef016202f30860479ec1f90ad4d65 +e8507ab662b3c98ce61e0a121f721a55fd03f7ae5112227da37af43bffc91cd1467276191a561cbaba0e34c1f454f679f3999d41e3670135b1830cf637397c4a5da44e050f872e2f9ddf38796a72fce90591b01f2e2c5fe715617386044a8a971411027d3806d6a095581689065bee15a4fca04958fb5ddae0ebf5a300300b15 +ca0a12b96ffae3b5527115329f674292820ce3d4088c63224afd871f8119479a55dab101651ff8a18c3adf9c72636fe333c4b3ebe674efde597ff92af502146127990e7cf6edd2d26092c39a5c54bae54cbaf1bffc2a4694b50c1d85e5a2f787d5f9440626b3106ebb2e05bde7a68c2898285f37ee3a28e2e1c9b0d3a0c485d5 +e3e88bd18aaf97c07ef653e8fc0a34c84fd1253a3569bbd446dff4824c2603c7f8eb27875c696cbf4468ddbe68f05441ba1ef367a318e65dcbc1933e89386b188e530ecce528eaec744f90bfa84646c9ea20bfed636b3064b3af93c55e78c984e3bb6fc651bfed438ab861acc7122055624ebd4498833c744b33ffef8c00e1dd +f8456e31f6500650a486eb37443fc7952d67a1769c9fe245af454f76ea0b3c5e7a16977abd85af7d224430556114337e54c2edbe2b3c168b6d091ab6969f75eaf010eae3967f346cfef4fe37bdde5b945fa81c545bc60a44ca4cdb881cb1d85d7756f3106c868ef2554bad9fdf621b6ad576dc6502d3d8eb338a6c661e0b4575 +dbd011e8510af2bd21a8e5aebaf1081feb39a43579a91b1287d1855ca69b461bfb39ff789bf9e18d521a29f9c0a98f801022dfe2b48ab47211d1e2eac93507553f05bcf830b9c0cc01a82e23ac09ded672c36287ec331146d15837a5132464cfd9a9850198ef18685376343822e6bd00b0042b0fb9a10c87e2e6ea25ec08574d +c88a0d8e14d4aa0b128e0c7b39ee774e520293f1dab004456f11eb20c812d76568b4255db7f62a4d003bf2cfb2e1e7d5307fdd19a37045aba83e3903cc80783a40c5b1ef779fdbabcc4b317ebe478f89bc5097d4bff5181ce8ab1485f65ed28b740ab329b4b40f3503778531f64608798271f5b7449971aa01082b742ae821c5 +f027a59ef13a773a37c37ebed7c1f185e170ff69456875c8dc725b7294883480d264d53467a7a39a69aeea0096c69f7e13a48be0e18acf2d771937bf856e63e584dac3a764bbe19db2f72f17c15f24d32c069c3103b85bde4c3addf09b97d195c26ca32f1d0db60d1bb3e8ca124bc68cd4b347950b3572f794dcf2ed28827a05 +d0005617806e66cdf95899ad4657a55406d11afc7e9509e6c203f1fb0c1cab50cba705185bdab4f711f9aa6e357f91b20dcc908cbe10180167428ae569a9aca1ea17c66aae42e99076dd72f18eebec4071c1873f323cf6fff816845c25725c19d59a5248d680f85e487ffb0b50400853cf228fd8c5ca39888cc5791cedc9ad25 +d54b2a1f600724faeef022a75a803724389d6c3bfecc6263b54c53705d78e0344e0c6a9fb7d29f707c068adec28c17723225f0fba495f6ecd6b6a379c3472665beaa8152cf3ee69b619428f5e38c874bc9b648a5c00b844288a46c4996108d3ebf3c1f43b8cb327d04a59ea5c108e76117c487a9b82f93cf928738bce6570655 +c8284c1ab062a0d0ff59bcb818c10920ee12ecfc4c628791d690bd5aaa84a9cc172db8a77a6139640968953b11462225d2c980826a017fb1260569859a2938e2df25f5afbd789e8c2edf0acc71e5cb2cf082afdbc5b4a1f8262df03fac03a2b05f67ab51acf7fcbd9e48d07fe439dc14b0d082d44b0b761d76bfb17a7bb9b785 +ebdb28743e4d9393c2dccf2402595e183fc6888fda052ffd2cd7b6198f09be48f1377712f042a63eb1cfedd9580099ca32d4a61d32b5945557ef67d9950d195009a4195167338243c83cf66bb24086655741fa93c99d3ab51b36ad100e02299926a272d56ea1a1e9e3a5b6ffd8e8a64abf5416fb09d409193319abe153409d8d +d65eb3f296ca96032658f0770215e613015268edbf6c29a95809f565029fbf9bc198cd69d0cadfaaea3105914a0fb42e909108417b0c429eebd2dab7833a3a840dd477de79e8e0a293fbb0a852522075dc5136e6c11cbfb0b17d55c0a7efc5bfc72e4b4b388eec6aaa0d0faee88dfd94d5d894f1835646470eff1814bbf139e5 +c05e541401f5c14ebf63bd8b9d8fa9634438e7fb90abd491f818d98000e0ffbd3452f77ebc328e2be0449f41d2c6c5bdde140ff58dfd1574e9720395d703fe10ab0cab8bf3d3ee0bf1f733dc5fd34e0da04ca61dbb977a83e27f09b23686daa5f094adfb78651907dfbd1ce6a6f18c54d1556292e1f7f3e94d76147a89fc0f2d +ee4cdd912fa1bfbb9665235f0a06a7cba1a8419cdd12f8a994adb73f241e5bade29f12a1a1e4e81e5d3beb88a15ac2f38e8f55361355a777706812db82c73b6f332703a9f5a4fab39a3de4160b5db08ec30b7047b88091ed3c94140cb753eeff87303ecac29edd3ef2332a546c0b871cd1ded23f27b33852d5bc05fed9c34855 +e1064d22e161db40a96faa22fe4ba463b16a94d17307cdfce9d9c0b642c5d167f1caf1dd777d8623f8dd0a1e0beded6bd5944a0107b045cc4310e6550db18703179d67377af2736ae9ef32b8e625a31254213d2fb63c815a960f78c18cb678ef77aefc1dd3bec2a7bd3d2e976a76fa7a8a6514d1e5d18e55f3dfc09b9aed64ed +f6bf2537599214db59122973bfcec0e66a65341e7bd9fc04c24c9600956b6fc07477d954d1bca1c854469182c9b31e92f7d78179048cd423ffce6f9cbcc91a38b4af16ea03a8d15d2ff8e3412dd9427f9954ea20fbfdf1fcae506d5d732b14a2e0bee1d0f93668e71cd30ee6da165e77dc8935353063de550c8d72573b66f635 +cd6dfb24defa5b2b18cdef0eda2adf0e861869c77a9ef643e27d9d7a02f001e32fe9927c1068aa0b2ee6de142623b161158a02af1c5d49619453d69556bb8e4dbeb36aefd74cdfbe384924e4afff623e4f5ea764c41d65f2032ea5c15cbedf0beb93f852ad2181b4ba545ca1d87fa9d9fbc84d37ae6cc0270e38fabd4ad160bd +fec9e49cce336962d2617746705dfcdc39ddecc68edc64fd17ce44640aed8577882d1bacdcbd504647ecf987095d0a3dc4f5b8290141ac0ab7442b4bdfb78e80f3540a0b85946bf8496a0ad4bf0d204c3236524e6cc09ca68f23a341b31ae7bad457846b0a8c37d4b9e09f21c1db009dbafae366ac179b4d5885ba3f3486515d +f4cf8eb9f784a44c2acb080ad31a8cc9cbc2896ea56bdfee5796eb213b1c5c06538ae73f6b8f3542fcd35a890a247b4332d99a8d58ccc39c3d663cecf6b29cef3afbffbc58eccc3719e9413ae52631be34af052e851f28e5fba511e0c4dab5261e5efdeaf4c4de17c4cf2531963581e038c878b677a365300a377cc8a36c6e65 +c5aed2f3eaaa7996b9b4d936d94d5e73fe64bdaec3a3b2d569a59c030929d43ba23454e922c76bf3e122a0798f6120f87f35a5557ab785dc2afcec66fcae2bf2972872613b493c5b9628d6151ca970b6f8185025eb4d253be4b638d17600b5aee7661afa0e6f56dead3d2de75c6d4aa0c0e0bda945620b44df8cb41f05370ec5 +c101c7e5ac5a0c57db703d288230e7283bd8c9d46576411b6df847260851335e155e08770d9ef9c2ac27cd575860cb65fe85eaa89eabcecc69c0deb244b7fa824cb09763d151a23135bec7a26fde2107af92b10bd1994c65dd25ed9b433c382443987af8edb72527e1fcff85bc0a94ce6de34549ce57b2c74321ba3975a1c0fd +c8462781628fd6bb2c9f47406393ffdb3de02027d4bc6a4eb28ac3cb21140958cde30e5a6201ddfbb8a1f1d40789f439b295f46fe034e077969f895178324b9f23432053f19c0de921076739c9115b364f2c1ad3267b3281814d99b769b386b60f14a57dd47b4095e56b6f0e838467be9e42d208f5574f231acae151c2ff0cb5 +f37aa90dd2a3793e0089a89a0d26e05c38a73328a39e21bd94512b1d81a3804f180f98080230082cf34eac7a602d78c9e402e77a05eddfc6eae2a8ef68b219d93c21feff16e50cb51376ffdaa51b9a930a9b18528176db4ec0c0fc2a535a0eb2f82eb5a0c5b8928f199458796ca0d7b2541a275895c26048dee1f7ea89d61d15 +e47f1e715bd6328113e2353bfc797cb1a008bc12910747730ba17e7e3978763485a68d8a6ff3d116c89cf81bfbfb00bb8517d382f841089a688d33bfeb8ac83d6269ede3d04f831cd65fc9e176c5295b488cf4571e1269a33dc41b1f079b7c0c5981733d878a5785fb261779f529d09d6ce90e94988ac4e4308aa25734ba08ad +f3b54bb99708acbd6ad66450e54026cf28a3c958eb019bc18f429ce68c06afbd52f63f9769e5897718564aaff8e4771524badcfce709a67c6350b178f436f48bd5dd546f3de5d9cd2b68e0c9ede5e9f474703d1956e7d95af0c8bb8d75568b200acf5f6717193ae70c7646676481af3dc2be3c777e1932915f7d5614d0af1e45 +cc59d09c80ee1962acdbaa0443945b0120ea91d7b95ef6ed0d325df83a8c8efe9b022ca8670af6fca2e9f2f0d0454e6b5430a8233709b2a4611163ea979f14634341446b8be00f4dc7b1b6920db2cfbeb1a75861f3d38b373b03a35ec8270bafec241f226dec940003b52e47489835e46a79360c963363aa862e5a316cbe3bb5 +de3f7519b2e3a2538cd66e3b2ba8f5ee8e67961e89a5560f1e89a8576f425dd8c89ad8a74ff176d76483b75b91ecbde59764e9d477d051374e9276e8bf16e132b66b5f33ad93bdba3d3ce14957db94482bc0a1035be41ebed25002e0df2dea3ba33f0127be27eba5c425d1388f81a6b9d52f7393e51abb202a04a118fc9d6685 +fc107d5a74aae7288ceea89bc44c366784a36461f2af8005d1ff880089fd7190f5986de041a583341d8ff7aefa3da09bd36ed24c2ffecf1d0951ee1b34ebe1cf737e4836daa7a59fee6033372eade4c8b80540e6b3c6c0fd4606f6167fd9d355f6bf650990f5fb64b27b74fec2beb1e0d902c536e08d199dd47734f5b7843935 +e541479fa9d88a4bd4ca0f6b7f1f06c799a8c1e0eeb441ac7b8439f08fa1c6a947bdffa3e31c54ce678bb5ecffd40576fba60e365bcca77d479f9169ab9f2f1ccc8468d53bc7ef6f2a4b533e8c3c73e3ecccb686dcbacd448932f3f7fb68a2505aefea662f4b87f259afe07bca12cf37de5b0103b7df99c5bf85fcd72e2dbccd +da26fb8b8d311836ffd5db5064ab3390a02ec5d4f08b92f18dec3d14a458decf147268a65b5cf85cb809e30e6a69b032c3ed89cd6703d4a7523ffb5c7863762556ac0d23ef72d41b5fc3c701b603771d859712d20bf486808158b76e3c647f9919f2253093ee441d9be8f638c38ada2c7f5e28530141d8bb0fdf2192a023f0dd +e57694952565c980f833b0448ef58ec973a1a6e9f2b497bf0660785ec578ecf9d3011ac2b390639c74ba8ca9ebbef87963ee133babce7aef70d27715620572f857413e02701a1070b63868b483c6ebcf419d66e3aa41fba5c4b2130dbebb8977e20489a485ec415ebbac10b169c0b0f1d0c21a96c52c3a9cbc71ed008126b165 +d6247d1a9e2c712a162f0d894c7079d3a8beb96e25c62866b467164d1172e99b15b583ef5c26af9fccb964d15cc778e5bfeec1ed3e5713aa3c09ac3ab353ad6c57b91705f910e8e0efc2d68cf81d7d604853399f811ffedfc6da6030137b156dcddc026eea0af1f88602072a4c0f119717ad6fa98bcb6b78a31e89e6f2dff105 +c19831e7cffce0a3b135f9fe75c84df6accf140118c762dc8d7d24bbbd58d61b93f9e41d49581e7b27b1322d16cab0ad0f7ab9f6d4885a1d9532e9126e1a4a2c7316388549ad1084335054a19bd1cdf2e7828d529c2fe1fc4d764b31ac490f26047a1564aa419dd99c9144095e35650b47934f29fb49343702838630fd9b2605 +ca44e81c9b8fb87c9da389778ecc62b97f40d4f4a5a0a1c6644e7aafd454eec28d58e5674b03d4135c21feca01a3760d11bb919b63cb6721c94e99cb6b56de6e0a649589b88bb229847006ed55a18b344a4de9b175a2ba3739220e6c107662920307af9e1022c7335a0955ea358df0ada2ad3943680ba2e0852d6e3fc2264b25 +e0ebda026946f37448a80a6d6cddfebc8520f7336c499b18ae59daa4b9122f6591e19f47a8603b4efbda0c07b60f6aef095b4143394fe0055290ed3d3ee10bc224d0df624a735f08e1562efc8cc338d83cbe95d372898c0985e947d1d61a0fdad9ad8ced32ecc8de121e3c52033b6c606540e996241a981387f066209d8951e5 +c429ea9d461c269b00c787861ed26644469f9384884b028063f9b556d9ab8033f12e3df5e2ff8dc0206a2ed4060a9782b1124c7886227d49688bb433a3f7c050130aeae8c0cdde9b6d9cdb3b0d355382039241518bf44bc5320d0be029af33298ddfe35caa2cad8ca4c3938428561a33d67453d3d48d55964bc89ec16019d5d5 +fcc2f150a65b58649c0e7986e99703ba3ded0a3bf24c3a514388580a1c992b141fd974948aaed36ddfdbaacaa97890c55f5edb67cdd0e5c24a0af84d07602143fbdfcb751e6bc881b4899682c0b45ebb668ba9b86c8100fc1a4420190b51e832c42ef628be065efd668b93058d3c50f4187884f49714c99b9b81011165ea64fd +defd2f3aa104b433c09ac4e959331cc538e6857aac1b1d34abc204712d0a3e081eb43219f24c5ef2ac7991377497231fc35a504fd18bf370bff33f9518b1f6ebcf7ba527ddec3c27931a2534311b5af43b615369b2436f157ec9c4924a74388102d7d702efedce8a9e1513731c2eb4a498dd38ef3d48c2671bf0556febd61105 +d24cd7fc935c6649cc1c4016e9b434f99f8adcedcfb14c10d19460559b79604504ae630eba090a8e12dce804a98754dfe97d418f69faef31b36c9b84494a52799fd6f6554bbf00bf09c6ceb31d80c9e898585ba514db0da2d5406242ac6425da82f54b59116ad5a8667bbd36359ef615124aaf49eb013b12c8e73c95ef1754e5 +d8454d83397aeb2f95c2ef3f631b09aab13bee7e2ea80a60b23f9b62a16661ce173a4adfe7cd6add3574eaaa2e3fde776fae2512f896102efda5a5d7963b0cb0d24c64cad43df1a404fb45124985fd979ea12e3b8e04986dc79424aad069912399f9967819336ffddfcf59256d81c31287bc0f826259d7ae518f5b4c90bca635 +e5294125e579b5344bac95b5bacfad8a53033192761a264dbcb51cea719e9c25ca5777d647ae22590a3845bd525e431752718570492bb6a7aea199976a5d5f88389289ff8fa3353e1c28ca733bf509982a478433f0690a564ffb77abd035f3cb0e3c2dd9cfa27d0213bc9a564cd40421bd8553c08d9cdd2c798affe3ca61fa05 +d51665034d9ecae075b5608ca2418916d2ec4005282a8324e438aa40df2c4fbe78d339c45293945203845d3ddd9b5f1829c4b7c9f06932279015db0426e12074fe6922892d1accc23322bc6c559b6238ab81318e19f2b09f8743c84b95a873fe6e8aba102ece14ba72ec41336de899675a01bd97803e9dab17e8f5a039b5e8dd +f186114528ec964fa924e4d9ab4a8968543c4edce6b5804d36379c8598cf0cc805034bf8f9d56263998506670eea8719bb510d5ae42b56906cbbbdae35c1144052c937d208e88d4604ee9649efcc4a6bab36e5610f3dd430838947d2c45147098ca1700c642769e7259025793028677068e41afb9ce631593b93bd17ca7a8575 +f16e8d1a0917b9df4114fac8cf2793b05359e131206f02ac1ff291ba5528232ae94b0f6043184b6adc09628251e0ec605e68a9c1e1ed0f777496fc8903fafbc624206a7de1c8ad6faab3baa383e7baf8200d55a5af19ec1344410857f3c8ac8d2f3ead5c582215344e23dbeeb91c862fd3f2f2483eda9edc4f170175f6e95b1d +c338871392900e2f76e013b9f1da842dc7e7631f8198033fddd6e8eb8badf74b402e5deaf65d397e8adde339503a42b7c7e0f8ecff0e09dbc8d29c58650dd694004576ed197da2838536e3b4343d3ca0cd3b762ffb994343e546c9108cf4f143c602749daa477d46d2d55d3a34d666b0f4fb423c2d485615177fa71329bf22c5 +efb3426bb8d11a7e6fa89fe0cd868e1a58743794ddc94b08e8b187efd3a22080bdc0cde343724416e6a2200be91c1f020c2256aef6d66f661c87958c366574c0778aa225160bf2e5bb4297a3d9a22ebe313532b04fa2240f93568a07b1864632326bbf5bc9032709b9b219fe8ea3922fe113a2b772d9fb033a5163c9fd95c6f5 +ea0dd3767681178a62cf5d7503bcf8079b6498453c06fd462dcea80c475c400b6072887616efdd6892efc06503c78dbc0f1e77bfa67f34f3ccee38c1843423fc5f3be216fbf950a631d90191f9cd3a7fb8d0af712c48534a3651ac75b482e1e5f9b27c9125f08a30480d72a3a275b039c6cda359798d2e75fcab0dabc7378d55 +e7e12f4fac98c66c07c1e5bf04c07154e5f5718c51231e0d551a2995f207cb71ace535541d09024dfc68faa213cc95bc0a1b07bcf1101c623560a1f4ad1ec3722b746f202537267c69641d91500880b9ad9f44d07c991405a1d2fe51f5810d7ee081d4113e14654efdcdfcb5857830448b1af7dddac073c4728c798cf393b315 +ca0a6fc6aeb2c9b9d4298060834ddf9c91f3b4f5287a3dab4d6795955fcda75753baae06d7e73eff76a3a0372b90259d6f805e2a2c3aa6a368e08e8100acb1dc2aaa5126bc91ae8e3f15b8cd638fac50f772832b585b71adc258caa8c496ec6adea9b7b7a0ba2c39dd02df58d83ac79bb0dc80367c818948f056d655aff4bc8d +deb89fecf1aedaddcf0d635550756c7570c088063eb88c84fa9e4e5b5da2c7d2f76fea3959f771cdc05a8e1066267ad88dc348b69d6df1cdccd9538ed5049f63a58d8bfe3e28fbb0978f9aa1a300a4bbe9d07cb83f661b2d5fb2b3eb7be01eed03be859ea4eb5cce32d1fa3919966e1e56d388a9b860a446c4a5810aca2e2075 +fcf39e5ba24ad54f27b50091da98de1bd4799c605431a715acefd96fb8bf1513cfde5f593f22686274fcdaafdbbd97c08f02a8d76064fc3af31041459747de9ef4ca9ce18dc252dc8d61ada1350100ecb0b1f97d769ca8bf5b937d0383e930a4c24b68b7a1742472732efcf927b37245e82fd08162c25178d477b515d997b915 +d790dce9372e7ea1d2caee36f69e987301a1a7b1e52bb53f091a2961af1c324155d5f4be1df673285bef975c141e583cbc91f0404c2fd1d005b00ac8b08c5492b1ccea8976dfd1c571471b50c521869a85263989f9857ccfed16022ff08573c672fd29f37be59dd27e872ef5747f87b0a641bb6a8ab487adc41b900396090d35 +ef8f422500d4490352508c3e9435ae2bf8372edec93d6a850c0ecb2f23996556d3635b4e0bc13544481773cf1ddc2663c36c7b4d340a2fbb3356597eb60765f876f8c002ddedf606cb86756c16db077a5fff5646b117d21e83facfb7bad9366e2532051837a3ae753fe0d494c34835518a8c247ee2d2079259b72c2859b4e4d5 +d429f267e30c0de6826ce7f65f90ea8033c03ecfb5dd9b4b90ca47495ab5bb2752b681b4ffbacd304ecee282c922ccb042a41b462723275ac300c8b0ab2a8bd83c114b4f516497c662e8193a8bf54782998236538f41c0f5e6ab06182aec139a7494e1827c3b78d7bebcb07962bb8d1569ea0873c9c6318d3d1cc2c422b5a935 +eafe2313b84fb9e62849079d30c7574f14bc26f1b8fdd3f3d65a81508bc7b6a08a1d568c1f25246544b939f122b1cd0f87692f0c944774aaa8956cb3df84882f5c38eace27bf1c6a3eeb4ac172c9d226d540e7a77fa24cbe6c4c4c79e38d23038b0d517a17b4262905845c185ccadfc2f642752cd15bc48a4ece8eb5ef080d2d +f470db3a4ab8db8f77a9dee199005f9e8223821083326eb8e9aa412669d10c7e018159e8fd5ababa671c0c3403d7e381ad7786275a17e1ebf478c75f5e945b07d59eb7959e253731b3266dec6193a2240ecdefd82ba1af59829ad0b875724e87a9f166918bedfbfb60e6fbc871c4bf5dd0dba6c3c9d46b7d199569c85b14bb85 +c71f44dadd29e0dea2f5ff3fefc4dab4fe6fff677c82058da2321f5935b35fd5a241ba8760cff8c910732e798f5c1a2a7bfb728412daee252c20f764c818c7d4c07c971f4a60f0c1ba922dbccb419ae96c15e13bd99526a947783b68ac247532087709a6b5c42e58a6f1493b5f418d5d41b0163441cd6d4224cc762767b76c85 +c4c55b788b5ad843666d57cd124ce4c9d3b0ab6f4074fff4bf2f77a293f35693457309f86e6cd9a3351609672a5b7b839ebd4354d565a44911cdca108b95d5f4d51ee45bc5a2facc0579424264ed19365de0a50915fd5f4a8bd8b8cea7df39226f10838e84f39383927b5385c4317016f4946f7ba1c1aea81d86431caf3edb4d +f8b46dd21201e8903bbc4c4fe61b97aa663c3002aeb8434a6fee34b462a781fc99f0a483cbe9d0f20bffded09611706e81e8c2c7070a58c31acf85a65830d9b6b51bf0e807aca1d291143c26b35be69db73ed5589ef2be4d483f97197a5b8ec3131bdef4675ef7be3aee533ba6bc1330cc6d2fcef3dcaba336dfae59a4e1f725 +f03b62129d41a09715c112d11c49642309f96a429af38086aeadf7c9e8d53bf487f48ae8cda37ea64f62132467f4a0ad6cfcfc6ada4f89d4c48f76d5f3f283bfc2076bfc7f757d94bfb152bf06a336f98a4ea411af5aa068dbf8e6ca2ee9d80ba2e48fe71bbe6ae886d3bcdcdfbfd73653ce43f963435181a9cc79e0b27a02e5 +d861169853e13e90282dfdccb3d9aaeb10c2c4e996ba1893937e2aa701a56cc27ae905aa733759f008aa1c0b67f6f2a01ba176ea222b7d496a5769250c343c3e7fd0489b683684efb061f35caca1725e01ecbb4b4d3b1d83320007fc66cbf040ea0a6aca3c5f2a88f35941ba7724c72903597aa621e97d7e09c8965403e1bec5 +d9acf96b15169b736c44d9a12d7e987e2c2e2982f2aaf5a446cb063e5d911b1ae053ff07913ed7c521d30e1f07534d223c8bd2b50344396e839c9479adbd23c196f01c166d7eb2906154b3584ffd365bab7164c193a5691a5047563357026f2b404e17beba02b1b000d9e66562714413ac53d12c84969e89f014175ba27d8d25 +f7b94f600362ca592424d0476ec8b022bab10653d3602273e3ea8ac58325db414f451b82c9722803ef553d0de850c1b8c230accfc51d1b759113e2bdf16d16e8e97b46a25980015dfdb90918dc3f3bd36fbb68b7954edf991bce1c291a564259cf642531175b52be6036fb8e962dc3d8435ee4d0baedfe8451355b3164a3391d +ca0ee7ed1ca5bf9222afed87fcb7c71ce8e73addaab1d3d8b6a22f00d0f4ede8b3f3132210995fa34fd85548740079313837fe8eb8f2fddc65f9de71031af83eb1aa6d8bdccc63a07c932b8c0b1d447bb4278be412e68da81b32ab8c38a9c4d8183fd89c16be206ce26c464065166c3560c27b931fb321ac06322909b5f370c5 +c3e5321f70946d1e3165628be877b8b281555e2911dcd721546811d082ebf023c7a745a119a40047e10715b5214129e9d29fcb2d7743331fcd43b6583696e58cd388892131fce98ec1c5b470492b37ce923a74e27994b147e5ee42ae3827165a4e7e532d2b99d9d24c35af491b49665b89e4ca5039ff9d0e71288b4b8d40bfdd +d3c922f7e1e70137012dd1489d3c76e8d35a4a71a052ecd459a7df03403afd9a530e0b7f23bc500abda5a4ea51016626c17f410d85cc4ac798d1a264c94105b736b7b0c8b5503ec701ed80af25a8b2c341e861f8d0ff8f0a13fd01f0333a80e57e0ed6473edfb0a51b67cdbddcc6a28808b371add5151c5d5ce45426e0f6b5cd +fec3c5a877fccbedab3019571ca33cb89c2a2f15f7188b18e3833da5c015527f01e54d2306086ace38b05e2fd9e5bd8bd4a669850f86853719c05715e885ed8b07d01661e0ef7e59d16119542cf6fcf052d609b81b85a60ec50933251d83aacf39f268e4c3793a467674708068d24267678b550645229efdc6cd54acd7e2c14d +fc22a6303f3e5c1ff1c907aa267144458f742b0c2877cc0ac406826c4cc68fe13758b928f93b1dfb2af2f6d7f72ef79aee62f5976ff3fb36478f5958956463417e74e6d29dd438c1f5f6e20d22a046a662d442ddf89c45ca850ac31e4d90f1b4148ba7e9f509b95bb7b2127f50ee3ae67a637de417cbaad674d9c9ab960d654d +c5e7d7d8bd4eee2149c6c8f40ba59f1cc8231f7ba294e6d5b7b4b23ff8a824cb1d806eadb5d3be8444289b12a4e1622499db5bdc7ce400e60aa21c7c8180caa399b036e388e1b777a272174604714c5944fca044d6085665eefe70ee6bf2cc00c9b388f1cb96983bd3bef01474714c89b24cacbf91a8ffb05b1ae9c4a4188bc5 +d948d43d26093a2ba551b0b2e23666c807e127b9dfbc43544e28d7eb650f537f66f7c0818564c960ad708ec73b7b9bc5bb698f1923a76e16d1694e9ebb4c9bd7930a951feb570fc9ae1ee7c6da44661e3d42d6e61bffdc063db904c70c23f91d690f91a80678996dad357e934ac2d6a7d6465b2f2cb1b426a9f49c58da5527ed +c05c527b0d5fa435fbaeec6762d909b72b29a5a9e78d723e01a27d3e279a69900a4befaf68f5faa93e1ada0807c692090bef24ebb7fa5592e6a6f914d16e928dd319559947609b39857f31e72ddd5d60fee1b05dfe8ba63ca3964bca4f5a4b713ff38117be91e0c99662de63068322e462f6e5c26728edfd1f2ad6fc9b0e7bf5 +cf63801c085a59629b4cc9ff4a84e8c591b78637935e74f2a0153b168af7319393080d5628a9f42e3d7e2c3f81abdbdf0e47c0803144323e40b67fafaf580c44a56361e140d9f2d7dd5101e733b6225dee687cd695899d1f66d5bf6aea44942e31050de4d15c1e575f9704a5e583cd9ff6bc255a1775a5c1fe2929edafacf265 +ee662270fbeeff37339f9531cb3cf368439d8965d87eb53a6db314e5326bcc25a8380ff08900df663bd18d9f955d05743d7b3689120df9bff9e2cf5d2576e5f8755e30daaab8f923d9f7d623342469d84e649c47596d4b58d10022c0d2fe06f1dd27708dddd8d8375e32f8f147e293832ee60528eb4e7b3dd57a715f9327ab7d +ce0a029939cda5b28090cd0a778c5542a424f9c82daa501da76aff59fa8ba8ec2c160dcf87e0a553b29ee948c66da6979d1ecbc7b37c91a89860bcbc543d46587c5b1b992e490d9c2d813d0983e93e396baa79dd4105960c30a75ad3492b873320cb4b3442e8d6355491388b6d59153b4da754a6725065607e6126dfdca4e27d +f2e87e164154e1daf3e72ec783ca1f8a5df3354fcb358ae29a4166ef64129764ad1aa1f33fcd59a3c86bcaab4b5f5b38395761539995a03fbeb491ed66cfaa68876b8ec1a0a079a127e14f82d866eee6f9a8077700c74855044f95a4ba1ee7c2021c7a642c1a2e734f8dd6af7fa47445b8c68a7730976be70388b737b7e374dd +f968866268344e69654fc79a607be13aa6407de096255f75476165aa384c674f795fa02a5ef8f19304025015baef3a7ee33513dc9912d512df4f7beb23140c011ed78a0acd2338c6ccd0eb1db4c1d33d165a168755c55f58462ba874d436d96e841eb0a5d00a5fa230db14462f03749a45a38ecaa9c26caee2965b3b2927aebd +e783c7deda612f1caefa7b7064bf23a0da09d2ae09d76d3841171b772dc8968ba9e53ad2c2887999268cf9760afb9233f8b9037063106453adaa744ffe6fb9509cdae6a1bc15f4f771b6c602d68d1a28be70c8a160d58b9d289d8347c5616936b63c866e7e5d6bf2b0143e0b6581ed2e2b0e564c7ae20425fcb18e4ae46665a5 +d978ffc21493198cfe598fc3d21d66b33b9c2bf692ebad110425c5f048b983aca82ddd6205a96ea5a61f42e1aa062c7b274635dd3d464cc49b63c7b35639af93ffa1c1e0b05b7303abdc7f25934decfebaed85a9575dd1369097211306bd9cf032a6cfdaebac6cd109945b7d56f32a1af5b9863e5a6c69300f87144b92db6b7d +d0422b9bdd9a3edb95cb89d1eea6ca34b686a61a8b6512c8b1fe1189a3cceb7734b8482ae1a4e2e00f2c567dccdf1a6079ba89d0116aa2a70c8b53f0aee2b00fc9e93953bbaa090b4e4ed7a8c41523cb7b05d44c267994e1928eba2422f4befd5ebb730b7e544b0d51ba4052b8724bf16769114a43dcb11b02feea881d99f705 +ebe131fa523c7ed17578e2e5823da2c3b192ac207dcd0d146ebcf735dbd17459132dc47b3d16950c395660957819d219b0d1e0cca9dc6ccda229a51247ab1112cbdcbfcdaff75027336d38fba3ca3b74b9a8cee891ebf6d08b96f33d77730149e52e8c8a38900cbd971cc54987a44ce90986f2e379eb9c6a20969694ae39905d +c3a99a38a01217be7d6eeb8e2eaa56c4a43feac43006201a3f8328de13398f452e051702cce7292789b98f122ec96cb82f38fee6ff5d92bfb420e8ed260ccace5eea797479a20fb214fd20449b012c178480a35d4320046ad3889f1ae3807a33ce322ebc5f6ab1bc8f39e05231db9e61d97f5aea8bc892d32bb98ef692689eed +f5ad28c75028eca2c03a38cdfac27e29cb9c4b99a15571a6c1342a9ed21e954f5c1f442b38324ac13951f883991d85c7fd03821a45dccfbf076c03114638af9fa416a2c71b12973019d164b04993ad85102a9db85f8bee7b86df5ad9fdd9cb89dfb07e60d48c0ffdf68a86760c77dc670a1b3b62d7886e4ea96f2ff88878db9d +cff89d75be266af6afb6b9eea3e0a02825b85cacb908c9a4911be00f3b7c8c5370c05c0846979c7fa9b2b18fcea91703b6be71912927d49250ad9237a59968409ca55cbc08ebc54ef98338c59b8600ff687733e4178dd09b49bc9570c86e405a1f137a888c902d729cbab861ed5f965e1e50c9d8c3b426d62185900429a22125 +eb8936415ee74a4aeb09de49a0d7f4fbdf19223bacacfbaedb5c51c0c8d52f6c061c606060d3f9119a4fdb7b4f17b4a37b624392377ab9f81d769eb45495272fe4bbab7d110c3fe7d86d1ac2d91753df8915a8161d2f7db2378e886dfc0fe44f49c4fa6bd601c572423a37f5f9c3f40ee5c04c8f6cb5452273c0d2cb4040f0dd +f0ce9f411618305ba4a296cd22040713246e2f3ea1f723d2e2643b9fc536a864458b48e388e542c360bf5917aaabfb2cf1ce1e30d275ffee99137dd3317e19a2c534a6113e3d89a6665e55902ac1f119a0ebd3390ede13cd04792c89d349fee7c66f17b30e38f78811c81d907e275167b5c3000e58be7bda033c500a172d889d +f7745942de25894a96defe06117eee661fe59b466be237cc66b0e3854cb6d3b9e97c8b52e216458c6e9bfe9303299ac6294f2d62000a964b128742616a726c89505f1d2f493a68e0ec22b80a03e0e478bddd2760b474072490ef5dffa6fc01410a7fd4cbde2aa34b82172deac580cf3c3ee442a3a096597dcd8eeefc285b0a4d +d32dd28cc369ac18b8a088e49062c13f8a344b83cf354849104450a743b6adcd27ae6c321068f49a0334aef4896d83df1997b865f658486421ad0c5773652236a07a8846ec484eea7830c30884e7c20c35d035bbb4b47a112cfda9ba84db9b3dbb0b0edde6d21f8022f5979b3dc441245e38bc47b817ee3b0be50668f8b45cb5 +e26f4e6b3f3588b49a92dbdcdb3e5056703af21b7cfb521d62eb318105df1d3ffa8001629da6f5d3429dd767016ab9707c009a4de738b74401ad916a4f364b10abaa44471b1f16fca5c12a5bb31b6a54f1431411b2cba27d762a6914a6d13b52c42b3ef5838cbd502852bd490fc9951505f81e8dd6f10270861d091103ad5b85 +d640540fe9113341d00aecb996e15420c007a758094e6e89d05f80c2fdc165bd75475286235f5bdd659227c55bb901c2e55724c2af4baf1b989c71cd46393badb590c58b682f0e7f0ba01359232b21aa0fd2cf1a8c71be06739f1237a7de275ab4fe4463db572bffb219e2fd11b8aae37d00227dd0ed1fc060f1613d98d8821d +dc86ed947a567f74bf4f8c8b2f32654a0efff484437a049772e6817787ddbdbea1ccf4d61ae351773d92078f2e2fc788b6556da2955203b2184b0947449ff778359a1fb91bed9aa62885e5c4e3f7a359185a6816c95be610ff82a3d528cbad1775884501b5d5d200303249deb845a6656d066182cc893f0bab7523a5f8ab8185 +eea1ee526723cd0ecc2e218d71fe39bf912afc094eaf6acb4b3f2d76dc104cc9dc5a59cdf7a18493bd90462eecf9223ebadd096d07ea4f03d680f38afe3d60eb8059ec466294580ea9ccb81dcbe840fbf7b65b8d15d624db9b0b9c84d0c3d2549e3782fb1bef4e264bb3bc2d1664c140b4854f513befc9d48b9c13603539220d +e12113c4525a41a9f3858d26a91cd61061bf7976f1090934eaad962220e176519cd512c103cd4b655c87f83dbcb274be6dfcae131b017ea0c3df253bd048b8498256d2cc862eeb4a2d957d9f3c6c746bb2e7192c116efaf3e3ffde5af9d129ee65f3ae419c6130693113f3be41af7f8e2d6832aeafd2647544eee1e6b8aa816d +dbb906ff42edf909c7c1f3c280b607743049440761021499a03a9992de6ec17bc32458e7d697dba61f747d0ce110a24c710d00c597316f2d079f1ec9de3f6225f3940286f4be61fce0ee9649460ad389423a25922015482a6da7524bc65280bb0de9f72c81e459d40706d318632d4a151be0f8ae78239de005ff723ad4d88abd +c82ae8d45b214bd7cde7be84140b8f80b3180966c4b154c6c7d77b94667a3e710ea5dce00ed4a048a8f541cd61d487d014d97c0da902c2ae55a8e8eaca23bb23dea15c68a9ef146d08de1cf61dc589203acaa42df4e1941cbad3d338b56091117af1c9a23904c3b4b7832482310c0e2f9261b1b703e3324418972d903881e135 +c0a6505471e66553d80b32defa0199a97d57b22af9ce17e2a2bb7eaa9a0ff64e76a5d4e05a982d51b8db2e9941480de002035f3ef566f10bbc035b799c03ec58735e4f590cbdb14388b84328d33c53844b757b4ca44dc3caffd9ba8fd6b134da06e0d4c9d8abc88ed43808d73d2b2fd4c6d4e8cd70f91b22ee246e2ffcecc24d +c130266cd4a28926e2f8764efdc55e59cf3e936c5b244226b728702fdf5be181ef9cdf6b4d2fc7046236a741b7b9f7a7c61133493bf6b8578f990a80e68d693fd07e7330644b13a35bb2041d7a0d83a0ff31ce8382d5e197f22826930e7d1eb99bc2ac85f7036c54288e64bbaf60b2460a58c962b028a4b9dba26a9ea65eb54d +ec0a61da39b2b0af9b1b04600ca6f3cfd5d1ccae3970f641999e2e04081c2edac59ad2e25c9bc2babea9afdaefa585b9bb094945d75c2651085e67350c7f89cbd1618129ffcd7f683a10d2de3bc76420436f23967b29d00c613e61b1950384d361170a8d6207c05fa6015cfbc78d4de334a372a94c2372232d56a14c095078ed +d95927e4875a12ab9e97d72bbe3792ffc100a88abb4e665b3de5531f6da18497956af30795a8219bf05ccab568333528059c85e1e1c43b28811838fbb19e4568a7adcbe7111a260562b7feb89e9d4e8c23cc4781004558618caf3984cf6b1c0f0fd56533713b855781ab6520e30e1c33ad34cd9fb192d302acc396f65ebfd82d +c32682f151c85652f533554a95f4c5d1063c73750be7adc84cf437ab072fb835f42fa4cfb3777827d22ef6ad96d3e5ad2a3022464a9be7d861b0f0815e3f678274bf86c4ec012082b46a49500f92cb7db69df1da1b9fcd2cf4d47ea28d6581adefa9aac478781f74ac7afa1ba709baada5d0a55b84446b849331bd450b9143ad +d639fb704008e9fe6288f4a3c1b4e4bb255af723f5a222eb6b17dc79eeb882254c07634d9995fbb231e6713863185102194217c72011a1aef91db92d101dbd0780f23f8e281156168552e2fd7910c5d31510ae75564709c6ef3ca59f0af02de59d7b6b413b31fb17c41d9e948ccd2d4b1d0ea9ed58cd2cb64eea4ccdfa7a591d +ff34ca1e9b2c4807f0c9d8940074d34ec8902310de7223053d8902f3643800ac916eb801f405c6ca4c3596e3545d0f6b388c4229b19638b82057826bdbeb1c65c7557848ad894b30e336eb812a0ffbf33fbeb42ed744c7199092d45178444093d12343937e3c356bc1eed086a2a6097bc99b1a18e5d3386e6410d451c52ac9d5 +fa3cedabf5c5865d9609117f32c1195a35f1f66144f2d8b7bc45f93d03718b9feb4b3bb324420c274de0adf7538d003d689de88f19e710e0774f6c9d02bf1e3f4ac646c1f2b05a2144f5bfb6bff0b9421338e01911c39d58593a13d5f09488dc0517cc49a94cf0e7efe39069ae5ea553efad66f049a3a1484bd6551a98a2c4e5 +c2a7edbcaa3c4b5539b1667c612d3aa11696347b7574722a520a30336d75f3b51cfa7bd8bcc94f393beb73cc34c27d7619d851f2b8c1738c87e7d502c2dc1fd979e66ee2561a92281f4d100a4a3a89179cde82303385dcc4c9f048f399237545c526e03093a55fd90a35b433ff86c635041674490876a0ee3407e13a4432473d +f46990850241249bbb7cdd181bf26bfed6858152d0a2f3a07e06015d3741fe9079527c881465364f8dbdc7ea9df72e3bc86b1534a1b9a9e9b0db457753cf70ea06a3440bd1459554e247bbe119e789d2e0f4857aff24f410a7194521dac382a81ce89040601cda6ceb76b96267ea9063777b79b32712e1a1ff0f8683745a576d +d585d7c8a09e54f83b1a6ea405693006b875d985f01d9ada9d414a44aed16c2759609706a07e926d3c903ff6abaebbe89855f4784de2975096f249508d4a3c2fe55f85a5d662ee4a48b2c21e9f862056bc6b0a802c5130ac4fedfef94bf402988fa29bf125cb933ae316dfd157bb1b4d56c12ac3f5ce2839e41cd8a80c3db045 +c97bc84c797cc5ce3c2be229b0746bc45fab70f26b59cdd7cf7a5a0b96cb7c1e5e6b97d743ff7acbe33f2356a65f5a885d7b0364474e2c72bc9d21099282bec72d23ff3812c2dab68b7687c8b4a49fc6c714dc935f69cb3444430ae719cb3aa72bc80eefddabded582da7098252dd8baf3b60bc3133c2dcb99e58b6ce9ae77cd +ea3d3fbacc5209a15b9321aea7b43727165f34b45fdc06169ca953dedb9b56a3f71fcee48217c54cabb6813e36957ca4453019496ffd665109ce2096dbb6ef049d7c47bcbf461532069522caf053940df12971d7748caed05e9e654110fb97d199683769a8e2dc7666b9bed501c9bc93b901334fccde993d646f9f2ebaa0b435 +ea860c75b83bb20a0ac27531c1ebfadba1157f1f398d39c0c1bb0d6ab81ef2889a400e89341712ae52a4e0e155dd2e2db41863330b02bf198793872565b515217b33909de3f12de190cddcab5ba8ee70af4f29c86273a62efe6fff135da9240667bf7d2ad03ec6bfa0e691967d56da9bd3c57ff9790ca2e905c86fa142623cbd +eaf4e7490624a6174c26558a38fb59f80fd1e0998f4a6ab68a2b02ff3a81905576bc378f6d3d413926888c4067959b51f0725f854fbad6213f7c99416cc413dfd90c814e11fdcf373864a2197bbffa3d1f30a79f008b90bb566a001943d37dc135eef8d10448218e72e2d95a7c02ae89690a6b1970b7f6edbd47419888210aad +c67db1f755259c3e502629df50c9e52e55a8911d237797c614b8e63908e5d3c1f13f9fbef4a6f54b56d8db3ee99076bb01a34225c31e316ab65de36beb85753384bc8979f19e54692d4312e0a1ea82abfdf1fde7963f05d811600311866becc994a1909603d29d90c6bee021b06952c1ea7b99d3ac4bfd0023bc88698651b415 +ed2741be0f80765dcbaaa2df41b383b3a66241743a2828fb34e2f941ff6c507d6a7dbe8706cb1208afba66b83df09562a52579c54d8889220d44856c78242722f1510181313931892ef29dad2c3e5938ce3e74ea24d3ab3a7275eac299809242a1ac425984e0520f03991342fba98292e672d99a9d0c063904428badb005eb95 +ca82695fa012d5e6f3c664b23458fd5daf95c94b4299f936f8b70b6bd79ef243b1b9f16443f5f8945fb01eb0beee10c2bcca4225e6076ae9f5576168826442d4318afcbe7be329b30f0b4becc72832534fafb6440998f31acb31258673a9d202d5dc5e1ac0e5f282c61eada2b6f592aa2393db06bcfcb8166f3439e01e62545d +fda28487fb44a1cc26896298f6ef49d609087687498713f41befbbf6ce0ddee25a61acce094feb2d291225b00be8fd93ee8ddfce42999f29b149cb00f36eaaa3d379e9802f70c3ff58858acab0ed34bb9050ceb4281832a194831bf82d860e27474fdbb2f7b66eca12307dc685bdaf34b623eafabe885c269bcd6c21a52ef0a5 +d8447ae18777fa8b39f9077b58e056dc22330314c427e6e8d13fc6a3610a2c1286246a724fb99312e7f915d891101b1d8815582165178d55bd4a2c367c24e78ab21b13a8b9cf3ff67541fe69049948b567fb2f2f2bd4e7c711693dc0b6ed7ead617a447fb5b5bc567f53be6bb0fa097eab097d91077fd6ed1f02db4ac96575bd +ef71e9bee6899aabd27cf4ab2db213d0ee49214291d073415a2663e370d01fa741495af57193e52c58ea3883b2a13b79d85c68ed4032a0fe96e5c005df2b0982892f1d6c1c425c04063122ce306bd1a194b7b5a1366c2ec673608c56299f521f0c3493e13bed9df1c462e36f3a0854ce33926d532a3c05af710f5fdb65d36cfd +e5359c379e60c97dcdafe5a336aaa0db6659cb8f806a5195c7e13211b396324e831aacbb8691146ec906a96ba3f66cca0c8ebbdab0af793b24c94081dbc19d8f1ee6625ddd16103bf49804fe41525c839f47270d6f1bb9930f46063b593d48145c1982a40cc78421277ffa9b134997b0a02c8af22a51d0c83333433b3fc36ba5 +ee72e1aa567796208b5d8e66fedd555d5755d9c353a5d1979d0bafe0201ada1abf26e9993e2d1a20fa6a1f374d8ef39f007120099df38d6481584e6c6df24d31637d5a4d5c92f8496335ae00a3c7a5b713ee5ff12d9c4dc48e02c8aff9a308592c8ed3f66c1128481059266c4f852540a1393139f7a2d8d4ba6548505af6f135 +d95444b1c9c3d55cfd17e0348d0b59c73d95a44621d30d3a6fca261a8a1a4fcca9c3e4c218b1a88c2aade830d7e74b558ca56446147f2546fc50a485fdfedc0e258378ec1364edcd99a44d4c203b01db566b20528da4c3ccf4593d388fdd27d6400fc1e05bcafb03ba5b59d0cf3edfc66c172a6d79d50c9f6efd6e32bea5b0e5 +f409c82f06463b8a59238727edc9d64a88747a76a4d8a0950533a63664e5c231c842557172601b388f3566d8ced5ee0dcd34eac2d1fa16ba38efa15734ee29e4e42ac00fcca1a9919b4c7965c7be46a72bb6a3a4539fc9fa9f9fd3732786ade282a4fd6b724c2638406b97e501abc5fef1f34b9a4117b54cbb96212cfb0d154d +ee71503445dc30a2e629e73523d04c9afb0ac5bf8c93dbdb701b6d4f95faf5f619aeca3cf32aa52d7c441043c6d08a46f20ccce3b63348fef6e5c5ea655a25364ec3cb997c57d88448b1eae83f65694df426c4b265680b8035a589f309bd1bdcd77615cf00fd98f989b2c1f68253959ff6e45e53524b49a6b81500c3b1975e7d +e8e6b89a01bb23b1a1e501e5cd91b8d7fd676e3b4c82045b2f3403893a44cd2beb9d1e72ea33ac197edf6838c445aa924e0174a83ef14074be38957f494f7aaef38cbd6b42ba7a3a3e4e570f0c9fbd0b9f0876c12f66dc7f2806341851997d623afdf8e1885126cf64e6614119fd9096da72f8bc765e87cdde95f796e03ac72d +f28d5a3c2f7f68fb0fa309881612184933794a4e09b4a914d0e15962ba28ecdd3cf032cc79ea4edc98f96a4d97f9ebe1a42f858c58db0a88470be1d9a2f15a3899bf7ad8703425ab51d37fc186578bdb269fbe91c83c99a5763e433ae85a91559c177303a06655300952f27438adf16897504c23e334f2ad0b9574714ff525ad +c36710875e7737d6163161d4aa394fc388baccf567a9a694cfff56728f5a5a84818d4b4c2a2c393cc92c4e59972980407221c75bd06253d1ea5883729fca08ed04a37e2fdae1d71c00ce3e5ec49ea516e9a43ed50dc130f9ca82a93c735fcd9b953893ad2a2f5dce201db07f5625fd0c09cf357201cdd071cdb442b99ee65635 +d9fd2b8e5a92de3cac06a9b941af8f6734c834fc586ff9664332272e5df184d6b0dadba9e1d75800bfe679a15caf98a340b68f1ad405cb1b92e1a0b5f176419e72874d162ce0966a24c15bd67d416230b07daec55774e40e130f5b59ad8cd81880a15659e30eb7c23caa315c4ddb1f7fb4d622b9b07900b28cb2c8850a9ead5d +f858fff7b6d38f73bbc3118f1a67e787abc04c759a97dd8ab894f1f4c70cb7deedc9d31f642af1deee7043deb93ffbb3cb2a50cfbc7de9345a66023578f8e168687fb8e54374cbc48b89d41a0c8ddd5136f2ba3119baf0b101d462db1f7d6adcef017b6ce12af71b3d83d36871836309ece1d2dd2316a7a4165a0c4936e4cf2d +c411fd6fae60edfaf2f378edc643faf350c7d5bd8d3b14ccc5024fdb2a720db6da39aeeecd2ce1a2abf2a1b2bde9a9e734f641bc1fbaaecf4eb979cdef4c72a3b735073ec40790e1b264519c00fcab517bb14e65721d5ed8e49af4d45cc272f98f9ddab8126322b0ed77f9dc830b33d3c0d00f7c989f000f5614f7e2b7a2dc7d +cdee1cecd0e500ef3a24913c8b4411fa864510348618d0497a27fd62406aa5e19256fc8c28a5865e2efb24b6e56280ace90eef672e2aa250355e6272218b50ff24351f52a9b6a95f3fd302da49668760566314b82dc4bd36641e52c42622fa3b99b0b6e080d2a6873c666757a809beb30675014a61ad558e02dbbbc931329735 +e43ab2cb35c4b7db2c89d68b1caa3a51e5939c423a7cb3cf907c66cb0dc17799a936cfdc74f6a1aa1ea1ea7b74640105152803015ca083207807ce0b3d27310689a15a59f5124bad92b0d7d38d81868bd8415f2ce12fd6dbdfae8345e30e2d3e481f736a9bbb0348c09c521b5a95595485e5db301d6398ff04a9dab2e17097a5 +d4b4aa3594a5a3764e984f8cf743bb10a9054ae512660fa39595e09b3fdaafdcfb25d814bf548fe219a3c932b85d1d05b6bac54704ae7b8d01b126c09463678752596df2eb1a49681d4eac1620718ffa9e1b383639f6a7e02bae1858ba20782b65b34a2873a7b20790699b219f6814edad9a70e02aa2241944fb548edcd38f7d +c424e212cd8caf79d592aba373255d335bb58dd95175bad04c404df2f49004585dec10629ffb6cdeed6a2b96f00e6a943533c05571b10d0f977f5ad6a63fdfd57822e7c9d83f7579cfcabdc57646dadeeb7e774272a2fa5739f9ee189d05ec7cae84894550e6b62cbf5364a9f125f23e6c66c4d6387179a480c8ca19a61a3405 +e35bbcf0eb6f2fd2bb055cddb9a62008bd11c72fe35f75f2f8dbd4e89549cea92ec4b559721751a938c7b491a79e7341db2f3fc9ad7210199fc1fb43a2d79964a7526a1f22130cb232fd006e85efbc33b03a437fc0806431a5e55fc3b738457c0fb9c2ed38d5a87382573b10202404e71dda4ee520568e860a2c5daeabf94d2d +fad58a9cbffe7e58a6fa508dc7fa68c3d16afb32593c74b324a96953e0a28c855cbd40e0c4edb5b255c3ccd3ebd5dfa03ff16afd76cf910cb513ffcb5103b87728d1d9f46c81f2eb908b4c35321aa78df4b4aebf26aa8ba4d7d9f4dc7817c5835a5cc1f06472467ac0c329952312829ce154002908a0312397d2001b22e55a05 +c2cc23eec815b9500fab0310f2ad42967b1d3a8a2ae30dc2e0b0756f03d15b986dbd05ae733b374e687d4c1ac71afb3062a0802016cf2f861c138aaa082570be4e3b9a3d8c3ea9d432375ce5672eda0d9264588ad178679401b1fbe8d39cc6d60866e7f7e672d96683069ffffae0fd0f7194b73552c2d37144d8da4d8f0347f5 +df830ac28a2ceb86de86c778400c44620fbca0ea597f2be44d138bab5d40d89ce5d802ae39b07186ce350ba22c05fb614af5d5e3e8796623ba2838bf8162bbfb336e159f9236ec9a8164cf7c59a59fe1309a4d740b337a4a0cc9d8a9d961d10e2a3e5d2f077a33edfe89721c2c53b238e6518d2d2104f2ccf3351bf73452ba0d +c390d2db5531bf90d8a92cbd10a58a255ef6c8d726b7c805479a5fcb0a805458da99c0bc9123aec25e4bbb483d7d2ab14c879ef3a278fe446c03235fdbc83c85779297db3ff92ddcc4c5a6f6372e924a5d24f87528f87f1f6cb0515bec718ec8b2f1dd334a48d94ba766664ef0c68b9d4edc80ab067e0b642555cee16492c735 +e9b097742abf5024caac24091c2c5890cb2ae2fd5e9c7128c961d19f4c5fad4bd763dcbf3c646ea3a1ac8d816b673af4d6a488f2e40ec0100d154d6d3fbaffc444bc000255950ed13da1308bdb6a8ee6bb3468564637c3c205f77a3ad718d7e90f02c19b6e497781d8da8053733492dad5d55db1b7b84ce21260c85dfcf4dabd +c29aeecd959ee5a8028ab5bf1543d47d90947a355022ba3c72db9304a49d740e7a3174ed0f56818a8bdbe015f7e11d05ea8b03a8e43688dbe0d7816fe9cc7311c546ae34c29d304fd5442fe8586a89b78994d121b0be22077879c6781c44f124a3be54e2a6fd72482777d63033536b8c01cb069c7ae01f16f3fc76e568cc5bd5 +dcba67abd50cec07b4e84ff593f1e89b7e30b28d1ba0704549a0f1de7e23327a8c997079464f0cc81feb46e3465ec010632b9ad0a085a1bd2a5e8c9778934241c68bfca1c96e476548296c787372e8057e7ecdab83493619ad567019616a53c19818228420509728032d8618a8f35fbd901fbd0a4c294a2ead8968ead89a1195 +d33920afbba20c8705f47c812f31cb7b36c7dd5e88a00ac9f555a6f0dac9026c4dae15c219f2760ccd38c0127671e5a33f00211c81343835d8cd856c93e9ff3a6c5c61730a7f388f6aef7779350ba98316f795b684c60950a18e52855288d2e7575315a5ed17bd837e176b0020e0d47d9c50b668a73c893289d66f79bcaffc5d +dd4b3b5cd4c6c13f1d180f2ced8fd94eed6df632f0d6dc0c3a86b08c971daacdb45d96b2df9f1911c8486a06fdd64535d3fe012c63bfeaee833e2b6a220e00860fe9360c9813f59c13dc1037addc9eda6784ab2435400342364fdbce37baeffbf4fc4d876eb10d8f48a6604d85609eb172939f57584087ca911511371ebb43ed +f445fcfdaafc3b04890f3a9d893bf0bab976d6ea0ab6353496c92a35812577970a6f0169a2f2c88dda1f8db9e5a48f1c8bd97dd8dc271321d4a512fbc1c22f8d433ff4acf7f07913fe3dd61c8085f7fbf5e38c73cc0bcf7143c7e7940bf891e48bb25e85e4ed044e299fc73f8ae5cbb928c350db712af57e3206075c31d64dad +ddd27681c4e17b61668296dc2ec218f7745b0d22d93b15bfd665cd1e2341685d1e46c2aa7272a81d2d6e492c879ae6d5bcfd27bfec68f86991448db24eb323b1a9972403d716074cc0e6381f58a9c414b67b53b86a0d4e572d117e31e831eed78674b63d8b53d8aa689eb629cff0625c90053e7de0554f26325affcff31c2295 +ed16929a515a5c173259fc7119e5b958b26a2c061788e7602bdb74df932bf38eb4f2864e8165d404f4bff6d1f4a4fbd0706b840a71f36fbb97d7da21ea11cd258914e1ad3c91f480154e2dd0588a52d30bad58a63da178c980dac5dcfbf07930cb7032bc86d352634c042978640ba314ea678097b6ff6bcaa5e76b5714dc6c35 +f63fb957a8f763458e2591089ba4c4c729bf996617e81bcd911297228a6b2f4d5f60f605ff5efee7513ceadfbfd2e6548850689fe19dcd9967787beabf44400c90d6ffa22874f1d14fc0132f56be66b3d0c62acec6243fc34a876f16b8f5f71564a58bcdffe30455573ca1aefd3b9fc62886d1ab6456de66100bac61d0c24e35 +fcc63fa090af719d1a27b6345425d6685aec8b3b8dbddc2b02e274205c91c965aa6e17761e448480316712a25b33a36ac31d959492c29268ea3f10547f28e90cc8cb597016f1f126148398e21920ca71960481fce3f6ee4c8064bdba7ef49af62cf3cff00cc9ad475ab84619244475378066ef891155390ca589b75efa544385 +e6da32d30e3934c02eb23cb417025a288538ccce07e0d9bce4de00d9492720692be2a48e82ac9a25144c0ec9b4b141c77648c35884316b311080fb0796cab75cfb93933a2aa9310423a7b2ef94860783aa27f3061246a8c6bb2e2b40b69fac7fb617d24d1cd094abb1a1c7bb46460598e66bb539aa0fa499ebadf05e151716d5 +f7379a553d60d6e51a8f37f2d910d9dd5256655efdc891a708c6cb52033ea4689732905a5bb46cc4d3183e74708578e39b0c8630cc0fdf50e5355aafdf07b478f19584951c251fa72b93be1a3a3b744fc3c911b0847b089eae9dd73ff7050a0fefd4508f549c37790de86c87ef74bb53a29800fc64fbe7d365e7e708dea86a45 +e933766d7ca9db5dc66ff2ddc7f44542daf51232fb9ab413b1d31aaac02dbca7113c4ca874ebf599363ca99572e19a3fa57761cdcc600ac6d2f0e8dd8471ee7fd1b5584f201a480ded805af6dbf651f1bf1f06757a7fafec243c30ef5eb3d94958ad6d6b9687689cd578e383c3f6d8e3fc8981e83a91dbfdb2c4e5292382a42d +ed0f5d59bd470fe130096bd507795c809d261787ce73c77de9480d57985759d4909b19b5e248bfe6c75655beffff3a28aae22c017ca4c20ca4dbc81288542fc5b6acb4df489e7a3895749d21f2a13c0cc7fef538dc806576dbf816b529c3800eed0dca00e3e4cc022dc498f8095c7f62573daa7c00b6a049fe550b1d74a78e05 +d647d958769ca155b5f98f62fb98b28c48bc228f641b7f0a05ffa07c35a7413e29f35fb675b6e2580bc1e37f95eab82aa64317fdaa73924ce0970434002d70d1a08f84099d1b151df7623ca07bfe27b964f2ef9796d1e48c172c812e7c039484c16df56e289fa32f8069ea99a209b23efc383bade2006ae60521ef2f9e7c28b5 +c49923c0119e93216c2684dbbd9385f2c59c9a7e6330a44479a62da7db661ed2a36bc6c22fe5a0d21fca0f8e0f2d91a4c2a5c42f917f8e8b8d3e33ce97342b2081bc65eee931d2659c5d7b997e74bbd005b91d1353a3a4d05bfe6d680053092f27832c22776178bfacae0117fe6d80f42d5385c38e0fdef4e3b8cb33016c4fa5 +e588adcbdf57002875cc72def03f19e6c24059914c3a6055a7d67374a8ba3d339ffa72067c69343ad5dd11001e98054928cc39ce04b543ea737b1735682cb87a9b82963080a79946dbbaffac5271f905b7236c6215a456cdc3c5c40fb8bad8ce33e67c1113cbd9f889fc785888f50bbec30982fbcadbde934d72d44990b12f9d +d36621350931f1a0d1a8b1d215c643ba1b6f63a879789a7f5ee272f570e5cf0ec06c0700fa2521e5d5799e091967c54622534dde1c7dce3fe659569320fcbca304499286c3798bae6b70f64b72e18cb4ef5884de2103661257f61d327667f7f63ef4d63482e9ade53bfaf117662b65e46db4a2f3eb0829ee5363f53d2ff38695 +ce5e2ed6e0b9a7e749f48d031452c9c49b9760dd74e9cbb87a3e6d208cdc657dae6caa5218e0a1e6118080e8d2201d541e9cfd9fd518ea91c88cf18d27e484f0ffd0d9d04713e6a6325df1912ed4ef490d1f8223b884277a45c18d9157f8224f9bcb68d4458b79cf80911990b08b40962f84b5481d08b834ec2b80b81d93f2d5 +dd6ab77fdad44b520ad7796facc9fc57e52a6adf9dd7acaf00834418d871f64ac6f2a44d44578bf2e4c488b57becb233fc3d1367b21227c42f0cfe256ddac7712556a3b15c9185f60093d07835e98d03c82a3b9ad8ed338a2b54d49a6d5320454be8aa1c444cefca7eeff7c3854bef4685e8e56a7a537b7a3cd088953301652d +def3aadd465c6faffd363a9c360eacce5859476883c48dde4c8faac7dfd58a1ebfe2316b8771dd04553b78a11d2b4617797fddb541f1e440b61ac9d1097fe55f27be65736448206d0349d2cd95d8856bcc9b770472e8e8db83d3ef3b38b40b83ffb2eea7c0f7596911fa79b320e2add7c8336a71dc1a75e29d415ba0bcf24815 +ec4150c5b4a666343f6b2a831f368a7e0d0cc7f64473e521f539eece8ce65065fc2b9c1484dc692c7f4999e766e277f6fc6d1beed8c64d807cdc10a4ca6db1ac8141406768fb4cbac076d77d9d0555d95fb60f878996a366b099e59952657823304a566b4009952c37389482e8979a5cb0a6f1cec39bc88442c91bd918187ef5 +d1b84e4ff948e7748adbfab581176b13a98fdfaa6097ca3615da0fddfe3a13134cb4737e440dd211976f4753cb17359ed5a4803e8fe8f485103fb47b82c923e4a923df949aa1339ec6e925bedf405f05863e2628bf3a2f4a301426e97e52cd17d5de113ed7b73425b5187a2442b141a15804a0e782528dbc545dcf90c1bb5edd +ed83c3fe0acb80253190a59051d684d71c8eb39fdc8e8beb75e0a166438e206f9e060dd6de4aa9569a16fd43a6337e34f8b038f19906c4670410262fb3cbcfdda0447e4cbb1c69bc2ede8fe60b0bf40ede40e6e380a5a16e8633adb18f3dc12b2e7c74e6dc088a23cef51792587dcb1ae90474f82f37c653d2abfdbf6350229d +f25cb0386c6f7d01a3aba79f9400e2e621a8174de2ab436650a9354c2ad0261db1ba8ebe694bc45f4ded8184ed410c53c796286de4e0427a026140f2a183891ac0422c1247e01a793f94ec112dd23b5c460eb72356b060b3cc701c8db7a9d5b7cd311048f3f7694a92da2fd07a000e56277ae75cc9a15e71a81224592e959da5 +ee03c438fc7f8908610430d2cd034cc01a6762d94eb940b5ebe7c227091cc64878d41821ac3e42af3149e45b4543e34660716c2cb49af0b6c03be8ff178a242e3b5daf281aa04e2ddacca16d65a2b065a7c61dbe4bd8160d0a4a005679a4b5f0cd3068e1e092304d2a585c4fb2176bae941fb11374d6bc0272a8513865cd457d +ef6568752b0fc3eafcdcf2f8ac2b1a9f774e53a131eeb37d49559cc60d9caa99d8bc777b9ff4e84702eb83165fa03627d4eb09d286ee42565e87da20bca80643fd26258d3a060206faa9fcc3508ec1537f6578209ac359f544529fd87c471635dd9db44d3ecb9f5d82906c171673ac1d8ab5fb3f1bfd7b3cc2c06cae9b7f6685 +ccec545b7d7f1ea51d8774cdf81a6e8794bc3cd87fbe1a8f8251d9741410b37bc39f6af6ba9efda0cd15243eed15cf11f0b4465e02c38acff963f71fa7220c9d52f64c2fbb8fe044bc6cbaa0895ab8bdedc65a89e0441524cbe28ef9ada6c63d0431583506354b9c2a5176779538bf229b74c8f7feaf5eebdf0825835f33aa8d +e4459658218601a13cc808dc9581fe25f3609976c1f3430c813a2b5dafc902d5440809e75b1e01568bda0d15f8de12f368d7c3a32bac5bd3781f08b0beaba41d4f0541576658fee91042aecf2a450aa0a1612010690c291537a9430de782eb56207da17b54c16e1096eb1f9799ec98910c8557a65d4dff8da6201949a9238715 +f62b559ef3edfe69b2ec36c3af8ec3c36a326409f7d8665ab2a9c26cc28c9daf5350e8164e06966a68e33ceb550504945fa967c6af820a49c4abf6076f94c44340972f524fca03156376720f5bd7a795a4f1d022f1d47cf571d2d4d75b677791bb31bde0a3613d289d4dd1a3da76b9450b56efebc996ff1a59eb3d42da77285d +f397abbfca0f6d6ab5c132ebd18a30c83514b2576c2876e20c6cceb43ae8654f786d9ee5d8ad7b968ff447274d8c082425a477836b59bd27db3920ffd45ce0aec781852cb2a4cba54aa57092b407e2558f27a8a4a43551ab0641b4446fb54845c883dcbefed352cc0f7c557f1597f3e360e8b5d27da51bfd38e7454d509bb19d +fa306da03ce1f59bdcf895d340061798b11295da3078bab00636ae87f758873c32fafa2579563cf2d313c0889664d66e10957e14b0d90af7915cf61151043c1ece2190769ec61bfad26fce27a86094606f734586ed7590500f21ef02db9b19ed5b7b9598396d10135febca8c3e0be26ba0f02e2e54bb6b1ce0a7e424c4cd0e15 +de301f25036944a4f6a8fe11d1d6781cc5e054a09d449a8b1443ee4ad50e9ac8e68e244dd8f8ebc9de0f6e3fd2bd5de7099e17c452631f1962ba400eeb79db5d36dde3f91c7d5780b2ea421b31c2ed57f11cf08c29bfdfe7350e3a87ef477e0d178cec6faa7a4c07519f5fb21661a9ba681906dbc2c2658d9d25bd42e436118d +fc1556bfd9852204f19ac3da8d59b2e889d4232f00afae9dd890b47882c130eeced040fb696842e0635ed0530cddb515054dc514765e9b555f9857cf9bb13cbf5e2fcbc6630a0989c4b2fd565d81e7745851bbffa65ae8ba42591a17c3a44e1d8d60cd549558a4e17bf5343613a2aa4bcb0d086588579865e14b696ef5d03dc5 +dc60b41e021104e87cf43ba8e75dd012c1121bd5c3e682b8efa1f1103a12e27d89c520ff95809fe0bd206ef70775c78a2364d01d91f4afc7c8a8d02a671e14e2cb1df0b14852e7c5134a31b4380788f8b0f37423ed853e3e1c1938ad3f7cec40cfabaea1eef28c8d2b01f6bab2a1d584084897801bd249147e6e0c725eec7ee5 +ceee4f09a49f1de80b4d0dcd33eb56e8ea3d85c1a2e5e856323c03253fb91e2b4347857a86aa1d8484a501238f10b7aaf4adc3c39e42dd04495590c814f6af2c6a07155b1a793cdab9067b7e709bc3d748b10a419fe3f530111444a7b8cf3dba2880ff1bf81a607ea367b5a81b52e16b41080ea36b18a0d3590566af84989945 +f6bc6ad26d71863b9c771160344c9aa98f35be8193d2ee0b47d342a9ded78aaa6c654df6aff01aba55fe283df748f12afb40f6556d4370a9a987b98e2b330c9576f76821afb9103f249af8d6544c76b94d0e19b710465b5a8732ebabce87869a115f7cd88e7c01dbbb79c9cc04d266b9c578a645616e8ae3d8fbae1f80667d15 +f295e2280717c5fccba279523dfac2149274ccbf9e7a6ef99e17444c8d4c89c668d0306cf955ed951b7f60b1ed3470643fedfedc01cba6d66c2f32ab122a83314e84e21e1bb1c1af7ba69fc64faff940e0e2a797aa758f8b2b3bf2e882dffbe2bbe2da6680e622d05ff03a4ef09e88cbc3595179f68779062eb7fffc336ef025 +d607837c88f51a8449b0d1ded1caa08df6bbefad69c55cfbdef7c7f60fc0b2b3851019ef5be975f84238082fc0b1a1b67d595a95ac5e412904cba879d5c67a99479d5132189c9cd21c1b3270f293d1be5b3ae383e4ad9c3e72acfcf357631facbab5adec457b11bf6eac2cd2995a28ae5768ed2dad963bbf28b5794eb082d3b5 +f18ec69d1572c4686076d8f7f96629bc04ac315b0ce5fddf4758aace119fb5562e39535b7f20702ca99e686e229bf951e7bbb6d5cd6919f94235e873c3a47ba36829070b5f34e4153d0649f7c4aa7acf14720036b80362ae1b1063222903e4c62f434ec16c852c926268e739ba62238994dcc6f95c440d4826dcae5a5660168d +d2e36d5dc038ebddb59318b497fa416f76d2ca62fb99f8d9568737430a5946069ef251c20d2311598e9d1055f8ba15b018c28ec131a683d4d26056e67a46216dc529ab933ceae21f762538db6ca6db0473ed9dcc8c1ac880ada42fcf52938bd0cf3c528587a5ed61f4478d185c4b0d4edba24d222b207016be16e43105fc96f5 +e4be11d1cb3926427f6b2d26c43ae756ab16ea299a5c6b4c38eaaef00e0642e2c4cacce642f3be830a8fa93f5bee03a7d738b0a4e4181e0778788cc81b6989549b16ba116cd931446f39be17de2d99896832ff4fa1d4e9d70a15c4a4e7afa4b319cf51fda2ba57572b5656a6333597df083aa8278addc3024c7a21690e7fe305 From 85f8e240fe337b145aba1de5edd2b03e759e4e38 Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Thu, 13 Feb 2025 19:45:52 +0000 Subject: [PATCH 377/397] internal/trace: emit sync event before deferred spilled error CL 648315 and CL 648195 fixed #71615 in the case where we fail to read the next generation by emitting an extra sync event before returning an error. But, it's possible we failed to even read the next spilled batch when we read the first generation, and have been carrying the error from trying to read a spilled batch since the last generation. In this case, we don't emit a final sync event, meaning that there are still some cases where #71615 happens. This change emits the final sync event in this corner case. I believe this is the final corner case. I could previously reproduce the issue by running the test under stress2, but I can no longer reproduce any failures after this change. Fixes #71615, for real this time. Change-Id: I10688a3c0e4b8327a95f31add365338c77c091ab Reviewed-on: https://go-review.googlesource.com/c/go/+/649259 Reviewed-by: Cherry Mui Auto-Submit: Michael Knyszek LUCI-TryBot-Result: Go LUCI --- src/internal/trace/reader.go | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/internal/trace/reader.go b/src/internal/trace/reader.go index f5f871763fd9cf..7212a424d79c5d 100644 --- a/src/internal/trace/reader.go +++ b/src/internal/trace/reader.go @@ -22,17 +22,18 @@ import ( // event as the first event, and a Sync event as the last event. // (There may also be any number of Sync events in the middle, too.) type Reader struct { - version version.Version - r *bufio.Reader - lastTs Time - gen *generation - spill *spilledBatch - spillErr error // error from reading spill - frontier []*batchCursor - cpuSamples []cpuSample - order ordering - syncs int - done bool + version version.Version + r *bufio.Reader + lastTs Time + gen *generation + spill *spilledBatch + spillErr error // error from reading spill + spillErrSync bool // whether we emitted a Sync before reporting spillErr + frontier []*batchCursor + cpuSamples []cpuSample + order ordering + syncs int + done bool v1Events *traceV1Converter } @@ -139,7 +140,12 @@ func (r *Reader) ReadEvent() (e Event, err error) { // Check if we need to refresh the generation. if len(r.frontier) == 0 && len(r.cpuSamples) == 0 { if r.spillErr != nil { - return Event{}, r.spillErr + if r.spillErrSync { + return Event{}, r.spillErr + } + r.spillErrSync = true + r.syncs++ + return syncEvent(nil, r.lastTs, r.syncs), nil } if r.gen != nil && r.spill == nil { // If we have a generation from the last read, @@ -154,6 +160,7 @@ func (r *Reader) ReadEvent() (e Event, err error) { // Read the next generation. r.gen, r.spill, r.spillErr = readGeneration(r.r, r.spill) if r.gen == nil { + r.spillErrSync = true r.syncs++ return syncEvent(nil, r.lastTs, r.syncs), nil } From 45447b4bfff4227a8945951dd7d37f2873992e1b Mon Sep 17 00:00:00 2001 From: Carlos Amedee Date: Tue, 11 Feb 2025 15:50:55 -0500 Subject: [PATCH 378/397] net/http: use runtime.AddCleanup instead of runtime.SetFinalizer Replace the usage of runtime.SetFinalizer with runtime.AddCleanup in tests. Updates #70907 Change-Id: Idd3f1c07f6a7709352ca09948fbcb4a0ad9418bb Reviewed-on: https://go-review.googlesource.com/c/go/+/648655 Auto-Submit: Carlos Amedee Reviewed-by: Damien Neil LUCI-TryBot-Result: Go LUCI --- src/net/http/clientserver_test.go | 2 +- src/net/http/transport_test.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/net/http/clientserver_test.go b/src/net/http/clientserver_test.go index 32d97ea9f083ce..208c6509fac758 100644 --- a/src/net/http/clientserver_test.go +++ b/src/net/http/clientserver_test.go @@ -1253,7 +1253,7 @@ func testTransportGCRequest(t *testing.T, mode testMode, body bool) { (func() { body := strings.NewReader("some body") req, _ := NewRequest("POST", cst.ts.URL, body) - runtime.SetFinalizer(req, func(*Request) { close(didGC) }) + runtime.AddCleanup(req, func(ch chan struct{}) { close(ch) }, didGC) res, err := cst.c.Do(req) if err != nil { t.Fatal(err) diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go index a454db5e034ff0..7166c112792334 100644 --- a/src/net/http/transport_test.go +++ b/src/net/http/transport_test.go @@ -2034,7 +2034,7 @@ func (d *countingDialer) DialContext(ctx context.Context, network, address strin d.total++ d.live++ - runtime.SetFinalizer(counted, d.decrement) + runtime.AddCleanup(counted, func(dd *countingDialer) { dd.decrement(nil) }, d) return counted, nil } @@ -2106,7 +2106,7 @@ func (cc *contextCounter) Track(ctx context.Context) context.Context { cc.mu.Lock() defer cc.mu.Unlock() cc.live++ - runtime.SetFinalizer(counted, cc.decrement) + runtime.AddCleanup(counted, func(c *contextCounter) { cc.decrement(nil) }, cc) return counted } From 8c05e020d534a407c20a3e672971be3aabe2ee9c Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Fri, 14 Feb 2025 09:06:21 -0800 Subject: [PATCH 379/397] internal/syscall/unix: fix fchownat linkname for AIX & Solaris Typo fix: libc_chownat => libc_fchownat Change-Id: I6721a988c19e3438b967a73559159c948ed51a0e Reviewed-on: https://go-review.googlesource.com/c/go/+/649636 Auto-Submit: Damien Neil LUCI-TryBot-Result: Go LUCI Reviewed-by: Ian Lance Taylor --- src/internal/syscall/unix/at_libc.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/internal/syscall/unix/at_libc.go b/src/internal/syscall/unix/at_libc.go index 137e0e093651ed..23db8cf6ac0ca6 100644 --- a/src/internal/syscall/unix/at_libc.go +++ b/src/internal/syscall/unix/at_libc.go @@ -17,7 +17,7 @@ import ( //go:linkname procReadlinkat libc_readlinkat //go:linkname procMkdirat libc_mkdirat //go:linkname procFchmodat libc_fchmodat -//go:linkname procFchownat libc_chownat +//go:linkname procFchownat libc_fchownat var ( procFstatat, From 1959703dddffef61760d5d4fdedc4df8d2d73438 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Ramos=20Carre=C3=B1o?= Date: Fri, 14 Feb 2025 10:14:29 +0000 Subject: [PATCH 380/397] syscall: skip testAmbientCaps tests if there is no nobody user When there is not a nobody user (for example inside Docker), the tests TestAmbientCaps and TestAmbientCapsUserns should be skipped instead of failing. Fixes #71644 Change-Id: I7f92db19e2b6f449d8d897650a0ecd89f5150f4a GitHub-Last-Rev: a4c4f5bb61929b4981dc0b92d773bd4ef13d7d3d GitHub-Pull-Request: golang/go#71729 Reviewed-on: https://go-review.googlesource.com/c/go/+/649396 LUCI-TryBot-Result: Go LUCI Reviewed-by: Ian Lance Taylor Auto-Submit: Ian Lance Taylor Reviewed-by: Carlos Amedee --- src/syscall/exec_linux_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/syscall/exec_linux_test.go b/src/syscall/exec_linux_test.go index 1c2024af4550bf..04973dc9ad306b 100644 --- a/src/syscall/exec_linux_test.go +++ b/src/syscall/exec_linux_test.go @@ -646,7 +646,7 @@ func testAmbientCaps(t *testing.T, userns bool) { u, err := user.Lookup("nobody") if err != nil { - t.Fatal(err) + t.Skip("skipping: the nobody user does not exist; see Issue 71644") } uid, err := strconv.ParseInt(u.Uid, 0, 32) if err != nil { From bad791343f50a165e27f9f9bda6ba42af05b1869 Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Sat, 15 Feb 2025 04:45:04 +1100 Subject: [PATCH 381/397] internal/syscall/unix: correct fchmodat on openbsd This is incorrectly calling the fchownat trampoline - call fchmodat as intended. Change-Id: I7b1e758d456006303ca95b70df9e6b52d3020158 Reviewed-on: https://go-review.googlesource.com/c/go/+/649655 Reviewed-by: Ian Lance Taylor TryBot-Bypass: Damien Neil Reviewed-by: Damien Neil Commit-Queue: Damien Neil Auto-Submit: Damien Neil --- src/internal/syscall/unix/at_openbsd.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/internal/syscall/unix/at_openbsd.go b/src/internal/syscall/unix/at_openbsd.go index 771cb063e0cf40..22c959b0c7e1ed 100644 --- a/src/internal/syscall/unix/at_openbsd.go +++ b/src/internal/syscall/unix/at_openbsd.go @@ -81,7 +81,7 @@ func Fchownat(dirfd int, path string, uid, gid int, flags int) error { if err != nil { return err } - _, _, errno := syscall_syscall6(abi.FuncPCABI0(libc_fchmodat_trampoline), + _, _, errno := syscall_syscall6(abi.FuncPCABI0(libc_fchownat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(p)), uintptr(uid), From 2299a4289d69c71573fd22350eea0677639e563c Mon Sep 17 00:00:00 2001 From: cuishuang Date: Thu, 13 Feb 2025 15:28:21 +0800 Subject: [PATCH 382/397] bytes: add examples for Lines, SplitSeq, SplitAfterSeq, FieldsSeq and FieldsFuncSeq Change-Id: I0e755d5c73f14d2c98853bdd31a7f2e84c92a906 Reviewed-on: https://go-review.googlesource.com/c/go/+/648860 Reviewed-by: Ian Lance Taylor Auto-Submit: Ian Lance Taylor Reviewed-by: Dmitri Shuralyov LUCI-TryBot-Result: Go LUCI --- src/bytes/example_test.go | 90 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/src/bytes/example_test.go b/src/bytes/example_test.go index c9086d391809d4..71a4a9e2ca2f23 100644 --- a/src/bytes/example_test.go +++ b/src/bytes/example_test.go @@ -628,3 +628,93 @@ func ExampleToUpperSpecial() { // Original : ahoj vývojári golang // ToUpper : AHOJ VÝVOJÁRİ GOLANG } + +func ExampleLines() { + text := []byte("Hello\nWorld\nGo Programming\n") + for line := range bytes.Lines(text) { + fmt.Printf("%q\n", line) + } + + // Output: + // "Hello\n" + // "World\n" + // "Go Programming\n" +} + +func ExampleSplitSeq() { + s := []byte("a,b,c,d") + for part := range bytes.SplitSeq(s, []byte(",")) { + fmt.Printf("%q\n", part) + } + + // Output: + // "a" + // "b" + // "c" + // "d" +} + +func ExampleSplitAfterSeq() { + s := []byte("a,b,c,d") + for part := range bytes.SplitAfterSeq(s, []byte(",")) { + fmt.Printf("%q\n", part) + } + + // Output: + // "a," + // "b," + // "c," + // "d" +} + +func ExampleFieldsSeq() { + text := []byte("The quick brown fox") + fmt.Println("Split byte slice into fields:") + for word := range bytes.FieldsSeq(text) { + fmt.Printf("%q\n", word) + } + + textWithSpaces := []byte(" lots of spaces ") + fmt.Println("\nSplit byte slice with multiple spaces:") + for word := range bytes.FieldsSeq(textWithSpaces) { + fmt.Printf("%q\n", word) + } + + // Output: + // Split byte slice into fields: + // "The" + // "quick" + // "brown" + // "fox" + // + // Split byte slice with multiple spaces: + // "lots" + // "of" + // "spaces" +} + +func ExampleFieldsFuncSeq() { + text := []byte("The quick brown fox") + fmt.Println("Split on whitespace(similar to FieldsSeq):") + for word := range bytes.FieldsFuncSeq(text, unicode.IsSpace) { + fmt.Printf("%q\n", word) + } + + mixedText := []byte("abc123def456ghi") + fmt.Println("\nSplit on digits:") + for word := range bytes.FieldsFuncSeq(mixedText, unicode.IsDigit) { + fmt.Printf("%q\n", word) + } + + // Output: + // Split on whitespace(similar to FieldsSeq): + // "The" + // "quick" + // "brown" + // "fox" + // + // Split on digits: + // "abc" + // "def" + // "ghi" +} From 11f7ea8ce045c27956fcbffcc98e8987f9fb9743 Mon Sep 17 00:00:00 2001 From: Andrey Bokhanko Date: Wed, 27 Nov 2024 20:47:58 +0300 Subject: [PATCH 383/397] cmd/compile: add type-based alias analysis Make ssa.disjoint call ssa.disjointTypes to disambiguate Values based on their types. Only one type-based rule is employed: a Type can't alias with a pointer (https://pkg.go.dev/unsafe#Pointer). Fixes #70488 Change-Id: I5a7e75292c2b6b5a01fb9048e3e2360e31dbcdd9 Reviewed-on: https://go-review.googlesource.com/c/go/+/632176 LUCI-TryBot-Result: Go LUCI Reviewed-by: Keith Randall Auto-Submit: Keith Randall Reviewed-by: Dmitri Shuralyov Reviewed-by: Keith Randall --- src/cmd/compile/internal/rttype/rttype.go | 58 ++++++++++------ src/cmd/compile/internal/ssa/rewrite.go | 39 +++++++++++ src/cmd/compile/internal/ssa/rewrite_test.go | 69 +++++++++++++++++++- 3 files changed, 144 insertions(+), 22 deletions(-) diff --git a/src/cmd/compile/internal/rttype/rttype.go b/src/cmd/compile/internal/rttype/rttype.go index a5aecb25356c65..aaf98dda152f1f 100644 --- a/src/cmd/compile/internal/rttype/rttype.go +++ b/src/cmd/compile/internal/rttype/rttype.go @@ -50,26 +50,26 @@ func Init() { // Note: this has to be called explicitly instead of being // an init function so it runs after the types package has // been properly initialized. - Type = fromReflect(reflect.TypeOf(abi.Type{})) - ArrayType = fromReflect(reflect.TypeOf(abi.ArrayType{})) - ChanType = fromReflect(reflect.TypeOf(abi.ChanType{})) - FuncType = fromReflect(reflect.TypeOf(abi.FuncType{})) - InterfaceType = fromReflect(reflect.TypeOf(abi.InterfaceType{})) - OldMapType = fromReflect(reflect.TypeOf(abi.OldMapType{})) - SwissMapType = fromReflect(reflect.TypeOf(abi.SwissMapType{})) - PtrType = fromReflect(reflect.TypeOf(abi.PtrType{})) - SliceType = fromReflect(reflect.TypeOf(abi.SliceType{})) - StructType = fromReflect(reflect.TypeOf(abi.StructType{})) + Type = FromReflect(reflect.TypeOf(abi.Type{})) + ArrayType = FromReflect(reflect.TypeOf(abi.ArrayType{})) + ChanType = FromReflect(reflect.TypeOf(abi.ChanType{})) + FuncType = FromReflect(reflect.TypeOf(abi.FuncType{})) + InterfaceType = FromReflect(reflect.TypeOf(abi.InterfaceType{})) + OldMapType = FromReflect(reflect.TypeOf(abi.OldMapType{})) + SwissMapType = FromReflect(reflect.TypeOf(abi.SwissMapType{})) + PtrType = FromReflect(reflect.TypeOf(abi.PtrType{})) + SliceType = FromReflect(reflect.TypeOf(abi.SliceType{})) + StructType = FromReflect(reflect.TypeOf(abi.StructType{})) - IMethod = fromReflect(reflect.TypeOf(abi.Imethod{})) - Method = fromReflect(reflect.TypeOf(abi.Method{})) - StructField = fromReflect(reflect.TypeOf(abi.StructField{})) - UncommonType = fromReflect(reflect.TypeOf(abi.UncommonType{})) + IMethod = FromReflect(reflect.TypeOf(abi.Imethod{})) + Method = FromReflect(reflect.TypeOf(abi.Method{})) + StructField = FromReflect(reflect.TypeOf(abi.StructField{})) + UncommonType = FromReflect(reflect.TypeOf(abi.UncommonType{})) - InterfaceSwitch = fromReflect(reflect.TypeOf(abi.InterfaceSwitch{})) - TypeAssert = fromReflect(reflect.TypeOf(abi.TypeAssert{})) + InterfaceSwitch = FromReflect(reflect.TypeOf(abi.InterfaceSwitch{})) + TypeAssert = FromReflect(reflect.TypeOf(abi.TypeAssert{})) - ITab = fromReflect(reflect.TypeOf(abi.ITab{})) + ITab = FromReflect(reflect.TypeOf(abi.ITab{})) // Make sure abi functions are correct. These functions are used // by the linker which doesn't have the ability to do type layout, @@ -92,8 +92,8 @@ func Init() { } } -// fromReflect translates from a host type to the equivalent target type. -func fromReflect(rt reflect.Type) *types.Type { +// FromReflect translates from a host type to the equivalent target type. +func FromReflect(rt reflect.Type) *types.Type { t := reflectToType(rt) types.CalcSize(t) return t @@ -108,6 +108,10 @@ func reflectToType(rt reflect.Type) *types.Type { return types.Types[types.TBOOL] case reflect.Int: return types.Types[types.TINT] + case reflect.Int8: + return types.Types[types.TINT8] + case reflect.Int16: + return types.Types[types.TINT16] case reflect.Int32: return types.Types[types.TINT32] case reflect.Uint8: @@ -116,9 +120,15 @@ func reflectToType(rt reflect.Type) *types.Type { return types.Types[types.TUINT16] case reflect.Uint32: return types.Types[types.TUINT32] + case reflect.Float32: + return types.Types[types.TFLOAT32] + case reflect.Float64: + return types.Types[types.TFLOAT64] case reflect.Uintptr: return types.Types[types.TUINTPTR] - case reflect.Ptr, reflect.Func, reflect.UnsafePointer: + case reflect.Ptr: + return types.NewPtr(reflectToType(rt.Elem())) + case reflect.Func, reflect.UnsafePointer: // TODO: there's no mechanism to distinguish different pointer types, // so we treat them all as unsafe.Pointer. return types.Types[types.TUNSAFEPTR] @@ -134,6 +144,12 @@ func reflectToType(rt reflect.Type) *types.Type { fields[i] = &types.Field{Sym: &types.Sym{Name: f.Name}, Type: ft} } return types.NewStruct(fields) + case reflect.Chan: + return types.NewChan(reflectToType(rt.Elem()), types.ChanDir(rt.ChanDir())) + case reflect.String: + return types.Types[types.TSTRING] + case reflect.Complex128: + return types.Types[types.TCOMPLEX128] default: base.Fatalf("unhandled kind %s", rt.Kind()) return nil @@ -155,7 +171,7 @@ func NewCursor(lsym *obj.LSym, off int64, t *types.Type) Cursor { // WritePtr writes a pointer "target" to the component at the location specified by c. func (c Cursor) WritePtr(target *obj.LSym) { - if c.typ.Kind() != types.TUNSAFEPTR { + if c.typ.Kind() != types.TUNSAFEPTR && c.typ.Kind() != types.TPTR { base.Fatalf("can't write ptr, it has kind %s", c.typ.Kind()) } if target == nil { diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go index 71f8e9045cecab..eb523675b15a6d 100644 --- a/src/cmd/compile/internal/ssa/rewrite.go +++ b/src/cmd/compile/internal/ssa/rewrite.go @@ -863,6 +863,12 @@ func disjoint(p1 *Value, n1 int64, p2 *Value, n2 int64) bool { } return base, offset } + + // Run types-based analysis + if disjointTypes(p1.Type, p2.Type) { + return true + } + p1, off1 := baseAndOffset(p1) p2, off2 := baseAndOffset(p2) if isSamePtr(p1, p2) { @@ -888,6 +894,39 @@ func disjoint(p1 *Value, n1 int64, p2 *Value, n2 int64) bool { return false } +// disjointTypes reports whether a memory region pointed to by a pointer of type +// t1 does not overlap with a memory region pointed to by a pointer of type t2 -- +// based on type aliasing rules. +func disjointTypes(t1 *types.Type, t2 *types.Type) bool { + // Unsafe pointer can alias with anything. + if t1.IsUnsafePtr() || t2.IsUnsafePtr() { + return false + } + + if !t1.IsPtr() || !t2.IsPtr() { + panic("disjointTypes: one of arguments is not a pointer") + } + + t1 = t1.Elem() + t2 = t2.Elem() + + // Not-in-heap types are not supported -- they are rare and non-important; also, + // type.HasPointers check doesn't work for them correctly. + if t1.NotInHeap() || t2.NotInHeap() { + return false + } + + isPtrShaped := func(t *types.Type) bool { return int(t.Size()) == types.PtrSize && t.HasPointers() } + + // Pointers and non-pointers are disjoint (https://pkg.go.dev/unsafe#Pointer). + if (isPtrShaped(t1) && !t2.HasPointers()) || + (isPtrShaped(t2) && !t1.HasPointers()) { + return true + } + + return false +} + // moveSize returns the number of bytes an aligned MOV instruction moves. func moveSize(align int64, c *Config) int64 { switch { diff --git a/src/cmd/compile/internal/ssa/rewrite_test.go b/src/cmd/compile/internal/ssa/rewrite_test.go index 357fe1183fad56..92e9d3fd5b9ca5 100644 --- a/src/cmd/compile/internal/ssa/rewrite_test.go +++ b/src/cmd/compile/internal/ssa/rewrite_test.go @@ -4,7 +4,12 @@ package ssa -import "testing" +import ( + "cmd/compile/internal/rttype" + "reflect" + "testing" + "unsafe" +) // We generate memmove for copy(x[1:], x[:]), however we may change it to OpMove, // because size is known. Check that OpMove is alias-safe, or we did call memmove. @@ -218,3 +223,65 @@ func TestMergePPC64AndSrwi(t *testing.T) { } } } + +func TestDisjointTypes(t *testing.T) { + tests := []struct { + v1, v2 any // two pointers to some types + expected bool + }{ + {new(int8), new(int8), false}, + {new(int8), new(float32), false}, + {new(int8), new(*int8), true}, + {new(*int8), new(*float32), false}, + {new(*int8), new(chan<- int8), false}, + {new(**int8), new(*int8), false}, + {new(***int8), new(**int8), false}, + {new(int8), new(chan<- int8), true}, + {new(int), unsafe.Pointer(nil), false}, + {new(byte), new(string), false}, + {new(int), new(string), false}, + {new(*int8), new(struct{ a, b int }), true}, + {new(*int8), new(struct { + a *int + b int + }), false}, + {new(*int8), new(struct { + a int + b *int + }), false}, // with more precise analysis it should be true + {new(*byte), new(string), false}, + {new(int), new(struct { + a int + b *int + }), false}, + {new(float64), new(complex128), false}, + {new(*byte), new([]byte), false}, + {new(int), new([]byte), false}, + {new(int), new([2]*byte), false}, // with more recise analysis it should be true + {new([2]int), new(*byte), true}, + } + for _, tst := range tests { + t1 := rttype.FromReflect(reflect.TypeOf(tst.v1)) + t2 := rttype.FromReflect(reflect.TypeOf(tst.v2)) + result := disjointTypes(t1, t2) + if result != tst.expected { + t.Errorf("disjointTypes(%s, %s) got %t expected %t", t1.String(), t2.String(), result, tst.expected) + } + } +} + +//go:noinline +func foo(p1 *int64, p2 *float64) int64 { + *p1 = 10 + *p2 = 0 // disjointTypes shouldn't consider this and preceding stores as non-aliasing + return *p1 +} + +func TestDisjointTypesRun(t *testing.T) { + f := float64(0) + i := (*int64)(unsafe.Pointer(&f)) + r := foo(i, &f) + if r != 0 { + t.Errorf("disjointTypes gives an incorrect answer that leads to an incorrect optimization.") + } +} From 5f65e5cb56f98381970de5485e704f3c7e20ca9a Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 11 Feb 2025 15:53:20 -0800 Subject: [PATCH 384/397] doc/godebug: mention GODEBUG=fips140 Fixes #71666 Change-Id: Ice816cf2943c5b6660f05934b4c7ca38545714b0 Reviewed-on: https://go-review.googlesource.com/c/go/+/648520 LUCI-TryBot-Result: Go LUCI Reviewed-by: Roland Shoemaker Reviewed-by: Filippo Valsorda Commit-Queue: Ian Lance Taylor Auto-Submit: Ian Lance Taylor Reviewed-by: Ian Lance Taylor --- doc/godebug.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/doc/godebug.md b/doc/godebug.md index 1b5674f2cd0b5b..cdc09ddcc4792d 100644 --- a/doc/godebug.md +++ b/doc/godebug.md @@ -153,6 +153,17 @@ and the [go command documentation](/cmd/go#hdr-Build_and_test_caching). ### Go 1.24 +Go 1.24 added a new `fips140` setting that controls whether the Go +Cryptographic Module operates in FIPS 140-3 mode. +The possible values are: +- "off": no special support for FIPS 140-3 mode. This is the default. +- "on": the Go Cryptographic Module operates in FIPS 140-3 mode. +- "only": like "on", but cryptographic algorithms not approved by + FIPS 140-3 return an error or panic. +For more information, see [FIPS 140-3 Compliance](/doc/security/fips140). +This setting is fixed at program startup time, and can't be modified +by changing the `GODEBUG` environment variable after the program starts. + Go 1.24 changed the global [`math/rand.Seed`](/pkg/math/rand/#Seed) to be a no-op. This behavior is controlled by the `randseednop` setting. For Go 1.24 it defaults to `randseednop=1`. From 7b7307f632052c0ab3752f24f6d787b281bb5b99 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Tue, 17 Dec 2024 20:40:49 +0100 Subject: [PATCH 385/397] crypto/rsa: add benchmarks for not and partially optimized keys Updates #59695 Change-Id: I7944195c805cd9da819cdf2bd49ecb2423ccd73b Reviewed-on: https://go-review.googlesource.com/c/go/+/637178 Auto-Submit: Filippo Valsorda Reviewed-by: Roland Shoemaker LUCI-TryBot-Result: Go LUCI Reviewed-by: Dmitri Shuralyov Reviewed-by: Daniel McCarney --- src/crypto/rsa/rsa_test.go | 51 ++++++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 11 deletions(-) diff --git a/src/crypto/rsa/rsa_test.go b/src/crypto/rsa/rsa_test.go index 9e4478f9705f85..795439d1c13df0 100644 --- a/src/crypto/rsa/rsa_test.go +++ b/src/crypto/rsa/rsa_test.go @@ -698,19 +698,48 @@ func BenchmarkEncryptOAEP(b *testing.B) { } func BenchmarkSignPKCS1v15(b *testing.B) { - b.Run("2048", func(b *testing.B) { - hashed := sha256.Sum256([]byte("testing")) + b.Run("2048", func(b *testing.B) { benchmarkSignPKCS1v15(b, test2048Key) }) + b.Run("2048/noprecomp/OnlyD", func(b *testing.B) { + benchmarkSignPKCS1v15(b, &PrivateKey{ + PublicKey: test2048Key.PublicKey, + D: test2048Key.D, + }) + }) + b.Run("2048/noprecomp/Primes", func(b *testing.B) { + benchmarkSignPKCS1v15(b, &PrivateKey{ + PublicKey: test2048Key.PublicKey, + D: test2048Key.D, + Primes: test2048Key.Primes, + }) + }) + // This is different from "2048" because it's only the public precomputed + // values, and not the crypto/internal/fips140/rsa.PrivateKey. + b.Run("2048/noprecomp/AllValues", func(b *testing.B) { + benchmarkSignPKCS1v15(b, &PrivateKey{ + PublicKey: test2048Key.PublicKey, + D: test2048Key.D, + Primes: test2048Key.Primes, + Precomputed: PrecomputedValues{ + Dp: test2048Key.Precomputed.Dp, + Dq: test2048Key.Precomputed.Dq, + Qinv: test2048Key.Precomputed.Qinv, + }, + }) + }) +} - var sink byte - b.ResetTimer() - for i := 0; i < b.N; i++ { - s, err := SignPKCS1v15(rand.Reader, test2048Key, crypto.SHA256, hashed[:]) - if err != nil { - b.Fatal(err) - } - sink ^= s[0] +func benchmarkSignPKCS1v15(b *testing.B, k *PrivateKey) { + hashed := sha256.Sum256([]byte("testing")) + + var sink byte + b.ResetTimer() + for i := 0; i < b.N; i++ { + s, err := SignPKCS1v15(rand.Reader, k, crypto.SHA256, hashed[:]) + if err != nil { + b.Fatal(err) } - }) + sink ^= s[0] + } } func BenchmarkVerifyPKCS1v15(b *testing.B) { From 10cef816aa9769345016c04032090ae7f5851f5c Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 13 Feb 2025 14:40:01 -0800 Subject: [PATCH 386/397] internal/godebugs: add fips140 as an opaque godebug setting This permits using "godebug fips140=on" in go.mod and using "//go:debug fips140=on" in the main package. Change code references to the godebug setting to remove the # which is no longer required. For #71666 Change-Id: I3a60ecc55b03848dadd6d431eb43137b6df6568b Reviewed-on: https://go-review.googlesource.com/c/go/+/649495 Reviewed-by: Ian Lance Taylor Auto-Submit: Ian Lance Taylor Reviewed-by: Roland Shoemaker LUCI-TryBot-Result: Go LUCI Reviewed-by: Filippo Valsorda --- src/crypto/fips140/fips140.go | 2 +- src/crypto/internal/fips140/check/check.go | 2 +- src/crypto/internal/fips140only/fips140only.go | 2 +- src/crypto/internal/fips140test/check_test.go | 2 +- src/internal/godebugs/table.go | 1 + 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/crypto/fips140/fips140.go b/src/crypto/fips140/fips140.go index 41d0d170cf9fc8..1c4036d5e74735 100644 --- a/src/crypto/fips140/fips140.go +++ b/src/crypto/fips140/fips140.go @@ -10,7 +10,7 @@ import ( "internal/godebug" ) -var fips140GODEBUG = godebug.New("#fips140") +var fips140GODEBUG = godebug.New("fips140") // Enabled reports whether the cryptography libraries are operating in FIPS // 140-3 mode. diff --git a/src/crypto/internal/fips140/check/check.go b/src/crypto/internal/fips140/check/check.go index f8a5d7a41e982e..454cd6c738b1af 100644 --- a/src/crypto/internal/fips140/check/check.go +++ b/src/crypto/internal/fips140/check/check.go @@ -100,7 +100,7 @@ func init() { clear(nbuf[:]) h.Reset() - if godebug.Value("#fips140") == "debug" { + if godebug.Value("fips140") == "debug" { println("fips140: verified code+data") } diff --git a/src/crypto/internal/fips140only/fips140only.go b/src/crypto/internal/fips140only/fips140only.go index 7126781af0d8bc..147877a34fcb5f 100644 --- a/src/crypto/internal/fips140only/fips140only.go +++ b/src/crypto/internal/fips140only/fips140only.go @@ -16,7 +16,7 @@ import ( // Enabled reports whether FIPS 140-only mode is enabled, in which non-approved // cryptography returns an error or panics. -var Enabled = godebug.New("#fips140").Value() == "only" +var Enabled = godebug.New("fips140").Value() == "only" func ApprovedHash(h hash.Hash) bool { switch h.(type) { diff --git a/src/crypto/internal/fips140test/check_test.go b/src/crypto/internal/fips140test/check_test.go index 3c594bdb338b0e..c014fff2a6d80d 100644 --- a/src/crypto/internal/fips140test/check_test.go +++ b/src/crypto/internal/fips140test/check_test.go @@ -27,7 +27,7 @@ func TestIntegrityCheck(t *testing.T) { return } - if godebug.New("#fips140").Value() == "on" { + if godebug.New("fips140").Value() == "on" { t.Fatalf("GODEBUG=fips140=on but verification did not run") } diff --git a/src/internal/godebugs/table.go b/src/internal/godebugs/table.go index 9c48a923f032c3..e0fde01f09d9bb 100644 --- a/src/internal/godebugs/table.go +++ b/src/internal/godebugs/table.go @@ -28,6 +28,7 @@ var All = []Info{ {Name: "asynctimerchan", Package: "time", Changed: 23, Old: "1"}, {Name: "dataindependenttiming", Package: "crypto/subtle", Opaque: true}, {Name: "execerrdot", Package: "os/exec"}, + {Name: "fips140", Package: "crypto/fips140", Opaque: true}, {Name: "gocachehash", Package: "cmd/go"}, {Name: "gocachetest", Package: "cmd/go"}, {Name: "gocacheverify", Package: "cmd/go"}, From 1ce87bea470c3eae9be75f6e2848271588cc6ca2 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Mon, 10 Feb 2025 11:30:52 +0100 Subject: [PATCH 387/397] crypto/internal/fips140/edwards25519: make Scalar.SetCanonicalBytes constant time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Internally we only use SetCanonicalBytes as part of Ed25519 verification, where all inputs are public, so it doesn't need to be constant time. However, this code is replicated outside of the standard library. Even there, an attack is not practical, so this should not be considered a security vulnerability: - For specific scalars, this only leaks at most four bits of information, and always the same four bits (so it's not an adaptive attack). - For derived scalars, assuming they are valid and uniformly distributed, the loop would return true on the first iteration with probability (1 - 2⁻¹²⁷) due to the shape of the scalar field order. Still, making it constant time is easy enough and saves the next person from having to think about it. This was previously reported by Yawning Angel, and then as part of a security audit. Change-Id: I6a6a46563c8abecb0b4a6f12033a71c4c4da6fa7 Reviewed-on: https://go-review.googlesource.com/c/go/+/648035 Reviewed-by: Roland Shoemaker LUCI-TryBot-Result: Go LUCI Reviewed-by: Dmitri Shuralyov Auto-Submit: Filippo Valsorda --- .../internal/fips140/edwards25519/scalar.go | 27 +++++++++----- .../fips140/edwards25519/scalar_test.go | 35 +++++++++++++------ 2 files changed, 42 insertions(+), 20 deletions(-) diff --git a/src/crypto/internal/fips140/edwards25519/scalar.go b/src/crypto/internal/fips140/edwards25519/scalar.go index 9d60146d794d68..22bbebfbb41d7d 100644 --- a/src/crypto/internal/fips140/edwards25519/scalar.go +++ b/src/crypto/internal/fips140/edwards25519/scalar.go @@ -7,6 +7,7 @@ package edwards25519 import ( "crypto/internal/fips140deps/byteorder" "errors" + "math/bits" ) // A Scalar is an integer modulo @@ -179,15 +180,23 @@ func isReduced(s []byte) bool { return false } - for i := len(s) - 1; i >= 0; i-- { - switch { - case s[i] > scalarMinusOneBytes[i]: - return false - case s[i] < scalarMinusOneBytes[i]: - return true - } - } - return true + s0 := byteorder.LEUint64(s[:8]) + s1 := byteorder.LEUint64(s[8:16]) + s2 := byteorder.LEUint64(s[16:24]) + s3 := byteorder.LEUint64(s[24:]) + + l0 := byteorder.LEUint64(scalarMinusOneBytes[:8]) + l1 := byteorder.LEUint64(scalarMinusOneBytes[8:16]) + l2 := byteorder.LEUint64(scalarMinusOneBytes[16:24]) + l3 := byteorder.LEUint64(scalarMinusOneBytes[24:]) + + // Do a constant time subtraction chain scalarMinusOneBytes - s. If there is + // a borrow at the end, then s > scalarMinusOneBytes. + _, b := bits.Sub64(l0, s0, 0) + _, b = bits.Sub64(l1, s1, b) + _, b = bits.Sub64(l2, s2, b) + _, b = bits.Sub64(l3, s3, b) + return b == 0 } // SetBytesWithClamping applies the buffer pruning described in RFC 8032, diff --git a/src/crypto/internal/fips140/edwards25519/scalar_test.go b/src/crypto/internal/fips140/edwards25519/scalar_test.go index 05551ef771187b..76e920a2feb2e2 100644 --- a/src/crypto/internal/fips140/edwards25519/scalar_test.go +++ b/src/crypto/internal/fips140/edwards25519/scalar_test.go @@ -26,7 +26,7 @@ func quickCheckConfig(slowScale int) *quick.Config { var scOneBytes = [32]byte{1} var scOne, _ = new(Scalar).SetCanonicalBytes(scOneBytes[:]) -var scMinusOne, _ = new(Scalar).SetCanonicalBytes(scalarMinusOneBytes[:]) +var scMinusOne = new(Scalar).Subtract(new(Scalar), scOne) // Generate returns a valid (reduced modulo l) Scalar with a distribution // weighted towards high, low, and edge values. @@ -38,7 +38,7 @@ func (Scalar) Generate(rand *mathrand.Rand, size int) reflect.Value { case diceRoll == 1: s = scOneBytes case diceRoll == 2: - s = scalarMinusOneBytes + s = [32]byte(scMinusOne.Bytes()) case diceRoll < 5: // Generate a low scalar in [0, 2^125). rand.Read(s[:16]) @@ -96,16 +96,29 @@ func TestScalarSetCanonicalBytes(t *testing.T) { t.Errorf("failed scalar->bytes->scalar round-trip: %v", err) } - b := scalarMinusOneBytes - b[31] += 1 - s := scOne - if out, err := s.SetCanonicalBytes(b[:]); err == nil { - t.Errorf("SetCanonicalBytes worked on a non-canonical value") - } else if s != scOne { - t.Errorf("SetCanonicalBytes modified its receiver") - } else if out != nil { - t.Errorf("SetCanonicalBytes did not return nil with an error") + expectReject := func(b []byte) { + t.Helper() + s := scOne + if out, err := s.SetCanonicalBytes(b[:]); err == nil { + t.Errorf("SetCanonicalBytes worked on a non-canonical value") + } else if s != scOne { + t.Errorf("SetCanonicalBytes modified its receiver") + } else if out != nil { + t.Errorf("SetCanonicalBytes did not return nil with an error") + } } + + b := scMinusOne.Bytes() + b[0] += 1 + expectReject(b) + + b = scMinusOne.Bytes() + b[31] += 1 + expectReject(b) + + b = scMinusOne.Bytes() + b[31] |= 0b1000_0000 + expectReject(b) } func TestScalarSetUniformBytes(t *testing.T) { From 67903012f71b6ceff7a25758c33e77c47710fbf7 Mon Sep 17 00:00:00 2001 From: cuishuang Date: Thu, 21 Nov 2024 17:14:21 +0800 Subject: [PATCH 388/397] cmd/go/internal: use pathpkg name more The package "path" is already imported under the name pathpkg and used many times in these files. It's not worth it to also make it available under the name path, so keep using pathpkg. Change-Id: I7f8fa7a11de338b9a7c0f58a48d5af68b5639cfe Reviewed-on: https://go-review.googlesource.com/c/go/+/630475 Auto-Submit: Dmitri Shuralyov Reviewed-by: Sam Thanawalla LUCI-TryBot-Result: Go LUCI Reviewed-by: Dmitri Shuralyov --- src/cmd/go/internal/modfetch/proxy.go | 3 +-- src/cmd/go/internal/modload/load.go | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/cmd/go/internal/modfetch/proxy.go b/src/cmd/go/internal/modfetch/proxy.go index e0efb097ecdda9..896f310bdf77ca 100644 --- a/src/cmd/go/internal/modfetch/proxy.go +++ b/src/cmd/go/internal/modfetch/proxy.go @@ -12,7 +12,6 @@ import ( "io" "io/fs" "net/url" - "path" pathpkg "path" "path/filepath" "strings" @@ -98,7 +97,7 @@ func proxyList() ([]proxySpec, error) { // Single-word tokens are reserved for built-in behaviors, and anything // containing the string ":/" or matching an absolute file path must be a // complete URL. For all other paths, implicitly add "https://". - if strings.ContainsAny(url, ".:/") && !strings.Contains(url, ":/") && !filepath.IsAbs(url) && !path.IsAbs(url) { + if strings.ContainsAny(url, ".:/") && !strings.Contains(url, ":/") && !filepath.IsAbs(url) && !pathpkg.IsAbs(url) { url = "https://" + url } diff --git a/src/cmd/go/internal/modload/load.go b/src/cmd/go/internal/modload/load.go index 12dd9425f65962..1a3a4b5a694493 100644 --- a/src/cmd/go/internal/modload/load.go +++ b/src/cmd/go/internal/modload/load.go @@ -103,7 +103,6 @@ import ( "io/fs" "maps" "os" - "path" pathpkg "path" "path/filepath" "runtime" @@ -717,7 +716,7 @@ func pathInModuleCache(ctx context.Context, dir string, rs *Requirements) string return "", false } - return path.Join(m.Path, filepath.ToSlash(sub)), true + return pathpkg.Join(m.Path, filepath.ToSlash(sub)), true } if rs.pruning == pruned { From 77343fa646c5d2a01fb3cbeabda1b3ff008c3b03 Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Thu, 6 Feb 2025 00:38:51 +1100 Subject: [PATCH 389/397] runtime: use return for async preemption resumption on arm64 Use return with register for async preemption resumption on arm64. This has the same behaviour as the current use of JMP, however is permitted when Branch Target Identification is being enforced, while a JMP with register is considered an indirect call and requires a `BTI J` marker at the resumption address. Updates #66054 Change-Id: I135ac577073467bedd9efd8df15b76c97dc08767 Reviewed-on: https://go-review.googlesource.com/c/go/+/646782 Reviewed-by: Dmitri Shuralyov LUCI-TryBot-Result: Go LUCI Reviewed-by: Cherry Mui --- src/runtime/mkpreempt.go | 2 +- src/runtime/preempt_arm64.s | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runtime/mkpreempt.go b/src/runtime/mkpreempt.go index 08500a90d532ed..6a9cf77a43fcf0 100644 --- a/src/runtime/mkpreempt.go +++ b/src/runtime/mkpreempt.go @@ -370,7 +370,7 @@ func genARM64() { p("MOVD -8(RSP), R29") // restore frame pointer p("MOVD (RSP), R27") // load PC to REGTMP p("ADD $%d, RSP", l.stack+16) // pop frame (including the space pushed by sigctxt.pushCall) - p("JMP (R27)") + p("RET (R27)") } func genMIPS(_64bit bool) { diff --git a/src/runtime/preempt_arm64.s b/src/runtime/preempt_arm64.s index c27d475dee6ae0..31ec9d940f76d4 100644 --- a/src/runtime/preempt_arm64.s +++ b/src/runtime/preempt_arm64.s @@ -82,4 +82,4 @@ TEXT ·asyncPreempt(SB),NOSPLIT|NOFRAME,$0-0 MOVD -8(RSP), R29 MOVD (RSP), R27 ADD $512, RSP - JMP (R27) + RET (R27) From d7c242a19ae0fd9adae1c6d6222df2f1d93646da Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Tue, 2 Jul 2024 00:31:53 +1000 Subject: [PATCH 390/397] cmd/internal/obj/riscv: support MOVD with floating point constants Currently, we only support loading of values from memory (or other registers). Add floating point constant support to MOVD. This is implemented by storing the floating point constant to a symbol, which is then loaded into the floating point register. Change-Id: I6db242d27f606f0d5d084a3ab93538698d3a4f8c Reviewed-on: https://go-review.googlesource.com/c/go/+/631876 Reviewed-by: Meng Zhuo Reviewed-by: Mark Ryan Reviewed-by: Dmitri Shuralyov Reviewed-by: Cherry Mui LUCI-TryBot-Result: Go LUCI --- src/cmd/asm/internal/asm/testdata/riscv64.s | 3 +++ src/cmd/internal/obj/riscv/obj.go | 22 ++++++++++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/cmd/asm/internal/asm/testdata/riscv64.s b/src/cmd/asm/internal/asm/testdata/riscv64.s index cbe99ba3485e7a..fc44f561f259ab 100644 --- a/src/cmd/asm/internal/asm/testdata/riscv64.s +++ b/src/cmd/asm/internal/asm/testdata/riscv64.s @@ -510,6 +510,9 @@ start: MOVD F0, 4(X5) // 27b20200 MOVD F0, F1 // d3000022 + // Convert to load of symbol (AUIPC + FLD) + MOVD $(709.78271289338397), F3 // 970f000087b10f00 + // TLS load with local-exec (LUI + ADDIW + ADD of TP + load) MOV tls(SB), X5 // b70f00009b8f0f00b38f4f0083b20f00 MOVB tls(SB), X5 // b70f00009b8f0f00b38f4f0083820f00 diff --git a/src/cmd/internal/obj/riscv/obj.go b/src/cmd/internal/obj/riscv/obj.go index c6f66d0195df4b..3a4ab556f7df2b 100644 --- a/src/cmd/internal/obj/riscv/obj.go +++ b/src/cmd/internal/obj/riscv/obj.go @@ -147,6 +147,15 @@ func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) { p.From.Name = obj.NAME_EXTERN p.From.Offset = 0 } + + case AMOVD: + if p.From.Type == obj.TYPE_FCONST && p.From.Name == obj.NAME_NONE && p.From.Reg == obj.REG_NONE { + f64 := p.From.Val.(float64) + p.From.Type = obj.TYPE_MEM + p.From.Sym = ctxt.Float64Sym(f64) + p.From.Name = obj.NAME_EXTERN + p.From.Offset = 0 + } } } @@ -2322,12 +2331,19 @@ func instructionsForMOV(p *obj.Prog) []*instruction { } // Note that the values for $off_hi and $off_lo are currently - // zero and will be assigned during relocation. + // zero and will be assigned during relocation. If the destination + // is an integer register then we can use the same register for the + // address computation, otherwise we need to use the temporary register. // // AUIPC $off_hi, Rd // L $off_lo, Rd, Rd - insAUIPC := &instruction{as: AAUIPC, rd: ins.rd} - ins.as, ins.rs1, ins.rs2, ins.imm = movToLoad(p.As), ins.rd, obj.REG_NONE, 0 + // + addrReg := ins.rd + if addrReg < REG_X0 || addrReg > REG_X31 { + addrReg = REG_TMP + } + insAUIPC := &instruction{as: AAUIPC, rd: addrReg} + ins.as, ins.rs1, ins.rs2, ins.imm = movToLoad(p.As), addrReg, obj.REG_NONE, 0 inss = []*instruction{insAUIPC, ins} default: From 63ae4167208259fea30769e7baf8ef5b4c73ef4e Mon Sep 17 00:00:00 2001 From: Jes Cok Date: Fri, 14 Feb 2025 13:50:24 +0000 Subject: [PATCH 391/397] os: explicitly return nil for rootChown in root_openat.go It is consistent with the same function in root_noopenat.go. Change-Id: I6ddbf4dfcc725cb2023bc6bed961cc525b9c43d2 GitHub-Last-Rev: 0802150a6a8e5d4bd395b702ecc518df1e8dd4c0 GitHub-Pull-Request: golang/go#71743 Reviewed-on: https://go-review.googlesource.com/c/go/+/649417 Auto-Submit: Ian Lance Taylor Reviewed-by: Damien Neil LUCI-TryBot-Result: Go LUCI Reviewed-by: Ian Lance Taylor Auto-Submit: Ian Lance Taylor --- src/os/root_openat.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/os/root_openat.go b/src/os/root_openat.go index 65d3eacf4df98b..cac0b1df0faf8b 100644 --- a/src/os/root_openat.go +++ b/src/os/root_openat.go @@ -84,7 +84,7 @@ func rootChown(r *Root, name string, uid, gid int) error { if err != nil { return &PathError{Op: "chownat", Path: name, Err: err} } - return err + return nil } func rootMkdir(r *Root, name string, perm FileMode) error { From c62c69dd5c1af0e25c76071f8987480680f09222 Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Fri, 3 Jan 2025 19:06:18 +1100 Subject: [PATCH 392/397] crypto/internal/fips140/subtle: provide riscv64 assembly implementation for xorBytes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Provide a riscv64 assembly implementation of xorBytes, which can process up to 64 bytes per loop and has better handling for unaligned inputs. This provides a considerable performance gain compared to the generic code. On a StarFive VisionFive 2: │ subtle.1 │ subtle.2 │ │ sec/op │ sec/op vs base │ XORBytes/8Bytes-4 59.54n ± 0% 58.15n ± 0% -2.33% (p=0.000 n=10) XORBytes/128Bytes-4 125.60n ± 0% 74.93n ± 0% -40.35% (p=0.000 n=10) XORBytes/2048Bytes-4 1088.5n ± 0% 602.4n ± 0% -44.66% (p=0.000 n=10) XORBytes/8192Bytes-4 4.163µ ± 0% 2.271µ ± 0% -45.45% (p=0.000 n=10) XORBytes/32768Bytes-4 35.47µ ± 0% 28.12µ ± 0% -20.74% (p=0.000 n=10) XORBytesUnaligned/8Bytes0Offset-4 59.80n ± 0% 57.48n ± 0% -3.86% (p=0.000 n=10) XORBytesUnaligned/8Bytes1Offset-4 72.97n ± 0% 57.48n ± 0% -21.23% (p=0.000 n=10) XORBytesUnaligned/8Bytes2Offset-4 72.97n ± 0% 57.50n ± 0% -21.21% (p=0.000 n=10) XORBytesUnaligned/8Bytes3Offset-4 72.99n ± 0% 57.48n ± 0% -21.26% (p=0.000 n=10) XORBytesUnaligned/8Bytes4Offset-4 72.96n ± 0% 57.44n ± 0% -21.28% (p=0.000 n=10) XORBytesUnaligned/8Bytes5Offset-4 72.93n ± 0% 57.48n ± 0% -21.18% (p=0.000 n=10) XORBytesUnaligned/8Bytes6Offset-4 72.97n ± 0% 57.47n ± 0% -21.25% (p=0.000 n=10) XORBytesUnaligned/8Bytes7Offset-4 72.96n ± 0% 57.47n ± 0% -21.24% (p=0.000 n=10) XORBytesUnaligned/128Bytes0Offset-4 125.30n ± 0% 74.18n ± 0% -40.80% (p=0.000 n=10) XORBytesUnaligned/128Bytes1Offset-4 557.4n ± 0% 131.1n ± 0% -76.48% (p=0.000 n=10) XORBytesUnaligned/128Bytes2Offset-4 557.3n ± 0% 132.5n ± 0% -76.22% (p=0.000 n=10) XORBytesUnaligned/128Bytes3Offset-4 557.6n ± 0% 133.7n ± 0% -76.02% (p=0.000 n=10) XORBytesUnaligned/128Bytes4Offset-4 557.4n ± 0% 125.0n ± 0% -77.57% (p=0.000 n=10) XORBytesUnaligned/128Bytes5Offset-4 557.7n ± 0% 125.7n ± 0% -77.46% (p=0.000 n=10) XORBytesUnaligned/128Bytes6Offset-4 557.5n ± 0% 127.0n ± 0% -77.22% (p=0.000 n=10) XORBytesUnaligned/128Bytes7Offset-4 557.7n ± 0% 128.3n ± 0% -76.99% (p=0.000 n=10) XORBytesUnaligned/2048Bytes0Offset-4 1088.5n ± 0% 601.9n ± 0% -44.71% (p=0.000 n=10) XORBytesUnaligned/2048Bytes1Offset-4 8243.0n ± 0% 655.7n ± 0% -92.05% (p=0.000 n=10) XORBytesUnaligned/2048Bytes2Offset-4 8244.0n ± 0% 657.1n ± 0% -92.03% (p=0.000 n=10) XORBytesUnaligned/2048Bytes3Offset-4 8247.5n ± 0% 658.7n ± 0% -92.01% (p=0.000 n=10) XORBytesUnaligned/2048Bytes4Offset-4 8243.0n ± 0% 649.8n ± 0% -92.12% (p=0.000 n=10) XORBytesUnaligned/2048Bytes5Offset-4 8247.0n ± 0% 650.2n ± 0% -92.12% (p=0.000 n=10) XORBytesUnaligned/2048Bytes6Offset-4 8243.0n ± 0% 651.6n ± 0% -92.09% (p=0.000 n=10) XORBytesUnaligned/2048Bytes7Offset-4 8244.0n ± 0% 652.8n ± 0% -92.08% (p=0.000 n=10) geomean 410.1n 147.2n -64.10% │ subtle.1 │ subtle.2 │ │ B/s │ B/s vs base │ XORBytes/8Bytes-4 128.1Mi ± 0% 131.2Mi ± 0% +2.40% (p=0.000 n=10) XORBytes/128Bytes-4 971.6Mi ± 0% 1629.2Mi ± 0% +67.69% (p=0.000 n=10) XORBytes/2048Bytes-4 1.752Gi ± 0% 3.166Gi ± 0% +80.68% (p=0.000 n=10) XORBytes/8192Bytes-4 1.833Gi ± 0% 3.360Gi ± 0% +83.35% (p=0.000 n=10) XORBytes/32768Bytes-4 881.0Mi ± 0% 1111.5Mi ± 0% +26.16% (p=0.000 n=10) XORBytesUnaligned/8Bytes0Offset-4 127.6Mi ± 0% 132.7Mi ± 0% +4.02% (p=0.000 n=10) XORBytesUnaligned/8Bytes1Offset-4 104.5Mi ± 0% 132.7Mi ± 0% +26.95% (p=0.000 n=10) XORBytesUnaligned/8Bytes2Offset-4 104.6Mi ± 0% 132.7Mi ± 0% +26.92% (p=0.000 n=10) XORBytesUnaligned/8Bytes3Offset-4 104.5Mi ± 0% 132.8Mi ± 0% +27.01% (p=0.000 n=10) XORBytesUnaligned/8Bytes4Offset-4 104.6Mi ± 0% 132.8Mi ± 0% +27.02% (p=0.000 n=10) XORBytesUnaligned/8Bytes5Offset-4 104.6Mi ± 0% 132.7Mi ± 0% +26.89% (p=0.000 n=10) XORBytesUnaligned/8Bytes6Offset-4 104.5Mi ± 0% 132.8Mi ± 0% +26.99% (p=0.000 n=10) XORBytesUnaligned/8Bytes7Offset-4 104.6Mi ± 0% 132.8Mi ± 0% +26.97% (p=0.000 n=10) XORBytesUnaligned/128Bytes0Offset-4 974.4Mi ± 0% 1645.7Mi ± 0% +68.90% (p=0.000 n=10) XORBytesUnaligned/128Bytes1Offset-4 219.0Mi ± 0% 931.3Mi ± 0% +325.23% (p=0.000 n=10) XORBytesUnaligned/128Bytes2Offset-4 219.0Mi ± 0% 921.2Mi ± 0% +320.57% (p=0.000 n=10) XORBytesUnaligned/128Bytes3Offset-4 218.9Mi ± 0% 912.9Mi ± 0% +316.97% (p=0.000 n=10) XORBytesUnaligned/128Bytes4Offset-4 219.0Mi ± 0% 976.4Mi ± 0% +345.85% (p=0.000 n=10) XORBytesUnaligned/128Bytes5Offset-4 218.9Mi ± 0% 971.2Mi ± 0% +343.70% (p=0.000 n=10) XORBytesUnaligned/128Bytes6Offset-4 219.0Mi ± 0% 961.1Mi ± 0% +338.86% (p=0.000 n=10) XORBytesUnaligned/128Bytes7Offset-4 218.9Mi ± 0% 951.1Mi ± 0% +334.52% (p=0.000 n=10) XORBytesUnaligned/2048Bytes0Offset-4 1.752Gi ± 0% 3.169Gi ± 0% +80.83% (p=0.000 n=10) XORBytesUnaligned/2048Bytes1Offset-4 236.9Mi ± 0% 2978.6Mi ± 0% +1157.10% (p=0.000 n=10) XORBytesUnaligned/2048Bytes2Offset-4 236.9Mi ± 0% 2972.1Mi ± 0% +1154.48% (p=0.000 n=10) XORBytesUnaligned/2048Bytes3Offset-4 236.8Mi ± 0% 2965.1Mi ± 0% +1152.05% (p=0.000 n=10) XORBytesUnaligned/2048Bytes4Offset-4 236.9Mi ± 0% 3005.9Mi ± 0% +1168.65% (p=0.000 n=10) XORBytesUnaligned/2048Bytes5Offset-4 236.8Mi ± 0% 3004.0Mi ± 0% +1168.42% (p=0.000 n=10) XORBytesUnaligned/2048Bytes6Offset-4 236.9Mi ± 0% 2997.2Mi ± 0% +1164.96% (p=0.000 n=10) XORBytesUnaligned/2048Bytes7Offset-4 236.9Mi ± 0% 2991.9Mi ± 0% +1162.93% (p=0.000 n=10) geomean 260.4Mi 806.7Mi +209.73% Change-Id: I9bec9c8f48df7284f8414ac745615c2a093e9ae9 Reviewed-on: https://go-review.googlesource.com/c/go/+/639858 Reviewed-by: Mark Ryan Reviewed-by: Cherry Mui Reviewed-by: Meng Zhuo TryBot-Bypass: Joel Sing Reviewed-by: Dmitri Shuralyov --- src/crypto/internal/fips140/subtle/xor_asm.go | 2 +- .../internal/fips140/subtle/xor_generic.go | 2 +- .../internal/fips140/subtle/xor_riscv64.s | 169 ++++++++++++++++++ 3 files changed, 171 insertions(+), 2 deletions(-) create mode 100644 src/crypto/internal/fips140/subtle/xor_riscv64.s diff --git a/src/crypto/internal/fips140/subtle/xor_asm.go b/src/crypto/internal/fips140/subtle/xor_asm.go index 16343db6588cb7..9a5da424aed9f2 100644 --- a/src/crypto/internal/fips140/subtle/xor_asm.go +++ b/src/crypto/internal/fips140/subtle/xor_asm.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build (amd64 || arm64 || loong64 || ppc64 || ppc64le) && !purego +//go:build (amd64 || arm64 || loong64 || ppc64 || ppc64le || riscv64) && !purego package subtle diff --git a/src/crypto/internal/fips140/subtle/xor_generic.go b/src/crypto/internal/fips140/subtle/xor_generic.go index e575c356960ae9..0b31eec60197d3 100644 --- a/src/crypto/internal/fips140/subtle/xor_generic.go +++ b/src/crypto/internal/fips140/subtle/xor_generic.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build (!amd64 && !arm64 && !loong64 && !ppc64 && !ppc64le) || purego +//go:build (!amd64 && !arm64 && !loong64 && !ppc64 && !ppc64le && !riscv64) || purego package subtle diff --git a/src/crypto/internal/fips140/subtle/xor_riscv64.s b/src/crypto/internal/fips140/subtle/xor_riscv64.s new file mode 100644 index 00000000000000..b5fa5dcef45e82 --- /dev/null +++ b/src/crypto/internal/fips140/subtle/xor_riscv64.s @@ -0,0 +1,169 @@ +// Copyright 2025 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. + +//go:build !purego + +#include "textflag.h" + +// func xorBytes(dst, a, b *byte, n int) +TEXT ·xorBytes(SB), NOSPLIT|NOFRAME, $0 + MOV dst+0(FP), X10 + MOV a+8(FP), X11 + MOV b+16(FP), X12 + MOV n+24(FP), X13 + + MOV $32, X15 + BLT X13, X15, loop4_check + + // Check alignment - if alignment differs we have to do one byte at a time. + AND $7, X10, X5 + AND $7, X11, X6 + AND $7, X12, X7 + BNE X5, X6, loop4_check + BNE X5, X7, loop4_check + BEQZ X5, loop64_check + + // Check one byte at a time until we reach 8 byte alignment. + MOV $8, X8 + SUB X5, X8 + SUB X8, X13 +align: + MOVBU 0(X11), X16 + MOVBU 0(X12), X17 + XOR X16, X17 + MOVB X17, 0(X10) + ADD $1, X10 + ADD $1, X11 + ADD $1, X12 + SUB $1, X8 + BNEZ X8, align + +loop64_check: + MOV $64, X15 + BLT X13, X15, tail32_check + PCALIGN $16 +loop64: + MOV 0(X11), X16 + MOV 0(X12), X17 + MOV 8(X11), X18 + MOV 8(X12), X19 + XOR X16, X17 + XOR X18, X19 + MOV X17, 0(X10) + MOV X19, 8(X10) + MOV 16(X11), X20 + MOV 16(X12), X21 + MOV 24(X11), X22 + MOV 24(X12), X23 + XOR X20, X21 + XOR X22, X23 + MOV X21, 16(X10) + MOV X23, 24(X10) + MOV 32(X11), X16 + MOV 32(X12), X17 + MOV 40(X11), X18 + MOV 40(X12), X19 + XOR X16, X17 + XOR X18, X19 + MOV X17, 32(X10) + MOV X19, 40(X10) + MOV 48(X11), X20 + MOV 48(X12), X21 + MOV 56(X11), X22 + MOV 56(X12), X23 + XOR X20, X21 + XOR X22, X23 + MOV X21, 48(X10) + MOV X23, 56(X10) + ADD $64, X10 + ADD $64, X11 + ADD $64, X12 + SUB $64, X13 + BGE X13, X15, loop64 + BEQZ X13, done + +tail32_check: + MOV $32, X15 + BLT X13, X15, tail16_check + MOV 0(X11), X16 + MOV 0(X12), X17 + MOV 8(X11), X18 + MOV 8(X12), X19 + XOR X16, X17 + XOR X18, X19 + MOV X17, 0(X10) + MOV X19, 8(X10) + MOV 16(X11), X20 + MOV 16(X12), X21 + MOV 24(X11), X22 + MOV 24(X12), X23 + XOR X20, X21 + XOR X22, X23 + MOV X21, 16(X10) + MOV X23, 24(X10) + ADD $32, X10 + ADD $32, X11 + ADD $32, X12 + SUB $32, X13 + BEQZ X13, done + +tail16_check: + MOV $16, X15 + BLT X13, X15, loop4_check + MOV 0(X11), X16 + MOV 0(X12), X17 + MOV 8(X11), X18 + MOV 8(X12), X19 + XOR X16, X17 + XOR X18, X19 + MOV X17, 0(X10) + MOV X19, 8(X10) + ADD $16, X10 + ADD $16, X11 + ADD $16, X12 + SUB $16, X13 + BEQZ X13, done + +loop4_check: + MOV $4, X15 + BLT X13, X15, loop1 + PCALIGN $16 +loop4: + MOVBU 0(X11), X16 + MOVBU 0(X12), X17 + MOVBU 1(X11), X18 + MOVBU 1(X12), X19 + XOR X16, X17 + XOR X18, X19 + MOVB X17, 0(X10) + MOVB X19, 1(X10) + MOVBU 2(X11), X20 + MOVBU 2(X12), X21 + MOVBU 3(X11), X22 + MOVBU 3(X12), X23 + XOR X20, X21 + XOR X22, X23 + MOVB X21, 2(X10) + MOVB X23, 3(X10) + ADD $4, X10 + ADD $4, X11 + ADD $4, X12 + SUB $4, X13 + BGE X13, X15, loop4 + + PCALIGN $16 +loop1: + BEQZ X13, done + MOVBU 0(X11), X16 + MOVBU 0(X12), X17 + XOR X16, X17 + MOVB X17, 0(X10) + ADD $1, X10 + ADD $1, X11 + ADD $1, X12 + SUB $1, X13 + JMP loop1 + +done: + RET From beac2f7d3b72ecaff146b98afb690489f0192422 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Fri, 14 Feb 2025 16:13:44 -0800 Subject: [PATCH 393/397] cmd/compile: fix sign extension of paired 32-bit loads on arm64 Fixes #71759 Change-Id: Iab05294ac933cc9972949158d3fe2bdc3073df5e Reviewed-on: https://go-review.googlesource.com/c/go/+/649895 LUCI-TryBot-Result: Go LUCI Reviewed-by: Cherry Mui Reviewed-by: Dmitri Shuralyov --- src/cmd/compile/internal/arm64/ssa.go | 2 +- src/cmd/compile/internal/ssa/_gen/ARM64Ops.go | 3 ++- src/cmd/compile/internal/ssa/opGen.go | 18 +++++++++++++++++ src/cmd/compile/internal/ssa/pair.go | 5 ++++- test/codegen/memcombine.go | 4 ++++ test/fixedbugs/issue71759.go | 20 +++++++++++++++++++ 6 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 test/fixedbugs/issue71759.go diff --git a/src/cmd/compile/internal/arm64/ssa.go b/src/cmd/compile/internal/arm64/ssa.go index 7bf8051bef5e7b..0f5c5a17bd5fa2 100644 --- a/src/cmd/compile/internal/arm64/ssa.go +++ b/src/cmd/compile/internal/arm64/ssa.go @@ -516,7 +516,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { ssagen.AddAux(&p.From, v) p.To.Type = obj.TYPE_REG p.To.Reg = v.Reg() - case ssa.OpARM64LDP, ssa.OpARM64LDPW, ssa.OpARM64FLDPD, ssa.OpARM64FLDPS: + case ssa.OpARM64LDP, ssa.OpARM64LDPW, ssa.OpARM64LDPSW, ssa.OpARM64FLDPD, ssa.OpARM64FLDPS: p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_MEM p.From.Reg = v.Args[0].Reg() diff --git a/src/cmd/compile/internal/ssa/_gen/ARM64Ops.go b/src/cmd/compile/internal/ssa/_gen/ARM64Ops.go index 4c4e610dba9413..53e6dbec3f159f 100644 --- a/src/cmd/compile/internal/ssa/_gen/ARM64Ops.go +++ b/src/cmd/compile/internal/ssa/_gen/ARM64Ops.go @@ -388,7 +388,8 @@ func init() { // arg1=mem // Returns the tuple . {name: "LDP", argLength: 2, reg: gpload2, aux: "SymOff", asm: "LDP", typ: "(UInt64,UInt64)", faultOnNilArg0: true, symEffect: "Read"}, // T=int64 (gp reg destination) - {name: "LDPW", argLength: 2, reg: gpload2, aux: "SymOff", asm: "LDPW", typ: "(UInt32,UInt32)", faultOnNilArg0: true, symEffect: "Read"}, // T=int32 (gp reg destination) ??? extension + {name: "LDPW", argLength: 2, reg: gpload2, aux: "SymOff", asm: "LDPW", typ: "(UInt32,UInt32)", faultOnNilArg0: true, symEffect: "Read"}, // T=int32 (gp reg destination) unsigned extension + {name: "LDPSW", argLength: 2, reg: gpload2, aux: "SymOff", asm: "LDPSW", typ: "(Int32,Int32)", faultOnNilArg0: true, symEffect: "Read"}, // T=int32 (gp reg destination) signed extension {name: "FLDPD", argLength: 2, reg: fpload2, aux: "SymOff", asm: "FLDPD", typ: "(Float64,Float64)", faultOnNilArg0: true, symEffect: "Read"}, // T=float64 (fp reg destination) {name: "FLDPS", argLength: 2, reg: fpload2, aux: "SymOff", asm: "FLDPS", typ: "(Float32,Float32)", faultOnNilArg0: true, symEffect: "Read"}, // T=float32 (fp reg destination) diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index 19a748eb08f548..718f4c93821dcf 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -1607,6 +1607,7 @@ const ( OpARM64FMOVDload OpARM64LDP OpARM64LDPW + OpARM64LDPSW OpARM64FLDPD OpARM64FLDPS OpARM64MOVDloadidx @@ -21664,6 +21665,23 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "LDPSW", + auxType: auxSymOff, + argLen: 2, + faultOnNilArg0: true, + symEffect: SymRead, + asm: arm64.ALDPSW, + reg: regInfo{ + inputs: []inputInfo{ + {0, 9223372038733561855}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB + }, + outputs: []outputInfo{ + {0, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 + {1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 + }, + }, + }, { name: "FLDPD", auxType: auxSymOff, diff --git a/src/cmd/compile/internal/ssa/pair.go b/src/cmd/compile/internal/ssa/pair.go index 5af9b0cb1b6d66..8e022df036e5b2 100644 --- a/src/cmd/compile/internal/ssa/pair.go +++ b/src/cmd/compile/internal/ssa/pair.go @@ -32,7 +32,10 @@ type pairableLoadInfo struct { // They must also take an offset in Aux/AuxInt. var pairableLoads = map[Op]pairableLoadInfo{ OpARM64MOVDload: {8, OpARM64LDP}, - OpARM64MOVWload: {4, OpARM64LDPW}, + OpARM64MOVWUload: {4, OpARM64LDPW}, + OpARM64MOVWload: {4, OpARM64LDPSW}, + // TODO: conceivably we could pair a signed and unsigned load + // if we knew the upper bits of one of them weren't being used. OpARM64FMOVDload: {8, OpARM64FLDPD}, OpARM64FMOVSload: {4, OpARM64FLDPS}, } diff --git a/test/codegen/memcombine.go b/test/codegen/memcombine.go index 9345391b61928f..c5744bf8d7f1a2 100644 --- a/test/codegen/memcombine.go +++ b/test/codegen/memcombine.go @@ -982,6 +982,10 @@ func dwloadI64(p *struct{ a, b int64 }) int64 { return p.a + p.b } func dwloadI32(p *struct{ a, b int32 }) int32 { + // arm64:"LDPSW\t" + return p.a + p.b +} +func dwloadU32(p *struct{ a, b uint32 }) uint32 { // arm64:"LDPW\t" return p.a + p.b } diff --git a/test/fixedbugs/issue71759.go b/test/fixedbugs/issue71759.go new file mode 100644 index 00000000000000..8134ff041b1505 --- /dev/null +++ b/test/fixedbugs/issue71759.go @@ -0,0 +1,20 @@ +// run + +// Copyright 2025 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +//go:noinline +func f(p *[2]int32) (int64, int64) { + return int64(p[0]), int64(p[1]) +} + +func main() { + p := [2]int32{-1, -1} + x, y := f(&p) + if x != -1 || y != -1 { + println(x, y) + } +} From 586e205522279406a9fcd2ab6cd1a1f416f1eae4 Mon Sep 17 00:00:00 2001 From: Alan Donovan Date: Wed, 12 Feb 2025 11:18:30 -0500 Subject: [PATCH 394/397] std: add //go:fix inline directives to some deprecated functions In particular, we apply it only to functions where it is always a code improvement to inline the call. We also apply it to some constants. In a few cases this may introduce a panic statement at the caller, which is debatable, but making the potential for panic evident is the purpose of the deprecation. The gofix analyzer in gopls v0.18 will show a diagnostic for calls to the annotated functions, and will offer to inline the call. The new //go:fix annotation needs a special exemption in the pragma check in the compiler. Updates #32816 Change-Id: I43bf15648ac12251734109eb7102394f8a76d55e Reviewed-on: https://go-review.googlesource.com/c/go/+/648995 Reviewed-by: Dmitri Shuralyov Commit-Queue: Alan Donovan Reviewed-by: Ian Lance Taylor Auto-Submit: Alan Donovan LUCI-TryBot-Result: Go LUCI --- src/cmd/compile/internal/noder/noder.go | 1 + src/go/importer/importer.go | 2 ++ src/go/types/signature.go | 2 ++ src/io/ioutil/ioutil.go | 8 ++++++++ src/io/ioutil/tempfile.go | 4 ++++ src/reflect/type.go | 4 ++++ 6 files changed, 21 insertions(+) diff --git a/src/cmd/compile/internal/noder/noder.go b/src/cmd/compile/internal/noder/noder.go index 7905c374c5e971..77daf9eda59085 100644 --- a/src/cmd/compile/internal/noder/noder.go +++ b/src/cmd/compile/internal/noder/noder.go @@ -162,6 +162,7 @@ var allowedStdPragmas = map[string]bool{ "go:cgo_ldflag": true, "go:cgo_dynamic_linker": true, "go:embed": true, + "go:fix": true, "go:generate": true, } diff --git a/src/go/importer/importer.go b/src/go/importer/importer.go index 54acd7e6940202..f0a1f651d2636c 100644 --- a/src/go/importer/importer.go +++ b/src/go/importer/importer.go @@ -80,6 +80,8 @@ func ForCompiler(fset *token.FileSet, compiler string, lookup Lookup) types.Impo // // Deprecated: Use [ForCompiler], which populates a FileSet // with the positions of objects created by the importer. +// +//go:fix inline func For(compiler string, lookup Lookup) types.Importer { return ForCompiler(token.NewFileSet(), compiler, lookup) } diff --git a/src/go/types/signature.go b/src/go/types/signature.go index 1738384febcc00..365b1119393dd2 100644 --- a/src/go/types/signature.go +++ b/src/go/types/signature.go @@ -38,6 +38,8 @@ type Signature struct { // must be of unnamed slice type. // // Deprecated: Use [NewSignatureType] instead which allows for type parameters. +// +//go:fix inline func NewSignature(recv *Var, params, results *Tuple, variadic bool) *Signature { return NewSignatureType(recv, nil, nil, params, results, variadic) } diff --git a/src/io/ioutil/ioutil.go b/src/io/ioutil/ioutil.go index af8ebe38501d4c..0ab4b5a0c333d9 100644 --- a/src/io/ioutil/ioutil.go +++ b/src/io/ioutil/ioutil.go @@ -24,6 +24,8 @@ import ( // as an error to be reported. // // Deprecated: As of Go 1.16, this function simply calls [io.ReadAll]. +// +//go:fix inline func ReadAll(r io.Reader) ([]byte, error) { return io.ReadAll(r) } @@ -34,6 +36,8 @@ func ReadAll(r io.Reader) ([]byte, error) { // to be reported. // // Deprecated: As of Go 1.16, this function simply calls [os.ReadFile]. +// +//go:fix inline func ReadFile(filename string) ([]byte, error) { return os.ReadFile(filename) } @@ -43,6 +47,8 @@ func ReadFile(filename string) ([]byte, error) { // (before umask); otherwise WriteFile truncates it before writing, without changing permissions. // // Deprecated: As of Go 1.16, this function simply calls [os.WriteFile]. +// +//go:fix inline func WriteFile(filename string, data []byte, perm fs.FileMode) error { return os.WriteFile(filename, data, perm) } @@ -87,6 +93,8 @@ func ReadDir(dirname string) ([]fs.FileInfo, error) { // the provided Reader r. // // Deprecated: As of Go 1.16, this function simply calls [io.NopCloser]. +// +//go:fix inline func NopCloser(r io.Reader) io.ReadCloser { return io.NopCloser(r) } diff --git a/src/io/ioutil/tempfile.go b/src/io/ioutil/tempfile.go index 47b2e4012f7622..ef2ce404d9ae8f 100644 --- a/src/io/ioutil/tempfile.go +++ b/src/io/ioutil/tempfile.go @@ -21,6 +21,8 @@ import ( // to remove the file when no longer needed. // // Deprecated: As of Go 1.17, this function simply calls [os.CreateTemp]. +// +//go:fix inline func TempFile(dir, pattern string) (f *os.File, err error) { return os.CreateTemp(dir, pattern) } @@ -36,6 +38,8 @@ func TempFile(dir, pattern string) (f *os.File, err error) { // to remove the directory when no longer needed. // // Deprecated: As of Go 1.17, this function simply calls [os.MkdirTemp]. +// +//go:fix inline func TempDir(dir, pattern string) (name string, err error) { return os.MkdirTemp(dir, pattern) } diff --git a/src/reflect/type.go b/src/reflect/type.go index e5ee7f90d0202c..b6fc99a9347cd4 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -301,6 +301,8 @@ const ( ) // Ptr is the old name for the [Pointer] kind. +// +//go:fix inline const Ptr = Pointer // uncommonType is present only for defined types or types with methods @@ -1323,6 +1325,8 @@ var ptrMap sync.Map // map[*rtype]*ptrType // The two functions behave identically. // // Deprecated: Superseded by [PointerTo]. +// +//go:fix inline func PtrTo(t Type) Type { return PointerTo(t) } // PointerTo returns the pointer type with element t. From b38415d7e9abad2a8255c6b527ab7a033851c5f2 Mon Sep 17 00:00:00 2001 From: Roland Shoemaker Date: Fri, 24 Jan 2025 12:27:08 -0800 Subject: [PATCH 395/397] crypto/internal/boring: remove unnecessary struct field That could result in a hanging pointer. Change-Id: I547950a3d3010e03b75f70f5f021f20124e2cef0 Reviewed-on: https://go-review.googlesource.com/c/go/+/644120 Auto-Submit: Roland Shoemaker Reviewed-by: Filippo Valsorda LUCI-TryBot-Result: Go LUCI Reviewed-by: Dmitri Shuralyov --- src/crypto/internal/boring/ecdh.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/crypto/internal/boring/ecdh.go b/src/crypto/internal/boring/ecdh.go index ff29eb17b11344..4a887fdfd67664 100644 --- a/src/crypto/internal/boring/ecdh.go +++ b/src/crypto/internal/boring/ecdh.go @@ -17,7 +17,6 @@ import ( type PublicKeyECDH struct { curve string key *C.GO_EC_POINT - group *C.GO_EC_GROUP bytes []byte } @@ -59,7 +58,7 @@ func NewPublicKeyECDH(curve string, bytes []byte) (*PublicKeyECDH, error) { return nil, errors.New("point not on curve") } - k := &PublicKeyECDH{curve, key, group, append([]byte(nil), bytes...)} + k := &PublicKeyECDH{curve, key, append([]byte(nil), bytes...)} // Note: Because of the finalizer, any time k.key is passed to cgo, // that call must be followed by a call to runtime.KeepAlive(k), // to make sure k is not collected (and finalized) before the cgo @@ -122,7 +121,7 @@ func (k *PrivateKeyECDH) PublicKey() (*PublicKeyECDH, error) { C._goboringcrypto_EC_POINT_free(pt) return nil, err } - pub := &PublicKeyECDH{k.curve, pt, group, bytes} + pub := &PublicKeyECDH{k.curve, pt, bytes} // Note: Same as in NewPublicKeyECDH regarding finalizer and KeepAlive. runtime.SetFinalizer(pub, (*PublicKeyECDH).finalize) return pub, nil From d5b75e40462c2b357df96de3083705d8ea4c8954 Mon Sep 17 00:00:00 2001 From: Artyom Litovets Date: Fri, 14 Feb 2025 12:03:06 +0000 Subject: [PATCH 396/397] runtime/maps: fix typo in group.go comment (H1 -> H2) Fixes a typo to correctly describe the hash bits of the control word. Change-Id: Id3c2ae0bd529e579a95258845f9d8028e23d10d2 GitHub-Last-Rev: 1baa81be5d292d5625d5d7788b8ea090453f962c GitHub-Pull-Request: golang/go#71730 Reviewed-on: https://go-review.googlesource.com/c/go/+/649416 Reviewed-by: Keith Randall Auto-Submit: Keith Randall Reviewed-by: Keith Randall LUCI-TryBot-Result: Go LUCI Reviewed-by: Ian Lance Taylor --- src/internal/runtime/maps/group.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/internal/runtime/maps/group.go b/src/internal/runtime/maps/group.go index f3e9d4d12b9b7e..6414ee5b9b03b9 100644 --- a/src/internal/runtime/maps/group.go +++ b/src/internal/runtime/maps/group.go @@ -111,7 +111,7 @@ func bitsetShiftOutLowest(b bitset) bitset { // // empty: 1 0 0 0 0 0 0 0 // deleted: 1 1 1 1 1 1 1 0 -// full: 0 h h h h h h h // h represents the H1 hash bits +// full: 0 h h h h h h h // h represents the H2 hash bits // // TODO(prattmic): Consider inverting the top bit so that the zero value is empty. type ctrl uint8 From d524e1eccd559b40130c3bac77f3f7dc33d476ab Mon Sep 17 00:00:00 2001 From: Jakub Ciolek Date: Fri, 3 Jan 2025 13:52:11 +0100 Subject: [PATCH 397/397] cmd/compile: on AMD64, turn x < 128 into x <= 127 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit x < 128 -> x <= 127 x >= 128 -> x > 127 This allows for shorter encoding as 127 fits into a single-byte immediate. archive/tar benchmark (Alder Lake 12600K) name old time/op new time/op delta /Writer/USTAR-16 1.46µs ± 0% 1.32µs ± 0% -9.43% (p=0.008 n=5+5) /Writer/GNU-16 1.85µs ± 1% 1.79µs ± 1% -3.47% (p=0.008 n=5+5) /Writer/PAX-16 3.21µs ± 0% 3.11µs ± 2% -2.96% (p=0.008 n=5+5) /Reader/USTAR-16 1.38µs ± 1% 1.37µs ± 0% ~ (p=0.127 n=5+4) /Reader/GNU-16 798ns ± 1% 800ns ± 2% ~ (p=0.548 n=5+5) /Reader/PAX-16 3.07µs ± 1% 3.00µs ± 0% -2.35% (p=0.008 n=5+5) [Geo mean] 1.76µs 1.70µs -3.15% compilecmp: hash/maphash hash/maphash.(*Hash).Write 517 -> 510 (-1.35%) runtime runtime.traceReadCPU 1626 -> 1615 (-0.68%) runtime [cmd/compile] runtime.traceReadCPU 1626 -> 1615 (-0.68%) math/rand/v2 type:.eq.[128]float32 65 -> 59 (-9.23%) bytes bytes.trimLeftUnicode 378 -> 373 (-1.32%) bytes.IndexAny 1189 -> 1157 (-2.69%) bytes.LastIndexAny 1256 -> 1239 (-1.35%) bytes.lastIndexFunc 263 -> 261 (-0.76%) strings strings.FieldsFuncSeq.func1 411 -> 399 (-2.92%) strings.EqualFold 625 -> 624 (-0.16%) strings.trimLeftUnicode 248 -> 231 (-6.85%) math/rand type:.eq.[128]float32 65 -> 59 (-9.23%) bytes [cmd/compile] bytes.LastIndexAny 1256 -> 1239 (-1.35%) bytes.lastIndexFunc 263 -> 261 (-0.76%) bytes.trimLeftUnicode 378 -> 373 (-1.32%) bytes.IndexAny 1189 -> 1157 (-2.69%) regexp/syntax regexp/syntax.(*parser).parseEscape 1113 -> 1102 (-0.99%) math/rand/v2 [cmd/compile] type:.eq.[128]float32 65 -> 59 (-9.23%) strings [cmd/compile] strings.EqualFold 625 -> 624 (-0.16%) strings.FieldsFuncSeq.func1 411 -> 399 (-2.92%) strings.trimLeftUnicode 248 -> 231 (-6.85%) math/rand [cmd/compile] type:.eq.[128]float32 65 -> 59 (-9.23%) regexp regexp.(*inputString).context 198 -> 197 (-0.51%) regexp.(*inputBytes).context 221 -> 212 (-4.07%) image/jpeg image/jpeg.(*decoder).processDQT 500 -> 491 (-1.80%) regexp/syntax [cmd/compile] regexp/syntax.(*parser).parseEscape 1113 -> 1102 (-0.99%) regexp [cmd/compile] regexp.(*inputString).context 198 -> 197 (-0.51%) regexp.(*inputBytes).context 221 -> 212 (-4.07%) encoding/csv encoding/csv.(*Writer).fieldNeedsQuotes 269 -> 266 (-1.12%) cmd/vendor/golang.org/x/sys/unix type:.eq.[131]struct 855 -> 823 (-3.74%) vendor/golang.org/x/text/unicode/norm vendor/golang.org/x/text/unicode/norm.nextDecomposed 4831 -> 4826 (-0.10%) vendor/golang.org/x/text/unicode/norm.(*Iter).returnSlice 281 -> 275 (-2.14%) vendor/golang.org/x/text/secure/bidirule vendor/golang.org/x/text/secure/bidirule.init.0 85 -> 83 (-2.35%) go/scanner go/scanner.isDigit 100 -> 98 (-2.00%) go/scanner.(*Scanner).next 431 -> 422 (-2.09%) go/scanner.isLetter 142 -> 124 (-12.68%) encoding/asn1 encoding/asn1.parseTagAndLength 1189 -> 1182 (-0.59%) encoding/asn1.makeField 3481 -> 3463 (-0.52%) text/scanner text/scanner.(*Scanner).next 1242 -> 1236 (-0.48%) archive/tar archive/tar.isASCII 133 -> 127 (-4.51%) archive/tar.(*Writer).writeRawFile 1206 -> 1198 (-0.66%) archive/tar.(*Reader).readHeader.func1 9 -> 7 (-22.22%) archive/tar.toASCII 393 -> 383 (-2.54%) archive/tar.splitUSTARPath 405 -> 396 (-2.22%) archive/tar.(*Writer).writePAXHeader.func1 627 -> 620 (-1.12%) text/template text/template.jsIsSpecial 59 -> 57 (-3.39%) go/doc go/doc.assumedPackageName 714 -> 701 (-1.82%) vendor/golang.org/x/net/http/httpguts vendor/golang.org/x/net/http/httpguts.headerValueContainsToken 965 -> 952 (-1.35%) vendor/golang.org/x/net/http/httpguts.tokenEqual 280 -> 269 (-3.93%) vendor/golang.org/x/net/http/httpguts.IsTokenRune 28 -> 26 (-7.14%) net/mail net/mail.isVchar 26 -> 24 (-7.69%) net/mail.isAtext 106 -> 104 (-1.89%) net/mail.(*Address).String 1084 -> 1052 (-2.95%) net/mail.isQtext 39 -> 37 (-5.13%) net/mail.isMultibyte 9 -> 7 (-22.22%) net/mail.isDtext 45 -> 43 (-4.44%) net/mail.(*addrParser).consumeQuotedString 1050 -> 1029 (-2.00%) net/mail.quoteString 741 -> 714 (-3.64%) cmd/internal/obj/s390x cmd/internal/obj/s390x.preprocess 6405 -> 6393 (-0.19%) cmd/internal/obj/x86 cmd/internal/obj/x86.toDisp8 303 -> 301 (-0.66%) fmt [cmd/compile] fmt.Fprintf 4726 -> 4662 (-1.35%) go/scanner [cmd/compile] go/scanner.(*Scanner).next 431 -> 422 (-2.09%) go/scanner.isLetter 142 -> 124 (-12.68%) go/scanner.isDigit 100 -> 98 (-2.00%) cmd/compile/internal/syntax cmd/compile/internal/syntax.(*source).nextch 879 -> 847 (-3.64%) cmd/vendor/golang.org/x/mod/module cmd/vendor/golang.org/x/mod/module.checkElem 1253 -> 1235 (-1.44%) cmd/vendor/golang.org/x/mod/module.escapeString 519 -> 517 (-0.39%) go/doc [cmd/compile] go/doc.assumedPackageName 714 -> 701 (-1.82%) cmd/compile/internal/syntax [cmd/compile] cmd/compile/internal/syntax.(*scanner).escape 1965 -> 1933 (-1.63%) cmd/compile/internal/syntax.(*scanner).next 8975 -> 8847 (-1.43%) cmd/internal/obj/s390x [cmd/compile] cmd/internal/obj/s390x.preprocess 6405 -> 6393 (-0.19%) cmd/internal/obj/x86 [cmd/compile] cmd/internal/obj/x86.toDisp8 303 -> 301 (-0.66%) cmd/internal/gcprog cmd/internal/gcprog.(*Writer).Repeat 688 -> 677 (-1.60%) cmd/internal/gcprog.(*Writer).varint 442 -> 439 (-0.68%) cmd/compile/internal/ir cmd/compile/internal/ir.splitPkg 331 -> 325 (-1.81%) cmd/compile/internal/ir [cmd/compile] cmd/compile/internal/ir.splitPkg 331 -> 325 (-1.81%) net/http net/http.containsDotDot.FieldsFuncSeq.func1 411 -> 399 (-2.92%) net/http.isNotToken 33 -> 30 (-9.09%) net/http.containsDotDot 606 -> 588 (-2.97%) net/http.isCookieNameValid 197 -> 191 (-3.05%) net/http.parsePattern 4330 -> 4317 (-0.30%) net/http.ParseCookie 1099 -> 1096 (-0.27%) net/http.validMethod 197 -> 187 (-5.08%) cmd/vendor/golang.org/x/text/unicode/norm cmd/vendor/golang.org/x/text/unicode/norm.(*Iter).returnSlice 281 -> 275 (-2.14%) cmd/vendor/golang.org/x/text/unicode/norm.nextDecomposed 4831 -> 4826 (-0.10%) net/http/cookiejar net/http/cookiejar.encode 1936 -> 1918 (-0.93%) expvar expvar.appendJSONQuote 972 -> 965 (-0.72%) cmd/cgo/internal/test cmd/cgo/internal/test.stack128 116 -> 114 (-1.72%) cmd/vendor/rsc.io/markdown cmd/vendor/rsc.io/markdown.newATXHeading 1637 -> 1628 (-0.55%) cmd/vendor/rsc.io/markdown.isUnicodePunct 197 -> 179 (-9.14%) Change-Id: I578bdf42ef229d687d526e378d697ced51e1880c Reviewed-on: https://go-review.googlesource.com/c/go/+/639935 LUCI-TryBot-Result: Go LUCI Reviewed-by: Keith Randall Reviewed-by: Cherry Mui Reviewed-by: Keith Randall --- src/cmd/compile/internal/ssa/_gen/AMD64.rules | 15 + src/cmd/compile/internal/ssa/rewriteAMD64.go | 399 ++++++++++++++++++ test/codegen/comparisons.go | 48 +++ 3 files changed, 462 insertions(+) diff --git a/src/cmd/compile/internal/ssa/_gen/AMD64.rules b/src/cmd/compile/internal/ssa/_gen/AMD64.rules index 9177067e522206..e590b41d5f5a2d 100644 --- a/src/cmd/compile/internal/ssa/_gen/AMD64.rules +++ b/src/cmd/compile/internal/ssa/_gen/AMD64.rules @@ -628,6 +628,21 @@ // x & 1 == 0 -> (x & 1) ^ 1 (SETAE (BT(L|Q)const [0] x)) => (XORLconst [1] (ANDLconst [1] x)) +// Shorten compare by rewriting x < 128 as x <= 127, which can be encoded in a single-byte immediate on x86. +(SETL c:(CMP(Q|L)const [128] x)) && c.Uses == 1 => (SETLE (CMP(Q|L)const [127] x)) +(SETB c:(CMP(Q|L)const [128] x)) && c.Uses == 1 => (SETBE (CMP(Q|L)const [127] x)) + +// x >= 128 -> x > 127 +(SETGE c:(CMP(Q|L)const [128] x)) && c.Uses == 1 => (SETG (CMP(Q|L)const [127] x)) +(SETAE c:(CMP(Q|L)const [128] x)) && c.Uses == 1 => (SETA (CMP(Q|L)const [127] x)) + +(CMOVQLT x y c:(CMP(Q|L)const [128] z)) && c.Uses == 1 => (CMOVQLE x y (CMP(Q|L)const [127] z)) +(CMOVLLT x y c:(CMP(Q|L)const [128] z)) && c.Uses == 1 => (CMOVLLE x y (CMP(Q|L)const [127] z)) +(LT c:(CMP(Q|L)const [128] z) yes no) && c.Uses == 1 => (LE (CMP(Q|L)const [127] z) yes no) +(CMOVQGE x y c:(CMP(Q|L)const [128] z)) && c.Uses == 1 => (CMOVQGT x y (CMP(Q|L)const [127] z)) +(CMOVLGE x y c:(CMP(Q|L)const [128] z)) && c.Uses == 1 => (CMOVLGT x y (CMP(Q|L)const [127] z)) +(GE c:(CMP(Q|L)const [128] z) yes no) && c.Uses == 1 => (GT (CMP(Q|L)const [127] z) yes no) + // Recognize bit tests: a&(1<= 128 +} + +func ge128Unsigned64(x uint64) bool { + // amd64:`CMPQ.*127` + // amd64:`SETHI` + return x >= 128 +} + +func ge128Signed32(x int32) bool { + // amd64:`CMPL.*127` + // amd64:`SETGT` + return x >= 128 +} + +func ge128Signed64(x int64) bool { + // amd64:`CMPQ.*127` + // amd64:`SETGT` + return x >= 128 +} + func cmpToCmnGreaterThanEqual(a, b, c, d int) int { var c1, c2, c3, c4 int // arm64:`CMN`,`CSET\tPL`,-`CMP`