summaryrefslogtreecommitdiffstats
path: root/src/cmd/link/internal/ld/stackcheck_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/link/internal/ld/stackcheck_test.go')
-rw-r--r--src/cmd/link/internal/ld/stackcheck_test.go87
1 files changed, 87 insertions, 0 deletions
diff --git a/src/cmd/link/internal/ld/stackcheck_test.go b/src/cmd/link/internal/ld/stackcheck_test.go
new file mode 100644
index 0000000..dd7e205
--- /dev/null
+++ b/src/cmd/link/internal/ld/stackcheck_test.go
@@ -0,0 +1,87 @@
+// Copyright 2022 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 ld
+
+import (
+ "fmt"
+ "internal/testenv"
+ "os"
+ "regexp"
+ "strconv"
+ "testing"
+)
+
+// See also $GOROOT/test/nosplit.go for multi-platform edge case tests.
+
+func TestStackCheckOutput(t *testing.T) {
+ testenv.MustHaveGoBuild(t)
+ t.Parallel()
+
+ cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-o", os.DevNull, "./testdata/stackcheck")
+ // The rules for computing frame sizes on all of the
+ // architectures are complicated, so just do this on amd64.
+ cmd.Env = append(os.Environ(), "GOARCH=amd64", "GOOS=linux")
+ outB, err := cmd.CombinedOutput()
+
+ if err == nil {
+ t.Fatalf("expected link to fail")
+ }
+ out := string(outB)
+
+ t.Logf("linker output:\n%s", out)
+
+ // Get expected limit.
+ limitRe := regexp.MustCompile(`nosplit stack over (\d+) byte limit`)
+ m := limitRe.FindStringSubmatch(out)
+ if m == nil {
+ t.Fatalf("no overflow errors in output")
+ }
+ limit, _ := strconv.Atoi(m[1])
+
+ wantMap := map[string]string{
+ "main.startSelf": fmt.Sprintf(
+ `main.startSelf<0>
+ grows 1008 bytes
+ %d bytes over limit
+`, 1008-limit),
+ "main.startChain": fmt.Sprintf(
+ `main.startChain<0>
+ grows 32 bytes, calls main.chain0<0>
+ grows 48 bytes, calls main.chainEnd<0>
+ grows 1008 bytes
+ %d bytes over limit
+ grows 32 bytes, calls main.chain2<0>
+ grows 80 bytes, calls main.chainEnd<0>
+ grows 1008 bytes
+ %d bytes over limit
+`, 32+48+1008-limit, 32+80+1008-limit),
+ "main.startRec": `main.startRec<0>
+ grows 8 bytes, calls main.startRec0<0>
+ grows 8 bytes, calls main.startRec<0>
+ infinite cycle
+`,
+ }
+
+ // Parse stanzas
+ stanza := regexp.MustCompile(`^(.*): nosplit stack over \d+ byte limit\n(.*\n(?: .*\n)*)`)
+ // Strip comments from cmd/go
+ out = regexp.MustCompile(`(?m)^#.*\n`).ReplaceAllString(out, "")
+ for len(out) > 0 {
+ m := stanza.FindStringSubmatch(out)
+ if m == nil {
+ t.Fatalf("unexpected output:\n%s", out)
+ }
+ out = out[len(m[0]):]
+ fn := m[1]
+ got := m[2]
+
+ want, ok := wantMap[fn]
+ if !ok {
+ t.Errorf("unexpected function: %s", fn)
+ } else if want != got {
+ t.Errorf("want:\n%sgot:\n%s", want, got)
+ }
+ }
+}