From 1b0a2e0bf0da41c0cd0074a8854aa786db93b6d2 Mon Sep 17 00:00:00 2001 From: Li Jie Date: Tue, 6 Oct 2026 12:57:08 +0800 Subject: [PATCH 1/5] fix: handle restored GOROOT regression coverage --- cl/debug_zero_size_test.go | 92 +++++++++++++++++++++++++++++++++ ssa/di.go | 11 +++- test/goroot/notapplicable.yaml | 3 ++ test/goroot/runner_unit_test.go | 4 ++ test/goroot/xfail.yaml | 10 ++++ 5 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 cl/debug_zero_size_test.go diff --git a/cl/debug_zero_size_test.go b/cl/debug_zero_size_test.go new file mode 100644 index 0000000000..2a6a3a2899 --- /dev/null +++ b/cl/debug_zero_size_test.go @@ -0,0 +1,92 @@ +package cl + +import ( + "go/ast" + "go/parser" + "go/token" + "go/types" + "testing" + + "github.com/xgo-dev/llgo/internal/optlevel" + llssa "github.com/xgo-dev/llgo/ssa" + "github.com/xgo-dev/llvm" + "golang.org/x/tools/go/ssa" + "golang.org/x/tools/go/ssa/ssautil" +) + +// GOROOT/test/abi/f_ret_z_not.go crashed in LLVM 22's +// SelectionDAGBuilder::resolveDanglingDebugInfo after optimization promoted an +// empty aggregate snapshot to dbg.value(empty zeroinitializer). Module +// verification alone does not catch it: exercise object emission too. +func TestZeroSizedDebugValuesEmitObjects(t *testing.T) { + const source = `package zero +type Z struct{} +type NZ struct { x, y int } +//go:noinline +func f(x, y int) (Z, NZ, Z) { + var z Z + return z, NZ{x, y}, z +} +//go:noinline +func g() (Z, NZ, Z) { + a, b, c := f(3, 4) + return c, b, a +} +func array(z [0]int) ([0]int, int, [0]int) { + var empty [0]int + return empty, 7, z +} +func check() int { + _, b, _ := g() + return b.x + b.y +} +` + fset := token.NewFileSet() + file, err := parser.ParseFile(fset, "zero.go", source, parser.ParseComments) + if err != nil { + t.Fatal(err) + } + ssaPkg, _, err := ssautil.BuildPackage(&types.Config{}, fset, + types.NewPackage("zero", "zero"), []*ast.File{file}, + ssa.SanityCheckFunctions|ssa.InstantiateGenerics|ssa.GlobalDebug) + if err != nil { + t.Fatal(err) + } + for _, target := range []struct{ name, goos, triple string }{ + {"darwin", "darwin", "aarch64-apple-darwin"}, + {"linux", "linux", "aarch64-unknown-linux-gnu"}, + {"windows-msvc", "windows", "aarch64-pc-windows-msvc"}, + {"windows-mingw", "windows", "aarch64-w64-windows-gnu"}, + } { + for _, level := range []optlevel.Level{optlevel.O0, optlevel.O2, optlevel.Os} { + t.Run(target.name+"/"+level.String(), func(t *testing.T) { + prog := newLLSSAProgForTarget(t, &llssa.Target{ + GOOS: target.goos, GOARCH: "arm64", LLVMTarget: target.triple, OptLevel: level, + }) + defer prog.Dispose() + pkg, _, err := newPackageEx(prog, nil, nil, nil, ssaPkg, + []*ast.File{file}, nil, false, Options{Debug: true, DebugSymbols: true}) + if err != nil { + t.Fatal(err) + } + mod := pkg.Module() + mod.SetDataLayout(prog.DataLayout()) + mod.SetTarget(target.triple) + options := llvm.NewPassBuilderOptions() + defer options.Dispose() + options.SetVerifyEach(true) + if err := mod.RunPasses("default<"+level.String()+">", prog.TargetMachine(), options); err != nil { + t.Fatal(err) + } + object, err := prog.TargetMachine().EmitToMemoryBuffer(mod, llvm.ObjectFile) + if err != nil { + t.Fatal(err) + } + defer object.Dispose() + if len(object.Bytes()) == 0 { + t.Fatal("empty object") + } + }) + } + } +} diff --git a/ssa/di.go b/ssa/di.go index 864c163eaf..0b0fbdf056 100644 --- a/ssa/di.go +++ b/ssa/di.go @@ -908,6 +908,15 @@ func (b Builder) doConstructDebugAddrWithStore(v Expr, t types.Type) (dbgPtr, st default: ty = v.Type } + // Empty aggregates have no SelectionDAG value. LLVM 22 can crash when + // promoting their debug snapshots to dbg.value(empty zeroinitializer). + // Back the debug-only address with a byte while keeping the source type + // in the variable metadata; there are no source value bits to copy. + storedValue := v + if b.Prog.SizeOf(ty) == 0 { + ty = b.Prog.Byte() + storedValue = b.Prog.IntVal(0, ty) + } // A debug snapshot reserves one slot per function invocation. Allocating // it at a DebugRef inside a loop grows the stack on every iteration at O0. // Keep the value update at its source position, but reserve the slot with @@ -915,8 +924,8 @@ func (b Builder) doConstructDebugAddrWithStore(v Expr, t types.Type) (dbgPtr, st entryBuilder := *b entryBuilder.impl = b.Func.entryAllocaBuilder() dbgPtr = entryBuilder.AllocaT(ty) + store = b.Store(dbgPtr, storedValue) dbgPtr.Type = b.Prog.Pointer(v.Type) - store = b.Store(dbgPtr, v) return dbgPtr, store } diff --git a/test/goroot/notapplicable.yaml b/test/goroot/notapplicable.yaml index 21aecdbe13..e550d9c759 100644 --- a/test/goroot/notapplicable.yaml +++ b/test/goroot/notapplicable.yaml @@ -4,6 +4,9 @@ # under test and explains the LLGo design choice that puts it out of scope. # Applicability is global: entries must not select a Go version or platform. not_applicable: + - directive: run + case: fixedbugs/issue75764.go + reason: "not applicable: this case asserts cmd/compile's promoted-interface-wrapper tail-call optimization through a wall-clock ratio for 1,000 versus 10,000 wrappers; LLGo delegates optimization to LLVM and does not require gc's constant-time wrapper-chain performance, so this compiler-specific optimization benchmark is outside language compatibility goals" - directive: run case: finprofiled.go reason: "not applicable: this case requires gc's 16-byte tiny allocator blocks and private MemProfile bookkeeping for finalizer-resurrected subobjects; LLGo uses BDWGC or tinygogc without that allocator/profile mechanism, so reproducing it is not an LLGo compatibility goal" diff --git a/test/goroot/runner_unit_test.go b/test/goroot/runner_unit_test.go index d74ef3b171..993b2e13de 100644 --- a/test/goroot/runner_unit_test.go +++ b/test/goroot/runner_unit_test.go @@ -349,6 +349,7 @@ func TestObservedNotApplicableCasesAreGlobal(t *testing.T) { repo := repoRoot(t) cfg := loadNotApplicableConfig(t, repo, filepath.Join("test", "goroot", "notapplicable.yaml")) cases := []testCase{ + {RelPath: "fixedbugs/issue75764.go", Directive: "run"}, {RelPath: "deferfin.go", Directive: "run"}, {RelPath: "finprofiled.go", Directive: "run"}, {RelPath: "fixedbugs/issue24491b.go", Directive: "run"}, @@ -464,6 +465,9 @@ func TestWasmObservedResourceExceptions(t *testing.T) { if timeout, _, match := cfg.MatchTimeout(version, "linux/amd64", rangegen); !match || timeout != 10*time.Minute { t.Errorf("%s linux/amd64 rangegen timeout = %s, %v; want 10m, true", version, timeout, match) } + if timeout, _, match := cfg.MatchTimeout(version, "windows-mingw/amd64", rangegen); !match || timeout != 10*time.Minute { + t.Errorf("%s Windows MinGW/amd64 rangegen timeout = %s, %v; want 10m, true", version, timeout, match) + } } for _, tt := range []struct { tc testCase diff --git a/test/goroot/xfail.yaml b/test/goroot/xfail.yaml index 1d2463752c..0acf551a74 100644 --- a/test/goroot/xfail.yaml +++ b/test/goroot/xfail.yaml @@ -119,6 +119,11 @@ timeouts: case: fixedbugs/issue39541.go timeout: 90s reason: the one-million reflect.MakeFunc concurrent call loop needs load-dependent runtime slack on Windows 386 + - platform: windows/amd64 + directive: run + case: fixedbugs/issue39541.go + timeout: 2m + reason: the one-million reflect.MakeFunc concurrent call loop exceeded the default minute on a paired Windows MSVC/amd64 runner; retain a bounded run with all output and exit checks - platform: darwin/arm64 directive: runoutput case: rangegen.go @@ -129,6 +134,11 @@ timeouts: case: rangegen.go timeout: 10m reason: rangegen generates a 6.4 MB compiler torture test; allow bounded build time while its 3 GiB heap target stays under the 4 GiB host guard + - platform: windows-mingw/amd64 + directive: runoutput + case: rangegen.go + timeout: 10m + reason: both Go 1.26 and 1.27 generated builds exceeded the default 3m timeout on Windows MinGW/amd64, peaking at 3.3 GiB each; keep the case enabled with bounded build time - version: go1.26 platform: linux/amd64 directive: run From 54748764cc4d166f99ed3796d7b7366a4de15d05 Mon Sep 17 00:00:00 2001 From: Li Jie Date: Tue, 6 Oct 2026 13:19:11 +0800 Subject: [PATCH 2/5] test: bound Windows ARM64 generated-case heap usage --- test/goroot/runner_test.go | 11 +++++++++-- test/goroot/runner_unit_test.go | 7 +++++++ test/goroot/xfail.yaml | 5 +++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/test/goroot/runner_test.go b/test/goroot/runner_test.go index 4b61056fb3..e3f510074f 100644 --- a/test/goroot/runner_test.go +++ b/test/goroot/runner_test.go @@ -822,10 +822,17 @@ func runCase(t *testing.T, repoRoot, goroot, goCmd, llgoBin string, tc testCase, } func boundedCaseEnv(goos, goarch string, tc testCase, extra []string) []string { - if goos == "linux" && goarch == "amd64" && tc.Directive == "runoutput" && tc.RelPath == "rangegen.go" { + if (goos == "linux" && goarch == "amd64" || goos == "windows" && goarch == "arm64") && + tc.Directive == "runoutput" && tc.RelPath == "rangegen.go" { // The generated compiler torture test exceeded the 4 GiB hosted // runner guard. Bound Go and LLGo's heaps for this case only. - return upsertEnv(extra, "GOMEMLIMIT=3GiB") + limit := "3GiB" + if goos == "windows" { + // Leave room for ARM64 native LLVM/CodeView allocations, which + // are outside Go's soft memory limit. + limit = "2GiB" + } + return upsertEnv(extra, "GOMEMLIMIT="+limit) } return extra } diff --git a/test/goroot/runner_unit_test.go b/test/goroot/runner_unit_test.go index 993b2e13de..064964188f 100644 --- a/test/goroot/runner_unit_test.go +++ b/test/goroot/runner_unit_test.go @@ -468,6 +468,11 @@ func TestWasmObservedResourceExceptions(t *testing.T) { if timeout, _, match := cfg.MatchTimeout(version, "windows-mingw/amd64", rangegen); !match || timeout != 10*time.Minute { t.Errorf("%s Windows MinGW/amd64 rangegen timeout = %s, %v; want 10m, true", version, timeout, match) } + for _, platform := range []string{"windows-msvc/arm64", "windows-mingw/arm64"} { + if timeout, _, match := cfg.MatchTimeout(version, platform, rangegen); !match || timeout != 10*time.Minute { + t.Errorf("%s %s rangegen timeout = %s, %v; want 10m, true", version, platform, timeout, match) + } + } } for _, tt := range []struct { tc testCase @@ -541,6 +546,8 @@ func TestBoundedCaseEnv(t *testing.T) { }{ {"linux", "amd64", rangegen, nil, []string{"GOMEMLIMIT=3GiB"}}, {"linux", "amd64", rangegen, []string{"GOMEMLIMIT=1GiB"}, []string{"GOMEMLIMIT=3GiB"}}, + {"windows", "arm64", rangegen, nil, []string{"GOMEMLIMIT=2GiB"}}, + {"windows", "arm64", rangegen, []string{"GOMEMLIMIT=1GiB"}, []string{"GOMEMLIMIT=2GiB"}}, {"linux", "arm64", rangegen, nil, nil}, {"darwin", "arm64", rangegen, nil, nil}, {"linux", "amd64", testCase{RelPath: "other.go", Directive: "runoutput"}, nil, nil}, diff --git a/test/goroot/xfail.yaml b/test/goroot/xfail.yaml index 0acf551a74..cb6fa5a890 100644 --- a/test/goroot/xfail.yaml +++ b/test/goroot/xfail.yaml @@ -139,6 +139,11 @@ timeouts: case: rangegen.go timeout: 10m reason: both Go 1.26 and 1.27 generated builds exceeded the default 3m timeout on Windows MinGW/amd64, peaking at 3.3 GiB each; keep the case enabled with bounded build time + - platform: windows/arm64 + directive: runoutput + case: rangegen.go + timeout: 10m + reason: the generated build reached the 4 GiB guard on Windows MSVC/ARM64; allow bounded build time with the case-local 2 GiB Go heap target while retaining the host resource guard - version: go1.26 platform: linux/amd64 directive: run From 54150be4a7028357a0fa797356407b6f7e0eb2ea Mon Sep 17 00:00:00 2001 From: Li Jie Date: Tue, 6 Oct 2026 13:43:45 +0800 Subject: [PATCH 3/5] test: bound GOROOT process resource sampling --- test/goroot/proc_unix_test.go | 80 ++++++++++++++++++++++++++++++++++- test/goroot/runner_test.go | 55 ++++++++++++++++++------ 2 files changed, 122 insertions(+), 13 deletions(-) diff --git a/test/goroot/proc_unix_test.go b/test/goroot/proc_unix_test.go index b5414760cc..95f94c4fdd 100644 --- a/test/goroot/proc_unix_test.go +++ b/test/goroot/proc_unix_test.go @@ -5,6 +5,7 @@ package goroot import ( "bufio" "bytes" + "context" "errors" "fmt" "os" @@ -12,6 +13,7 @@ import ( "path/filepath" "runtime" "strconv" + "strings" "syscall" "testing" "time" @@ -30,8 +32,33 @@ func killProcessTree(cmd *exec.Cmd) { func resourceMonitoringSupported() bool { return true } +var processRSSQueryTimeout = time.Second + func processGroupRSS(processGroupID int) (uint64, error) { - output, err := exec.Command("ps", "-axo", "pgid=,rss=").Output() + // A slow process-table query must not block the command's wait or + // timeout channels. A failed sample is retried on the next RSS tick. + ctx, cancel := context.WithTimeout(context.Background(), processRSSQueryTimeout) + defer cancel() + type queryResult struct { + output []byte + err error + } + result := make(chan queryResult, 1) + go func() { + output, err := exec.CommandContext(ctx, "ps", "-axo", "pgid=,rss=").Output() + result <- queryResult{output, err} + }() + var output []byte + var err error + select { + case query := <-result: + output, err = query.output, query.err + case <-ctx.Done(): + return 0, ctx.Err() + } + if ctx.Err() != nil { + return 0, ctx.Err() + } if err != nil { return 0, err } @@ -58,6 +85,57 @@ func processGroupRSS(processGroupID int) (uint64, error) { return totalKiB << 10, nil } +func TestProcessGroupRSSQueryIsBounded(t *testing.T) { + dir := t.TempDir() + if err := os.WriteFile(filepath.Join(dir, "ps"), []byte("#!/bin/sh\nexec /bin/sleep 2\n"), 0o755); err != nil { + t.Fatal(err) + } + t.Setenv("PATH", dir+string(os.PathListSeparator)+os.Getenv("PATH")) + previous := processRSSQueryTimeout + processRSSQueryTimeout = 20 * time.Millisecond + t.Cleanup(func() { processRSSQueryTimeout = previous }) + start := time.Now() + if _, err := processGroupRSS(os.Getpid()); !errors.Is(err, context.DeadlineExceeded) { + t.Fatalf("slow RSS query error = %v, want deadline exceeded", err) + } + if elapsed := time.Since(start); elapsed >= time.Second { + t.Fatalf("slow RSS query took %s, want bounded return", elapsed) + } +} + +func TestRunProgramDeadlineAfterSlowRSSQuery(t *testing.T) { + disableSystemMemoryLimits(t) + dir := t.TempDir() + if err := os.WriteFile(filepath.Join(dir, "ps"), []byte("#!/bin/sh\nexec /bin/sleep 2\n"), 0o755); err != nil { + t.Fatal(err) + } + t.Setenv("PATH", dir+string(os.PathListSeparator)+os.Getenv("PATH")) + previousTimeout, previousPoll := processRSSQueryTimeout, *flagRSSPoll + processRSSQueryTimeout, *flagRSSPoll = 400*time.Millisecond, 5*time.Millisecond + t.Cleanup(func() { processRSSQueryTimeout, *flagRSSPoll = previousTimeout, previousPoll }) + // Both children exit while sampling is still running. Their actual wait + // completion time decides the deadline, rather than select's random pick. + for _, tc := range []struct { + name, sleep string + wantTimeout bool + }{ + {"before-deadline", "0.05", false}, + {"after-deadline", "0.25", true}, + } { + t.Run(tc.name, func(t *testing.T) { + _, _, exitCode, _, err := runProgram(t.TempDir(), "/bin/sh", os.Environ(), + 150*time.Millisecond, "-c", "sleep "+tc.sleep) + if tc.wantTimeout { + if err == nil || !strings.Contains(err.Error(), "timed out after") { + t.Fatalf("late child error = %v, want timeout", err) + } + } else if err != nil || exitCode != 0 { + t.Fatalf("completed child was reported as timed out: exit=%d, err=%v", exitCode, err) + } + }) + } +} + func TestRunProgramWaitDelayCleansDescendant(t *testing.T) { guardTestTimeout(t) disableSystemMemoryLimits(t) diff --git a/test/goroot/runner_test.go b/test/goroot/runner_test.go index e3f510074f..d956ac593f 100644 --- a/test/goroot/runner_test.go +++ b/test/goroot/runner_test.go @@ -1015,15 +1015,20 @@ func runProgram(dir, app string, env []string, timeout time.Duration, args ...st } waitCh := make(chan error, 1) + var waitFinished time.Time go func() { - waitCh <- cmd.Wait() + err := cmd.Wait() + waitFinished = time.Now() + waitCh <- err }() var err error var terminationErr error var timeoutTimer *time.Timer var timeoutCh <-chan time.Time + var deadline time.Time if timeout > 0 { + deadline = time.Now().Add(timeout) timeoutTimer = time.NewTimer(timeout) timeoutCh = timeoutTimer.C defer timeoutTimer.Stop() @@ -1052,20 +1057,23 @@ func runProgram(dir, app string, env []string, timeout time.Duration, args ...st } var peakRSS uint64 for { + // Completion takes priority over a queued sampling tick or timeout, + // especially when a slow resource query outlives the direct child. select { case err = <-waitCh: - // ErrWaitDelay identifies a pipe-copy timeout after a successful - // direct child, but an ExitError masks it after a non-zero exit. - // Either error can therefore leave descendants alive. - if err != nil { - killProcessTree(cmd) - } - goto finished + goto waited + default: + } + select { case <-timeoutCh: - terminationErr = fmt.Errorf("timed out after %s", timeout) - killProcessTree(cmd) - err = waitTerminatedProgram(cmd, waitCh, 10*time.Second) - goto finished + goto timedOut + default: + } + select { + case err = <-waitCh: + goto waited + case <-timeoutCh: + goto timedOut case <-rssCh: rssBytes, rssErr := processGroupRSS(cmd.Process.Pid) if rssErr != nil { @@ -1091,6 +1099,29 @@ func runProgram(dir, app string, env []string, timeout time.Duration, args ...st } } +timedOut: + select { + case err = <-waitCh: + goto waited + default: + } + terminationErr = fmt.Errorf("timed out after %s", timeout) + killProcessTree(cmd) + err = waitTerminatedProgram(cmd, waitCh, 10*time.Second) + goto finished +waited: + // Receiving waitCh also publishes waitFinished. Preserve the deadline + // for children that finish late, even if completion and timeout were both + // queued while a resource query was running. + if !deadline.IsZero() && waitFinished.After(deadline) { + terminationErr = fmt.Errorf("timed out after %s", timeout) + } + // ErrWaitDelay identifies a pipe-copy timeout after a successful direct + // child, but an ExitError masks it after a non-zero exit. Either error + // can therefore leave descendants alive. + if err != nil || terminationErr != nil { + killProcessTree(cmd) + } finished: if *flagRSSWarnMiB > 0 && peakRSS >= uint64(*flagRSSWarnMiB)<<20 { fmt.Fprintf(os.Stderr, "goroot resource warning: %s peak process-group RSS %s\n", filepath.Base(app), formatBytes(peakRSS)) From be59990acd4c6a507ef69249a1fc9c2f815118d8 Mon Sep 17 00:00:00 2001 From: Li Jie Date: Tue, 6 Oct 2026 13:45:03 +0800 Subject: [PATCH 4/5] docs: explain debug snapshot store typing --- ssa/di.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ssa/di.go b/ssa/di.go index 0b0fbdf056..d5f6b6d048 100644 --- a/ssa/di.go +++ b/ssa/di.go @@ -924,6 +924,8 @@ func (b Builder) doConstructDebugAddrWithStore(v Expr, t types.Type) (dbgPtr, st entryBuilder := *b entryBuilder.impl = b.Func.entryAllocaBuilder() dbgPtr = entryBuilder.AllocaT(ty) + // Store through the allocated type so closure snapshots also initialize + // their data field before exposing the source-typed debug address. store = b.Store(dbgPtr, storedValue) dbgPtr.Type = b.Prog.Pointer(v.Type) return dbgPtr, store From 5c4020c76e6b61c43c2c6f3c51ddc4af5db8ed76 Mon Sep 17 00:00:00 2001 From: Li Jie Date: Tue, 6 Oct 2026 13:58:27 +0800 Subject: [PATCH 5/5] test: leave more native memory for Windows ARM64 rangegen --- test/goroot/runner_test.go | 2 +- test/goroot/runner_unit_test.go | 4 ++-- test/goroot/xfail.yaml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/goroot/runner_test.go b/test/goroot/runner_test.go index d956ac593f..913eb43a58 100644 --- a/test/goroot/runner_test.go +++ b/test/goroot/runner_test.go @@ -830,7 +830,7 @@ func boundedCaseEnv(goos, goarch string, tc testCase, extra []string) []string { if goos == "windows" { // Leave room for ARM64 native LLVM/CodeView allocations, which // are outside Go's soft memory limit. - limit = "2GiB" + limit = "1GiB" } return upsertEnv(extra, "GOMEMLIMIT="+limit) } diff --git a/test/goroot/runner_unit_test.go b/test/goroot/runner_unit_test.go index 064964188f..acc530823a 100644 --- a/test/goroot/runner_unit_test.go +++ b/test/goroot/runner_unit_test.go @@ -546,8 +546,8 @@ func TestBoundedCaseEnv(t *testing.T) { }{ {"linux", "amd64", rangegen, nil, []string{"GOMEMLIMIT=3GiB"}}, {"linux", "amd64", rangegen, []string{"GOMEMLIMIT=1GiB"}, []string{"GOMEMLIMIT=3GiB"}}, - {"windows", "arm64", rangegen, nil, []string{"GOMEMLIMIT=2GiB"}}, - {"windows", "arm64", rangegen, []string{"GOMEMLIMIT=1GiB"}, []string{"GOMEMLIMIT=2GiB"}}, + {"windows", "arm64", rangegen, nil, []string{"GOMEMLIMIT=1GiB"}}, + {"windows", "arm64", rangegen, []string{"GOMEMLIMIT=4GiB"}, []string{"GOMEMLIMIT=1GiB"}}, {"linux", "arm64", rangegen, nil, nil}, {"darwin", "arm64", rangegen, nil, nil}, {"linux", "amd64", testCase{RelPath: "other.go", Directive: "runoutput"}, nil, nil}, diff --git a/test/goroot/xfail.yaml b/test/goroot/xfail.yaml index cb6fa5a890..050d038e2f 100644 --- a/test/goroot/xfail.yaml +++ b/test/goroot/xfail.yaml @@ -143,7 +143,7 @@ timeouts: directive: runoutput case: rangegen.go timeout: 10m - reason: the generated build reached the 4 GiB guard on Windows MSVC/ARM64; allow bounded build time with the case-local 2 GiB Go heap target while retaining the host resource guard + reason: the generated build still reached the 4 GiB guard with a 2 GiB Go heap target on Windows MSVC/ARM64; allow bounded build time with a case-local 1 GiB target while retaining the host resource guard - version: go1.26 platform: linux/amd64 directive: run