* tree-vect-loop-manip.c (vect_do_peeling): Do not use
[official-gcc.git] / libgo / misc / cgo / testcarchive / carchive_test.go
blob4865b806a3e20c64e04161b2d41c44b742a939ba
1 // Copyright 2016 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 package carchive_test
7 import (
8 "bufio"
9 "debug/elf"
10 "fmt"
11 "io/ioutil"
12 "os"
13 "os/exec"
14 "path/filepath"
15 "runtime"
16 "strings"
17 "syscall"
18 "testing"
19 "time"
20 "unicode"
23 // Program to run.
24 var bin []string
26 // C compiler with args (from $(go env CC) $(go env GOGCCFLAGS)).
27 var cc []string
29 // An environment with GOPATH=$(pwd).
30 var gopathEnv []string
32 // ".exe" on Windows.
33 var exeSuffix string
35 var GOOS, GOARCH string
36 var libgodir string
38 func init() {
39 GOOS = goEnv("GOOS")
40 GOARCH = goEnv("GOARCH")
41 bin = cmdToRun("./testp")
43 ccOut := goEnv("CC")
44 cc = []string{string(ccOut)}
46 out := goEnv("GOGCCFLAGS")
47 quote := '\000'
48 start := 0
49 lastSpace := true
50 backslash := false
51 s := string(out)
52 for i, c := range s {
53 if quote == '\000' && unicode.IsSpace(c) {
54 if !lastSpace {
55 cc = append(cc, s[start:i])
56 lastSpace = true
58 } else {
59 if lastSpace {
60 start = i
61 lastSpace = false
63 if quote == '\000' && !backslash && (c == '"' || c == '\'') {
64 quote = c
65 backslash = false
66 } else if !backslash && quote == c {
67 quote = '\000'
68 } else if (quote == '\000' || quote == '"') && !backslash && c == '\\' {
69 backslash = true
70 } else {
71 backslash = false
75 if !lastSpace {
76 cc = append(cc, s[start:])
79 if GOOS == "darwin" {
80 // For Darwin/ARM.
81 // TODO(crawshaw): can we do better?
82 cc = append(cc, []string{"-framework", "CoreFoundation", "-framework", "Foundation"}...)
84 libgodir = GOOS + "_" + GOARCH
85 if runtime.Compiler == "gccgo" {
86 libgodir = "gccgo_" + libgodir + "_fPIC"
87 } else {
88 switch GOOS {
89 case "darwin":
90 if GOARCH == "arm" || GOARCH == "arm64" {
91 libgodir += "_shared"
93 case "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris":
94 libgodir += "_shared"
97 cc = append(cc, "-I", filepath.Join("pkg", libgodir))
99 // Build an environment with GOPATH=$(pwd)
100 env := os.Environ()
101 var n []string
102 for _, e := range env {
103 if !strings.HasPrefix(e, "GOPATH=") {
104 n = append(n, e)
107 dir, err := os.Getwd()
108 if err != nil {
109 fmt.Fprintln(os.Stderr, err)
110 os.Exit(2)
112 n = append(n, "GOPATH="+dir)
113 gopathEnv = n
115 if GOOS == "windows" {
116 exeSuffix = ".exe"
120 func goEnv(key string) string {
121 out, err := exec.Command("go", "env", key).Output()
122 if err != nil {
123 fmt.Fprintf(os.Stderr, "go env %s failed:\n%s\n", key, err)
124 if ee, ok := err.(*exec.ExitError); ok {
125 fmt.Fprintf(os.Stderr, "%s", ee.Stderr)
127 os.Exit(2)
129 return strings.TrimSpace(string(out))
132 func cmdToRun(name string) []string {
133 execScript := "go_" + goEnv("GOOS") + "_" + goEnv("GOARCH") + "_exec"
134 executor, err := exec.LookPath(execScript)
135 if err != nil {
136 return []string{name}
138 return []string{executor, name}
141 func testInstall(t *testing.T, exe, libgoa, libgoh string, buildcmd ...string) {
142 cmd := exec.Command(buildcmd[0], buildcmd[1:]...)
143 cmd.Env = gopathEnv
144 if out, err := cmd.CombinedOutput(); err != nil {
145 t.Logf("%s", out)
146 t.Fatal(err)
148 defer func() {
149 os.Remove(libgoa)
150 os.Remove(libgoh)
153 ccArgs := append(cc, "-o", exe, "main.c")
154 if GOOS == "windows" {
155 ccArgs = append(ccArgs, "main_windows.c", libgoa, "-lntdll", "-lws2_32", "-lwinmm")
156 } else {
157 ccArgs = append(ccArgs, "main_unix.c", libgoa)
159 if runtime.Compiler == "gccgo" {
160 ccArgs = append(ccArgs, "-lgo")
162 t.Log(ccArgs)
163 if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
164 t.Logf("%s", out)
165 t.Fatal(err)
167 defer os.Remove(exe)
169 binArgs := append(cmdToRun(exe), "arg1", "arg2")
170 cmd = exec.Command(binArgs[0], binArgs[1:]...)
171 if runtime.Compiler == "gccgo" {
172 cmd.Env = append(os.Environ(), "GCCGO=1")
174 if out, err := cmd.CombinedOutput(); err != nil {
175 t.Logf("%s", out)
176 t.Fatal(err)
180 func TestInstall(t *testing.T) {
181 defer os.RemoveAll("pkg")
183 libgoa := "libgo.a"
184 if runtime.Compiler == "gccgo" {
185 libgoa = "liblibgo.a"
188 testInstall(t, "./testp1"+exeSuffix,
189 filepath.Join("pkg", libgodir, libgoa),
190 filepath.Join("pkg", libgodir, "libgo.h"),
191 "go", "install", "-buildmode=c-archive", "libgo")
193 // Test building libgo other than installing it.
194 // Header files are now present.
195 testInstall(t, "./testp2"+exeSuffix, "libgo.a", "libgo.h",
196 "go", "build", "-buildmode=c-archive", filepath.Join("src", "libgo", "libgo.go"))
198 testInstall(t, "./testp3"+exeSuffix, "libgo.a", "libgo.h",
199 "go", "build", "-buildmode=c-archive", "-o", "libgo.a", "libgo")
202 func TestEarlySignalHandler(t *testing.T) {
203 switch GOOS {
204 case "darwin":
205 switch GOARCH {
206 case "arm", "arm64":
207 t.Skipf("skipping on %s/%s; see https://golang.org/issue/13701", GOOS, GOARCH)
209 case "windows":
210 t.Skip("skipping signal test on Windows")
213 defer func() {
214 os.Remove("libgo2.a")
215 os.Remove("libgo2.h")
216 os.Remove("testp")
217 os.RemoveAll("pkg")
220 cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo2.a", "libgo2")
221 cmd.Env = gopathEnv
222 if out, err := cmd.CombinedOutput(); err != nil {
223 t.Logf("%s", out)
224 t.Fatal(err)
227 ccArgs := append(cc, "-o", "testp"+exeSuffix, "main2.c", "libgo2.a")
228 if runtime.Compiler == "gccgo" {
229 ccArgs = append(ccArgs, "-lgo")
231 if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
232 t.Logf("%s", out)
233 t.Fatal(err)
236 if out, err := exec.Command(bin[0], bin[1:]...).CombinedOutput(); err != nil {
237 t.Logf("%s", out)
238 t.Fatal(err)
242 func TestSignalForwarding(t *testing.T) {
243 checkSignalForwardingTest(t)
245 defer func() {
246 os.Remove("libgo2.a")
247 os.Remove("libgo2.h")
248 os.Remove("testp")
249 os.RemoveAll("pkg")
252 cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo2.a", "libgo2")
253 cmd.Env = gopathEnv
254 if out, err := cmd.CombinedOutput(); err != nil {
255 t.Logf("%s", out)
256 t.Fatal(err)
259 ccArgs := append(cc, "-o", "testp"+exeSuffix, "main5.c", "libgo2.a")
260 if runtime.Compiler == "gccgo" {
261 ccArgs = append(ccArgs, "-lgo")
263 if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
264 t.Logf("%s", out)
265 t.Fatal(err)
268 cmd = exec.Command(bin[0], append(bin[1:], "1")...)
270 out, err := cmd.CombinedOutput()
271 t.Logf("%s", out)
272 expectSignal(t, err, syscall.SIGSEGV)
274 // Test SIGPIPE forwarding
275 cmd = exec.Command(bin[0], append(bin[1:], "3")...)
277 out, err = cmd.CombinedOutput()
278 t.Logf("%s", out)
279 expectSignal(t, err, syscall.SIGPIPE)
282 func TestSignalForwardingExternal(t *testing.T) {
283 checkSignalForwardingTest(t)
285 defer func() {
286 os.Remove("libgo2.a")
287 os.Remove("libgo2.h")
288 os.Remove("testp")
289 os.RemoveAll("pkg")
292 cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo2.a", "libgo2")
293 cmd.Env = gopathEnv
294 if out, err := cmd.CombinedOutput(); err != nil {
295 t.Logf("%s", out)
296 t.Fatal(err)
299 ccArgs := append(cc, "-o", "testp"+exeSuffix, "main5.c", "libgo2.a")
300 if runtime.Compiler == "gccgo" {
301 ccArgs = append(ccArgs, "-lgo")
303 if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
304 t.Logf("%s", out)
305 t.Fatal(err)
308 // We want to send the process a signal and see if it dies.
309 // Normally the signal goes to the C thread, the Go signal
310 // handler picks it up, sees that it is running in a C thread,
311 // and the program dies. Unfortunately, occasionally the
312 // signal is delivered to a Go thread, which winds up
313 // discarding it because it was sent by another program and
314 // there is no Go handler for it. To avoid this, run the
315 // program several times in the hopes that it will eventually
316 // fail.
317 const tries = 20
318 for i := 0; i < tries; i++ {
319 cmd = exec.Command(bin[0], append(bin[1:], "2")...)
321 stderr, err := cmd.StderrPipe()
322 if err != nil {
323 t.Fatal(err)
325 defer stderr.Close()
327 r := bufio.NewReader(stderr)
329 err = cmd.Start()
331 if err != nil {
332 t.Fatal(err)
335 // Wait for trigger to ensure that the process is started.
336 ok, err := r.ReadString('\n')
338 // Verify trigger.
339 if err != nil || ok != "OK\n" {
340 t.Fatalf("Did not receive OK signal")
343 // Give the program a chance to enter the sleep function.
344 time.Sleep(time.Millisecond)
346 cmd.Process.Signal(syscall.SIGSEGV)
348 err = cmd.Wait()
350 if err == nil {
351 continue
354 if expectSignal(t, err, syscall.SIGSEGV) {
355 return
359 t.Errorf("program succeeded unexpectedly %d times", tries)
362 // checkSignalForwardingTest calls t.Skip if the SignalForwarding test
363 // doesn't work on this platform.
364 func checkSignalForwardingTest(t *testing.T) {
365 switch GOOS {
366 case "darwin":
367 switch GOARCH {
368 case "arm", "arm64":
369 t.Skipf("skipping on %s/%s; see https://golang.org/issue/13701", GOOS, GOARCH)
371 case "windows":
372 t.Skip("skipping signal test on Windows")
376 // expectSignal checks that err, the exit status of a test program,
377 // shows a failure due to a specific signal. Returns whether we found
378 // the expected signal.
379 func expectSignal(t *testing.T, err error, sig syscall.Signal) bool {
380 if err == nil {
381 t.Error("test program succeeded unexpectedly")
382 } else if ee, ok := err.(*exec.ExitError); !ok {
383 t.Errorf("error (%v) has type %T; expected exec.ExitError", err, err)
384 } else if ws, ok := ee.Sys().(syscall.WaitStatus); !ok {
385 t.Errorf("error.Sys (%v) has type %T; expected syscall.WaitStatus", ee.Sys(), ee.Sys())
386 } else if !ws.Signaled() || ws.Signal() != sig {
387 t.Errorf("got %v; expected signal %v", ee, sig)
388 } else {
389 return true
391 return false
394 func TestOsSignal(t *testing.T) {
395 switch GOOS {
396 case "windows":
397 t.Skip("skipping signal test on Windows")
400 defer func() {
401 os.Remove("libgo3.a")
402 os.Remove("libgo3.h")
403 os.Remove("testp")
404 os.RemoveAll("pkg")
407 cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo3.a", "libgo3")
408 cmd.Env = gopathEnv
409 if out, err := cmd.CombinedOutput(); err != nil {
410 t.Logf("%s", out)
411 t.Fatal(err)
414 ccArgs := append(cc, "-o", "testp"+exeSuffix, "main3.c", "libgo3.a")
415 if runtime.Compiler == "gccgo" {
416 ccArgs = append(ccArgs, "-lgo")
418 if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
419 t.Logf("%s", out)
420 t.Fatal(err)
423 if out, err := exec.Command(bin[0], bin[1:]...).CombinedOutput(); err != nil {
424 t.Logf("%s", out)
425 t.Fatal(err)
429 func TestSigaltstack(t *testing.T) {
430 switch GOOS {
431 case "windows":
432 t.Skip("skipping signal test on Windows")
435 defer func() {
436 os.Remove("libgo4.a")
437 os.Remove("libgo4.h")
438 os.Remove("testp")
439 os.RemoveAll("pkg")
442 cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo4.a", "libgo4")
443 cmd.Env = gopathEnv
444 if out, err := cmd.CombinedOutput(); err != nil {
445 t.Logf("%s", out)
446 t.Fatal(err)
449 ccArgs := append(cc, "-o", "testp"+exeSuffix, "main4.c", "libgo4.a")
450 if runtime.Compiler == "gccgo" {
451 ccArgs = append(ccArgs, "-lgo")
453 if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
454 t.Logf("%s", out)
455 t.Fatal(err)
458 if out, err := exec.Command(bin[0], bin[1:]...).CombinedOutput(); err != nil {
459 t.Logf("%s", out)
460 t.Fatal(err)
464 const testar = `#!/usr/bin/env bash
465 while expr $1 : '[-]' >/dev/null; do
466 shift
467 done
468 echo "testar" > $1
469 echo "testar" > PWD/testar.ran
472 func TestExtar(t *testing.T) {
473 switch GOOS {
474 case "windows":
475 t.Skip("skipping signal test on Windows")
477 if runtime.Compiler == "gccgo" {
478 t.Skip("skipping -extar test when using gccgo")
481 defer func() {
482 os.Remove("libgo4.a")
483 os.Remove("libgo4.h")
484 os.Remove("testar")
485 os.Remove("testar.ran")
486 os.RemoveAll("pkg")
489 os.Remove("testar")
490 dir, err := os.Getwd()
491 if err != nil {
492 t.Fatal(err)
494 s := strings.Replace(testar, "PWD", dir, 1)
495 if err := ioutil.WriteFile("testar", []byte(s), 0777); err != nil {
496 t.Fatal(err)
499 cmd := exec.Command("go", "build", "-buildmode=c-archive", "-ldflags=-extar="+filepath.Join(dir, "testar"), "-o", "libgo4.a", "libgo4")
500 cmd.Env = gopathEnv
501 if out, err := cmd.CombinedOutput(); err != nil {
502 t.Logf("%s", out)
503 t.Fatal(err)
506 if _, err := os.Stat("testar.ran"); err != nil {
507 if os.IsNotExist(err) {
508 t.Error("testar does not exist after go build")
509 } else {
510 t.Errorf("error checking testar: %v", err)
515 func TestPIE(t *testing.T) {
516 switch GOOS {
517 case "windows", "darwin", "plan9":
518 t.Skipf("skipping PIE test on %s", GOOS)
521 defer func() {
522 os.Remove("testp" + exeSuffix)
523 os.RemoveAll("pkg")
526 cmd := exec.Command("go", "install", "-buildmode=c-archive", "libgo")
527 cmd.Env = gopathEnv
528 if out, err := cmd.CombinedOutput(); err != nil {
529 t.Logf("%s", out)
530 t.Fatal(err)
533 libgoa := "libgo.a"
534 if runtime.Compiler == "gccgo" {
535 libgoa = "liblibgo.a"
538 ccArgs := append(cc, "-fPIE", "-pie", "-o", "testp"+exeSuffix, "main.c", "main_unix.c", filepath.Join("pkg", libgodir, libgoa))
539 if runtime.Compiler == "gccgo" {
540 ccArgs = append(ccArgs, "-lgo")
542 if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
543 t.Logf("%s", out)
544 t.Fatal(err)
547 binArgs := append(bin, "arg1", "arg2")
548 cmd = exec.Command(binArgs[0], binArgs[1:]...)
549 if runtime.Compiler == "gccgo" {
550 cmd.Env = append(os.Environ(), "GCCGO=1")
552 if out, err := cmd.CombinedOutput(); err != nil {
553 t.Logf("%s", out)
554 t.Fatal(err)
557 f, err := elf.Open("testp" + exeSuffix)
558 if err != nil {
559 t.Fatal("elf.Open failed: ", err)
561 defer f.Close()
562 if hasDynTag(t, f, elf.DT_TEXTREL) {
563 t.Errorf("%s has DT_TEXTREL flag", "testp"+exeSuffix)
567 func hasDynTag(t *testing.T, f *elf.File, tag elf.DynTag) bool {
568 ds := f.SectionByType(elf.SHT_DYNAMIC)
569 if ds == nil {
570 t.Error("no SHT_DYNAMIC section")
571 return false
573 d, err := ds.Data()
574 if err != nil {
575 t.Errorf("can't read SHT_DYNAMIC contents: %v", err)
576 return false
578 for len(d) > 0 {
579 var t elf.DynTag
580 switch f.Class {
581 case elf.ELFCLASS32:
582 t = elf.DynTag(f.ByteOrder.Uint32(d[:4]))
583 d = d[8:]
584 case elf.ELFCLASS64:
585 t = elf.DynTag(f.ByteOrder.Uint64(d[:8]))
586 d = d[16:]
588 if t == tag {
589 return true
592 return false
595 func TestSIGPROF(t *testing.T) {
596 switch GOOS {
597 case "windows", "plan9":
598 t.Skipf("skipping SIGPROF test on %s", GOOS)
601 t.Parallel()
603 defer func() {
604 os.Remove("testp6" + exeSuffix)
605 os.Remove("libgo6.a")
606 os.Remove("libgo6.h")
609 cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo6.a", "libgo6")
610 cmd.Env = gopathEnv
611 if out, err := cmd.CombinedOutput(); err != nil {
612 t.Logf("%s", out)
613 t.Fatal(err)
616 ccArgs := append(cc, "-o", "testp6"+exeSuffix, "main6.c", "libgo6.a")
617 if runtime.Compiler == "gccgo" {
618 ccArgs = append(ccArgs, "-lgo")
620 if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
621 t.Logf("%s", out)
622 t.Fatal(err)
625 argv := cmdToRun("./testp6")
626 cmd = exec.Command(argv[0], argv[1:]...)
627 if out, err := cmd.CombinedOutput(); err != nil {
628 t.Logf("%s", out)
629 t.Fatal(err)
633 // TestCompileWithoutShared tests that if we compile code without the
634 // -shared option, we can put it into an archive. When we use the go
635 // tool with -buildmode=c-archive, it passes -shared to the compiler,
636 // so we override that. The go tool doesn't work this way, but Bazel
637 // will likely do it in the future. And it ought to work. This test
638 // was added because at one time it did not work on PPC GNU/Linux.
639 func TestCompileWithoutShared(t *testing.T) {
640 // For simplicity, reuse the signal forwarding test.
641 checkSignalForwardingTest(t)
643 defer func() {
644 os.Remove("libgo2.a")
645 os.Remove("libgo2.h")
648 cmd := exec.Command("go", "build", "-buildmode=c-archive", "-gcflags=-shared=false", "-o", "libgo2.a", "libgo2")
649 cmd.Env = gopathEnv
650 t.Log(cmd.Args)
651 out, err := cmd.CombinedOutput()
652 t.Logf("%s", out)
653 if err != nil {
654 t.Fatal(err)
657 exe := "./testnoshared" + exeSuffix
658 ccArgs := append(cc, "-o", exe, "main5.c", "libgo2.a")
659 if runtime.Compiler == "gccgo" {
660 ccArgs = append(ccArgs, "-lgo")
662 t.Log(ccArgs)
663 out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
664 t.Logf("%s", out)
665 if err != nil {
666 t.Fatal(err)
668 defer os.Remove(exe)
670 binArgs := append(cmdToRun(exe), "3")
671 t.Log(binArgs)
672 out, err = exec.Command(binArgs[0], binArgs[1:]...).CombinedOutput()
673 t.Logf("%s", out)
674 expectSignal(t, err, syscall.SIGPIPE)