Source file
src/runtime/vdso_test.go
1
2
3
4
5
6
7 package runtime_test
8
9 import (
10 "bytes"
11 "internal/asan"
12 "internal/testenv"
13 "os"
14 "os/exec"
15 "path/filepath"
16 "syscall"
17 "testing"
18 "time"
19 )
20
21
22
23 func TestUsingVDSO(t *testing.T) {
24 if asan.Enabled {
25 t.Skip("test fails with ASAN beause the ASAN leak checker won't run under strace")
26 }
27
28 const calls = 100
29
30 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
31
32 var total int64
33 for i := 0; i < calls; i++ {
34 total += time.Now().UnixNano()
35 }
36 os.Exit(0)
37 }
38
39 t.Parallel()
40
41
42
43 strace := "/bin/strace"
44 if _, err := os.Stat(strace); err != nil {
45 strace = "/usr/bin/strace"
46 if _, err := os.Stat(strace); err != nil {
47 t.Skipf("skipping test because strace not found: %v", err)
48 }
49 }
50
51 exe, err := os.Executable()
52 if err != nil {
53 t.Skipf("skipping because Executable failed: %v", err)
54 }
55
56 t.Logf("GO_WANT_HELPER_PROCESS=1 %s -f -e clock_gettime %s -test.run=^TestUsingVDSO$", strace, exe)
57 cmd := testenv.Command(t, strace, "-f", "-e", "clock_gettime", exe, "-test.run=^TestUsingVDSO$")
58 cmd = testenv.CleanCmdEnv(cmd)
59 cmd.Env = append(cmd.Env, "GO_WANT_HELPER_PROCESS=1")
60 out, err := cmd.CombinedOutput()
61 if len(out) > 0 {
62 t.Logf("%s", out)
63 }
64 if err != nil {
65 if err := err.(*exec.ExitError); err != nil && err.Sys().(syscall.WaitStatus).Signaled() {
66 if !bytes.Contains(out, []byte("+++ killed by")) {
67
68
69
70
71 t.Log(err)
72 testenv.SkipFlaky(t, 63734)
73 }
74 }
75 t.Fatal(err)
76 }
77
78 if got := bytes.Count(out, []byte("gettime")); got >= calls {
79 t.Logf("found %d gettime calls, want < %d", got, calls)
80
81
82 tempdir := t.TempDir()
83 cfn := filepath.Join(tempdir, "time.c")
84 cexe := filepath.Join(tempdir, "time")
85 if err := os.WriteFile(cfn, []byte(vdsoCProgram), 0o644); err != nil {
86 t.Fatal(err)
87 }
88 cc := os.Getenv("CC")
89 if cc == "" {
90 cc, err = exec.LookPath("gcc")
91 if err != nil {
92 cc, err = exec.LookPath("clang")
93 if err != nil {
94 t.Skip("can't verify VDSO status, no C compiler")
95 }
96 }
97 }
98
99 t.Logf("%s -o %s %s", cc, cexe, cfn)
100 cmd = testenv.Command(t, cc, "-o", cexe, cfn)
101 cmd = testenv.CleanCmdEnv(cmd)
102 out, err = cmd.CombinedOutput()
103 if len(out) > 0 {
104 t.Logf("%s", out)
105 }
106 if err != nil {
107 t.Skipf("can't verify VDSO status, C compiled failed: %v", err)
108 }
109
110 t.Logf("%s -f -e clock_gettime %s", strace, cexe)
111 cmd = testenv.Command(t, strace, "-f", "-e", "clock_gettime", cexe)
112 cmd = testenv.CleanCmdEnv(cmd)
113 out, err = cmd.CombinedOutput()
114 if len(out) > 0 {
115 t.Logf("%s", out)
116 }
117 if err != nil {
118 t.Skipf("can't verify VDSO status, C program failed: %v", err)
119 }
120
121 if cgot := bytes.Count(out, []byte("gettime")); cgot >= 100 {
122 t.Logf("found %d gettime calls, want < %d", cgot, 100)
123 t.Log("C program does not use VDSO either")
124 return
125 }
126
127
128
129 t.Errorf("did not use VDSO system call")
130 }
131 }
132
133 const vdsoCProgram = `
134 #include <stdio.h>
135 #include <time.h>
136
137 int main() {
138 int i;
139 time_t tot;
140 for (i = 0; i < 100; i++) {
141 struct timespec ts;
142 clock_gettime(CLOCK_MONOTONIC, &ts);
143 tot += ts.tv_nsec;
144 }
145 printf("%d\n", (int)(tot));
146 return 0;
147 }
148 `
149
View as plain text