From 3c62677c5e3eb69916590f7b09cd052d38317fb5 Mon Sep 17 00:00:00 2001 From: Davis Goodin Date: Fri, 9 Jan 2026 13:07:14 -0800 Subject: [PATCH 1/7] Add Microsoft version information --- eng/_util/cmd/build/build.go | 15 + ...13-Add-Microsoft-version-information.patch | 311 ++++++++++++++++++ 2 files changed, 326 insertions(+) create mode 100644 patches/0013-Add-Microsoft-version-information.patch diff --git a/eng/_util/cmd/build/build.go b/eng/_util/cmd/build/build.go index 6f4ff35361..7f75ea041f 100644 --- a/eng/_util/cmd/build/build.go +++ b/eng/_util/cmd/build/build.go @@ -279,6 +279,21 @@ func build(o *options) (err error) { } else { version, _, _ = strings.Cut(string(data), "\n") } + // We also need to copy our MICROSOFT_REVISION file in so the toolset can report that it's a + // Microsoft build of a specific revision and embed that info into built binaries. + microsoftRevisionSrc := filepath.Join(rootDir, "MICROSOFT_REVISION") + microsoftRevisionDst := filepath.Join(goRootDir, "MICROSOFT_REVISION") + if err := copyFile(microsoftRevisionDst, microsoftRevisionSrc); err != nil { + if !errors.Is(err, os.ErrNotExist) { + return fmt.Errorf("unable to pack: failed to read MICROSOFT_REVISION file for unexpected reason: %v", err) + } + // Ok: a main branch build won't have a MICROSOFT_REVISION file. + } else { + // Best effort: clean up the MICROSOFT_REVISION file when we're done. This is just for + // dev workflows: the temp MICROSOFT_REVISION file should never be checked in. + defer os.Remove(microsoftRevisionDst) + } + cmd := exec.Command(filepath.Join(goRootDir, "bin", "go"+executableExtension), "tool", "distpack") cmd.Env = append(os.Environ(), "GOROOT="+goRootDir) cmd.Stdout = os.Stdout diff --git a/patches/0013-Add-Microsoft-version-information.patch b/patches/0013-Add-Microsoft-version-information.patch new file mode 100644 index 0000000000..0fd78afb6d --- /dev/null +++ b/patches/0013-Add-Microsoft-version-information.patch @@ -0,0 +1,311 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: bot-for-go[bot] <199222863+bot-for-go[bot]@users.noreply.github.com> +Date: Tue, 13 Jan 2026 11:21:36 -0800 +Subject: [PATCH] Add Microsoft version information + +Embed a Microsoft marker and the current revision into built Go binaries, +including the Go toolset itself. This makes it easy to identify the Microsoft +build of Go toolset through "go version", and if a binary was built by the +Microsoft build of Go through "go version [...] ". + +Including revision means that it is also possible to determine whether +Microsoft-specific fixes have been applied to a given Go binary built by this +toolset. + +Includes compatibility opt out features: "ms_version=0" GODEBUG option to change runtime.Version() behavior, and +"-ms_embedupstreamversion" ld option if compatibility with external inspection is the concern. +--- + doc/godebug.md | 7 ++++ + src/cmd/dist/build.go | 16 +++++++++ + src/cmd/dist/buildruntime.go | 1 + + src/cmd/go/internal/cache/hash.go | 17 +++++---- + src/cmd/link/internal/ld/main.go | 32 ++++++----------- + src/internal/buildcfg/cfg.go | 58 ++++++++++++++++++++++++++++++- + src/internal/godebugs/table.go | 1 + + src/runtime/extern.go | 10 ++++++ + src/runtime/runtime1.go | 4 +++ + 9 files changed, 118 insertions(+), 28 deletions(-) + +diff --git a/doc/godebug.md b/doc/godebug.md +index 4c95ceb09bcbbe..001304ac49cebb 100644 +--- a/doc/godebug.md ++++ b/doc/godebug.md +@@ -192,6 +192,13 @@ Microsoft build of Go 1.26 added a new `ms_tlsprofile` setting that controls the + - "default": use the recommended Microsoft TLS settings. This is the default. + - "off": use the default upstream Go TLS settings. + ++Microsoft build of Go 1.26 added a new `ms_version` setting. It controls whether ++the Go runtime uses a Microsoft-specific version string in the output of ++`runtime.Version()`. This in turn affects the output of `go version`. ++The possible values are: ++- "0": `runtime.Version()` returns the upstream version string, for example: "go1.26.0". ++- "1" (default): `runtime.Version()` returns the Microsoft build of Go version string, for example: "go1.26.0-1_microsoft". ++ + ### Go 1.25 + + Go 1.25 added a new `decoratemappings` setting that controls whether the Go +diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go +index 917f682fd4bfaf..85512e38220de6 100644 +--- a/src/cmd/dist/build.go ++++ b/src/cmd/dist/build.go +@@ -450,6 +450,22 @@ func findgoversion() string { + return version + } + ++// findmsgorevision returns the Microsoft-specific Go revision string from ++// MICROSOFT_REVISION, or empty string if the file doesn't exist. ++// ++// Enforces that the file content is a valid integer. ++func findmsgorevision() string { ++ path := pathf("%s/MICROSOFT_REVISION", goroot) ++ if isfile(path) { ++ r := chomp(readfile(path)) ++ if _, err := strconv.Atoi(r); err != nil { ++ fatalf("MICROSOFT_REVISION content is not an integer: %q", r) ++ } ++ return r ++ } ++ return "" ++} ++ + // goModVersion returns the go version declared in src/go.mod. This is the + // go version to use in the go.mod building go_bootstrap, toolchain2, and toolchain3. + // (toolchain1 must be built with requiredBootstrapVersion(goModVersion)) +diff --git a/src/cmd/dist/buildruntime.go b/src/cmd/dist/buildruntime.go +index 87e88671763996..dccdca982300d7 100644 +--- a/src/cmd/dist/buildruntime.go ++++ b/src/cmd/dist/buildruntime.go +@@ -64,6 +64,7 @@ func mkbuildcfg(file string) { + fmt.Fprintf(&buf, "const defaultGO_EXTLINK_ENABLED = `%s`\n", goextlinkenabled) + fmt.Fprintf(&buf, "const defaultGO_LDSO = `%s`\n", defaultldso) + fmt.Fprintf(&buf, "const version = `%s`\n", findgoversion()) ++ fmt.Fprintf(&buf, "const msVersionRevision = `%s`\n", findmsgorevision()) + fmt.Fprintf(&buf, "const defaultGOOS = runtime.GOOS\n") + fmt.Fprintf(&buf, "const defaultGOARCH = runtime.GOARCH\n") + fmt.Fprintf(&buf, "const DefaultGOFIPS140 = `%s`\n", gofips140) +diff --git a/src/cmd/go/internal/cache/hash.go b/src/cmd/go/internal/cache/hash.go +index 27d275644a4bd0..d41dbd6b4d4841 100644 +--- a/src/cmd/go/internal/cache/hash.go ++++ b/src/cmd/go/internal/cache/hash.go +@@ -48,12 +48,17 @@ var hashSalt = []byte(stripExperiment(runtime.Version())) + // stripExperiment strips any GOEXPERIMENT configuration from the Go + // version string. + func stripExperiment(version string) string { +- if i := strings.Index(version, " X:"); i >= 0 { +- return version[:i] +- } +- if i := strings.Index(version, "-X:"); i >= 0 { +- return version[:i] +- } ++ // Microsoft build of Go patch: this function originally only removed one of ++ // the " X:" or "-X:" suffixes, and it looked for " X:" first. This breaks ++ // the gobootstrap cache salt because our version has both "-X:" and " X:" ++ // suffixes. For example, it fails to remove the "-X:" part in this example: ++ // ++ // go1.26rc1-1_microsoft-X:nodwarf5,nogreenteagc,norandomizedheapbase64,nosizespecializedmalloc X:nodwarf5,nogreenteagc,norandomizedheapbase64,nosizespecializedmalloc ++ // ++ // We patch this function to remove both without an early exit when one of ++ // the suffixes is found. ++ version, _, _ = strings.Cut(version, " X:") ++ version, _, _ = strings.Cut(version, "-X:") + return version + } + +diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go +index ce290ab4617cfd..5dbdd13d3957a2 100644 +--- a/src/cmd/link/internal/ld/main.go ++++ b/src/cmd/link/internal/ld/main.go +@@ -44,7 +44,6 @@ import ( + "os" + "runtime" + "runtime/pprof" +- "slices" + "strconv" + "strings" + ) +@@ -187,26 +186,8 @@ func Main(arch *sys.Arch, theArch Arch) { + addstrdata1(ctxt, "runtime.defaultGOROOT="+buildcfg.GOROOT) + } + +- buildVersion := buildcfg.Version +- if goexperiment := buildcfg.Experiment.String(); goexperiment != "" { +- // buildVersion is intended to contain non-default experiment flags. +- // The Microsoft build of Go default behavior is to set the +- // nosystemcrypto experiments, so we don't include it in the buildVersion string. +- // This is also important because runtime.Version() gets the value from +- // the buildVersion string, and many code out there, e.g. the standard library +- // go/version package, doesn't expect the version to contain experiments. +- goexperiment = strings.Join(slices.DeleteFunc(strings.Split(goexperiment, ","), func(s string) bool { +- return s == "nosystemcrypto" || s == "ms_nocgo_opensslcrypto" +- }), ",") +- if goexperiment != "" { +- sep := " " +- if !strings.Contains(buildVersion, "-") { // See go.dev/issue/75953. +- sep = "-" +- } +- buildVersion += sep + "X:" + goexperiment +- } +- } +- addstrdata1(ctxt, "runtime.buildVersion="+buildVersion) ++ // Save upstream build version for use by GODEBUG=ms_version=0 at runtime. ++ addstrdata1(ctxt, "runtime.upstreamBuildVersion="+buildcfg.UpstreamVersion) + + // TODO(matloob): define these above and then check flag values here + if ctxt.Arch.Family == sys.AMD64 && buildcfg.GOOS == "plan9" { +@@ -222,10 +203,19 @@ func Main(arch *sys.Arch, theArch Arch) { + objabi.Flagfn1("X", "add string value `definition` of the form importpath.name=value", func(s string) { addstrdata1(ctxt, s) }) + objabi.Flagcount("v", "print link trace", &ctxt.Debugvlog) + objabi.Flagfn1("importcfg", "read import configuration from `file`", ctxt.readImportCfg) ++ msEmbedUpstreamVersionFlag := flag.Bool( ++ "ms_embedupstreamversion", false, ++ "for compatibility, embed the upstream Go version rather than the Microsoft build of Go version") + + objabi.Flagparse(usage) + counter.CountFlags("link/flag:", *flag.CommandLine) + ++ if *msEmbedUpstreamVersionFlag { ++ addstrdata1(ctxt, "runtime.buildVersion="+buildcfg.UpstreamVersion) ++ } else { ++ addstrdata1(ctxt, "runtime.buildVersion="+buildcfg.Version) ++ } ++ + if ctxt.Debugvlog > 0 { + // dump symbol info on crash + defer func() { ctxt.loader.Dump() }() +diff --git a/src/internal/buildcfg/cfg.go b/src/internal/buildcfg/cfg.go +index 89fd74eb823162..ddf9e40366855d 100644 +--- a/src/internal/buildcfg/cfg.go ++++ b/src/internal/buildcfg/cfg.go +@@ -15,6 +15,7 @@ import ( + "fmt" + "os" + "path/filepath" ++ "slices" + "strconv" + "strings" + ) +@@ -35,9 +36,64 @@ var ( + ToolTags = toolTags() + GO_LDSO = defaultGO_LDSO + GOFIPS140 = gofips140() +- Version = version ++ Version = fixDefaultExperimentVersionParts(msVersion()) + ) + ++var ( ++ UpstreamVersion = fixDefaultExperimentVersionParts(version) ++) ++ ++func msVersion() string { ++ // The "microsoft" mark if no specific revision is set (e.g. a main branch ++ // build) or "{rev}_microsoft" if a revision is set. ++ var marker string ++ if msVersionRevision == "" { ++ marker = "microsoft" ++ } else { ++ marker = msVersionRevision + "_microsoft" ++ } ++ // Gobootstrap has a version like this and we need to insert our marker ++ // before the "-X:...". The -X gets trimmed off when creating the build ++ // cache salt and causes a version mismatch with the final build of the go ++ // cmd, showing up as a stale stdlib when built with gobootstrap vs. go. ++ // Example version: ++ // ++ // go1.26rc1-X:nodwarf5,nogreenteagc,[...] ++ if before, after, ok := strings.Cut(UpstreamVersion, "-X:"); ok { ++ return before + "-" + marker + "-X:" + after ++ } ++ // Similarly, a dev build's version has some text and a timestamp, and for ++ // better visiblity, we want to insert before the "-devel": ++ // ++ // go1.26-devel_c16402d15b [timestamp] ++ if before, after, ok := strings.Cut(UpstreamVersion, "-devel"); ok { ++ return before + "-" + marker + "-devel" + after ++ } ++ return UpstreamVersion + "-" + marker ++} ++ ++func fixDefaultExperimentVersionParts(buildVersion string) string { ++ if goexperiment := Experiment.String(); goexperiment != "" { ++ // buildVersion is intended to contain non-default experiment flags. ++ // The Microsoft build of Go default behavior is to set the ++ // nosystemcrypto experiments, so we don't include it in the buildVersion string. ++ // This is also important because runtime.Version() gets the value from ++ // the buildVersion string, and many code out there, e.g. the standard library ++ // go/version package, doesn't expect the version to contain experiments. ++ goexperiment = strings.Join(slices.DeleteFunc(strings.Split(goexperiment, ","), func(s string) bool { ++ return s == "nosystemcrypto" || s == "ms_nocgo_opensslcrypto" ++ }), ",") ++ if goexperiment != "" { ++ sep := " " ++ if !strings.Contains(buildVersion, "-") { // See go.dev/issue/75953. ++ sep = "-" ++ } ++ buildVersion += sep + "X:" + goexperiment ++ } ++ } ++ return buildVersion ++} ++ + // Error is one of the errors found (if any) in the build configuration. + var Error error + +diff --git a/src/internal/godebugs/table.go b/src/internal/godebugs/table.go +index 7a5ea67c7dca33..d3e5b7b71d528c 100644 +--- a/src/internal/godebugs/table.go ++++ b/src/internal/godebugs/table.go +@@ -51,6 +51,7 @@ var All = []Info{ + {Name: "jstmpllitinterp", Package: "html/template", Opaque: true}, // bug #66217: remove Opaque + {Name: "ms_tlsprofile", Package: "crypto/tls", Opaque: true}, + {Name: "ms_tlsx25519", Package: "crypto/tls", Opaque: true}, ++ {Name: "ms_version", Package: "runtime", Opaque: true}, + //{Name: "multipartfiles", Package: "mime/multipart"}, + {Name: "multipartmaxheaders", Package: "mime/multipart"}, + {Name: "multipartmaxparts", Package: "mime/multipart"}, +diff --git a/src/runtime/extern.go b/src/runtime/extern.go +index a9f97a1a045525..d713426f814eed 100644 +--- a/src/runtime/extern.go ++++ b/src/runtime/extern.go +@@ -367,10 +367,20 @@ func GOROOT() string { + // This is accessed by "go version ". + var buildVersion string + ++// upstreamBuildVersion is the version string that upstream Go would have ++// assigned at build time. It's used when GODEBUG=ms_version=0 is set for ++// compatibility purposes. ++// ++// This is set by the linker. ++var upstreamBuildVersion string ++ + // Version returns the Go tree's version string. + // It is either the commit hash and date at the time of the build or, + // when possible, a release tag like "go1.3". + func Version() string { ++ if debug.msversion.Load() == 0 { ++ return upstreamBuildVersion ++ } + return buildVersion + } + +diff --git a/src/runtime/runtime1.go b/src/runtime/runtime1.go +index 965ff8ab5167d5..c102c3f3eea087 100644 +--- a/src/runtime/runtime1.go ++++ b/src/runtime/runtime1.go +@@ -364,6 +364,9 @@ var debug struct { + // tracebacklabels controls the inclusion of goroutine labels in the + // goroutine status header line. + tracebacklabels atomic.Int32 ++ ++ // msversion controls the return value of [runtime.Version()]. ++ msversion atomic.Int32 + } + + var dbgvars = []*dbgVar{ +@@ -401,6 +404,7 @@ var dbgvars = []*dbgVar{ + {name: "tracebacklabels", atomic: &debug.tracebacklabels, def: 0}, + {name: "tracefpunwindoff", value: &debug.tracefpunwindoff}, + {name: "updatemaxprocs", value: &debug.updatemaxprocs, def: 1}, ++ {name: "ms_version", atomic: &debug.msversion, def: 1}, + } + + func parseRuntimeDebugVars(godebug string) { From 069801a21742006c5a70cabe174cfef34964fe8e Mon Sep 17 00:00:00 2001 From: Davis Goodin Date: Tue, 13 Jan 2026 15:30:18 -0800 Subject: [PATCH 2/7] Fix duplicate experiments, simplify and reduce diff --- ...13-Add-Microsoft-version-information.patch | 161 +++++++----------- 1 file changed, 57 insertions(+), 104 deletions(-) diff --git a/patches/0013-Add-Microsoft-version-information.patch b/patches/0013-Add-Microsoft-version-information.patch index 0fd78afb6d..12432803bf 100644 --- a/patches/0013-Add-Microsoft-version-information.patch +++ b/patches/0013-Add-Microsoft-version-information.patch @@ -1,6 +1,6 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: bot-for-go[bot] <199222863+bot-for-go[bot]@users.noreply.github.com> -Date: Tue, 13 Jan 2026 11:21:36 -0800 +Date: Tue, 13 Jan 2026 15:28:15 -0800 Subject: [PATCH] Add Microsoft version information Embed a Microsoft marker and the current revision into built Go binaries, @@ -12,32 +12,35 @@ Including revision means that it is also possible to determine whether Microsoft-specific fixes have been applied to a given Go binary built by this toolset. -Includes compatibility opt out features: "ms_version=0" GODEBUG option to change runtime.Version() behavior, and -"-ms_embedupstreamversion" ld option if compatibility with external inspection is the concern. +Includes compatibility opt out features: "ms_version=0" GODEBUG option to change +runtime.Version() behavior, and "-ms_embedupstreamversion" ld option if +compatibility with external inspection is the concern. --- - doc/godebug.md | 7 ++++ - src/cmd/dist/build.go | 16 +++++++++ + doc/godebug.md | 9 ++++++++ + src/cmd/dist/build.go | 16 ++++++++++++++ src/cmd/dist/buildruntime.go | 1 + - src/cmd/go/internal/cache/hash.go | 17 +++++---- - src/cmd/link/internal/ld/main.go | 32 ++++++----------- - src/internal/buildcfg/cfg.go | 58 ++++++++++++++++++++++++++++++- + src/cmd/go/internal/cache/hash.go | 6 ++++++ + src/cmd/link/internal/ld/main.go | 22 ++++++++++++++++--- + src/internal/buildcfg/cfg.go | 35 ++++++++++++++++++++++++++++++- src/internal/godebugs/table.go | 1 + - src/runtime/extern.go | 10 ++++++ - src/runtime/runtime1.go | 4 +++ - 9 files changed, 118 insertions(+), 28 deletions(-) + src/runtime/extern.go | 10 +++++++++ + src/runtime/runtime1.go | 4 ++++ + 9 files changed, 100 insertions(+), 4 deletions(-) diff --git a/doc/godebug.md b/doc/godebug.md -index 4c95ceb09bcbbe..001304ac49cebb 100644 +index 4c95ceb09bcbbe..58b4d513656ff8 100644 --- a/doc/godebug.md +++ b/doc/godebug.md -@@ -192,6 +192,13 @@ Microsoft build of Go 1.26 added a new `ms_tlsprofile` setting that controls the +@@ -192,6 +192,15 @@ Microsoft build of Go 1.26 added a new `ms_tlsprofile` setting that controls the - "default": use the recommended Microsoft TLS settings. This is the default. - "off": use the default upstream Go TLS settings. +Microsoft build of Go 1.26 added a new `ms_version` setting. It controls whether +the Go runtime uses a Microsoft-specific version string in the output of -+`runtime.Version()`. This in turn affects the output of `go version`. -+The possible values are: ++`runtime.Version()`. This also affects the output of `go version`. This doesn't ++affect the version embedded in a binary created by `go build`: for this, see ++the ld flag `-ms_embedupstreamversion`. ++The possible values of `ms_version` are: +- "0": `runtime.Version()` returns the upstream version string, for example: "go1.26.0". +- "1" (default): `runtime.Version()` returns the Microsoft build of Go version string, for example: "go1.26.0-1_microsoft". + @@ -84,75 +87,48 @@ index 87e88671763996..dccdca982300d7 100644 fmt.Fprintf(&buf, "const defaultGOARCH = runtime.GOARCH\n") fmt.Fprintf(&buf, "const DefaultGOFIPS140 = `%s`\n", gofips140) diff --git a/src/cmd/go/internal/cache/hash.go b/src/cmd/go/internal/cache/hash.go -index 27d275644a4bd0..d41dbd6b4d4841 100644 +index 27d275644a4bd0..3c40024b4b7ab7 100644 --- a/src/cmd/go/internal/cache/hash.go +++ b/src/cmd/go/internal/cache/hash.go -@@ -48,12 +48,17 @@ var hashSalt = []byte(stripExperiment(runtime.Version())) - // stripExperiment strips any GOEXPERIMENT configuration from the Go +@@ -49,6 +49,12 @@ var hashSalt = []byte(stripExperiment(runtime.Version())) // version string. func stripExperiment(version string) string { -- if i := strings.Index(version, " X:"); i >= 0 { -- return version[:i] -- } -- if i := strings.Index(version, "-X:"); i >= 0 { -- return version[:i] -- } -+ // Microsoft build of Go patch: this function originally only removed one of -+ // the " X:" or "-X:" suffixes, and it looked for " X:" first. This breaks -+ // the gobootstrap cache salt because our version has both "-X:" and " X:" -+ // suffixes. For example, it fails to remove the "-X:" part in this example: -+ // -+ // go1.26rc1-1_microsoft-X:nodwarf5,nogreenteagc,norandomizedheapbase64,nosizespecializedmalloc X:nodwarf5,nogreenteagc,norandomizedheapbase64,nosizespecializedmalloc -+ // -+ // We patch this function to remove both without an early exit when one of -+ // the suffixes is found. -+ version, _, _ = strings.Cut(version, " X:") -+ version, _, _ = strings.Cut(version, "-X:") - return version - } - + if i := strings.Index(version, " X:"); i >= 0 { ++ // Check that version doesn't also have a "-X:" suffix. This will only ++ // happen if there is a coding mistake, and it's better to catch it here ++ // than experience a stale cache later due to mismatch. ++ if strings.Contains(version, "-X:") { ++ panic(fmt.Sprintf("stripExperiment found both ' X:' and '-X:' suffixes in version %q", version)) ++ } + return version[:i] + } + if i := strings.Index(version, "-X:"); i >= 0 { diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go -index ce290ab4617cfd..5dbdd13d3957a2 100644 +index ce290ab4617cfd..fef6775b79835d 100644 --- a/src/cmd/link/internal/ld/main.go +++ b/src/cmd/link/internal/ld/main.go -@@ -44,7 +44,6 @@ import ( - "os" - "runtime" - "runtime/pprof" -- "slices" - "strconv" - "strings" - ) -@@ -187,26 +186,8 @@ func Main(arch *sys.Arch, theArch Arch) { +@@ -187,8 +187,8 @@ func Main(arch *sys.Arch, theArch Arch) { addstrdata1(ctxt, "runtime.defaultGOROOT="+buildcfg.GOROOT) } - buildVersion := buildcfg.Version - if goexperiment := buildcfg.Experiment.String(); goexperiment != "" { -- // buildVersion is intended to contain non-default experiment flags. -- // The Microsoft build of Go default behavior is to set the -- // nosystemcrypto experiments, so we don't include it in the buildVersion string. -- // This is also important because runtime.Version() gets the value from -- // the buildVersion string, and many code out there, e.g. the standard library -- // go/version package, doesn't expect the version to contain experiments. -- goexperiment = strings.Join(slices.DeleteFunc(strings.Split(goexperiment, ","), func(s string) bool { -- return s == "nosystemcrypto" || s == "ms_nocgo_opensslcrypto" -- }), ",") -- if goexperiment != "" { -- sep := " " -- if !strings.Contains(buildVersion, "-") { // See go.dev/issue/75953. -- sep = "-" -- } -- buildVersion += sep + "X:" + goexperiment -- } -- } ++ goexperiment := buildcfg.Experiment.String() ++ appendExperimentVersion := func(buildVersion string) string { + // buildVersion is intended to contain non-default experiment flags. + // The Microsoft build of Go default behavior is to set the + // nosystemcrypto experiments, so we don't include it in the buildVersion string. +@@ -205,8 +205,8 @@ func Main(arch *sys.Arch, theArch Arch) { + } + buildVersion += sep + "X:" + goexperiment + } ++ return buildVersion + } - addstrdata1(ctxt, "runtime.buildVersion="+buildVersion) -+ // Save upstream build version for use by GODEBUG=ms_version=0 at runtime. -+ addstrdata1(ctxt, "runtime.upstreamBuildVersion="+buildcfg.UpstreamVersion) // TODO(matloob): define these above and then check flag values here if ctxt.Arch.Family == sys.AMD64 && buildcfg.GOOS == "plan9" { -@@ -222,10 +203,19 @@ func Main(arch *sys.Arch, theArch Arch) { +@@ -222,10 +222,26 @@ func Main(arch *sys.Arch, theArch Arch) { objabi.Flagfn1("X", "add string value `definition` of the form importpath.name=value", func(s string) { addstrdata1(ctxt, s) }) objabi.Flagcount("v", "print link trace", &ctxt.Debugvlog) objabi.Flagfn1("importcfg", "read import configuration from `file`", ctxt.readImportCfg) @@ -163,37 +139,36 @@ index ce290ab4617cfd..5dbdd13d3957a2 100644 objabi.Flagparse(usage) counter.CountFlags("link/flag:", *flag.CommandLine) ++ var buildVersion string + if *msEmbedUpstreamVersionFlag { -+ addstrdata1(ctxt, "runtime.buildVersion="+buildcfg.UpstreamVersion) ++ buildVersion = appendExperimentVersion(buildcfg.UpstreamVersion) + } else { -+ addstrdata1(ctxt, "runtime.buildVersion="+buildcfg.Version) ++ buildVersion = appendExperimentVersion(buildcfg.Version) + } ++ // Embed build version information. Microsoft build of Go version or ++ // upstream version depending on ld flag. ++ addstrdata1(ctxt, "runtime.buildVersion="+buildVersion) ++ // Always save the upstream build version. This might be used by ++ // GODEBUG=ms_version=0 at runtime. ++ addstrdata1(ctxt, "runtime.upstreamBuildVersion="+appendExperimentVersion(buildcfg.UpstreamVersion)) + if ctxt.Debugvlog > 0 { // dump symbol info on crash defer func() { ctxt.loader.Dump() }() diff --git a/src/internal/buildcfg/cfg.go b/src/internal/buildcfg/cfg.go -index 89fd74eb823162..ddf9e40366855d 100644 +index 89fd74eb823162..79e3f12b3ba102 100644 --- a/src/internal/buildcfg/cfg.go +++ b/src/internal/buildcfg/cfg.go -@@ -15,6 +15,7 @@ import ( - "fmt" - "os" - "path/filepath" -+ "slices" - "strconv" - "strings" - ) -@@ -35,9 +36,64 @@ var ( +@@ -35,9 +35,42 @@ var ( ToolTags = toolTags() GO_LDSO = defaultGO_LDSO GOFIPS140 = gofips140() - Version = version -+ Version = fixDefaultExperimentVersionParts(msVersion()) ++ Version = msVersion() ) +var ( -+ UpstreamVersion = fixDefaultExperimentVersionParts(version) ++ UpstreamVersion = version +) + +func msVersion() string { @@ -224,28 +199,6 @@ index 89fd74eb823162..ddf9e40366855d 100644 + } + return UpstreamVersion + "-" + marker +} -+ -+func fixDefaultExperimentVersionParts(buildVersion string) string { -+ if goexperiment := Experiment.String(); goexperiment != "" { -+ // buildVersion is intended to contain non-default experiment flags. -+ // The Microsoft build of Go default behavior is to set the -+ // nosystemcrypto experiments, so we don't include it in the buildVersion string. -+ // This is also important because runtime.Version() gets the value from -+ // the buildVersion string, and many code out there, e.g. the standard library -+ // go/version package, doesn't expect the version to contain experiments. -+ goexperiment = strings.Join(slices.DeleteFunc(strings.Split(goexperiment, ","), func(s string) bool { -+ return s == "nosystemcrypto" || s == "ms_nocgo_opensslcrypto" -+ }), ",") -+ if goexperiment != "" { -+ sep := " " -+ if !strings.Contains(buildVersion, "-") { // See go.dev/issue/75953. -+ sep = "-" -+ } -+ buildVersion += sep + "X:" + goexperiment -+ } -+ } -+ return buildVersion -+} + // Error is one of the errors found (if any) in the build configuration. var Error error From 7ec93e84cad3cacb713bf6fd560d5546698007a5 Mon Sep 17 00:00:00 2001 From: Davis Goodin Date: Tue, 13 Jan 2026 15:37:47 -0800 Subject: [PATCH 3/7] Tidier MICROSOFT_REVISION copy --- eng/_util/cmd/build/build.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/eng/_util/cmd/build/build.go b/eng/_util/cmd/build/build.go index 7f75ea041f..a25d8bef56 100644 --- a/eng/_util/cmd/build/build.go +++ b/eng/_util/cmd/build/build.go @@ -270,7 +270,7 @@ func build(o *options) (err error) { if version, err = writeDevelVersionFile(goRootDir, executableExtension); err != nil { return fmt.Errorf("unable to pack: failed writing development VERSION file: %v", err) } - // Best effort: clean up the VERSION file when we're done. This is just for dev + // Best effort: clean up the VERSION file when we're done. Clean up for tidier dev // workflows: the temp VERSION file should never be checked in. defer os.Remove(filepath.Join(goRootDir, "VERSION")) } else { @@ -281,16 +281,15 @@ func build(o *options) (err error) { } // We also need to copy our MICROSOFT_REVISION file in so the toolset can report that it's a // Microsoft build of a specific revision and embed that info into built binaries. - microsoftRevisionSrc := filepath.Join(rootDir, "MICROSOFT_REVISION") microsoftRevisionDst := filepath.Join(goRootDir, "MICROSOFT_REVISION") - if err := copyFile(microsoftRevisionDst, microsoftRevisionSrc); err != nil { + if err := copyFile(microsoftRevisionDst, filepath.Join(rootDir, "MICROSOFT_REVISION")); err != nil { if !errors.Is(err, os.ErrNotExist) { return fmt.Errorf("unable to pack: failed to read MICROSOFT_REVISION file for unexpected reason: %v", err) } - // Ok: a main branch build won't have a MICROSOFT_REVISION file. + // Ok: a main branch or pre-stable release branch has no MICROSOFT_REVISION file. } else { - // Best effort: clean up the MICROSOFT_REVISION file when we're done. This is just for - // dev workflows: the temp MICROSOFT_REVISION file should never be checked in. + // Best effort: clean up the MICROSOFT_REVISION file when we're done. Clean up for + // tidier dev workflows: the temp MICROSOFT_REVISION file should never be checked in. defer os.Remove(microsoftRevisionDst) } From 7705a8bea885df3a03b5744a9448100089b209ae Mon Sep 17 00:00:00 2001 From: Davis Goodin Date: Tue, 13 Jan 2026 16:14:34 -0800 Subject: [PATCH 4/7] Avoid patch churn, reduce upstream diff --- ...03-Implement-crypto-internal-backend.patch | 77 ++++++++++--------- ...13-Add-Microsoft-version-information.patch | 36 +++++---- 2 files changed, 60 insertions(+), 53 deletions(-) diff --git a/patches/0003-Implement-crypto-internal-backend.patch b/patches/0003-Implement-crypto-internal-backend.patch index 8c76316632..05e506701a 100644 --- a/patches/0003-Implement-crypto-internal-backend.patch +++ b/patches/0003-Implement-crypto-internal-backend.patch @@ -22,7 +22,7 @@ desired goexperiments and build tags. .../go/testdata/script/env_cross_build.txt | 2 + .../script/test_android_issue62123.txt | 2 + src/cmd/internal/testdir/testdir_test.go | 7 + - src/cmd/link/internal/ld/main.go | 20 +- + src/cmd/link/internal/ld/main.go | 2 +- src/cmd/link/link_test.go | 8 + src/crypto/internal/backend/backend_test.go | 56 +++ src/crypto/internal/backend/bbig/big.go | 17 + @@ -50,10 +50,10 @@ desired goexperiments and build tags. src/crypto/internal/backend/stub.s | 10 + src/crypto/systemcrypto_nocgo_linux.go | 15 + src/go/build/deps_test.go | 24 +- - src/internal/buildcfg/exp.go | 57 +++ + src/internal/buildcfg/exp.go | 77 ++++ src/runtime/runtime_boring.go | 5 + src/syscall/exec_linux_test.go | 4 + - 44 files changed, 2766 insertions(+), 20 deletions(-) + 44 files changed, 2771 insertions(+), 17 deletions(-) create mode 100644 src/cmd/go/systemcrypto_test.go create mode 100644 src/crypto/internal/backend/backend_test.go create mode 100644 src/crypto/internal/backend/bbig/big.go @@ -742,44 +742,18 @@ index c7060898778c88..47de9e25baa759 100644 gorootTestDir: filepath.Join(testenv.GOROOT(t), "test"), runoutputGate: make(chan bool, *runoutputLimit), diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go -index a4b3a0422f2f41..ce290ab4617cfd 100644 +index a4b3a0422f2f41..0140c385e47991 100644 --- a/src/cmd/link/internal/ld/main.go +++ b/src/cmd/link/internal/ld/main.go -@@ -44,6 +44,7 @@ import ( - "os" - "runtime" - "runtime/pprof" -+ "slices" - "strconv" - "strings" - ) -@@ -188,11 +189,22 @@ func Main(arch *sys.Arch, theArch Arch) { - - buildVersion := buildcfg.Version - if goexperiment := buildcfg.Experiment.String(); goexperiment != "" { -- sep := " " -- if !strings.Contains(buildVersion, "-") { // See go.dev/issue/75953. -- sep = "-" -+ // buildVersion is intended to contain non-default experiment flags. -+ // The Microsoft build of Go default behavior is to set the -+ // nosystemcrypto experiments, so we don't include it in the buildVersion string. -+ // This is also important because runtime.Version() gets the value from -+ // the buildVersion string, and many code out there, e.g. the standard library -+ // go/version package, doesn't expect the version to contain experiments. -+ goexperiment = strings.Join(slices.DeleteFunc(strings.Split(goexperiment, ","), func(s string) bool { -+ return s == "nosystemcrypto" || s == "ms_nocgo_opensslcrypto" -+ }), ",") -+ if goexperiment != "" { -+ sep := " " -+ if !strings.Contains(buildVersion, "-") { // See go.dev/issue/75953. -+ sep = "-" -+ } -+ buildVersion += sep + "X:" + goexperiment - } -- buildVersion += sep + "X:" + goexperiment +@@ -187,7 +187,7 @@ func Main(arch *sys.Arch, theArch Arch) { } - addstrdata1(ctxt, "runtime.buildVersion="+buildVersion) + buildVersion := buildcfg.Version +- if goexperiment := buildcfg.Experiment.String(); goexperiment != "" { ++ if goexperiment := buildcfg.Experiment.MSString(); goexperiment != "" { + sep := " " + if !strings.Contains(buildVersion, "-") { // See go.dev/issue/75953. + sep = "-" diff --git a/src/cmd/link/link_test.go b/src/cmd/link/link_test.go index 036eda13bc8807..33a79409ecc1fe 100644 --- a/src/cmd/link/link_test.go @@ -3265,7 +3239,7 @@ index 3f2b2399ec4127..f52b6b1ac71711 100644 < crypto/rand < crypto/ed25519 # depends on crypto/rand.Reader diff --git a/src/internal/buildcfg/exp.go b/src/internal/buildcfg/exp.go -index 0c25f3cce97202..4bcb62b7c63fe6 100644 +index 0c25f3cce97202..1e52c897293c17 100644 --- a/src/internal/buildcfg/exp.go +++ b/src/internal/buildcfg/exp.go @@ -5,12 +5,15 @@ @@ -3345,6 +3319,33 @@ index 0c25f3cce97202..4bcb62b7c63fe6 100644 return flags, nil } +@@ -203,6 +260,26 @@ func (exp *ExperimentFlags) String() string { + return strings.Join(expList(&exp.Flags, &exp.baseline, false), ",") + } + ++// MSString returns the canonical GOEXPERIMENT string to enable this experiment ++// configuration. This is a modified version of what's returned by ++// [ExperimentFlags.String] that ensures experiments that have a different ++// baseline in the Microsoft build of Go are elided. ++// ++// Elision is important because this method is involved in the value of ++// runtime.Version(), and many usages out there, e.g. the standard library ++// go/version package, don't expect the version to contain experiments. ++func (exp *ExperimentFlags) MSString() string { ++ // Parse [String] rather than calling expList directly so that changes to ++ // [String] are reflected in [MSString] without careful tracking. ++ exps := strings.Split(exp.String(), ",") ++ // The Microsoft build of Go default behavior sets a few experiments that we ++ // need to remove it from the result. ++ exps = slices.DeleteFunc(exps, func(s string) bool { ++ return s == "nosystemcrypto" || s == "ms_nocgo_opensslcrypto" ++ }) ++ return strings.Join(exps, ",") ++} ++ + // expList returns the list of lower-cased experiment names for + // experiments that differ from base. base may be nil to indicate no + // experiments. If all is true, then include all experiment flags, diff --git a/src/runtime/runtime_boring.go b/src/runtime/runtime_boring.go index 831ee67afc952d..d2f00d57c10286 100644 --- a/src/runtime/runtime_boring.go diff --git a/patches/0013-Add-Microsoft-version-information.patch b/patches/0013-Add-Microsoft-version-information.patch index 12432803bf..1be815148b 100644 --- a/patches/0013-Add-Microsoft-version-information.patch +++ b/patches/0013-Add-Microsoft-version-information.patch @@ -20,12 +20,12 @@ compatibility with external inspection is the concern. src/cmd/dist/build.go | 16 ++++++++++++++ src/cmd/dist/buildruntime.go | 1 + src/cmd/go/internal/cache/hash.go | 6 ++++++ - src/cmd/link/internal/ld/main.go | 22 ++++++++++++++++--- + src/cmd/link/internal/ld/main.go | 33 +++++++++++++++++++++++------ src/internal/buildcfg/cfg.go | 35 ++++++++++++++++++++++++++++++- src/internal/godebugs/table.go | 1 + src/runtime/extern.go | 10 +++++++++ src/runtime/runtime1.go | 4 ++++ - 9 files changed, 100 insertions(+), 4 deletions(-) + 9 files changed, 108 insertions(+), 7 deletions(-) diff --git a/doc/godebug.md b/doc/godebug.md index 4c95ceb09bcbbe..58b4d513656ff8 100644 @@ -104,31 +104,37 @@ index 27d275644a4bd0..3c40024b4b7ab7 100644 } if i := strings.Index(version, "-X:"); i >= 0 { diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go -index ce290ab4617cfd..fef6775b79835d 100644 +index 0140c385e47991..a55738a24d63c1 100644 --- a/src/cmd/link/internal/ld/main.go +++ b/src/cmd/link/internal/ld/main.go -@@ -187,8 +187,8 @@ func Main(arch *sys.Arch, theArch Arch) { +@@ -186,15 +186,20 @@ func Main(arch *sys.Arch, theArch Arch) { addstrdata1(ctxt, "runtime.defaultGOROOT="+buildcfg.GOROOT) } - buildVersion := buildcfg.Version -- if goexperiment := buildcfg.Experiment.String(); goexperiment != "" { -+ goexperiment := buildcfg.Experiment.String() -+ appendExperimentVersion := func(buildVersion string) string { - // buildVersion is intended to contain non-default experiment flags. - // The Microsoft build of Go default behavior is to set the - // nosystemcrypto experiments, so we don't include it in the buildVersion string. -@@ -205,8 +205,8 @@ func Main(arch *sys.Arch, theArch Arch) { - } - buildVersion += sep + "X:" + goexperiment ++ // Set up a function that we can apply to both the Microsoft and upstream ++ // versions. This approach is intended to minimize the patch diff and avoid ++ // touching the same lines as earlier patches. ++ appendExperimentVersion := func(buildVersion string) string { return buildVersion } + if goexperiment := buildcfg.Experiment.MSString(); goexperiment != "" { +- sep := " " +- if !strings.Contains(buildVersion, "-") { // See go.dev/issue/75953. +- sep = "-" ++ appendExperimentVersion = func(buildVersion string) string { ++ sep := " " ++ if !strings.Contains(buildVersion, "-") { // See go.dev/issue/75953. ++ sep = "-" ++ } ++ buildVersion += sep + "X:" + goexperiment ++ return buildVersion } -+ return buildVersion +- buildVersion += sep + "X:" + goexperiment } - addstrdata1(ctxt, "runtime.buildVersion="+buildVersion) // TODO(matloob): define these above and then check flag values here if ctxt.Arch.Family == sys.AMD64 && buildcfg.GOOS == "plan9" { -@@ -222,10 +222,26 @@ func Main(arch *sys.Arch, theArch Arch) { +@@ -210,10 +215,26 @@ func Main(arch *sys.Arch, theArch Arch) { objabi.Flagfn1("X", "add string value `definition` of the form importpath.name=value", func(s string) { addstrdata1(ctxt, s) }) objabi.Flagcount("v", "print link trace", &ctxt.Debugvlog) objabi.Flagfn1("importcfg", "read import configuration from `file`", ctxt.readImportCfg) From 1d60ebb3b847348818228076529e19d3e36d5c56 Mon Sep 17 00:00:00 2001 From: Davis Goodin Date: Tue, 13 Jan 2026 16:50:53 -0800 Subject: [PATCH 5/7] Fix comment typo --- patches/0003-Implement-crypto-internal-backend.patch | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/patches/0003-Implement-crypto-internal-backend.patch b/patches/0003-Implement-crypto-internal-backend.patch index 05e506701a..d8454c5102 100644 --- a/patches/0003-Implement-crypto-internal-backend.patch +++ b/patches/0003-Implement-crypto-internal-backend.patch @@ -3239,7 +3239,7 @@ index 3f2b2399ec4127..f52b6b1ac71711 100644 < crypto/rand < crypto/ed25519 # depends on crypto/rand.Reader diff --git a/src/internal/buildcfg/exp.go b/src/internal/buildcfg/exp.go -index 0c25f3cce97202..1e52c897293c17 100644 +index 0c25f3cce97202..0ec29033d9de89 100644 --- a/src/internal/buildcfg/exp.go +++ b/src/internal/buildcfg/exp.go @@ -5,12 +5,15 @@ @@ -3336,7 +3336,7 @@ index 0c25f3cce97202..1e52c897293c17 100644 + // [String] are reflected in [MSString] without careful tracking. + exps := strings.Split(exp.String(), ",") + // The Microsoft build of Go default behavior sets a few experiments that we -+ // need to remove it from the result. ++ // need to remove from the result. + exps = slices.DeleteFunc(exps, func(s string) bool { + return s == "nosystemcrypto" || s == "ms_nocgo_opensslcrypto" + }) From 6e3217b35a2bb69a68e62868b99ca466047ec79e Mon Sep 17 00:00:00 2001 From: Davis Goodin Date: Tue, 13 Jan 2026 16:51:23 -0800 Subject: [PATCH 6/7] Add cmd/go script tests for GODEBUG and ld flag --- ...13-Add-Microsoft-version-information.patch | 137 ++++++++++++++++-- 1 file changed, 127 insertions(+), 10 deletions(-) diff --git a/patches/0013-Add-Microsoft-version-information.patch b/patches/0013-Add-Microsoft-version-information.patch index 1be815148b..c9f67b4871 100644 --- a/patches/0013-Add-Microsoft-version-information.patch +++ b/patches/0013-Add-Microsoft-version-information.patch @@ -16,16 +16,20 @@ Includes compatibility opt out features: "ms_version=0" GODEBUG option to change runtime.Version() behavior, and "-ms_embedupstreamversion" ld option if compatibility with external inspection is the concern. --- - doc/godebug.md | 9 ++++++++ - src/cmd/dist/build.go | 16 ++++++++++++++ - src/cmd/dist/buildruntime.go | 1 + - src/cmd/go/internal/cache/hash.go | 6 ++++++ - src/cmd/link/internal/ld/main.go | 33 +++++++++++++++++++++++------ - src/internal/buildcfg/cfg.go | 35 ++++++++++++++++++++++++++++++- - src/internal/godebugs/table.go | 1 + - src/runtime/extern.go | 10 +++++++++ - src/runtime/runtime1.go | 4 ++++ - 9 files changed, 108 insertions(+), 7 deletions(-) + doc/godebug.md | 9 +++ + src/cmd/dist/build.go | 16 ++++++ + src/cmd/dist/buildruntime.go | 1 + + src/cmd/go/internal/cache/hash.go | 6 ++ + .../testdata/script/gotoolchain_local_ms.txt | 46 ++++++++++++++++ + src/cmd/go/testdata/script/ms_version.txt | 55 +++++++++++++++++++ + src/cmd/link/internal/ld/main.go | 33 +++++++++-- + src/internal/buildcfg/cfg.go | 35 +++++++++++- + src/internal/godebugs/table.go | 1 + + src/runtime/extern.go | 10 ++++ + src/runtime/runtime1.go | 4 ++ + 11 files changed, 209 insertions(+), 7 deletions(-) + create mode 100644 src/cmd/go/testdata/script/gotoolchain_local_ms.txt + create mode 100644 src/cmd/go/testdata/script/ms_version.txt diff --git a/doc/godebug.md b/doc/godebug.md index 4c95ceb09bcbbe..58b4d513656ff8 100644 @@ -103,6 +107,119 @@ index 27d275644a4bd0..3c40024b4b7ab7 100644 return version[:i] } if i := strings.Index(version, "-X:"); i >= 0 { +diff --git a/src/cmd/go/testdata/script/gotoolchain_local_ms.txt b/src/cmd/go/testdata/script/gotoolchain_local_ms.txt +new file mode 100644 +index 00000000000000..e88d6d070e14ea +--- /dev/null ++++ b/src/cmd/go/testdata/script/gotoolchain_local_ms.txt +@@ -0,0 +1,46 @@ ++# This test uses the fake toolchain switch support in cmd/go/internal/toolchain.Switch ++# to exercise version selection logic. ++# It's a trimmed copy of gotoolchain_local.txt that has been modified to use ++# versions just like what the Microsoft build of Go uses. ++ ++env TESTGO_VERSION=go1.500 ++env TESTGO_VERSION_SWITCH=switch ++ ++go mod init m ++ ++# GOTOOLCHAIN names can have -suffix ++env GOTOOLCHAIN=go1.800-1_microsoft ++go version ++stdout go1.800-1_microsoft ++ ++env GOTOOLCHAIN=auto ++go mod edit -go=1.999 -toolchain=go1.800-1_microsoft ++go version ++stdout go1.999 ++ ++go mod edit -go=1.777 -toolchain=go1.800-1_microsoft ++go version ++stdout go1.800-1_microsoft ++ ++# toolchain built with a custom version should know how it compares to others ++ ++env TESTGO_VERSION=go1.500-1_microsoft ++go mod edit -go=1.499 -toolchain=none ++go version ++stdout go1.500-1_microsoft ++ ++go mod edit -go=1.499 -toolchain=go1.499 ++go version ++stdout go1.500-1_microsoft ++ ++go mod edit -go=1.500 -toolchain=none ++go version ++stdout go1.500-1_microsoft ++ ++go mod edit -go=1.500 -toolchain=go1.500 ++go version ++stdout go1.500-1_microsoft ++ ++go mod edit -go=1.501 -toolchain=none ++go version ++stdout go1.501 +diff --git a/src/cmd/go/testdata/script/ms_version.txt b/src/cmd/go/testdata/script/ms_version.txt +new file mode 100644 +index 00000000000000..bf0fbdc2a3f2ed +--- /dev/null ++++ b/src/cmd/go/testdata/script/ms_version.txt +@@ -0,0 +1,55 @@ ++# This test checks the Microsoft-specific Go version feature behaviors. ++ ++# Test 'go version' itself. ++go version ++stdout '-microsoft' ++ ++env GODEBUG= ++go version ++stdout '-microsoft' ++ ++env GODEBUG=ms_version=0 ++go version ++! stdout '-microsoft' ++ ++# Check what's embedded into a built binary. ++go build ./printversion.go ++ ++env GODEBUG= ++exec ./printversion ++stdout '-microsoft' ++go version ./printversion ++stdout '-microsoft' ++ ++env GODEBUG=ms_version=0 ++exec ./printversion ++! stdout '-microsoft' ++go version ./printversion ++stdout '-microsoft' # GODEBUG only affects runtime.Version. ++ ++# Use linker flag to embed only the upstream version. ++go build -ldflags=-ms_embedupstreamversion ./printversion.go ++ ++env GODEBUG= ++exec ./printversion ++! stdout '-microsoft' ++go version ./printversion ++! stdout '-microsoft' ++ ++env GODEBUG=ms_version=0 ++exec ./printversion ++! stdout '-microsoft' ++go version ./printversion ++! stdout '-microsoft' ++ ++-- printversion.go -- ++package main ++ ++import ( ++ "fmt" ++ "runtime" ++) ++ ++func main() { ++ fmt.Println(runtime.Version()) ++} diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go index 0140c385e47991..a55738a24d63c1 100644 --- a/src/cmd/link/internal/ld/main.go From 4c9f16746bf6db9177f2f9b85186a629c2079310 Mon Sep 17 00:00:00 2001 From: Davis Goodin Date: Tue, 13 Jan 2026 20:50:48 -0800 Subject: [PATCH 7/7] Hunch: in test, don't overwrite files using build command for defender --- ...13-Add-Microsoft-version-information.patch | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/patches/0013-Add-Microsoft-version-information.patch b/patches/0013-Add-Microsoft-version-information.patch index c9f67b4871..96b16bcb62 100644 --- a/patches/0013-Add-Microsoft-version-information.patch +++ b/patches/0013-Add-Microsoft-version-information.patch @@ -161,7 +161,7 @@ index 00000000000000..e88d6d070e14ea +stdout go1.501 diff --git a/src/cmd/go/testdata/script/ms_version.txt b/src/cmd/go/testdata/script/ms_version.txt new file mode 100644 -index 00000000000000..bf0fbdc2a3f2ed +index 00000000000000..1662b28f1d07d9 --- /dev/null +++ b/src/cmd/go/testdata/script/ms_version.txt @@ -0,0 +1,55 @@ @@ -180,33 +180,33 @@ index 00000000000000..bf0fbdc2a3f2ed +! stdout '-microsoft' + +# Check what's embedded into a built binary. -+go build ./printversion.go ++go build -o ms ./printversion.go + +env GODEBUG= -+exec ./printversion ++exec ./ms +stdout '-microsoft' -+go version ./printversion ++go version ./ms +stdout '-microsoft' + +env GODEBUG=ms_version=0 -+exec ./printversion ++exec ./ms +! stdout '-microsoft' -+go version ./printversion ++go version ./ms +stdout '-microsoft' # GODEBUG only affects runtime.Version. + +# Use linker flag to embed only the upstream version. -+go build -ldflags=-ms_embedupstreamversion ./printversion.go ++go build -ldflags=-ms_embedupstreamversion -o upstream ./printversion.go + +env GODEBUG= -+exec ./printversion ++exec ./upstream +! stdout '-microsoft' -+go version ./printversion ++go version ./upstream +! stdout '-microsoft' + +env GODEBUG=ms_version=0 -+exec ./printversion ++exec ./upstream +! stdout '-microsoft' -+go version ./printversion ++go version ./upstream +! stdout '-microsoft' + +-- printversion.go --