Source file
src/runtime/signal_windows_test.go
1
2
3
4
5 package runtime_test
6
7 import (
8 "bufio"
9 "bytes"
10 "fmt"
11 "internal/testenv"
12 "os/exec"
13 "path/filepath"
14 "runtime"
15 "strings"
16 "syscall"
17 "testing"
18 )
19
20 func TestVectoredHandlerExceptionInNonGoThread(t *testing.T) {
21 if *flagQuick {
22 t.Skip("-quick")
23 }
24 if strings.HasPrefix(testenv.Builder(), "windows-amd64-2012") {
25 testenv.SkipFlaky(t, 49681)
26 }
27 testenv.MustHaveGoBuild(t)
28 testenv.MustHaveCGO(t)
29 testenv.MustHaveExecPath(t, "gcc")
30 testprog.Lock()
31 defer testprog.Unlock()
32 dir := t.TempDir()
33
34
35 dll := filepath.Join(dir, "veh.dll")
36 cmd := exec.Command("gcc", "-shared", "-o", dll, "testdata/testwinlibthrow/veh.c")
37 out, err := testenv.CleanCmdEnv(cmd).CombinedOutput()
38 if err != nil {
39 t.Fatalf("failed to build c exe: %s\n%s", err, out)
40 }
41
42
43 exe := filepath.Join(dir, "test.exe")
44 cmd = exec.Command(testenv.GoToolPath(t), "build", "-o", exe, "testdata/testwinlibthrow/main.go")
45 out, err = testenv.CleanCmdEnv(cmd).CombinedOutput()
46 if err != nil {
47 t.Fatalf("failed to build go library: %s\n%s", err, out)
48 }
49
50
51 cmd = exec.Command(exe)
52 out, err = testenv.CleanCmdEnv(cmd).CombinedOutput()
53 if err == nil {
54 t.Fatal("error expected")
55 }
56 if _, ok := err.(*exec.ExitError); ok && len(out) > 0 {
57 if !bytes.Contains(out, []byte("Exception 0x2a")) {
58 t.Fatalf("unexpected failure while running executable: %s\n%s", err, out)
59 }
60 } else {
61 t.Fatalf("unexpected error while running executable: %s\n%s", err, out)
62 }
63
64 cmd = exec.Command(exe, "thread")
65 out, err = testenv.CleanCmdEnv(cmd).CombinedOutput()
66 if err == nil {
67 t.Fatal("error expected")
68 }
69 if err, ok := err.(*exec.ExitError); ok {
70 if err.ExitCode() != 42 {
71 t.Fatalf("unexpected failure while running executable: %s\n%s", err, out)
72 }
73 } else {
74 t.Fatalf("unexpected error while running executable: %s\n%s", err, out)
75 }
76 }
77
78 func TestVectoredHandlerDontCrashOnLibrary(t *testing.T) {
79 if *flagQuick {
80 t.Skip("-quick")
81 }
82
83 testenv.MustHaveGoBuild(t)
84 testenv.MustHaveCGO(t)
85 testenv.MustHaveExecPath(t, "gcc")
86 testprog.Lock()
87 defer testprog.Unlock()
88 dir := t.TempDir()
89
90
91 dll := filepath.Join(dir, "testwinlib.dll")
92 cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", dll, "-buildmode", "c-shared", "testdata/testwinlib/main.go")
93 out, err := testenv.CleanCmdEnv(cmd).CombinedOutput()
94 if err != nil {
95 t.Fatalf("failed to build go library: %s\n%s", err, out)
96 }
97
98
99 exe := filepath.Join(dir, "test.exe")
100 cmd = exec.Command("gcc", "-L"+dir, "-I"+dir, "-ltestwinlib", "-o", exe, "testdata/testwinlib/main.c")
101 out, err = testenv.CleanCmdEnv(cmd).CombinedOutput()
102 if err != nil {
103 t.Fatalf("failed to build c exe: %s\n%s", err, out)
104 }
105
106
107 cmd = exec.Command(exe)
108 out, err = testenv.CleanCmdEnv(cmd).CombinedOutput()
109 if err != nil {
110 t.Fatalf("failure while running executable: %s\n%s", err, out)
111 }
112 var expectedOutput string
113 if runtime.GOARCH == "arm64" {
114
115 expectedOutput = "exceptionCount: 1\ncontinueCount: 1\nunhandledCount: 0\n"
116 } else {
117 expectedOutput = "exceptionCount: 1\ncontinueCount: 1\nunhandledCount: 1\n"
118 }
119
120 cleanedOut := strings.ReplaceAll(string(out), "\r\n", "\n")
121 if cleanedOut != expectedOutput {
122 t.Errorf("expected output %q, got %q", expectedOutput, cleanedOut)
123 }
124 }
125
126 func sendCtrlBreak(pid int) error {
127 kernel32, err := syscall.LoadDLL("kernel32.dll")
128 if err != nil {
129 return fmt.Errorf("LoadDLL: %v\n", err)
130 }
131 generateEvent, err := kernel32.FindProc("GenerateConsoleCtrlEvent")
132 if err != nil {
133 return fmt.Errorf("FindProc: %v\n", err)
134 }
135 result, _, err := generateEvent.Call(syscall.CTRL_BREAK_EVENT, uintptr(pid))
136 if result == 0 {
137 return fmt.Errorf("GenerateConsoleCtrlEvent: %v\n", err)
138 }
139 return nil
140 }
141
142
143
144 func TestCtrlHandler(t *testing.T) {
145 testenv.MustHaveGoBuild(t)
146 t.Parallel()
147
148
149 exe := filepath.Join(t.TempDir(), "test.exe")
150 cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", exe, "testdata/testwinsignal/main.go")
151 out, err := testenv.CleanCmdEnv(cmd).CombinedOutput()
152 if err != nil {
153 t.Fatalf("failed to build go exe: %v\n%s", err, out)
154 }
155
156
157 cmd = exec.Command(exe)
158 var stdout strings.Builder
159 var stderr strings.Builder
160 cmd.Stdout = &stdout
161 cmd.Stderr = &stderr
162 inPipe, err := cmd.StdinPipe()
163 if err != nil {
164 t.Fatalf("Failed to create stdin pipe: %v", err)
165 }
166
167 defer inPipe.Close()
168
169
170 const _CREATE_NEW_CONSOLE = 0x00000010
171 cmd.SysProcAttr = &syscall.SysProcAttr{
172 CreationFlags: _CREATE_NEW_CONSOLE,
173 HideWindow: true,
174 }
175 if err := cmd.Start(); err != nil {
176 t.Fatalf("Start failed: %v", err)
177 }
178 defer func() {
179 cmd.Process.Kill()
180 cmd.Wait()
181 }()
182
183
184 if err := cmd.Wait(); err != nil {
185 t.Fatalf("Program exited with error: %v\n%s", err, &stderr)
186 }
187
188
189 if expected, got := syscall.SIGTERM.String(), strings.TrimSpace(stdout.String()); expected != got {
190 t.Fatalf("Expected '%s' got: %s", expected, got)
191 }
192 }
193
194
195
196 func TestLibraryCtrlHandler(t *testing.T) {
197 if *flagQuick {
198 t.Skip("-quick")
199 }
200 if runtime.GOARCH != "amd64" {
201 t.Skip("this test can only run on windows/amd64")
202 }
203 testenv.MustHaveGoBuild(t)
204 testenv.MustHaveCGO(t)
205 testenv.MustHaveExecPath(t, "gcc")
206 testprog.Lock()
207 defer testprog.Unlock()
208 dir := t.TempDir()
209
210
211 dll := filepath.Join(dir, "dummy.dll")
212 cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", dll, "-buildmode", "c-shared", "testdata/testwinlibsignal/dummy.go")
213 out, err := testenv.CleanCmdEnv(cmd).CombinedOutput()
214 if err != nil {
215 t.Fatalf("failed to build go library: %s\n%s", err, out)
216 }
217
218
219 exe := filepath.Join(dir, "test.exe")
220 cmd = exec.Command("gcc", "-o", exe, "testdata/testwinlibsignal/main.c")
221 out, err = testenv.CleanCmdEnv(cmd).CombinedOutput()
222 if err != nil {
223 t.Fatalf("failed to build c exe: %s\n%s", err, out)
224 }
225
226
227 cmd = exec.Command(exe)
228 var stderr bytes.Buffer
229 cmd.Stderr = &stderr
230 outPipe, err := cmd.StdoutPipe()
231 if err != nil {
232 t.Fatalf("Failed to create stdout pipe: %v", err)
233 }
234 outReader := bufio.NewReader(outPipe)
235
236 cmd.SysProcAttr = &syscall.SysProcAttr{
237 CreationFlags: syscall.CREATE_NEW_PROCESS_GROUP,
238 }
239 if err := cmd.Start(); err != nil {
240 t.Fatalf("Start failed: %v", err)
241 }
242
243 errCh := make(chan error, 1)
244 go func() {
245 if line, err := outReader.ReadString('\n'); err != nil {
246 errCh <- fmt.Errorf("could not read stdout: %v", err)
247 } else if strings.TrimSpace(line) != "ready" {
248 errCh <- fmt.Errorf("unexpected message: %v", line)
249 } else {
250 errCh <- sendCtrlBreak(cmd.Process.Pid)
251 }
252 }()
253
254 if err := <-errCh; err != nil {
255 t.Fatal(err)
256 }
257 if err := cmd.Wait(); err != nil {
258 t.Fatalf("Program exited with error: %v\n%s", err, &stderr)
259 }
260 }
261
262 func TestIssue59213(t *testing.T) {
263 if runtime.GOOS != "windows" {
264 t.Skip("skipping windows only test")
265 }
266 if *flagQuick {
267 t.Skip("-quick")
268 }
269 testenv.MustHaveGoBuild(t)
270 testenv.MustHaveCGO(t)
271
272 goEnv := func(arg string) string {
273 cmd := testenv.Command(t, testenv.GoToolPath(t), "env", arg)
274 cmd.Stderr = new(bytes.Buffer)
275
276 line, err := cmd.Output()
277 if err != nil {
278 t.Fatalf("%v: %v\n%s", cmd, err, cmd.Stderr)
279 }
280 out := string(bytes.TrimSpace(line))
281 t.Logf("%v: %q", cmd, out)
282 return out
283 }
284
285 cc := goEnv("CC")
286 cgoCflags := goEnv("CGO_CFLAGS")
287
288 t.Parallel()
289
290 tmpdir := t.TempDir()
291 dllfile := filepath.Join(tmpdir, "test.dll")
292 exefile := filepath.Join(tmpdir, "gotest.exe")
293
294
295 cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-o", dllfile, "-buildmode", "c-shared", "testdata/testwintls/main.go")
296 out, err := testenv.CleanCmdEnv(cmd).CombinedOutput()
297 if err != nil {
298 t.Fatalf("failed to build go library: %s\n%s", err, out)
299 }
300
301
302 cmd = testenv.Command(t, cc, "-o", exefile, "testdata/testwintls/main.c")
303 testenv.CleanCmdEnv(cmd)
304 cmd.Env = append(cmd.Env, "CGO_CFLAGS="+cgoCflags)
305 out, err = cmd.CombinedOutput()
306 if err != nil {
307 t.Fatalf("failed to build c exe: %s\n%s", err, out)
308 }
309
310
311 cmd = testenv.Command(t, exefile, dllfile, "GoFunc")
312 out, err = testenv.CleanCmdEnv(cmd).CombinedOutput()
313 if err != nil {
314 t.Fatalf("failed: %s\n%s", err, out)
315 }
316 }
317
View as plain text