1
2
3
4
5 package test
6
7 import (
8 "internal/platform"
9 "internal/testenv"
10 "os"
11 "path/filepath"
12 "runtime"
13 "strings"
14 "testing"
15 )
16
17
18
19
20
21
22 func TestIssue81478(t *testing.T) {
23 if !platform.RaceDetectorSupported(runtime.GOOS, runtime.GOARCH) {
24 t.Skipf("race detector not supported on %s/%s", runtime.GOOS, runtime.GOARCH)
25 }
26 testenv.MustHaveGoBuild(t)
27
28 dir := t.TempDir()
29 src := filepath.Join(dir, "x.go")
30 if err := os.WriteFile(src, []byte(issue81478src), 0644); err != nil {
31 t.Fatalf("could not write file: %v", err)
32 }
33
34 cmd := testenv.Command(t, testenv.GoToolPath(t), "tool", "compile", "-race", "-p=main", "-S", "-o", filepath.Join(dir, "x.o"), src)
35 out, err := cmd.CombinedOutput()
36 if err != nil {
37 t.Fatalf("compile failed: %v\n%s", err, out)
38 }
39
40
41
42
43 for _, wrapper := range []string{"main.(*W).F", "main.(*S).G"} {
44 body, ok := funcBody(string(out), wrapper)
45 if !ok {
46 t.Errorf("no assembly found for %s", wrapper)
47 continue
48 }
49 enter := strings.Count(body, "runtime.racefuncenter")
50 exit := strings.Count(body, "runtime.racefuncexit")
51 if enter == 0 {
52 t.Errorf("%s: not instrumented for the race detector\n%s", wrapper, body)
53 } else if enter != exit {
54 t.Errorf("%s: unbalanced race instrumentation: %d racefuncenter, %d racefuncexit\n%s", wrapper, enter, exit, body)
55 }
56 }
57 }
58
59
60
61 func funcBody(out, fn string) (string, bool) {
62 lines := strings.Split(out, "\n")
63 for i, line := range lines {
64 if !strings.HasPrefix(line, fn+" STEXT") {
65 continue
66 }
67 end := i + 1
68 for end < len(lines) && strings.HasPrefix(lines[end], "\t") {
69 end++
70 }
71 return strings.Join(lines[i:end], "\n"), true
72 }
73 return "", false
74 }
75
76 var issue81478src = `
77 package main
78
79 type I interface{ F() }
80
81 type T struct{ n int }
82
83 func (t *T) F() { t.n++ }
84
85 //go:noinline
86 func (t *T) G() { t.n++ }
87
88 // W.F is a wrapper around an embedded interface method.
89 type W struct{ I }
90
91 // S.G is a wrapper around an embedded pointer's method.
92 type S struct{ *T }
93
94 var _ I = &W{}
95 var _ = (&S{}).G
96
97 func main() {}
98 `
99
View as plain text