From 78f63eb7909969a7ee7fbe1b2bbcec678f0e20b4 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Wed, 20 May 2026 17:03:35 +0200 Subject: [PATCH 1/5] crypto/internal/cryptotest/wycheproof: avoid reading go.sum at test time Change-Id: I63cdd2bcb855be6f799aa5ddf461b1dd6a6a6964 Reviewed-on: https://go-review.googlesource.com/c/go/+/780481 Reviewed-by: Roland Shoemaker Reviewed-by: Dmitri Shuralyov Auto-Submit: Filippo Valsorda LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com --- .../wycheproof/_schema/schema_gen.go | 60 +++++++++++++++++++ .../cryptotest/wycheproof/schemaversion.go | 11 ++++ .../cryptotest/wycheproof/wycheproof.go | 46 ++------------ 3 files changed, 75 insertions(+), 42 deletions(-) create mode 100644 src/crypto/internal/cryptotest/wycheproof/schemaversion.go diff --git a/src/crypto/internal/cryptotest/wycheproof/_schema/schema_gen.go b/src/crypto/internal/cryptotest/wycheproof/_schema/schema_gen.go index 5ad885fb8b72dc..e9d26ed262e023 100644 --- a/src/crypto/internal/cryptotest/wycheproof/_schema/schema_gen.go +++ b/src/crypto/internal/cryptotest/wycheproof/_schema/schema_gen.go @@ -12,10 +12,13 @@ package main import ( + "bufio" + "fmt" "io/fs" "log" "os" "path/filepath" + "strings" "github.com/atombender/go-jsonschema/pkg/generator" "github.com/c2sp/wycheproof" @@ -88,4 +91,61 @@ func main() { if err := os.WriteFile(outFile, content, 0644); err != nil { log.Fatalf("error writing file %s: %v\n", outFile, err) } + + // Write a sibling file recording the Wycheproof module version that the + // generated schema.go was produced against. The wycheproof package uses + // this constant to fetch matching test vectors at runtime. We avoid reading + // go.sum at test time because it might not be available (e.g. if the test + // binary was copied to a remote machine). + version, err := wycheproofVersionFromSum("go.sum") + if err != nil { + log.Fatalf("extracting wycheproof version: %v", err) + } + const versionFile = "../schemaversion.go" + versionSrc := fmt.Sprintf(`// Copyright 2026 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 generated by _schema/schema_gen.go, DO NOT EDIT. + +package wycheproof + +// wycheproofVersion is the github.com/c2sp/wycheproof module version that +// schema.go was generated against. +const wycheproofVersion = %q +`, version) + if err := os.WriteFile(versionFile, []byte(versionSrc), 0644); err != nil { + log.Fatalf("writing %s: %v", versionFile, err) + } +} + +// wycheproofVersionFromSum returns the github.com/c2sp/wycheproof module +// version recorded in the given go.sum file. +func wycheproofVersionFromSum(path string) (string, error) { + f, err := os.Open(path) + if err != nil { + return "", err + } + defer f.Close() + + var version string + found := 0 + scanner := bufio.NewScanner(f) + for scanner.Scan() { + fields := strings.Fields(scanner.Text()) + if len(fields) == 3 && fields[0] == "github.com/c2sp/wycheproof" { + version = strings.TrimSuffix(fields[1], "/go.mod") + found++ + } + } + if err := scanner.Err(); err != nil { + return "", err + } + switch { + case found == 0: + return "", fmt.Errorf("%s: missing github.com/c2sp/wycheproof entry", path) + case found > 2: + return "", fmt.Errorf("%s: %d github.com/c2sp/wycheproof entries (run 'go mod tidy')", path, found) + } + return version, nil } diff --git a/src/crypto/internal/cryptotest/wycheproof/schemaversion.go b/src/crypto/internal/cryptotest/wycheproof/schemaversion.go new file mode 100644 index 00000000000000..12088f043a228a --- /dev/null +++ b/src/crypto/internal/cryptotest/wycheproof/schemaversion.go @@ -0,0 +1,11 @@ +// Copyright 2026 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 generated by _schema/schema_gen.go, DO NOT EDIT. + +package wycheproof + +// wycheproofVersion is the github.com/c2sp/wycheproof module version that +// schema.go was generated against. +const wycheproofVersion = "v0.0.0-20260428174413-4d535535851f" diff --git a/src/crypto/internal/cryptotest/wycheproof/wycheproof.go b/src/crypto/internal/cryptotest/wycheproof/wycheproof.go index 93b83806a6986f..e75c91f13d0f76 100644 --- a/src/crypto/internal/cryptotest/wycheproof/wycheproof.go +++ b/src/crypto/internal/cryptotest/wycheproof/wycheproof.go @@ -8,7 +8,6 @@ package wycheproof import ( - "bufio" "crypto" "crypto/internal/cryptotest" "encoding/hex" @@ -18,7 +17,6 @@ import ( "os" "path" "reflect" - "strings" "testing" ) @@ -34,9 +32,11 @@ func LoadVectorFile(t *testing.T, filename string, value any) { // We want to avoid a dependency on c2sp/wycheproof or the schema generator // in this stdlib code, so we fetch the module at runtime and read the - // vector JSON from that module clone. + // vector JSON from that module clone. The version is pinned to whatever + // the _schema generator was last run against (see schemaversion.go), so + // the vectors match the generated schema.go. wycheproofDir := cryptotest.FetchModule( - t, "github.com/c2sp/wycheproof", findVersionFromSum(t)) + t, "github.com/c2sp/wycheproof", wycheproofVersion) content, err := os.ReadFile(path.Join(wycheproofDir, "testvectors_v1", filename)) if err != nil { @@ -49,44 +49,6 @@ func LoadVectorFile(t *testing.T, filename string, value any) { } } -// To make sure this code fetches the same module version as we used to -// generate the vendored schema.go we parse the _schema Go module's -// go.sum to find the Wycheproof version used. -func findVersionFromSum(t *testing.T) string { - testenv.MustHaveSource(t) - - goSumPath := path.Join( - testenv.GOROOT(t), - "src/crypto/internal/cryptotest/wycheproof/_schema/go.sum") - f, err := os.Open(goSumPath) - if err != nil { - t.Fatalf("_schema module go.sum read failed: %v", err) - } - defer f.Close() - - var version string - found := 0 - scanner := bufio.NewScanner(f) - for scanner.Scan() { - fields := strings.Fields(scanner.Text()) - if len(fields) == 3 && fields[0] == "github.com/c2sp/wycheproof" { - version = strings.TrimSuffix(fields[1], "/go.mod") - found++ - } - } - - // We expect 2 entries for a tidied sum file. - if found > 2 { - t.Fatalf( - "_schema module requires 'go tidy' - found %d wycheproof occurrences in go.sum", - found) - } else if found == 0 { - t.Fatal("_schema module go.sum missing wycheproof dependency") - } - - return version -} - // ShouldPass returns true if a test should pass informed by expected result // and flags. // From 5a1c0ee6de2dab64a6e55d83ec092d81adbcccb4 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 20 May 2026 15:02:43 -0700 Subject: [PATCH 2/5] test/fixedbugs: minor adjustments to line-directive specific tests Mostly an attempt at understanding the new compiler behavior. Also, replace some deprecated ioutil calls with os calls. Follow-up on CL 706795. Change-Id: Ia626cc44a4188674bb8f21bf9a0c207c6b1a10b1 Reviewed-on: https://go-review.googlesource.com/c/go/+/779983 Reviewed-by: Robert Griesemer Auto-Submit: Robert Griesemer Reviewed-by: Neal Patel LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com --- test/fixedbugs/issue18149.go | 6 +++--- test/fixedbugs/issue22660.go | 27 +++++++++++++-------------- test/fixedbugs/issue22662.go | 2 +- test/fixedbugs/issue22662b.go | 5 ++--- 4 files changed, 19 insertions(+), 21 deletions(-) diff --git a/test/fixedbugs/issue18149.go b/test/fixedbugs/issue18149.go index 4b6eea6fd0998e..d8b3de86802c8b 100644 --- a/test/fixedbugs/issue18149.go +++ b/test/fixedbugs/issue18149.go @@ -17,7 +17,7 @@ import ( ) // Since go.dev/issue/70478, the compiler resolves a relative filename in a -// //line directive against the directory of the source file, so the expected +// line directive against the directory of the source file, so the expected // path may be a suffix of the actual filename rather than equal to it. // Accept either an exact match or the file as a path-component suffix. // Compiler-emitted paths are always slash-normalized (cmd/internal/objabi.AbsFile). @@ -36,7 +36,7 @@ func check(file string, line int) { func main() { //line /foo/bar.go:123 - check(`/foo/bar.go`, 123) + check("/foo/bar.go", 123) //line c:/foo/bar.go:987 - check(`c:/foo/bar.go`, 987) + check("c:/foo/bar.go", 987) } diff --git a/test/fixedbugs/issue22660.go b/test/fixedbugs/issue22660.go index 1d89805e9efb6d..3e495a29c44798 100644 --- a/test/fixedbugs/issue22660.go +++ b/test/fixedbugs/issue22660.go @@ -11,7 +11,6 @@ package main import ( "bytes" "fmt" - "io/ioutil" "log" "os" "os/exec" @@ -20,33 +19,33 @@ import ( ) func main() { - f, err := ioutil.TempFile("", "issue22660.go") + f, err := os.CreateTemp("", "issue22660.go") if err != nil { log.Fatal(err) } f.Close() defer os.Remove(f.Name()) - // path components from the //line directive must survive -trimpath and - // appear in error messages (since go.dev/issue/70478, as a path-component - // suffix of the resolved path, not as the bare prefix). + // path must appear in error messages even if we strip them with -trimpath path := filepath.Join("users", "xxx", "go") + filename := filepath.Join(path, "foo.go") var src bytes.Buffer - fmt.Fprintf(&src, "//line %s:1\n", filepath.Join(path, "foo.go")) - - if err := ioutil.WriteFile(f.Name(), src.Bytes(), 0660); err != nil { + fmt.Fprintf(&src, "//line %s:1\n", filename) + if err := os.WriteFile(f.Name(), src.Bytes(), 0660); err != nil { log.Fatal(err) } out, err := exec.Command("go", "tool", "compile", "-p=p", fmt.Sprintf("-trimpath=%s", path), f.Name()).CombinedOutput() if err == nil { - log.Fatalf("expected compiling %s to fail", f.Name()) + // The file only contains a line directive, w/o a package clause. + log.Fatalf("expected compiling %s to fail with syntax error", f.Name()) } - // After #70478 the resolved path is /users/xxx/go/foo.go, - // so the directive's components must appear as a path suffix. - want := filepath.Join(path, "foo.go") - if !strings.Contains(string(out), string(filepath.Separator)+want) { - log.Fatalf("expected path component (%s) in error message, got:\n%s", want, out) + // The error message position depends on the line directive. + // The resolved path is /filename, so the directive's components + // must appear as a path suffix in the error message's error position + // (go.dev/issue/70478). + if !strings.Contains(string(out), string(filepath.Separator)+filename) { + log.Fatalf("expected full path and filename (%s) in error message, got:\n%s", filename, out) } } diff --git a/test/fixedbugs/issue22662.go b/test/fixedbugs/issue22662.go index 16e8abfa0e0d02..d732485424f79c 100644 --- a/test/fixedbugs/issue22662.go +++ b/test/fixedbugs/issue22662.go @@ -16,7 +16,7 @@ import ( ) // Since go.dev/issue/70478, the compiler resolves a relative filename in a -// //line directive against the directory of the source file, so the expected +// line directive against the directory of the source file, so the expected // path may be a suffix of the actual filename rather than equal to it. // Accept either an exact match or the file as a path-component suffix. // Compiler-emitted paths are always slash-normalized (cmd/internal/objabi.AbsFile). diff --git a/test/fixedbugs/issue22662b.go b/test/fixedbugs/issue22662b.go index 15c28ec95ece59..eca486d451b217 100644 --- a/test/fixedbugs/issue22662b.go +++ b/test/fixedbugs/issue22662b.go @@ -11,7 +11,6 @@ package main import ( - "io/ioutil" "log" "os" "os/exec" @@ -38,7 +37,7 @@ var tests = []struct { } func main() { - f, err := ioutil.TempFile("", "issue22662b.go") + f, err := os.CreateTemp("", "issue22662b.go") if err != nil { log.Fatal(err) } @@ -46,7 +45,7 @@ func main() { defer os.Remove(f.Name()) for _, test := range tests { - if err := ioutil.WriteFile(f.Name(), []byte(test.src), 0660); err != nil { + if err := os.WriteFile(f.Name(), []byte(test.src), 0660); err != nil { log.Fatal(err) } From dd1da37fa4d53bcebb82e8aa8c667dd9a82ae47d Mon Sep 17 00:00:00 2001 From: Michael Matloob Date: Wed, 20 May 2026 15:08:23 -0400 Subject: [PATCH 3/5] runtime: always call slowpath for heap bits in span This allows us to avoid calling mallocgcSmallScanNoHeader when sizespecializedmalloc is enabled, reducing binary size. Change-Id: I16b98bac06eccd42b3c146f3b829aae96a6a6964 Reviewed-on: https://go-review.googlesource.com/c/go/+/780700 Auto-Submit: Michael Matloob Reviewed-by: Michael Pratt Reviewed-by: Michael Matloob LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com --- src/runtime/malloc.go | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index 8c5ec383f7b2f8..c13a9a6cc6a9bc 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -1076,17 +1076,29 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer { return unsafe.Pointer(&zerobase) } - if sizeSpecializedMallocEnabled && size < uintptr(len(mallocNoScanTable)) { - if typ == nil || !typ.Pointers() { - if size >= maxTinySize { - return mallocNoScanTable[size](size, typ, needzero) + if sizeSpecializedMallocEnabled { + if size < uintptr(len(mallocNoScanTable)) { + if typ == nil || !typ.Pointers() { + if size >= maxTinySize { + return mallocNoScanTable[size](size, typ, needzero) + } + return mallocgcTinySC2(size, typ, needzero) + } else { + if !needzero { + throw("objects with pointers must be zeroed") + } + return mallocScanTable[size](size, typ, needzero) } - return mallocgcTinySC2(size, typ, needzero) - } else { - if !needzero { - throw("objects with pointers must be zeroed") + } + if heapBitsInSpan(size) { + noscan := typ == nil || !typ.Pointers() + sc := gc.SizeToSizeClass8[divRoundUp(size, gc.SmallSizeDiv)] + elemsize := uintptr(gc.SizeClassToSize[sc]) + spc := makeSpanClass(sc, noscan) + if noscan { + return mallocgcSmallNoScanSlowPath(size, typ, needzero, spc, elemsize) } - return mallocScanTable[size](size, typ, needzero) + return mallocgcSmallScanSlowPath(size, typ, needzero, spc, elemsize) } } @@ -1127,11 +1139,7 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer { if !needzero { throw("objects with pointers must be zeroed") } - if heapBitsInSpan(size) { - x, elemsize = mallocgcSmallScanNoHeader(size, typ) - } else { - x, elemsize = mallocgcSmallScanHeader(size, typ) - } + x, elemsize = mallocgcSmallScanHeader(size, typ) } } else { x, elemsize = mallocgcLarge(size, typ, needzero) From e2c188568d47c07990cc70f2fab2973c2a6838e3 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Tue, 19 May 2026 22:31:50 -0400 Subject: [PATCH 4/5] cmd/compile: compute embedded field offset in static initialization Currently, when static initializes a variable with a struct literal, the compiler uses the field's offset in its containing struct. This is usually correct, except that with the newly- allowed direct access of embedded field, the offset does not include the offset of the embedded type in its containing type. We need to include all the implicit field offsets in the offset calculation. For #9859. Change-Id: Ifa4fae77383d912fba2638538248b06a3c286373 Reviewed-on: https://go-review.googlesource.com/c/go/+/780220 LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/staticinit/sched.go | 2 +- src/cmd/compile/internal/typecheck/subr.go | 18 ++++++++++++++++++ test/complit2.go | 4 ++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/staticinit/sched.go b/src/cmd/compile/internal/staticinit/sched.go index 62331392a58d81..42a2276414177e 100644 --- a/src/cmd/compile/internal/staticinit/sched.go +++ b/src/cmd/compile/internal/staticinit/sched.go @@ -546,7 +546,7 @@ func (s *Schedule) initplan(n ir.Node) { if a.Sym().IsBlank() { continue } - s.addvalue(p, a.Field.Offset, a.Value) + s.addvalue(p, typecheck.FieldOffset(n.Type(), a.Field), a.Value) } case ir.OMAPLIT: diff --git a/src/cmd/compile/internal/typecheck/subr.go b/src/cmd/compile/internal/typecheck/subr.go index 3b22d260bf4faf..27943f2902c85c 100644 --- a/src/cmd/compile/internal/typecheck/subr.go +++ b/src/cmd/compile/internal/typecheck/subr.go @@ -790,3 +790,21 @@ var slist []symlink type symlink struct { field *types.Field } + +// FieldOffset returns the offset of field f in t, +// including any implicit offsets from embedded fields. +func FieldOffset(t *types.Type, f *types.Field) int64 { + if f.Sym == nil { + return f.Offset + } + path, ambig := dotpath(f.Sym, t, nil, false) + if path == nil || ambig { + return f.Offset + } + var offset int64 + for _, d := range path { + offset += d.field.Offset + } + offset += f.Offset + return offset +} diff --git a/test/complit2.go b/test/complit2.go index 43b23c023d0cba..bc1d915d171415 100644 --- a/test/complit2.go +++ b/test/complit2.go @@ -28,6 +28,7 @@ type C struct { func main() { eq(A{1, B{b: "foo"}}, A{a: 1, b: "foo"}) eq(A{B: B{C: C{c: "foo"}}}, A{c: "foo"}) + eq(x, A{B: B{b: "foo"}}) } func eq(x, y any) { @@ -35,3 +36,6 @@ func eq(x, y any) { panic(fmt.Sprintf("%v != %v", x, y)) } } + +// test global initializer +var x = A{b: "foo"} From 04ed01963e1b2ec2f801416988cb7d57b7e13b36 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Wed, 20 May 2026 22:23:26 -0400 Subject: [PATCH 5/5] runtime/trace: remove unused runtime_readTrace declaration runtime_readTrace is not used anywhere. And the linknamed target does not exist in the runtime package. Remove. Change-Id: I108d556facfefe6c7a59c37c039b3f2f8bcdb5b7 Reviewed-on: https://go-review.googlesource.com/c/go/+/780921 LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: David Chase --- src/runtime/trace/subscribe.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/runtime/trace/subscribe.go b/src/runtime/trace/subscribe.go index a4d653dcaece92..90a7eac070ecf4 100644 --- a/src/runtime/trace/subscribe.go +++ b/src/runtime/trace/subscribe.go @@ -199,6 +199,3 @@ func (t *traceMultiplexer) startLocked() error { t.enabled.Store(true) return nil } - -//go:linkname runtime_readTrace -func runtime_readTrace() (buf []byte)